From f9eb291f6312cdb8fe530d34c7846e0343cf7ee6 Mon Sep 17 00:00:00 2001 From: Matteo Velludini Date: Wed, 17 May 2017 16:39:14 +0200 Subject: [PATCH 1/4] First implementation of FeatureDockedGrid and DockedGrid components --- package.json | 1 + .../data/featuregrid/DockedGrid.jsx | 88 ++++++++++ .../data/featuregrid/FeatureDockedGrid.jsx | 152 ++++++++++++++++++ .../data/featuregrid/FeatureGrid.jsx | 2 +- .../featuregrid/__tests__/DockedGrid-test.jsx | 50 ++++++ .../__tests__/FeatureDockedGrid-test.jsx | 141 ++++++++++++++++ web/client/themes/default/ms2-theme.less | 40 ++++- 7 files changed, 471 insertions(+), 3 deletions(-) create mode 100644 web/client/components/data/featuregrid/DockedGrid.jsx create mode 100644 web/client/components/data/featuregrid/FeatureDockedGrid.jsx create mode 100644 web/client/components/data/featuregrid/__tests__/DockedGrid-test.jsx create mode 100644 web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx diff --git a/package.json b/package.json index 0e37065b12..d0adf45e65 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "react-color": "2.11.3", "react-confirm-button": "0.0.2", "react-copy-to-clipboard": "4.1.0", + "react-data-grid": "2.0.41", "react-dnd": "2.2.3", "react-dnd-html5-backend": "2.2.3", "react-dock": "0.2.3", diff --git a/web/client/components/data/featuregrid/DockedGrid.jsx b/web/client/components/data/featuregrid/DockedGrid.jsx new file mode 100644 index 0000000000..1728145229 --- /dev/null +++ b/web/client/components/data/featuregrid/DockedGrid.jsx @@ -0,0 +1,88 @@ +/* + * Copyright 2017, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +const React = require('react'); +const Dock = require('react-dock'); +/** + * Component for rendering a docked panel. + * @memberof components.dockedgrid + * @class + * @prop {number} dockSize. The extension in % of the docked panel + * @prop {object} featureDockedGrid. + * @prop {number} maxDockSize. The maximum extension in % of the docked panel + * @prop {number} minDockSize. The minimum extension in % of the docked panel + * @prop {string} position the position of the docked panel + * @prop {function} setDockSize. The metod called when the docked panel is resized + * + */ +const DockedGrid = React.createClass({ + propTypes: { + dockSize: React.PropTypes.number, + featureDockedGrid: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.func]), + maxDockSize: React.PropTypes.number, + minDockSize: React.PropTypes.number, + position: React.PropTypes.string, + setDockSize: React.PropTypes.func + }, + contextTypes: { + messages: React.PropTypes.object + }, + getDefaultProps() { + return { + dockSize: 0.35, + featureDockedGrid: {}, + maxDockSize: 1.0, + minDockSize: 0.1, + position: "bottom", + setDockSize: () => {} + }; + }, + render() { + const FeatureDockedGrid = this.props.featureDockedGrid; + return ( + +
+ +
+
+ ); + }, + limitDockHeight(size) { + if (size >= this.props.maxDockSize) { + this.props.setDockSize(this.props.maxDockSize); + } else if (size <= this.props.minDockSize) { + this.props.setDockSize(this.props.minDockSize); + } else { + this.props.setDockSize(size); + } + } +}); + +module.exports = DockedGrid; diff --git a/web/client/components/data/featuregrid/FeatureDockedGrid.jsx b/web/client/components/data/featuregrid/FeatureDockedGrid.jsx new file mode 100644 index 0000000000..7a6217d0a6 --- /dev/null +++ b/web/client/components/data/featuregrid/FeatureDockedGrid.jsx @@ -0,0 +1,152 @@ +/* + * Copyright 2017, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +const React = require('react'); +const ReactDataGrid = require('react-data-grid'); +const {Button, ButtonToolbar, Glyphicon} = require('react-bootstrap'); + +/** + * Component for rendering a feature grid. + * @memberof components.featuredockedgrid + * @class + * @prop {object} [columns] the columns rendered in the header. Each object is composed by key,name,resizable + * @prop {number} headerRowHeight the height in pixels of the rows in the header + * @prop {number} minHeight the min height of the grid container + * @prop {number} minWidth the min width of the grid container + * @prop {function} onRowsSelected. The method to call when checkbox is checked. + * @prop {function} onRowsDeselected. The method to call when checkbox is un-checked. + * @prop {string} position the position of the docked panel where this component is wrapped + * @prop {string} refDataGrid the reference to the react-data-grid-component + * @prop {number} rowHeight the height of the rows in the grid + * @prop {string} rowKey the key used to distinguish rows + * @prop {object} rows. The features passed to the grid + * @prop {object} selectBy. It contains the selected rows + * @prop {number} size. The size of the dock panel wrapping this component + * @prop {object} style. The style of a wrapper div + * @prop {object} toolbar. The tools of the grid + * @prop {object} [tools] The tools of the grid + * + */ +const FeatureDockedGrid = React.createClass({ + propTypes: { + columns: React.PropTypes.array.isRequired, + headerRowHeight: React.PropTypes.number, + minHeight: React.PropTypes.number.isRequired, + minWidth: React.PropTypes.number.isRequired, + onRowsDeselected: React.PropTypes.func, + onRowsSelected: React.PropTypes.func, + position: React.PropTypes.string, + refDataGrid: React.PropTypes.string, + rowHeight: React.PropTypes.number.isRequired, + rowKey: React.PropTypes.string, + rows: React.PropTypes.array.isRequired, + selectBy: React.PropTypes.object, + size: React.PropTypes.number, + style: React.PropTypes.object, + toolbar: React.PropTypes.object, + tools: React.PropTypes.array + }, + contextTypes: { + messages: React.PropTypes.object + }, + getDefaultProps() { + return { + headerRowHeight: 55, + rowHeight: 30, + minHeight: 250, + minWidth: 600, + onRowsDeselected: () => {}, + onRowsSelected: () => {}, + refDataGrid: "grid", + rows: [], + rowKey: "id", + tools: [], + columns: [], + toolbar: {}, + selectBy: {}, + style: { height: "400px", width: "800px" } + }; + }, + getInitialState() { + return { + minHeight: this.props.minHeight + }; + }, + componentWillReceiveProps(newProps) { + if (this.props.size !== newProps.size) { + const pos = newProps.position; + if (pos === "right" || pos === "left") { + this.setState({minWidth: this.getWidth(this.refs.grid)}); + } + if (pos === "top" || pos === "bottom") { + this.setState({minHeight: this.getHeight(this.refs.grid)}); + } + } + }, + getHeight(element) { + return element && element.getDataGridDOMNode().clientHeight || this.props.minHeight; + }, + getWidth(element) { + return element && element.getDataGridDOMNode().clientWidth; + }, + render() { + let tools = []; + if (this.props.toolbar.zoom) { + tools.push(); + } + const rowText = this.props.selectBy.keys.values.length === 1 ? 'row' : 'rows'; + const rowsSelected = this.props.selectBy.keys.values.length || 0; + tools = [...tools, this.props.tools]; + + return ( +
+
+ +
+
+
+ {rowsSelected} {rowText} selected +
+ + {tools.map((tool) => tool)} + + + +
+
); + }, + + rowGetter(i) { + return this.props.rows[i]; + } + +}); + +module.exports = FeatureDockedGrid; diff --git a/web/client/components/data/featuregrid/FeatureGrid.jsx b/web/client/components/data/featuregrid/FeatureGrid.jsx index f4f688b249..941f729e8e 100644 --- a/web/client/components/data/featuregrid/FeatureGrid.jsx +++ b/web/client/components/data/featuregrid/FeatureGrid.jsx @@ -188,7 +188,7 @@ const FeatureGrid = React.createClass({ flexDirection: "column", height: "100%" }}> -
+
{} +}; +describe("Test DockedGrid Component", () => { + beforeEach((done) => { + document.body.innerHTML = '
'; + setTimeout(done); + }); + + afterEach((done) => { + ReactDOM.unmountComponentAtNode(document.getElementById("container")); + document.body.innerHTML = ''; + setTimeout(done); + }); + + it('Test DockedGrid rendering without tools', () => { + let comp = ReactDOM.render( + , document.getElementById("container")); + expect(comp).toExist(); + + }); + it('Test DockedGrid rendering with 1 added tool', () => { + let comp = ReactDOM.render( + , document.getElementById("container")); + expect(comp).toExist(); + }); + + +}); diff --git a/web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx b/web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx new file mode 100644 index 0000000000..dfec5c5843 --- /dev/null +++ b/web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx @@ -0,0 +1,141 @@ +/* + * Copyright 2017, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +const React = require("react"); +const expect = require('expect'); +const ReactDOM = require('react-dom'); +const FeatureDockedGrid = require('../FeatureDockedGrid'); + +const state = { + columns: [ + { + key: 'id', + name: 'id', + resizable: true + }, { + key: 'name', + name: 'nome livello', + resizable: true + }], + features: [{ + id: "1", + name: "Edifici" + }, { + id: "2", + name: "Aiuola" + }, { + id: "3", + name: "Edifici" + }, { + id: "4", + name: "Aiuola" + }, { + id: "5", + name: "Edifici" + }, { + id: "6", + name: "Aiuola" + }, { + id: "7", + name: "Edifici" + }, { + id: "8", + name: "Aiuola" + }, { + id: "9", + name: "Edifici" + }, { + id: "10", + name: "Aiuola" + }, { + id: "11", + name: "Edifici" + }, { + id: "12", + name: "Aiuola" + }, { + id: "13", + name: "Edifici" + }, { + id: "14", + name: "Aiuola" + }, { + id: "15", + name: "extra 15" + }, { + id: "16", + name: "extra 16" + }], + open: true, + selectBy: { + keys: { + rowKey: '', + values: [] + } + } + }; + +const defaultProps = { + rowsCount: state.features.length, + minHeight: 250, + minWidth: 600, + size: 0.3, + position: "bottom", + columns: state.columns, + selectBy: state.selectBy, + rows: state.features +}; +describe("Test FeatureDockedGrid Component", () => { + beforeEach((done) => { + document.body.innerHTML = '
'; + setTimeout(done); + }); + + afterEach((done) => { + ReactDOM.unmountComponentAtNode(document.getElementById("container")); + document.body.innerHTML = ''; + setTimeout(done); + }); + + it('Test FeatureDockedGrid rendering without tools', () => { + let comp = ReactDOM.render( + , document.getElementById("container")); + expect(comp).toExist(); + let btns = document.getElementsByTagName("button"); + expect(btns.length).toBe(2); + }); + it('Test FeatureDockedGrid rendering with 1 added tool', () => { + let comp = ReactDOM.render( + , document.getElementById("container")); + expect(comp).toExist(); + let btns = document.getElementsByTagName("button"); + expect(btns.length).toBe(3); + }); + it('Test FeatureDockedGrid re-rendering for entering in the componentWillReceiveProps', () => { + let comp = ReactDOM.render( + , document.getElementById("container")); + expect(comp).toExist(); + let comp2 = ReactDOM.render( + , document.getElementById("container")); + expect(comp2).toExist(); + + let btns = document.getElementsByTagName("button"); + expect(btns.length).toBe(2); + }); + +}); diff --git a/web/client/themes/default/ms2-theme.less b/web/client/themes/default/ms2-theme.less index 8735028f1f..02d3b4fb34 100644 --- a/web/client/themes/default/ms2-theme.less +++ b/web/client/themes/default/ms2-theme.less @@ -952,7 +952,43 @@ select.form-control option { background-color: @ms2-color-primary !important; color: @ms2-color-text-primary !important; } -/* feauture grid */ +/* feature grid made by react-data-grid */ +.react-grid-Header{ + background: @ms2-color-primary; + color: @ms2-color-text-primary; + font-family: @font-family-base; +} +.react-grid-Main .react-grid-Header .react-grid-HeaderCell{ + background: @ms2-color-primary; + color: @ms2-color-text-primary; + font-family: @font-family-base; + height:55px !important; + text-align: center; + padding-top: 17px; +} +.react-grid-Row--even .react-grid-Cell { background-color: #f2f2f2; } + +.react-grid-Main, .react-grid-Container, #feature-grid-container { + height: 100%; + width: 100% !important; +} +.react-grid-Container { + width: 100% !important; +} +/* +.react-grid-Canvas{ + height: 100% !important; +}*/ +.react-grid-Grid{ + min-height: 100% !important; +} + +.radio-custom+.radio-custom-label:before, .react-grid-checkbox+.react-grid-checkbox-label:before{ + width: 15px; + height: 15px; +} + +// feature grid .ag-fresh .ag-header, .ag-fresh .ag-tool-panel-container { background: @ms2-color-primary !important; @@ -960,7 +996,7 @@ select.form-control option { font-family: @font-family-base; } -.ag-fresh .ag-tool-panel-container .ag-list-selection { + .ag-fresh .ag-tool-panel-container .ag-list-selection { color: #000000; } From 64a2becacbdf82ca3d42f614f863f14345bac29f Mon Sep 17 00:00:00 2001 From: Matteo Velludini Date: Thu, 18 May 2017 17:53:03 +0200 Subject: [PATCH 2/4] Improved and generalized components --- .../buttons/GlobeViewSwitcherButton.jsx | 2 +- .../data/featuregrid/DockedGrid.jsx | 88 ---------- .../data/featuregrid/FeatureDockedGrid.jsx | 152 ------------------ web/client/components/misc/DockablePanel.jsx | 109 +++++++++++++ web/client/components/misc/ResizableGrid.jsx | 116 +++++++++++++ .../__tests__/DockablePanel-test.jsx} | 19 +-- .../__tests__/ResizableGrid-test.jsx} | 53 +++--- web/client/themes/default/ms2-theme.less | 34 ++-- web/client/translations/data.de-DE | 4 + web/client/translations/data.en-US | 4 + web/client/translations/data.fr-FR | 4 + web/client/translations/data.it-IT | 4 + 12 files changed, 301 insertions(+), 288 deletions(-) delete mode 100644 web/client/components/data/featuregrid/DockedGrid.jsx delete mode 100644 web/client/components/data/featuregrid/FeatureDockedGrid.jsx create mode 100644 web/client/components/misc/DockablePanel.jsx create mode 100644 web/client/components/misc/ResizableGrid.jsx rename web/client/components/{data/featuregrid/__tests__/DockedGrid-test.jsx => misc/__tests__/DockablePanel-test.jsx} (57%) rename web/client/components/{data/featuregrid/__tests__/FeatureDockedGrid-test.jsx => misc/__tests__/ResizableGrid-test.jsx} (73%) diff --git a/web/client/components/buttons/GlobeViewSwitcherButton.jsx b/web/client/components/buttons/GlobeViewSwitcherButton.jsx index 4b0c6f5a4e..08bb2bd791 100644 --- a/web/client/components/buttons/GlobeViewSwitcherButton.jsx +++ b/web/client/components/buttons/GlobeViewSwitcherButton.jsx @@ -82,7 +82,7 @@ const GlobeViewSwitcherButton = React.createClass({ ].reduce((result, key) => { result[key] = this.props[key]; return result; }, {}); }, render() { - return } />; + return } />; } }); diff --git a/web/client/components/data/featuregrid/DockedGrid.jsx b/web/client/components/data/featuregrid/DockedGrid.jsx deleted file mode 100644 index 1728145229..0000000000 --- a/web/client/components/data/featuregrid/DockedGrid.jsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -const React = require('react'); -const Dock = require('react-dock'); -/** - * Component for rendering a docked panel. - * @memberof components.dockedgrid - * @class - * @prop {number} dockSize. The extension in % of the docked panel - * @prop {object} featureDockedGrid. - * @prop {number} maxDockSize. The maximum extension in % of the docked panel - * @prop {number} minDockSize. The minimum extension in % of the docked panel - * @prop {string} position the position of the docked panel - * @prop {function} setDockSize. The metod called when the docked panel is resized - * - */ -const DockedGrid = React.createClass({ - propTypes: { - dockSize: React.PropTypes.number, - featureDockedGrid: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.func]), - maxDockSize: React.PropTypes.number, - minDockSize: React.PropTypes.number, - position: React.PropTypes.string, - setDockSize: React.PropTypes.func - }, - contextTypes: { - messages: React.PropTypes.object - }, - getDefaultProps() { - return { - dockSize: 0.35, - featureDockedGrid: {}, - maxDockSize: 1.0, - minDockSize: 0.1, - position: "bottom", - setDockSize: () => {} - }; - }, - render() { - const FeatureDockedGrid = this.props.featureDockedGrid; - return ( - -
- -
-
- ); - }, - limitDockHeight(size) { - if (size >= this.props.maxDockSize) { - this.props.setDockSize(this.props.maxDockSize); - } else if (size <= this.props.minDockSize) { - this.props.setDockSize(this.props.minDockSize); - } else { - this.props.setDockSize(size); - } - } -}); - -module.exports = DockedGrid; diff --git a/web/client/components/data/featuregrid/FeatureDockedGrid.jsx b/web/client/components/data/featuregrid/FeatureDockedGrid.jsx deleted file mode 100644 index 7a6217d0a6..0000000000 --- a/web/client/components/data/featuregrid/FeatureDockedGrid.jsx +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2017, GeoSolutions Sas. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. - */ -const React = require('react'); -const ReactDataGrid = require('react-data-grid'); -const {Button, ButtonToolbar, Glyphicon} = require('react-bootstrap'); - -/** - * Component for rendering a feature grid. - * @memberof components.featuredockedgrid - * @class - * @prop {object} [columns] the columns rendered in the header. Each object is composed by key,name,resizable - * @prop {number} headerRowHeight the height in pixels of the rows in the header - * @prop {number} minHeight the min height of the grid container - * @prop {number} minWidth the min width of the grid container - * @prop {function} onRowsSelected. The method to call when checkbox is checked. - * @prop {function} onRowsDeselected. The method to call when checkbox is un-checked. - * @prop {string} position the position of the docked panel where this component is wrapped - * @prop {string} refDataGrid the reference to the react-data-grid-component - * @prop {number} rowHeight the height of the rows in the grid - * @prop {string} rowKey the key used to distinguish rows - * @prop {object} rows. The features passed to the grid - * @prop {object} selectBy. It contains the selected rows - * @prop {number} size. The size of the dock panel wrapping this component - * @prop {object} style. The style of a wrapper div - * @prop {object} toolbar. The tools of the grid - * @prop {object} [tools] The tools of the grid - * - */ -const FeatureDockedGrid = React.createClass({ - propTypes: { - columns: React.PropTypes.array.isRequired, - headerRowHeight: React.PropTypes.number, - minHeight: React.PropTypes.number.isRequired, - minWidth: React.PropTypes.number.isRequired, - onRowsDeselected: React.PropTypes.func, - onRowsSelected: React.PropTypes.func, - position: React.PropTypes.string, - refDataGrid: React.PropTypes.string, - rowHeight: React.PropTypes.number.isRequired, - rowKey: React.PropTypes.string, - rows: React.PropTypes.array.isRequired, - selectBy: React.PropTypes.object, - size: React.PropTypes.number, - style: React.PropTypes.object, - toolbar: React.PropTypes.object, - tools: React.PropTypes.array - }, - contextTypes: { - messages: React.PropTypes.object - }, - getDefaultProps() { - return { - headerRowHeight: 55, - rowHeight: 30, - minHeight: 250, - minWidth: 600, - onRowsDeselected: () => {}, - onRowsSelected: () => {}, - refDataGrid: "grid", - rows: [], - rowKey: "id", - tools: [], - columns: [], - toolbar: {}, - selectBy: {}, - style: { height: "400px", width: "800px" } - }; - }, - getInitialState() { - return { - minHeight: this.props.minHeight - }; - }, - componentWillReceiveProps(newProps) { - if (this.props.size !== newProps.size) { - const pos = newProps.position; - if (pos === "right" || pos === "left") { - this.setState({minWidth: this.getWidth(this.refs.grid)}); - } - if (pos === "top" || pos === "bottom") { - this.setState({minHeight: this.getHeight(this.refs.grid)}); - } - } - }, - getHeight(element) { - return element && element.getDataGridDOMNode().clientHeight || this.props.minHeight; - }, - getWidth(element) { - return element && element.getDataGridDOMNode().clientWidth; - }, - render() { - let tools = []; - if (this.props.toolbar.zoom) { - tools.push(); - } - const rowText = this.props.selectBy.keys.values.length === 1 ? 'row' : 'rows'; - const rowsSelected = this.props.selectBy.keys.values.length || 0; - tools = [...tools, this.props.tools]; - - return ( -
-
- -
-
-
- {rowsSelected} {rowText} selected -
- - {tools.map((tool) => tool)} - - - -
-
); - }, - - rowGetter(i) { - return this.props.rows[i]; - } - -}); - -module.exports = FeatureDockedGrid; diff --git a/web/client/components/misc/DockablePanel.jsx b/web/client/components/misc/DockablePanel.jsx new file mode 100644 index 0000000000..871544e5d2 --- /dev/null +++ b/web/client/components/misc/DockablePanel.jsx @@ -0,0 +1,109 @@ +/* + * Copyright 2017, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +const React = require('react'); +const Dock = require('react-dock'); +/** + * Component for rendering a dockablePanel panel. + * @memberof components.dockablePanel + * @class + * @prop {string} id. The
id value of the dockable panel + * @prop {string} dimMode. If none - content is not dimmed, if transparent - pointer events are disabled (so you can click through it), if opaque - click on dim area closes the dock. Default is none + * @prop {number} dockSize. Size of dock panel (width or height, depending on position). Is a % value [0~1] + * @prop {bool} isVisible. If true, dock is visible + * @prop {number} maxDockSize. The maximum extension in % + * @prop {number} minDockSize. The minimum extension in % + * @prop {string} position. Side to dock (left, right, top or bottom). Default is bottom. + * @prop {bool} fluid. If true, resize dock proportionally on window resize. + * @prop {function} setDockSize. The metod called when the dockable panel is resized + * @prop {object} toolbar. it contains the toolbar + * @prop {object} toolbarHeight. the height of the toolbar in px + * @prop {object} wrappedComponent. A connected Component to be rendered inside the dock panel + * @prop {number} zIndex. Positioned below dialogs, above left menu + * + */ +const DockablePanel = React.createClass({ + propTypes: { + id: React.PropTypes.string, + dimMode: React.PropTypes.string, + dockSize: React.PropTypes.number, + isVisible: React.PropTypes.bool, + fluid: React.PropTypes.bool, + maxDockSize: React.PropTypes.number, + minDockSize: React.PropTypes.number, + position: React.PropTypes.string, + setDockSize: React.PropTypes.func, + toolbar: React.PropTypes.object, + toolbarHeight: React.PropTypes.number, + wrappedComponent: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.func]), + zIndex: React.PropTypes.number + }, + contextTypes: { + messages: React.PropTypes.object + }, + getDefaultProps() { + return { + id: "dock", + dimMode: "none", + dockSize: 0.35, + fluid: true, + isVisible: true, + maxDockSize: 1.0, + minDockSize: 0.1, + position: "bottom", + setDockSize: () => {}, + toolbar: null, + toolbarHeight: 60, + wrappedComponent: {}, + zIndex: 1030 + }; + }, + getAutoHeight(pos) { + return pos === "top" || pos === "bottom"; + }, + getAutoWidth(pos) { + return pos === "left" || pos === "right"; + }, + render() { + const WrappedComponent = this.props.wrappedComponent; + return ( + +
+ {this.props.wrappedComponent !== null ? () : null } +
+ {this.props.toolbar} +
+ ); + }, + limitDockHeight(size) { + if (size >= this.props.maxDockSize) { + this.props.setDockSize(this.props.maxDockSize); + } else if (size <= this.props.minDockSize) { + this.props.setDockSize(this.props.minDockSize); + } else { + this.props.setDockSize(size); + } + } +}); + +module.exports = DockablePanel; diff --git a/web/client/components/misc/ResizableGrid.jsx b/web/client/components/misc/ResizableGrid.jsx new file mode 100644 index 0000000000..77bd1d24a4 --- /dev/null +++ b/web/client/components/misc/ResizableGrid.jsx @@ -0,0 +1,116 @@ +/* + * Copyright 2017, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ +const React = require('react'); +const ReactDataGrid = require('react-data-grid'); +/** + * Component for rendering a feature grid. + * @memberof components.ResizableGrid + * @class + * @prop {boolean} autoHeight if true it calculates the available height for the grid + * @prop {boolean} autoWidth if true it sets the minWidth available width for the grid + * @prop {object[]} columns the columns rendered in the header. Each object is composed by key,name,resizable + * @prop {number} headerRowHeight the height in pixels of the rows in the header + * @prop {number} minHeight the min height of the grid container + * @prop {number} minWidth the min width of the grid container + * @prop {function} onRowsSelected. The method to call when checkbox is checked. + * @prop {function} onRowsDeselected. The method to call when checkbox is un-checked. + * @prop {string} refGrid the reference to the react-data-grid-component + * @prop {number} rowHeight the height of the rows in the grid + * @prop {string} rowKey the key used to distinguish rows + * @prop {object} rows. The features passed to the grid + * @prop {object} selectBy. It contains the selected rows + * @prop {number} size. The size of the dock panel wrapping this component + * + */ +const ResizableGrid = React.createClass({ + propTypes: { + autoWidth: React.PropTypes.bool, + autoHeight: React.PropTypes.bool, + columns: React.PropTypes.array.isRequired, + headerRowHeight: React.PropTypes.number, + minHeight: React.PropTypes.number.isRequired, + minWidth: React.PropTypes.number, + onRowsDeselected: React.PropTypes.func, + onRowsSelected: React.PropTypes.func, + onMount: React.PropTypes.func, + refGrid: React.PropTypes.string, + rowHeight: React.PropTypes.number.isRequired, + rowKey: React.PropTypes.string, + rows: React.PropTypes.array.isRequired, + selectBy: React.PropTypes.object, + size: React.PropTypes.object + }, + contextTypes: { + messages: React.PropTypes.object + }, + getDefaultProps() { + return { + autoWidth: true, + autoHeight: true, + columns: [], + headerRowHeight: 55, + minHeight: 250, + minWidth: null, + onRowsDeselected: () => {}, + onRowsSelected: () => {}, + refGrid: "grid", + rowHeight: 30, + rowKey: "id", + rows: [], + selectBy: {keys: {values: []}}, + onMount: () => {} + }; + }, + getInitialState() { + return { + minHeight: this.props.minHeight, + minWidth: this.props.minWidth + }; + }, + componentWillReceiveProps(newProps) { + if (this.props.size !== newProps.size) { + this.setState({ + minWidth: newProps.size.width ? this.getWidth(this.refs.grid) : null, + minHeight: this.getHeight(this.refs.grid)} + ); + } + }, + getHeight(element) { + return element && element.getDataGridDOMNode().clientHeight || this.props.minHeight; + }, + getWidth(element) { + return element && element.getDataGridDOMNode().clientWidth || this.props.minWidth; + }, + render() { + return ( + + ); + }, + rowGetter(i) { + return this.props.rows[i]; + } +}); + +module.exports = ResizableGrid; diff --git a/web/client/components/data/featuregrid/__tests__/DockedGrid-test.jsx b/web/client/components/misc/__tests__/DockablePanel-test.jsx similarity index 57% rename from web/client/components/data/featuregrid/__tests__/DockedGrid-test.jsx rename to web/client/components/misc/__tests__/DockablePanel-test.jsx index 2542b49012..7e32dd3883 100644 --- a/web/client/components/data/featuregrid/__tests__/DockedGrid-test.jsx +++ b/web/client/components/misc/__tests__/DockablePanel-test.jsx @@ -8,18 +8,17 @@ const React = require("react"); const expect = require('expect'); const ReactDOM = require('react-dom'); -const DockedGrid = require('../DockedGrid'); -const FeatureDockedGrid = require('../FeatureDockedGrid'); +const DockablePanel = require('../DockablePanel'); const defaultProps = { dockSize: 0.35, - featureDockedGrid: FeatureDockedGrid, + wrappedComponent: null, position: "bottom", maxDockSize: 1.0, minDockSize: 0.1, setDockSize: () => {} }; -describe("Test DockedGrid Component", () => { +describe("Test DockablePanel Component", () => { beforeEach((done) => { document.body.innerHTML = '
'; setTimeout(done); @@ -31,20 +30,12 @@ describe("Test DockedGrid Component", () => { setTimeout(done); }); - it('Test DockedGrid rendering without tools', () => { + it('Test DockablePanel rendering without tools', () => { let comp = ReactDOM.render( - , document.getElementById("container")); + , document.getElementById("container")); expect(comp).toExist(); }); - it('Test DockedGrid rendering with 1 added tool', () => { - let comp = ReactDOM.render( - , document.getElementById("container")); - expect(comp).toExist(); - }); }); diff --git a/web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx b/web/client/components/misc/__tests__/ResizableGrid-test.jsx similarity index 73% rename from web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx rename to web/client/components/misc/__tests__/ResizableGrid-test.jsx index dfec5c5843..16d71145ca 100644 --- a/web/client/components/data/featuregrid/__tests__/FeatureDockedGrid-test.jsx +++ b/web/client/components/misc/__tests__/ResizableGrid-test.jsx @@ -8,7 +8,7 @@ const React = require("react"); const expect = require('expect'); const ReactDOM = require('react-dom'); -const FeatureDockedGrid = require('../FeatureDockedGrid'); +const ResizableGrid = require('../ResizableGrid'); const state = { columns: [ @@ -83,13 +83,17 @@ const defaultProps = { rowsCount: state.features.length, minHeight: 250, minWidth: 600, - size: 0.3, + size: { + width: true, + height: false, + size: 0.35 + }, position: "bottom", columns: state.columns, selectBy: state.selectBy, rows: state.features }; -describe("Test FeatureDockedGrid Component", () => { +describe("Test ResizableGrid Component", () => { beforeEach((done) => { document.body.innerHTML = '
'; setTimeout(done); @@ -101,41 +105,44 @@ describe("Test FeatureDockedGrid Component", () => { setTimeout(done); }); - it('Test FeatureDockedGrid rendering without tools', () => { + it('Test ResizableGrid rendering without tools', () => { let comp = ReactDOM.render( - , document.getElementById("container")); expect(comp).toExist(); - let btns = document.getElementsByTagName("button"); - expect(btns.length).toBe(2); }); - it('Test FeatureDockedGrid rendering with 1 added tool', () => { - let comp = ReactDOM.render( - , document.getElementById("container")); - expect(comp).toExist(); - let btns = document.getElementsByTagName("button"); - expect(btns.length).toBe(3); - }); - it('Test FeatureDockedGrid re-rendering for entering in the componentWillReceiveProps', () => { + + it('Test ResizableGrid re-rendering for entering in the componentWillReceiveProps', () => { let comp = ReactDOM.render( - , document.getElementById("container")); expect(comp).toExist(); let comp2 = ReactDOM.render( - , document.getElementById("container")); expect(comp2).toExist(); - let btns = document.getElementsByTagName("button"); - expect(btns.length).toBe(2); + let comp3 = ReactDOM.render( + , document.getElementById("container")); + expect(comp3).toExist(); + }); }); diff --git a/web/client/themes/default/ms2-theme.less b/web/client/themes/default/ms2-theme.less index 02d3b4fb34..b1f0563b9f 100644 --- a/web/client/themes/default/ms2-theme.less +++ b/web/client/themes/default/ms2-theme.less @@ -953,12 +953,12 @@ select.form-control option { color: @ms2-color-text-primary !important; } /* feature grid made by react-data-grid */ -.react-grid-Header{ +#container-wrapped-component .react-grid-Header{ background: @ms2-color-primary; color: @ms2-color-text-primary; font-family: @font-family-base; } -.react-grid-Main .react-grid-Header .react-grid-HeaderCell{ +#container-wrapped-component .react-grid-Main .react-grid-Header .react-grid-HeaderCell{ background: @ms2-color-primary; color: @ms2-color-text-primary; font-family: @font-family-base; @@ -966,23 +966,37 @@ select.form-control option { text-align: center; padding-top: 17px; } -.react-grid-Row--even .react-grid-Cell { background-color: #f2f2f2; } +#container-wrapped-component .react-grid-Row--even .react-grid-Cell { background-color: #f2f2f2; } -.react-grid-Main, .react-grid-Container, #feature-grid-container { +#container-wrapped-component .react-grid-Main, .react-grid-Container { height: 100%; width: 100% !important; } -.react-grid-Container { +#container-wrapped-component .react-grid-Container { width: 100% !important; } -/* -.react-grid-Canvas{ - height: 100% !important; -}*/ -.react-grid-Grid{ +// dock panel +#dock-toolbar #left-tools.left-tools{ + position: absolute; + left: 10px; + bottom: 2px; +} +#dock-toolbar #right-tools.right-tools{ + position: absolute; + right: 2px; + bottom: 2px; +} +#container-wrapped-component{ + display: flex; + flex: 1 0 auto; + flexDirection: column; + width: 100%; +} +#container-wrapped-component .react-grid-Grid{ min-height: 100% !important; } + .radio-custom+.radio-custom-label:before, .react-grid-checkbox+.react-grid-checkbox-label:before{ width: 15px; height: 15px; diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE index ea8a0086ff..8ac53df258 100644 --- a/web/client/translations/data.de-DE +++ b/web/client/translations/data.de-DE @@ -46,6 +46,10 @@ "featureTypeError": "Layerattribute können nicht geladen werden", "elevation": "Höhe" }, + "dock": { + "row": "{rowsSelected} reihe ausgewählt", + "rows": "{rowsSelected} reihen ausgewählt" + }, "globeswitcher": { "tooltipDeactivate": "Beenden Sie den 3D-Modus", "tooltipActivate": "Geben Sie den 3D-Modus ein" diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US index fae566375f..1b576e56d8 100644 --- a/web/client/translations/data.en-US +++ b/web/client/translations/data.en-US @@ -46,6 +46,10 @@ "featureTypeError": "Cannot load layer attributes", "elevation": "Elevation" }, + "dock": { + "row": "{rowsSelected} row selected", + "rows": "{rowsSelected} rows selected" + }, "globeswitcher": { "tooltipDeactivate": "Exit 3D Mode", "tooltipActivate": "Enter 3D Mode" diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR index d6a3a478a3..e4eee2a39b 100644 --- a/web/client/translations/data.fr-FR +++ b/web/client/translations/data.fr-FR @@ -46,6 +46,10 @@ "featureTypeError": "Impossible de charger les attributs de calque", "elevation": "élévation" }, + "dock": { + "row": "{rowsSelected} ligne sélectionné", + "rows": "{rowsSelected} lignes sélectionné" + }, "globeswitcher": { "tooltipDeactivate": "Sortie en mode 3D", "tooltipActivate": "Entrez le mode 3D" diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT index 57f5414aca..ad22586c39 100644 --- a/web/client/translations/data.it-IT +++ b/web/client/translations/data.it-IT @@ -46,6 +46,10 @@ "featureTypeError": "Impossibile caricare gli attributi del layer", "elevation": "Elevazione" }, + "dock": { + "row": "{rowsSelected} riga selezionata", + "rows": "{rowsSelected} righe selezionate" + }, "globeswitcher": { "tooltipDeactivate": "Disattiva la modalità 3D", "tooltipActivate": "Attiva la modalità 3D" From 3c7de8340af8b69326177bfe7a7a941eb5b51a84 Mon Sep 17 00:00:00 2001 From: Matteo Velludini Date: Thu, 18 May 2017 18:24:05 +0200 Subject: [PATCH 3/4] fixed requested changes --- .../buttons/GlobeViewSwitcherButton.jsx | 2 +- web/client/components/misc/DockablePanel.jsx | 16 +++++++--------- web/client/components/misc/ResizableGrid.jsx | 19 +++---------------- web/client/themes/default/ms2-theme.less | 14 +++++++------- 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/web/client/components/buttons/GlobeViewSwitcherButton.jsx b/web/client/components/buttons/GlobeViewSwitcherButton.jsx index 08bb2bd791..64e0164cd1 100644 --- a/web/client/components/buttons/GlobeViewSwitcherButton.jsx +++ b/web/client/components/buttons/GlobeViewSwitcherButton.jsx @@ -82,7 +82,7 @@ const GlobeViewSwitcherButton = React.createClass({ ].reduce((result, key) => { result[key] = this.props[key]; return result; }, {}); }, render() { - return } />; + return } />; } }); diff --git a/web/client/components/misc/DockablePanel.jsx b/web/client/components/misc/DockablePanel.jsx index 871544e5d2..2f9d9deb28 100644 --- a/web/client/components/misc/DockablePanel.jsx +++ b/web/client/components/misc/DockablePanel.jsx @@ -47,7 +47,6 @@ const DockablePanel = React.createClass({ }, getDefaultProps() { return { - id: "dock", dimMode: "none", dockSize: 0.35, fluid: true, @@ -62,11 +61,11 @@ const DockablePanel = React.createClass({ zIndex: 1030 }; }, - getAutoHeight(pos) { - return pos === "top" || pos === "bottom"; + getHeight(pos) { + return pos === "top" || pos === "bottom" ? true : undefined; }, - getAutoWidth(pos) { - return pos === "left" || pos === "right"; + getWidth(pos) { + return pos === "left" || pos === "right" ? true : undefined; }, render() { const WrappedComponent = this.props.wrappedComponent; @@ -82,12 +81,11 @@ const DockablePanel = React.createClass({ fluid={this.props.fluid} dimStyle={{ background: 'rgba(0, 0, 100, 0.2)' }} > -
+
{this.props.wrappedComponent !== null ? () : null }
diff --git a/web/client/components/misc/ResizableGrid.jsx b/web/client/components/misc/ResizableGrid.jsx index 77bd1d24a4..2bea5be785 100644 --- a/web/client/components/misc/ResizableGrid.jsx +++ b/web/client/components/misc/ResizableGrid.jsx @@ -17,13 +17,10 @@ const ReactDataGrid = require('react-data-grid'); * @prop {number} headerRowHeight the height in pixels of the rows in the header * @prop {number} minHeight the min height of the grid container * @prop {number} minWidth the min width of the grid container - * @prop {function} onRowsSelected. The method to call when checkbox is checked. - * @prop {function} onRowsDeselected. The method to call when checkbox is un-checked. * @prop {string} refGrid the reference to the react-data-grid-component * @prop {number} rowHeight the height of the rows in the grid * @prop {string} rowKey the key used to distinguish rows * @prop {object} rows. The features passed to the grid - * @prop {object} selectBy. It contains the selected rows * @prop {number} size. The size of the dock panel wrapping this component * */ @@ -35,14 +32,12 @@ const ResizableGrid = React.createClass({ headerRowHeight: React.PropTypes.number, minHeight: React.PropTypes.number.isRequired, minWidth: React.PropTypes.number, - onRowsDeselected: React.PropTypes.func, - onRowsSelected: React.PropTypes.func, onMount: React.PropTypes.func, refGrid: React.PropTypes.string, rowHeight: React.PropTypes.number.isRequired, rowKey: React.PropTypes.string, + rowSelection: React.PropTypes.object, rows: React.PropTypes.array.isRequired, - selectBy: React.PropTypes.object, size: React.PropTypes.object }, contextTypes: { @@ -56,13 +51,11 @@ const ResizableGrid = React.createClass({ headerRowHeight: 55, minHeight: 250, minWidth: null, - onRowsDeselected: () => {}, - onRowsSelected: () => {}, refGrid: "grid", rowHeight: 30, rowKey: "id", + rowSelection: null, rows: [], - selectBy: {keys: {values: []}}, onMount: () => {} }; }, @@ -97,13 +90,7 @@ const ResizableGrid = React.createClass({ rowGetter={this.rowGetter} rowHeight={this.props.rowHeight} rowKey={this.props.rowKey} - rowSelection={{ - showCheckbox: true, - enableShiftSelect: true, - onRowsSelected: this.props.onRowsSelected, - onRowsDeselected: this.props.onRowsDeselected, - selectBy: this.props.selectBy - }} + rowSelection={this.props.rowSelection} rowsCount={this.props.rows.length} /> ); diff --git a/web/client/themes/default/ms2-theme.less b/web/client/themes/default/ms2-theme.less index b1f0563b9f..9bc237e952 100644 --- a/web/client/themes/default/ms2-theme.less +++ b/web/client/themes/default/ms2-theme.less @@ -953,12 +953,12 @@ select.form-control option { color: @ms2-color-text-primary !important; } /* feature grid made by react-data-grid */ -#container-wrapped-component .react-grid-Header{ +.dockpanel-wrapped-component .react-grid-Header{ background: @ms2-color-primary; color: @ms2-color-text-primary; font-family: @font-family-base; } -#container-wrapped-component .react-grid-Main .react-grid-Header .react-grid-HeaderCell{ +.dockpanel-wrapped-component .react-grid-Main .react-grid-Header .react-grid-HeaderCell{ background: @ms2-color-primary; color: @ms2-color-text-primary; font-family: @font-family-base; @@ -966,13 +966,13 @@ select.form-control option { text-align: center; padding-top: 17px; } -#container-wrapped-component .react-grid-Row--even .react-grid-Cell { background-color: #f2f2f2; } +.dockpanel-wrapped-component .react-grid-Row--even .react-grid-Cell { background-color: #f2f2f2; } -#container-wrapped-component .react-grid-Main, .react-grid-Container { +.dockpanel-wrapped-component .react-grid-Main, .react-grid-Container { height: 100%; width: 100% !important; } -#container-wrapped-component .react-grid-Container { +.dockpanel-wrapped-component .react-grid-Container { width: 100% !important; } // dock panel @@ -986,13 +986,13 @@ select.form-control option { right: 2px; bottom: 2px; } -#container-wrapped-component{ +.dockpanel-wrapped-component{ display: flex; flex: 1 0 auto; flexDirection: column; width: 100%; } -#container-wrapped-component .react-grid-Grid{ +.dockpanel-wrapped-component .react-grid-Grid{ min-height: 100% !important; } From 80ebd24ea5dc7f601ce6e1faca2d84934adb1b5c Mon Sep 17 00:00:00 2001 From: Matteo Velludini Date: Fri, 19 May 2017 10:26:13 +0200 Subject: [PATCH 4/4] clean up code --- web/client/components/misc/DockablePanel.jsx | 12 +++---- web/client/components/misc/ResizableGrid.jsx | 36 +++++++++----------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/web/client/components/misc/DockablePanel.jsx b/web/client/components/misc/DockablePanel.jsx index 2f9d9deb28..c4dcb212b4 100644 --- a/web/client/components/misc/DockablePanel.jsx +++ b/web/client/components/misc/DockablePanel.jsx @@ -14,14 +14,14 @@ const Dock = require('react-dock'); * @prop {string} id. The
id value of the dockable panel * @prop {string} dimMode. If none - content is not dimmed, if transparent - pointer events are disabled (so you can click through it), if opaque - click on dim area closes the dock. Default is none * @prop {number} dockSize. Size of dock panel (width or height, depending on position). Is a % value [0~1] - * @prop {bool} isVisible. If true, dock is visible - * @prop {number} maxDockSize. The maximum extension in % - * @prop {number} minDockSize. The minimum extension in % + * @prop {bool} isVisible. If true, dock is visible. Default is true. + * @prop {number} maxDockSize. The maximum extension in %. Default 1.0 + * @prop {number} minDockSize. The minimum extension in %. Default 0.1 * @prop {string} position. Side to dock (left, right, top or bottom). Default is bottom. - * @prop {bool} fluid. If true, resize dock proportionally on window resize. + * @prop {bool} fluid. If true, resize dock proportionally on window resize. Default is true. * @prop {function} setDockSize. The metod called when the dockable panel is resized * @prop {object} toolbar. it contains the toolbar - * @prop {object} toolbarHeight. the height of the toolbar in px + * @prop {object} toolbarHeight. the height of the toolbar in px. Default 40 * @prop {object} wrappedComponent. A connected Component to be rendered inside the dock panel * @prop {number} zIndex. Positioned below dialogs, above left menu * @@ -56,7 +56,7 @@ const DockablePanel = React.createClass({ position: "bottom", setDockSize: () => {}, toolbar: null, - toolbarHeight: 60, + toolbarHeight: 40, wrappedComponent: {}, zIndex: 1030 }; diff --git a/web/client/components/misc/ResizableGrid.jsx b/web/client/components/misc/ResizableGrid.jsx index 2bea5be785..5731a5b24e 100644 --- a/web/client/components/misc/ResizableGrid.jsx +++ b/web/client/components/misc/ResizableGrid.jsx @@ -11,28 +11,24 @@ const ReactDataGrid = require('react-data-grid'); * Component for rendering a feature grid. * @memberof components.ResizableGrid * @class - * @prop {boolean} autoHeight if true it calculates the available height for the grid - * @prop {boolean} autoWidth if true it sets the minWidth available width for the grid - * @prop {object[]} columns the columns rendered in the header. Each object is composed by key,name,resizable - * @prop {number} headerRowHeight the height in pixels of the rows in the header - * @prop {number} minHeight the min height of the grid container - * @prop {number} minWidth the min width of the grid container + * @prop {object[]} columns. The columns rendered in the header. Each object is composed by key,name,[reizable=true|false]. + * @prop {number} headerRowHeight the height in pixels of the rows in the header. Default 55 + * @prop {number} minHeight the min height of the grid container. Default 250 + * @prop {number} minWidth the min width of the grid container. * @prop {string} refGrid the reference to the react-data-grid-component - * @prop {number} rowHeight the height of the rows in the grid - * @prop {string} rowKey the key used to distinguish rows - * @prop {object} rows. The features passed to the grid - * @prop {number} size. The size of the dock panel wrapping this component + * @prop {number} rowHeight the height of the rows in the grid. Default 30 + * @prop {string} rowKey the key used to distinguish rows. + * @prop {object} rowSelection The object used to handle selection of rows. It puts a column of check as the first row. + * @prop {object[]} rows. The features passed to the grid. + * @prop {number} size. The size of the dock panel wrapping this component. * */ const ResizableGrid = React.createClass({ propTypes: { - autoWidth: React.PropTypes.bool, - autoHeight: React.PropTypes.bool, columns: React.PropTypes.array.isRequired, headerRowHeight: React.PropTypes.number, minHeight: React.PropTypes.number.isRequired, minWidth: React.PropTypes.number, - onMount: React.PropTypes.func, refGrid: React.PropTypes.string, rowHeight: React.PropTypes.number.isRequired, rowKey: React.PropTypes.string, @@ -45,8 +41,6 @@ const ResizableGrid = React.createClass({ }, getDefaultProps() { return { - autoWidth: true, - autoHeight: true, columns: [], headerRowHeight: 55, minHeight: 250, @@ -55,8 +49,7 @@ const ResizableGrid = React.createClass({ rowHeight: 30, rowKey: "id", rowSelection: null, - rows: [], - onMount: () => {} + rows: [] }; }, getInitialState() { @@ -66,9 +59,14 @@ const ResizableGrid = React.createClass({ }; }, componentWillReceiveProps(newProps) { - if (this.props.size !== newProps.size) { + if (this.props.size.width !== newProps.size.width ) { + this.setState({ + minWidth: this.getWidth(this.refs.grid), + minHeight: this.getHeight(this.refs.grid)} + ); + } + if (this.props.size.height !== newProps.size.height ) { this.setState({ - minWidth: newProps.size.width ? this.getWidth(this.refs.grid) : null, minHeight: this.getHeight(this.refs.grid)} ); }