Skip to content

Commit

Permalink
Make ES5 compatible by using an object instead of Map and WeakMap
Browse files Browse the repository at this point in the history
  • Loading branch information
kristerkari committed Nov 30, 2017
1 parent e8bb27d commit ed73765
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 45 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ It's smart enough to not remove class names added in mutlipe places, and to main
npm install --save react-global-style
```

You may need a polyfill for the ES6 features `Map` and `WeakMap`. These are included in [babel-polyfill], which many apps already use.

[babel-polyfill]: https://babeljs.io/docs/usage/polyfill/

## Usage

```jsx
Expand Down
44 changes: 21 additions & 23 deletions src/ReactGlobalStyle.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
const React = require('react');

// ed = elementData, we use getEd a lot
// WeakMap for edge cases where many elements are targeted
// Not a big deal if it's shimmed as Map
export let ed = new WeakMap();
export let ed = {};
export const getEd = (element = document.body) => {
if (ed.has(element)) {
return ed.get(element);
if (ed[element] !== undefined) {
return ed[element];
}

const classCounts = new Map();
const styleLevels = new Map();
const classCounts = {};
const styleLevels = {};

const incrClassCount = (key) => {
if (classCounts.has(key)) {
classCounts.set(key, classCounts.get(key) + 1);
if (classCounts[key] !== undefined) {
classCounts[key] = classCounts[key] + 1;
} else {
classCounts.set(key, 1);
classCounts[key] = 1;
}
};

const decrClassCount = (key) => {
classCounts.set(key, classCounts.get(key) - 1);
classCounts[key] = classCounts[key] - 1;
};

const addStyleLevel = (key, value) => {
if (styleLevels.has(key)) {
styleLevels.set(key, styleLevels.get(key).concat([value]));
}
if (styleLevels[key] !== undefined) {
styleLevels[key] = styleLevels[key].concat([value]);
}
else {
const items = [value];
if (element.style[key]) items.unshift(element.style[key]);
styleLevels.set(key, items);
styleLevels[key] = items;
}
}

const removeStyleLevel = (key, value) => {
if (styleLevels.has(key)) {
const styles = styleLevels.get(key);
if (styleLevels[key] !== undefined) {
const styles = styleLevels[key];
const newStyles = styles.slice(0, -1);

styleLevels.set(key, newStyles);
styleLevels[key] = newStyles;
}
}

Expand All @@ -54,13 +52,13 @@ export const getEd = (element = document.body) => {
addStyleLevel,
removeStyleLevel,
};
ed.set(element, data);
ed[element] = data;
return data;
};

// Private. Used for the unit tests.
export const reset = () => {
ed = new WeakMap()
ed = {};
};

const splitClasses = (classes) => {
Expand Down Expand Up @@ -94,7 +92,7 @@ export default class ReactGlobalStyle extends React.Component {
oldClasses.forEach((b) => {
if (classes.indexOf(b) === -1) {
this.ed().decrClassCount(b);
if (!this.ed().classCounts.get(b)) {
if (!this.ed().classCounts[b]) {
this.el().classList.remove(b);
}
}
Expand All @@ -118,7 +116,7 @@ export default class ReactGlobalStyle extends React.Component {
// Remove the style by peeling back a layer
if (!style[b] && style[b] !== 0) {
ed.removeStyleLevel(b);
const levels = ed.styleLevels.get(b);
const levels = ed.styleLevels[b];
if (levels && levels.length) {
el.style[b] = levels[levels.length - 1];
} else {
Expand All @@ -128,6 +126,7 @@ export default class ReactGlobalStyle extends React.Component {
});
}
componentDidMount() {
reset();
this.updateClasses(splitClasses(this.props.className), []);
this.updateStyles(this.props.style, {});
}
Expand All @@ -144,4 +143,3 @@ export default class ReactGlobalStyle extends React.Component {
}
render() { return null; }
}

36 changes: 18 additions & 18 deletions src/__tests__/ReactGlobalStyle-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,59 @@ const setup = () => {
describe(`classCounts`, () => {
it(`works for first run`, () => {
const ed = setup();
expect([...ed.classCounts]).toEqual([]);
expect(ed.classCounts).toEqual({});
ed.incrClassCount(`foo`);
expect([...ed.classCounts]).toEqual([[`foo`, 1]]);
expect(ed.classCounts).toEqual({ foo: 1 });
});

it(`works for second run`, () => {
const ed = setup();
ed.incrClassCount(`foo`);
ed.incrClassCount(`foo`);
expect([...ed.classCounts]).toEqual([[`foo`, 2]]);
expect(ed.classCounts).toEqual({ foo: 2 });
});

it(`removes`, () => {
const ed = setup();
ed.incrClassCount(`foo`);
ed.incrClassCount(`foo`);
ed.decrClassCount(`foo`);
expect([...ed.classCounts]).toEqual([[`foo`, 1]]);
expect(ed.classCounts).toEqual({ foo: 1 });
});
});

describe(`styleLevels`, () => {
it(`works for first run`, () => {
const ed = setup();
expect([...ed.styleLevels]).toEqual([]);
expect(ed.styleLevels).toEqual({});
ed.addStyleLevel(`color`, `red`);
expect([...ed.styleLevels]).toEqual([[`color`, [`red`]]]);
expect(ed.styleLevels).toEqual({ color: [`red`] });
});

it(`works for multiple levels`, () => {
const ed = setup();
expect([...ed.styleLevels]).toEqual([]);
expect(ed.styleLevels).toEqual({});
ed.addStyleLevel(`color`, `red`);
ed.addStyleLevel(`width`, `5px`);
ed.addStyleLevel(`color`, `blue`);
expect([...ed.styleLevels]).toEqual([
[`color`, [`red`, `blue`]],
[`width`, [`5px`]],
]);
expect(ed.styleLevels).toEqual({
color: [`red`, `blue`],
width: [`5px`],
});
ed.removeStyleLevel(`color`);
expect([...ed.styleLevels]).toEqual([
[`color`, [`red`]],
[`width`, [`5px`]],
]);
expect(ed.styleLevels).toEqual({
color: [`red`],
width: [`5px`],
});
});

it(`works with existing styles`, () => {
document.body.style.color = 'red';
const ed = setup();
ed.addStyleLevel('color', 'green');
expect([...ed.styleLevels]).toEqual([
['color', ['red', 'green']],
]);
expect(ed.styleLevels).toEqual({
'color': ['red', 'green'],
});
document.body.style.color = '';
});
});
Expand Down

0 comments on commit ed73765

Please sign in to comment.