diff --git a/README.md b/README.md index 9d0454a..a66b3b2 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ Install with [npm](https://www.npmjs.com/): ## Usage +`react-toggle-pattern` provide three components. + +- `` or pattern. This is same with `` +- `` or pattern +- `` and pattern + Put `` into ``. ```js @@ -38,6 +44,51 @@ It means that - `anyAttribute` is any name. - `anyValue` is any type. +`` and `` has same interface. + +### OR AND pattern + +#### OR + +`` filter child components by **OR** matching. + +```js + + + + +``` + +Result to: + +```html +
+ + +
+``` + +Both components are **or** match with TogglePattern. + +#### AND + +`` filter child components by **AND** matching. + +```js + + + + +``` + +Result to: + +```html + +``` + +`` is not **and** match with TogglePattern. + ### Example Show component that has truly attribute with `` @@ -88,7 +139,7 @@ Show component**s** that match attribute and value with ` ``` -Result to `
` +Result to `
` ----- @@ -103,6 +154,31 @@ Not show when not match Result to `null`. +------ + +OR match + +```js + + + + +``` + +Result to `
Visible
Hidden
`. + +------ + +And match + +````js + + + + +``` + +Result to ``. ## Changelog diff --git a/package.json b/package.json index d28034e..7f6144e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ ], "version": "1.1.1", "description": "React Component that provide toggle pattern", - "main": "lib/react-toggle-pattern.js", + "main": "lib/index.js", "directories": { "test": "test" }, diff --git a/src/react-toggle-pattern.js b/src/ToggleAndPattern.js similarity index 60% rename from src/react-toggle-pattern.js rename to src/ToggleAndPattern.js index 630273b..666f84e 100644 --- a/src/react-toggle-pattern.js +++ b/src/ToggleAndPattern.js @@ -1,10 +1,12 @@ // LICENSE : MIT "use strict"; const React = require("react"); - -export class TogglePattern extends React.Component { +import {matchAnd} from "./utils/match-props"; +export default class ToggleAndPattern extends React.Component { getFlagNames() { - return Object.keys(this.props); + return Object.keys(this.props).filter(key => { + return key !== "children"; + }); } /** @@ -19,14 +21,8 @@ export class TogglePattern extends React.Component { if (!child.props) { return false; } - const childKeys = Object.keys(child.props); - return childKeys.some(childKey => { - return flagKeyNames.some(parentKey => { - const parentValue = this.props[parentKey]; - const childValue = child.props[childKey]; - return childValue === parentValue; - }); - }); + // all match + return matchAnd(flagKeyNames, this.props, child.props); }); }; @@ -38,7 +34,7 @@ export class TogglePattern extends React.Component { if (components.length === 1) { return components[0]; } - return
+ return
{components}
; } diff --git a/src/ToggleOrPattern.js b/src/ToggleOrPattern.js new file mode 100644 index 0000000..0cf47e3 --- /dev/null +++ b/src/ToggleOrPattern.js @@ -0,0 +1,41 @@ +// LICENSE : MIT +"use strict"; +const React = require("react"); +import {matchOr} from "./utils/match-props"; +export default class ToggleOrPattern extends React.Component { + getFlagNames() { + return Object.keys(this.props).filter(key => { + return key !== "children"; + }); + } + + /** + * get components from `children` that matches key and value with own props. + * @returns {ReactComponent[]} + */ + getMatchedComponent() { + const children = [].concat(this.props.children); + const flagKeyNames = this.getFlagNames(); + return children.filter(child => { + // ignore text child + if (!child.props) { + return false; + } + // all match + return matchOr(flagKeyNames, this.props, child.props); + }); + }; + + render() { + const components = this.getMatchedComponent(); + if (components.length === 0) { + return null; + } + if (components.length === 1) { + return components[0]; + } + return
+ {components} +
; + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..0d2bde2 --- /dev/null +++ b/src/index.js @@ -0,0 +1,10 @@ +// LICENSE : MIT +"use strict"; +import ToggleAndPattern from "./ToggleAndPattern"; +import ToggleOrPattern from "./ToggleOrPattern"; +module.exports = { + // default: or pattern + TogglePattern: ToggleOrPattern, + ToggleOrPattern, + ToggleAndPattern +}; \ No newline at end of file diff --git a/src/utils/match-props.js b/src/utils/match-props.js new file mode 100644 index 0000000..e81e096 --- /dev/null +++ b/src/utils/match-props.js @@ -0,0 +1,37 @@ +// LICENSE : MIT +"use strict"; +export function matchAnd(keys, parentProps, childProps) { + const childKeys = Object.keys(childProps); + // all match + return keys.every(parentKey => { + return childKeys.some(childKey => { + const parentValue = parentProps[parentKey]; + const childValue = childProps[childKey]; + if (childValue === parentValue) { + return true + } else if (childValue === undefined && parentKey === true) { + // + return true; + } + return false; + }); + }); +} +export function matchOr(keys, parentProps, childProps) { + const childKeys = Object.keys(childProps); + // some match + return keys.some(parentKey => { + return childKeys.some(childKey => { + const parentValue = parentProps[parentKey]; + const childValue = childProps[childKey]; + if (childValue === parentValue) { + return true + } else if (childValue === undefined && parentKey === true) { + // + return true; + } + return false; + }); + }); + +} \ No newline at end of file diff --git a/test/ToggleAndPattern-test.js b/test/ToggleAndPattern-test.js new file mode 100644 index 0000000..c1e91b4 --- /dev/null +++ b/test/ToggleAndPattern-test.js @@ -0,0 +1,83 @@ +const assert = require("power-assert"); +import React from "react"; +import {shallow} from 'enzyme'; +import ToggleAndPattern from "../src/ToggleAndPattern"; +class ComponentY extends React.Component { + render() { + return
Hidden
+ } +} +class ComponentX extends React.Component { + render() { + return
Visible
+ } +} +describe('', () => { + it('renders 1 components', () => { + const result = shallow( + + + ); + assert(result.is(ComponentX)); + }); + it('renders 1 components', () => { + const result = shallow( + + + ); + assert(result.is(ComponentY)); + }); + it('renders 0 components', () => { + const result = shallow( + + + ); + assert(result.node === null); + }); + it('renders 2 components', () => { + const wrapper = shallow( + + + ); + const result = wrapper.find(ComponentX); + assert(result.length === 2); + assert.equal(wrapper.html(), `
Visible
Visible
`) + }); + it('no renders components', () => { + const wrapper = shallow( + + ); + const result = wrapper.find(ComponentX); + assert(result.length === 0); + }); + + it('match any type value', () => { + const wrapper = shallow( + + + ); + assert(wrapper.is(ComponentX)); + + const symbol = {}; + const wrapper1 = shallow( + + + ); + assert(wrapper1.is(ComponentX)); + }); + it('safe handling mixed text', () => { + const wrapper = shallow( + + text + + ); + assert(wrapper.is(ComponentX)); + }); + it('render match And pattern', () => { + const wrapper = shallow( + + + ); + assert(wrapper.is(ComponentX)); + }); +}); diff --git a/test/ToggleOrPattern-test.js b/test/ToggleOrPattern-test.js new file mode 100644 index 0000000..a428610 --- /dev/null +++ b/test/ToggleOrPattern-test.js @@ -0,0 +1,88 @@ +const assert = require("power-assert"); +import React from "react"; +import {shallow} from 'enzyme'; +import ToggleOrPattern from "../src/ToggleOrPattern"; +class ComponentY extends React.Component { + render() { + return
Hidden
+ } +} +class ComponentX extends React.Component { + render() { + return
Visible
+ } +} +describe('', () => { + it('renders 1 components', () => { + const result = shallow( + + + ); + assert(result.is(ComponentX)); + }); + it('renders 1 components', () => { + const result = shallow( + + + ); + assert(result.is(ComponentY)); + }); + it('renders 0 components', () => { + const result = shallow( + + + ); + assert(result.node === null); + }); + it('renders 2 components', () => { + const wrapper = shallow( + + + ); + const result = wrapper.find(ComponentX); + assert(result.length === 2); + assert.equal(wrapper.html(), `
Visible
Visible
`) + }); + it('no renders components', () => { + const wrapper = shallow( + + ); + const result = wrapper.find(ComponentX); + assert(result.length === 0); + }); + + it('match any type value', () => { + const wrapper = shallow( + + + ); + assert(wrapper.is(ComponentX)); + + const symbol = {}; + const wrapper1 = shallow( + + + ); + assert(wrapper1.is(ComponentX)); + }); + it('safe handling mixed text', () => { + const wrapper = shallow( + + text + + ); + assert(wrapper.is(ComponentX)); + }); + it('render match Or pattern', () => { + const wrapper = shallow( + + + ); + const x = wrapper.find(ComponentX); + assert(x.length === 1); + const y = wrapper.find(ComponentX); + assert(y.length === 1); + assert.equal(wrapper.html(), `
Visible
Hidden
`) + + }); +}); diff --git a/test/react-toggle-pattern-test.js b/test/react-toggle-pattern-test.js index 3ce86b2..96e09ca 100644 --- a/test/react-toggle-pattern-test.js +++ b/test/react-toggle-pattern-test.js @@ -1,7 +1,7 @@ const assert = require("power-assert"); import React from "react"; import {shallow} from 'enzyme'; -import {TogglePattern} from "../src/react-toggle-pattern"; +import {TogglePattern} from "../src/index"; class ComponentY extends React.Component { render() { return
Hidden
@@ -41,7 +41,7 @@ describe('', () => { ); const result = wrapper.find(ComponentX); assert(result.length === 2); - assert.equal(wrapper.html(), `
Visible
Visible
`) + assert.equal(wrapper.html(), `
Visible
Visible
`) }); it('no renders components', () => { const wrapper = shallow(