Skip to content

Commit

Permalink
Merge pull request #7 from goodwings/master
Browse files Browse the repository at this point in the history
React 16 compatibility
  • Loading branch information
malte-wessel authored Oct 21, 2017
2 parents ad99207 + 9b9e4d5 commit d775d95
Show file tree
Hide file tree
Showing 19 changed files with 5,618 additions and 205 deletions.
30 changes: 30 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# http://editorconfig.org

# A special property that should be specified at the top of the file outside of
# any sections. Set to true to stop .editor config file search on current file
root = true

[*]
# Indentation style
# Possible values - tab, space
indent_style = space

# Indentation size in single-spaced characters
# Possible values - an integer, tab
indent_size = 4

# Line ending file format
# Possible values - lf, crlf, cr
end_of_line = lf

# File character encoding
# Possible values - latin1, utf-8, utf-16be, utf-16le
charset = utf-8

# Denotes whether to trim whitespace at the end of lines
# Possible values - true, false
trim_trailing_whitespace = true

# Denotes whether file should end with a newline
# Possible values - true, false
insert_final_newline = true
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
lib
**/node_modules
**/webpack.config.js
examples/**/server.js
examples/**/server.js
examples/*
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
"react/jsx-indent-props": 0,
"react/jsx-no-bind": 0,
"react/jsx-closing-bracket-location": 0,
"react/jsx-filename-extension": 0,
"react/react-in-jsx-scope": 2,
"react/no-multi-comp": 0,
"react/prefer-es6-class": 0,
"react/prefer-stateless-function": 0,
"max-len": 0,
"indent": [0, 4],
"new-cap": 0,
Expand Down
3 changes: 2 additions & 1 deletion examples/simple/components/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { createClass } from 'react';
import React from 'react';
import createClass from 'create-react-class';
import { createResponsiveConnect } from 'react-matchmedia-connect';

const matchMediaConnect = createResponsiveConnect();
Expand Down
12 changes: 8 additions & 4 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint no-var: 0, no-unused-vars: 0 */
var path = require('path');
var webpack = require('webpack');

var runCoverage = process.env.COVERAGE === 'true';

var coverageLoaders = [];
Expand All @@ -10,7 +11,7 @@ if (runCoverage) {
coverageLoaders.push({
test: /\.js$/,
include: path.resolve('src/'),
loader: 'isparta'
loader: 'isparta-loader'
});
coverageReporters.push('coverage');
}
Expand All @@ -33,10 +34,13 @@ module.exports = function karmaConfig(config) {
}
},
module: {
loaders: [{
rules: [{
test: /\.js$/,
loader: 'babel',
exclude: /(node_modules)/
loader: 'babel-loader',
exclude: /(node_modules)/,
options: {
plugins: ['rewire']
}
}].concat(coverageLoaders)
}
},
Expand Down
36 changes: 23 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-matchmedia-connect",
"version": "0.1.2",
"version": "0.2.0",
"description": "Higher order component for matchMedia",
"main": "lib/index.js",
"scripts": {
Expand Down Expand Up @@ -32,20 +32,30 @@
"url": "https://github.com/malte-wessel/react-matchmedia-connect/issues"
},
"homepage": "https://github.com/malte-wessel/react-matchmedia-connect",
"dependencies": {
"lodash.capitalize": "^4.2.1",
"lodash.foreach": "^4.5.0",
"lodash.pick": "^4.4.0",
"lodash.throttle": "^4.1.1",
"shallowequal": "^1.0.2"
},
"devDependencies": {
"babel-cli": "^6.2.0",
"babel-core": "^6.2.1",
"babel-eslint": "4.*",
"babel-loader": "^6.2.0",
"babel-eslint": "^8",
"babel-loader": "7.1.2",
"babel-plugin-rewire": "^1.1.0",
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-1": "^6.1.18",
"babel-register": "^6.3.13",
"babel-runtime": "^6.3.19",
"eslint": "^1.6.0",
"eslint-config-airbnb": "^5.0.0",
"eslint-plugin-react": "^3.5.1",
"expect": "^1.6.0",
"eslint": "^4",
"eslint-config-airbnb": "^16",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7",
"expect": "^21.2.1",
"isparta-loader": "^2.0.0",
"karma": "0.13.19",
"karma-chrome-launcher": "^0.2.1",
Expand All @@ -54,15 +64,15 @@
"karma-mocha": "^0.2.0",
"karma-mocha-reporter": "^1.0.3",
"karma-sourcemap-loader": "^0.3.6",
"karma-webpack": "^1.6.0",
"karma-webpack": "2.0.5",
"mocha": "^2.2.5",
"react": "^0.14.3",
"react-addons-test-utils": "^0.14.6",
"react-dom": "^0.14.3",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"rimraf": "^2.3.4",
"simulant": "^0.1.5",
"webpack": "^1.9.6",
"webpack-dev-server": "^1.8.2"
"sinon": "^4.0.1",
"webpack": "^3",
"webpack-dev-server": "^2.9"
},
"peerDependencies": {
"react": ">=0.14.0",
Expand Down
80 changes: 40 additions & 40 deletions src/createMatchMediaConnect.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React, { createClass } from 'react';
import shallowEqual from './utils/shallowEqual';
import throttle from './utils/throttle';
import pick from './utils/pick';
import React, { Component } from 'react';
import forEach from 'lodash.foreach';
import pick from 'lodash.pick';
import shallowEqual from 'shallowequal';
import throttle from 'lodash.throttle';

function pickState(pickProperties, stateToPickFrom) {
if (!pickProperties.length) return stateToPickFrom;
return pick(stateToPickFrom, ...pickProperties);
}

export default function createMatchMediaConnect(queryMap = {}, options = {}) {
const { matchMediaFn = window.matchMedia } = options;
const mqls = {};
const listeners = [];
let state = {};
let internalState = {};

function subscribe(listener) {
listeners.push(listener);
Expand All @@ -19,70 +25,64 @@ export default function createMatchMediaConnect(queryMap = {}, options = {}) {

function createState() {
const nextState = {};
for (const key in mqls) {
if (!mqls.hasOwnProperty(key)) continue;
const mql = mqls[key];
forEach(mqls, (mql, key) => {
const { matches } = mql;
nextState[key] = matches;
}
});
return nextState;
}

const handleChange = throttle(() => {
const nextState = createState();
if (shallowEqual(state, nextState)) return;
state = nextState;
listeners.forEach(listener => listener(nextState));
if (shallowEqual(internalState, nextState)) return;
internalState = nextState;
forEach(listeners, listener => listener(nextState));
});

if (matchMediaFn) {
for (const key in queryMap) {
if (!queryMap.hasOwnProperty(key)) continue;
const query = queryMap[key];
forEach(queryMap, (query, key) => {
const mql = matchMediaFn(query);
mql.addListener(handleChange);
mqls[key] = mql;
}
});
}

function destroy() {
listeners.length = 0;
for (const key in mqls) {
if (!mqls.hasOwnProperty(key)) continue;
const mql = mqls[key];

forEach(mqls, (mql, key) => {
mql.removeListener(handleChange);
mqls[key] = undefined;
}
delete mqls[key];
});
}

state = createState();
internalState = createState();


function connect(pickProperties = []) {
function pickState(stateToPickFrom) {
if (!pickProperties.length) return stateToPickFrom;
return pick(stateToPickFrom, ...pickProperties);
}
return function wrapWithConnect(Component) {
return createClass({
displayName: 'ConnectMatchMedia',
getInitialState() {
return pickState(state);
},
return function wrapWithConnect(WrappedComponent) {
return class WrapWithConnect extends Component {
constructor(props) {
super(props);
this.state = pickState(pickProperties, internalState);
}
componentDidMount() {
this.unsubscribe = subscribe(this.handleChange);
},
}
componentWillUnmount() {
this.unsubscribe();
},
handleChange(nextState) {
const nextPickedState = pickState(nextState);
if (shallowEqual(this.state, nextPickedState)) return;
}
handleChange = (nextState) => {
const nextPickedState = pickState(pickProperties, nextState);


if (shallowEqual(this.state, nextPickedState)) { return; }
this.setState(nextPickedState);
},
}
render() {
return <Component {...this.props} {...this.state}/>;
return <WrappedComponent {...this.props} {...this.state} />;
}
});
};
};
}

Expand Down
9 changes: 4 additions & 5 deletions src/createResponsiveConnect.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import capitalize from 'lodash.capitalize';
import forEach from 'lodash.foreach';
import createMatchMediaConnect from './createMatchMediaConnect';
import capitalize from './utils/capitalize';

const defaultBreakpoints = {
xs: 480,
Expand All @@ -15,11 +16,9 @@ export default function createResponsiveConnect(breakpoints = defaultBreakpoints
isPortrait: '(orientation: portrait)'
};

for (const key in breakpoints) {
if (!breakpoints.hasOwnProperty(key)) continue;
const value = breakpoints[key];
forEach(breakpoints, (value, key) => {
breakpointsList.push({ key, value });
}
});

// Make sure breakpoints are ordered by value ASC
breakpointsList.sort(({ value: a }, { value: b }) => a - b);
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import createMatchMediaConnect from './createMatchMediaConnect';
import createResponsiveConnect from './createResponsiveConnect';

export { createMatchMediaConnect, createResponsiveConnect };
9 changes: 0 additions & 9 deletions src/utils/pick.js

This file was deleted.

18 changes: 0 additions & 18 deletions src/utils/shallowEqual.js

This file was deleted.

35 changes: 0 additions & 35 deletions src/utils/throttle.js

This file was deleted.

6 changes: 3 additions & 3 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import expect from 'expect';
import sinon from 'sinon';

window.expect = expect;
window.createSpy = expect.createSpy;
window.spyOn = expect.spyOn;
window.isSpy = expect.isSpy;
window.sinon = sinon;

const context = require.context('./test', true, /\.spec\.js$/);
context.keys().forEach(context);
Loading

0 comments on commit d775d95

Please sign in to comment.