Skip to content

Commit f2f36ef

Browse files
authored
feat(src): add ToggleAndDisplayPattern (#6)
* feat(src): add ToggleAndDisplayPattern ToggleAndDisplayPattern use `hidden` attribute and toggle it. So, it means that ToggleAndDisplayPattern don't delete component actually. Show and Hide is the concept of ToggleAndDisplayPattern. This pattern help to toggle <img /> which occur request with ading. ToggleAndDisplayPattern add the component at once.
 * chore(npm): remove unused uuid
1 parent 3c9bd5f commit f2f36ef

File tree

6 files changed

+181
-20
lines changed

6 files changed

+181
-20
lines changed

example/src/App.js

+34-14
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import React, {Component} from 'react';
2-
import {TogglePattern} from "react-toggle-pattern";
2+
import {ToggleAndDisplayPattern as TogglePattern} from "react-toggle-pattern";
33
import ActiveElement from "./ActiveElement";
44
import './App.css';
55

66
class App extends Component {
77
constructor() {
88
super();
99
this.state = {
10-
pattern: "A"
10+
pattern: "A",
11+
patternCorD: "C"
1112
}
1213
}
1314

@@ -22,21 +23,40 @@ class App extends Component {
2223
pattern: "A"
2324
});
2425
};
26+
const onClickC = () => {
27+
this.setState({
28+
patternCorD: "D"
29+
});
30+
};
31+
const onClickD = () => {
32+
this.setState({
33+
patternCorD: "C"
34+
});
35+
};
2536
return (
2637
<div className="App">
27-
<TogglePattern pattern={this.state.pattern}>
28-
<div pattern={"A"} onClick={onClickA}>
29-
<button><p>
30-
A
31-
</p></button>
32-
</div>
33-
<div pattern={"B"} onClick={onClickB}>
34-
<span>BBB</span>
35-
<button>
36-
<span>B</span>
38+
<div>
39+
<h2>Pattern A or B</h2>
40+
<TogglePattern pattern={this.state.pattern}>
41+
<button pattern={"A"} onClick={onClickA}>
42+
AAAAAA
43+
</button>
44+
<button pattern={"B"} onClick={onClickB}>
45+
BBBBBB
46+
</button>
47+
</TogglePattern>
48+
</div>
49+
<div>
50+
<h2>Pattern C or D</h2>
51+
<TogglePattern pattern={this.state.patternCorD}>
52+
<button key="C" pattern={"C"} onClick={onClickC}>
53+
CCCCCCC
54+
</button>
55+
<button key="D" pattern={"D"} onClick={onClickD}>
56+
DDDDDDD
3757
</button>
38-
</div>
39-
</TogglePattern>
58+
</TogglePattern>
59+
</div>
4060
<ActiveElement />
4161
</div>
4262
);

package.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"src/",
1616
"lib/"
1717
],
18-
"version": "1.2.1",
18+
"version": "1.3.1",
1919
"description": "React Component that provide toggle pattern",
2020
"main": "lib/index.js",
2121
"directories": {
@@ -38,18 +38,20 @@
3838
"devDependencies": {
3939
"babel-cli": "^6.8.0",
4040
"babel-preset-es2015": "^6.6.0",
41-
"babel-preset-jsdoc-to-assert": "^1.0.1",
41+
"babel-preset-jsdoc-to-assert": "^4.0.0",
4242
"babel-preset-power-assert": "^1.0.0",
4343
"babel-preset-react": "^6.5.0",
4444
"babel-register": "^6.8.0",
4545
"enzyme": "^2.3.0",
46-
"mocha": "^2.4.5",
46+
"mocha": "^3.1.0",
4747
"power-assert": "^1.4.1",
4848
"react": "^15.0.2",
4949
"react-addons-test-utils": "^15.0.2",
5050
"react-dom": "^15.0.2"
5151
},
5252
"peerDependencies": {
5353
"react": ">=15.0.2"
54+
},
55+
"dependencies": {
5456
}
5557
}

src/ToggleAndDisplayPattern.js

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
const React = require("react");
2+
const findDOMNode = require("react-dom").findDOMNode;
3+
import {matchAnd} from "./utils/match-props";
4+
export default class ToggleAndDisplayPattern extends React.Component {
5+
constructor(...args) {
6+
super(...args);
7+
this.wrapper = null;
8+
this._activeChidlren = [];
9+
this._hiddenChildren = [];
10+
}
11+
12+
getFlagNames() {
13+
return Object.keys(this.props).filter(key => {
14+
return key !== "children";
15+
});
16+
}
17+
18+
/**
19+
* get components from `children` that matches key and value with own props.
20+
* @returns {ReactComponent[]}
21+
*/
22+
mapComponents() {
23+
const children = [].concat(this.props.children);
24+
const flagKeyNames = this.getFlagNames();
25+
return children.map((child, index) => {
26+
if (!child.props) {
27+
return null;
28+
}
29+
// all match
30+
if (matchAnd(flagKeyNames, this.props, child.props)) {
31+
const newProps = {
32+
key: index
33+
};
34+
newProps.ref = (c) => {
35+
if (typeof child.ref === 'function') {
36+
child.ref(c);
37+
}
38+
if (c) {
39+
this._activeChidlren.push(c);
40+
}
41+
};
42+
return React.cloneElement(child, newProps);
43+
} else {
44+
const newProps = {
45+
key: index
46+
};
47+
newProps.ref = (c) => {
48+
if (typeof child.ref === 'function') {
49+
child.ref(c);
50+
}
51+
if (c) {
52+
this._hiddenChildren.push(c);
53+
}
54+
};
55+
return React.cloneElement(child, newProps);
56+
}
57+
});
58+
}
59+
60+
componentWillUpdate() {
61+
this._activeChidlren = [];
62+
this._hiddenChildren = [];
63+
}
64+
65+
componentDidMount() {
66+
this._updatePattens();
67+
}
68+
69+
componentDidUpdate() {
70+
this._updatePattens()
71+
}
72+
73+
render() {
74+
const components = this.mapComponents();
75+
if (components.length === 0) {
76+
return null;
77+
}
78+
return <span
79+
className="TogglePattern ToggleAndDisplayPattern"
80+
ref={(c) => this.wrapper = c}>
81+
{components}
82+
</span>;
83+
}
84+
85+
_updatePattens() {
86+
const wrapper = findDOMNode(this.wrapper);
87+
let isActiveWrapper = false;
88+
// include focus element?
89+
if (wrapper) {
90+
const activeElement = document.activeElement;
91+
isActiveWrapper = wrapper.contains(activeElement);
92+
}
93+
this._activeChidlren.forEach(child => {
94+
const childDOM = findDOMNode(child);
95+
if (childDOM) {
96+
childDOM.hidden = false;
97+
}
98+
});
99+
this._hiddenChildren.forEach(child => {
100+
const childDOM = findDOMNode(child);
101+
if (childDOM) {
102+
childDOM.hidden = true;
103+
}
104+
});
105+
// move to focus
106+
if (isActiveWrapper && this._activeChidlren.length === 1) {
107+
const activeDOM = findDOMNode(this._activeChidlren[0]);
108+
if (activeDOM) {
109+
activeDOM.focus();
110+
}
111+
}
112+
}
113+
}

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
// LICENSE : MIT
22
"use strict";
3+
import ToggleAndDisplayPattern from "./ToggleAndDisplayPattern";
34
import ToggleAndPattern from "./ToggleAndPattern";
45
import ToggleOrPattern from "./ToggleOrPattern";
56
module.exports = {
67
// default: or pattern
78
TogglePattern: ToggleOrPattern,
9+
ToggleAndDisplayPattern,
810
ToggleOrPattern,
911
ToggleAndPattern
1012
};

src/utils/match-props.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// LICENSE : MIT
22
"use strict";
33
export function matchAnd(keys, parentProps, childProps) {
4-
const childKeys = Object.keys(childProps);
4+
const childKeys = childProps ? Object.keys(childProps) : [];
55
// all match
66
return keys.every(parentKey => {
77
return childKeys.some(childKey => {
@@ -11,7 +11,7 @@ export function matchAnd(keys, parentProps, childProps) {
1111
const parentValue = parentProps[parentKey];
1212
const childValue = childProps[childKey];
1313
if (childValue === parentValue) {
14-
return true
14+
return true;
1515
} else if (childValue === undefined && parentKey === true) {
1616
// <X attr />
1717
return true;
@@ -21,7 +21,7 @@ export function matchAnd(keys, parentProps, childProps) {
2121
});
2222
}
2323
export function matchOr(keys, parentProps, childProps) {
24-
const childKeys = Object.keys(childProps);
24+
const childKeys = childProps ? Object.keys(childProps) : [];
2525
// some match
2626
return keys.some(parentKey => {
2727
return childKeys.some(childKey => {

test/ToggleAndDisplayPattern-test.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const assert = require("power-assert");
2+
import React from "react";
3+
import {shallow} from 'enzyme';
4+
import ToggleAndDisplayPattern from "../src/ToggleAndDisplayPattern";
5+
class ComponentY extends React.Component {
6+
render() {
7+
return <div>Hidden</div>
8+
}
9+
}
10+
class ComponentX extends React.Component {
11+
render() {
12+
return <div>Visible</div>
13+
}
14+
}
15+
describe('<ToggleAndDisplayPattern />', () => {
16+
it('renders 1 <ComponentX /> components', () => {
17+
const result = shallow(<ToggleAndDisplayPattern isEditing={true}>
18+
<ComponentX isEditing/>
19+
<ComponentY/>
20+
</ToggleAndDisplayPattern>);
21+
assert.equal(result.html(), `<span class="TogglePattern ToggleAndDisplayPattern"><div>Visible</div><div>Hidden</div></span>`)
22+
;
23+
});
24+
});

0 commit comments

Comments
 (0)