From 5b790d3cb69db566ef497470bc5610a65655ece3 Mon Sep 17 00:00:00 2001 From: azu Date: Thu, 19 May 2016 20:54:03 +0900 Subject: [PATCH 1/2] feat(component): add ``, `` components These component provide "and", "or" matching mechanism. `` is still or matching. --- README.md | 78 +++++++++++++++- package.json | 2 +- ...-toggle-pattern.js => ToggleAndPattern.js} | 20 ++--- src/ToggleOrPattern.js | 41 +++++++++ src/index.js | 10 +++ src/utils/match-props.js | 37 ++++++++ test/ToggleAndPattern-test.js | 83 +++++++++++++++++ test/ToggleOrPattern-test.js | 88 +++++++++++++++++++ test/react-toggle-pattern-test.js | 4 +- 9 files changed, 347 insertions(+), 16 deletions(-) rename src/{react-toggle-pattern.js => ToggleAndPattern.js} (60%) create mode 100644 src/ToggleOrPattern.js create mode 100644 src/index.js create mode 100644 src/utils/match-props.js create mode 100644 test/ToggleAndPattern-test.js create mode 100644 test/ToggleOrPattern-test.js diff --git a/README.md b/README.md index 9d0454a..c76a69b 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..2a8d8d1 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..7b82ee4 --- /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..02ba1e3 --- /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..bfd0207 --- /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..27b211a 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( From 50456fc8885424fcfea250e9d86f86a493df2537 Mon Sep 17 00:00:00 2001 From: azu Date: Thu, 19 May 2016 21:55:01 +0900 Subject: [PATCH 2/2] chore(component): add always "TogglePattern" className --- README.md | 6 +++--- src/ToggleAndPattern.js | 2 +- src/ToggleOrPattern.js | 2 +- test/ToggleAndPattern-test.js | 2 +- test/ToggleOrPattern-test.js | 4 ++-- test/react-toggle-pattern-test.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c76a69b..a66b3b2 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ It means that Result to: ```html -
+
@@ -139,7 +139,7 @@ Show component**s** that match attribute and value with ` ``` -Result to `
` +Result to `
` ----- @@ -165,7 +165,7 @@ OR match ``` -Result to `
Visible
Hidden
`. +Result to `
Visible
Hidden
`. ------ diff --git a/src/ToggleAndPattern.js b/src/ToggleAndPattern.js index 2a8d8d1..666f84e 100644 --- a/src/ToggleAndPattern.js +++ b/src/ToggleAndPattern.js @@ -34,7 +34,7 @@ export default class ToggleAndPattern extends React.Component { if (components.length === 1) { return components[0]; } - return
+ return
{components}
; } diff --git a/src/ToggleOrPattern.js b/src/ToggleOrPattern.js index 7b82ee4..0cf47e3 100644 --- a/src/ToggleOrPattern.js +++ b/src/ToggleOrPattern.js @@ -34,7 +34,7 @@ export default class ToggleOrPattern extends React.Component { if (components.length === 1) { return components[0]; } - return
+ return
{components}
; } diff --git a/test/ToggleAndPattern-test.js b/test/ToggleAndPattern-test.js index 02ba1e3..c1e91b4 100644 --- a/test/ToggleAndPattern-test.js +++ b/test/ToggleAndPattern-test.js @@ -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( diff --git a/test/ToggleOrPattern-test.js b/test/ToggleOrPattern-test.js index bfd0207..a428610 100644 --- a/test/ToggleOrPattern-test.js +++ b/test/ToggleOrPattern-test.js @@ -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( @@ -82,7 +82,7 @@ describe('', () => { assert(x.length === 1); const y = wrapper.find(ComponentX); assert(y.length === 1); - assert.equal(wrapper.html(), `
Visible
Hidden
`) + assert.equal(wrapper.html(), `
Visible
Hidden
`) }); }); diff --git a/test/react-toggle-pattern-test.js b/test/react-toggle-pattern-test.js index 27b211a..96e09ca 100644 --- a/test/react-toggle-pattern-test.js +++ b/test/react-toggle-pattern-test.js @@ -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(