forked from react-grid-layout/react-grid-layout
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WidthProvider.jsx
110 lines (97 loc) · 2.8 KB
/
WidthProvider.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// @flow
import * as React from "react";
import PropTypes from "prop-types";
import ResizeObserver from "resize-observer-polyfill";
import clsx from "clsx";
import type { ReactRef } from "../ReactGridLayoutPropTypes";
type WPDefaultProps = {|
measureBeforeMount: boolean
|};
// eslint-disable-next-line no-unused-vars
type WPProps = {|
className?: string,
style?: Object,
...WPDefaultProps
|};
type WPState = {|
width: number
|};
type ComposedProps<Config> = {|
...Config,
measureBeforeMount?: boolean,
className?: string,
style?: Object,
width?: number
|};
const layoutClassName = "react-grid-layout";
/*
* A simple HOC that provides facility for listening to container resizes.
*
* The Flow type is pretty janky here. I can't just spread `WPProps` into this returned object - I wish I could - but it triggers
* a flow bug of some sort that causes it to stop typechecking.
*/
export default function WidthProvideRGL<Config>(
ComposedComponent: React.AbstractComponent<Config>
): React.AbstractComponent<ComposedProps<Config>> {
return class WidthProvider extends React.Component<
ComposedProps<Config>,
WPState
> {
static defaultProps: WPDefaultProps = {
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: PropTypes.bool
};
state: WPState = {
width: 1280
};
elementRef: ReactRef<HTMLDivElement> = React.createRef();
mounted: boolean = false;
resizeObserver: ResizeObserver;
componentDidMount() {
this.mounted = true;
this.resizeObserver = new ResizeObserver(entries => {
const node = this.elementRef.current;
if (node instanceof HTMLElement) {
const width = entries[0].contentRect.width;
this.setState({ width });
}
});
const node = this.elementRef.current;
if (node instanceof HTMLElement) {
this.resizeObserver.observe(node);
}
}
componentWillUnmount() {
this.mounted = false;
const node = this.elementRef.current;
if (node instanceof HTMLElement) {
this.resizeObserver.unobserve(node);
}
this.resizeObserver.disconnect();
}
render() {
const { measureBeforeMount, ...rest } = this.props;
if (measureBeforeMount && !this.mounted) {
return (
<div
className={clsx(this.props.className, layoutClassName)}
style={this.props.style}
// $FlowIgnore ref types
ref={this.elementRef}
/>
);
}
return (
<ComposedComponent
innerRef={this.elementRef}
{...rest}
{...this.state}
/>
);
}
};
}