├── .yo-rc.json ├── .eslintignore ├── coverage └── lcov-report │ ├── sort-arrow-sprite.png │ ├── prettify.css │ ├── src │ ├── index.js.html │ ├── i18n.js.html │ ├── index.html │ ├── utils.js.html │ ├── TreeSelect.js.html │ └── RightTreeNode.jsx.html │ ├── index.html │ ├── sorter.js │ ├── base.css │ └── prettify.js ├── tests ├── index.js ├── const.js ├── utils.spec.js ├── Select.rightTree.spec.js ├── Select.multiple.spec.js ├── Select.checkable.spec.js └── TreeSelect.spec.js ├── src ├── index.js ├── i18n.js ├── TreeSelect.js ├── utils.js ├── RightTreeNode.jsx ├── SelectTrigger.jsx └── TreeSelect.less ├── demo ├── index.js ├── TreeSelectDemo.less └── TreeSelectDemo.js ├── .gitignore ├── .npmignore ├── .eslintrc.json ├── index.html ├── .travis.yml ├── HISTORY.md ├── package.json └── README.md /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-uxcore": {} 3 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | demo/ 2 | build/ 3 | mock/ 4 | dist/ -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WisestCoder/uxcore-tree-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 | * TreeSelect Component for uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | module.exports = require('./TreeSelect'); 10 | -------------------------------------------------------------------------------- /demo/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TreeSelect Component Demo for uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | var Demo = require('./TreeSelectDemo'); 10 | ReactDOM.render(, document.getElementById('UXCoreDemo')); 11 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "env": { 7 | "browser": true 8 | }, 9 | "rules": { 10 | "import/no-extraneous-dependencies": "off", 11 | "react/jsx-no-bind": "off", 12 | "no-underscore-dangle": ["off"], 13 | "arrow-body-style": ["off"] 14 | }, 15 | "parser": "babel-eslint" 16 | } 17 | -------------------------------------------------------------------------------- /src/i18n.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'zh-cn': { 3 | placeholder: '请选择', 4 | confirm: '确定', 5 | alreadyChoosed: '已选择', 6 | pleaseSelectFromLeft: '请从左侧选择', 7 | clear: '清空', 8 | delete: '删除', 9 | all: '全选', 10 | }, 11 | 'en-us': { 12 | placeholder: 'Please select', 13 | confirm: 'OK', 14 | alreadyChoosed: 'Choosed', 15 | pleaseSelectFromLeft: 'Please select from left', 16 | clear: 'clear', 17 | delete: 'Delete', 18 | all: 'All', 19 | }, 20 | }; 21 | -------------------------------------------------------------------------------- /tests/const.js: -------------------------------------------------------------------------------- 1 | const options = [{ 2 | value: 'zhejiang', 3 | label: '浙江', 4 | children: [{ 5 | value: 'hangzhou', 6 | label: '杭州', 7 | children: [{ 8 | value: 'xihu', 9 | label: '西湖', 10 | }], 11 | }], 12 | }, { 13 | value: 'jiangsu', 14 | label: '江苏', 15 | children: [{ 16 | value: 'nanjing', 17 | label: '南京', 18 | children: [{ 19 | value: 'zhonghuamen', 20 | label: '中华门', 21 | }], 22 | }], 23 | }]; 24 | 25 | export default options; 26 | -------------------------------------------------------------------------------- /demo/TreeSelectDemo.less: -------------------------------------------------------------------------------- 1 | /** 2 | * TreeSelect Component Demo Style for Uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | html { 9 | box-sizing: border-box; 10 | * { 11 | box-sizing: inherit; 12 | } 13 | } 14 | 15 | @import "../node_modules/kuma-base/variable"; 16 | @svg-path: '../node_modules/kuma-base/core/svg/blue'; 17 | @import "../node_modules/kuma-base/core"; 18 | @import "../src/TreeSelect.less"; 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 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | uxcore-tree-select 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.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" -------------------------------------------------------------------------------- /src/TreeSelect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TreeSelect Component for uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | import RcTreeSelect from './Select'; 9 | import assign from 'object-assign'; 10 | import TreeNode from 'rc-tree-select/lib/TreeNode'; 11 | import strategies from 'rc-tree-select/lib/strategies'; 12 | 13 | 14 | let supportSVG = false; 15 | if (typeof document !== 'undefined') { 16 | supportSVG = document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1'); 17 | } 18 | 19 | class TreeSelect extends RcTreeSelect {} 20 | 21 | TreeSelect.TreeNode = TreeNode; 22 | assign(TreeSelect, strategies); 23 | TreeSelect.displayName = 'TreeSelect'; 24 | 25 | TreeSelect.defaultProps = assign(RcTreeSelect.defaultProps, { 26 | prefixCls: 'uxcore-tree-select', 27 | dropdownClassName: supportSVG ? 'use-svg' : 'no-svg', 28 | transitionName: 'slideUp', 29 | choiceTransitionName: 'uxcore-tree-select-selection__choice-zoom', 30 | showSearch: false, 31 | dropdownMatchSelectWidth: false, 32 | maxTagTextLength: 10, 33 | locale: 'zh-cn', 34 | }); 35 | 36 | TreeSelect.propTypes = RcTreeSelect.propTypes; 37 | 38 | 39 | module.exports = TreeSelect; 40 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # HISTORY 2 | 3 | --- 4 | 5 | ## 0.4.3 6 | 7 | * `FIXED` add `rc-tree-select` missing utils functions. 8 | 9 | ## 0.4.2 10 | 11 | * `FIXED` fix `rc-tree-select` version to `1.12.10` 12 | 13 | ## 0.4.1 14 | 15 | * `FIX` clear inputValue when nextProps.value is empty. 16 | 17 | ## 0.4.0 18 | 19 | * `UPDATE` rc-tree-select@1.12.0, change extend-style to usage-style. 20 | 21 | ## 0.3.2 22 | 23 | * `FIXED` inputMirrorInstance is undefined [reference](https://github.com/uxcore/uxcore-tree-select/issues/7) 24 | 25 | ## 0.3.1 26 | 27 | * `FIXED` rc-tree-select@1.11.0 is a breaking change for the component 28 | 29 | ## 0.3.0 30 | 31 | * `UPDATE` React 15 32 | 33 | ## 0.2.4 34 | 35 | * `FIXED` lock tree version, fix switcher arrow style 36 | 37 | ## 0.2.3 38 | 39 | * `FIXED` server render bug 40 | 41 | ## 0.2.2 42 | 43 | `FIXED` i18n 44 | 45 | ## 0.2.1 46 | 47 | `FIXED` fix missing dependencies 48 | 49 | ## 0.2.0 50 | 51 | `CHANGED` add new prop `resultsPanelAllClearBtn` , `resultsPanelTitle`, `resultsPanelTitleStyle` & `filterResultsPanel` 52 | 53 | ## 0.1.4 54 | 55 | `FIXED` add missing loading icon. 56 | 57 | 58 | ## 0.1.3 59 | `CHANGED` change hover & selected styles 60 | 61 | ## 0.1.2 62 | `UPDATE` change some styles 63 | 64 | ## 0.1.1 65 | `UPDATE` change some styles 66 | 67 | ## 0.1.0 68 | `NEW` first version base on rc-tree-select 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uxcore-tree-select", 3 | "version": "0.4.3", 4 | "description": "uxcore-tree-select component for uxcore.", 5 | "repository": "https://github.com/uxcore/uxcore-tree-select.git", 6 | "author": "biangang.bg", 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 electron", 14 | "coverage": "uxcore-tools run electron-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-tree-select/issues" 26 | }, 27 | "keywords": [ 28 | "react", 29 | "react-component", 30 | "uxcore-tree-select", 31 | "TreeSelect", 32 | "uxcore", 33 | "react", 34 | "component" 35 | ], 36 | "devDependencies": { 37 | "console-polyfill": "^0.2.2", 38 | "enzyme": "^3.2.0", 39 | "enzyme-adapter-react-15": "^1.0.5", 40 | "es5-shim": "^4.5.8", 41 | "expect.js": "~0.3.1", 42 | "kuma-base": "1.x", 43 | "react": "15.x", 44 | "react-dom": "15.x", 45 | "react-test-renderer": "15.x", 46 | "uxcore-kuma": "*", 47 | "uxcore-tools": "0.2.x" 48 | }, 49 | "dependencies": { 50 | "classnames": "^2.1.2", 51 | "object-assign": "~4.1.0", 52 | "prop-types": "15.x", 53 | "rc-tree": "~1.7.1", 54 | "rc-tree-select": "~1.12.10", 55 | "rc-trigger": "^2.2.2", 56 | "rc-util": "^4.0.2" 57 | }, 58 | "contributors": [], 59 | "license": "MIT" 60 | } -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | import { isPositionPrefix, isInclude, isMultiple } from 'rc-tree-select/lib/util'; 2 | 3 | // Refactor 4 | export function flatToHierarchy(arr, flag = false) { 5 | if (!arr.length) { 6 | return arr; 7 | } 8 | const hierarchyNodes = []; 9 | const levelObj = {}; 10 | arr.forEach((item) => { 11 | if (!item.pos) { 12 | return; 13 | } 14 | const posLen = item.pos.split('-').length; 15 | if (!levelObj[posLen]) { 16 | levelObj[posLen] = []; 17 | } 18 | levelObj[posLen].push(item); 19 | }); 20 | // levelObj 收集每个层级的child 21 | const levelArr = Object.keys(levelObj).sort((a, b) => b - a); 22 | 23 | // const s = Date.now(); 24 | // todo: there are performance issues! 25 | levelArr.reduce((pre, cur) => { 26 | if (cur && cur !== pre) { 27 | levelObj[pre].forEach((item) => { 28 | let haveParent = false; 29 | levelObj[cur].forEach((ii) => { 30 | if (isPositionPrefix(ii.pos, item.pos)) { 31 | haveParent = true; 32 | // select multiple模式下的筛选 33 | if (flag && ii.isAll) { 34 | return; 35 | } 36 | if (!ii.children) { 37 | ii.children = []; // eslint-disable-line 38 | } 39 | ii.children.push(item); 40 | } 41 | }); 42 | if (!haveParent) { 43 | hierarchyNodes.push(item); 44 | } 45 | }); 46 | } 47 | return cur; 48 | }); 49 | // console.log(Date.now() - s); 50 | return levelObj[levelArr[levelArr.length - 1]].concat(hierarchyNodes); 51 | } 52 | 53 | export function isMultipleOrTags(props) { 54 | return !!(isMultiple(props) || props.tags); 55 | } 56 | 57 | export function isMultipleOrTagsOrCombobox(props) { 58 | return (isMultiple(props) || props.tags || props.combobox); 59 | } 60 | 61 | export function isSingleMode(props) { 62 | return !(isMultiple(props) || props.tags || props.combobox); 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /tests/utils.spec.js: -------------------------------------------------------------------------------- 1 | import { flatToHierarchy, filterCheckedKeysBaseKey } from '../src/utils'; 2 | import React from 'react'; 3 | import Enzyme from 'enzyme'; 4 | import expect from 'expect.js'; 5 | import TreeSelect from '../src'; 6 | import Adapter from 'enzyme-adapter-react-15'; 7 | // import focusTest from './shared/focusTest'; 8 | 9 | const { mount, render } = Enzyme; 10 | 11 | Enzyme.configure({ adapter: new Adapter() }); 12 | 13 | describe('Utils', () => { 14 | describe('flatToHierarchy', () => { 15 | const array = [ 16 | { 17 | value: '0-0', 18 | pos: '0-0', 19 | }, 20 | { 21 | value: '0', 22 | pos: '0', 23 | children: [ 24 | { 25 | value: '0-0', 26 | pos: '0-0', 27 | }, 28 | ], 29 | }, 30 | ]; 31 | const array2 = [ 32 | { 33 | value: '0-0', 34 | pos: '0-0', 35 | isAll: true, 36 | }, 37 | { 38 | value: '0', 39 | pos: '0', 40 | isAll: true, 41 | children: [ 42 | { 43 | value: '0-0', 44 | pos: '0-0', 45 | }, 46 | ], 47 | }, 48 | ]; 49 | const array3 = [...array2]; 50 | it('test equal array to tree with flag=false', () => { 51 | expect(JSON.stringify(flatToHierarchy(array))).to.equal(JSON.stringify([ 52 | { 53 | value: '0', 54 | pos: '0', 55 | children: [ 56 | { 57 | value: '0-0', 58 | pos: '0-0', 59 | }, 60 | { 61 | value: '0-0', 62 | pos: '0-0', 63 | }, 64 | ], 65 | }, 66 | ])); 67 | }); 68 | 69 | it('test equal array to tree with flag=true', () => { 70 | expect(JSON.stringify(flatToHierarchy(array2, true))).to.equal(JSON.stringify([ 71 | { 72 | value: '0', 73 | pos: '0', 74 | isAll: true, 75 | children: [ 76 | { 77 | value: '0-0', 78 | pos: '0-0', 79 | }, 80 | ], 81 | }, 82 | ])); 83 | }); 84 | 85 | it('test equal array with isAll to tree with flag=false', () => { 86 | expect(JSON.stringify(flatToHierarchy(array3))).to.equal(JSON.stringify([ 87 | { 88 | value: '0', 89 | pos: '0', 90 | isAll: true, 91 | children: [ 92 | { 93 | value: '0-0', 94 | pos: '0-0', 95 | }, 96 | { 97 | value: '0-0', 98 | pos: '0-0', 99 | isAll: true, 100 | }, 101 | ], 102 | }, 103 | ])); 104 | }); 105 | }); 106 | }); 107 | -------------------------------------------------------------------------------- /tests/Select.rightTree.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import expect from 'expect.js'; 3 | import Enzyme from 'enzyme'; 4 | import TreeSelect from '../src'; 5 | import Adapter from 'enzyme-adapter-react-15'; 6 | import options from './const'; 7 | 8 | const { mount, render } = Enzyme; 9 | 10 | Enzyme.configure({ adapter: new Adapter() }); 11 | 12 | describe('Tree Right', () => { 13 | const treeData = [ 14 | { key: 'a', value: 'a', label: 'labela' }, 15 | { key: 'b', value: 'b', label: 'labelb' }, 16 | ]; 17 | const treeData2 = [ 18 | { key: 'a', value: 'a', label: 'labela', children: [ 19 | { key: 'b', value: 'b', label: 'labelb' }, 20 | ] }, 21 | ]; 22 | 23 | it('render title', () => { 24 | const wrapper = mount( 25 | 30 | ); 31 | const trigger = mount(wrapper.find('Trigger').props().popup); 32 | expect(trigger.find('.uxcore-tree-select-dropdown-right-title').text()).to.equal('haha'); 33 | }); 34 | 35 | it('render chooseable number', () => { 36 | const wrapper = mount( 37 | 43 | ); 44 | const trigger = mount(wrapper.find('Trigger').props().popup); 45 | expect(trigger.find('.uxcore-tree-select-dropdown-right-selected-number').text()).to.equal('(2)'); 46 | }); 47 | 48 | it('allow to expend', () => { 49 | const wrapper = mount( 50 | 56 | ); 57 | const trigger = mount(wrapper.find('Trigger').props().popup); 58 | trigger.find('.uxcore-tree-select-rightTreeNode-arrow-close').simulate('click'); 59 | expect(trigger.find('.uxcore-tree-select-rightTreeNode-label')).to.have.length(2); 60 | }); 61 | 62 | it('allow to remove', () => { 63 | const wrapper = mount( 64 | 70 | ); 71 | const trigger = mount(wrapper.find('Trigger').props().popup); 72 | trigger.find('.uxcore-tree-select-rightTreeNode-clear').simulate('click'); 73 | expect(wrapper.state().value).to.have.length(0); 74 | }); 75 | 76 | it('allow to removeAll', () => { 77 | const wrapper = mount( 78 | 84 | ); 85 | const trigger = mount(wrapper.find('Trigger').props().popup); 86 | trigger.find('.uxcore-tree-select-dropdown-right-allClear').simulate('click'); 87 | expect(wrapper.state().value).to.have.length(0); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /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 |  * TreeSelect Component for uxcore
72 |  * @author biangang.bg
73 |  *
74 |  * Copyright 2014-2015, Uxcore Team, Alinw.
75 |  * All rights reserved.
76 |  */
77 |  
78 | module.exports = require('./TreeSelect');
79 |  
81 |
82 |
83 | 87 | 88 | 89 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /tests/Select.multiple.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import React from 'react'; 3 | import Enzyme from 'enzyme'; 4 | import expect from 'expect.js'; 5 | import TreeSelect from '../src'; 6 | import Adapter from 'enzyme-adapter-react-15'; 7 | 8 | const { mount, render } = Enzyme; 9 | 10 | Enzyme.configure({ adapter: new Adapter() }); 11 | 12 | describe('TreeSelect.multiple', () => { 13 | const treeData = [ 14 | { key: '0', value: '0', label: 'label0' }, 15 | { key: '1', value: '1', label: 'label1' }, 16 | ]; 17 | const createSelect = (props) => ( 18 | 23 | ); 24 | const select = (wrapper, index = 0) => { 25 | // console.log('-----xxxxx-----', wrapper.find('.uxcore-tree-select-tree-node-content-wrapper')); 26 | wrapper.find('.uxcore-tree-select-tree-node-content-wrapper').at(index).simulate('click'); 27 | }; 28 | 29 | it('render by inputValue', () => { 30 | const wrapper = mount(createSelect({ inputValue: '0' })); 31 | const choices = wrapper.find('.uxcore-tree-select-search__field'); 32 | expect(choices.prop('value')).to.equal('0'); 33 | }); 34 | 35 | it('select multiple nodes', () => { 36 | const wrapper = mount(createSelect({ open: true })); 37 | const trigger = mount(wrapper.find('Trigger').props().popup); 38 | select(trigger, 0); 39 | select(trigger, 1); 40 | wrapper.update(); 41 | const result = wrapper.find('.uxcore-tree-select-selection__choice'); 42 | const choices = wrapper.find('.uxcore-tree-select-selection__choice__content'); 43 | expect(result).to.have.length(2); 44 | expect(choices.at(0).prop('children')).to.be('label0'); 45 | expect(choices.at(1).prop('children')).to.be('label1'); 46 | }); 47 | 48 | it('remove selected node', () => { 49 | const wrapper = mount(createSelect({ defaultValue: ['0', '1'] })); 50 | wrapper.find('.uxcore-tree-select-selection__choice__remove').first().simulate('click'); 51 | // const choice = wrapper.find('.uxcore-tree-select-selection__choice'); 52 | // expect(choice).to.have.length(1); 53 | // expect(choice.prop('children')).to.be('label1'); 54 | expect(wrapper.state('value')).to.have.length(1); 55 | expect(wrapper.state('value')[0].label).to.be('label1'); 56 | }); 57 | 58 | it('remove by backspace key', () => { 59 | const wrapper = mount(createSelect({ defaultValue: ['0', '1'] })); 60 | wrapper.find('input').simulate('keyDown', { keyCode: 8 }); // 回退键 61 | // const choice = wrapper.find('.uxcore-tree-select-selection__choice__content'); 62 | // expect(choice).to.have.length(1); 63 | // expect(choice.prop('children')).to.be('label0'); 64 | expect(wrapper.state('value')).to.have.length(1); 65 | expect(wrapper.state('value')[0].label).to.be('label0'); 66 | }); 67 | 68 | it('focus', () => { 69 | const handleFocus = () => {}; 70 | const treeData2 = [ 71 | { key: '0', value: '0', label: '0 label' }, 72 | ]; 73 | const wrapper = mount( 74 | 79 | ); 80 | wrapper.instance().focus(); 81 | expect(handleFocus).to.not.throwException(); 82 | }); 83 | 84 | it('blur', () => { 85 | const handleBlur = () => {}; 86 | const treeData2 = [ 87 | { key: '0', value: '0', label: '0 label' }, 88 | ]; 89 | const wrapper = mount( 90 | 95 | ); 96 | wrapper.instance().focus(); 97 | wrapper.instance().blur(); 98 | expect(handleBlur).to.not.throwException(); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /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 | 81.79% 24 | Statements 25 | 804/983 26 |
27 |
28 | 69.81% 29 | Branches 30 | 481/689 31 |
32 |
33 | 83.72% 34 | Functions 35 | 144/172 36 |
37 |
38 | 86.27% 39 | Lines 40 | 754/874 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/
81.79%804/98369.81%481/68983.72%144/17286.27%754/874
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/RightTreeNode.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * RightTreeNode Component for Tree 3 | * @author chenqiu wb-cq231719@alibaba-inc.com 4 | */ 5 | 6 | import React from 'react'; 7 | import PropTypes from 'prop-types'; 8 | import classnames from 'classnames'; 9 | import i18n from './i18n'; 10 | 11 | export default class RightTreeNode extends React.Component { 12 | constructor(props) { 13 | super(props); 14 | this.state = { 15 | expand: !(props.isAll || (this.isSelectNode() && props.children)), 16 | }; 17 | } 18 | 19 | componentWillReceiveProps(nextProps) { 20 | if (this.props.isAll !== nextProps.isAll) { 21 | this.setState({ 22 | expand: !nextProps.isAll, 23 | }); 24 | } 25 | } 26 | 27 | getMaxWidth(isSelectNode, paddingLeftStyle) { 28 | const { locale, children, isAll, dropdownWidth, disabled } = this.props; 29 | // padding:32, delete:26, isALL: 38, arrow: 18 30 | let padWidth = 20; 31 | if (isAll || (isSelectNode && children)) { 32 | padWidth += locale === 'en-us' ? 25 : 36; 33 | } 34 | if (isSelectNode && !disabled) { 35 | padWidth += locale === 'en-us' ? 38 : 26; 36 | } 37 | if (children) { 38 | padWidth += 18; 39 | } 40 | 41 | return (dropdownWidth - padWidth - paddingLeftStyle); 42 | } 43 | 44 | removeSelected = () => { 45 | const { removeSelected, value } = this.props; 46 | 47 | removeSelected(value); 48 | } 49 | 50 | isSelectNode() { 51 | const { pos, keys } = this.props; 52 | 53 | return keys.indexOf(pos) > -1; 54 | } 55 | 56 | expand = () => { 57 | this.setState({ 58 | expand: !this.state.expand, 59 | }); 60 | } 61 | 62 | render() { 63 | const { treeNodeLabelProp, children, isAll, prefixCls, level, locale, disabled } = this.props; 64 | const { expand } = this.state; 65 | // padding 无箭头 +36 有箭头+18 66 | let paddingLeft = 0; 67 | if (level > 1) { 68 | paddingLeft = !children ? (16 + (level - 1) * 18) : (16 + (level - 2) * 18); 69 | } else if (level === 1 && !children) { 70 | // fix style for the first level label which has no Children 71 | paddingLeft = 5; 72 | } 73 | const arrowCls = { 74 | [`${prefixCls}-arrow-close`]: !expand, 75 | [`${prefixCls}-arrow-open`]: expand, 76 | [`${prefixCls}-arrow-switch`]: true, 77 | }; 78 | const isSelectNode = this.isSelectNode(); 79 | 80 | const maxWidth = this.getMaxWidth(isSelectNode, paddingLeft); 81 | 82 | const content = ( 87 | {this.props[treeNodeLabelProp]} 88 | ); 89 | 90 | return ( 91 |
92 |
93 | { 94 | children ? 95 | 96 | : null 97 | } 98 | {content} 99 | {isAll || (isSelectNode && children) ? 100 | {i18n[locale].all} : null} 101 | { 102 | (isSelectNode && !disabled) ? 103 | 104 | {i18n[locale].delete} 105 | 106 | : null 107 | } 108 |
109 | { 110 | expand && children ? children : null 111 | } 112 |
113 | ); 114 | } 115 | } 116 | 117 | RightTreeNode.defaultProps = { 118 | locale: 'zh-cn', 119 | keys: [], 120 | }; 121 | 122 | RightTreeNode.propTypes = { 123 | value: PropTypes.oneOfType([PropTypes.array, PropTypes.string, PropTypes.object]), 124 | treeNodeLabelProp: PropTypes.any, 125 | children: PropTypes.any, 126 | isAll: PropTypes.bool, 127 | prefixCls: PropTypes.string, 128 | level: PropTypes.number, 129 | removeSelected: PropTypes.func, 130 | pos: PropTypes.string, 131 | locale: PropTypes.oneOf(['zh-cn', 'en-us']), 132 | dropdownWidth: PropTypes.number, 133 | keys: PropTypes.array, 134 | disabled: PropTypes.bool, 135 | }; 136 | -------------------------------------------------------------------------------- /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 | 
113 | 
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 |   70 | 71 |   72 |   73 |   74 |   75 |   76 |   77 |   78 |   79 |   80 |   81 |   82 |   83 |   84 |   85 |   86 |   87 |   88 |   89 |   90 |  
'use strict';
 91 |  
 92 | module.exports = {
 93 |   'zh-cn': {
 94 |     placeholder: '请选择',
 95 |     confirm: '确定',
 96 |     alreadyChoosed: '已选择',
 97 |     pleaseSelectFromLeft: '请从左侧选择',
 98 |     clear: '清空',
 99 |     'delete': '删除',
100 |     all: '全选'
101 |   },
102 |   'en-us': {
103 |     placeholder: 'Please select',
104 |     confirm: 'OK',
105 |     alreadyChoosed: 'Choosed',
106 |     pleaseSelectFromLeft: 'Please select from left',
107 |     clear: 'clear',
108 |     'delete': 'Delete',
109 |     all: 'All'
110 |   }
111 | };
112 |  
114 |
115 |
116 | 120 | 121 | 122 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /tests/Select.checkable.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef, react/no-multi-comp */ 2 | import React from 'react'; 3 | import Enzyme from 'enzyme'; 4 | import TreeSelect, { SHOW_PARENT, SHOW_ALL } from '../src'; 5 | import Adapter from 'enzyme-adapter-react-15'; 6 | import options from './const'; 7 | 8 | const { mount, render } = Enzyme; 9 | 10 | Enzyme.configure({ adapter: new Adapter() }); 11 | 12 | describe('TreeSelect.checkable', () => { 13 | it('can be single checked', () => { 14 | const wrapper = mount(); 25 | // select 26 | const trigger = mount(wrapper.find('Trigger').props().popup); 27 | trigger.find('.uxcore-tree-select-tree-checkbox').last().simulate('click'); 28 | wrapper.update(); 29 | expect(wrapper.find('.uxcore-tree-select-selection__choice')).to.have.length(1); 30 | }); 31 | 32 | it('can be multiple checked', () => { 33 | const wrapper = mount(); 44 | // select 45 | const trigger = mount(wrapper.find('Trigger').props().popup); 46 | trigger.find('.uxcore-tree-select-tree-checkbox').first().simulate('click'); 47 | trigger.find('.uxcore-tree-select-tree-checkbox').at(1).simulate('click'); 48 | wrapper.update(); 49 | expect(wrapper.find('.uxcore-tree-select-selection__choice')).to.have.length(2); 50 | }); 51 | 52 | it('can be controled by inputValue', () => { 53 | const wrapper = mount(); 64 | wrapper.find('input').simulate('change', { target: { value: '3' } }); 65 | // expect(trigger.find('.uxcore-tree-select-tree-checkbox')).to.have.length(3); 66 | const trigger = mount(wrapper.find('Trigger').props().popup); 67 | // trigger.update(); 68 | expect(trigger.find('.uxcore-tree-select-tree-checkbox')).to.have.length(1); 69 | }); 70 | 71 | it('remove selected value with showCheckedStrategy=SHOW_ALL', () => { 72 | const wrapper = mount( 73 | 84 | ); 85 | wrapper.find('.uxcore-tree-select-selection__choice__remove').first().simulate('click'); 86 | expect(wrapper.state().value).to.have.length(1); 87 | expect(wrapper.state().value[0].value).to.equal('2'); 88 | }); 89 | 90 | it('remove selected value with showCheckedStrategy=SHOW_PARENT', () => { 91 | const wrapper = mount( 92 | 103 | ); 104 | wrapper.find('.uxcore-tree-select-selection__choice__remove').first().simulate('click'); 105 | expect(wrapper.state().value).to.have.length(1); 106 | expect(wrapper.state().value[0].value).to.equal('2'); 107 | }); 108 | 109 | it('clear selected value and input value', () => { 110 | const treeData = [ 111 | { 112 | key: '0', 113 | value: '0', 114 | label: 'label0', 115 | }, 116 | ]; 117 | 118 | const wrapper = mount( 119 | 126 | ); 127 | // open 128 | wrapper.find('.uxcore-tree-select').simulate('click'); 129 | const trigger = mount(wrapper.find('Trigger').props().popup); 130 | trigger.find('.uxcore-tree-select-tree-checkbox').at(0).simulate('click'); 131 | wrapper.find('input').simulate('change', { target: { value: 'foo' } }); 132 | wrapper.find('.uxcore-tree-select-selection__clear').simulate('click'); 133 | expect(JSON.stringify(wrapper.state().value)).to.equal(JSON.stringify([])); 134 | expect(wrapper.state().inputValue).to.be(''); 135 | }); 136 | }); 137 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## uxcore-tree-select 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![build status][travis-image]][travis-url] 5 | [![Test Coverage][coveralls-image]][coveralls-url] 6 | [![Dependency Status][dep-image]][dep-url] 7 | [![devDependency Status][devdep-image]][devdep-url] 8 | [![NPM downloads][downloads-image]][npm-url] 9 | 10 | [![Sauce Test Status][sauce-image]][sauce-url] 11 | 12 | [npm-image]: http://img.shields.io/npm/v/uxcore-tree-select.svg?style=flat-square 13 | [npm-url]: http://npmjs.org/package/uxcore-tree-select 14 | [travis-image]: https://img.shields.io/travis/uxcore/uxcore-tree-select.svg?style=flat-square 15 | [travis-url]: https://travis-ci.org/uxcore/uxcore-tree-select 16 | [coveralls-image]: https://img.shields.io/coveralls/uxcore/uxcore-tree-select.svg?style=flat-square 17 | [coveralls-url]: https://coveralls.io/r/uxcore/uxcore-tree-select?branch=master 18 | [dep-image]: http://img.shields.io/david/uxcore/uxcore-tree-select.svg?style=flat-square 19 | [dep-url]: https://david-dm.org/uxcore/uxcore-tree-select 20 | [devdep-image]: http://img.shields.io/david/dev/uxcore/uxcore-tree-select.svg?style=flat-square 21 | [devdep-url]: https://david-dm.org/uxcore/uxcore-tree-select#info=devDependencies 22 | [downloads-image]: https://img.shields.io/npm/dm/uxcore-tree-select.svg 23 | [sauce-image]: https://saucelabs.com/browser-matrix/uxcore-tree-select.svg 24 | [sauce-url]: https://saucelabs.com/u/uxcore-tree-select 25 | 26 | ## TL;DR 27 | 28 | uxcore-tree-select ui component for react 29 | 30 | #### setup develop environment 31 | 32 | ```sh 33 | $ git clone https://github.com/uxcore/uxcore-tree-select 34 | $ cd uxcore-tree-select 35 | $ npm install 36 | $ gulp server 37 | ``` 38 | 39 | ## Usage 40 | 41 | ## demo 42 | http://uxcore.github.io/ 43 | 44 | ## API 45 | 46 | ### TreeSelect props 47 | 48 | | name | description | type | default | since Ver. | 49 | |----------|----------------|----------|--------------|--------------| 50 | |className | additional css class of root dom node | String | '' | 51 | |prefixCls | prefix class | String | 'uxcore-tree-select' | 52 | |animation | dropdown animation name. only support slide-up now | String | '' | 53 | |transitionName | dropdown css animation name | String | '' | 54 | |choiceTransitionName | css animation name for selected items at multiple mode | String | '' | 55 | |dropdownMatchSelectWidth | whether dropdown's with is same with select | bool | true | 56 | |dropdownClassName | additional className applied to dropdown | String | - | 57 | |dropdownStyle | additional style applied to dropdown | Object | {} | 58 | |dropdownPopupAlign | specify alignment for dropdown | Object | - | 59 | |notFoundContent | specify content to show when no result matches. | String | 'Not Found' | 60 | |showSearch | whether show search input in single mode | bool | false | 61 | |allowClear | whether allowClear | bool | false | 62 | |maxTagTextLe\ngth | max tag text length to show | number | - | 63 | |multiple | whether multiple select (true when enable treeCheckable) | bool | false | 64 | |disabled | whether disabled select | bool | false | 65 | |inputValue | if enable search, you can set default input's value, if set to null, auto clear input value when finish select/unselect operation | string/null | '' | 66 | |defaultValue | initial selected treeNode(s) | same as value type | - | 67 | |value | current selected treeNode(s). | normal: String/Array. labelInValue: {value:String,label:React.Node}/Array<{value,label}>. treeCheckStrictly(halfChecked default false): {value:String,label:React.Node, halfChecked}/Array<{value,label,halfChecked}>. | - | 68 | |labelInValue| whether to embed label in value, see above value type | Bool | false | 69 | |onChange | called when select treeNode or input value change | function(value, label(null), extra) | - | 70 | |onSelect | called when select treeNode | function(value, node, extra) | - | 71 | |onSearch | called when input changed | function | - | 72 | |showCheckedStrategy | `TreeSelect.SHOW_ALL`: show all checked treeNodes (Include parent treeNode). `TreeSelect.SHOW_PARENT`: show checked treeNodes (Just show parent treeNode). Default just show child. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD | 73 | |treeIcon | show tree icon | bool | false | 74 | |treeLine | show tree line | bool | false | 75 | |treeDefaultExpandAll | default expand all treeNode | bool | false | 76 | |treeCheckable | whether tree show checkbox (select callback will not fire) | bool | false | 77 | |treeCheckStrictly | check node precisely, parent and children nodes are not associated| bool | false | 78 | |filterTreeNode | whether filter treeNodes by input value. default filter by treeNode's treeNodeFilterProp prop's value | bool/Function(inputValue:string, treeNode:TreeNode) | Function | 79 | |treeNodeFilterProp | which prop value of treeNode will be used for filter if filterTreeNode return true | String | 'value' | 80 | |treeNodeLabelProp | which prop value of treeNode will render as content of select | String | 'title' | 81 | |treeData | treeNodes data Array, if set it then you need not to construct children TreeNode. (value should be unique across the whole array) | array<{value,label,children, [disabled]}> | [] | 82 | |treeDataSimpleMode | enable simple mode of treeData.(treeData should be like this: [{"id":1, "pId":0, "label":"test1"},...], `pId` is parent node's id) | bool/object{id:'id', pId:'pId', rootPId:null} | false | 83 | |loadData | load data asynchronously | function(node) | - | 84 | | resultsPanelAllClearBtn | 在下拉框右半部分中是否显示清除按钮 | bool | true | 0.2.0 | 85 | | resultsPanelTitle | 在下拉框右半部分中显示标题/说明 | string | '' | 0.2.0 | 86 | | resultsPanelTitleStyle | 下拉框右半部分中的标题/说明的样式 | object | {} | 0.2.0 | 87 | | filterResultsPanel | 下拉框右半部分中的结果是否受inputValue影响,如果为true,则右边树形结果也会根据inputValue过滤 | bool | true | 0.2.0 | 88 | | locale | string | false | `'zh-cn'` | 国际化,枚举值 `'en-us'` `'zh-cn'`| 0.2.2 | 89 | 90 | ### TreeNode props 91 | > note: you'd better to use `treeData` instead of using TreeNode. 92 | 93 | | name | description | type | default | 94 | |----------|----------------|----------|--------------| 95 | |disabled | disable treeNode | bool | false | 96 | |key | it's value must be unique across the tree's all TreeNode, you must set it | String | - | 97 | |value | default as treeNodeFilterProp (be unique across the tree's all TreeNode) | String | '' | 98 | |title | tree/subTree's title | String/element | '---' | 99 | |isLeaf | whether it's leaf node | bool | false | 100 | -------------------------------------------------------------------------------- /demo/TreeSelectDemo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TreeSelect Component Demo for uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | import React from 'react'; 9 | import TreeSelect, { TreeNode, SHOW_PARENT } from '../src'; 10 | 11 | function generateData(x = 3, y = 2, z = 1, gData = []) { 12 | // x:每一级下的节点总数。y:每级节点里有y个节点、存在子节点。z:树的level层级数(0表示一级) 13 | function _loop(_level, _preKey, _tns) { 14 | const preKey = _preKey || '0'; 15 | const tns = _tns || gData; 16 | 17 | const children = []; 18 | for (let i = 0; i < x; i++) { 19 | const key = `${preKey}-${i}`; 20 | tns.push({ label: `${key}-label`, value: `${key}-value`, key, disabled: key === '0-0-0-1' }); 21 | if (i < y) { 22 | children.push(key); 23 | } 24 | } 25 | if (_level < 0) { 26 | return tns; 27 | } 28 | const __level = _level - 1; 29 | children.forEach((key, index) => { 30 | tns[index].children = []; 31 | return _loop(__level, key, tns[index].children); 32 | }); 33 | } 34 | _loop(z); 35 | return gData; 36 | } 37 | 38 | let gData = generateData(); 39 | 40 | class Demo extends React.Component { 41 | 42 | constructor(props) { 43 | super(props); 44 | this.state = { 45 | visible: false, 46 | inputValue: '0-0-0-label', 47 | value: '0-0-0-value', 48 | multipleValue: [], 49 | simpleTreeData: [ 50 | { key: 1, pId: 0, label: 'test1', value: '1' }, 51 | { key: 2, pId: 0, label: 'test2', value: '2' }, 52 | { key: 11, pId: 1, label: 'test11', value: '3' }, 53 | { key: 12, pId: 2, label: 'test12', value: '4' }, 54 | { key: 111, pId: 11, label: 'test111', value: 'a' }, 55 | ], 56 | treeDataSimpleMode: { 57 | id: 'key', 58 | rootPId: 0, 59 | }, 60 | }; 61 | } 62 | 63 | onClick() { 64 | this.setState({ 65 | visible: true, 66 | }); 67 | } 68 | 69 | onClose() { 70 | this.setState({ 71 | visible: false, 72 | }); 73 | } 74 | onSearch(value) { 75 | console.log(value, arguments); 76 | } 77 | onChange(value) { 78 | console.log('onChange', arguments); 79 | this.setState({ value }); 80 | } 81 | onMultipleChange(value) { 82 | console.log('onMultipleChange', arguments); 83 | this.setState({ multipleValue: value }); 84 | } 85 | onSelect() { 86 | // use onChange instead 87 | console.log('onselect', arguments); 88 | } 89 | filterTreeNode(input, child) { // 开头符合过滤 90 | return String(child.props.title).indexOf(input) === 0; 91 | } 92 | render() { 93 | return ( 94 |
95 |

single select

96 | 测试标题} 100 | resultsPanelTitleStyle={{ fontWeight: 'bold' }} 101 | placeholder={请下拉选择} 102 | searchPlaceholder="please search" 103 | allowClear 104 | showSearch 105 | value={this.state.value} 106 | treeData={gData} 107 | treeNodeFilterProp="label" 108 | onSearch={this.onSearch.bind(this)} 109 | onChange={this.onChange.bind(this)} 110 | onSelect={this.onSelect.bind(this)} 111 | /> 112 | 113 | 114 |

multiple select

115 | 130 | 135 | 136 |

check select

137 | 152 | 153 |

use treeDataSimpleMode

154 | 请下拉选择} 157 | searchPlaceholder="please search" 158 | maxTagTextLength={10} 159 | value={this.state.value} 160 | treeData={this.state.simpleTreeData} 161 | treeNodeFilterProp="title" 162 | treeDataSimpleMode={this.state.treeDataSimpleMode} 163 | treeCheckable showCheckedStrategy={SHOW_PARENT} 164 | onChange={this.onChange.bind(this)} 165 | onSelect={this.onSelect.bind(this)} 166 | /> 167 | 168 |

use TreeNode Component (not recommend)

169 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | sss} 186 | key="0-1-1-0" 187 | /> 188 | 189 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 |
205 | ); 206 | } 207 | } 208 | 209 | export default Demo; 210 | -------------------------------------------------------------------------------- /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 | 81.79% 24 | Statements 25 | 804/983 26 |
27 |
28 | 69.81% 29 | Branches 30 | 481/689 31 |
32 |
33 | 83.72% 34 | Functions 35 | 144/172 36 |
37 |
38 | 86.27% 39 | Lines 40 | 754/874 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
RightTreeNode.jsx
85.71%72/8472.6%53/7392.86%13/1498.39%61/62
Select.jsx
79.28%440/55568.67%274/39980.21%77/9681.71%420/514
SelectTrigger.jsx
85.11%223/26273.29%118/16185.71%42/4990.6%212/234
TreeSelect.js
78.26%36/4653.13%17/3285.71%6/7100%28/28
i18n.js
100%1/1100%0/0100%0/0100%1/1
index.js
100%1/1100%0/0100%0/0100%1/1
utils.js
91.18%31/3479.17%19/24100%6/691.18%31/34
154 |
155 |
156 | 160 | 161 | 162 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/utils.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/utils.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

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

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

 46 | 
233 | 
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 |   110 | 111 |   112 |   113 | 114 |   115 | 116 |   117 |   118 | 119 | 118× 120 |   121 | 118× 122 | 63× 123 |   124 | 55× 125 | 55× 126 | 55× 127 | 71× 128 |   129 |   130 | 71× 131 | 71× 132 | 58× 133 |   134 | 71× 135 |   136 |   137 | 55× 138 | 139 |   140 |   141 |   142 |   143 | 55× 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 | 55× 169 |   170 |  
'use strict';
171 |  
172 | Object.defineProperty(exports, "__esModule", {
173 |   value: true
174 | });
175 | exports.flatToHierarchy = flatToHierarchy;
176 |  
177 | var _util = require('rc-tree-select/lib/util');
178 |  
179 | // Refactor
180 | function flatToHierarchy(arr) {
181 |   var flag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
182 |  
183 |   if (!arr.length) {
184 |     return arr;
185 |   }
186 |   var hierarchyNodes = [];
187 |   var levelObj = {};
188 |   arr.forEach(function (item) {
189 |     Iif (!item.pos) {
190 |       return;
191 |     }
192 |     var posLen = item.pos.split('-').length;
193 |     if (!levelObj[posLen]) {
194 |       levelObj[posLen] = [];
195 |     }
196 |     levelObj[posLen].push(item);
197 |   });
198 |   // levelObj 收集每个层级的child
199 |   var levelArr = Object.keys(levelObj).sort(function (a, b) {
200 |     return b - a;
201 |   });
202 |  
203 |   // const s = Date.now();
204 |   // todo: there are performance issues!
205 |   levelArr.reduce(function (pre, cur) {
206 |     Eif (cur && cur !== pre) {
207 |       levelObj[pre].forEach(function (item) {
208 |         var haveParent = false;
209 |         levelObj[cur].forEach(function (ii) {
210 |           Eif ((0, _util.isPositionPrefix)(ii.pos, item.pos)) {
211 |             haveParent = true;
212 |             // select multiple模式下的筛选
213 |             if (flag && ii.isAll) {
214 |               return;
215 |             }
216 |             Iif (!ii.children) {
217 |               ii.children = []; // eslint-disable-line
218 |             }
219 |             ii.children.push(item);
220 |           }
221 |         });
222 |         Iif (!haveParent) {
223 |           hierarchyNodes.push(item);
224 |         }
225 |       });
226 |     }
227 |     return cur;
228 |   });
229 |   // console.log(Date.now() - s);
230 |   return levelObj[levelArr[levelArr.length - 1]].concat(hierarchyNodes);
231 | }
232 |  
234 |
235 |
236 | 240 | 241 | 242 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /tests/TreeSelect.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import React from 'react'; 3 | import expect from 'expect.js'; 4 | import Enzyme from 'enzyme'; 5 | import TreeSelect from '../src'; 6 | import Adapter from 'enzyme-adapter-react-15'; 7 | import options from './const'; 8 | 9 | const { TreeNode } = TreeSelect; 10 | const { mount, render } = Enzyme; 11 | 12 | Enzyme.configure({ adapter: new Adapter() }); 13 | 14 | describe('TreeSelect', () => { 15 | it('should render single select', () => { 16 | const wrapper = mount(); 17 | expect(wrapper.find('.uxcore-tree-select-selection__placeholder').html()) 18 | .to 19 | .equal('请选择'); 20 | }); 21 | 22 | it('should render sub-menu', () => { 23 | const wrapper = mount(); 24 | wrapper.find('.uxcore-tree-select').simulate('click'); 25 | const trigger = mount(wrapper.find('Trigger').props().popup); 26 | expect(trigger.length).to.be(1); 27 | }); 28 | 29 | it('render width inputValue', () => { 30 | // only one treeNode will be render 31 | const wrapper = mount( 32 | 39 | ); 40 | const trigger = mount(wrapper.find('Trigger').props().popup); 41 | expect(trigger.find('Tree')).to.have.length(1); 42 | }); 43 | 44 | it('sets default value', () => { 45 | const treeData = [ 46 | { key: '0', value: '0', label: 'label0' }, 47 | ]; 48 | const wrapper = mount( 49 | 50 | ); 51 | expect( 52 | wrapper.find('.uxcore-tree-select-selection__rendered > span').props().children 53 | ).to.equal('label0'); 54 | }); 55 | 56 | it('can be controlled by value', () => { 57 | const treeData = [ 58 | { key: '0', value: '0', label: 'label0' }, 59 | { key: '1', value: '1', label: 'label1' }, 60 | ]; 61 | const wrapper = mount( 62 | 63 | ); 64 | let choice = wrapper.find('.uxcore-tree-select-selection__rendered > span'); 65 | expect(choice.prop('children')).to.equal('label0'); 66 | wrapper.setProps({ value: '1' }); 67 | choice = wrapper.find('.uxcore-tree-select-selection__rendered > span'); 68 | expect(choice.prop('children')).to.equal('label1'); 69 | }); 70 | 71 | it('embed label to value by add props:labelInValue', () => { 72 | const treeData = [ 73 | { key: '0', value: '0', label: 'label0' }, 74 | { key: '1', value: '1', label: 'label1' }, 75 | ]; 76 | const wrapper = mount( 77 | 78 | ); 79 | wrapper.setProps({ value: { value: '0', label: 'label0' } }); 80 | expect(JSON.stringify(wrapper.state().value)).to.equal(JSON.stringify([ 81 | { value: '0', label: 'label0' }, 82 | ])); 83 | }); 84 | 85 | it('close tree when press ESC', () => { 86 | const wrapper = mount( 87 | 88 | 89 | 90 | ); 91 | wrapper.setState({ open: true }); 92 | const trigger = mount(wrapper.find('Trigger').props().popup); 93 | trigger.find('.uxcore-tree-select-search__field').simulate('keyDown', { keyCode: 27 }); 94 | expect(wrapper.state('open')).to.equal(false); 95 | }); 96 | 97 | it('checks node correctly after treeData updated', () => { 98 | const wrapper = mount( 99 | 100 | ); 101 | wrapper.setProps({ treeData: [{ key: '0', value: '0', label: 'label0' }] }); 102 | const trigger = mount(wrapper.find('Trigger').props().popup); 103 | trigger.find('.uxcore-tree-select-tree-checkbox').simulate('click'); 104 | expect(JSON.stringify(wrapper.state().value)).to.equal(JSON.stringify([{ value: '0', label: 'label0' }])); 105 | }); 106 | 107 | it('expands tree nodes by treeDefaultExpandedKeys', () => { 108 | const wrapper = mount( 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | ); 117 | const trigger = mount(wrapper.find('Trigger').props().popup); 118 | const node = trigger.find('.uxcore-tree-select-tree-node-content-wrapper').at(1); 119 | expect(node.hasClass('uxcore-tree-select-tree-node-content-wrapper-open')).to.equal(true); 120 | }); 121 | 122 | describe('select', () => { 123 | const treeData = [ 124 | { key: '0', value: '0', label: 'label0' }, 125 | { key: '1', value: '1', label: 'label1' }, 126 | ]; 127 | const createSelect = (props) => ( 128 | 133 | ); 134 | 135 | it('render result by treeNodeLabelProp', () => { 136 | const wrapper = mount(createSelect({ treeNodeLabelProp: 'value', value: '0' })); 137 | // const trigger = mount(wrapper.find('Trigger').props().popup); 138 | expect(wrapper.find('.uxcore-tree-select-selection__rendered > span').prop('children')).to.equal('0'); 139 | }); 140 | }); 141 | 142 | describe('search nodes', () => { 143 | const treeData = [ 144 | { key: 'a', value: 'a', label: 'labela' }, 145 | { key: 'b', value: 'b', label: 'labelb' }, 146 | ]; 147 | const createSelect = (props) => ( 148 | 154 | ); 155 | 156 | it('fires search event', () => { 157 | const onSearch = x => x; 158 | const wrapper = mount(createSelect({ onSearch })); 159 | const trigger = mount(wrapper.find('Trigger').props().popup); 160 | trigger.find('input').simulate('change', { target: { value: 'a' } }); 161 | // expect(onSearch).to.equalCalledWith('a'); 162 | expect(onSearch).withArgs('a').to.not.throwException(); 163 | }); 164 | 165 | it('search nodes by filterTreeNode', () => { 166 | const filter = (value, node) => node.props.value.toLowerCase() === value.toLowerCase(); 167 | const wrapper = mount(createSelect({ filterTreeNode: filter })); 168 | const trigger = mount(wrapper.find('Trigger').props().popup); 169 | trigger.find('input').simulate('change', { target: { value: 'A' } }); 170 | // expect(trigger.find('TreeNode')).to.have.length(1); 171 | // expect(trigger.find('TreeNode').prop('value')).to.equal('a'); 172 | expect(wrapper.state().inputValue).to.equal('A'); 173 | }); 174 | 175 | it('search nodes by treeNodeFilterProp', () => { 176 | const wrapper = mount(createSelect({ treeNodeFilterProp: 'label' })); 177 | const trigger = mount(wrapper.find('Trigger').props().popup); 178 | trigger.find('input').simulate('change', { target: { value: 'labela' } }); 179 | // expect(trigger.find('TreeNode')).to.have.length(1); 180 | // expect(trigger.find('TreeNode').prop('value')).to.equal('a'); 181 | expect(wrapper.state().inputValue).to.equal('labela'); 182 | }); 183 | }); 184 | 185 | describe('allowClear', () => { 186 | it('allowClear when defaultValue is not exist', () => { 187 | const wrapper = mount( 188 | 189 | 190 | 191 | ); 192 | const trigger = mount(wrapper.find('Trigger').props().popup); 193 | trigger.find('.uxcore-tree-select-tree-title').simulate('click'); 194 | wrapper.update(); 195 | wrapper.find('.uxcore-tree-select-selection__clear').simulate('click'); 196 | expect(JSON.stringify(wrapper.state().value)).to.equal(JSON.stringify([])); 197 | }); 198 | 199 | it('allowClear when defaultValue is exist', () => { 200 | const wrapper = mount( 204 | 205 | ); 206 | wrapper.find('.uxcore-tree-select-selection__clear').simulate('click'); 207 | expect(JSON.stringify(wrapper.state().value)).to.equal(JSON.stringify([])); 208 | }); 209 | }); 210 | 211 | describe('node unmount', () => { 212 | const App = (isMount) => { 213 | if (!isMount) { 214 | return null; 215 | } 216 | return ( 217 | 218 | 219 | 220 | ); 221 | }; 222 | 223 | const wrapper = mount(); 226 | expect(wrapper.find('TreeSelect')).to.have.length(1); 227 | wrapper.setProps({ isMount: false }); 228 | wrapper.unmount(); 229 | expect(wrapper.find('TreeSelect')).to.have.length(0); 230 | }); 231 | 232 | describe('focus and blur test', () => { 233 | it('focus', () => { 234 | const handleFocus = () => {}; 235 | const treeData = [ 236 | { key: '0', value: '0', label: '0 label' }, 237 | ]; 238 | const wrapper = mount( 239 | 244 | ); 245 | wrapper.instance().focus(); 246 | expect(handleFocus).to.not.throwException(); 247 | }); 248 | 249 | it('blur', () => { 250 | const handleBlur = () => {}; 251 | const treeData = [ 252 | { key: '0', value: '0', label: '0 label' }, 253 | ]; 254 | const wrapper = mount( 255 | 260 | ); 261 | wrapper.instance().focus(); 262 | wrapper.instance().blur(); 263 | expect(handleBlur).to.not.throwException(); 264 | }); 265 | }); 266 | }); 267 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/TreeSelect.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/TreeSelect.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

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

21 |
22 |
23 | 78.26% 24 | Statements 25 | 36/46 26 |
27 |
28 | 53.13% 29 | Branches 30 | 17/32 31 |
32 |
33 | 85.71% 34 | Functions 35 | 6/7 36 |
37 |
38 | 100% 39 | Lines 40 | 28/28 41 |
42 |
43 |
44 |
45 |

 46 | 
257 | 
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 |   118 | 119 |   120 | 121 |   122 | 123 |   124 | 125 |   126 | 127 |   128 | 129 |   130 | 131 |   132 | 133 |   134 | 135 |   136 | 137 |   138 | 35× 139 |   140 | 35× 141 |   142 | 143 |   144 |   145 |   146 |   147 |   148 |   149 |   150 |   151 | 152 | 153 | 154 |   155 |   156 | 157 | 158 |   159 | 160 | 35× 161 |   162 | 35× 163 |   164 |   165 | 166 |   167 |   168 | 169 | 170 | 171 |   172 | 173 |   174 |   175 |   176 |   177 |   178 |   179 |   180 |   181 |   182 |   183 | 184 |   185 | 186 |  
'use strict';
187 |  
188 | var _Select = require('./Select');
189 |  
190 | var _Select2 = _interopRequireDefault(_Select);
191 |  
192 | var _objectAssign = require('object-assign');
193 |  
194 | var _objectAssign2 = _interopRequireDefault(_objectAssign);
195 |  
196 | var _TreeNode = require('rc-tree-select/lib/TreeNode');
197 |  
198 | var _TreeNode2 = _interopRequireDefault(_TreeNode);
199 |  
200 | var _strategies = require('rc-tree-select/lib/strategies');
201 |  
202 | var _strategies2 = _interopRequireDefault(_strategies);
203 |  
204 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
205 |  
206 | 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; }
207 |  
208 | function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
209 |  
210 | 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; }
211 |  
212 | 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); } /**
213 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * TreeSelect Component for uxcore
214 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * @author biangang.bg
215 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 *
216 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * Copyright 2014-2015, Uxcore Team, Alinw.
217 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * All rights reserved.
218 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 */
219 |  
220 |  
221 | var supportSVG = false;
222 | Eif (typeof document !== 'undefined') {
223 |   supportSVG = document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');
224 | }
225 |  
226 | var TreeSelect = function (_RcTreeSelect) {
227 |   _inherits(TreeSelect, _RcTreeSelect);
228 |  
229 |   function TreeSelect() {
230 |     _classCallCheck(this, TreeSelect);
231 |  
232 |     return _possibleConstructorReturn(this, _RcTreeSelect.apply(this, arguments));
233 |   }
234 |  
235 |   return TreeSelect;
236 | }(_Select2['default']);
237 |  
238 | TreeSelect.TreeNode = _TreeNode2['default'];
239 | (0, _objectAssign2['default'])(TreeSelect, _strategies2['default']);
240 | TreeSelect.displayName = 'TreeSelect';
241 |  
242 | TreeSelect.defaultProps = (0, _objectAssign2['default'])(_Select2['default'].defaultProps, {
243 |   prefixCls: 'uxcore-tree-select',
244 |   dropdownClassName: supportSVG ? 'use-svg' : 'no-svg',
245 |   transitionName: 'slideUp',
246 |   choiceTransitionName: 'uxcore-tree-select-selection__choice-zoom',
247 |   showSearch: false,
248 |   dropdownMatchSelectWidth: false,
249 |   maxTagTextLength: 10,
250 |   locale: 'zh-cn'
251 | });
252 |  
253 | TreeSelect.propTypes = _Select2['default'].propTypes;
254 |  
255 | module.exports = TreeSelect;
256 |  
258 |
259 |
260 | 264 | 265 | 266 | 273 | 274 | 275 | 276 | -------------------------------------------------------------------------------- /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/SelectTrigger.jsx: -------------------------------------------------------------------------------- 1 | // customized rc-tree-select https://github.com/react-component/tree-select/blob/master/src/SelectTrigger.jsx 2 | 3 | import React, { Component } from 'react'; 4 | import PropTypes from 'prop-types'; 5 | import ReactDOM from 'react-dom'; 6 | import classnames from 'classnames'; 7 | import Trigger from 'rc-trigger'; 8 | import Tree, { TreeNode } from 'rc-tree'; 9 | import { 10 | loopAllChildren, 11 | getValuePropValue, 12 | labelCompatible, 13 | saveRef, 14 | } from 'rc-tree-select/lib/util'; 15 | import toArray from 'rc-util/lib/Children/toArray'; 16 | import i18n from './i18n'; 17 | import { flatToHierarchy } from './utils'; 18 | import RightTreeNode from './RightTreeNode'; 19 | 20 | 21 | const BUILT_IN_PLACEMENTS = { 22 | bottomLeft: { 23 | points: ['tl', 'bl'], 24 | offset: [0, 4], 25 | overflow: { 26 | adjustX: 0, 27 | adjustY: 1, 28 | }, 29 | }, 30 | topLeft: { 31 | points: ['bl', 'tl'], 32 | offset: [0, -4], 33 | overflow: { 34 | adjustX: 0, 35 | adjustY: 1, 36 | }, 37 | }, 38 | }; 39 | 40 | class SelectTrigger extends Component { 41 | static propTypes = { 42 | dropdownMatchSelectWidth: PropTypes.bool, 43 | dropdownPopupAlign: PropTypes.object, 44 | visible: PropTypes.bool, 45 | filterTreeNode: PropTypes.any, 46 | treeNodes: PropTypes.any, 47 | inputValue: PropTypes.string, 48 | prefixCls: PropTypes.string, 49 | popupClassName: PropTypes.string, 50 | children: PropTypes.any, 51 | removeSelected: PropTypes.func, 52 | value: PropTypes.array, 53 | locale: PropTypes.string, 54 | onAllClear: PropTypes.func, 55 | resultsPanelAllClearBtn: PropTypes.bool, 56 | resultsPanelTitle: PropTypes.any, 57 | resultsPanelTitleStyle: PropTypes.object, 58 | }; 59 | 60 | state = { 61 | _expandedKeys: [], 62 | fireOnExpand: false, 63 | dropdownWidth: null, 64 | }; 65 | 66 | componentDidMount() { 67 | this.setDropdownWidth(); 68 | } 69 | 70 | componentWillReceiveProps(nextProps) { 71 | if (nextProps.inputValue && nextProps.inputValue !== this.props.inputValue) { 72 | // set autoExpandParent to true 73 | this.setState({ 74 | _expandedKeys: [], 75 | fireOnExpand: false, 76 | }); 77 | } 78 | } 79 | 80 | componentDidUpdate() { 81 | this.setDropdownWidth(); 82 | } 83 | 84 | onResultsPanelAllClear = () => { 85 | this.props.onAllClear(); 86 | } 87 | 88 | onExpand = (expandedKeys) => { 89 | // rerender 90 | this.setState({ 91 | _expandedKeys: expandedKeys, 92 | fireOnExpand: true, 93 | }, () => { 94 | // Fix https://github.com/ant-design/ant-design/issues/5689 95 | if (this.trigger && this.trigger.forcePopupAlign) { 96 | this.trigger.forcePopupAlign(); 97 | } 98 | }); 99 | } 100 | 101 | setDropdownWidth() { 102 | const width = ReactDOM.findDOMNode(this).offsetWidth; 103 | if (width !== this.state.dropdownWidth) { 104 | this.setState({ dropdownWidth: width }); 105 | } 106 | } 107 | 108 | getPopupEleRefs() { 109 | return this.popupEle; 110 | } 111 | 112 | getPopupDOMNode() { 113 | return this.trigger.getPopupDomNode(); 114 | } 115 | 116 | getDropdownTransitionName() { 117 | const props = this.props; 118 | let transitionName = props.transitionName; 119 | if (!transitionName && props.animation) { 120 | transitionName = `${this.getDropdownPrefixCls()}-${props.animation}`; 121 | } 122 | return transitionName; 123 | } 124 | 125 | getDropdownPrefixCls() { 126 | return `${this.props.prefixCls}-dropdown`; 127 | } 128 | 129 | highlightTreeNode = (treeNode) => { 130 | const props = this.props; 131 | const filterVal = treeNode.props[labelCompatible(props.treeNodeFilterProp)]; 132 | if (typeof filterVal === 'string') { 133 | return props.inputValue && filterVal.indexOf(props.inputValue) > -1; 134 | } 135 | return false; 136 | } 137 | 138 | filterTreeNode = (input, child) => { 139 | if (!input) { 140 | return true; 141 | } 142 | const filterTreeNode = this.props.filterTreeNode; 143 | if (!filterTreeNode) { 144 | return true; 145 | } 146 | if (child.props.disabled) { 147 | return false; 148 | } 149 | return filterTreeNode.call(this, input, child); 150 | } 151 | 152 | filterSelectedTreeNode(valueArr, child) { 153 | if (valueArr.indexOf(child.props.value) > -1) { 154 | return true; 155 | } 156 | return false; 157 | } 158 | 159 | processSelectedTreeNode(treeNodes) { // 筛选已经选中的treeNode并重组 160 | const filterPoss = []; 161 | const { value } = this.props; 162 | const valueArr = value.map(item => item.value); 163 | loopAllChildren(treeNodes, (child, index, pos) => { 164 | if (this.filterSelectedTreeNode(valueArr, child)) { 165 | filterPoss.push(pos); 166 | } 167 | }); 168 | 169 | // Include the filtered nodes's ancestral nodes. 170 | // 加入processedPoss包括其祖先组件 171 | const processedPoss = []; 172 | filterPoss.forEach(pos => { 173 | const arr = pos.split('-'); 174 | arr.reduce((pre, cur) => { 175 | const res = `${pre}-${cur}`; 176 | if (processedPoss.indexOf(res) < 0) { 177 | processedPoss.push(res); 178 | } 179 | return res; 180 | }); 181 | }); 182 | // 再筛选一遍将node都push进去 183 | const filterNodesPositions = []; 184 | loopAllChildren(treeNodes, (child, index, pos) => { 185 | if (processedPoss.indexOf(pos) > -1) { 186 | const renderNode = { node: child, pos, isAll: false }; 187 | // 如果有children就是全选的 188 | if (filterPoss.indexOf(pos) > -1 && child.props.children) { 189 | renderNode.isAll = true; 190 | } 191 | filterNodesPositions.push(renderNode); 192 | } 193 | }); 194 | 195 | // 阶层 讲平层转换为阶级数组 196 | const hierarchyNodes = flatToHierarchy(filterNodesPositions, true); 197 | 198 | const recursive = children => 199 | children.map(child => { 200 | if (child.children) { 201 | return React.cloneElement(child.node, { isAll: child.isAll }, recursive(child.children)); 202 | } 203 | // 单一节点 本身就包括children 204 | return React.cloneElement(child.node, { isAll: child.isAll }); 205 | }); 206 | 207 | return recursive(hierarchyNodes); 208 | } 209 | 210 | processTreeNode(treeNodes) { 211 | const filterPoss = []; 212 | this._expandedKeys = []; 213 | loopAllChildren(treeNodes, (child, index, pos) => { 214 | if (this.filterTreeNode(this.props.inputValue, child)) { 215 | filterPoss.push(pos); 216 | this._expandedKeys.push(child.key); 217 | } 218 | }); 219 | 220 | // Include the filtered nodes's ancestral nodes. 221 | const processedPoss = []; 222 | filterPoss.forEach(pos => { 223 | const arr = pos.split('-'); 224 | arr.reduce((pre, cur) => { 225 | const res = `${pre}-${cur}`; 226 | if (processedPoss.indexOf(res) < 0) { 227 | processedPoss.push(res); 228 | } 229 | return res; 230 | }); 231 | }); 232 | const filterNodesPositions = []; 233 | loopAllChildren(treeNodes, (child, index, pos) => { 234 | if (processedPoss.indexOf(pos) > -1) { 235 | filterNodesPositions.push({ node: child, pos }); 236 | } 237 | }); 238 | 239 | const hierarchyNodes = flatToHierarchy(filterNodesPositions); 240 | 241 | const recursive = children => { 242 | return children.map(child => { 243 | if (child.children) { 244 | return React.cloneElement(child.node, {}, recursive(child.children)); 245 | } 246 | return child.node; 247 | }); 248 | }; 249 | return recursive(hierarchyNodes); 250 | } 251 | 252 | renderRightTree(newTreeNodes, keys) { 253 | const props = this.props; 254 | 255 | const trProps = { 256 | prefixCls: `${props.prefixCls}-rightTreeNode`, 257 | treeNodeLabelProp: props.treeNodeLabelProp, 258 | isMultiple: props.multiple || props.tags || props.treeCheckable, 259 | removeSelected: props.removeSelected, 260 | locale: props.locale, 261 | onSelect: this.onSelect, 262 | keys, 263 | dropdownWidth: this.state.dropdownWidth, 264 | }; 265 | 266 | const recursive = (children, level) => 267 | // Note: if use `React.Children.map`, the node's key will be modified. 268 | toArray(children).map(function handler(child) { // eslint-disable-line 269 | if (child && child.props.children) { 270 | // null or String has no Prop 271 | return ( 275 | {recursive(child.props.children, (level + 1))} 276 | ); 277 | } 278 | return (); 282 | }); 283 | 284 | return ( 285 |
289 | {recursive(newTreeNodes, 1)} 290 |
291 | ); 292 | } 293 | 294 | renderRightDropdown(rightTreeNodes, keys) { 295 | const { 296 | resultsPanelAllClearBtn, 297 | resultsPanelTitle, 298 | resultsPanelTitleStyle, 299 | value, 300 | locale, 301 | } = this.props; 302 | 303 | const resultsPanelPrefixCls = `${this.getDropdownPrefixCls()}-right`; 304 | 305 | let renderRightDropdownTitle = null; 306 | 307 | if (resultsPanelTitle) { 308 | renderRightDropdownTitle = ( 309 |

310 | {resultsPanelTitle} 311 |

312 | ); 313 | } 314 | const num = value.length || 0; 315 | 316 | const noContent = (
319 | {i18n[locale].pleaseSelectFromLeft} 320 |
); 321 | const clear = ({i18n[locale].clear}); 326 | 327 | return ( 328 |
329 |
330 |
331 | 332 | {i18n[locale].alreadyChoosed} 333 | ({num}) 334 | 335 | {resultsPanelAllClearBtn && num ? clear : null} 336 |
337 | {renderRightDropdownTitle} 338 |
339 | { 340 | num === 0 ? noContent : this.renderRightTree(rightTreeNodes, keys) 341 | } 342 |
343 | ); 344 | } 345 | 346 | renderTree(keys, halfCheckedKeys, newTreeNodes, multiple) { 347 | const props = this.props; 348 | 349 | const trProps = { 350 | multiple, 351 | prefixCls: `${props.prefixCls}-tree`, 352 | showIcon: props.treeIcon, 353 | showLine: props.treeLine, 354 | defaultExpandAll: props.treeDefaultExpandAll, 355 | defaultExpandedKeys: props.treeDefaultExpandedKeys, 356 | filterTreeNode: this.highlightTreeNode, 357 | }; 358 | 359 | if (props.treeCheckable) { 360 | trProps.selectable = false; 361 | trProps.checkable = props.treeCheckable; 362 | trProps.onCheck = props.onSelect; 363 | trProps.checkStrictly = props.treeCheckStrictly; 364 | if (props.inputValue) { 365 | // enable checkStrictly when search tree. 366 | trProps.checkStrictly = true; 367 | } else { 368 | trProps._treeNodesStates = props._treeNodesStates; 369 | } 370 | if (trProps.treeCheckStrictly && halfCheckedKeys.length) { 371 | trProps.checkedKeys = { checked: keys, halfChecked: halfCheckedKeys }; 372 | } else { 373 | trProps.checkedKeys = keys; 374 | } 375 | } else { 376 | trProps.selectedKeys = keys; 377 | trProps.onSelect = props.onSelect; 378 | } 379 | 380 | // expand keys 381 | if (!trProps.defaultExpandAll && !trProps.defaultExpandedKeys && !props.loadData) { 382 | trProps.expandedKeys = keys; 383 | } 384 | trProps.autoExpandParent = true; 385 | trProps.onExpand = this.onExpand; 386 | if (this._expandedKeys && this._expandedKeys.length) { 387 | trProps.expandedKeys = this._expandedKeys; 388 | } 389 | if (this.state.fireOnExpand) { 390 | trProps.expandedKeys = this.state._expandedKeys; 391 | trProps.autoExpandParent = false; 392 | } 393 | 394 | // async loadData 395 | if (props.loadData) { 396 | trProps.loadData = props.loadData; 397 | } 398 | 399 | return ( 400 | 401 | {newTreeNodes} 402 | 403 | ); 404 | } 405 | 406 | render() { 407 | const props = this.props; 408 | const multiple = props.multiple; 409 | const dropdownPrefixCls = this.getDropdownPrefixCls(); 410 | const popupClassName = { 411 | [props.dropdownClassName]: !!props.dropdownClassName, 412 | [`${dropdownPrefixCls}--${multiple ? 'multiple' : 'single'}`]: 1, 413 | }; 414 | let visible = props.visible; 415 | const search = multiple || props.combobox || !props.showSearch ? null : ( 416 | {props.inputElement} 417 | ); 418 | 419 | const recursive = children => { 420 | // Note: if use `React.Children.map`, the node's key will be modified. 421 | return toArray(children).map(function handler(child) { // eslint-disable-line 422 | if (!child) { 423 | return null; 424 | } 425 | if (child && child.props.children) { 426 | // null or String has no Prop 427 | return ( 428 | 429 | {recursive(child.props.children)} 430 | 431 | ); 432 | } 433 | return ; 434 | }); 435 | }; 436 | // const s = Date.now(); 437 | let treeNodes; 438 | if (props._cachetreeData && this.treeNodes) { 439 | treeNodes = this.treeNodes; 440 | } else { 441 | treeNodes = recursive(props.treeData || props.treeNodes); 442 | this.treeNodes = treeNodes; 443 | } 444 | // console.log(Date.now()-s); 445 | 446 | if (props.inputValue) { 447 | treeNodes = this.processTreeNode(treeNodes); 448 | } 449 | 450 | const rightTreeNodes = props.filterResultsPanel ? 451 | this.processSelectedTreeNode(treeNodes) : 452 | this.processSelectedTreeNode(this.treeNodes); 453 | 454 | const keys = []; 455 | const halfCheckedKeys = []; 456 | loopAllChildren(treeNodes, (child) => { 457 | if (props.value.some(item => item.value === getValuePropValue(child))) { 458 | keys.push(child.key); 459 | } 460 | if (props.halfCheckedValues && 461 | props.halfCheckedValues.some(item => item.value === getValuePropValue(child))) { 462 | halfCheckedKeys.push(child.key); 463 | } 464 | }); 465 | 466 | let notFoundContent; 467 | if (!treeNodes.length) { 468 | if (props.notFoundContent) { 469 | notFoundContent = ( 470 | 471 | {props.notFoundContent} 472 | 473 | ); 474 | } else if (!search) { 475 | visible = false; 476 | } 477 | } 478 | const popupElement = (
481 |
482 | {search} 483 | {notFoundContent || this.renderTree(keys, halfCheckedKeys, treeNodes, multiple)} 484 |
485 | {this.renderRightDropdown(rightTreeNodes, keys)} 486 |
); 487 | 488 | const popupStyle = { ...props.dropdownStyle }; 489 | const widthProp = props.dropdownMatchSelectWidth ? 'width' : 'minWidth'; 490 | if (this.state.dropdownWidth) { 491 | popupStyle[widthProp] = `${this.state.dropdownWidth * 2}px`; 492 | } 493 | return ( 494 | 509 | {this.props.children} 510 | 511 | ); 512 | } 513 | } 514 | 515 | export default SelectTrigger; 516 | -------------------------------------------------------------------------------- /coverage/lcov-report/src/RightTreeNode.jsx.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for src/RightTreeNode.jsx 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

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

21 |
22 |
23 | 85.71% 24 | Statements 25 | 72/84 26 |
27 |
28 | 72.6% 29 | Branches 30 | 53/73 31 |
32 |
33 | 92.86% 34 | Functions 35 | 13/14 36 |
37 |
38 | 98.39% 39 | Lines 40 | 61/62 41 |
42 |
43 |
44 |
45 |

 46 | 
620 | 
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 |   239 | 240 |   241 |   242 |   243 | 244 |   245 | 246 |   247 | 248 |   249 | 250 |   251 | 252 |   253 | 254 |   255 | 256 |   257 | 258 |   259 | 260 |   261 | 262 |   263 | 105× 264 |   265 | 26× 266 |   267 | 26× 268 |   269 | 270 |   271 |   272 |   273 |   274 | 275 | 276 |   277 | 278 | 26× 279 |   280 | 26× 281 |   282 | 26× 283 | 284 |   285 |   286 |   287 |   288 | 289 |   290 |   291 | 26× 292 | 293 |   294 |   295 |   296 |   297 | 26× 298 |   299 |   300 | 26× 301 |   302 |   303 | 304 | 305 |   306 |   307 |   308 |   309 |   310 |   311 | 312 | 35× 313 |   314 |   315 |   316 |   317 |   318 |   319 |   320 | 35× 321 | 35× 322 | 323 |   324 | 35× 325 | 34× 326 |   327 | 35× 328 | 329 |   330 |   331 | 35× 332 |   333 |   334 | 335 | 59× 336 |   337 |   338 |   339 |   340 | 59× 341 |   342 |   343 | 344 | 35× 345 |   346 | 35× 347 |   348 |   349 |   350 |   351 |   352 |   353 |   354 | 35× 355 |   356 |   357 | 35× 358 | 35× 359 | 360 | 34× 361 |   362 | 30× 363 |   364 | 35× 365 | 35× 366 |   367 | 35× 368 |   369 | 35× 370 |   371 |   372 |   373 |   374 |   375 |   376 |   377 |   378 |   379 | 35× 380 |   381 |   382 |   383 |   384 |   385 |   386 |   387 |   388 |   389 |   390 |   391 |   392 |   393 |   394 |   395 |   396 |   397 |   398 |   399 |   400 |   401 |   402 | 403 |   404 |   405 | 406 |   407 |   408 | 409 |   410 |   411 |   412 |   413 | 414 |   415 |   416 |   417 |   418 |   419 |   420 |   421 |   422 |   423 |   424 |   425 |   426 |   427 | 428 |  
'use strict';
429 |  
430 | Object.defineProperty(exports, "__esModule", {
431 |   value: true
432 | });
433 |  
434 | var _react = require('react');
435 |  
436 | var _react2 = _interopRequireDefault(_react);
437 |  
438 | var _propTypes = require('prop-types');
439 |  
440 | var _propTypes2 = _interopRequireDefault(_propTypes);
441 |  
442 | var _classnames = require('classnames');
443 |  
444 | var _classnames2 = _interopRequireDefault(_classnames);
445 |  
446 | var _i18n = require('./i18n');
447 |  
448 | var _i18n2 = _interopRequireDefault(_i18n);
449 |  
450 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
451 |  
452 | 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; }
453 |  
454 | 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; }
455 |  
456 | function _classCallCheck(instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
457 |  
458 | 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; }
459 |  
460 | 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); } /**
461 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * RightTreeNode Component for Tree
462 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 * @author chenqiu  wb-cq231719@alibaba-inc.com
463 |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 */
464 |  
465 | var RightTreeNode = function (_React$Component) {
466 |   _inherits(RightTreeNode, _React$Component);
467 |  
468 |   function RightTreeNode(props) {
469 |     _classCallCheck(this, RightTreeNode);
470 |  
471 |     var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
472 |  
473 |     _this.removeSelected = function () {
474 |       var _this$props = _this.props,
475 |           removeSelected = _this$props.removeSelected,
476 |           value = _this$props.value;
477 |  
478 |  
479 |       removeSelected(value);
480 |     };
481 |  
482 |     _this.expand = function () {
483 |       _this.setState({
484 |         expand: !_this.state.expand
485 |       });
486 |     };
487 |  
488 |     _this.state = {
489 |       expand: !(props.isAll || _this.isSelectNode() && props.children)
490 |     };
491 |     return _this;
492 |   }
493 |  
494 |   RightTreeNode.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
495 |     Iif (this.props.isAll !== nextProps.isAll) {
496 |       this.setState({
497 |         expand: !nextProps.isAll
498 |       });
499 |     }
500 |   };
501 |  
502 |   RightTreeNode.prototype.getMaxWidth = function getMaxWidth(isSelectNode, paddingLeftStyle) {
503 |     var _props = this.props,
504 |         locale = _props.locale,
505 |         children = _props.children,
506 |         isAll = _props.isAll,
507 |         dropdownWidth = _props.dropdownWidth,
508 |         disabled = _props.disabled;
509 |     // padding:32, delete:26, isALL: 38, arrow: 18
510 |  
511 |     var padWidth = 20;
512 |     if (isAll || isSelectNode && children) {
513 |       padWidth += locale === 'en-us' ? 25 : 36;
514 |     }
515 |     if (isSelectNode && !disabled) {
516 |       padWidth += locale === 'en-us' ? 38 : 26;
517 |     }
518 |     if (children) {
519 |       padWidth += 18;
520 |     }
521 |  
522 |     return dropdownWidth - padWidth - paddingLeftStyle;
523 |   };
524 |  
525 |   RightTreeNode.prototype.isSelectNode = function isSelectNode() {
526 |     var _props2 = this.props,
527 |         pos = _props2.pos,
528 |         keys = _props2.keys;
529 |  
530 |  
531 |     return keys.indexOf(pos) > -1;
532 |   };
533 |  
534 |   RightTreeNode.prototype.render = function render() {
535 |     var _arrowCls;
536 |  
537 |     var _props3 = this.props,
538 |         treeNodeLabelProp = _props3.treeNodeLabelProp,
539 |         children = _props3.children,
540 |         isAll = _props3.isAll,
541 |         prefixCls = _props3.prefixCls,
542 |         level = _props3.level,
543 |         locale = _props3.locale,
544 |         disabled = _props3.disabled;
545 |     var expand = this.state.expand;
546 |     // padding 无箭头 +36  有箭头+18
547 |  
548 |     var paddingLeft = 0;
549 |     if (level > 1) {
550 |       paddingLeft = !children ? 16 + (level - 1) * 18 : 16 + (level - 2) * 18;
551 |     } else if (level === 1 && !children) {
552 |       // fix style for the first level label which has no Children
553 |       paddingLeft = 5;
554 |     }
555 |     var arrowCls = (_arrowCls = {}, _defineProperty(_arrowCls, prefixCls + '-arrow-close', !expand), _defineProperty(_arrowCls, prefixCls + '-arrow-open', expand), _defineProperty(_arrowCls, prefixCls + '-arrow-switch', true), _arrowCls);
556 |     var isSelectNode = this.isSelectNode();
557 |  
558 |     var maxWidth = this.getMaxWidth(isSelectNode, paddingLeft);
559 |  
560 |     var content = _react2['default'].createElement(
561 |       'span',
562 |       {
563 |         style: { maxWidth: maxWidth + 'px' },
564 |         className: prefixCls + '-label',
565 |         title: this.props[treeNodeLabelProp]
566 |       },
567 |       this.props[treeNodeLabelProp]
568 |     );
569 |  
570 |     return _react2['default'].createElement(
571 |       'div',
572 |       null,
573 |       _react2['default'].createElement(
574 |         'div',
575 |         { className: prefixCls + '-hoverNode', style: { paddingLeft: paddingLeft + 'px' } },
576 |         children ? _react2['default'].createElement('span', { onClick: this.expand, className: (0, _classnames2['default'])(arrowCls) }) : null,
577 |         content,
578 |         isAll || isSelectNode && children ? _react2['default'].createElement(
579 |           'span',
580 |           { className: prefixCls + '-allSelect' },
581 |           _i18n2['default'][locale].all
582 |         ) : null,
583 |         isSelectNode && !disabled ? _react2['default'].createElement(
584 |           'span',
585 |           { className: prefixCls + '-clear', onClick: this.removeSelected },
586 |           _i18n2['default'][locale]['delete']
587 |         ) : null
588 |       ),
589 |       expand && children ? children : null
590 |     );
591 |   };
592 |  
593 |   return RightTreeNode;
594 | }(_react2['default'].Component);
595 |  
596 | exports['default'] = RightTreeNode;
597 |  
598 |  
599 | RightTreeNode.defaultProps = {
600 |   locale: 'zh-cn',
601 |   keys: []
602 | };
603 |  
604 | RightTreeNode.propTypes = {
605 |   value: _propTypes2['default'].oneOfType([_propTypes2['default'].array, _propTypes2['default'].string, _propTypes2['default'].object]),
606 |   treeNodeLabelProp: _propTypes2['default'].any,
607 |   children: _propTypes2['default'].any,
608 |   isAll: _propTypes2['default'].bool,
609 |   prefixCls: _propTypes2['default'].string,
610 |   level: _propTypes2['default'].number,
611 |   removeSelected: _propTypes2['default'].func,
612 |   pos: _propTypes2['default'].string,
613 |   locale: _propTypes2['default'].oneOf(['zh-cn', 'en-us']),
614 |   dropdownWidth: _propTypes2['default'].number,
615 |   keys: _propTypes2['default'].array,
616 |   disabled: _propTypes2['default'].bool
617 | };
618 | module.exports = exports['default'];
619 |  
621 |
622 |
623 | 627 | 628 | 629 | 636 | 637 | 638 | 639 | -------------------------------------------------------------------------------- /src/TreeSelect.less: -------------------------------------------------------------------------------- 1 | /** 2 | * TreeSelect Component Style for uxcore 3 | * @author biangang.bg 4 | * 5 | * Copyright 2014-2015, Uxcore Team, Alinw. 6 | * All rights reserved. 7 | */ 8 | 9 | @__select-tree-prefix-cls: uxcore-tree-select; 10 | 11 | .effect() { 12 | animation-duration: .3s; 13 | animation-fill-mode: both; 14 | transform-origin: 0 0; 15 | } 16 | .arrowClose() { 17 | position: relative; 18 | content: ''; 19 | display: block; 20 | top: 5px; 21 | left: 8px; 22 | width: 0px; 23 | height: 0px; 24 | border-color: transparent transparent transparent rgba(31, 56, 88, 0.4); 25 | border-style: solid; 26 | border-width: 4px 0 4px 4px; 27 | } 28 | .arrowOpen() { 29 | position: relative; 30 | content: ''; 31 | display: block; 32 | top: 7px; 33 | left: 6px; 34 | width: 0px; 35 | height: 0px; 36 | border-color: rgba(31, 56, 88, 0.4) transparent transparent transparent; 37 | border-style: solid; 38 | border-width: 4px 4px 0 4px; 39 | } 40 | 41 | .@{__select-tree-prefix-cls} { 42 | font-family: PingFangSC-Regular; 43 | box-sizing: border-box; 44 | position: relative; 45 | display: inline-block; 46 | vertical-align: middle; 47 | color: @text-secondary-color; 48 | 49 | ul, li { 50 | margin: 0; 51 | padding: 0; 52 | list-style: none; 53 | } 54 | 55 | &-selection { 56 | outline: none; 57 | user-select: none; 58 | -webkit-user-select: none; 59 | box-sizing: border-box; 60 | display: block; 61 | background-color: #fff; 62 | border-radius: @input-border-radius; 63 | border: 1px solid @border-color; 64 | &:hover { 65 | border-color: @border-hover-color; 66 | } 67 | &:active { 68 | border-color: @border-hover-color; 69 | } 70 | &__placeholder { 71 | i { 72 | font-style: normal; 73 | } 74 | } 75 | } 76 | 77 | &-focused &-selection { 78 | border-color: @border-hover-color; 79 | } 80 | 81 | &-enabled &-selection { 82 | &:hover { 83 | border-color: @border-hover-color; 84 | } 85 | &:active { 86 | border-color: @border-hover-color; 87 | } 88 | } 89 | 90 | &-selection-selected-value { 91 | overflow: hidden; 92 | padding-right: 10px; 93 | text-overflow: ellipsis; 94 | } 95 | 96 | &-arrow { 97 | position: absolute; 98 | top: 1px; 99 | right: 1px; 100 | width: 20px; 101 | height: 32px; 102 | b { 103 | position: absolute; 104 | top: 0; 105 | right: 0; 106 | left: 0; 107 | bottom: 0; 108 | margin: auto; 109 | width: 0; 110 | height: 0; 111 | border-color: @text-thirdary-color transparent transparent transparent; 112 | border-style: solid; 113 | border-width: 4px 4px 0 4px; 114 | } 115 | } 116 | 117 | &-selection--single { 118 | height: 36px; 119 | cursor: pointer; 120 | position: relative; 121 | 122 | .@{__select-tree-prefix-cls}-selection__placeholder { 123 | position: absolute; 124 | top: 0; 125 | color: rgba(31, 56, 88, 0.4); 126 | } 127 | 128 | .@{__select-tree-prefix-cls}-selection__rendered { 129 | display: block; 130 | overflow: hidden; 131 | white-space: nowrap; 132 | text-overflow: ellipsis; 133 | padding-left: 10px; 134 | padding-right: 20px; 135 | line-height: 34px; 136 | } 137 | 138 | .@{__select-tree-prefix-cls}-selection__clear { 139 | font-weight: bold; 140 | position: absolute; 141 | color: @text-thirdary-color; 142 | top: 7px; 143 | right: 20px; 144 | &:after { 145 | content: '×' 146 | } 147 | } 148 | } 149 | 150 | &-disabled { 151 | color: @text-disabled-color; 152 | cursor: not-allowed; 153 | 154 | .@{__select-tree-prefix-cls}-selection { 155 | background-color: @bg-disabled-color; 156 | &:hover, &:active { 157 | border-color: @border-disabled-color; 158 | } 159 | } 160 | 161 | .@{__select-tree-prefix-cls}-selection--single, 162 | .@{__select-tree-prefix-cls}-selection__choice__remove { 163 | cursor: not-allowed; 164 | color: @text-disabled-color; 165 | 166 | &:hover, &:active { 167 | border-color: @border-disabled-color; 168 | } 169 | } 170 | } 171 | 172 | &-search__field__wrap { 173 | display: inline-block; 174 | position: relative; 175 | } 176 | 177 | &-search__field__placeholder { 178 | position: absolute; 179 | top: 0; 180 | left: 3px; 181 | color: rgba(31, 56, 88, 0.4); 182 | i { 183 | font-style: normal; 184 | } 185 | } 186 | 187 | &-search__field__mirror { 188 | position: absolute; 189 | top: 0; 190 | left: -9999px; 191 | white-space: pre; 192 | pointer-events: none; 193 | } 194 | 195 | &-search--inline { 196 | width: 100%; 197 | position: relative; 198 | .@{__select-tree-prefix-cls}-search__field__wrap { 199 | width: 100%; 200 | } 201 | .@{__select-tree-prefix-cls}-search__field { 202 | border: none; 203 | font-size: 100%; 204 | line-height: 16px; 205 | background: transparent; 206 | outline: 0; 207 | width: 100%; 208 | } 209 | .@{__select-tree-prefix-cls}-selection-selected-value { 210 | position: absolute; 211 | left: 0; 212 | top: 0; 213 | opacity: 0.4; 214 | filter: "alpha(opacity=40)"; 215 | width: 100%; 216 | } 217 | > i { 218 | float: right; 219 | } 220 | } 221 | 222 | &-enabled.@{__select-tree-prefix-cls}-selection--multiple { 223 | cursor: text; 224 | } 225 | 226 | &-selection--multiple { 227 | min-height: 36px; 228 | 229 | .@{__select-tree-prefix-cls}-search--inline { 230 | float: left; 231 | width: auto; 232 | .@{__select-tree-prefix-cls}-search__field { 233 | &__wrap { 234 | width: auto; 235 | } 236 | width: 0.75em; 237 | } 238 | } 239 | 240 | .@{__select-tree-prefix-cls}-search__field__placeholder { 241 | top: 9px; 242 | left: 8px; 243 | } 244 | 245 | .@{__select-tree-prefix-cls}-selection__rendered { 246 | overflow: hidden; 247 | text-overflow: ellipsis; 248 | padding-left: 8px; 249 | padding-bottom: 2px; 250 | } 251 | 252 | > ul > li { 253 | margin-top: 4px; 254 | height: 26px; 255 | line-height: 26px; 256 | } 257 | } 258 | 259 | &-enabled { 260 | .@{__select-tree-prefix-cls}-selection__choice { 261 | cursor: default; 262 | &:hover { 263 | .@{__select-tree-prefix-cls}-selection__choice__remove { 264 | opacity: 1; 265 | transform: scale(1); 266 | } 267 | .@{__select-tree-prefix-cls}-selection__choice__content { 268 | margin-left: -8px; 269 | margin-right: 8px; 270 | } 271 | } 272 | } 273 | } 274 | 275 | & .@{__select-tree-prefix-cls}-selection__choice { 276 | background-color: #f3f3f3; 277 | border-radius: 4px; 278 | float: left; 279 | padding: 0 15px; 280 | margin-right: 4px; 281 | position: relative; 282 | overflow: hidden; 283 | transition: padding .3s cubic-bezier(0.6, -0.28, 0.735, 0.045), width .3s cubic-bezier(0.6, -0.28, 0.735, 0.045); 284 | 285 | &__content { 286 | margin-left: 0; 287 | margin-right: 0; 288 | transition: margin .3s cubic-bezier(0.165, 0.84, 0.44, 1); 289 | } 290 | 291 | &-zoom-enter, &-zoom-appear, &-zoom-leave { 292 | .effect(); 293 | opacity: 0; 294 | animation-play-state: paused; 295 | animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275); 296 | } 297 | 298 | &-zoom-leave { 299 | opacity: 1; 300 | animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045); 301 | } 302 | 303 | &-zoom-enter.@{__select-tree-prefix-cls}-selection__choice-zoom-enter-active, 304 | &-zoom-appear.@{__select-tree-prefix-cls}-selection__choice-zoom-appear-active { 305 | animation-play-state: running; 306 | animation-name: rcSelectChoiceZoomIn; 307 | } 308 | 309 | &-zoom-leave.@{__select-tree-prefix-cls}-selection__choice-zoom-leave-active { 310 | animation-play-state: running; 311 | animation-name: rcSelectChoiceZoomOut; 312 | } 313 | 314 | @keyframes rcSelectChoiceZoomIn { 315 | 0% { 316 | transform: scale(0.6); 317 | opacity: 0; 318 | } 319 | 100% { 320 | transform: scale(1); 321 | opacity: 1; 322 | } 323 | } 324 | 325 | @keyframes rcSelectChoiceZoomOut { 326 | to { 327 | transform: scale(0); 328 | opacity: 0; 329 | } 330 | } 331 | 332 | &__remove { 333 | color: #919191; 334 | cursor: pointer; 335 | font-weight: bold; 336 | padding: 0 4px 0 0; 337 | position: absolute; 338 | opacity: 0; 339 | transform: scale(0); 340 | top: 0; 341 | right: 2px; 342 | transition: opacity .3s, transform .3s; 343 | &:before { 344 | content: '×' 345 | } 346 | 347 | &:hover { 348 | color: #333; 349 | } 350 | } 351 | } 352 | 353 | &-dropdown { 354 | font-family: PingFangSC-Regular; 355 | z-index: 1070; 356 | box-shadow: 0 0px 4px #d9d9d9; 357 | left: -9999px; 358 | top: -9999px; 359 | position: absolute; 360 | outline: none; 361 | max-height: 312px; 362 | overflow: hidden; 363 | &-hidden { 364 | display: none; 365 | } 366 | span.@{__select-tree-prefix-cls}-tree-title { 367 | display: inline-block; 368 | vertical-align: middle; 369 | width: 92px; 370 | overflow: hidden; 371 | text-overflow: ellipsis; 372 | white-space: nowrap; 373 | 374 | } 375 | .@{__select-tree-prefix-cls}-not-found { 376 | display: inline-block; 377 | margin: 10px 0 0 20px; 378 | } 379 | } 380 | 381 | 382 | &-dropdown-search { 383 | display: block; 384 | padding: 18px 18px 0px; 385 | position: relative; 386 | .@{__select-tree-prefix-cls}-search__field__wrap { 387 | width: 100%; 388 | } 389 | .@{__select-tree-prefix-cls}-search_icon { 390 | position: absolute; 391 | right: 4px; 392 | top: 3px; 393 | font-size: 13px; 394 | } 395 | .@{__select-tree-prefix-cls}-search__field__placeholder { 396 | top: 4px; 397 | padding-left: 6px; 398 | } 399 | .@{__select-tree-prefix-cls}-search__field { 400 | padding: 4px 4px 4px 7px; 401 | width: 100%; 402 | box-sizing: border-box; 403 | border: 1px solid #d9d9d9; 404 | border-radius: @input-border-radius; 405 | outline: none; 406 | } 407 | &.@{__select-tree-prefix-cls}-search--hide { 408 | display: none; 409 | } 410 | } 411 | 412 | &-open { 413 | .@{__select-tree-prefix-cls}-arrow b { 414 | border-color: transparent transparent #888 transparent; 415 | border-width: 0 4px 4px 4px; 416 | } 417 | } 418 | 419 | &-search__field__mirror{ 420 | position: absolute; 421 | top: 0; 422 | left: -9999px; 423 | white-space: pre; 424 | pointer-events: none; 425 | } 426 | } 427 | 428 | .@{__select-tree-prefix-cls}-inline { 429 | z-index: 2; 430 | .@{__select-tree-prefix-cls}-selection { 431 | border: 0 none; 432 | &__rendered { 433 | display: inline-block; 434 | padding: 0 10px; 435 | height: 36px; 436 | } 437 | &__placeholder { 438 | position: static; 439 | } 440 | &-selected-value { 441 | padding-right: 0; 442 | } 443 | } 444 | &.@{__select-tree-prefix-cls}-open { 445 | .@{__select-tree-prefix-cls}-selection { 446 | border: 1px solid @border-color; 447 | border-bottom-color: #fff; 448 | } 449 | } 450 | .@{__select-tree-prefix-cls}-arrow { 451 | position: relative; 452 | display: inline-block; 453 | vertical-align: top; 454 | } 455 | } 456 | .@{__select-tree-prefix-cls}-inline-dropdown { 457 | z-index: 1; 458 | box-shadow: none; 459 | } 460 | 461 | @keyframes slideUpIn { 462 | 0% { 463 | opacity: 0; 464 | transform-origin: 0 0; 465 | transform: scaleY(.8); 466 | } 467 | 468 | 100% { 469 | opacity: 1; 470 | transform-origin: 0 0; 471 | transform: scaleY(1); 472 | } 473 | } 474 | 475 | @keyframes slideUpOut { 476 | 0% { 477 | opacity: 1; 478 | transform-origin: 0 0; 479 | transform: scaleY(1); 480 | } 481 | 482 | 100% { 483 | opacity: 0; 484 | transform-origin: 0 0; 485 | transform: scaleY(.8); 486 | } 487 | } 488 | 489 | @keyframes slideDownIn { 490 | 0% { 491 | opacity: 0; 492 | transform-origin: 100% 100%; 493 | transform: scaleY(.8); 494 | } 495 | 496 | 100% { 497 | opacity: 1; 498 | transform-origin: 100% 100%; 499 | transform: scaleY(1); 500 | } 501 | } 502 | 503 | @keyframes slideDownOut { 504 | 0% { 505 | opacity: 1; 506 | transform-origin: 100% 100%; 507 | transform: scaleY(1); 508 | } 509 | 510 | 100% { 511 | opacity: 0; 512 | transform-origin: 100% 100%; 513 | transform: scaleY(.8); 514 | } 515 | } 516 | 517 | .@{__select-tree-prefix-cls}-dropdown-placement-bottomLeft { 518 | &.slideUp-enter, 519 | &.slideUp-appear { 520 | opacity: 0; 521 | transform-origin: 0 0; 522 | transform: scaleY(.8); 523 | animation-timing-function: ease; 524 | animation-duration: .3s; 525 | } 526 | &.slideUp-enter-active, 527 | &.slideUp-appear-active { 528 | visibility: visible; 529 | animation-name: slideUpIn; 530 | } 531 | &.slideUp-leave { 532 | opacity: 1; 533 | transform-origin: 0 0; 534 | transform: scaleY(1); 535 | animation-timing-function: ease; 536 | animation-duration: .3s; 537 | } 538 | &.slideUp-leave-active { 539 | visibility: visible; 540 | animation-name: slideUpOut; 541 | } 542 | } 543 | 544 | .@{__select-tree-prefix-cls}-dropdown-placement-topLeft { 545 | &.slideUp-enter, 546 | &.slideUp-appear { 547 | opacity: 0; 548 | transform-origin: 100% 100%; 549 | transform: scaleY(.8); 550 | animation-timing-function: ease; 551 | animation-duration: .3s; 552 | } 553 | &.slideUp-enter-active, 554 | &.slideUp-appear-active { 555 | visibility: visible; 556 | animation-name: slideDownIn; 557 | } 558 | &.slideUp-leave { 559 | opacity: 1; 560 | transform-origin: 100% 100%; 561 | transform: scaleY(1); 562 | animation-timing-function: ease; 563 | animation-duration: .3s; 564 | } 565 | &.slideUp-leave-active { 566 | visibility: visible; 567 | animation-name: slideDownOut; 568 | } 569 | } 570 | 571 | .@{__select-tree-prefix-cls}-dropdown-left, 572 | .@{__select-tree-prefix-cls}-dropdown-right { 573 | background-color: white; 574 | border: 1px solid #dcdcdc; 575 | border-radius: @input-border-radius; 576 | box-sizing: border-box; 577 | display: inline-block; 578 | vertical-align: middle; 579 | width: 50%; 580 | height: 100%; 581 | overflow-y: auto; 582 | height: 100%; 583 | } 584 | 585 | .@{__select-tree-prefix-cls}-dropdown-right { 586 | border-left-color: transparent; 587 | overflow-y: hidden; 588 | padding-bottom: 3px; 589 | position: relative; 590 | &-selected { 591 | &-title { 592 | color: rgba(31, 56, 88, 0.6); 593 | } 594 | &-number { 595 | color: rgba(0, 0, 0, 0.8); 596 | } 597 | } 598 | &-allClear { 599 | float: right; 600 | cursor: pointer; 601 | color: #3C99D8; 602 | } 603 | &-noContent { 604 | color: rgba(31,56,88,0.4); 605 | font-size: 12px; 606 | line-height: 48px; 607 | background: rgba(31,56,88,0.04); 608 | border: 1px dashed rgba(31,56,88,0.20); 609 | height: 48px; 610 | width: 75%; 611 | text-align: center; 612 | top: 50%; 613 | left: 50%; 614 | transform: translate(-50%, -50%); 615 | position: absolute; 616 | } 617 | &-title { 618 | text-align: center; 619 | font-size: 14px; 620 | } 621 | } 622 | 623 | .@{__select-tree-prefix-cls}-rightTreeNode { 624 | font-size: 12px; 625 | color: rgba(0, 0, 0, 0.6); 626 | overflow: auto; 627 | &-clear { 628 | position: absolute; 629 | right: 15px; 630 | top: 1px; 631 | cursor: pointer; 632 | color: #3C99D8; 633 | transition: opacity .3s, transform .3s; 634 | transform: scale(0); 635 | -ms-transform: scale(0); 636 | } 637 | 638 | &-hoverNode { 639 | &:hover{ 640 | background: rgba(31,56,88,0.04); 641 | .@{__select-tree-prefix-cls}-rightTreeNode-clear { 642 | opacity: 1; 643 | transform: scale(1); 644 | -ms-transform: scale(1); 645 | } 646 | } 647 | span { 648 | vertical-align: middle; 649 | } 650 | height: 28px; 651 | line-height: 28px; 652 | padding: 0 16px; 653 | white-space: nowrap; 654 | position: relative; 655 | } 656 | &-label { 657 | white-space: nowrap; 658 | display: inline-block; 659 | vertical-align: middle; 660 | overflow: hidden; 661 | text-overflow: ellipsis; 662 | } 663 | &-allSelect { 664 | color: rgba(31,56,88,0.6); 665 | margin-left: 12px; 666 | } 667 | &-arrow-switch { 668 | width: 18px; 669 | height: 18px; 670 | display: inline-block; 671 | vertical-align: middle; 672 | border: 0 none; 673 | cursor: pointer; 674 | } 675 | .@{__select-tree-prefix-cls}-rightTreeNode-arrow-close { 676 | &:after { 677 | .arrowClose(); 678 | } 679 | } 680 | .@{__select-tree-prefix-cls}-rightTreeNode-arrow-open { 681 | &:after { 682 | .arrowOpen(); 683 | } 684 | } 685 | 686 | } 687 | 688 | @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { 689 | /* IE10/11-specific styles go here */ 690 | .@{__select-tree-prefix-cls}-selection--multiple { 691 | .@{__select-tree-prefix-cls}-search--inline { 692 | .@{__select-tree-prefix-cls}-search__field { 693 | width: 50px!important; 694 | } 695 | } 696 | } 697 | } 698 | 699 | @tree-assets-img: 'https://aliwork.alicdn.com/tps/TB1k_tsKpXXXXcQXFXXXXXXXXXX-130-87.png'; 700 | 701 | @__select-tree-node-prefix-cls: uxcore-tree-select-tree; 702 | 703 | .@{__select-tree-node-prefix-cls} { 704 | .@{__select-tree-node-prefix-cls}-node-selected { 705 | color: @brand-primary; 706 | } 707 | margin: 0; 708 | padding: 14px 18px; 709 | li { 710 | padding: 0; 711 | margin: 0; 712 | list-style: none; 713 | white-space: nowrap; 714 | outline: 0; 715 | line-height: 24px; 716 | ul { 717 | margin: 0; 718 | padding: 0 0 0 18px; 719 | &.@{__select-tree-node-prefix-cls}-line { 720 | background: url("https://t.alipayobjects.com/images/T13BtfXl0mXXXXXXXX.gif") 0 0 repeat-y; 721 | } 722 | } 723 | a { 724 | display: inline-block; 725 | padding: 2px 6px; 726 | cursor: pointer; 727 | text-decoration: none; 728 | line-height: 18px; 729 | vertical-align: middle; 730 | color: #666; 731 | &:hover { 732 | background-color: hsv(round(hsvhue(@brand-primary) + 2), round(hsvsaturation(@brand-primary) - 78%), round(hsvvalue(@brand-primary) + 5%)); 733 | } 734 | } 735 | span { 736 | &.@{__select-tree-node-prefix-cls}-switcher-noop, 737 | &.@{__select-tree-node-prefix-cls}-switcher, 738 | &.@{__select-tree-node-prefix-cls}-iconEle { 739 | margin-right: 2px; 740 | width: 18px; 741 | height: 18px; 742 | display: inline-block; 743 | vertical-align: middle; 744 | border: 0 none; 745 | cursor: pointer; 746 | outline: none; 747 | background-color: transparent; 748 | background-repeat: no-repeat; 749 | background-attachment: scroll; 750 | background-image: url(@tree-assets-img); 751 | } 752 | &.@{__select-tree-node-prefix-cls}-icon_loading { 753 | margin-right: 2px; 754 | background: url('https://t.alipayobjects.com/images/rmsweb/T1YxhiXgJbXXXXXXXX.gif') no-repeat scroll 0 0; 755 | } 756 | &.@{__select-tree-node-prefix-cls}-switcher-noop { 757 | background-image: none; 758 | } 759 | &.@{__select-tree-node-prefix-cls}-switcher { 760 | &-disabled { 761 | background: #fff; 762 | position: relative; 763 | &:after { 764 | content: '-'; 765 | position: absolute; 766 | top: 8px; 767 | left: 6px; 768 | color: gray; 769 | } 770 | } 771 | &.@{__select-tree-node-prefix-cls}-roots_open { 772 | background-position: -112px 0px; 773 | } 774 | &.@{__select-tree-node-prefix-cls}-roots_close { 775 | background-position: -94px 0px; 776 | } 777 | &.@{__select-tree-node-prefix-cls}-center_open { 778 | background-position: -112px -18px; 779 | } 780 | &.@{__select-tree-node-prefix-cls}-center_close { 781 | background-position: -94px -18px; 782 | } 783 | &.@{__select-tree-node-prefix-cls}-bottom_open { 784 | background-position: -112px -36px; 785 | } 786 | &.@{__select-tree-node-prefix-cls}-bottom_close { 787 | background-position: -94px -36px; 788 | } 789 | } 790 | } 791 | } 792 | &-child-tree { 793 | display: none; 794 | &-open { 795 | display: block; 796 | } 797 | } 798 | &-treenode-disabled { 799 | > span, 800 | > a { 801 | color: gray; 802 | font-weight: bold; 803 | } 804 | } 805 | } 806 | .use-svg { 807 | .@{__select-tree-node-prefix-cls}-switcher { 808 | &.@{__select-tree-node-prefix-cls}-switcher_open { 809 | background: none; 810 | &:after { 811 | .arrowOpen(); 812 | } 813 | } 814 | &.@{__select-tree-node-prefix-cls}-switcher_close { 815 | background: none; 816 | &:after { 817 | .arrowClose(); 818 | } 819 | } 820 | &.@{__select-tree-node-prefix-cls}-noline_open { 821 | background: url('https://img.alicdn.com/tps/TB1IvveJVXXXXbcXFXXXXXXXXXX-14-10.svg') 50% 50% no-repeat; 822 | background-size: 50% auto; 823 | } 824 | &.@{__select-tree-node-prefix-cls}-noline_close { 825 | background: url('https://img.alicdn.com/tps/TB17BHzJVXXXXXEXXXXXXXXXXXX-10-14.svg') 50% 50% no-repeat; 826 | background-size: auto 50%; 827 | } 828 | } 829 | .@{__select-tree-node-prefix-cls}-checkbox { 830 | display: inline-block; 831 | width: 16px; 832 | height: 16px; 833 | margin: 0 3px; 834 | vertical-align: middle; 835 | cursor: pointer; 836 | outline: none; 837 | background: url("@{svg-path}/checkbox-normal.svg") no-repeat; 838 | &.@{__select-tree-node-prefix-cls}-checkbox-checked { 839 | background: url("@{svg-path}/checkbox-checked.svg") no-repeat; 840 | &.@{__select-tree-node-prefix-cls}-checkbox-disabled { 841 | background: url("@{svg-path}/checkbox-checked-disabled.svg") no-repeat; 842 | } 843 | } 844 | &.@{__select-tree-node-prefix-cls}-checkbox-indeterminate { 845 | background: url("@{svg-path}/checkbox-partial-checked.svg") no-repeat; 846 | } 847 | &-checkbox-disabled { 848 | background: url("@{svg-path}/checkbox-disabled.svg") no-repeat; 849 | } 850 | } 851 | } 852 | .no-svg { 853 | .@{__select-tree-node-prefix-cls}-switcher { 854 | &.@{__select-tree-node-prefix-cls}-noline_open { 855 | background-position: -115px -72px; 856 | } 857 | &.@{__select-tree-node-prefix-cls}-noline_close { 858 | background-position: -97px -72px; 859 | } 860 | } 861 | .@{__select-tree-node-prefix-cls}-checkbox { 862 | margin-right: 2px; 863 | display: inline-block; 864 | vertical-align: middle; 865 | cursor: pointer; 866 | outline: none; 867 | background-image: url(@tree-assets-img); 868 | width: 14px; 869 | height: 14px; 870 | background-position: 0 0; 871 | &.@{__select-tree-node-prefix-cls}-checkbox-checked { 872 | background-position: -15px 0; 873 | } 874 | &.@{__select-tree-node-prefix-cls}-checkbox-indeterminate { 875 | background-position: -15px -28px; 876 | } 877 | &-disabled { 878 | background-position: 0 -28px!important; 879 | } 880 | } 881 | } --------------------------------------------------------------------------------