Skip to content

Commit

Permalink
Fix for react-grid-layout#212 - provide a method for eliminating anim…
Browse files Browse the repository at this point in the history
…ation on mount.
  • Loading branch information
STRML committed Apr 14, 2016
1 parent cccee20 commit 8d69d31
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 50 deletions.
10 changes: 5 additions & 5 deletions .flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ index.js
[libs]

[options]
suppress_comment=.*\\\\s*$FlowFixMe.*
suppress_comment=.*\\\\s*$FlowBug.*
suppress_comment=.*\\\\s*$FlowIgnore.*
suppress_comment=\\(.\\|\n\\)*\\$FlowNewLine.*
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowFixMe.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowBug.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIgnore.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowNewLine.*
suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIssue
esproposal.class_instance_fields=ignore
esproposal.class_static_fields=ignore
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ render: function() {

This allows you to easily replace `<WidthProvider>` with your own Provider HOC if you need more sophisticated logic.

`<WidthProvider>` accepts a single prop, `measureBeforeMount`. If `true`, `<WidthProvider>` will measure the
container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation
on application/component mount.


### Grid Layout Props

Expand Down
1 change: 1 addition & 0 deletions examples/example-styles.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
body {
background: white;
padding: 20px;
overflow: scroll;
}
#content {
width: 100%;
Expand Down
32 changes: 23 additions & 9 deletions lib/components/WidthProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,52 @@
import React from "react";
import ReactDOM from 'react-dom';

type State = {width: number};
type State = {
mounted: boolean,
width: number
};

/*
* A simple HOC that provides facility for listening to container resizes.
*/
export default (ComposedComponent: ReactClass): ReactClass => class extends React.Component {

static defaultProps = {
measureBeforeMount: false
};

static propTypes = {
// If true, will not render children until mounted. Useful for getting the exact width before
// rendering, to prevent any unsightly resizing.
measureBeforeMount: React.PropTypes.bool
};

state: State = {
mounted: false,
width: 1280
};

componentDidMount() {
const node = ReactDOM.findDOMNode(this);
// Bind here so we have the same reference when removing the listener on unmount.
this.onWindowResize = this._onWindowResize.bind(this, node);
this.setState({mounted: true});

window.addEventListener('resize', this.onWindowResize);
// This is intentional. Once to properly set the breakpoint and resize the elements,
// and again to compensate for any scrollbar that appeared because of the first step.
this.onWindowResize();
// Call to properly set the breakpoint and resize the elements.
// Note that if you're doing a full-width element, this can get a little wonky if a scrollbar
// appears because of the grid. In that case, fire your own resize event, or set `overflow: scroll` on your body.
this.onWindowResize();
}

componentWillUnmount() {
window.removeEventListener('resize', this.onWindowResize);
}

_onWindowResize(node: HTMLElement, _event: Event) {
this.setState({width: node.offsetWidth});
onWindowResize = (_event: Event, cb: ?Function) => {
const node = ReactDOM.findDOMNode(this);
this.setState({width: node.offsetWidth}, cb);
}

render() {
if (this.props.measureBeforeMount && !this.state.mounted) return <div {...this.props} {...this.state} />;
return <ComposedComponent {...this.props} {...this.state} />;
}
};
74 changes: 38 additions & 36 deletions test/examples/0-showcase.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
'use strict';
var React = require('react');
var PureRenderMixin = require('react/lib/ReactComponentWithPureRenderMixin');
var _ = require('lodash');
var WidthProvider = require('react-grid-layout').WidthProvider;
var ResponsiveReactGridLayout = require('react-grid-layout').Responsive;
ResponsiveReactGridLayout = WidthProvider(ResponsiveReactGridLayout);
import React from 'react';
import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin';
import _ from 'lodash';
import {Responsive, WidthProvider} from 'react-grid-layout';
const ResponsiveReactGridLayout = WidthProvider(Responsive);

var BasicLayout = React.createClass({
mixins: [PureRenderMixin],
class ShowcaseLayout extends React.Component {

propTypes: {
static propTypes = {
onLayoutChange: React.PropTypes.func.isRequired
},
};

getDefaultProps() {
return {
className: "layout",
rowHeight: 30,
cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
initialLayout: generateLayout()
};
},
static defaultProps = {
className: "layout",
rowHeight: 30,
cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},
initialLayout: generateLayout()
};

getInitialState() {
return {
layouts: {lg: this.props.initialLayout},
currentBreakpoint: 'lg'
};
},
state = {
currentBreakpoint: 'lg',
mounted: false,
layouts: {lg: this.props.initialLayout},
};

componentDidMount() {
this.setState({mounted: true});
}

generateDOM() {
return _.map(this.state.layouts.lg, function (l, i) {
Expand All @@ -39,23 +37,23 @@ var BasicLayout = React.createClass({
}
</div>);
});
},
}

onBreakpointChange(breakpoint) {
onBreakpointChange = (breakpoint) => {
this.setState({
currentBreakpoint: breakpoint
});
},
};

onLayoutChange(layout, layouts) {
onLayoutChange = (layout, layouts) => {
this.props.onLayoutChange(layout, layouts);
},
};

onNewLayout() {
onNewLayout = () => {
this.setState({
layouts: {lg: generateLayout()}
});
},
};

render() {
return (
Expand All @@ -68,13 +66,19 @@ var BasicLayout = React.createClass({
layouts={this.state.layouts}
onBreakpointChange={this.onBreakpointChange}
onLayoutChange={this.onLayoutChange}
useCSSTransforms={true}>
// WidthProvider option
measureBeforeMount={false}
// I like to have it animate on mount. If you don't, delete `useCSSTransforms` (it's default `true`)
// and set `measureBeforeMount={true}`.
useCSSTransforms={this.state.mounted}>
{this.generateDOM()}
</ResponsiveReactGridLayout>
</div>
);
}
});
}

module.exports = ShowcaseLayout;

function generateLayout() {
return _.map(_.range(0, 25), function (item, i) {
Expand All @@ -90,8 +94,6 @@ function generateLayout() {
});
}

module.exports = BasicLayout;

if (require.main === module) {
require('../test-hook.jsx')(module.exports);
}

0 comments on commit 8d69d31

Please sign in to comment.