├── .babelrc ├── .gitignore ├── README.md ├── lib └── index.js ├── package.json ├── src └── index.js └── test └── dom.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["@babel/preset-env", { "loose": true }], "@babel/preset-react"], 3 | "plugins":[ 4 | "@babel/plugin-proposal-class-properties" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | node_modules 5 | *.log 6 | TODOs.md 7 | TODO.md 8 | explorations 9 | test/e2e/reports 10 | test/e2e/screenshots 11 | coverage 12 | dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-propers 2 | 3 | > Select react doms , and update props. 4 | 5 | 6 | 7 | ### Usage 8 | 9 | ``` 10 | import React from "react" 11 | import ReactDOM from "react-dom" 12 | import Propers from "react-propers" 13 | 14 | ReactDOM.render( 15 | { 16 | switch(key){ 17 | case "aaa": 18 | return { 19 | className:"aaa" 20 | } 21 | case "bbb": 22 | return { 23 | className:"bbb" 24 | } 25 | case "ccc": 26 | return { 27 | className:"ccc" 28 | } 29 | case "ddd": 30 | return false 31 | } 32 | return props 33 | }}> 34 | {React=>( 35 | <> 36 |
111
37 |
222
38 |
333
39 |
444
40 | 41 | )} 42 |
43 | ) 44 | 45 | //out put 46 | 47 |
111
222
333
48 | ``` 49 | 50 | 51 | 52 | ### Install 53 | 54 | ``` 55 | npm install --save react-propers 56 | ``` 57 | 58 | ### API 59 | 60 | #### `selector : String | Array` 61 | 62 | > Support single selector and multi selector. 63 | 64 | #### `traverse : Function` 65 | 66 | > You can use [qverse](https://github.com/janryWang/qverse) to easily update props. 67 | 68 | ### LICENSE 69 | 70 | The MIT License (MIT) 71 | 72 | Copyright (c) 2018 JanryWang 73 | 74 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 75 | 76 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | exports.__esModule = true; 4 | exports.default = exports.Propers = void 0; 5 | 6 | var _react = _interopRequireDefault(require("react")); 7 | 8 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 9 | 10 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } 11 | 12 | function _inheritsLoose(subClass, superClass) { subClass.prototype.__proto__ = superClass && superClass.prototype; subClass.__proto__ = superClass; } 13 | 14 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 15 | 16 | var isArr = function isArr(val) { 17 | return Array.isArray(val); 18 | }; 19 | 20 | var isStr = function isStr(val) { 21 | return typeof val === "string"; 22 | }; 23 | 24 | var isFn = function isFn(fn) { 25 | return typeof fn === "function"; 26 | }; 27 | 28 | var getPathSegments = function getPathSegments(path) { 29 | if (isArr(path)) return path; 30 | 31 | if (isStr(path) && path) { 32 | return (path || "").trim().split(/\s*\.\s*/); 33 | } 34 | 35 | return []; 36 | }; 37 | 38 | var _createElement = _react.default.createElement; 39 | 40 | var getSelector = function getSelector(props, selector) { 41 | selector = Array.isArray(selector) ? selector : [selector]; 42 | 43 | for (var i = 0; i < selector.length; i++) { 44 | var item = props[selector[i]]; 45 | if (item !== undefined && item !== null) return item; 46 | } 47 | }; 48 | 49 | var Propers = 50 | /*#__PURE__*/ 51 | function (_React$Component) { 52 | function Propers() { 53 | return _React$Component.apply(this, arguments) || this; 54 | } 55 | 56 | var _proto = Propers.prototype; 57 | 58 | _proto.buildCreateElement = function buildCreateElement() { 59 | var _this$props = this.props, 60 | traverse = _this$props.traverse, 61 | selector = _this$props.selector, 62 | state = _this$props.state; 63 | return function (component, props) { 64 | for (var _len = arguments.length, children = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { 65 | children[_key - 2] = arguments[_key]; 66 | } 67 | 68 | if (!isFn(traverse)) return _createElement.apply(null, arguments); 69 | var $selector = props && getSelector(props, selector); 70 | var $props = $selector ? traverse(props, Object.defineProperties({}, { 71 | path: { 72 | get: function get() { 73 | return getPathSegments(String($selector)); 74 | } 75 | }, 76 | key: { 77 | value: $selector, 78 | writable: false 79 | }, 80 | payload: { 81 | value: props, 82 | writable: false 83 | }, 84 | index: { 85 | value: $selector, 86 | writable: false 87 | }, 88 | component: { 89 | value: component, 90 | writable: false 91 | }, 92 | state: { 93 | value: state, 94 | writable: false 95 | } 96 | })) : props; 97 | 98 | if ($selector) { 99 | if ($props && !$props["data-propers-hidden"]) { 100 | return _createElement.apply(void 0, [component, $props].concat(children)); 101 | } 102 | } else { 103 | return _createElement.apply(void 0, [component, $props].concat(children)); 104 | } 105 | }; 106 | }; 107 | 108 | _proto.render = function render() { 109 | var children = this.props.children; 110 | if (!isFn(children)) return children; 111 | this.react = this.react || _extends({}, _react.default, { 112 | createElement: this.buildCreateElement() 113 | }); 114 | return children(this.react); 115 | }; 116 | 117 | _inheritsLoose(Propers, _React$Component); 118 | 119 | return Propers; 120 | }(_react.default.Component); 121 | 122 | exports.Propers = Propers; 123 | 124 | _defineProperty(Propers, "defaultProps", { 125 | selector: "id" 126 | }); 127 | 128 | var _default = Propers; 129 | exports.default = _default; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-propers", 3 | "version": "0.1.5", 4 | "description": "", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": " cross-env NODE_ENV=test ava", 8 | "build": "babel src/index.js --out-dir lib", 9 | "precommit": "npm run build && lint-staged && npm run test && git add -A" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/janryWang/react-propers.git" 14 | }, 15 | "author": "janry", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/janryWang/react-propers/issues" 19 | }, 20 | "homepage": "https://github.com/janryWang/react-propers#readme", 21 | "devDependencies": { 22 | "@babel/cli": "^7.0.0-beta.46", 23 | "@babel/core": "^7.0.0-beta.46", 24 | "@babel/plugin-proposal-class-properties": "^7.0.0-beta.46", 25 | "@babel/preset-env": "^7.0.0-beta.46", 26 | "@babel/preset-react": "^7.0.0-beta.46", 27 | "@babel/register": "^7.0.0-beta.46", 28 | "ava": "^1.0.0-beta.4", 29 | "cross-env": "^5.1.4", 30 | "enzyme": "^3.3.0", 31 | "enzyme-adapter-react-16": "^1.1.1", 32 | "husky": "^0.14.3", 33 | "lint-staged": "^4.3.0", 34 | "prettier": "^1.11.x", 35 | "qverse": "^0.1.0", 36 | "react": "^16.3.2", 37 | "react-dom": "^16.3.2" 38 | }, 39 | "lint-staged": { 40 | "src/*.js": [ 41 | "prettier --write --tab-width 4 --no-semi", 42 | "git add" 43 | ], 44 | "dist/*.js": [ 45 | "prettier --write --tab-width 4 --no-semi", 46 | "git add" 47 | ], 48 | "test.js": [ 49 | "prettier --write --tab-width 4 --no-semi", 50 | "git add" 51 | ] 52 | }, 53 | "ava": { 54 | "require": [ 55 | "@babel/register" 56 | ], 57 | "files": [ 58 | "test/**/*.spec.js", 59 | "test/*.spec.js" 60 | ], 61 | "babel": { 62 | "testOptions": { 63 | "babelrc": false, 64 | "presets": [ 65 | [ 66 | "@babel/preset-env", 67 | { 68 | "loose": true 69 | } 70 | ], 71 | "@babel/preset-react" 72 | ], 73 | "plugins": [ 74 | "@babel/plugin-proposal-class-properties" 75 | ] 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | const isArr = val => Array.isArray(val) 4 | const isStr = val => typeof val === "string" 5 | const isFn = fn => typeof fn === "function" 6 | 7 | const getPathSegments = path => { 8 | if (isArr(path)) return path 9 | if (isStr(path) && path) { 10 | return (path || "").trim().split(/\s*\.\s*/) 11 | } 12 | return [] 13 | } 14 | 15 | const _createElement = React.createElement 16 | 17 | const getSelector = (props, selector) => { 18 | selector = Array.isArray(selector) ? selector : [selector] 19 | for (let i = 0; i < selector.length; i++) { 20 | let item = props[selector[i]] 21 | if (item !== undefined && item !== null) return item 22 | } 23 | } 24 | 25 | export class Propers extends React.Component { 26 | static defaultProps = { 27 | selector: "id" 28 | } 29 | 30 | buildCreateElement() { 31 | const { traverse, selector, state } = this.props 32 | return function(component, props, ...children) { 33 | if (!isFn(traverse)) return _createElement.apply(null, arguments) 34 | const $selector = props && getSelector(props, selector) 35 | const $props = $selector 36 | ? traverse( 37 | props, 38 | Object.defineProperties( 39 | {}, 40 | { 41 | path: { 42 | get: () => { 43 | return getPathSegments(String($selector)) 44 | } 45 | }, 46 | key: { 47 | value: $selector, 48 | writable: false 49 | }, 50 | payload: { 51 | value: props, 52 | writable: false 53 | }, 54 | index: { 55 | value: $selector, 56 | writable: false 57 | }, 58 | component: { 59 | value: component, 60 | writable: false 61 | }, 62 | state: { 63 | value: state, 64 | writable: false 65 | } 66 | } 67 | ) 68 | ) 69 | : props 70 | if ($selector) { 71 | if ($props && !$props["data-propers-hidden"]) { 72 | return _createElement(component, $props, ...children) 73 | } 74 | } else { 75 | return _createElement(component, $props, ...children) 76 | } 77 | } 78 | } 79 | 80 | render() { 81 | const { children } = this.props 82 | if (!isFn(children)) return children 83 | 84 | this.react = this.react || { 85 | ...React, 86 | createElement: this.buildCreateElement() 87 | } 88 | 89 | return children(this.react) 90 | } 91 | } 92 | 93 | export default Propers 94 | -------------------------------------------------------------------------------- /test/dom.spec.js: -------------------------------------------------------------------------------- 1 | import test from "ava" 2 | import React from "react" 3 | import Enzyme, { shallow } from "enzyme" 4 | import Adapter from "enzyme-adapter-react-16" 5 | import Propers from "../src/index" 6 | import qverse from "qverse" 7 | 8 | Enzyme.configure({ adapter: new Adapter() }) 9 | 10 | const testAll = (cases)=>{ 11 | cases.forEach((_case,index)=>{ 12 | _case && test(`${index+1}th case.`,(t)=>{ 13 | const dom = shallow( 14 | 17 | {_case.render} 18 | 19 | ) 20 | t.is(dom.html(),_case.equal) 21 | }) 22 | }) 23 | } 24 | 25 | testAll([ 26 | { 27 | render(React){ 28 | return
lalalalala
29 | }, 30 | traverse($){ 31 | $("*").display(false) 32 | }, 33 | equal:"
" 34 | }, 35 | { 36 | render(React){ 37 | return (
38 |
lalalalala
39 |
hahahahaha
40 |
) 41 | }, 42 | traverse($){ 43 | $("*").produce((props)=>{ 44 | props.className = "123" 45 | }) 46 | }, 47 | equal:'
lalalalala
hahahahaha
' 48 | } 49 | ]) 50 | --------------------------------------------------------------------------------