├── .yo-rc.json ├── coverage ├── lcov-report │ ├── sort-arrow-sprite.png │ ├── prettify.css │ ├── src │ │ ├── index.js.html │ │ ├── i18n.js.html │ │ ├── SuperComponent.js.html │ │ ├── index.html │ │ ├── util.js.html │ │ ├── Search.jsx.html │ │ └── CascadeSubmenu.jsx.html │ ├── index.html │ ├── sorter.js │ ├── base.css │ └── prettify.js └── lcov.info ├── tests ├── index.js ├── options.js └── CascadeSelect.spec.jsx ├── src ├── index.js ├── i18n.js ├── SuperComponent.js ├── util.js ├── Search.jsx ├── CascadeSubmenu.jsx ├── CascadeSelect.less └── CascadeSelect.jsx ├── .gitignore ├── .npmignore ├── demo ├── index.js ├── CascadeSelectDemo.less └── CascadeSelectDemo.jsx ├── .eslintrc.json ├── .travis.yml ├── index.html ├── package.json ├── HISTORY.md └── README.md /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-uxcore": {} 3 | } -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WisestCoder/uxcore-cascade-select/HEAD/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * only require other specs here 3 | */ 4 | 5 | const req = require.context('.', false, /\.spec\.js(x)?$/); 6 | req.keys().forEach(req); -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component for uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | module.exports = require('./CascadeSelect'); 10 | -------------------------------------------------------------------------------- /src/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'zh-cn': { 3 | placeholder: '请选择', 4 | confirm: '确定', 5 | alreadyChoosed: '已选择', 6 | }, 7 | 'en-us': { 8 | placeholder: 'Please select', 9 | confirm: 'OK', 10 | alreadyChoosed: 'Choosed', 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.log 3 | .idea/ 4 | .ipr 5 | .iws 6 | *~ 7 | ~* 8 | *.diff 9 | *.patch 10 | *.bak 11 | .DS_Store 12 | Thumbs.db 13 | .project 14 | .*proj 15 | .svn/ 16 | *.swp 17 | *.swo 18 | *.pyc 19 | *.pyo 20 | .build 21 | node_modules 22 | _site 23 | sea-modules 24 | spm_modules 25 | .cache 26 | .happypack 27 | dist 28 | build 29 | assets/**/*.css 30 | .vscode -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bower_components/ 2 | *.cfg 3 | node_modules/ 4 | nohup.out 5 | *.iml 6 | .idea/ 7 | .ipr 8 | .iws 9 | *~ 10 | ~* 11 | *.diff 12 | *.log 13 | *.patch 14 | *.bak 15 | .DS_Store 16 | Thumbs.db 17 | .project 18 | .*proj 19 | .svn/ 20 | *.swp 21 | out/ 22 | .build 23 | .happypack 24 | node_modules 25 | _site 26 | sea-modules 27 | spm_modules 28 | .cache 29 | dist -------------------------------------------------------------------------------- /demo/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component Demo for uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | const ReactDOM = require('react-dom'); 10 | const React = require('react'); 11 | const Demo = require('./CascadeSelectDemo'); 12 | ReactDOM.render(, document.getElementById('UXCoreDemo')); 13 | -------------------------------------------------------------------------------- /src/SuperComponent.js: -------------------------------------------------------------------------------- 1 | const React = require('react'); 2 | 3 | class SuperComponent extends React.Component { 4 | prefixCls(name) { 5 | const { prefixCls } = this.props; 6 | return name.split(/\s/).map(i => `${prefixCls}-${i}`).join(' '); 7 | } 8 | } 9 | 10 | SuperComponent.propTypes = { 11 | prefixCls: React.PropTypes.string, 12 | }; 13 | 14 | export default SuperComponent; 15 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "parser": "babel-eslint", 7 | "env": { 8 | "browser": true 9 | }, 10 | "rules": { 11 | "import/no-extraneous-dependencies": "off", 12 | "react/jsx-no-bind": "off" 13 | }, 14 | "globals": { 15 | "it": true, 16 | "describe": true, 17 | "beforeEach": true, 18 | "afterEach": true 19 | } 20 | } -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | sudo: false 4 | 5 | addons: 6 | apt: 7 | packages: 8 | - xvfb 9 | 10 | notification: 11 | email: 12 | - wsj7552715@hotmail.com 13 | 14 | node_js: 15 | - 6.9.0 16 | 17 | before_install: 18 | - | 19 | if ! git diff --name-only $TRAVIS_COMMIT_RANGE | grep -qve '(\.md$)|(\.html$)' 20 | then 21 | echo "Only docs were updated, stopping build process." 22 | exit 23 | fi 24 | phantomjs --version 25 | install: 26 | - export DISPLAY=':99.0' 27 | - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 28 | - npm install 29 | 30 | 31 | script: 32 | - | 33 | if [ "$TEST_TYPE" = test ]; then 34 | npm test 35 | else 36 | npm run $TEST_TYPE 37 | fi 38 | env: 39 | matrix: 40 | - TEST_TYPE=test 41 | - TEST_TYPE=coverage 42 | - TEST_TYPE=saucelabs 43 | 44 | matrix: 45 | allow_failures: 46 | - env: "TEST_TYPE=saucelabs" -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | uxcore-cascade-select 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/CascadeSelectDemo.less: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component Demo Style for Uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | @import "../node_modules/kuma-base/theme/orange"; 10 | @import "../src/CascadeSelect.less"; 11 | 12 | body { 13 | background-color: #fff; 14 | padding: 50px; 15 | font-family: Verdana, Geneva, Tahoma, sans-serif; 16 | } 17 | 18 | .demo-wrap { 19 | width: 800px; 20 | margin-right: 20px; 21 | } 22 | 23 | small { 24 | color: lightgray; 25 | } 26 | 27 | // .kuma-cascader-submenu-empty, 28 | // .kuma-dropdown-menu-submenu { 29 | // width: 400px; 30 | // } 31 | 32 | h2 { 33 | font-size: 16px; 34 | font-weight: normal; 35 | margin: 20px 0 10px; 36 | color: #555; 37 | } 38 | 39 | // button { 40 | // padding: 2px 4px; 41 | // border-radius: 4px; 42 | // background-color: #fff; 43 | // border: 1px solid #ccc; 44 | // &:active { 45 | // background-color: #f5f5f5; 46 | // } 47 | // } 48 | -------------------------------------------------------------------------------- /tests/options.js: -------------------------------------------------------------------------------- 1 | export const options = [{ 2 | value: 'alibaba', 3 | label: '阿里巴巴', 4 | children: [{ 5 | value: 'platform', 6 | label: '信息平台', 7 | children: [{ 8 | value: 'fe', 9 | label: '前端开发', 10 | }, { 11 | value: 'test', 12 | label: '测试', 13 | }], 14 | }], 15 | }, { 16 | value: 'beijing', 17 | label: '日本', 18 | children: [{ 19 | value: 'xicheng', 20 | label: '西城', 21 | children: [ 22 | // { 23 | // value: 'zhonggc', 24 | // label: '中观村大街', 25 | // }, 26 | ], 27 | }], 28 | }, { 29 | value: 'tianjin', 30 | label: '天津', 31 | children: [{ 32 | value: 'heping', 33 | label: '和平区', 34 | children: [{ 35 | value: 'nanjinglu', 36 | label: '南京路', 37 | }], 38 | }, { 39 | value: 'hexi', 40 | label: '河西区', 41 | children: [{ 42 | value: 'dagu', 43 | label: '大沽路', 44 | }], 45 | }], 46 | }, { 47 | value: 'zhejiang', 48 | label: '浙江', 49 | children: [{ 50 | value: 'hangzhou', 51 | label: '杭州', 52 | children: [{ 53 | value: 'xihu', 54 | label: '西湖', 55 | }], 56 | }], 57 | }, { 58 | value: 'jiangsu', 59 | label: '江苏', 60 | children: [{ 61 | value: 'nanjing', 62 | label: '南京', 63 | children: [{ 64 | value: 'zhonghuamen', 65 | label: '中华门', 66 | }], 67 | }], 68 | }]; 69 | 70 | export const asyncOptions = [ 71 | { 72 | value: '0', 73 | label: '0', 74 | }, 75 | { 76 | value: '1', 77 | label: '1', 78 | }, 79 | ]; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uxcore-cascade-select", 3 | "version": "0.6.4", 4 | "description": "Cascade select field", 5 | "repository": "https://github.com/uxcore/uxcore-cascade-select.git", 6 | "author": "changming", 7 | "main": "build/index.js", 8 | "scripts": { 9 | "start": "uxcore-tools run start", 10 | "server": "uxcore-tools run server", 11 | "lint": "uxcore-tools run lint", 12 | "build": "uxcore-tools run build", 13 | "test": "uxcore-tools run test", 14 | "coverage": "uxcore-tools run coverage", 15 | "pub": "uxcore-tools run pub", 16 | "dep": "uxcore-tools run dep", 17 | "tnpm-dep": "uxcore-tools run tnpm-dep", 18 | "chrome": "uxcore-tools run chrome", 19 | "browsers": "uxcore-tools run browsers", 20 | "saucelabs": "uxcore-tools run saucelabs", 21 | "update": "uxcore-tools run update", 22 | "tnpm-update": "uxcore-tools run tnpm-update" 23 | }, 24 | "bugs": { 25 | "url": "http://github.com/uxcore/uxcore-cascade-select/issues" 26 | }, 27 | "keywords": [ 28 | "react", 29 | "react-component", 30 | "uxcore-cascade-select", 31 | "CascadeSelect", 32 | "component" 33 | ], 34 | "devDependencies": { 35 | "console-polyfill": "^0.2.2", 36 | "enzyme": "^3.0.0", 37 | "enzyme-adapter-react-15": "^1.0.5", 38 | "es5-shim": "^4.5.8", 39 | "expect.js": "~0.3.1", 40 | "jquery": "^3.2.1", 41 | "kuma-base": "1.x", 42 | "react": "15.x", 43 | "react-dom": "15.x", 44 | "react-test-renderer": "15.x", 45 | "uxcore-kuma": "*", 46 | "uxcore-tools": "0.2.x" 47 | }, 48 | "dependencies": { 49 | "classnames": "^2.1.2", 50 | "lie": "^3.1.1", 51 | "object-assign": "^4.0.0", 52 | "prop-types": "15.x", 53 | "uxcore-button": "^0.4.10", 54 | "uxcore-dropdown": "^0.4.1", 55 | "uxcore-select2": "^0.4.17" 56 | }, 57 | "contributors": [], 58 | "license": "MIT" 59 | } -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | const supportNativeFind = !!Array.prototype.find; 2 | 3 | const find = (() => { 4 | if (supportNativeFind) { 5 | return (ary, ...params) => ary.find(...params); 6 | } 7 | return (ary, predicate) => { 8 | if (this === null) { 9 | throw new TypeError('find called on null or undefined'); 10 | } 11 | if (typeof predicate !== 'function') { 12 | throw new TypeError('predicate must be a function'); 13 | } 14 | const length = ary.length >>> 0; 15 | const ctx = arguments[2]; 16 | let value; 17 | 18 | for (let i = 0; i < length; i++) { 19 | value = ary[i]; 20 | if (predicate.call(ctx, value, i, ary)) { 21 | return value; 22 | } 23 | } 24 | return undefined; 25 | }; 26 | })(); 27 | 28 | const deepCopy = o => JSON.parse(JSON.stringify(o)); 29 | 30 | const getArrayLeafItemContains = (options, keyArr) => { 31 | let position; 32 | let isFound = false; 33 | const selectedOptions = []; 34 | function recursion(opts, pos = '0') { 35 | opts.forEach((opt, index) => { 36 | if (isFound) return; 37 | if (`${keyArr[0]}_` === `${opt.value}_`) { 38 | position = `${pos}-${index}`; 39 | isFound = true; 40 | } 41 | if (opt.children) { 42 | recursion(opt.children, `${pos}-${index}`); 43 | } 44 | }); 45 | } 46 | recursion(options); 47 | if (!position) return []; 48 | let parents = options; 49 | position.split('-').slice(1).forEach((pos) => { 50 | selectedOptions.push(parents[pos]); 51 | parents = parents[pos].children; 52 | }); 53 | 54 | return selectedOptions; 55 | }; 56 | 57 | const getOptions = (options, value = [], level = 0) => { 58 | if (level === 0 && options) { 59 | return options; 60 | } 61 | if (value.length) { 62 | for (let i = 0, l = options.length; i < l; i++) { 63 | if (`${options[i].value}_` === `${value[0]}_`) { 64 | return getOptions(options[i].children, value.slice(1), level - 1); 65 | } 66 | } 67 | } 68 | return []; 69 | }; 70 | 71 | export default { 72 | find, 73 | getArrayLeafItemContains, 74 | deepCopy, 75 | getOptions, 76 | }; 77 | -------------------------------------------------------------------------------- /src/Search.jsx: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | const Search = ({ 4 | text, 5 | disabled, 6 | placeholder, 7 | searchOption, 8 | value, 9 | onValueChange, 10 | onSearchResultChange, 11 | }) => ( 12 | { 21 | const keywords = e.target.value; 22 | // 修复IE11下bug 23 | if (value === null && text === '' && keywords === '') { 24 | onValueChange(null); 25 | } else { 26 | onValueChange(keywords); 27 | } 28 | if (searchOption) { 29 | searchOption.doSearch(keywords, (searchResult) => { 30 | onSearchResultChange(searchResult); 31 | }); 32 | } 33 | }} 34 | /> 35 | ); 36 | 37 | Search.propTypes = { 38 | value: PropTypes.string, 39 | text: PropTypes.string, 40 | disabled: PropTypes.bool, 41 | placeholder: PropTypes.string, 42 | searchOption: PropTypes.object, 43 | onSearchResultChange: PropTypes.func, 44 | onValueChange: PropTypes.func, 45 | }; 46 | 47 | Search.renderResult = (result, onSelect) => ( 48 |
58 | 78 |
79 | ); 80 | 81 | export default Search; 82 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/index.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / src/ index.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 1/1 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 1/1 41 |
42 |
43 |
44 |
45 |

46 | 
80 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12  58 |   59 |   60 |   61 |   62 |   63 |   64 |   65 |   66 |   67 | 68 |  
'use strict';
69 |  
70 | /**
71 |  * CascadeSelect Component for uxcore
72 |  * @author changming
73 |  *
74 |  * Copyright 2015-2017, Uxcore Team, Alinw.
75 |  * All rights reserved.
76 |  */
77 |  
78 | module.exports = require('./CascadeSelect');
79 |  
81 |
82 |
83 | 87 | 88 | 89 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/i18n.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/i18n.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / src/ i18n.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 1/1 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 1/1 41 |
42 |
43 |
44 |
45 |

 46 | 
 89 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15  61 |   62 | 63 |   64 |   65 |   66 |   67 |   68 |   69 |   70 |   71 |   72 |   73 |   74 |  
'use strict';
 75 |  
 76 | module.exports = {
 77 |   'zh-cn': {
 78 |     placeholder: '请选择',
 79 |     confirm: '确定',
 80 |     alreadyChoosed: '已选择'
 81 |   },
 82 |   'en-us': {
 83 |     placeholder: 'Please select',
 84 |     confirm: 'OK',
 85 |     alreadyChoosed: 'Choosed'
 86 |   }
 87 | };
 88 |  
90 |
91 |
92 | 96 | 97 | 98 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 87.7% 24 | Statements 25 | 499/569 26 |
27 |
28 | 74.79% 29 | Branches 30 | 264/353 31 |
32 |
33 | 80.73% 34 | Functions 35 | 88/109 36 |
37 |
38 | 88.55% 39 | Lines 40 | 441/498 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
src/
87.7%499/56974.79%264/35380.73%88/10988.55%441/498
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # history 2 | 3 | ## 0.6.4 4 | 5 | * `FIXED`: placeholder color follow Select2 placeholder color. 6 | 7 | ## 0.6.3 8 | 9 | * `FIXED`: Could not occur onChange by clicking clear button when props.isMustSelectLeaf is true. 10 | 11 | ## 0.6.2 12 | 13 | * `FIXED`: get selectedOptions error 14 | 15 | ## 0.6.1 16 | 17 | * `FIXED`: fixed selectedOptions[0].hasOwnProperty error 18 | 19 | ## 0.6.0 20 | 21 | * `FIXED`: modified disabled style priority. 22 | * `CHANGED`: updated dropdown dom structure and style. 23 | 24 | ## 0.5.8 25 | 26 | * `FIXED`: revert to 0.5.6 27 | 28 | ## 0.5.7 29 | 30 | * `FIXED`: modified disabled style priority. 31 | 32 | ## 0.5.6 33 | 34 | * `FIXED`: could not clear display-value from outside. 35 | 36 | ## 0.5.5 37 | 38 | * `UPDATE`: optimized visual display 39 | 40 | ## 0.5.4 41 | 42 | * `FIX`: the component's height has 2 px more in the small or middle size mode. 43 | 44 | ## 0.5.3 45 | 46 | * `FIX`: the selection has no display result after clear the first selection. 47 | 48 | ## 0.5.2 49 | 50 | * `FIX`: input has duplicated onChange event in IE11 browser under search mode. 51 | 52 | ## 0.5.1 53 | 54 | * `Add`: searchOption prop 55 | * `Add`: 'search' option of displayMode 56 | * `FIX`: give value before options could not display the result 57 | 58 | ## 0.5.0 59 | 60 | * `Add`: onSelect prop 61 | 62 | ## 0.4.1 63 | 64 | * `Add`: isMustSelectLeaf: whether or not to select the leaf option 65 | 66 | ## 0.4.0 67 | 68 | * `UPDATE`: react 15 69 | 70 | ## 0.3.5 71 | 72 | * `Add`: size prop 73 | 74 | ## 0.3.4 75 | 76 | * `ADD`: columnWidth prop, remove dropDownWidth prop 77 | 78 | ## 0.3.3 79 | 80 | * `FIXED`: hover and focus color. 81 | 82 | ## 0.3.2 83 | 84 | * `FIXED`: arrow color. 85 | 86 | ## 0.3.1 87 | 88 | * `FIXED`: default color is transparent. 89 | 90 | ## 0.3.0 91 | 92 | * `New Feature`: add select display mode. 93 | 94 | ## 0.2.11 95 | 96 | * `ADD`: trigger onChange when on click `the ok button`. 97 | 98 | ## 0.2.10 99 | 100 | * `FIXED`: display selection text immediately when the `changeOnSelect=true` 101 | 102 | ## 0.2.9 103 | 104 | * `FIXED`: `dropDownWidth` prop type check. 105 | 106 | ## 0.2.8 107 | 108 | * `NEW`: new prop, `dropDownWidth`(number): define the dropdown width. 109 | 110 | ## 0.2.7 111 | 112 | * `NEW`: new display mode, `miniMode=false` will display the rich style with button and selection. 113 | 114 | ## 0.2.3 115 | 116 | * `CHANGED` update i18n. 117 | 118 | ## 0.2.2 119 | 120 | * `NEW`: Pass the only `[key]` as the value will be treated as the choosed leaf **key**. 121 | * `FIXED`: `e.stopPropagation()` when click the clear button. 122 | 123 | ## 0.2.1 124 | 125 | * `NEW` add new prop `getPopupContainer` 126 | 127 | ## 0.2.0 128 | 129 | * `CHANGED` update `uxcore-dropdown` to `~0.4.0` 130 | 131 | ## 0.1.12 132 | 133 | * `FIXED` even if default value is error, options should show correctly [#11](https://github.com/uxcore/uxcore-cascade-select/issues/11) 134 | 135 | ## 0.1.11 136 | 137 | * `FIXED` throw error if options cannot match value [#9](https://github.com/uxcore/uxcore-cascade-select/issues/9) 138 | 139 | ## 0.1.10 140 | 141 | * `CHANGED` another efficient way to fix issue #7 142 | 143 | ## 0.1.9 144 | 145 | * `CHANGED` subMenu won't be hide before selected options's length is larger than cascadeSize when cascadeSize is not equal to options level. [#7](https://github.com/uxcore/uxcore-cascade-select/issues/7) 146 | 147 | ## 0.1.8 148 | 149 | * `FIXED` add support for browsers that does not implement array.prototype.find. 150 | 151 | ## 0.1.7 152 | 153 | * `CHANGED` beforeRender default value optimazition 154 | 155 | ## 0.1.6 156 | 157 | * `FIXED` input height bug 158 | 159 | ## 0.1.5 160 | 161 | * `FIXED` fix value/onChange logic 162 | 163 | ## 0.1.4 164 | 165 | * `CHANGED` remove dependency rc-trigger (trigger bug has been fixed) 166 | 167 | ## 0.1.3 168 | 169 | * `FIXED` specify rc-trigger@~1.6.0 170 | -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## uxcore-cascade-select 2 | 3 | React cascade select 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![build status][travis-image]][travis-url] 7 | [![Test Coverage][coveralls-image]][coveralls-url] 8 | [![Dependency Status][dep-image]][dep-url] 9 | [![devDependency Status][devdep-image]][devdep-url] 10 | [![NPM downloads][downloads-image]][npm-url] 11 | 12 | [![Sauce Test Status][sauce-image]][sauce-url] 13 | 14 | [npm-image]: http://img.shields.io/npm/v/uxcore-cascade-select.svg?style=flat-square 15 | [npm-url]: http://npmjs.org/package/uxcore-cascade-select 16 | [travis-image]: https://img.shields.io/travis/uxcore/uxcore-cascade-select.svg?style=flat-square 17 | [travis-url]: https://travis-ci.org/uxcore/uxcore-cascade-select 18 | [coveralls-image]: https://img.shields.io/coveralls/uxcore/uxcore-cascade-select.svg?style=flat-square 19 | [coveralls-url]: https://coveralls.io/r/uxcore/uxcore-cascade-select?branch=master 20 | [dep-image]: http://img.shields.io/david/uxcore/uxcore-cascade-select.svg?style=flat-square 21 | [dep-url]: https://david-dm.org/uxcore/uxcore-cascade-select 22 | [devdep-image]: http://img.shields.io/david/dev/uxcore/uxcore-cascade-select.svg?style=flat-square 23 | [devdep-url]: https://david-dm.org/uxcore/uxcore-cascade-select#info=devDependencies 24 | [downloads-image]: https://img.shields.io/npm/dm/uxcore-cascade-select.svg 25 | [sauce-image]: https://saucelabs.com/browser-matrix/uxcore-cascade-select.svg 26 | [sauce-url]: https://saucelabs.com/u/uxcore-cascade-select 27 | 28 | 29 | ### Development 30 | 31 | ```sh 32 | git clone https://github.com/uxcore/uxcore-cascade-select 33 | cd uxcore-cascade-select 34 | npm install 35 | npm run server 36 | ``` 37 | 38 | if you'd like to save your install time,you can use uxcore-tools globally. 39 | 40 | ```sh 41 | npm install uxcore-tools -g 42 | git clone https://github.com/uxcore/uxcore-cascade-select 43 | cd uxcore-cascade-select 44 | npm install 45 | npm run dep 46 | npm run start 47 | ``` 48 | 49 | ### Test Case 50 | 51 | ```sh 52 | npm run test 53 | ``` 54 | 55 | ### Coverage 56 | 57 | ```sh 58 | npm run coverage 59 | ``` 60 | 61 | ## Demo 62 | 63 | http://uxcore.github.io/components/cascade-select 64 | 65 | ## Contribute 66 | 67 | Yes please! See the [CONTRIBUTING](https://github.com/uxcore/uxcore/blob/master/CONTRIBUTING.md) for details. 68 | 69 | ## API 70 | 71 | ```javascript 72 | import CascadeSelect from 'uxcore-cascade-select' 73 | import { render } from 'react-dom' 74 | 75 | render(, document.getElementById('root')) 76 | ``` 77 | 78 | ## Props 79 | | Name | Type | Required | Default | Comments | 80 | |---|---|---|---|---| 81 | | prefixCls | string | false | `'kuma-cascader'` | 默认的类名前缀 | 82 | | className | string | false | `''` | 自定义类名 | 83 | | options | array | false | `[]` | 选项数据源,格式可见下方Demo | 84 | | value | array | false | `null` | 可由外部控制的值 | 85 | | defaultValue | array | false | `[]` | 初始默认值 | 86 | | placeholder | string | false | `'Please Select'` or `'请选择'` | placeholder | 87 | | onChange | function | false | `function(value, selectedOptions)` | 选择完成后回调 | 88 | | disabled | boolean | false | `false` | 是否禁用 | 89 | | clearable | boolean | false | `false` | 是否支持清除 | 90 | | changeOnSelect | boolean | false | `false` | 是否将每次选择立刻显示在控件中 | 91 | | expandTrigger | string | false | `'click'` | 次级菜单展开方式,支持 `click` 和 `hover` | 92 | | beforeRender | function | false | `(value, selectedOptions) => selectedOptions.map(o => o && o.label).join(' / ')` | 处理要显示的内容 | 93 | | cascadeSize | number | false | `3` | 级联的层级数 | 94 | | getPopupContainer | function():HTMLElement | false | - | 返回一个 html 元素用作 Popup 面板的容器,默认是插在body 中的一个 div | 95 | | locale | string | false | `'zh-cn'` | `'en-us'` 96 | | miniMode | boolean | false | true | 是否是简洁显示风格 97 | | columnWidth | number | false | null | dropdown中每一列的宽度, 如为空,整体宽度等于input输入框的宽度 98 | | displayMode | string | false | `dropdown` | `select` 或者 `dropdown` 或者 `search` 99 | | getSelectPlaceholder | func | false | `function(idx){ return '请选择' }` | select显示模式下的placeholder生成函数 100 | | size | string | false | `large` | 尺寸,枚举值:`large`, `middle`, `small` 101 | | isMustSelectLeaf | bool | false | `false` | 是否必须选择到叶子节点 102 | | onSelect | function | false | null | 异步加载层级,需要 return 一个数组,具体用法参考下方 demo 103 | | searchOption | function | false | null | 开启关键词搜索的配置,当 dispalyMode 为 search 时启用,具体配置方式[参考下方](props.searchOption) 104 | 105 | ## Demos 106 | 107 | ### props.options 108 | 109 | ```javascript 110 | const options = [{ 111 | value: 'zhejiang', 112 | label: '浙江', 113 | children: [{ 114 | value: 'hangzhou', 115 | label: '杭州', 116 | children: [{ 117 | value: 'xihu', 118 | label: '西湖', 119 | }], 120 | }], 121 | }, { 122 | value: 'jiangsu', 123 | label: '江苏', 124 | children: [{ 125 | value: 'nanjing', 126 | label: '南京', 127 | children: [{ 128 | value: 'zhonghuamen', 129 | label: '中华门', 130 | }], 131 | }], 132 | }]; 133 | ``` 134 | 135 | ### 当不指定 dropdown 宽度时,还可以使用css来定制dropdown宽度 136 | 137 | ```less 138 | .kuma-cascader-submenu-empty, 139 | .kuma-dropdown-menu-submenu { 140 | width: 400px; // 你想要的 dropdown 宽度 141 | } 142 | ``` 143 | 144 | ### props.onSelect 145 | 146 | ```javascript 147 | { 155 | ajax({ 156 | url: 'xxx/xx.json', 157 | data: { 158 | key 159 | }, 160 | success(content) { 161 | resolve(content); // content必须为array 162 | }, 163 | error() { 164 | reject(); 165 | } 166 | }) 167 | }} 168 | /> 169 | ``` 170 | 171 | ### props.searchOption 172 | 173 | ```javascript 174 | { 175 | doSearch(keyword, afterSearch) { // 异步搜索函数 176 | // keyword 为搜索的关键词 177 | // afterSearch 为搜索完成之后需要将结果显示在页面中,afterSearch 接收的参数为 [{ label, value }, ...] 178 | Fetch('/search?keyword=' + keyword).then(result => afterSearch(result)) 179 | } 180 | } 181 | ``` -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /src/CascadeSubmenu.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component for uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | import React from 'react'; 9 | import PropTypes from 'prop-types'; 10 | import classnames from 'classnames'; 11 | import Button from 'uxcore-button'; 12 | import { find } from './util'; 13 | import i18n from './i18n'; 14 | import SuperComponent from './SuperComponent'; 15 | 16 | const isNotEmpty = (arr) => { 17 | if (arr instanceof Array) { 18 | return arr.length; 19 | } 20 | return false; 21 | }; 22 | 23 | class CascadeSubmenu extends SuperComponent { 24 | onItemClick(item, groupIndex, hasChildren) { 25 | if (this.props.onItemClick) { 26 | this.props.onItemClick(item.value, groupIndex, item, hasChildren); 27 | } 28 | } 29 | 30 | onItemHover(item, groupIndex, hasChildren) { 31 | clearTimeout(this.timeout); 32 | this.timeout = setTimeout(() => { 33 | if (this.props.onItemClick) { 34 | this.props.onItemClick(item.value, groupIndex, item, hasChildren); 35 | } 36 | }, 400); 37 | } 38 | 39 | renderUlList(data, key, groupIndex) { 40 | const { expandTrigger } = this.props; 41 | return data.map(item => { 42 | const otherProps = {}; 43 | if (expandTrigger === 'click') { 44 | otherProps.onClick = 45 | this.onItemClick.bind(this, item, groupIndex, isNotEmpty(item.children)); 46 | } else if (expandTrigger === 'hover') { 47 | otherProps.onMouseOver = 48 | this.onItemHover.bind(this, item, groupIndex, isNotEmpty(item.children)); 49 | } 50 | 51 | if (item.value === key) { 52 | if (groupIndex === 0) { 53 | this.displayData = [item.label]; 54 | } else { 55 | this.displayData[groupIndex] = item.label; 56 | } 57 | } 58 | 59 | return ( 60 |
  • 66 | {item.label} 67 |
  • 68 | ); 69 | }); 70 | } 71 | 72 | renderLoading() { 73 | return ( 74 |
    75 | ); 76 | } 77 | 78 | renderSubmenus() { 79 | const { value, options, expandTrigger, cascadeSize, miniMode, loading } = this.props; 80 | const submenu = []; 81 | let columnSize = cascadeSize; 82 | if (!miniMode) { 83 | columnSize = cascadeSize + 1; 84 | } 85 | let unitWidth = `${(100 / columnSize).toFixed(1)}%`; 86 | const firstStyle = {}; 87 | if (value && value.length > 0) { 88 | firstStyle.width = unitWidth; 89 | } else { 90 | firstStyle.width = '100%'; 91 | } 92 | submenu.push( 93 |
      100 | {this.renderUlList(options, value[0], 0)} 101 |
    102 | ); 103 | let prevSelected = null; 104 | value.forEach((key, index) => { 105 | const style = {}; 106 | if (value && value.length > index + 1) { 107 | style.width = unitWidth; 108 | } else { 109 | style.width = `${((cascadeSize - value.length)/columnSize * 100).toFixed(1)}%`; 110 | } 111 | const parent = find(prevSelected || options, item => item.value === key); 112 | const renderArr = parent && parent.children; 113 | prevSelected = renderArr; 114 | if (renderArr || loading[key]) { 115 | submenu.push( 116 |
      123 | { 124 | loading[key] ? this.renderLoading() : 125 | this.renderUlList(renderArr, value[index + 1], index + 1) 126 | } 127 |
    128 | ); 129 | } 130 | }); 131 | return submenu; 132 | } 133 | 134 | renderBottomBar() { 135 | const size = this.props.size; 136 | let btnSize = size === 'large' ? 'medium' : 'small'; 137 | return ( 138 |
    139 | 142 |
    143 | ); 144 | } 145 | 146 | renderAllSelection() { 147 | const width = `${(100 / (this.props.cascadeSize + 1)).toFixed(1)}%`; 148 | return ( 149 |
    150 |
    151 | {i18n[this.props.locale].alreadyChoosed} 152 |
    153 |
    154 | { 155 | this.displayData ? 156 | this.displayData.map((label, idx) => 157 |
    158 | {label} 159 |
    160 | ) : 161 | null 162 | } 163 |
    164 |
    165 | ); 166 | } 167 | 168 | render() { 169 | const wrapStyle = {}; 170 | if (this.props.columnWidth) { 171 | wrapStyle.width = this.props.columnWidth * this.props.cascadeSize; 172 | // if (!this.props.miniMode) { 173 | // wrapStyle.width = this.props.columnWidth * (this.props.cascadeSize + 1); 174 | // } 175 | } 176 | return ( 177 |
    178 |
    179 |
    180 | {this.renderSubmenus()} 181 | 182 | { 183 | this.props.miniMode ? null : 184 | this.renderAllSelection() 185 | } 186 |
    187 | { 188 | this.props.miniMode ? null : 189 | this.renderBottomBar() 190 | } 191 |
    192 |
    193 | ); 194 | } 195 | } 196 | 197 | CascadeSubmenu.propTypes = { 198 | prefixCls: PropTypes.string, 199 | onItemClick: PropTypes.func, 200 | value: PropTypes.array, 201 | options: PropTypes.array, 202 | miniMode: PropTypes.bool, 203 | onOkButtonClick: PropTypes.func, 204 | columnWidth: PropTypes.number, 205 | cascadeSize: PropTypes.number, 206 | size: PropTypes.oneOf(['large', 'middle', 'small']), 207 | className: PropTypes.string, 208 | }; 209 | 210 | CascadeSubmenu.defaultProps = { 211 | prefixCls: 'kuma-cascader', 212 | onItemClick() { }, 213 | value: [], 214 | options: [], 215 | miniMode: false, 216 | onOkButtonClick: () => { }, 217 | size: 'large', 218 | className: '', 219 | }; 220 | 221 | CascadeSubmenu.displayName = 'CascadeSubmenu'; 222 | 223 | export default CascadeSubmenu; 224 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/SuperComponent.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/SuperComponent.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
    17 |
    18 |

    19 | all files / src/ SuperComponent.js 20 |

    21 |
    22 |
    23 | 88.89% 24 | Statements 25 | 32/36 26 |
    27 |
    28 | 54.17% 29 | Branches 30 | 13/24 31 |
    32 |
    33 | 100% 34 | Functions 35 | 8/8 36 |
    37 |
    38 | 100% 39 | Lines 40 | 19/19 41 |
    42 |
    43 |
    44 |
    45 |
    
     46 | 
    173 | 
    1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43  89 |   90 | 91 |   92 |   93 |   94 | 95 |   96 | 33× 97 |   98 | 33× 99 |   100 | 101 |   102 | 103 |   104 | 105 | 106 |   107 | 108 | 33× 109 |   110 | 33× 111 |   112 |   113 | 114 | 787× 115 |   116 | 787× 117 | 800× 118 |   119 |   120 |   121 | 122 |   123 |   124 | 125 |   126 |   127 |   128 | 129 | 130 |  
    'use strict';
    131 |  
    132 | Object.defineProperty(exports, "__esModule", {
    133 |   value: true
    134 | });
    135 |  
    136 | function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); Iif (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
    137 |  
    138 | function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    139 |  
    140 | function _possibleConstructorReturn(self, call) { Iif (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
    141 |  
    142 | function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); }
    143 |  
    144 | var React = require('react');
    145 |  
    146 | var SuperComponent = function (_React$Component) {
    147 |   _inherits(SuperComponent, _React$Component);
    148 |  
    149 |   function SuperComponent() {
    150 |     _classCallCheck(this, SuperComponent);
    151 |  
    152 |     return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
    153 |   }
    154 |  
    155 |   SuperComponent.prototype.prefixCls = function prefixCls(name) {
    156 |     var prefixCls = this.props.prefixCls;
    157 |  
    158 |     return name.split(/\s/).map(function (i) {
    159 |       return prefixCls + '-' + i;
    160 |     }).join(' ');
    161 |   };
    162 |  
    163 |   return SuperComponent;
    164 | }(React.Component);
    165 |  
    166 | SuperComponent.propTypes = {
    167 |   prefixCls: React.PropTypes.string
    168 | };
    169 |  
    170 | exports['default'] = SuperComponent;
    171 | module.exports = exports['default'];
    172 |  
    174 |
    175 |
    176 | 180 |
    181 | 182 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
    17 |
    18 |

    19 | all files src/ 20 |

    21 |
    22 |
    23 | 87.7% 24 | Statements 25 | 499/569 26 |
    27 |
    28 | 74.79% 29 | Branches 30 | 264/353 31 |
    32 |
    33 | 80.73% 34 | Functions 35 | 88/109 36 |
    37 |
    38 | 88.55% 39 | Lines 40 | 441/498 41 |
    42 |
    43 |
    44 |
    45 |
    46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 |
    FileStatementsBranchesFunctionsLines
    CascadeSelect.jsx
    86.92%279/32176.5%153/20082.76%48/5887.58%261/298
    CascadeSubmenu.jsx
    96.09%123/12878.75%63/8088%22/2599%99/100
    Search.jsx
    50%12/2430.77%4/1322.22%2/947.83%11/23
    SuperComponent.js
    88.89%32/3654.17%13/24100%8/8100%19/19
    i18n.js
    100%1/1100%0/0100%0/0100%1/1
    index.js
    100%1/1100%0/0100%0/0100%1/1
    util.js
    87.93%51/5886.11%31/3688.89%8/987.5%49/56
    154 |
    155 |
    156 | 160 | 161 | 162 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /demo/CascadeSelectDemo.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component Demo for uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | const React = require('react'); 10 | const CascadeSelect = require('../src'); 11 | 12 | const options = [{ 13 | value: 100224, 14 | label: 'IS', 15 | children: [{ 16 | value: 100240, 17 | label: '通讯服务', 18 | children: [{ 19 | value: 2815, 20 | label: '短信服务', 21 | }, { 22 | value: 2816, 23 | label: '互联网电话', 24 | }], 25 | }], 26 | }, { 27 | value: 'alibaba', 28 | label: '阿里巴巴', 29 | children: [{ 30 | value: 'platform', 31 | label: '信息平台', 32 | children: [{ 33 | value: 'fe', 34 | label: '前端开发名称加长加长加长加长', 35 | }], 36 | }], 37 | }, { 38 | value: 'beijing', 39 | label: '日本', 40 | children: [{ 41 | value: 'xicheng', 42 | label: '西城', 43 | children: [ 44 | // { 45 | // value: 'zhonggc', 46 | // label: '中观村大街', 47 | // }, 48 | ], 49 | }], 50 | }, { 51 | value: 'tianjin', 52 | label: '天津', 53 | children: [{ 54 | value: 'heping', 55 | label: '和平区', 56 | children: [{ 57 | value: 'nanjinglu', 58 | label: '南京路', 59 | children: [{ 60 | value: 'newbal', 61 | label: '新百伦', 62 | }], 63 | }], 64 | }, { 65 | value: 'hexi', 66 | label: '河西区', 67 | children: [{ 68 | value: 'dagu', 69 | label: '大沽路', 70 | }], 71 | }], 72 | }, { 73 | value: 'zhejiang', 74 | label: '浙江', 75 | children: [{ 76 | value: 'hangzhou', 77 | label: '杭州', 78 | children: [{ 79 | value: 'xihu', 80 | label: '西湖', 81 | }], 82 | }], 83 | }, { 84 | value: 'jiangsu', 85 | label: '江苏', 86 | children: [{ 87 | value: 'nanjing', 88 | label: '南京', 89 | children: [{ 90 | value: 'zhonghuamen', 91 | label: '中华门', 92 | }], 93 | }], 94 | }]; 95 | 96 | const asyncOptions = [ 97 | { 98 | value: '0', 99 | label: '0', 100 | }, 101 | { 102 | value: '1', 103 | label: '1', 104 | }, 105 | ]; 106 | 107 | const optionsGenerator = (key, level) => { 108 | const childrenOptions = []; 109 | for (let i = 0; i <= level; i += 1) { 110 | childrenOptions.push({ 111 | label: `label-${key}-${i}`, 112 | value: `${key}-${i}`, 113 | }); 114 | } 115 | return childrenOptions; 116 | }; 117 | 118 | class Demo extends React.Component { 119 | 120 | constructor(props) { 121 | super(props); 122 | this.state = { 123 | xValue: ['jiangsu', 'nanjing', 'zhonghuamen'], 124 | value: [2815], 125 | firstValue: ['zhonghuamen'], 126 | asyncValue: ['nanjinglu'], 127 | asyncOptions: [], 128 | }; 129 | } 130 | 131 | loadFirstOptions() { 132 | setTimeout(() => { 133 | this.setState({ 134 | firstOptions: options, 135 | }); 136 | }, 500); 137 | } 138 | 139 | handleChange(value) { 140 | console.log('onChange', value); 141 | if (value.length) { 142 | this.setState({ 143 | firstValue: [value[value.length - 1]], 144 | }); 145 | } 146 | } 147 | 148 | handleAsyncChange = (value, selected) => { 149 | console.log('AsyncChange', value, selected); 150 | // 异步时候设置value请设置完整,如['1', '1-1', '1-1-0'], 151 | if (value.length) { 152 | this.setState({ 153 | asyncValue: value, 154 | }); 155 | } 156 | } 157 | 158 | render() { 159 | return ( 160 |
    161 |

    search

    162 | { 168 | console.log(value); 169 | }} 170 | columnWidth={150} 171 | miniMode={false} 172 | searchOption={{ 173 | doSearch(keyword, afterSearch) { 174 | afterSearch([ 175 | { 176 | label: 'test1', 177 | value: 'ID_TEST1', 178 | }, 179 | { 180 | label: '短信服务', 181 | value: 2815, 182 | }, 183 | { 184 | label: 'test3 test3 test3 test3 test3 test3 test3 test3 test3 test3', 185 | value: 'ID_TEST3', 186 | }, 187 | ]); 188 | }, 189 | }} 190 | isMustSelectLeaf 191 | /> 192 | 193 |

    默认的

    194 | { 197 | console.log(...args); 198 | }} 199 | /> 200 | 201 |

    异步 value先有,options 异步加载,常用于数据回填

    202 | 209 | 218 | 219 | 220 |

    异步Select 风格

    221 | { 225 | const div = document.createElement('div'); 226 | div.className = 'uxcore'; 227 | document.body.appendChild(div); 228 | return div; 229 | }} 230 | dropDownWidth={400} 231 | onChange={this.handleAsyncChange.bind(this)} 232 | displayMode="select" 233 | cascadeSize={3} 234 | size="small" 235 | onSelect={(resolve, reject, key, level) => { 236 | setTimeout(() => { 237 | if (key === '1-0') { 238 | reject(); 239 | } 240 | resolve(optionsGenerator(key, level)); 241 | }, 1000); 242 | }} 243 | /> 244 |

    Select 风格

    245 | { 249 | const div = document.createElement('div'); 250 | div.className = 'uxcore'; 251 | document.body.appendChild(div); 252 | return div; 253 | }} 254 | dropDownWidth={400} 255 | onChange={(value, selected) => { 256 | this.setState({ 257 | firstValue: [value[value.length - 1]], 258 | }); 259 | }} 260 | displayMode="select" 261 | cascadeSize={3} 262 | size="small" 263 | /> 264 |

    Clearable

    265 | { 270 | console.log('Clearable', value, selected); 271 | }} 272 | locale={'en_US'} 273 | miniMode={false} 274 | cascadeSize={3} 275 | size="small" 276 | displayMode="dropdown" 277 | /> 278 |

    禁用的

    279 | { }} 285 | /> 286 |

    必须选到根节点

    287 | { console.log(value, selected); }} 292 | size="small" 293 | isMustSelectLeaf 294 | /> 295 |

    鼠标悬浮的

    296 | { }} 302 | /> 303 |

    改变value

    304 | { }} 310 | /> 311 | 316 | { }} 322 | /> 323 | 328 |
    329 | ); 330 | } 331 | } 332 | 333 | module.exports = Demo; 334 | -------------------------------------------------------------------------------- /src/CascadeSelect.less: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component Style for uxcore 3 | * @author changming 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | @_prefix-cls: kuma-cascader; 10 | @_prefix-cls-dropdown: kuma-dropdown-menu; 11 | @_text-color: #333; 12 | @_gray-text: #76889A; 13 | @_border: @border-color; 14 | @_border-light: #e8e8e8; 15 | @_hover-color: #F6F7F9; 16 | @_background: #fff; 17 | .effect() { 18 | animation-duration: .3s; 19 | animation-fill-mode: both; 20 | transform-origin: 0 0; 21 | } 22 | 23 | .transition() { 24 | transition: all .3s; 25 | } 26 | 27 | .@{_prefix-cls} { 28 | &-wrapper { 29 | min-height: @trigger-height-large; 30 | width: 100%; 31 | position: relative; 32 | color: @_text-color; 33 | border: 1px solid @border-color; 34 | border-radius: @input-border-radius; 35 | background-color: @_background; 36 | .transition(); 37 | &:hover { 38 | border-color: @border-hover-color; 39 | .kuma-icon { 40 | color: @border-hover-color; 41 | } 42 | } 43 | } 44 | &-clearable:hover { 45 | .@{_prefix-cls}-close-wrap { 46 | visibility: visible; 47 | opacity: 1; 48 | transform: scale(1); 49 | } 50 | } 51 | &-close-wrap { 52 | visibility: hidden; 53 | opacity: 0; 54 | transform: scale(.6); 55 | position: absolute; 56 | right: 20px; 57 | top: 50%; 58 | text-align: center; 59 | width: 20px; 60 | height: 20px; 61 | line-height: 20px; 62 | margin-top: -10px; 63 | cursor: pointer; 64 | .transition(); 65 | .kuma-icon { 66 | color: @_gray-text; 67 | font-size: 14px; 68 | &:hover { 69 | color: darken(@_gray-text, 10%); 70 | } 71 | } 72 | } 73 | &-focus { 74 | border-color: @border-focus-color; 75 | .kuma-icon { 76 | color: @border-focus-color; 77 | } 78 | &:hover { 79 | border-color: @border-focus-color; 80 | .kuma-icon { 81 | color: @border-focus-color; 82 | } 83 | } 84 | } 85 | &-trigger { 86 | cursor: pointer; 87 | white-space: nowrap; 88 | overflow: hidden; 89 | text-overflow: ellipsis; 90 | margin-right: 30px; 91 | } 92 | &-text { 93 | line-height: @trigger-height-large; 94 | padding: 0 10px; 95 | } 96 | &-placeholder { 97 | color: @normal-alpha-4; 98 | } 99 | &-arrow { 100 | color: @_border; 101 | position: absolute; 102 | right: 2px; 103 | top: 50%; 104 | width: 20px; 105 | height: 20px; 106 | margin-top: -10px; 107 | line-height: 20px; 108 | text-align: center; 109 | .transition(); 110 | } 111 | &-arrow-reverse { 112 | transform: rotate(180deg); 113 | } 114 | } 115 | 116 | div.@{_prefix-cls}-disabled { 117 | background: @bg-disabled-color; 118 | border-color: @border-disabled-color; 119 | color: @text-disabled-color; 120 | cursor: not-allowed; 121 | .kuma-icon { 122 | color: @border-disabled-color; 123 | } 124 | &:hover { 125 | border-color: @border-disabled-color; 126 | .kuma-icon { 127 | color: @border-disabled-color; 128 | } 129 | } 130 | } 131 | 132 | .@{_prefix-cls}-submenu-warpper { 133 | 134 | .@{_prefix-cls-dropdown} { 135 | &-submenu-bottom-bar { 136 | padding: 10px 0; 137 | text-align: center; 138 | border-top: 1px solid #d9d9d9; 139 | } 140 | &-submenu-all-selection { 141 | float: right; 142 | height: 100%; 143 | overflow: hidden; 144 | background-color: @_background; 145 | z-index: 1; 146 | position: relative; 147 | } 148 | &-submenu-all-selection-title { 149 | margin: 5px 0 5px 10px; 150 | color: #999; 151 | } 152 | &-submenu-all-body { 153 | margin: 10px; 154 | i { 155 | font-size: 12px; 156 | color: #999; 157 | } 158 | & > div { 159 | overflow: hidden; 160 | white-space: nowrap; 161 | text-overflow: ellipsis; 162 | height: 24px; 163 | line-height: 24px; 164 | } 165 | } 166 | } 167 | 168 | .@{_prefix-cls-dropdown} { 169 | &-submenu { 170 | margin: 0; 171 | background-color: @_background; 172 | border: 1px solid #d9d9d9; 173 | border-radius: @input-border-radius; 174 | box-shadow: @box-shadow-1; 175 | overflow: hidden; 176 | &-border { 177 | margin: 0; 178 | border-top: 1px solid @_border-light; 179 | } 180 | } 181 | &-submenu-wrap { 182 | height: 120px; 183 | overflow: hidden; 184 | &>ul { 185 | line-height: @trigger-height-large; // width: 33.3%; 186 | height: 100%; 187 | overflow: auto; 188 | float: left; 189 | border-right: 1px solid @_border-light; 190 | &:last-child { 191 | border-right: none; 192 | } 193 | } 194 | li { 195 | padding: 0 20px 0 10px; 196 | white-space: nowrap; 197 | overflow: hidden; 198 | text-overflow: ellipsis; 199 | cursor: pointer; 200 | .transition(); 201 | &:hover, 202 | &.active { 203 | background-color: @_hover-color; 204 | } 205 | &.active { 206 | font-weight: bolder; 207 | } 208 | &:active { 209 | font-weight: bolder; 210 | background-color: darken(@_hover-color, 3%); 211 | } 212 | } 213 | } 214 | } 215 | 216 | ul.@{_prefix-cls-dropdown}-hoverable { 217 | li { 218 | position: relative; 219 | &:after { 220 | font-family: kuma!important; 221 | font-size: 16px; 222 | font-style: normal; 223 | -webkit-font-smoothing: antialiased; 224 | -webkit-text-stroke-width: .2px; 225 | content: "\e643"; 226 | position: absolute; 227 | right: 2px; 228 | top: 0; 229 | color: #666; 230 | } 231 | } 232 | } 233 | 234 | .@{_prefix-cls-dropdown}-center-loading { 235 | margin: 0 auto; 236 | position: absolute; 237 | left: 50%; 238 | top: 50%; 239 | transform: translate(-50%, -50%); 240 | } 241 | .@{_prefix-cls-dropdown}-submenu-wrap > ul { 242 | position: relative; 243 | } 244 | 245 | .@{_prefix-cls-dropdown}-size-middle { 246 | .@{_prefix-cls-dropdown}-submenu-wrap > ul { 247 | line-height: @trigger-height-middle; 248 | } 249 | } 250 | .@{_prefix-cls-dropdown}-size-small { 251 | .@{_prefix-cls-dropdown}-submenu-wrap > ul { 252 | line-height: @trigger-height-small; 253 | } 254 | } 255 | 256 | } 257 | 258 | .@{_prefix-cls} { 259 | &-select-wrap { 260 | margin-right: -15px; 261 | .kuma-select2 { 262 | width: 100%; 263 | } 264 | } 265 | &-select-item-wrap { 266 | display: inline-block; 267 | padding-right: 15px; 268 | } 269 | &-select-loading { 270 | width: 16px; 271 | height: 16px; 272 | position: absolute; 273 | top: 8px; 274 | right: 8px; 275 | background: #fff url(data:image/gif;base64,R0lGODlhEAAQAKIGAMLY8YSx5HOm4Mjc88/g9Ofw+v///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgAGACwAAAAAEAAQAAADMGi6RbUwGjKIXCAA016PgRBElAVlG/RdLOO0X9nK61W39qvqiwz5Ls/rRqrggsdkAgAh+QQFCgAGACwCAAAABwAFAAADD2hqELAmiFBIYY4MAutdCQAh+QQFCgAGACwGAAAABwAFAAADD1hU1kaDOKMYCGAGEeYFCQAh+QQFCgAGACwKAAIABQAHAAADEFhUZjSkKdZqBQG0IELDQAIAIfkEBQoABgAsCgAGAAUABwAAAxBoVlRKgyjmlAIBqCDCzUoCACH5BAUKAAYALAYACgAHAAUAAAMPaGpFtYYMAgJgLogA610JACH5BAUKAAYALAIACgAHAAUAAAMPCAHWFiI4o1ghZZJB5i0JACH5BAUKAAYALAAABgAFAAcAAAMQCAFmIaEp1motpDQySMNFAgA7) no-repeat; 276 | } 277 | &-internal-select-item-wrap { 278 | position: relative; 279 | } 280 | } 281 | 282 | // size 283 | .@{_prefix-cls}-size-middle { 284 | &.@{_prefix-cls}-wrapper { 285 | min-height: @trigger-height-middle; 286 | } 287 | .@{_prefix-cls}-text { 288 | line-height: @trigger-height-middle - 2; 289 | } 290 | } 291 | .@{_prefix-cls}-size-small { 292 | &.@{_prefix-cls}-wrapper { 293 | min-height: @trigger-height-small; 294 | } 295 | .@{_prefix-cls}-text { 296 | line-height: @trigger-height-small - 2; 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /tests/CascadeSelect.spec.jsx: -------------------------------------------------------------------------------- 1 | import expect from 'expect.js'; 2 | import React from 'react'; 3 | import sinon from 'sinon'; 4 | import $ from 'jquery'; 5 | import Enzyme from 'enzyme'; 6 | import { render, findDOMNode, unmountComponentAtNode } from 'react-dom'; 7 | import Adapter from 'enzyme-adapter-react-15'; 8 | import CascadeSelect from '../src'; 9 | import { deepCopy } from '../src/util'; 10 | import { options, asyncOptions } from './options'; 11 | 12 | const { mount } = Enzyme; 13 | 14 | Enzyme.configure({ adapter: new Adapter() }); 15 | 16 | const optionsGenerator = (key, level) => { 17 | const childrenOptions = []; 18 | for (let i = 0; i <= level; i += 1) { 19 | childrenOptions.push({ 20 | label: `label-${key}-${i}`, 21 | value: `${key}-${i}`, 22 | }); 23 | } 24 | return childrenOptions; 25 | }; 26 | 27 | function noop() { } 28 | 29 | describe('CascadeSelect', () => { 30 | let instance; 31 | let div; 32 | 33 | beforeEach(() => { 34 | div = document.createElement('div'); 35 | document.body.appendChild(div); 36 | }); 37 | 38 | afterEach(() => { 39 | unmountComponentAtNode(div); 40 | document.body.removeChild(div); 41 | }); 42 | 43 | it('should display placeholder', () => { 44 | instance = render(, div); 45 | expect($(findDOMNode(instance)).find('.kuma-cascader-placeholder').html()).to.equal('请选择'); 46 | }); 47 | 48 | it('should add the custom className', () => { 49 | instance = render(, div); 50 | expect($(findDOMNode(instance))[0].className.indexOf('abc') > -1).to.be.ok(); 51 | }); 52 | 53 | it('should have a sub menu', () => { 54 | const wrapper = mount(); 55 | wrapper.simulate('change'); 56 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 57 | expect(dropdownWrapper.length > 0).to.be.ok(); 58 | }); 59 | 60 | it('should have the defaultValue', () => { 61 | instance = render( 62 | , div); 66 | expect($(findDOMNode(instance)).find('.kuma-cascader-trigger').attr('title')) 67 | .to 68 | .eql('阿里巴巴 / 信息平台 / 前端开发'); 69 | }); 70 | 71 | it('onChange should be called successfully', () => { 72 | const wrapper = mount( 73 | { 76 | expect(value.length === selected.length).to.be.ok(); 77 | }} 78 | columnWidth={100} 79 | /> 80 | ); 81 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 82 | mount(dropdownWrapper.props().overlay).props().onItemClick(); 83 | }); 84 | 85 | it('should be disabled', () => { 86 | instance = render(, div); 87 | expect($(findDOMNode(instance))[0].className.indexOf('kuma-cascader-disabled') > -1).to.be.ok(); 88 | }); 89 | 90 | it('should be clearable', () => { 91 | const wrapper = mount(); 92 | wrapper.find('.kuma-icon-error').simulate('click'); 93 | expect(wrapper.find('.kuma-cascader-placeholder').text()).to.eql('请选择'); 94 | }); 95 | 96 | it('expandTrigger', () => { 97 | const wrapper = mount(); 98 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 99 | expect(mount(dropdownWrapper.props().overlay).props().expandTrigger).to.eql('hover'); 100 | }); 101 | 102 | it('onItemClick', () => { 103 | const wrapper = mount(); 104 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 105 | mount(dropdownWrapper.props().overlay) 106 | .find('li') 107 | .at(0) 108 | .simulate('click'); 109 | const option = mount(dropdownWrapper.props().overlay).props().options[0]; 110 | mount(dropdownWrapper.props().overlay).props().onItemClick(option, 2, false); 111 | expect(wrapper.state('value').length > 0).to.be.ok(); 112 | }); 113 | 114 | it('onItemHover', () => { 115 | const wrapper = mount(); 116 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 117 | mount(dropdownWrapper.props().overlay) 118 | .find('li') 119 | .at(0) 120 | .simulate('mouseover'); 121 | const option = mount(dropdownWrapper.props().overlay).props().options[0]; 122 | mount(dropdownWrapper.props().overlay).props().onItemClick(option, 2, false); 123 | expect(wrapper.state('value').length > 0).to.be.ok(); 124 | }); 125 | 126 | it('render submenus value renderArr', (done) => { 127 | const wrapper = mount( 128 | 132 | ); 133 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 134 | const value = mount(dropdownWrapper.props().overlay).props().value; 135 | expect(value.length).to.eql(mount(dropdownWrapper.props().overlay).find('ul').length); 136 | done(); 137 | }); 138 | 139 | it('array contains single item as the value - case 1', (done) => { 140 | instance = render(, div); 141 | expect($(findDOMNode(instance)).find('.kuma-cascader-trigger').text()).to.eql('天津 / 和平区 / 南京路'); 142 | done(); 143 | }); 144 | 145 | it('array contains single item as the value - case 2', (done) => { 146 | instance = render(, div); 147 | expect($(findDOMNode(instance)).find('.kuma-cascader-trigger').text()).to.eql('日本 / 西城'); 148 | done(); 149 | }); 150 | 151 | it('displayMode select onChange', () => { 152 | const onChange = sinon.spy(noop); 153 | const wrapper = mount( 154 | trigger.parentNode} 161 | /> 162 | ); 163 | const select = mount(wrapper.find('Select').at(2).getElement()); 164 | select.find('.kuma-select2').simulate('click'); 165 | mount(select.find('Trigger').props().popup).find('li').at(1) 166 | .simulate('click'); 167 | expect(onChange.calledOnce).to.be.ok(); 168 | }); 169 | 170 | it('Async CascadeSelect', (done) => { 171 | const wrapper = mount( 172 | { 176 | setTimeout(() => { 177 | resolve(optionsGenerator(key, level)); 178 | }, 100); 179 | }} 180 | /> 181 | ); 182 | setTimeout(() => { 183 | expect($(wrapper.getDOMNode()).find('.kuma-cascader-trigger').attr('title')) 184 | .to 185 | .be('1 / label-1-1 / label-1-1-0'); 186 | done(); 187 | }, 300); 188 | }); 189 | 190 | it('Async CascadeSelect displayMode select', (done) => { 191 | const wrapper = mount( 192 | { 196 | setTimeout(() => { 197 | resolve(optionsGenerator(key, level)); 198 | }, 100); 199 | }} 200 | displayMode="select" 201 | /> 202 | ); 203 | setTimeout(() => { 204 | expect( 205 | $(wrapper.find('Select2').at(2).getDOMNode()) 206 | .find('.kuma-select2-selection-selected-value').text()) 207 | .to 208 | .be('label-1-1-0'); 209 | done(); 210 | }, 300); 211 | }); 212 | 213 | it('no miniMode', () => { 214 | const onChange = sinon.spy(noop); 215 | const wrapper = mount( 216 | 223 | ); 224 | const dropdownWrapper = mount(wrapper.find('Trigger').getElement()); 225 | const overlay = mount(dropdownWrapper.props().overlay); 226 | overlay.find('li').at(0).simulate('click'); 227 | overlay.find('button').simulate('click'); 228 | expect(onChange.calledOnce).to.equal(true); 229 | }); 230 | 231 | it('displayMode is search, dropdown will display search result.', () => { 232 | const onChange = sinon.spy(noop); 233 | const wrapper = mount( 234 | 259 | ); 260 | const dropdownWrapper = wrapper.find('Trigger'); 261 | const overlay = mount(dropdownWrapper.props().overlay); 262 | const input = wrapper.find('input').getDOMNode(); 263 | input.value = 'test'; 264 | setTimeout(() => { 265 | const li = overlay.find('li').at(1); 266 | expect(li.text()).to.equal('前端开发'); 267 | // overlay.find('li').at(1).simulate('click'); 268 | // overlay.find('button').at(0).simulate('click'); 269 | // expect(input.getDOMNode().value).to.equal('阿里巴巴 / 信息平台 / 前端开发'); 270 | }, 200); 271 | }); 272 | 273 | it('displayMode is search, click search result will get the real text.', () => { 274 | const onChange = sinon.spy(noop); 275 | const wrapper = mount( 276 | 301 | ); 302 | const dropdownWrapper = wrapper.find('Trigger'); 303 | const overlay = mount(dropdownWrapper.props().overlay); 304 | const input = wrapper.find('input').getDOMNode(); 305 | input.value = 'test'; 306 | setTimeout(() => { 307 | const li = overlay.find('li').at(1); 308 | li.simulate('click'); 309 | setTimeout(() => { 310 | overlay.find('button').at(0).simulate('click'); 311 | expect(input.getDOMNode().value).to.equal('阿里巴巴 / 信息平台 / 前端开发'); 312 | }, 200); 313 | }, 200); 314 | }); 315 | 316 | it('pass value before options', () => { 317 | const wrapper = mount( 318 | 323 | ); 324 | wrapper.setProps({ options }); 325 | setTimeout(() => { 326 | expect(wrapper.find('input').getDOMNode().value).to.equal('阿里巴巴 / 信息平台 / 前端开发'); 327 | }, 200); 328 | }); 329 | }); 330 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/util.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/util.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
    17 |
    18 |

    19 | all files / src/ util.js 20 |

    21 |
    22 |
    23 | 87.93% 24 | Statements 25 | 51/58 26 |
    27 |
    28 | 86.11% 29 | Branches 30 | 31/36 31 |
    32 |
    33 | 88.89% 34 | Functions 35 | 8/9 36 |
    37 |
    38 | 87.5% 39 | Lines 40 | 49/56 41 |
    42 |
    43 |
    44 |
    45 |
    
     46 | 
    335 | 
    1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97  143 |   144 | 145 |   146 |   147 | 148 | 149 |   150 | 151 | 152 |   153 |   154 |   155 |   156 |   157 |   158 |   159 |   160 | 161 | 33× 162 |   163 |   164 | 33× 165 |   166 |   167 | 33× 168 | 33× 169 | 33× 170 |   171 | 33× 172 | 43× 173 | 43× 174 | 33× 175 |   176 |   177 |   178 |   179 |   180 |   181 | 182 | 183 |   184 |   185 | 186 | 187 | 188 | 189 | 190 | 16× 191 |   192 | 16× 193 | 29× 194 | 18× 195 | 196 | 197 |   198 | 18× 199 | 12× 200 |   201 |   202 |   203 | 204 | 205 | 206 | 207 | 208 | 209 |   210 |   211 | 212 |   213 |   214 | 215 | 36× 216 | 36× 217 |   218 | 36× 219 | 15× 220 |   221 | 21× 222 | 223 | 12× 224 | 225 |   226 |   227 |   228 | 12× 229 |   230 |   231 | 232 |   233 |   234 |   235 |   236 |   237 | 238 |  
    'use strict';
    239 |  
    240 | Object.defineProperty(exports, "__esModule", {
    241 |   value: true
    242 | });
    243 | var _arguments = arguments;
    244 | var supportNativeFind = !!Array.prototype.find;
    245 |  
    246 | var find = function () {
    247 |   Iif (supportNativeFind) {
    248 |     return function (ary) {
    249 |       for (var _len = arguments.length, params = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    250 |         params[_key - 1] = arguments[_key];
    251 |       }
    252 |  
    253 |       return ary.find.apply(ary, params);
    254 |     };
    255 |   }
    256 |   return function (ary, predicate) {
    257 |     Iif (undefined === null) {
    258 |       throw new TypeError('find called on null or undefined');
    259 |     }
    260 |     Iif (typeof predicate !== 'function') {
    261 |       throw new TypeError('predicate must be a function');
    262 |     }
    263 |     var length = ary.length >>> 0;
    264 |     var ctx = _arguments[2];
    265 |     var value = void 0;
    266 |  
    267 |     for (var i = 0; i < length; i++) {
    268 |       value = ary[i];
    269 |       if (predicate.call(ctx, value, i, ary)) {
    270 |         return value;
    271 |       }
    272 |     }
    273 |     return undefined;
    274 |   };
    275 | }();
    276 |  
    277 | var deepCopy = function deepCopy(o) {
    278 |   return JSON.parse(JSON.stringify(o));
    279 | };
    280 |  
    281 | var getArrayLeafItemContains = function getArrayLeafItemContains(options, keyArr) {
    282 |   var position = void 0;
    283 |   var isFound = false;
    284 |   var selectedOptions = [];
    285 |   function recursion(opts) {
    286 |     var pos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '0';
    287 |  
    288 |     opts.forEach(function (opt, index) {
    289 |       if (isFound) return;
    290 |       if (keyArr[0] + '_' === opt.value + '_') {
    291 |         position = pos + '-' + index;
    292 |         isFound = true;
    293 |       }
    294 |       if (opt.children) {
    295 |         recursion(opt.children, pos + '-' + index);
    296 |       }
    297 |     });
    298 |   }
    299 |   recursion(options);
    300 |   if (!position) return [];
    301 |   var parents = options;
    302 |   position.split('-').slice(1).forEach(function (pos) {
    303 |     selectedOptions.push(parents[pos]);
    304 |     parents = parents[pos].children;
    305 |   });
    306 |  
    307 |   return selectedOptions;
    308 | };
    309 |  
    310 | var getOptions = function getOptions(options) {
    311 |   var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
    312 |   var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
    313 |  
    314 |   if (level === 0 && options) {
    315 |     return options;
    316 |   }
    317 |   if (value.length) {
    318 |     for (var i = 0, l = options.length; i < l; i++) {
    319 |       if (options[i].value + '_' === value[0] + '_') {
    320 |         return getOptions(options[i].children, value.slice(1), level - 1);
    321 |       }
    322 |     }
    323 |   }
    324 |   return [];
    325 | };
    326 |  
    327 | exports['default'] = {
    328 |   find: find,
    329 |   getArrayLeafItemContains: getArrayLeafItemContains,
    330 |   deepCopy: deepCopy,
    331 |   getOptions: getOptions
    332 | };
    333 | module.exports = exports['default'];
    334 |  
    336 |
    337 |
    338 | 342 | 343 | 344 | 351 | 352 | 353 | 354 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/Search.jsx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/Search.jsx 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
    17 |
    18 |

    19 | all files / src/ Search.jsx 20 |

    21 |
    22 |
    23 | 50% 24 | Statements 25 | 12/24 26 |
    27 |
    28 | 30.77% 29 | Branches 30 | 4/13 31 |
    32 |
    33 | 22.22% 34 | Functions 35 | 2/9 36 |
    37 |
    38 | 47.83% 39 | Lines 40 | 11/23 41 |
    42 |
    43 |
    44 |
    45 |
    
     46 | 
    329 | 
    1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95  141 |   142 | 143 |   144 |   145 |   146 | 147 |   148 | 149 |   150 | 151 |   152 | 153 | 154 |   155 |   156 |   157 |   158 |   159 |   160 | 161 |   162 |   163 |   164 |   165 |   166 |   167 |   168 |   169 |   170 |   171 |   172 |   173 |   174 |   175 |   176 |   177 |   178 |   179 |   180 |   181 |   182 |   183 | 184 |   185 |   186 |   187 |   188 |   189 |   190 |   191 |   192 |   193 | 194 |   195 |   196 |   197 |   198 |   199 |   200 |   201 |   202 |   203 |   204 |   205 |   206 |   207 |   208 |   209 |   210 |   211 |   212 |   213 |   214 |   215 |   216 |   217 |   218 |   219 |   220 |   221 |   222 |   223 |   224 |   225 |   226 |   227 |   228 |   229 |   230 |   231 |   232 | 233 | 234 |  
    'use strict';
    235 |  
    236 | Object.defineProperty(exports, "__esModule", {
    237 |   value: true
    238 | });
    239 |  
    240 | var _react = require('react');
    241 |  
    242 | var _react2 = _interopRequireDefault(_react);
    243 |  
    244 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
    245 |  
    246 | var Search = function Search(_ref) {
    247 |   var text = _ref.text,
    248 |       disabled = _ref.disabled,
    249 |       placeholder = _ref.placeholder,
    250 |       searchOption = _ref.searchOption,
    251 |       value = _ref.value,
    252 |       onValueChange = _ref.onValueChange,
    253 |       onSearchResultChange = _ref.onSearchResultChange;
    254 |   return _react2['default'].createElement('input', {
    255 |     type: 'text',
    256 |     placeholder: placeholder,
    257 |     style: { width: '100%', border: 'none', background: 'transparent' },
    258 |     disabled: disabled,
    259 |     value: value !== null ? value : text,
    260 |     onChange: function onChange(e) {
    261 |       var keywords = e.target.value;
    262 |       // 修复IE11下bug
    263 |       if (value === null && text === '' && keywords === '') {
    264 |         onValueChange(null);
    265 |       } else {
    266 |         onValueChange(keywords);
    267 |       }
    268 |       if (searchOption) {
    269 |         searchOption.doSearch(keywords, function (searchResult) {
    270 |           onSearchResultChange(searchResult);
    271 |         });
    272 |       }
    273 |     }
    274 |   });
    275 | };
    276 |  
    277 | Search.propTypes = {
    278 |   value: _react.PropTypes.string,
    279 |   text: _react.PropTypes.string,
    280 |   disabled: _react.PropTypes.bool,
    281 |   placeholder: _react.PropTypes.string,
    282 |   searchOption: _react.PropTypes.object,
    283 |   onSearchResultChange: _react.PropTypes.func,
    284 |   onValueChange: _react.PropTypes.func
    285 | };
    286 |  
    287 | Search.renderResult = function (result, onSelect) {
    288 |   return _react2['default'].createElement(
    289 |     'div',
    290 |     {
    291 |       className: '',
    292 |       style: {
    293 |         background: '#fff',
    294 |         border: '1px solid #d9d9d9',
    295 |         boxShadow: '0 1px 4px 0 rgba(31,56,88,.15)',
    296 |         borderRadius: '3px',
    297 |         minWidth: '200px'
    298 |       }
    299 |     },
    300 |     _react2['default'].createElement(
    301 |       'ul',
    302 |       { className: 'kuma-select2-dropdown-menu' },
    303 |       result.map(function (item) {
    304 |         return _react2['default'].createElement(
    305 |           'li',
    306 |           {
    307 |             key: item.value,
    308 |             className: 'kuma-select2-dropdown-menu-item',
    309 |             onClick: function onClick() {
    310 |               return onSelect(item);
    311 |             },
    312 |             onMouseEnter: function onMouseEnter(e) {
    313 |               e.target.className += ' kuma-select2-dropdown-menu-item-active';
    314 |             },
    315 |             onMouseLeave: function onMouseLeave(e) {
    316 |               e.target.className = e.target.className.replace(' kuma-select2-dropdown-menu-item-active', '');
    317 |             }
    318 |           },
    319 |           item.label
    320 |         );
    321 |       })
    322 |     )
    323 |   );
    324 | };
    325 |  
    326 | exports['default'] = Search;
    327 | module.exports = exports['default'];
    328 |  
    330 |
    331 |
    332 | 336 | 337 | 338 | 345 | 346 | 347 | 348 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 2 | -------------------------------------------------------------------------------- /src/CascadeSelect.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * CascadeSelect Component for uxcore 3 | * @author changming.zy 4 | * 5 | * Copyright 2015-2017, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | import React from 'react'; 9 | import PropTypes from 'prop-types'; 10 | import classnames from 'classnames'; 11 | import Dropdown from 'uxcore-dropdown'; 12 | import Select2 from 'uxcore-select2'; 13 | import Promise from 'lie'; 14 | import i18n from './i18n'; 15 | import CascadeSubmenu from './CascadeSubmenu'; 16 | import SuperComponent from './SuperComponent'; 17 | import Search from './Search'; 18 | 19 | import { find, getArrayLeafItemContains, deepCopy, getOptions } from './util'; 20 | 21 | const noop = function noop() {}; 22 | class CascadeSelect extends SuperComponent { 23 | constructor(props) { 24 | super(props); 25 | const { options } = props; 26 | this.options = options.slice(); 27 | this.loadedOptions = {}; 28 | this.state = { 29 | displayValue: [], 30 | value: [], 31 | selectedOptions: [], 32 | showSubMenu: false, 33 | loading: {}, 34 | searchResult: [], 35 | inputValue: null, 36 | }; 37 | // 兼容老版本的locale code 38 | const { locale } = props; 39 | if (locale === 'zh_CN') { 40 | this.locale = 'zh-cn'; 41 | } else if (locale === 'en_US') { 42 | this.locale = 'en-us'; 43 | } else { 44 | this.locale = locale; 45 | } 46 | 47 | this.getSelectPlaceholder = props.getSelectPlaceholder || 48 | function getSelectPlaceholder() { return i18n[this.locale].placeholder; }; 49 | } 50 | 51 | componentDidMount() { 52 | this.setValue(this.props); 53 | } 54 | 55 | componentWillReceiveProps(nextProps) { 56 | const { options, value } = nextProps; 57 | if (options !== this.props.options) { 58 | this.options = options; 59 | this.loadedOptions = {}; 60 | } 61 | if ((value && deepCopy(value) !== deepCopy(this.props.value)) || 62 | (options !== this.props.options)) { 63 | this.setValue(nextProps); 64 | } 65 | } 66 | 67 | saveRef(refName) { 68 | const me = this; 69 | return (c) => { 70 | me[refName] = c; 71 | }; 72 | } 73 | /** 74 | * 获取options, 下面为请求第二层数据时的参数参考 75 | * @param {*} values 当前的values值, 如['jiangsu'] 76 | * @param {*} key 请求的key值, 如'jiangsu' 77 | * @param {*} level 请求的层数, 如 1 78 | */ 79 | fetchOptions(values, key, level) { 80 | let node = this.options; 81 | const { loading } = this.state; 82 | if (this.loadedOptions[key]) { 83 | return Promise.resolve('n'); 84 | } 85 | const { onSelect, cascadeSize } = this.props; 86 | if (onSelect && level < cascadeSize) { 87 | return new Promise((resolve, reject) => { 88 | loading[key] = true; 89 | this.setState({ loading }); 90 | onSelect(resolve, reject, key, level); 91 | }).then((children) => { 92 | this.loadedOptions[key] = true; 93 | values.forEach((value, index) => { 94 | if (index + 1 > level) { 95 | return; 96 | } 97 | node = find(node, item => item.value === value); 98 | if (node.children) { 99 | node = node.children; 100 | } 101 | }); 102 | node.children = children; 103 | loading[key] = false; 104 | this.setState({ loading }); 105 | return 'y'; 106 | }).catch(() => { 107 | loading[key] = false; 108 | this.setState({ loading }); 109 | }); 110 | } 111 | return Promise.resolve('n'); 112 | } 113 | 114 | setMultiState(selectedOptions) { 115 | let value; 116 | if (selectedOptions && selectedOptions.length) { 117 | value = selectedOptions.map(item => item.value); 118 | } 119 | this.setState({ 120 | displayValue: value || [], 121 | value: value || [], 122 | selectedOptions, 123 | }); 124 | } 125 | 126 | setValue(props) { 127 | const { onSelect } = props; 128 | if (onSelect) { 129 | this.getAsyncSelectedOptions(props, (selectedOptions) => { 130 | this.setMultiState(selectedOptions); 131 | }); 132 | } else { 133 | const selectedOptions = this.getSelectedOptions(props); 134 | this.setMultiState(selectedOptions); 135 | } 136 | } 137 | 138 | getAsyncSelectedOptions(props, callback = noop) { 139 | let selectedOptions = []; 140 | const { value, defaultValue, cascadeSize } = props; 141 | const { options } = this; 142 | const theValue = value || defaultValue; 143 | let renderArr = null; 144 | let prevSelected = null; 145 | const recursive = (i = 0) => { 146 | const len = theValue.length; 147 | if (len === 0) { 148 | callback.call(this, selectedOptions); 149 | return; 150 | } 151 | if (i === 0) { 152 | renderArr = options; 153 | } else { 154 | renderArr = prevSelected && prevSelected.children; 155 | } 156 | if (!renderArr && i < cascadeSize) { 157 | this.fetchOptions(theValue.slice(0, i), theValue[i - 1], i) 158 | .then(() => { 159 | renderArr = prevSelected && prevSelected.children; 160 | internalExecute.call(this, i, len); // eslint-disable-line 161 | }); 162 | } else { 163 | internalExecute.call(this, i, len); // eslint-disable-line 164 | } 165 | }; 166 | function internalExecute(i, len) { 167 | prevSelected = find(renderArr, item => item.value === theValue[i]); 168 | if (renderArr && prevSelected) { 169 | selectedOptions[i] = prevSelected; 170 | if (i + 1 === len) { 171 | callback.call(this, selectedOptions); 172 | } else { 173 | recursive(i + 1); 174 | } 175 | } else { 176 | selectedOptions = []; 177 | callback.call(this, selectedOptions); 178 | } 179 | } 180 | recursive(); 181 | } 182 | 183 | getSelectedOptions(props) { 184 | let selectedOptions = []; 185 | const { value, defaultValue } = props; 186 | const { options } = this; 187 | const theValue = value || defaultValue; 188 | if (theValue && theValue.length > 1) { 189 | let renderArr = null; 190 | let prevSelected = null; 191 | for (let i = 0, l = theValue.length; i < l; i++) { 192 | if (i === 0) { 193 | renderArr = options; 194 | } else { 195 | renderArr = prevSelected && prevSelected.children; 196 | } 197 | prevSelected = find(renderArr, item => item.value === theValue[i]); 198 | if (renderArr && prevSelected) { 199 | selectedOptions[i] = prevSelected; 200 | } else { 201 | selectedOptions = []; 202 | break; 203 | } 204 | } 205 | } else if (theValue && theValue.length === 1) { 206 | selectedOptions = getArrayLeafItemContains(options, theValue); 207 | } 208 | return selectedOptions; 209 | } 210 | 211 | onSubmenuItemClick = (key, index, selectedOption, hasChildren) => { 212 | const { value, selectedOptions } = this.state; 213 | const { changeOnSelect, cascadeSize, miniMode, onSelect } = this.props; 214 | let { showSubMenu } = this.state; 215 | let hideSubmenu = false; 216 | const newValue = value.slice(0, index); 217 | newValue.push(key); 218 | const newSelectedOptions = selectedOptions.slice(0, index); 219 | newSelectedOptions.push(selectedOption); 220 | 221 | if (!miniMode) { // 如果展示风格为复杂风格,则点击OK才进行onChange回调 222 | this.newValue = newValue; 223 | this.newSelectedOptions = newSelectedOptions; 224 | } else { 225 | this.onValueChange(newValue, newSelectedOptions); 226 | } 227 | 228 | let displayValue = newValue; 229 | if (!miniMode) { 230 | displayValue = []; 231 | } 232 | 233 | this.setState({ 234 | value: newValue, 235 | selectedOptions: newSelectedOptions, 236 | }); 237 | if (onSelect && (!hasChildren && (index + 1) < cascadeSize)) { 238 | if (!changeOnSelect) { 239 | displayValue = []; 240 | } 241 | this.setState({ 242 | displayValue, 243 | }); 244 | this.fetchOptions(newValue, key, (index + 1)); 245 | } else { 246 | if (!hasChildren || (index + 1) >= cascadeSize) { 247 | if (miniMode) { 248 | hideSubmenu = true; 249 | showSubMenu = false; 250 | } 251 | } 252 | // 如果还没选完整,displayValue置空 253 | if (!(changeOnSelect || hideSubmenu || (newValue.length >= cascadeSize))) { 254 | displayValue = []; 255 | } 256 | this.setState({ 257 | displayValue, 258 | showSubMenu, 259 | }); 260 | } 261 | } 262 | 263 | onValueChange(value, selectedOptions) { 264 | const { onChange, isMustSelectLeaf, cascadeSize } = this.props; 265 | if (onChange) { 266 | if (isMustSelectLeaf) { 267 | if ((value && (value.length >= cascadeSize || value.length === 0)) || 268 | (selectedOptions && 269 | ( 270 | (selectedOptions[selectedOptions.length - 1] && !selectedOptions[selectedOptions.length - 1].hasOwnProperty('children')) || 271 | selectedOptions.length === 0 272 | ) 273 | ) 274 | ) { 275 | onChange(value, selectedOptions); 276 | } 277 | } else { 278 | onChange(value, selectedOptions); 279 | } 280 | } 281 | } 282 | 283 | clearContent(e) { 284 | e.stopPropagation(); 285 | this.setState({ 286 | displayValue: [], 287 | value: [], 288 | selectedOptions: [], 289 | inputValue: null, 290 | }); 291 | this.onValueChange([], []); 292 | } 293 | 294 | onDropDownVisibleChange(visible) { 295 | const { disabled } = this.props; 296 | if (!disabled) { 297 | this.setState({ showSubMenu: visible }); 298 | } 299 | } 300 | 301 | renderContent() { 302 | const { 303 | className, 304 | disabled, 305 | clearable, 306 | } = this.props; 307 | 308 | const { selectedOptions, showSubMenu, displayValue } = this.state; 309 | 310 | let placeholder = this.props.placeholder; 311 | if (!placeholder) { 312 | placeholder = i18n[this.locale].placeholder; 313 | } 314 | 315 | const displayText = displayValue.length ? 316 | this.props.beforeRender(displayValue, selectedOptions) : 317 | ''; 318 | 319 | let cpnt = ( 320 |
    324 | { 325 | placeholder && !displayValue.length ? 326 |
    327 | {placeholder} 328 |
    : 329 | null 330 | } 331 | {displayText} 332 |
    333 | ); 334 | 335 | if (this.props.displayMode === 'search') { 336 | cpnt = ( 337 | { 344 | this.setState({ inputValue }); 345 | }} 346 | onSearchResultChange={(searchResult) => { 347 | this.setState({ searchResult, showSubMenu: true }); 348 | }} 349 | /> 350 | ); 351 | } 352 | 353 | return ( 354 |
    0, 361 | [this.prefixCls('focus')]: showSubMenu, 362 | [this.prefixCls(`size-${this.props.size}`)]: true, 363 | })} 364 | > 365 |
    366 | {cpnt} 367 |
    368 |
    374 | 375 |
    376 | { 377 |
    380 | 381 |
    382 | } 383 |
    384 | ); 385 | } 386 | 387 | renderSelect2Options(opt) { 388 | if (this.options) { 389 | return opt.map((optionItem) => ( 390 | 394 | {optionItem.label} 395 | 396 | )); 397 | } 398 | return null; 399 | } 400 | 401 | renderSelect() { 402 | const { value, loading } = this.state; 403 | const { options } = this; 404 | const { cascadeSize } = this.props; 405 | const back = []; 406 | const relLoading = {}; 407 | for (let i = 0; i < cascadeSize; i++) { 408 | const opt = getOptions(options, value, i); 409 | if (loading[value[i]]) { 410 | relLoading[i + 1] = true; 411 | } 412 | back.push(( 413 |
    418 |
    419 | { 429 | let stateValue = this.state.value; 430 | let selectedOptions = this.state.selectedOptions; 431 | if (i === 0) { 432 | stateValue = [v]; 433 | selectedOptions = options.filter(item => `${item.value}_` === `${v}_`); 434 | } else { 435 | stateValue[i] = v; 436 | selectedOptions[i] = opt.filter(item => `${item.value}_` === `${v}_`)[0]; 437 | stateValue = stateValue.slice(0, i + 1); 438 | selectedOptions = selectedOptions.slice(0, i + 1); 439 | } 440 | if (!(selectedOptions[i].children && selectedOptions[i].children.length)) { 441 | this.fetchOptions(stateValue, v, i + 1); 442 | } 443 | this.setState({ value: stateValue, selectedOptions }, () => { 444 | this.onValueChange(stateValue, selectedOptions); 445 | }); 446 | }} 447 | size={this.props.size} 448 | > 449 | {this.renderSelect2Options(opt)} 450 | 451 | { 452 | relLoading[i] ? 453 | : 454 | null 455 | } 456 |
    457 |
    458 | )); 459 | } 460 | return
    {back}
    ; 461 | } 462 | 463 | renderSearchResult() { 464 | const { options } = this.props; 465 | return Search.renderResult(this.state.searchResult, (item) => { 466 | const selectedOptions = this.getSelectedOptions({ 467 | value: [item.value], 468 | options, 469 | }); 470 | let val = []; 471 | if (selectedOptions && selectedOptions.length) { 472 | val = selectedOptions.map(i => i.value); 473 | } 474 | this.setState({ 475 | inputValue: null, 476 | searchResult: [], 477 | displayValue: val, 478 | value: val, 479 | selectedOptions, 480 | }, () => { 481 | this.props.onChange(val, selectedOptions); 482 | }); 483 | }); 484 | } 485 | 486 | getDomWidth(dom) { 487 | if (dom) { 488 | return parseFloat(getComputedStyle(dom).width); 489 | } else { 490 | return 0; 491 | } 492 | } 493 | 494 | render() { 495 | if (this.props.displayMode === 'select') { 496 | return this.renderSelect(); 497 | } 498 | 499 | const { 500 | disabled, 501 | prefixCls, 502 | expandTrigger, 503 | cascadeSize, 504 | getPopupContainer, 505 | columnWidth, 506 | displayMode, 507 | } = this.props; 508 | const { options } = this; 509 | const { value, loading } = this.state; 510 | if (disabled) { 511 | return this.renderContent(); 512 | } 513 | let submenu = ( 514 |
    518 | ); 519 | if (displayMode === 'search' && this.state.searchResult.length > 0) { 520 | submenu = this.renderSearchResult(); 521 | } else if (options.length && !disabled) { 522 | submenu = ( 523 | { 533 | this.wrapper.click(); 534 | const newValue = this.newValue; 535 | const newSelectedOptions = this.newSelectedOptions; 536 | if (newValue && newSelectedOptions) { 537 | this.setState({ 538 | value: newValue, 539 | displayValue: newValue, 540 | selectedOptions: newSelectedOptions, 541 | inputValue: null, 542 | }, () => { 543 | delete this.newValue; 544 | delete this.newSelectedOptions; 545 | this.onValueChange(newValue, newSelectedOptions); 546 | }); 547 | } 548 | }} 549 | columnWidth={this.props.columnWidth || this.getDomWidth(this.wrapper) / this.props.cascadeSize} 550 | size={this.props.size} 551 | loading={loading} 552 | className={this.prefixCls('submenu-warpper')} 553 | /> 554 | ); 555 | } 556 | return ( 557 | 565 | {this.renderContent()} 566 | 567 | ); 568 | } 569 | 570 | } 571 | 572 | CascadeSelect.defaultProps = { 573 | prefixCls: 'kuma-cascader', 574 | className: '', 575 | placeholder: '', 576 | options: [], 577 | defaultValue: [], 578 | value: null, 579 | onChange: () => { }, 580 | disabled: false, 581 | clearable: false, 582 | changeOnSelect: false, 583 | expandTrigger: 'click', 584 | cascadeSize: 3, 585 | beforeRender: (value, selectedOptions) => { 586 | if (selectedOptions.length) { 587 | return selectedOptions.map(o => o && o.label).join(' / '); 588 | } 589 | return value.join('/'); 590 | }, 591 | locale: 'zh-cn', 592 | miniMode: true, 593 | columnWidth: null, 594 | displayMode: 'dropdown', 595 | getSelectPlaceholder: null, 596 | size: 'large', 597 | isMustSelectLeaf: false, 598 | }; 599 | 600 | // http://facebook.github.io/react/docs/reusable-components.html 601 | CascadeSelect.propTypes = { 602 | prefixCls: PropTypes.string, 603 | className: PropTypes.string, 604 | options: PropTypes.array, 605 | defaultValue: PropTypes.array, 606 | value: PropTypes.array, 607 | placeholder: PropTypes.string, 608 | onChange: PropTypes.func, 609 | disabled: PropTypes.bool, 610 | clearable: PropTypes.bool, 611 | changeOnSelect: PropTypes.bool, 612 | expandTrigger: PropTypes.string, 613 | beforeRender: PropTypes.func, 614 | locale: PropTypes.oneOf(['zh-cn', 'en-us', 'zh_CN', 'en_US']), 615 | miniMode: PropTypes.bool, 616 | columnWidth: PropTypes.number, 617 | displayMode: PropTypes.oneOf(['dropdown', 'select', 'search']), 618 | getSelectPlaceholder: PropTypes.func, 619 | size: PropTypes.oneOf(['large', 'middle', 'small']), 620 | isMustSelectLeaf: PropTypes.bool, 621 | }; 622 | 623 | CascadeSelect.displayName = 'CascadeSelect'; 624 | 625 | module.exports = CascadeSelect; 626 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/index.js 3 | FNF:0 4 | FNH:0 5 | DA:11,1 6 | LF:1 7 | LH:1 8 | BRF:0 9 | BRH:0 10 | end_of_record 11 | TN: 12 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/CascadeSelect.jsx 13 | FN:45,_interopRequireDefault 14 | FN:47,_defaults 15 | FN:49,_defineProperty 16 | FN:51,_classCallCheck 17 | FN:53,_possibleConstructorReturn 18 | FN:55,_inherits 19 | FN:64,noop 20 | FN:66,(anonymous_8) 21 | FN:69,CascadeSelect 22 | FN:74,(anonymous_10) 23 | FN:158,getSelectPlaceholder 24 | FN:164,componentDidMount 25 | FN:168,componentWillReceiveProps 26 | FN:181,saveRef 27 | FN:183,(anonymous_15) 28 | FN:195,fetchOptions 29 | FN:209,(anonymous_17) 30 | FN:213,(anonymous_18) 31 | FN:215,(anonymous_19) 32 | FN:219,(anonymous_20) 33 | FN:230,(anonymous_21) 34 | FN:238,setMultiState 35 | FN:241,(anonymous_23) 36 | FN:252,setValue 37 | FN:258,(anonymous_25) 38 | FN:267,getAsyncSelectedOptions 39 | FN:281,recursive 40 | FN:295,(anonymous_28) 41 | FN:303,internalExecute 42 | FN:304,(anonymous_30) 43 | FN:322,getSelectedOptions 44 | FN:333,_loop 45 | FN:339,(anonymous_33) 46 | FN:361,onValueChange 47 | FN:378,clearContent 48 | FN:389,onDropDownVisibleChange 49 | FN:397,renderContent 50 | FN:440,onValueChange 51 | FN:443,onSearchResultChange 52 | FN:477,renderSelect2Options 53 | FN:479,(anonymous_41) 54 | FN:493,renderSelect 55 | FN:505,_loop2 56 | FN:531,onChange 57 | FN:536,(anonymous_45) 58 | FN:541,(anonymous_46) 59 | FN:550,(anonymous_47) 60 | FN:573,renderSearchResult 61 | FN:578,(anonymous_49) 62 | FN:585,(anonymous_50) 63 | FN:595,(anonymous_51) 64 | FN:601,getDomWidth 65 | FN:609,render 66 | FN:648,onOkButtonClick 67 | FN:658,(anonymous_55) 68 | FN:695,onChange 69 | FN:701,beforeRender 70 | FN:703,(anonymous_58) 71 | FNF:58 72 | FNH:48 73 | FNDA:10,_interopRequireDefault 74 | FNDA:1,_defaults 75 | FNDA:424,_defineProperty 76 | FNDA:20,_classCallCheck 77 | FNDA:20,_possibleConstructorReturn 78 | FNDA:1,_inherits 79 | FNDA:0,noop 80 | FNDA:1,(anonymous_8) 81 | FNDA:20,CascadeSelect 82 | FNDA:6,(anonymous_10) 83 | FNDA:27,getSelectPlaceholder 84 | FNDA:20,componentDidMount 85 | FNDA:1,componentWillReceiveProps 86 | FNDA:53,saveRef 87 | FNDA:101,(anonymous_15) 88 | FNDA:5,fetchOptions 89 | FNDA:4,(anonymous_17) 90 | FNDA:4,(anonymous_18) 91 | FNDA:6,(anonymous_19) 92 | FNDA:12,(anonymous_20) 93 | FNDA:0,(anonymous_21) 94 | FNDA:21,setMultiState 95 | FNDA:26,(anonymous_23) 96 | FNDA:21,setValue 97 | FNDA:2,(anonymous_25) 98 | FNDA:2,getAsyncSelectedOptions 99 | FNDA:6,recursive 100 | FNDA:4,(anonymous_28) 101 | FNDA:6,internalExecute 102 | FNDA:10,(anonymous_30) 103 | FNDA:19,getSelectedOptions 104 | FNDA:12,_loop 105 | FNDA:12,(anonymous_33) 106 | FNDA:8,onValueChange 107 | FNDA:1,clearContent 108 | FNDA:0,onDropDownVisibleChange 109 | FNDA:53,renderContent 110 | FNDA:0,onValueChange 111 | FNDA:0,onSearchResultChange 112 | FNDA:27,renderSelect2Options 113 | FNDA:38,(anonymous_41) 114 | FNDA:9,renderSelect 115 | FNDA:27,_loop2 116 | FNDA:1,onChange 117 | FNDA:0,(anonymous_45) 118 | FNDA:2,(anonymous_46) 119 | FNDA:1,(anonymous_47) 120 | FNDA:0,renderSearchResult 121 | FNDA:0,(anonymous_49) 122 | FNDA:0,(anonymous_50) 123 | FNDA:0,(anonymous_51) 124 | FNDA:41,getDomWidth 125 | FNDA:62,render 126 | FNDA:1,onOkButtonClick 127 | FNDA:1,(anonymous_55) 128 | FNDA:5,onChange 129 | FNDA:12,beforeRender 130 | FNDA:26,(anonymous_58) 131 | DA:3,1 132 | DA:5,1 133 | DA:7,1 134 | DA:9,1 135 | DA:11,1 136 | DA:13,1 137 | DA:15,1 138 | DA:17,1 139 | DA:19,1 140 | DA:21,1 141 | DA:23,1 142 | DA:25,1 143 | DA:27,1 144 | DA:29,1 145 | DA:31,1 146 | DA:33,1 147 | DA:35,1 148 | DA:37,1 149 | DA:39,1 150 | DA:41,1 151 | DA:43,1 152 | DA:45,10 153 | DA:47,6 154 | DA:49,424 155 | DA:51,20 156 | DA:53,20 157 | DA:55,1 158 | DA:64,1 159 | DA:66,1 160 | DA:67,1 161 | DA:69,1 162 | DA:70,20 163 | DA:72,20 164 | DA:74,20 165 | DA:75,6 166 | DA:78,6 167 | DA:83,6 168 | DA:85,6 169 | DA:86,6 170 | DA:87,6 171 | DA:88,6 172 | DA:89,6 173 | DA:91,6 174 | DA:93,1 175 | DA:94,1 176 | DA:96,5 177 | DA:99,6 178 | DA:100,6 179 | DA:101,1 180 | DA:104,6 181 | DA:108,6 182 | DA:109,0 183 | DA:110,0 184 | DA:112,0 185 | DA:115,0 186 | DA:117,6 187 | DA:118,3 188 | DA:119,3 189 | DA:120,3 190 | DA:124,6 191 | DA:125,3 192 | DA:127,6 193 | DA:134,20 194 | DA:136,20 195 | DA:137,20 196 | DA:138,20 197 | DA:148,20 198 | DA:150,20 199 | DA:151,0 200 | DA:152,20 201 | DA:153,4 202 | DA:155,16 203 | DA:158,20 204 | DA:159,27 205 | DA:161,20 206 | DA:164,1 207 | DA:165,20 208 | DA:168,1 209 | DA:169,1 210 | DA:172,1 211 | DA:173,1 212 | DA:174,1 213 | DA:176,1 214 | DA:177,1 215 | DA:181,1 216 | DA:182,53 217 | DA:183,53 218 | DA:184,101 219 | DA:195,1 220 | DA:196,5 221 | DA:198,5 222 | DA:199,5 223 | DA:201,5 224 | DA:202,0 225 | DA:204,5 226 | DA:208,5 227 | DA:209,4 228 | DA:210,4 229 | DA:211,4 230 | DA:212,4 231 | DA:214,4 232 | DA:215,4 233 | DA:216,6 234 | DA:217,0 235 | DA:219,6 236 | DA:220,12 237 | DA:222,6 238 | DA:223,2 239 | DA:226,4 240 | DA:227,4 241 | DA:228,4 242 | DA:229,4 243 | DA:231,0 244 | DA:232,0 245 | DA:235,1 246 | DA:238,1 247 | DA:239,21 248 | DA:240,21 249 | DA:241,9 250 | DA:242,26 251 | DA:245,21 252 | DA:252,1 253 | DA:253,21 254 | DA:255,21 255 | DA:257,21 256 | DA:258,2 257 | DA:259,2 258 | DA:262,19 259 | DA:263,19 260 | DA:267,1 261 | DA:268,2 262 | DA:270,2 263 | DA:272,2 264 | DA:273,2 265 | DA:276,2 266 | DA:278,2 267 | DA:279,2 268 | DA:280,2 269 | DA:281,2 270 | DA:282,6 271 | DA:284,6 272 | DA:285,6 273 | DA:286,0 274 | DA:287,0 275 | DA:289,6 276 | DA:290,2 277 | DA:292,4 278 | DA:294,6 279 | DA:295,4 280 | DA:296,4 281 | DA:297,4 282 | DA:300,2 283 | DA:303,1 284 | DA:304,6 285 | DA:305,10 286 | DA:307,6 287 | DA:308,6 288 | DA:309,6 289 | DA:310,2 290 | DA:312,4 291 | DA:315,0 292 | DA:316,0 293 | DA:319,2 294 | DA:322,1 295 | DA:323,19 296 | DA:324,19 297 | DA:326,19 298 | DA:328,19 299 | DA:329,19 300 | DA:330,4 301 | DA:331,4 302 | DA:333,4 303 | DA:334,12 304 | DA:335,4 305 | DA:337,8 306 | DA:339,12 307 | DA:340,12 308 | DA:342,12 309 | DA:343,12 310 | DA:345,0 311 | DA:346,0 312 | DA:350,4 313 | DA:351,12 314 | DA:353,12 315 | DA:355,15 316 | DA:356,4 317 | DA:358,19 318 | DA:361,1 319 | DA:362,8 320 | DA:367,8 321 | DA:368,8 322 | DA:369,1 323 | DA:370,1 324 | DA:373,7 325 | DA:378,1 326 | DA:379,1 327 | DA:380,1 328 | DA:386,1 329 | DA:389,1 330 | DA:390,0 331 | DA:392,0 332 | DA:393,0 333 | DA:397,1 334 | DA:398,53 335 | DA:402,53 336 | DA:406,53 337 | DA:412,53 338 | DA:413,53 339 | DA:414,51 340 | DA:417,53 341 | DA:419,53 342 | DA:433,53 343 | DA:434,4 344 | DA:441,0 345 | DA:444,0 346 | DA:449,53 347 | DA:477,1 348 | DA:478,27 349 | DA:479,27 350 | DA:480,38 351 | DA:490,0 352 | DA:493,1 353 | DA:494,9 354 | DA:496,9 355 | DA:499,9 356 | DA:500,9 357 | DA:502,9 358 | DA:503,9 359 | DA:505,9 360 | DA:506,27 361 | DA:507,27 362 | DA:508,0 363 | DA:510,27 364 | DA:532,1 365 | DA:533,1 366 | DA:534,1 367 | DA:535,0 368 | DA:536,0 369 | DA:537,0 370 | DA:540,1 371 | DA:541,1 372 | DA:542,2 373 | DA:544,1 374 | DA:545,1 375 | DA:547,1 376 | DA:548,1 377 | DA:550,1 378 | DA:551,1 379 | DA:563,9 380 | DA:564,27 381 | DA:566,9 382 | DA:573,1 383 | DA:574,0 384 | DA:576,0 385 | DA:578,0 386 | DA:579,0 387 | DA:583,0 388 | DA:584,0 389 | DA:585,0 390 | DA:586,0 391 | DA:589,0 392 | DA:596,0 393 | DA:601,1 394 | DA:602,41 395 | DA:603,28 396 | DA:605,13 397 | DA:609,1 398 | DA:610,62 399 | DA:612,62 400 | DA:613,9 401 | DA:616,53 402 | DA:624,53 403 | DA:625,53 404 | DA:629,53 405 | DA:630,2 406 | DA:632,51 407 | DA:636,51 408 | DA:637,0 409 | DA:638,51 410 | DA:639,45 411 | DA:649,1 412 | DA:650,1 413 | DA:651,1 414 | DA:652,1 415 | DA:653,1 416 | DA:659,1 417 | DA:660,1 418 | DA:661,1 419 | DA:671,51 420 | DA:685,1 421 | DA:688,1 422 | DA:702,12 423 | DA:703,12 424 | DA:704,26 425 | DA:707,0 426 | DA:719,1 427 | DA:741,1 428 | DA:743,1 429 | LF:298 430 | LH:261 431 | BRDA:45,1,0,0 432 | BRDA:45,1,1,10 433 | BRDA:45,2,0,10 434 | BRDA:45,2,1,10 435 | BRDA:47,3,0,1 436 | BRDA:47,3,1,5 437 | BRDA:47,4,0,6 438 | BRDA:47,4,1,6 439 | BRDA:47,4,2,1 440 | BRDA:49,5,0,0 441 | BRDA:49,5,1,424 442 | BRDA:51,6,0,0 443 | BRDA:51,6,1,20 444 | BRDA:53,7,0,0 445 | BRDA:53,7,1,20 446 | BRDA:53,8,0,20 447 | BRDA:53,8,1,0 448 | BRDA:53,9,0,20 449 | BRDA:53,9,1,20 450 | BRDA:53,9,2,0 451 | BRDA:55,10,0,0 452 | BRDA:55,10,1,1 453 | BRDA:55,11,0,1 454 | BRDA:55,11,1,0 455 | BRDA:55,12,0,1 456 | BRDA:55,12,1,1 457 | BRDA:55,13,0,1 458 | BRDA:55,13,1,0 459 | BRDA:55,14,0,0 460 | BRDA:55,14,1,1 461 | BRDA:91,15,0,1 462 | BRDA:91,15,1,5 463 | BRDA:100,16,0,1 464 | BRDA:100,16,1,5 465 | BRDA:108,17,0,0 466 | BRDA:108,17,1,6 467 | BRDA:108,18,0,6 468 | BRDA:108,18,1,0 469 | BRDA:108,18,2,0 470 | BRDA:109,19,0,0 471 | BRDA:109,19,1,0 472 | BRDA:117,20,0,3 473 | BRDA:117,20,1,3 474 | BRDA:117,21,0,6 475 | BRDA:117,21,1,3 476 | BRDA:118,22,0,3 477 | BRDA:118,22,1,0 478 | BRDA:124,23,0,3 479 | BRDA:124,23,1,3 480 | BRDA:124,24,0,6 481 | BRDA:124,24,1,6 482 | BRDA:124,24,2,3 483 | BRDA:150,25,0,0 484 | BRDA:150,25,1,20 485 | BRDA:152,26,0,4 486 | BRDA:152,26,1,16 487 | BRDA:158,27,0,20 488 | BRDA:158,27,1,20 489 | BRDA:172,28,0,1 490 | BRDA:172,28,1,0 491 | BRDA:176,29,0,1 492 | BRDA:176,29,1,0 493 | BRDA:176,30,0,1 494 | BRDA:176,30,1,1 495 | BRDA:176,30,2,0 496 | BRDA:201,31,0,0 497 | BRDA:201,31,1,5 498 | BRDA:208,32,0,4 499 | BRDA:208,32,1,1 500 | BRDA:208,33,0,5 501 | BRDA:208,33,1,4 502 | BRDA:216,34,0,0 503 | BRDA:216,34,1,6 504 | BRDA:222,35,0,2 505 | BRDA:222,35,1,4 506 | BRDA:240,36,0,9 507 | BRDA:240,36,1,12 508 | BRDA:240,37,0,21 509 | BRDA:240,37,1,21 510 | BRDA:246,38,0,21 511 | BRDA:246,38,1,12 512 | BRDA:247,39,0,21 513 | BRDA:247,39,1,12 514 | BRDA:257,40,0,2 515 | BRDA:257,40,1,19 516 | BRDA:270,41,0,2 517 | BRDA:270,41,1,0 518 | BRDA:270,42,0,2 519 | BRDA:270,42,1,2 520 | BRDA:278,43,0,2 521 | BRDA:278,43,1,0 522 | BRDA:282,44,0,4 523 | BRDA:282,44,1,2 524 | BRDA:282,45,0,6 525 | BRDA:282,45,1,4 526 | BRDA:285,46,0,0 527 | BRDA:285,46,1,6 528 | BRDA:289,47,0,2 529 | BRDA:289,47,1,4 530 | BRDA:292,48,0,4 531 | BRDA:292,48,1,4 532 | BRDA:294,49,0,4 533 | BRDA:294,49,1,2 534 | BRDA:294,50,0,6 535 | BRDA:294,50,1,4 536 | BRDA:296,51,0,4 537 | BRDA:296,51,1,4 538 | BRDA:307,52,0,6 539 | BRDA:307,52,1,0 540 | BRDA:307,53,0,6 541 | BRDA:307,53,1,6 542 | BRDA:309,54,0,2 543 | BRDA:309,54,1,4 544 | BRDA:328,55,0,19 545 | BRDA:328,55,1,14 546 | BRDA:329,56,0,4 547 | BRDA:329,56,1,15 548 | BRDA:329,57,0,19 549 | BRDA:329,57,1,19 550 | BRDA:334,58,0,4 551 | BRDA:334,58,1,8 552 | BRDA:337,59,0,8 553 | BRDA:337,59,1,8 554 | BRDA:342,60,0,12 555 | BRDA:342,60,1,0 556 | BRDA:342,61,0,12 557 | BRDA:342,61,1,12 558 | BRDA:353,62,0,0 559 | BRDA:353,62,1,12 560 | BRDA:355,63,0,4 561 | BRDA:355,63,1,11 562 | BRDA:355,64,0,15 563 | BRDA:355,64,1,15 564 | BRDA:367,65,0,8 565 | BRDA:367,65,1,0 566 | BRDA:368,66,0,1 567 | BRDA:368,66,1,7 568 | BRDA:369,67,0,1 569 | BRDA:369,67,1,0 570 | BRDA:369,68,0,1 571 | BRDA:369,68,1,1 572 | BRDA:369,68,2,0 573 | BRDA:369,68,3,0 574 | BRDA:392,69,0,0 575 | BRDA:392,69,1,0 576 | BRDA:413,70,0,51 577 | BRDA:413,70,1,2 578 | BRDA:417,71,0,12 579 | BRDA:417,71,1,41 580 | BRDA:425,72,0,41 581 | BRDA:425,72,1,12 582 | BRDA:425,73,0,53 583 | BRDA:425,73,1,53 584 | BRDA:433,74,0,4 585 | BRDA:433,74,1,49 586 | BRDA:453,75,0,53 587 | BRDA:453,75,1,51 588 | BRDA:453,75,2,3 589 | BRDA:478,76,0,27 590 | BRDA:478,76,1,0 591 | BRDA:507,77,0,0 592 | BRDA:507,77,1,27 593 | BRDA:534,78,0,0 594 | BRDA:534,78,1,1 595 | BRDA:547,79,0,1 596 | BRDA:547,79,1,0 597 | BRDA:547,80,0,1 598 | BRDA:547,80,1,0 599 | BRDA:558,81,0,0 600 | BRDA:558,81,1,27 601 | BRDA:584,82,0,0 602 | BRDA:584,82,1,0 603 | BRDA:584,83,0,0 604 | BRDA:584,83,1,0 605 | BRDA:602,84,0,28 606 | BRDA:602,84,1,13 607 | BRDA:612,85,0,9 608 | BRDA:612,85,1,53 609 | BRDA:629,86,0,2 610 | BRDA:629,86,1,51 611 | BRDA:634,87,0,4 612 | BRDA:634,87,1,47 613 | BRDA:636,88,0,0 614 | BRDA:636,88,1,51 615 | BRDA:636,89,0,51 616 | BRDA:636,89,1,4 617 | BRDA:638,90,0,45 618 | BRDA:638,90,1,6 619 | BRDA:638,91,0,51 620 | BRDA:638,91,1,45 621 | BRDA:652,92,0,1 622 | BRDA:652,92,1,0 623 | BRDA:652,93,0,1 624 | BRDA:652,93,1,1 625 | BRDA:665,94,0,45 626 | BRDA:665,94,1,41 627 | BRDA:702,95,0,12 628 | BRDA:702,95,1,0 629 | BRDA:704,96,0,26 630 | BRDA:704,96,1,23 631 | BRF:200 632 | BRH:153 633 | end_of_record 634 | TN: 635 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/i18n.js 636 | FNF:0 637 | FNH:0 638 | DA:3,1 639 | LF:1 640 | LH:1 641 | BRF:0 642 | BRH:0 643 | end_of_record 644 | TN: 645 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/CascadeSubmenu.jsx 646 | FN:7,(anonymous_1) 647 | FN:35,_interopRequireDefault 648 | FN:37,_defaults 649 | FN:39,_defineProperty 650 | FN:41,_classCallCheck 651 | FN:43,_possibleConstructorReturn 652 | FN:45,_inherits 653 | FN:54,isNotEmpty 654 | FN:61,(anonymous_9) 655 | FN:64,CascadeSubmenu 656 | FN:70,onItemClick 657 | FN:76,onItemHover 658 | FN:80,(anonymous_13) 659 | FN:87,renderUlList 660 | FN:92,(anonymous_15) 661 | FN:120,renderLoading 662 | FN:124,renderSubmenus 663 | FN:157,(anonymous_18) 664 | FN:164,(anonymous_19) 665 | FN:184,renderBottomBar 666 | FN:198,renderAllSelection 667 | FN:211,(anonymous_22) 668 | FN:224,render 669 | FN:267,onItemClick 670 | FN:272,onOkButtonClick 671 | FNF:25 672 | FNH:22 673 | FNDA:74,(anonymous_1) 674 | FNDA:6,_interopRequireDefault 675 | FNDA:1,_defaults 676 | FNDA:19,_defineProperty 677 | FNDA:13,_classCallCheck 678 | FNDA:13,_possibleConstructorReturn 679 | FNDA:1,_inherits 680 | FNDA:74,isNotEmpty 681 | FNDA:1,(anonymous_9) 682 | FNDA:13,CascadeSubmenu 683 | FNDA:2,onItemClick 684 | FNDA:1,onItemHover 685 | FNDA:1,(anonymous_13) 686 | FNDA:19,renderUlList 687 | FNDA:74,(anonymous_15) 688 | FNDA:0,renderLoading 689 | FNDA:13,renderSubmenus 690 | FNDA:9,(anonymous_18) 691 | FNDA:9,(anonymous_19) 692 | FNDA:3,renderBottomBar 693 | FNDA:3,renderAllSelection 694 | FNDA:3,(anonymous_22) 695 | FNDA:13,render 696 | FNDA:0,onItemClick 697 | FNDA:0,onOkButtonClick 698 | DA:3,1 699 | DA:7,74 700 | DA:9,1 701 | DA:11,1 702 | DA:13,1 703 | DA:15,1 704 | DA:17,1 705 | DA:19,1 706 | DA:21,1 707 | DA:23,1 708 | DA:25,1 709 | DA:27,1 710 | DA:29,1 711 | DA:31,1 712 | DA:33,1 713 | DA:35,6 714 | DA:37,6 715 | DA:39,19 716 | DA:41,13 717 | DA:43,13 718 | DA:45,1 719 | DA:54,1 720 | DA:55,74 721 | DA:56,68 722 | DA:58,6 723 | DA:61,1 724 | DA:62,1 725 | DA:64,1 726 | DA:65,13 727 | DA:67,13 728 | DA:70,1 729 | DA:71,2 730 | DA:72,2 731 | DA:76,1 732 | DA:77,1 733 | DA:79,1 734 | DA:80,1 735 | DA:81,1 736 | DA:82,1 737 | DA:87,1 738 | DA:88,19 739 | DA:90,19 740 | DA:92,19 741 | DA:93,74 742 | DA:94,74 743 | DA:95,54 744 | DA:96,20 745 | DA:97,20 746 | DA:100,74 747 | DA:101,9 748 | DA:102,3 749 | DA:104,6 750 | DA:108,74 751 | DA:120,1 752 | DA:121,0 753 | DA:124,1 754 | DA:125,13 755 | DA:127,13 756 | DA:135,13 757 | DA:136,13 758 | DA:137,13 759 | DA:138,3 760 | DA:140,13 761 | DA:141,13 762 | DA:142,13 763 | DA:143,3 764 | DA:145,10 765 | DA:147,13 766 | DA:156,13 767 | DA:157,13 768 | DA:158,9 769 | DA:159,9 770 | DA:160,6 771 | DA:162,3 772 | DA:164,9 773 | DA:165,9 774 | DA:167,9 775 | DA:168,9 776 | DA:169,9 777 | DA:170,6 778 | DA:181,13 779 | DA:184,1 780 | DA:185,3 781 | DA:186,3 782 | DA:187,3 783 | DA:198,1 784 | DA:199,3 785 | DA:200,3 786 | DA:212,3 787 | DA:224,1 788 | DA:225,13 789 | DA:226,13 790 | DA:227,1 791 | DA:232,13 792 | DA:249,1 793 | DA:252,1 794 | DA:265,1 795 | DA:277,1 796 | DA:279,1 797 | DA:280,1 798 | LF:100 799 | LH:99 800 | BRDA:7,1,0,1 801 | BRDA:7,1,1,1 802 | BRDA:7,2,0,74 803 | BRDA:7,2,1,0 804 | BRDA:35,3,0,0 805 | BRDA:35,3,1,6 806 | BRDA:35,4,0,6 807 | BRDA:35,4,1,6 808 | BRDA:37,5,0,1 809 | BRDA:37,5,1,5 810 | BRDA:37,6,0,6 811 | BRDA:37,6,1,6 812 | BRDA:37,6,2,1 813 | BRDA:39,7,0,0 814 | BRDA:39,7,1,19 815 | BRDA:41,8,0,0 816 | BRDA:41,8,1,13 817 | BRDA:43,9,0,0 818 | BRDA:43,9,1,13 819 | BRDA:43,10,0,13 820 | BRDA:43,10,1,0 821 | BRDA:43,11,0,13 822 | BRDA:43,11,1,13 823 | BRDA:43,11,2,0 824 | BRDA:45,12,0,0 825 | BRDA:45,12,1,1 826 | BRDA:45,13,0,1 827 | BRDA:45,13,1,0 828 | BRDA:45,14,0,1 829 | BRDA:45,14,1,1 830 | BRDA:45,15,0,1 831 | BRDA:45,15,1,0 832 | BRDA:45,16,0,0 833 | BRDA:45,16,1,1 834 | BRDA:55,17,0,68 835 | BRDA:55,17,1,6 836 | BRDA:71,18,0,2 837 | BRDA:71,18,1,0 838 | BRDA:81,19,0,1 839 | BRDA:81,19,1,0 840 | BRDA:94,20,0,54 841 | BRDA:94,20,1,20 842 | BRDA:96,21,0,20 843 | BRDA:96,21,1,0 844 | BRDA:100,22,0,9 845 | BRDA:100,22,1,65 846 | BRDA:101,23,0,3 847 | BRDA:101,23,1,6 848 | BRDA:137,24,0,3 849 | BRDA:137,24,1,10 850 | BRDA:142,25,0,3 851 | BRDA:142,25,1,10 852 | BRDA:142,26,0,13 853 | BRDA:142,26,1,13 854 | BRDA:159,27,0,6 855 | BRDA:159,27,1,3 856 | BRDA:159,28,0,9 857 | BRDA:159,28,1,9 858 | BRDA:164,29,0,9 859 | BRDA:164,29,1,3 860 | BRDA:167,30,0,9 861 | BRDA:167,30,1,9 862 | BRDA:169,31,0,6 863 | BRDA:169,31,1,3 864 | BRDA:169,32,0,9 865 | BRDA:169,32,1,3 866 | BRDA:174,33,0,6 867 | BRDA:174,33,1,0 868 | BRDA:177,34,0,0 869 | BRDA:177,34,1,6 870 | BRDA:186,35,0,3 871 | BRDA:186,35,1,0 872 | BRDA:211,36,0,1 873 | BRDA:211,36,1,2 874 | BRDA:226,37,0,1 875 | BRDA:226,37,1,12 876 | BRDA:242,38,0,10 877 | BRDA:242,38,1,3 878 | BRDA:244,39,0,10 879 | BRDA:244,39,1,3 880 | BRF:80 881 | BRH:63 882 | end_of_record 883 | TN: 884 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/util.js 885 | FN:9,(anonymous_1) 886 | FN:11,(anonymous_2) 887 | FN:19,(anonymous_3) 888 | FN:40,deepCopy 889 | FN:44,getArrayLeafItemContains 890 | FN:48,recursion 891 | FN:51,(anonymous_7) 892 | FN:65,(anonymous_8) 893 | FN:73,getOptions 894 | FNF:9 895 | FNH:8 896 | FNDA:1,(anonymous_1) 897 | FNDA:0,(anonymous_2) 898 | FNDA:33,(anonymous_3) 899 | FNDA:4,deepCopy 900 | FNDA:4,getArrayLeafItemContains 901 | FNDA:16,recursion 902 | FNDA:29,(anonymous_7) 903 | FNDA:8,(anonymous_8) 904 | FNDA:36,getOptions 905 | DA:3,1 906 | DA:6,1 907 | DA:7,1 908 | DA:9,1 909 | DA:10,1 910 | DA:11,0 911 | DA:12,0 912 | DA:13,0 913 | DA:16,0 914 | DA:19,1 915 | DA:20,33 916 | DA:21,0 917 | DA:23,33 918 | DA:24,0 919 | DA:26,33 920 | DA:27,33 921 | DA:28,33 922 | DA:30,33 923 | DA:31,43 924 | DA:32,43 925 | DA:33,33 926 | DA:36,0 927 | DA:40,1 928 | DA:41,4 929 | DA:44,1 930 | DA:45,4 931 | DA:46,4 932 | DA:47,4 933 | DA:48,1 934 | DA:49,16 935 | DA:51,16 936 | DA:52,29 937 | DA:53,18 938 | DA:54,3 939 | DA:55,3 940 | DA:57,18 941 | DA:58,12 942 | DA:62,4 943 | DA:63,4 944 | DA:64,3 945 | DA:65,3 946 | DA:66,8 947 | DA:67,8 948 | DA:70,3 949 | DA:73,1 950 | DA:74,36 951 | DA:75,36 952 | DA:77,36 953 | DA:78,15 954 | DA:80,21 955 | DA:81,9 956 | DA:82,12 957 | DA:83,9 958 | DA:87,12 959 | DA:90,1 960 | DA:96,1 961 | LF:56 962 | LH:49 963 | BRDA:10,1,0,0 964 | BRDA:10,1,1,1 965 | BRDA:20,2,0,0 966 | BRDA:20,2,1,33 967 | BRDA:23,3,0,0 968 | BRDA:23,3,1,33 969 | BRDA:32,4,0,33 970 | BRDA:32,4,1,10 971 | BRDA:49,5,0,12 972 | BRDA:49,5,1,4 973 | BRDA:49,6,0,16 974 | BRDA:49,6,1,12 975 | BRDA:52,7,0,11 976 | BRDA:52,7,1,18 977 | BRDA:53,8,0,3 978 | BRDA:53,8,1,15 979 | BRDA:57,9,0,12 980 | BRDA:57,9,1,6 981 | BRDA:63,10,0,1 982 | BRDA:63,10,1,3 983 | BRDA:74,11,0,36 984 | BRDA:74,11,1,0 985 | BRDA:74,12,0,36 986 | BRDA:74,12,1,36 987 | BRDA:75,13,0,36 988 | BRDA:75,13,1,0 989 | BRDA:75,14,0,36 990 | BRDA:75,14,1,36 991 | BRDA:77,15,0,15 992 | BRDA:77,15,1,21 993 | BRDA:77,16,0,36 994 | BRDA:77,16,1,15 995 | BRDA:80,17,0,9 996 | BRDA:80,17,1,12 997 | BRDA:82,18,0,9 998 | BRDA:82,18,1,3 999 | BRF:36 1000 | BRH:31 1001 | end_of_record 1002 | TN: 1003 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/SuperComponent.js 1004 | FN:7,_defaults 1005 | FN:9,_classCallCheck 1006 | FN:11,_possibleConstructorReturn 1007 | FN:13,_inherits 1008 | FN:17,(anonymous_5) 1009 | FN:20,SuperComponent 1010 | FN:26,prefixCls 1011 | FN:29,(anonymous_8) 1012 | FNF:8 1013 | FNH:8 1014 | FNDA:1,_defaults 1015 | FNDA:33,_classCallCheck 1016 | FNDA:33,_possibleConstructorReturn 1017 | FNDA:1,_inherits 1018 | FNDA:1,(anonymous_5) 1019 | FNDA:33,SuperComponent 1020 | FNDA:787,prefixCls 1021 | FNDA:800,(anonymous_8) 1022 | DA:3,1 1023 | DA:7,5 1024 | DA:9,33 1025 | DA:11,33 1026 | DA:13,1 1027 | DA:15,1 1028 | DA:17,1 1029 | DA:18,1 1030 | DA:20,1 1031 | DA:21,33 1032 | DA:23,33 1033 | DA:26,1 1034 | DA:27,787 1035 | DA:29,787 1036 | DA:30,800 1037 | DA:34,1 1038 | DA:37,1 1039 | DA:41,1 1040 | DA:42,1 1041 | LF:19 1042 | LH:19 1043 | BRDA:7,1,0,0 1044 | BRDA:7,1,1,5 1045 | BRDA:7,2,0,5 1046 | BRDA:7,2,1,5 1047 | BRDA:7,2,2,0 1048 | BRDA:9,3,0,0 1049 | BRDA:9,3,1,33 1050 | BRDA:11,4,0,0 1051 | BRDA:11,4,1,33 1052 | BRDA:11,5,0,0 1053 | BRDA:11,5,1,33 1054 | BRDA:11,6,0,33 1055 | BRDA:11,6,1,0 1056 | BRDA:11,6,2,0 1057 | BRDA:13,7,0,0 1058 | BRDA:13,7,1,1 1059 | BRDA:13,8,0,1 1060 | BRDA:13,8,1,0 1061 | BRDA:13,9,0,1 1062 | BRDA:13,9,1,1 1063 | BRDA:13,10,0,1 1064 | BRDA:13,10,1,0 1065 | BRDA:13,11,0,0 1066 | BRDA:13,11,1,1 1067 | BRF:24 1068 | BRH:13 1069 | end_of_record 1070 | TN: 1071 | SF:/Users/xuzhifei/Documents/work/uxcore-cascade-select/src/Search.jsx 1072 | FN:11,_interopRequireDefault 1073 | FN:13,Search 1074 | FN:27,onChange 1075 | FN:36,(anonymous_4) 1076 | FN:54,(anonymous_5) 1077 | FN:70,(anonymous_6) 1078 | FN:76,onClick 1079 | FN:79,onMouseEnter 1080 | FN:82,onMouseLeave 1081 | FNF:9 1082 | FNH:2 1083 | FNDA:1,_interopRequireDefault 1084 | FNDA:4,Search 1085 | FNDA:0,onChange 1086 | FNDA:0,(anonymous_4) 1087 | FNDA:0,(anonymous_5) 1088 | FNDA:0,(anonymous_6) 1089 | FNDA:0,onClick 1090 | FNDA:0,onMouseEnter 1091 | FNDA:0,onMouseLeave 1092 | DA:3,1 1093 | DA:7,1 1094 | DA:9,1 1095 | DA:11,1 1096 | DA:13,1 1097 | DA:14,4 1098 | DA:21,4 1099 | DA:28,0 1100 | DA:30,0 1101 | DA:31,0 1102 | DA:33,0 1103 | DA:35,0 1104 | DA:36,0 1105 | DA:37,0 1106 | DA:44,1 1107 | DA:54,1 1108 | DA:55,0 1109 | DA:71,0 1110 | DA:77,0 1111 | DA:80,0 1112 | DA:83,0 1113 | DA:93,1 1114 | DA:94,1 1115 | LF:23 1116 | LH:11 1117 | BRDA:11,1,0,0 1118 | BRDA:11,1,1,1 1119 | BRDA:11,2,0,1 1120 | BRDA:11,2,1,1 1121 | BRDA:26,3,0,0 1122 | BRDA:26,3,1,4 1123 | BRDA:30,4,0,0 1124 | BRDA:30,4,1,0 1125 | BRDA:30,5,0,0 1126 | BRDA:30,5,1,0 1127 | BRDA:30,5,2,0 1128 | BRDA:35,6,0,0 1129 | BRDA:35,6,1,0 1130 | BRF:13 1131 | BRH:4 1132 | end_of_record 1133 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/CascadeSubmenu.jsx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/CascadeSubmenu.jsx 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
    17 |
    18 |

    19 | all files / src/ CascadeSubmenu.jsx 20 |

    21 |
    22 |
    23 | 96.09% 24 | Statements 25 | 123/128 26 |
    27 |
    28 | 78.75% 29 | Branches 30 | 63/80 31 |
    32 |
    33 | 88% 34 | Functions 35 | 22/25 36 |
    37 |
    38 | 99% 39 | Lines 40 | 99/100 41 |
    42 |
    43 |
    44 |
    45 |
    
     46 | 
    887 | 
    1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97 143 | 98 144 | 99 145 | 100 146 | 101 147 | 102 148 | 103 149 | 104 150 | 105 151 | 106 152 | 107 153 | 108 154 | 109 155 | 110 156 | 111 157 | 112 158 | 113 159 | 114 160 | 115 161 | 116 162 | 117 163 | 118 164 | 119 165 | 120 166 | 121 167 | 122 168 | 123 169 | 124 170 | 125 171 | 126 172 | 127 173 | 128 174 | 129 175 | 130 176 | 131 177 | 132 178 | 133 179 | 134 180 | 135 181 | 136 182 | 137 183 | 138 184 | 139 185 | 140 186 | 141 187 | 142 188 | 143 189 | 144 190 | 145 191 | 146 192 | 147 193 | 148 194 | 149 195 | 150 196 | 151 197 | 152 198 | 153 199 | 154 200 | 155 201 | 156 202 | 157 203 | 158 204 | 159 205 | 160 206 | 161 207 | 162 208 | 163 209 | 164 210 | 165 211 | 166 212 | 167 213 | 168 214 | 169 215 | 170 216 | 171 217 | 172 218 | 173 219 | 174 220 | 175 221 | 176 222 | 177 223 | 178 224 | 179 225 | 180 226 | 181 227 | 182 228 | 183 229 | 184 230 | 185 231 | 186 232 | 187 233 | 188 234 | 189 235 | 190 236 | 191 237 | 192 238 | 193 239 | 194 240 | 195 241 | 196 242 | 197 243 | 198 244 | 199 245 | 200 246 | 201 247 | 202 248 | 203 249 | 204 250 | 205 251 | 206 252 | 207 253 | 208 254 | 209 255 | 210 256 | 211 257 | 212 258 | 213 259 | 214 260 | 215 261 | 216 262 | 217 263 | 218 264 | 219 265 | 220 266 | 221 267 | 222 268 | 223 269 | 224 270 | 225 271 | 226 272 | 227 273 | 228 274 | 229 275 | 230 276 | 231 277 | 232 278 | 233 279 | 234 280 | 235 281 | 236 282 | 237 283 | 238 284 | 239 285 | 240 286 | 241 287 | 242 288 | 243 289 | 244 290 | 245 291 | 246 292 | 247 293 | 248 294 | 249 295 | 250 296 | 251 297 | 252 298 | 253 299 | 254 300 | 255 301 | 256 302 | 257 303 | 258 304 | 259 305 | 260 306 | 261 307 | 262 308 | 263 309 | 264 310 | 265 311 | 266 312 | 267 313 | 268 314 | 269 315 | 270 316 | 271 317 | 272 318 | 273 319 | 274 320 | 275 321 | 276 322 | 277 323 | 278 324 | 279 325 | 280 326 | 281  327 |   328 | 329 |   330 |   331 |   332 | 74× 333 |   334 | 335 |   336 | 337 |   338 | 339 |   340 | 341 |   342 | 343 |   344 | 345 |   346 | 347 |   348 | 349 |   350 | 351 |   352 | 353 |   354 | 355 |   356 | 357 |   358 | 359 |   360 | 361 |   362 | 363 |   364 | 19× 365 |   366 | 13× 367 |   368 | 13× 369 |   370 | 371 |   372 |   373 |   374 |   375 |   376 |   377 |   378 |   379 | 380 | 74× 381 | 68× 382 |   383 | 384 |   385 |   386 | 387 | 388 |   389 | 390 | 13× 391 |   392 | 13× 393 |   394 |   395 | 396 | 397 | 398 |   399 |   400 |   401 | 402 | 403 |   404 | 405 | 406 | 407 | 408 |   409 |   410 |   411 |   412 | 413 | 19× 414 |   415 | 19× 416 |   417 | 19× 418 | 74× 419 | 74× 420 | 54× 421 | 20× 422 | 20× 423 |   424 |   425 | 74× 426 | 427 | 428 |   429 | 430 |   431 |   432 |   433 | 74× 434 |   435 |   436 |   437 |   438 |   439 |   440 |   441 |   442 |   443 |   444 |   445 | 446 |   447 |   448 |   449 | 450 | 13× 451 |   452 | 13× 453 |   454 |   455 |   456 |   457 |   458 |   459 |   460 | 13× 461 | 13× 462 | 13× 463 | 464 |   465 | 13× 466 | 13× 467 | 13× 468 | 469 |   470 | 10× 471 |   472 | 13× 473 |   474 |   475 |   476 |   477 |   478 |   479 |   480 |   481 | 13× 482 | 13× 483 | 484 | 485 | 486 |   487 | 488 |   489 | 490 | 491 |   492 | 493 | 494 | 495 | 496 |   497 |   498 |   499 |   500 |   501 |   502 |   503 |   504 |   505 |   506 | 13× 507 |   508 |   509 | 510 | 511 | 512 | 513 |   514 |   515 |   516 |   517 |   518 |   519 |   520 |   521 |   522 |   523 | 524 | 525 | 526 |   527 |   528 |   529 |   530 |   531 |   532 |   533 |   534 |   535 |   536 |   537 | 538 |   539 |   540 |   541 |   542 |   543 |   544 |   545 |   546 |   547 |   548 |   549 | 550 | 13× 551 | 13× 552 | 553 |   554 |   555 |   556 |   557 | 13× 558 |   559 |   560 |   561 |   562 |   563 |   564 |   565 |   566 |   567 |   568 |   569 |   570 |   571 |   572 |   573 |   574 | 575 |   576 |   577 | 578 |   579 |   580 |   581 |   582 |   583 |   584 |   585 |   586 |   587 |   588 |   589 |   590 | 591 |   592 |   593 |   594 |   595 |   596 |   597 |   598 |   599 |   600 |   601 |   602 | 603 |   604 | 605 | 606 |  
    'use strict';
    607 |  
    608 | Object.defineProperty(exports, "__esModule", {
    609 |   value: true
    610 | });
    611 |  
    612 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { Eif (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
    613 |  
    614 | var _react = require('react');
    615 |  
    616 | var _react2 = _interopRequireDefault(_react);
    617 |  
    618 | var _propTypes = require('prop-types');
    619 |  
    620 | var _propTypes2 = _interopRequireDefault(_propTypes);
    621 |  
    622 | var _classnames3 = require('classnames');
    623 |  
    624 | var _classnames4 = _interopRequireDefault(_classnames3);
    625 |  
    626 | var _uxcoreButton = require('uxcore-button');
    627 |  
    628 | var _uxcoreButton2 = _interopRequireDefault(_uxcoreButton);
    629 |  
    630 | var _util = require('./util');
    631 |  
    632 | var _i18n = require('./i18n');
    633 |  
    634 | var _i18n2 = _interopRequireDefault(_i18n);
    635 |  
    636 | var _SuperComponent2 = require('./SuperComponent');
    637 |  
    638 | var _SuperComponent3 = _interopRequireDefault(_SuperComponent2);
    639 |  
    640 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
    641 |  
    642 | function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = Object.getOwnPropertyDescriptor(defaults, key); if (value && value.configurable && obj[key] === undefined) { Object.defineProperty(obj, key, value); } } return obj; }
    643 |  
    644 | function _defineProperty(obj, key, value) { Iif (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
    645 |  
    646 | function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    647 |  
    648 | function _possibleConstructorReturn(self, call) { Iif (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
    649 |  
    650 | function _inherits(subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass); } /**
    651 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * CascadeSelect Component for uxcore
    652 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @author changming
    653 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                *
    654 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * Copyright 2015-2017, Uxcore Team, Alinw.
    655 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * All rights reserved.
    656 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
    657 |  
    658 |  
    659 | var isNotEmpty = function isNotEmpty(arr) {
    660 |   if (arr instanceof Array) {
    661 |     return arr.length;
    662 |   }
    663 |   return false;
    664 | };
    665 |  
    666 | var CascadeSubmenu = function (_SuperComponent) {
    667 |   _inherits(CascadeSubmenu, _SuperComponent);
    668 |  
    669 |   function CascadeSubmenu() {
    670 |     _classCallCheck(this, CascadeSubmenu);
    671 |  
    672 |     return _possibleConstructorReturn(this, _SuperComponent.apply(this, arguments));
    673 |   }
    674 |  
    675 |   CascadeSubmenu.prototype.onItemClick = function onItemClick(item, groupIndex, hasChildren) {
    676 |     Eif (this.props.onItemClick) {
    677 |       this.props.onItemClick(item.value, groupIndex, item, hasChildren);
    678 |     }
    679 |   };
    680 |  
    681 |   CascadeSubmenu.prototype.onItemHover = function onItemHover(item, groupIndex, hasChildren) {
    682 |     var _this2 = this;
    683 |  
    684 |     clearTimeout(this.timeout);
    685 |     this.timeout = setTimeout(function () {
    686 |       Eif (_this2.props.onItemClick) {
    687 |         _this2.props.onItemClick(item.value, groupIndex, item, hasChildren);
    688 |       }
    689 |     }, 400);
    690 |   };
    691 |  
    692 |   CascadeSubmenu.prototype.renderUlList = function renderUlList(data, key, groupIndex) {
    693 |     var _this3 = this;
    694 |  
    695 |     var expandTrigger = this.props.expandTrigger;
    696 |  
    697 |     return data.map(function (item) {
    698 |       var otherProps = {};
    699 |       if (expandTrigger === 'click') {
    700 |         otherProps.onClick = _this3.onItemClick.bind(_this3, item, groupIndex, isNotEmpty(item.children));
    701 |       } else Eif (expandTrigger === 'hover') {
    702 |         otherProps.onMouseOver = _this3.onItemHover.bind(_this3, item, groupIndex, isNotEmpty(item.children));
    703 |       }
    704 |  
    705 |       if (item.value === key) {
    706 |         if (groupIndex === 0) {
    707 |           _this3.displayData = [item.label];
    708 |         } else {
    709 |           _this3.displayData[groupIndex] = item.label;
    710 |         }
    711 |       }
    712 |  
    713 |       return _react2['default'].createElement(
    714 |         'li',
    715 |         _extends({
    716 |           key: item.value,
    717 |           title: item.label,
    718 |           className: (0, _classnames4['default'])({ active: item.value === key })
    719 |         }, otherProps),
    720 |         item.label
    721 |       );
    722 |     });
    723 |   };
    724 |  
    725 |   CascadeSubmenu.prototype.renderLoading = function renderLoading() {
    726 |     return _react2['default'].createElement('div', { className: 'kuma-loading-s ' + this.prefixCls('center-loading') });
    727 |   };
    728 |  
    729 |   CascadeSubmenu.prototype.renderSubmenus = function renderSubmenus() {
    730 |     var _this4 = this;
    731 |  
    732 |     var _props = this.props,
    733 |         value = _props.value,
    734 |         options = _props.options,
    735 |         expandTrigger = _props.expandTrigger,
    736 |         cascadeSize = _props.cascadeSize,
    737 |         miniMode = _props.miniMode,
    738 |         loading = _props.loading;
    739 |  
    740 |     var submenu = [];
    741 |     var columnSize = cascadeSize;
    742 |     if (!miniMode) {
    743 |       columnSize = cascadeSize + 1;
    744 |     }
    745 |     var unitWidth = (100 / columnSize).toFixed(1) + '%';
    746 |     var firstStyle = {};
    747 |     if (value && value.length > 0) {
    748 |       firstStyle.width = unitWidth;
    749 |     } else {
    750 |       firstStyle.width = '100%';
    751 |     }
    752 |     submenu.push(_react2['default'].createElement(
    753 |       'ul',
    754 |       {
    755 |         className: (0, _classnames4['default'])(_defineProperty({}, this.prefixCls('hoverable'), expandTrigger === 'hover')),
    756 |         key: 'firstMenu',
    757 |         style: firstStyle
    758 |       },
    759 |       this.renderUlList(options, value[0], 0)
    760 |     ));
    761 |     var prevSelected = null;
    762 |     value.forEach(function (key, index) {
    763 |       var style = {};
    764 |       if (value && value.length > index + 1) {
    765 |         style.width = unitWidth;
    766 |       } else {
    767 |         style.width = ((cascadeSize - value.length) / columnSize * 100).toFixed(1) + '%';
    768 |       }
    769 |       var parent = (0, _util.find)(prevSelected || options, function (item) {
    770 |         return item.value === key;
    771 |       });
    772 |       var renderArr = parent && parent.children;
    773 |       prevSelected = renderArr;
    774 |       if (renderArr || loading[key]) {
    775 |         submenu.push(_react2['default'].createElement(
    776 |           'ul',
    777 |           {
    778 |             key: key,
    779 |             className: (0, _classnames4['default'])(_defineProperty({}, _this4.prefixCls('hoverable'), expandTrigger === 'hover' && index < cascadeSize - 1)),
    780 |             style: style
    781 |           },
    782 |           loading[key] ? _this4.renderLoading() : _this4.renderUlList(renderArr, value[index + 1], index + 1)
    783 |         ));
    784 |       }
    785 |     });
    786 |     return submenu;
    787 |   };
    788 |  
    789 |   CascadeSubmenu.prototype.renderBottomBar = function renderBottomBar() {
    790 |     var size = this.props.size;
    791 |     var btnSize = size === 'large' ? 'medium' : 'small';
    792 |     return _react2['default'].createElement(
    793 |       'div',
    794 |       { className: this.prefixCls('submenu-bottom-bar') },
    795 |       _react2['default'].createElement(
    796 |         _uxcoreButton2['default'],
    797 |         { size: btnSize, onClick: this.props.onOkButtonClick },
    798 |         _i18n2['default'][this.props.locale].confirm
    799 |       )
    800 |     );
    801 |   };
    802 |  
    803 |   CascadeSubmenu.prototype.renderAllSelection = function renderAllSelection() {
    804 |     var width = (100 / (this.props.cascadeSize + 1)).toFixed(1) + '%';
    805 |     return _react2['default'].createElement(
    806 |       'div',
    807 |       { style: { width: width }, className: this.prefixCls('submenu-all-selection') },
    808 |       _react2['default'].createElement(
    809 |         'div',
    810 |         { className: this.prefixCls('submenu-all-selection-title') },
    811 |         _i18n2['default'][this.props.locale].alreadyChoosed
    812 |       ),
    813 |       _react2['default'].createElement(
    814 |         'div',
    815 |         { className: this.prefixCls('submenu-all-body') },
    816 |         this.displayData ? this.displayData.map(function (label, idx) {
    817 |           return _react2['default'].createElement(
    818 |             'div',
    819 |             { key: idx, style: { marginLeft: 12 * idx } },
    820 |             _react2['default'].createElement('i', { className: 'kuma-icon kuma-icon-chevron-right' }),
    821 |             ' ',
    822 |             label
    823 |           );
    824 |         }) : null
    825 |       )
    826 |     );
    827 |   };
    828 |  
    829 |   CascadeSubmenu.prototype.render = function render() {
    830 |     var wrapStyle = {};
    831 |     if (this.props.columnWidth) {
    832 |       wrapStyle.width = this.props.columnWidth * this.props.cascadeSize;
    833 |       // if (!this.props.miniMode) {
    834 |       //   wrapStyle.width = this.props.columnWidth * (this.props.cascadeSize + 1);
    835 |       // }
    836 |     }
    837 |     return _react2['default'].createElement(
    838 |       'div',
    839 |       { className: this.props.className },
    840 |       _react2['default'].createElement(
    841 |         'div',
    842 |         { className: this.prefixCls('submenu size-' + this.props.size), style: wrapStyle },
    843 |         _react2['default'].createElement(
    844 |           'div',
    845 |           { className: this.prefixCls('submenu-wrap') },
    846 |           this.renderSubmenus(),
    847 |           this.props.miniMode ? null : this.renderAllSelection()
    848 |         ),
    849 |         this.props.miniMode ? null : this.renderBottomBar()
    850 |       )
    851 |     );
    852 |   };
    853 |  
    854 |   return CascadeSubmenu;
    855 | }(_SuperComponent3['default']);
    856 |  
    857 | CascadeSubmenu.propTypes = {
    858 |   prefixCls: _propTypes2['default'].string,
    859 |   onItemClick: _propTypes2['default'].func,
    860 |   value: _propTypes2['default'].array,
    861 |   options: _propTypes2['default'].array,
    862 |   miniMode: _propTypes2['default'].bool,
    863 |   onOkButtonClick: _propTypes2['default'].func,
    864 |   columnWidth: _propTypes2['default'].number,
    865 |   cascadeSize: _propTypes2['default'].number,
    866 |   size: _propTypes2['default'].oneOf(['large', 'middle', 'small']),
    867 |   className: _propTypes2['default'].string
    868 | };
    869 |  
    870 | CascadeSubmenu.defaultProps = {
    871 |   prefixCls: 'kuma-cascader',
    872 |   onItemClick: function onItemClick() {},
    873 |  
    874 |   value: [],
    875 |   options: [],
    876 |   miniMode: false,
    877 |   onOkButtonClick: function onOkButtonClick() {},
    878 |   size: 'large',
    879 |   className: ''
    880 | };
    881 |  
    882 | CascadeSubmenu.displayName = 'CascadeSubmenu';
    883 |  
    884 | exports['default'] = CascadeSubmenu;
    885 | module.exports = exports['default'];
    886 |  
    888 |
    889 |
    890 | 894 |
    895 | 896 | 903 | 904 | 905 | 906 | --------------------------------------------------------------------------------