Skip to content

Commit 8a72152

Browse files
committed
Prepare for 0.2.0
- add eslint - optimize rerenders with shallowDiff in propsToPass - remove unnecessary dependencies - others
1 parent 1e7a622 commit 8a72152

File tree

11 files changed

+1116
-515
lines changed

11 files changed

+1116
-515
lines changed

.eslintrc

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"parser": "babel-eslint",
3+
"extends": [
4+
"eslint:recommended",
5+
"plugin:import/recommended",
6+
"plugin:react/recommended"
7+
],
8+
"parserOptions": {
9+
"ecmaVersion": 6,
10+
"sourceType": "module",
11+
"ecmaFeatures": {
12+
"jsx": true,
13+
"experimentalObjectRestSpread": true
14+
}
15+
},
16+
"env": {
17+
"browser": true,
18+
"node": true
19+
},
20+
"rules": {
21+
"valid-jsdoc": 2,
22+
"react/prop-types": 0,
23+
"react/jsx-uses-react": 1,
24+
"react/jsx-no-undef": 2,
25+
"import/no-unresolved": ["error", { "ignore": ["^react$"] }],
26+
"comma-dangle": ["error", "always-multiline"],
27+
"semi": ["error", "never"],
28+
"no-trailing-spaces": ["error", { "skipBlankLines": true }]
29+
},
30+
"plugins": [
31+
"import",
32+
"react"
33+
]
34+
}

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
node_modules
22
lib
33
.DS_Store
4+
*.log
5+
.vscode

.storybook/components/MobileBreakpoint.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import withSizes from '../../lib/withSizes';
2+
import withSizes from '../../src/withSizes';
33

44
const MobileBreakpoint = ({ isMobile, breakpoint, width }) => (
55
<div>

.storybook/stories/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import { storiesOf, action, linkTo } from '@kadira/storybook';
33
import { Code, Result } from '../components';
44
import MobileBreakpoint from '../components/MobileBreakpoint';
5-
import withSizes from '../../lib/withSizes';
5+
import withSizes from '../../src/withSizes';
66

77
const mapSizesToProps = sizes => ({
88
backgroundColor: sizes.width > 800 ? 'green' : 'blue',

package.json

+18-9
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@
22
"name": "react-sizes",
33
"version": "0.1.2",
44
"description": "Hoc to easily map window sizes to props.",
5-
"main": "index.js",
5+
"main": "lib/index.js",
66
"scripts": {
7-
"clear": "del lib",
8-
"build": "yarn clear && babel src -d lib --source-maps",
9-
"dev": "chokidar 'src/**/*' -c 'yarn build'",
7+
"clean": "rimraf lib",
8+
"lint": "eslint src",
9+
"build": "cross-env NODE_ENV=production npm run lint && npm run clear && babel src -d lib --source-maps",
10+
"prepublish": "npm run lint && npm run clean && npm run build",
1011
"storybook": "start-storybook -p 6006",
11-
"build-storybook": "build-storybook",
12-
"pub": "npm run build && np"
12+
"build-storybook": "build-storybook"
1313
},
1414
"repository": {
1515
"type": "git",
1616
"url": "git+ssh://[email protected]/renatorib/react-sizes.git"
1717
},
18+
"files": [
19+
"lib",
20+
"src"
21+
],
1822
"keywords": [
1923
"react",
2024
"hoc",
@@ -36,23 +40,28 @@
3640
"dependencies": {
3741
"lodash.keys": "^4.2.0",
3842
"lodash.throttle": "^4.1.1",
39-
"react-display-name": "^0.2.0",
4043
"uuid": "^3.0.1"
4144
},
4245
"devDependencies": {
4346
"@kadira/storybook": "^2.21.0",
4447
"babel-cli": "^6.24.1",
48+
"babel-eslint": "^8.0.0",
4549
"babel-plugin-transform-export-extensions": "^6.22.0",
4650
"babel-preset-es2015": "^6.24.1",
4751
"babel-preset-react": "^6.24.1",
4852
"babel-preset-stage-2": "^6.24.1",
4953
"chokidar-cli": "^1.2.0",
54+
"cross-env": "^5.0.5",
5055
"del-cli": "^0.2.1",
56+
"eslint": "^4.6.1",
57+
"eslint-plugin-import": "^2.7.0",
58+
"eslint-plugin-react": "^7.3.0",
5159
"np": "^2.13.1",
60+
"react": "^15.6.1",
61+
"react-dom": "^15.5.3",
5262
"react-syntax-highlighter": "^5.3.0"
5363
},
5464
"peerDependencies": {
55-
"react": "^15.6.1",
56-
"react-dom": "^15.6.1"
65+
"react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0"
5766
}
5867
}

src/presets.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const isMobile = ({ width }) => width < 480
2+
export const isTablet = ({ width }) => width >= 480 && width < 1024
3+
export const isDesktop = ({ width }) => width >= 1024
4+
5+
export const isGtMobile = (sizes) => !isMobile(sizes)
6+
export const isGtTablet = (sizes) => isDesktop(sizes)
7+
8+
export const isStTablet = (sizes) => isMobile(sizes)
9+
export const isStDesktop = (sizes) => !isStDesktop(sizes)
10+
11+
export const isTabletAndGreater = (sizes) => !isMobile(sizes)
12+
export const isTabletAndSmaller = (sizes) => !isStDesktop(sizes)
13+

src/utils/getDisplayName.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const getDisplayName = (Component) => (
2+
Component.displayName ||
3+
Component.name ||
4+
(typeof Component === 'string' && Component.length > 0
5+
? Component
6+
: 'Unknown')
7+
)
8+
9+
export default getDisplayName

src/utils/getWindowSizes.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const getSizes = (window) => {
2+
const canUseDOM = typeof window !== 'undefined'
3+
4+
return {
5+
width: canUseDOM ? window.innerWidth : null,
6+
height: canUseDOM ? window.innerHeight : null,
7+
canUseDOM,
8+
}
9+
}
10+
11+
export default getSizes

src/utils/shallowDiff.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const shallowDiff = (a, b) => {
2+
for (let i in a) {
3+
if (!(i in b)) return true
4+
}
5+
6+
for (let i in b) {
7+
if (a[i] !== b[i]) return true
8+
}
9+
10+
return false
11+
}
12+
13+
export default shallowDiff

src/withSizes.js

+40-43
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,83 @@
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 */
62

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'
97

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 = {}
1518

1619
const withSizes = (...mappedSizesToProps) => (WrappedComponent) => {
1720
const parseMappedSizesToProps = (dimensions, props) => {
1821
const propsToPass = mappedSizesToProps
1922
.map(check => check(dimensions, props))
20-
.reduce((acc, props) => ({...acc, ...props}), {});
23+
.reduce((acc, props) => ({...acc, ...props}), {})
2124

22-
return propsToPass;
25+
return propsToPass
2326
}
2427

2528
return class extends Component {
2629
static displayName = `withSizes(${getDisplayName(WrappedComponent)})`;
2730

2831
state = {
2932
id: `A${v4()}`,
30-
propsToPass: parseMappedSizesToProps(getSizes(window), this.props),
33+
propsToPass: parseMappedSizesToProps(getWindowSizes(window), this.props),
3134
};
3235

3336
componentDidMount() {
3437
if (!resizeListener) {
35-
resizeListener = window.addEventListener('resize', this.throttledWindowResize);
38+
resizeListener = window.addEventListener('resize', this.throttledWindowResize)
3639
}
3740

38-
listeners[this.state.id] = (sizes) => this.setState({
39-
propsToPass: parseMappedSizesToProps(sizes, this.props)
40-
});
41+
listeners[this.state.id] = this.listenerCallback
4142

42-
this.dispatchSizes();
43+
this.dispatchSizes()
4344
}
4445

4546
componentWillUnmount() {
46-
delete listeners[this.state.id];
47+
delete listeners[this.state.id]
4748
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 })
5059
}
5160
}
5261

5362
dispatchSizes = () => {
5463
keys(listeners).forEach(key => {
55-
const callback = listeners[key];
64+
const callback = listeners[key]
5665

5766
if (typeof callback === 'function') {
58-
callback(getSizes(window));
67+
callback(getWindowSizes(window))
5968
}
60-
});
69+
})
6170
};
6271

6372
throttledWindowResize = (
6473
throttle(this.dispatchSizes, 200)
6574
);
6675

6776
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} />
6979
}
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+
}
8582

86-
export default withSizes;
83+
export default Object.assign(withSizes, presets)

0 commit comments

Comments
 (0)