|
1 |
| -import React, { Component } from 'react'; |
2 |
| -import { v4 } from 'uuid'; |
3 |
| -import keys from 'lodash.keys'; |
4 |
| -import throttle from 'lodash.throttle'; |
5 |
| -import getDisplayName from 'react-display-name'; |
| 1 | +/* eslint-disable no-console */ |
6 | 2 |
|
7 |
| -let resizeListener; |
8 |
| -const listeners = {}; |
| 3 | +import React, { Component } from 'react' |
| 4 | +import { v4 } from 'uuid' |
| 5 | +import keys from 'lodash.keys' |
| 6 | +import throttle from 'lodash.throttle' |
9 | 7 |
|
10 |
| -const getSizes = (window) => ({ |
11 |
| - width: typeof window !== 'undefined' && window.innerWidth, |
12 |
| - height: typeof window !== 'undefined' && window.innerHeight, |
13 |
| - canUseDOM: typeof window !== 'undefined', |
14 |
| -}); |
| 8 | +import * as presets from './presets' |
| 9 | + |
| 10 | +import getDisplayName from './utils/getDisplayName' |
| 11 | +import shallowDiff from './utils/shallowDiff' |
| 12 | +import getWindowSizes from './utils/getWindowSizes' |
| 13 | + |
| 14 | +const debug = process.env.NODE_ENV !== 'production' |
| 15 | + |
| 16 | +let resizeListener |
| 17 | +const listeners = {} |
15 | 18 |
|
16 | 19 | const withSizes = (...mappedSizesToProps) => (WrappedComponent) => {
|
17 | 20 | const parseMappedSizesToProps = (dimensions, props) => {
|
18 | 21 | const propsToPass = mappedSizesToProps
|
19 | 22 | .map(check => check(dimensions, props))
|
20 |
| - .reduce((acc, props) => ({...acc, ...props}), {}); |
| 23 | + .reduce((acc, props) => ({...acc, ...props}), {}) |
21 | 24 |
|
22 |
| - return propsToPass; |
| 25 | + return propsToPass |
23 | 26 | }
|
24 | 27 |
|
25 | 28 | return class extends Component {
|
26 | 29 | static displayName = `withSizes(${getDisplayName(WrappedComponent)})`;
|
27 | 30 |
|
28 | 31 | state = {
|
29 | 32 | id: `A${v4()}`,
|
30 |
| - propsToPass: parseMappedSizesToProps(getSizes(window), this.props), |
| 33 | + propsToPass: parseMappedSizesToProps(getWindowSizes(window), this.props), |
31 | 34 | };
|
32 | 35 |
|
33 | 36 | componentDidMount() {
|
34 | 37 | if (!resizeListener) {
|
35 |
| - resizeListener = window.addEventListener('resize', this.throttledWindowResize); |
| 38 | + resizeListener = window.addEventListener('resize', this.throttledWindowResize) |
36 | 39 | }
|
37 | 40 |
|
38 |
| - listeners[this.state.id] = (sizes) => this.setState({ |
39 |
| - propsToPass: parseMappedSizesToProps(sizes, this.props) |
40 |
| - }); |
| 41 | + listeners[this.state.id] = this.listenerCallback |
41 | 42 |
|
42 |
| - this.dispatchSizes(); |
| 43 | + this.dispatchSizes() |
43 | 44 | }
|
44 | 45 |
|
45 | 46 | componentWillUnmount() {
|
46 |
| - delete listeners[this.state.id]; |
| 47 | + delete listeners[this.state.id] |
47 | 48 | if (keys(listeners).length < 1) {
|
48 |
| - window.removeEventListener('resize', this.throttledWindowResize); |
49 |
| - resizeListener = null; |
| 49 | + window.removeEventListener('resize', this.throttledWindowResize) |
| 50 | + resizeListener = null |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + listenerCallback = (sizes) => { |
| 55 | + const propsToPass = parseMappedSizesToProps(sizes, this.props) |
| 56 | + |
| 57 | + if (shallowDiff(propsToPass, this.state.propsToPass)) { |
| 58 | + this.setState({ propsToPass }) |
50 | 59 | }
|
51 | 60 | }
|
52 | 61 |
|
53 | 62 | dispatchSizes = () => {
|
54 | 63 | keys(listeners).forEach(key => {
|
55 |
| - const callback = listeners[key]; |
| 64 | + const callback = listeners[key] |
56 | 65 |
|
57 | 66 | if (typeof callback === 'function') {
|
58 |
| - callback(getSizes(window)); |
| 67 | + callback(getWindowSizes(window)) |
59 | 68 | }
|
60 |
| - }); |
| 69 | + }) |
61 | 70 | };
|
62 | 71 |
|
63 | 72 | throttledWindowResize = (
|
64 | 73 | throttle(this.dispatchSizes, 200)
|
65 | 74 | );
|
66 | 75 |
|
67 | 76 | render() {
|
68 |
| - return <WrappedComponent {...this.props} {...this.state.propsToPass} />; |
| 77 | + if (debug) console.log('render', this.state.propsToPass) |
| 78 | + return <WrappedComponent {...this.props} {...this.state.propsToPass} /> |
69 | 79 | }
|
70 |
| - }; |
71 |
| -}; |
72 |
| - |
73 |
| -withSizes.isMobile = ({ width }) => width < 480; |
74 |
| -withSizes.isTablet = ({ width }) => width >= 480 && width < 1024; |
75 |
| -withSizes.isDesktop = ({ width }) => width >= 1024; |
76 |
| - |
77 |
| -withSizes.isGtMobile = (sizes) => !withSizes.isMobile(sizes); |
78 |
| -withSizes.isGtTablet = (sizes) => withSizes.isDesktop(sizes); |
79 |
| - |
80 |
| -withSizes.isStTablet = (sizes) => withSizes.isMobile(sizes); |
81 |
| -withSizes.isStDesktop = (sizes) => !withSizes.isStDesktop(sizes); |
82 |
| - |
83 |
| -withSizes.isTabletAndGreater = (sizes) => !withSizes.isMobile(sizes); |
84 |
| -withSizes.isTabletAndSmaller = (sizes) => !withSizes.isStDesktop(sizes); |
| 80 | + } |
| 81 | +} |
85 | 82 |
|
86 |
| -export default withSizes; |
| 83 | +export default Object.assign(withSizes, presets) |
0 commit comments