danfessler / react-panelgroup Goto Github PK
View Code? Open in Web Editor NEWA react component for resizable panel group layouts:
Home Page: https://danfessler.github.io/react-panelgroup/
License: MIT License
A react component for resizable panel group layouts:
Home Page: https://danfessler.github.io/react-panelgroup/
License: MIT License
Hi guys.
Is there a way to increase separator thickness like the example here: https://codepen.io/rstrahl/pen/eJZQej?
Thanks!
Got lots of messages like this in console during resize:
ERROR! SIZES DON'T MATCH!: 532.7000122070312 532.2000122070312
Perhaps, this is due to non-standard DPI:
window.devicePixelRatio == 2.5
I suggest adding threshold of ~2 pixels instead of exact match here: https://github.com/DanFessler/react-panelgroup/blob/master/src/PanelGroup.js#L225
Browser: Chrome Version 70.0.3538.67 (Official Build) (64-bit), Windows 10
Hi,
When the window resizes to smaller than the defined minSize range then the following error is thrown.
Anything wrong being done on the configuration? or min size has to be dynamic?
[{ size: 400, minSize: 400, resize: 'dynamic' }, { size: 900, minSize: 300, resize: 'dynamic' }]
But the same is changed to
[{ size: 400, minSize: 400, resize: 'dynamic' }, { size: 900, minSize: 0, resize: 'dynamic' }]
then there are no errors.
Uncaught RangeError: Maximum call stack size exceeded
at Object.getPanelMinSize (PanelGroup.js:241)
at Object.resizePanel (PanelGroup.js:201)
at Object.resizePanel (PanelGroup.js:208)
at Object.resizePanel (PanelGroup.js:226)
at Object.resizePanel (PanelGroup.js:208)
at Object.resizePanel (PanelGroup.js:226)
at Object.resizePanel (PanelGroup.js:208)
at Object.resizePanel (PanelGroup.js:226)
at Object.resizePanel (PanelGroup.js:208)
at Object.resizePanel (PanelGroup.js:226)
Not sure if this is expected or requires any fix.
Thanks!
Thanks for your project!
I only have 1 question, is that possible to add more style to the panel divider? For instance, animation, etc.
Thank you for your library!
I was wondering what the release cycle is like? How often do you publish to NPM? I'd really like to use this library (and even contribute) for one of my React 16 projects, but the React 16 fixes are not available in NPM yet.
Currently I need to workaround this by cloning the project and pushing to a private NPM repo.
Regards,
Tim
Warning: A string ref, "resizeObject", has been found within a strict mode tree. String refs are a source of potential bugs and should be avoided. We recommend using useRef() or createRef() instead. Learn more about using refs safely here: https://fb.me/react-strict-mode-string-ref
in div (created by Panel)
in Panel (created by PanelGroup)
Hi, first of all, I really like your library thanks form making it!. But I have a problem, I don't understand how does the "weight" works when the resize
property is stretch
, Could you care to explain me?
Hello, @DanFessler!
Is there a plan to support React 16? The only problem is the React.createClass
. If you are OK with it, I'd submit a PR.
Hi,
First, thanks for you lib !
I have an issue and would like to propose a solution.
You often need to custom Divider style when you drag it, like a visual feedback to let user knows he's inside a draggable area. This is currently possible thanks to the divider
CSS class and a :hover
on this class.
Except that when you're dragging the divider, it happens that your mouse leave -for a second- the Divider area (delay between new panelWidths and render), which cause the lost of the .divider:hover
.
See this GIF for demo (maybe it's not clear due to low fps, but :hover is often lost when dragging quickly):
Add a custom divider-dragging
class when a Divider is dragging. This way, we can custom style of the Divider when hovered AND when dragged.
I can make a PR if you agree on this one.
Great component, thanks!
What argument are you intending to pass to onUpdate callback as this.state.props doesn't exist?
this.state.panels?
componentWillUpdate: function componentWillUpdate() {
if (this.props.onUpdate) {
this.props.onUpdate(this.state.props.slice());
}
}
I'm having trouble adding scrolling to my panels with the content exceeds the current size of the panel. Is there a simple way of doing this?
Here's a patch to apply on Reactv15 state:
--- index.js
+++ index.js
@@ -1,28 +1,58 @@
// @flow
-import React from 'react';
+// @flow-ignore
+import React, { MouseEvent } from 'react';
import ReactDOM from 'react-dom';
-/**
- * From https://github.com/DanFessler/react-panelgroup
- */
-var PanelGroup = React.createClass({
-
- // Default props
- getDefaultProps: function() {
- return {
- spacing: 1,
- direction: "row",
- panelWidths: []
- };
- },
+type PanelProp =
+ { snap?: number[],
+ size: number,
+ resize?: 'stretch' | 'dynamic',
+ minSize: number
+ }
+
+type PanelT =
+ { snap: number[],
+ size: number,
+ resize: 'stretch' | 'dynamic',
+ minSize: number
+ }
+
+type PanelGroupState =
+ { panels: PanelT[] }
+
+type Direction =
+ | 'row'
+ | 'column'
+
+type Delta =
+ { x: number,
+ y: number }
+
+type PanelGroupProps =
+ { panelWidths: PanelProp[],
+ children?: any, //React.ReactChildren
+ borderColor?: string,
+ spacing: number,
+ direction: Direction,
+ onUpdate?: PanelT[] => void,
+ onWindowResize?: (/* panel id */ number, Delta, ?(void => void)) => void,
+ panelColor?: string,
+ showHandles: boolean
+ }
+
+class PanelGroup extends React.Component {
+ state: PanelGroupState
+ props: PanelGroupProps
+
+ static defaultProps = {
+ spacing: 1,
+ direction: "row",
+ panelWidths: [],
+ showHandles: false
+ }
// Load initial panel configuration from props
- getInitialState: function() {
- return this.loadPanels(this.props)
- },
+ constructor () {
+ super(...arguments);
+
+ this.state = this.loadPanels(this.props)
+ }
// reload panel configuration if props update
- componentWillReceiveProps: function(nextProps) {
+ componentWillReceiveProps (nextProps: PanelGroupProps) {
var nextPanels = nextProps.panelWidths;
@@ -49,13 +79,15 @@ var PanelGroup = React.createClass({
}
- },
+ }
- // load provided props into state
- loadPanels: function(props) {
+ /**
+ * Load provided props into state
+ */
+ loadPanels = (props: PanelGroupProps) => {
var panels = []
- if (props.children) {
+ if (props.children != null) {
// Default values if none were provided
var defaultSize = 256;
@@ -69,15 +101,16 @@ var PanelGroup = React.createClass({
if (i < props.panelWidths.length && props.panelWidths[i]) {
var widthObj = {
- size: props.panelWidths[i].size !== null ? props.panelWidths[i].size : defaultSize,
- minSize: props.panelWidths[i].minSize !== null ? props.panelWidths[i].minSize : defaultMinSize,
+ size: props.panelWidths[i].size != null ? props.panelWidths[i].size : defaultSize,
+ minSize: props.panelWidths[i].minSize != null ? props.panelWidths[i].minSize : defaultMinSize,
resize: props.panelWidths[i].resize? props.panelWidths[i].resize :
props.panelWidths[i].size? "dynamic" : defaultResize,
+ snap: props.panelWidths[i].snap != null ? props.panelWidths[i].snap : []
}
panels.push(widthObj);
} else {
// default values if no props are given
- panels.push({size: defaultSize, resize: defaultResize, minSize: defaultMinSize})
+ panels.push({size: defaultSize, resize: defaultResize, minSize: defaultMinSize, snap:[]})
}
// if none of the panels included was stretchy, make the last one stretchy
@@ -86,29 +119,28 @@ var PanelGroup = React.createClass({
}
}
- return {
- panels: panels
- }
- },
+ return { panels }
+ };
// Pass internal state out if there's a callback for it
// Useful for saving panel configuration
- onUpdate: function(panels) {
- if (this.props.onUpdate) {
- this.props.onUpdate(panels.slice())
+ onUpdate = (panels: PanelT[]) => {
+ const fn = this.props.onUpdate;
+ if (fn != null) {
+ fn(panels.slice());
}
- },
+ };
// For styling, track which direction to apply sizing to
- getSizeDirection: function(caps) {
+ getSizeDirection = (caps: boolean = false) => {
if (caps)
return this.props.direction === "column" ? "Height" : "Width";
else
return this.props.direction === "column" ? "height" : "width";
- },
+ };
// Render component
- render: function() {
+ render () {
var style = {
container: {
@@ -144,10 +176,10 @@ var PanelGroup = React.createClass({
display: "flex",
overflow: "hidden",
position: "relative",
+ backgroundColor: '#555555'
}
// patch in the background color if it was supplied as a prop
- // @flow-ignore CSS
Object.assign(panelStyle, {backgroundColor: this.props.panelColor});
// give position info to children
@@ -176,22 +208,22 @@ var PanelGroup = React.createClass({
}
return <div className="panel-group" style={style.container}>{newChildren}</div>
- },
+ }
// Entry point for resizing panels.
// We clone the panel array and perform operations on it so we can
// setState after the recursive operations are finished
- handleResize: function(i, delta) {
+ handleResize = (i: number, delta: Delta) => {
var tempPanels = this.state.panels.slice();
var returnDelta = this.resizePanel(i, this.props.direction === "row" ? delta.x : delta.y, tempPanels);
this.setState({panels: tempPanels});
this.onUpdate(tempPanels)
return returnDelta;
- },
+ };
// Recursive panel resizing so we can push other panels out of the way
// if we've exceeded the target panel's extents
- resizePanel: function(panelIndex, delta, panels) {
+ resizePanel = (panelIndex: number, delta: number, panels: PanelT[]) => {
var minsize; var maxsize;
@@ -209,22 +241,22 @@ var PanelGroup = React.createClass({
// if we made the left panel too small
if (panels[panelIndex].size < minsize) {
- delta = minsize - panels[panelIndex].size;
+ let delta = minsize - panels[panelIndex].size;
if (panelIndex === 0)
- resultDelta += this.resizePanel(panelIndex, delta, panels);
+ resultDelta = this.resizePanel(panelIndex, delta, panels);
else
- resultDelta += this.resizePanel(panelIndex-1, -delta, panels);
+ resultDelta = this.resizePanel(panelIndex-1, -delta, panels);
};
// if we made the left panel too big
if (maxsize !== 0 && panels[panelIndex].size > maxsize) {
- delta = panels[panelIndex].size - maxsize;
+ let delta = panels[panelIndex].size - maxsize;
if (panelIndex === 0)
- resultDelta += this.resizePanel(panelIndex, -delta, panels);
+ resultDelta = this.resizePanel(panelIndex, -delta, panels);
else
- resultDelta += this.resizePanel(panelIndex-1, delta, panels);
+ resultDelta = this.resizePanel(panelIndex-1, delta, panels);
};
@@ -234,30 +266,60 @@ var PanelGroup = React.createClass({
// if we made the right panel too small
if (panels[panelIndex+1].size < minsize) {
- delta = minsize - panels[panelIndex+1].size;
+ let delta = minsize - panels[panelIndex+1].size;
if (panelIndex+1 === panels.length-1)
- resultDelta += this.resizePanel(panelIndex, -delta, panels);
+ resultDelta = this.resizePanel(panelIndex, -delta, panels);
else
- resultDelta += this.resizePanel(panelIndex+1, delta, panels);
+ resultDelta = this.resizePanel(panelIndex+1, delta, panels);
};
// if we made the right panel too big
if (maxsize !== 0 && panels[panelIndex+1].size > maxsize) {
- delta = panels[panelIndex+1].size - maxsize;
+ let delta = panels[panelIndex+1].size - maxsize;
if (panelIndex+1 === panels.length-1)
- resultDelta += this.resizePanel(panelIndex, delta, panels);
+ resultDelta = this.resizePanel(panelIndex, delta, panels);
else
- resultDelta += this.resizePanel(panelIndex+1, -delta, panels);
+ resultDelta = this.resizePanel(panelIndex+1, -delta, panels);
};
+ // Iterate through left panel's snap positions
+ for (let i=0; i<panels[panelIndex].snap.length; i++) {
+ if (Math.abs(panels[panelIndex].snap[i] - panels[panelIndex].size) < 20) {
+
+ let delta = panels[panelIndex].snap[i] - panels[panelIndex].size;
+
+ if (
+ delta !== 0 &&
+ panels[panelIndex].size + delta >= this.getPanelMinSize(panelIndex, panels) &&
+ panels[panelIndex+1].size - delta >= this.getPanelMinSize(panelIndex+1, panels)
+ )
+ resultDelta = this.resizePanel(panelIndex, delta, panels);
+ }
+ }
+
+ // Iterate through right panel's snap positions
+ for (let i=0; i<panels[panelIndex+1].snap.length; i++) {
+ if (Math.abs(panels[panelIndex+1].snap[i] - panels[panelIndex+1].size) < 20) {
+
+ let delta = panels[panelIndex+1].snap[i] - panels[panelIndex+1].size;
+
+ if (
+ delta !== 0 &&
+ panels[panelIndex].size + delta >= this.getPanelMinSize(panelIndex, panels) &&
+ panels[panelIndex+1].size - delta >= this.getPanelMinSize(panelIndex+1, panels)
+ )
+ resultDelta = this.resizePanel(panelIndex, -delta, panels);
+ }
+ }
+
// return how much this panel actually resized
return resultDelta;
- },
+ };
// Utility function for getting min pixel size of panel
- getPanelMinSize: function(panelIndex: number, panels: any[]) {
+ getPanelMinSize = (panelIndex: number, panels: PanelT[]) => {
if (panels[panelIndex].resize === "fixed") {
if (!panels[panelIndex].fixedSize) {
panels[panelIndex].fixedSize = panels[panelIndex].size;
@@ -265,10 +327,10 @@ var PanelGroup = React.createClass({
return panels[panelIndex].fixedSize;
}
return panels[panelIndex].minSize;
- },
+ };
// Utility function for getting max pixel size of panel
- getPanelMaxSize: function(panelIndex, panels) {
+ getPanelMaxSize = (panelIndex: number, panels: PanelT[]) => {
if (panels[panelIndex].resize === "fixed") {
if (!panels[panelIndex].fixedSize) {
panels[panelIndex].fixedSize = panels[panelIndex].size;
@@ -276,21 +338,21 @@ var PanelGroup = React.createClass({
return panels[panelIndex].fixedSize;
}
return 0;
- },
+ };
// Utility function for getting min pixel size of the entire panel group
- getPanelGroupMinSize: function(spacing) {
+ getPanelGroupMinSize = (spacing: number) => {
var size = 0;
for (var i = 0; i < this.state.panels.length; i++) {
size += this.getPanelMinSize(i, this.state.panels);
}
return size + ((this.state.panels.length-1) * spacing)
- },
+ };
// Hard-set a panel's size
// Used to recalculate a stretchy panel when the window is resized
- setPanelSize: function(panelIndex, size, callback) {
- size = this.props.direction === "column"? size.y : size.x;
+ setPanelSize = (panelIndex: number, sizeXY: Delta, callback: void => void = () => {}) => {
+ const size = this.props.direction === "column"? sizeXY.y : sizeXY.x;
if (size !== this.state.panels[panelIndex].size){
var tempPanels = this.state.panels;
@@ -308,56 +370,56 @@ var PanelGroup = React.createClass({
callback();
}
}
- },
-})
-
+ };
+}
-var Panel = React.createClass({
+class Panel extends React.Component {
// Find the resizeObject if it has one
- componentDidMount: function() {
+ componentDidMount () {
if (this.props.resize === "stretch") {
this.refs.resizeObject.addEventListener("load", () => this.onResizeObjectLoad());
this.refs.resizeObject.data = "about:blank";
this.calculateStretchWidth();
}
- },
+ }
// Attach resize event listener to resizeObject
- onResizeObjectLoad() {
+ onResizeObjectLoad = () => {
this.refs.resizeObject.contentDocument.defaultView.addEventListener(
"resize", () => this.calculateStretchWidth());
- },
+ };
// Utility function to wait for next render before executing a function
- onNextFrame: function(callback) {
+ onNextFrame = (callback) => {
setTimeout(function () {
window.requestAnimationFrame(callback)
}, 0)
- },
+ };
// Recalculate the stretchy panel if it's container has been resized
- calculateStretchWidth: function() {
- if (this.props.onWindowResize !== null) {
- var node = ReactDOM.findDOMNode(this)
- if (node === null) { throw new Error("Couldn't find Panel DOM node"); }
- if (node instanceof Text) { throw new Error("Expected DOM node to be of type Element"); }
- var rect = node.getBoundingClientRect();
-
- this.props.onWindowResize(
+ calculateStretchWidth = () => {
+ const onResize = this.props.onWindowResize;
+ if (onResize != null) {
+ const node = ReactDOM.findDOMNode(this);
+ if (node == null) { throw new Error('ReactDOM.findDOMNode(this) => null') }
+ if (node instanceof Text) { throw new Error("Node was of Text type, but it should've been Element"); }
+ const rect = node.getBoundingClientRect();
+
+ onResize(
this.props.panelID,
{x:rect.width, y:rect.height},
// recalcalculate again if the width is below minimum
// Kinda hacky, but for large resizes like fullscreen/Restore
// it can't solve it in one pass.
- function() {this.onNextFrame(this.calculateStretchWidth)}.bind(this)
+ // function() {this.onNextFrame(this.calculateStretchWidth)}.bind(this)
);
}
- },
+ };
// Render component
- render: function() {
+ render () {
var style = {
resizeObject: {
@@ -381,42 +443,51 @@ var Panel = React.createClass({
</div>
)
}
-})
-
-
-var Divider = React.createClass({
+}
+
+type DividerProps =
+ { dividerWidth: number,
+ handleBleed: number,
+ panelID: number,
+ handleResize: (panelId: number, delta: Delta) => number,
+ borderColor?: string,
+ showHandles: boolean }
+
+type DividerState =
+ { dragging: boolean,
+ initPos: Delta }
+
+class Divider extends React.Component {
+ props: DividerProps
+ state: DividerState
+
+ static defaultProps = {
+ dividerWidth: 1,
+ handleBleed: 4,
+ }
- getDefaultProps: function() {
- return {
- dividerWidth: 1,
- handleBleed: 4,
- };
- },
+ constructor () {
+ super(...arguments);
- getInitialState: function () {
- return {
+ this.state = {
dragging: false,
- initPos: {x:null,y:null},
- }
- },
+ initPos: {x:0,y:0},
+ };
+ }
// Add/remove event listeners based on drag state
- componentDidUpdate: function (props, state) {
+ componentDidUpdate (props: DividerProps, state: DividerState) {
if (this.state.dragging && !state.dragging) {
- // @flow-ignore
document.addEventListener('mousemove', this.onMouseMove)
- // @flow-ignore
document.addEventListener('mouseup', this.onMouseUp)
} else if (!this.state.dragging && state.dragging) {
- // @flow-ignore
document.removeEventListener('mousemove', this.onMouseMove)
- // @flow-ignore
document.removeEventListener('mouseup', this.onMouseUp)
}
- },
+ }
// Start drag state and set initial position
- onMouseDown: function (e) {
+ onMouseDown = (e) => {
// only left mouse button
if (e.button !== 0) return
@@ -431,54 +502,72 @@ var Divider = React.createClass({
e.stopPropagation()
e.preventDefault()
- },
+ };
// End drag state
- onMouseUp: function (e) {
+ onMouseUp = (e: MouseEvent) => {
this.setState({dragging: false})
e.stopPropagation()
e.preventDefault()
- },
+ };
// Call resize handler if we're dragging
- onMouseMove: function (e) {
+ onMouseMove = (e: MouseEvent) => {
if (!this.state.dragging) return
+ let initDelta = {
+ x: e.pageX - this.state.initPos.x,
+ y: e.pageY - this.state.initPos.y
+ }
+
+ let flowMask = {
+ x: (this.props.direction === "row" ? 1 : 0),
+ y: (this.props.direction === "column" ? 1 : 0)
+ }
+
+ let flowDelta = (initDelta.x * flowMask.x) + (initDelta.y * flowMask.y);
+
+ // Resize the panels
var resultDelta = this.handleResize(
this.props.panelID,
- {x: e.pageX - this.state.initPos.x, y: e.pageY - this.state.initPos.y}
+ initDelta
);
- // if we've resized the panel like intended, reset the initPos
- if (resultDelta !== 0) {
+ // if the divider moved, reset the initPos
+ if (resultDelta + flowDelta !== 0) {
+
+ // Did we move the expected amount? (snapping will result in a larger delta)
+ let expectedDelta = (resultDelta === flowDelta);
+
this.setState({
initPos: {
- x: e.pageX,
- y: e.pageY
+ // if we moved more than expected, add the difference to the Position
+ x: e.pageX + (expectedDelta? 0 : resultDelta * flowMask.x),
+ y: e.pageY + (expectedDelta? 0 : resultDelta * flowMask.y)
},
})
}
e.stopPropagation()
e.preventDefault()
- },
+ };
// Handle resizing
- handleResize(i, delta) {
+ handleResize =(i, delta) => {
return this.props.handleResize(i, delta);
- },
+ };
// Utility functions for handle size provided how much bleed
// we want outside of the actual divider div
- getHandleWidth: function() {
+ getHandleWidth = () => {
return (this.props.dividerWidth + (this.props.handleBleed * 2));
- },
- getHandleOffset: function() {
+ };
+ getHandleOffset = () => {
return (this.props.dividerWidth/2) - (this.getHandleWidth()/2);
- },
+ };
// Render component
- render: function() {
+ render () {
var style = {
divider: {
width: this.props.direction === "row" ? this.props.dividerWidth : "auto",
@@ -489,6 +578,7 @@ var Divider = React.createClass({
maxHeight: this.props.direction === "column" ? this.props.dividerWidth : "auto",
flexGrow: 0,
position: "relative",
+ backgroundColor: "#cccccc"
},
handle: {
position: "absolute",
@@ -496,12 +586,12 @@ var Divider = React.createClass({
height: this.props.direction === "column" ? this.getHandleWidth() : "100%",
left: this.props.direction === "row" ? this.getHandleOffset() : 0,
top: this.props.direction === "column" ? this.getHandleOffset() : 0,
- backgroundColor: this.props.showHandles? "rgba(0,128,255,0.25)" : "auto",
- cursor: this.props.direction === "row" ? "ew-resize" : "ns-resize",
+ backgroundColor: this.props.showHandles ? "rgba(0,128,255,0.25)" : "auto",
+ cursor: this.props.direction === "row" ? "col-resize" : "row-resize",
zIndex: 100,
}
}
- // @flow-ignore CSS
+
Object.assign(style.divider, {backgroundColor: this.props.borderColor});
return (
@@ -510,7 +600,7 @@ var Divider = React.createClass({
</div>
);
}
-})
+}
-export default PanelGroup;
\ No newline at end of file
+export default PanelGroup;
A potential resolution would to use a percentage system instead of pixels
It would be great if this panel would handle touch support for mobile devices.
Hello, in my use case i dont want to let resize neighbor panel.
Anyway I can do it?
Hello! As the title says, changing the direction of panel group causes the resize functionality to stop working. I was able to reproduce this on the demo site by using React DevTools to change the direction of the panels and the same issue occurred as seen below.
Before changing the property:
After changing the property:
You'll notice the separators are no longer visible and you can no longer resize the panels.
The below code should be enough to reproduce this.
const [isColumnMode, setIsColumnMode] = useState(true);
return (
<>
<PanelGroup direction={isColumnMode ? 'column' : 'row'}>
<div>Panel 1</div>
<div>Panel 2</div>
</PanelGroup>
<button onClick={() => setIsColumnMode(!isColumnMode)}>
Toggle View Mode
</button>
</>
);
I had one possible "fix" without changing the library, albeit a very non-performant one. Essentially adding a key to a parent component such that it changed every time the panel direction changed (ie <div key={isColumnMode}>
), forces React to re-render all of that div's children including the PanelGroup. And since it would be re-rendered, it would act as a newly formed PanelGroup and work fine. However, this operation is very heavy and is not optimal for our use case.
Any help with this would be greatly appreciated. Thank you!
I am working on an app which requires 3 panes. But the two panes at the end should not expand after a particular limit. It would be good to have maxSize to be set for each pane.
I've seen a handful of implementations of panels like this where there's a small "handle" on the resizer divider. This can be really useful for mobile (eg: #16 )since it is often more useful to "toggle" panels on mobile rather than drag to resize.
This is something I'm looking at doing, but wanted to file an issue first to see if anyone in the community had implemented something like this.
panelWidths
configs objectonHandleClick
called with arguments panels
(like current onUpdate
method), along with the panelIndex
of the selected panel divider.onHandleClick
would only fire onMouseUp
if isDragging === false
panelIndex
refer to?If a handle is placed on panel 0, it is placed on the divider between panels 0 and 1. This is straightforward.
In a three column layout with a stretch
column between two sidebars, does the handle for the righthand sidebar go on panel 1 or panel 2?
possible solution: handle
could take either a single DOM element (as described above, ie: "basic config mode"), or it could take an object with properties: handle.component
, handle.direction
, etc
Hi! I'd like to know if there is an option to avoid recursive resizing. It would be useful to have a prop on the PanelGroup component to avoid it and only allow resizing of two adjacent panels.
I see there are some cases (I configured the snap in panelWidths) in which recursive resizing causes RangeError: Maximum call stack size exceeded:
PanelGroup.js:125 Uncaught RangeError: Maximum call stack size exceeded
at PanelGroup._this.resizePanel
Thank you.
Right now, the handle/divider for resizing the panels just has a CSS class of "divider" which is likely to clash with existing styling we have in our site. Is there a way to customize this?
Hi guys,
I receive in the console this error:
console.warn node_modules/react-dom/cjs/react-dom.development.js:12386
Warning: componentWillReceiveProps has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.
* Move data fetching code or side effects to componentDidUpdate.
* If you're updating state whenever props change, refactor your code to use memoization techniques or move it to static getDerivedStateFromProps. Learn more at: https://fb.me/react-derived-state
* Rename componentWillReceiveProps to UNSAFE_componentWillReceiveProps to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.
Please update the following components: PanelGroup
Can you do something about it?
Thanks!
dependencies break with React 17 along with some severity issues
is it possible to resize last child div beyound page height when direction="column"?
It doesn't appear that the update was successfully uploaded to npm. Installing this package from npm/yarn with react 16 still throws the "react___default.a.createClass is not a function" error.
Manually compiling the src and copying to node_modules works.
I am using react-panelgroups with rows. The height of each panel is dynamically set by the user, and I wish to keep the panel heights synchronized while the user changes them individually. From what I can tell they change independently and require constant updating panel div heights to align with each other. It's added quite a bit of new code. Am I missing something? Does anyone have any ideas as to how to make the panel div heights talk to each other/synchronize?
I have a scenario where I need to know if the divider is being dragged, to add some additional styling to some components. I can see the 'dragging' class being applied on the 'divider'. Is that the only way to know? Doesn't seem very 'React' way of finding out.
Any help appreciated. Thanks!
I'm unable to get my "column" of two panels to fill the height of the page they're in. Any advice?
Hello,
When using version 1.0.7 of the PanelGroup, we get an "Unable to find node on an unmounted component." error from time to time.
I could easily reproduce it by creating a test project where the React component using the PanelGroup is replaced by another React component when clicking a button. When clicking this button rapidly, the unmounted errors are shown in the console. It does seem to happen more frequently when my browser/pc is slower or the component using the PanelGroup is more complex.
The error seems to be introduced when this.onNextFrame(this.calculateStretchWidth); was put in the Panel.componentDidMount.
Thanks for the help.
Pieter
Thanks in advance.
demo code in git, unfortunately, doesn't help.
Currently, defaults for sizes are hardcoded in, but it'd be nice to be able to specify the defaults for all panels for situations where you want the same defaultMinSize for all panels but you don't know the number of panels ahead of time and don't want to keep re-creating the panelWidths array.
https://github.com/DanFessler/react-panelgroup/blob/master/src/PanelGroup.js#L81-L84
const defaultSize = 256;
const defaultMinSize = 48;
const defaultMaxSize = 0;
const defaultResize = 'stretch';
to
const defaultSize = this.props.defaultSize || 256;
const defaultMinSize = this.props.defaultMinSize || 48;
const defaultMaxSize = this.props.defaultMinSize || 0;
const defaultResize = 'stretch';
In our application, by default, two panels are used. But on pressing the button of an event one more panel is added.
Panel sizes are also saved in store mobx.
When the component is loaded in the store for the first time, the panelWidths array is saved using onUpdate , but when after that I try to call another panel on click, I get an error
<PanelGroup
onUpdate={(e: Array<any>) => { // when updating panels, write update state
accountStore.setSizesPanel(e);
}}
panelWidths={accountStore.panelWidthsSettings} // read state from store
>
<Panel0 / >
{accountStore.isVisibleCustomPanel() ? <Panel1 /> : null}. // appears on user click
<Panel2 />
</PanelGroup>
Hello,
I'm trying add a snapping feature to react-panelgroup. So far I've tried to change the size of each panel object based on where it is, the container width and how many panels there are. But when I change the size it gets stuck in a never ending loop of updating.
Figured I'd come on here and see if you know of any projects that tried to add some kind of snapping or constraining feature to react-panelgroup?
Thanks,
Michael
When I update some child component of a panel, the panel is re-rendered with the initial sizes. I am sure that this is not working as intended, but I can't find away past it.
I have tried to tie the onUpdate to a state change, figuring that I could catch the new sizes, and apply it to the component when react re-renders. However, it seems that onUpdate is triggered by the re-rendering, and I have a loop on my hands. onUpdate is triggered even before i tie the panelWidths to the state.
What am I doing wrong? I am fairly new to react and I might be missing some key insight here.
windowResize(sizes) {
//setting the state to something, forcing a re-render, and then onUpdate triggers
this.setState({test:"test"});
}
render() {
...
return <PanelGroup style={{height:"100%"}} borderColor="grey" onUpdate={this.windowResize} panelWidths={[
{size: 100, minSize:50, resize: "dynamic"},
{minSize:100, resize: "stretch"},
{size: 100, minSize:50, resize: "dynamic"}]}>
...
</PanelGroup>
}
//I added this to stop an infinite loop. Counter defined elsewhere
shouldComponentUpdate(nextProps, nextState) {
counter++;
return counter<100;
}
I'm curious if you have any plans for publishing Typescript typings for this, or if for the library itself using Typescript?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.