parent
ff7a426d55
commit
e23265c74c
|
@ -1,4 +1,3 @@
|
||||||
import { getOptionProps } from './props-util'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
directives: {
|
directives: {
|
||||||
|
@ -17,9 +16,9 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
setState (state, callback) {
|
setState (state, callback) {
|
||||||
const newState = typeof state === 'function' ? state(this.$data) : state
|
const newState = typeof state === 'function' ? state(this.$data) : state
|
||||||
if (this.getDerivedStateFromProps) {
|
// if (this.getDerivedStateFromProps) {
|
||||||
Object.assign(newState, this.getDerivedStateFromProps(getOptionProps(this), this.$data, true) || {})
|
// Object.assign(newState, this.getDerivedStateFromProps(getOptionProps(this), { ...this.$data, ...newState }, true) || {})
|
||||||
}
|
// }
|
||||||
Object.assign(this.$data, newState)
|
Object.assign(this.$data, newState)
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
callback && callback()
|
callback && callback()
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`renders ./components/tree-select/demo/basic.md correctly 1`] = `
|
exports[`renders ./components/tree-select/demo/basic.md correctly 1`] = `<span role="combobox" aria-haspopup="listbox" tabindex="0" class="ant-select ant-select-enabled ant-select-allow-clear" style="width: 300px;"><span class="ant-select-selection ant-select-selection--single"><span class="ant-select-selection__rendered"><span class="ant-select-selection__placeholder">Please select</span></span><span class="ant-select-arrow" style="outline: none;"><i class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></span></span>`;
|
||||||
<span class="ant-select ant-select-enabled ant-select-allow-clear" style="width: 300px;"><span role="combobox" aria-autocomplete="list" aria-haspopup="true" tabindex="0" class="ant-select-selection
|
|
||||||
ant-select-selection--single"><span class="ant-select-selection__rendered"><span class="ant-select-selection__placeholder">Please select</span></span><span class="ant-select-arrow" style="outline: none;"><i class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></span></span>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`renders ./components/tree-select/demo/checkable.md correctly 1`] = `
|
exports[`renders ./components/tree-select/demo/checkable.md correctly 1`] = `
|
||||||
<span class="ant-select ant-select-enabled" style="width: 300px;"><span role="combobox" aria-autocomplete="list" aria-haspopup="true" class="ant-select-selection
|
<span role="combobox" aria-haspopup="listbox" tabindex="-1" class="ant-select ant-select-enabled" style="width: 300px;"><span class="ant-select-selection ant-select-selection--multiple"><div class="ant-select-selection__rendered"><li unselectable="unselectable" role="menuitem" title="Node1" class="ant-select-selection__choice"><span class="ant-select-selection__choice__remove"><i class="ant-select-remove-icon anticon anticon-close"><svg viewBox="64 64 896 896" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></i></span><span class="ant-select-selection__choice__content">Node1</span></li>
|
||||||
ant-select-selection--multiple"><div class="ant-select-selection__rendered"><li title="Node1" unselectable="unselectable" class="ant-select-selection__choice"><span class="ant-select-selection__choice__remove"><i class="ant-select-remove-icon anticon anticon-close"><svg viewBox="64 64 896 896" data-icon="close" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg></i></span><span class="ant-select-selection__choice__content">Node1</span></li>
|
<li class="ant-select-search ant-select-search--inline"><span class="ant-select-search__field__wrap"><input type="text" aria-label="filter select" aria-autocomplete="list" aria-multiline="false" class="ant-select-search__field" style="width: 0px;"><span class="ant-select-search__field__mirror"> </span></span></li>
|
||||||
<li class="ant-select-search ant-select-search--inline"><span class="ant-select-search__field__wrap"><input role="textbox" class="ant-select-search__field"><span class="ant-select-search__field__mirror"> </span></span></li>
|
</div>
|
||||||
</div><span class="ant-select-search__field__placeholder" style="display: none;">Please select</span></span>
|
</span></span>
|
||||||
</span>
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/tree-select/demo/multiple.md correctly 1`] = `
|
exports[`renders ./components/tree-select/demo/multiple.md correctly 1`] = `
|
||||||
<span class="ant-select ant-select-enabled ant-select-allow-clear" style="width: 300px;"><span role="combobox" aria-autocomplete="list" aria-haspopup="true" class="ant-select-selection
|
<span role="combobox" aria-haspopup="listbox" tabindex="-1" class="ant-select ant-select-enabled ant-select-allow-clear" style="width: 300px;"><span class="ant-select-selection ant-select-selection--multiple"><div class="ant-select-selection__rendered"><li class="ant-select-search ant-select-search--inline"><span class="ant-select-search__field__wrap"><input type="text" aria-label="filter select" aria-autocomplete="list" aria-multiline="false" class="ant-select-search__field" style="width: 0px;"><span class="ant-select-search__field__mirror"> </span></span></li>
|
||||||
ant-select-selection--multiple"><div class="ant-select-selection__rendered"><li class="ant-select-search ant-select-search--inline"><span class="ant-select-search__field__wrap"><input role="textbox" class="ant-select-search__field"><span class="ant-select-search__field__mirror"> </span></span></li>
|
|
||||||
</div><span class="ant-select-search__field__placeholder" style="display: block;">Please select</span></span></span>
|
</div><span class="ant-select-search__field__placeholder" style="display: block;">Please select</span></span></span>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/tree-select/demo/treeData.md correctly 1`] = `
|
exports[`renders ./components/tree-select/demo/suffix.md correctly 1`] = `<span role="combobox" aria-haspopup="listbox" tabindex="0" class="ant-select ant-select-enabled ant-select-allow-clear" style="width: 300px;"><span class="ant-select-selection ant-select-selection--single"><span class="ant-select-selection__rendered"><span class="ant-select-selection__placeholder">Please select</span></span><span class="ant-select-arrow" style="outline: none;"><i class="anticon anticon-smile"><svg viewBox="64 64 896 896" data-icon="smile" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M288 421a48 48 0 1 0 96 0 48 48 0 1 0-96 0zm352 0a48 48 0 1 0 96 0 48 48 0 1 0-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 0 1 248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 0 1 249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 0 1 775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 0 1 775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 0 0-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 0 0-8-8.4z"></path></svg></i></span></span></span>`;
|
||||||
<span class="ant-select ant-select-enabled" style="width: 300px;"><span role="combobox" aria-autocomplete="list" aria-haspopup="true" tabindex="0" class="ant-select-selection
|
|
||||||
ant-select-selection--single"><span class="ant-select-selection__rendered"><span class="ant-select-selection__placeholder">Please select</span></span><span class="ant-select-arrow" style="outline: none;"><i class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></span></span>
|
exports[`renders ./components/tree-select/demo/treeData.md correctly 1`] = `<span role="combobox" aria-haspopup="listbox" tabindex="0" class="ant-select ant-select-enabled" style="width: 300px;"><span class="ant-select-selection ant-select-selection--single"><span class="ant-select-selection__rendered"><span class="ant-select-selection__placeholder">Please select</span></span><span class="ant-select-arrow" style="outline: none;"><i class="ant-select-arrow-icon anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" class=""><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></i></span></span></span>`;
|
||||||
`;
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ The most basic usage.
|
||||||
>
|
>
|
||||||
<a-tree-select-node value='parent 1' title='parent 1' key='0-1'>
|
<a-tree-select-node value='parent 1' title='parent 1' key='0-1'>
|
||||||
<a-tree-select-node value='parent 1-0' title='parent 1-0' key='0-1-1'>
|
<a-tree-select-node value='parent 1-0' title='parent 1-0' key='0-1-1'>
|
||||||
<a-tree-select-node value='leaf1' title='my leaf' key='random' />
|
<a-tree-select-node :selectable="false" value='leaf1' title='my leaf' key='random' />
|
||||||
<a-tree-select-node value='leaf2' title='your leaf' key='random1' />
|
<a-tree-select-node value='leaf2' title='your leaf' key='random1' />
|
||||||
</a-tree-select-node>
|
</a-tree-select-node>
|
||||||
<a-tree-select-node value='parent 1-1' title='parent 1-1' key='random2'>
|
<a-tree-select-node value='parent 1-1' title='parent 1-1' key='random2'>
|
||||||
|
@ -39,12 +39,13 @@ The most basic usage.
|
||||||
export default {
|
export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
treeExpandedKeys: [],
|
||||||
value: undefined,
|
value: undefined,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onChange (value) {
|
onChange (value) {
|
||||||
console.log(arguments)
|
console.log(value)
|
||||||
this.value = value
|
this.value = value
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,6 @@ Multiple and checkable.
|
||||||
treeCheckable
|
treeCheckable
|
||||||
:showCheckedStrategy="SHOW_PARENT"
|
:showCheckedStrategy="SHOW_PARENT"
|
||||||
searchPlaceholder='Please select'
|
searchPlaceholder='Please select'
|
||||||
treeNodeFilterProp='label'
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -27,29 +26,29 @@ import { TreeSelect } from 'ant-design-vue'
|
||||||
const SHOW_PARENT = TreeSelect.SHOW_PARENT
|
const SHOW_PARENT = TreeSelect.SHOW_PARENT
|
||||||
|
|
||||||
const treeData = [{
|
const treeData = [{
|
||||||
label: 'Node1',
|
title: 'Node1',
|
||||||
value: '0-0',
|
value: '0-0',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
children: [{
|
children: [{
|
||||||
label: 'Child Node1',
|
title: 'Child Node1',
|
||||||
value: '0-0-0',
|
value: '0-0-0',
|
||||||
key: '0-0-0',
|
key: '0-0-0',
|
||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
label: 'Node2',
|
title: 'Node2',
|
||||||
value: '0-1',
|
value: '0-1',
|
||||||
key: '0-1',
|
key: '0-1',
|
||||||
children: [{
|
children: [{
|
||||||
label: 'Child Node3',
|
title: 'Child Node3',
|
||||||
value: '0-1-0',
|
value: '0-1-0',
|
||||||
key: '0-1-0',
|
key: '0-1-0',
|
||||||
disabled: true,
|
disabled: true,
|
||||||
}, {
|
}, {
|
||||||
label: 'Child Node4',
|
title: 'Child Node4',
|
||||||
value: '0-1-1',
|
value: '0-1-1',
|
||||||
key: '0-1-1',
|
key: '0-1-1',
|
||||||
}, {
|
}, {
|
||||||
label: 'Child Node5',
|
title: 'Child Node5',
|
||||||
value: '0-1-2',
|
value: '0-1-2',
|
||||||
key: '0-1-2',
|
key: '0-1-2',
|
||||||
}],
|
}],
|
||||||
|
@ -64,7 +63,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onChange (value) {
|
onChange (value) {
|
||||||
console.log('onChange ', value, arguments)
|
console.log('onChange ', value)
|
||||||
this.value = value
|
this.value = value
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Basic from './basic'
|
||||||
import Checkable from './checkable'
|
import Checkable from './checkable'
|
||||||
import Multiple from './multiple'
|
import Multiple from './multiple'
|
||||||
import TreeData from './treeData'
|
import TreeData from './treeData'
|
||||||
|
import Suffix from './suffix'
|
||||||
|
|
||||||
import CN from '../index.zh-CN.md'
|
import CN from '../index.zh-CN.md'
|
||||||
import US from '../index.en-US.md'
|
import US from '../index.en-US.md'
|
||||||
|
@ -35,6 +36,7 @@ export default {
|
||||||
<Checkable/>
|
<Checkable/>
|
||||||
<Multiple/>
|
<Multiple/>
|
||||||
<TreeData/>
|
<TreeData/>
|
||||||
|
<Suffix />
|
||||||
<api>
|
<api>
|
||||||
<template slot='cn'>
|
<template slot='cn'>
|
||||||
<CN/>
|
<CN/>
|
||||||
|
|
|
@ -47,14 +47,14 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onChange (value) {
|
onChange (value) {
|
||||||
console.log(arguments)
|
console.log(value)
|
||||||
this.value = value
|
this.value = value
|
||||||
},
|
},
|
||||||
onSearch () {
|
onSearch () {
|
||||||
console.log(arguments)
|
console.log(...arguments)
|
||||||
},
|
},
|
||||||
onSelect () {
|
onSelect () {
|
||||||
console.log(arguments)
|
console.log(...arguments)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
<cn>
|
||||||
|
#### 后缀图标
|
||||||
|
最简单的用法。
|
||||||
|
</cn>
|
||||||
|
|
||||||
|
<us>
|
||||||
|
#### Suffix
|
||||||
|
The most basic usage.
|
||||||
|
</us>
|
||||||
|
|
||||||
|
```html
|
||||||
|
<template>
|
||||||
|
<a-tree-select
|
||||||
|
showSearch
|
||||||
|
style="width: 300px"
|
||||||
|
:value="value"
|
||||||
|
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||||
|
placeholder='Please select'
|
||||||
|
allowClear
|
||||||
|
treeDefaultExpandAll
|
||||||
|
@change="onChange"
|
||||||
|
>
|
||||||
|
<a-icon slot="suffixIcon" type="smile" />
|
||||||
|
<a-tree-select-node value='parent 1' title='parent 1' key='0-1'>
|
||||||
|
<a-tree-select-node value='parent 1-0' title='parent 1-0' key='0-1-1'>
|
||||||
|
<a-tree-select-node value='leaf1' title='my leaf' key='random' />
|
||||||
|
<a-tree-select-node value='leaf2' title='your leaf' key='random1' />
|
||||||
|
</a-tree-select-node>
|
||||||
|
<a-tree-select-node value='parent 1-1' title='parent 1-1' key='random2'>
|
||||||
|
<a-tree-select-node value='sss' key='random3'>
|
||||||
|
<b style="color: #08c" slot="title">sss</b>
|
||||||
|
</a-tree-select-node>
|
||||||
|
</a-tree-select-node>
|
||||||
|
</a-tree-select-node>
|
||||||
|
</a-tree-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
value: undefined,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange (value) {
|
||||||
|
console.log(value)
|
||||||
|
this.value = value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
|
@ -16,10 +16,9 @@ The tree structure can be populated using `treeData` property. This is a quick a
|
||||||
:treeData="treeData"
|
:treeData="treeData"
|
||||||
placeholder='Please select'
|
placeholder='Please select'
|
||||||
treeDefaultExpandAll
|
treeDefaultExpandAll
|
||||||
labelInValue
|
|
||||||
v-model="value"
|
v-model="value"
|
||||||
>
|
>
|
||||||
<span style="color: #08c" slot="label" slot-scope="{key, value}" v-if="key='0-0-1'">
|
<span style="color: #08c" slot="title" slot-scope="{key, value}" v-if="key='0-0-1'">
|
||||||
<a-icon type="home"/>Child Node1 {{value}}
|
<a-icon type="home"/>Child Node1 {{value}}
|
||||||
</span>
|
</span>
|
||||||
</a-tree-select>
|
</a-tree-select>
|
||||||
|
@ -27,22 +26,22 @@ The tree structure can be populated using `treeData` property. This is a quick a
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const treeData = [{
|
const treeData = [{
|
||||||
label: 'Node1',
|
title: 'Node1',
|
||||||
value: '0-0',
|
value: '0-0',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
children: [{
|
children: [{
|
||||||
value: '0-0-1',
|
value: '0-0-1',
|
||||||
key: '0-0-1',
|
key: '0-0-1',
|
||||||
scopedSlots: { // custom label
|
scopedSlots: { // custom title
|
||||||
label: 'label',
|
title: 'title',
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
label: 'Child Node2',
|
title: 'Child Node2',
|
||||||
value: '0-0-2',
|
value: '0-0-2',
|
||||||
key: '0-0-2',
|
key: '0-0-2',
|
||||||
}],
|
}],
|
||||||
}, {
|
}, {
|
||||||
label: 'Node2',
|
title: 'Node2',
|
||||||
value: '0-1',
|
value: '0-1',
|
||||||
key: '0-1',
|
key: '0-1',
|
||||||
}]
|
}]
|
||||||
|
|
|
@ -21,16 +21,17 @@
|
||||||
| showCheckedStrategy | The way show selected item in box. **Default:** just show child nodes. **`TreeSelect.SHOW_ALL`:** show all checked treeNodes (include parent treeNode). **`TreeSelect.SHOW_PARENT`:** show checked treeNodes (just show parent treeNode). | enum { TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD |
|
| showCheckedStrategy | The way show selected item in box. **Default:** just show child nodes. **`TreeSelect.SHOW_ALL`:** show all checked treeNodes (include parent treeNode). **`TreeSelect.SHOW_PARENT`:** show checked treeNodes (just show parent treeNode). | enum { TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD |
|
||||||
| showSearch | Whether to display a search input in the dropdown menu(valid only in the single mode) | boolean | false |
|
| showSearch | Whether to display a search input in the dropdown menu(valid only in the single mode) | boolean | false |
|
||||||
| size | To set the size of the select input, options: `large` `small` | string | 'default' |
|
| size | To set the size of the select input, options: `large` `small` | string | 'default' |
|
||||||
|
| suffixIcon | The custom suffix icon | VNode \| slot | - |
|
||||||
| treeCheckable | Whether to show checkbox on the treeNodes | boolean | false |
|
| treeCheckable | Whether to show checkbox on the treeNodes | boolean | false |
|
||||||
| treeCheckStrictly | Whether to check nodes precisely (in the `checkable` mode), means parent and child nodes are not associated, and it will make `labelInValue` be true | boolean | false |
|
| treeCheckStrictly | Whether to check nodes precisely (in the `checkable` mode), means parent and child nodes are not associated, and it will make `labelInValue` be true | boolean | false |
|
||||||
| treeData | Data of the treeNodes, manual construction work is no longer needed if this property has been set(ensure the Uniqueness of each value) | array<{ value, label, children, [disabled, disableCheckbox, selectable] }> | \[] |
|
| treeData | Data of the treeNodes, manual construction work is no longer needed if this property has been set(ensure the Uniqueness of each value) | array<{ value, label, children, [disabled, disableCheckbox, selectable] }> | \[] |
|
||||||
| treeDataSimpleMode | Enable simple mode of treeData.(treeData should like this: [{id:1, pId:0, value:'1', label:"test1",...},...], pId is parent node's id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
|
| treeDataSimpleMode | Enable simple mode of treeData.(treeData should like this: [{id:1, pId:0, value:'1', label:"test1",...},...], pId is parent node's id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
|
||||||
| treeDefaultExpandAll | Whether to expand all treeNodes by default | boolean | false |
|
| treeDefaultExpandAll | Whether to expand all treeNodes by default | boolean | false |
|
||||||
| treeDefaultExpandedKeys | Default expanded treeNodes | string\[] | - |
|
| treeDefaultExpandedKeys | Default expanded treeNodes | string\[] | - |
|
||||||
|
| treeExpandedKeys | Set expanded keys | string\[] | - |
|
||||||
| treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | 'value' |
|
| treeNodeFilterProp | Will be used for filtering if `filterTreeNode` returns true | string | 'value' |
|
||||||
| treeNodeLabelProp | Will render as content of select | string | 'title' |
|
| treeNodeLabelProp | Will render as content of select | string | 'title' |
|
||||||
| value(v-model) | To set the current selected treeNode(s). | string\|string\[] | - |
|
| value(v-model) | To set the current selected treeNode(s). | string\|string\[] | - |
|
||||||
| suffixIcon | The custom suffix icon | VNode \| slot | - |
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
| Events Name | Description | Arguments |
|
| Events Name | Description | Arguments |
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
| change | A callback function, can be executed when selected treeNodes or input value change | function(value, label, extra) |
|
| change | A callback function, can be executed when selected treeNodes or input value change | function(value, label, extra) |
|
||||||
| search | A callback function, can be executed when the search input changes. | function(value: string) |
|
| search | A callback function, can be executed when the search input changes. | function(value: string) |
|
||||||
| select | A callback function, can be executed when you select a treeNode. | function(value, node, extra) |
|
| select | A callback function, can be executed when you select a treeNode. | function(value, node, extra) |
|
||||||
|
| treeExpand | A callback function, can be executed when treeNode expanded | function(expandedKeys) |
|
||||||
|
|
||||||
### Tree Methods
|
### Tree Methods
|
||||||
|
|
||||||
|
@ -52,6 +54,7 @@
|
||||||
|
|
||||||
| Property | Description | Type | Default |
|
| Property | Description | Type | Default |
|
||||||
| -------- | ----------- | ---- | ------- |
|
| -------- | ----------- | ---- | ------- |
|
||||||
|
| selectable | can be selected | boolean | true |
|
||||||
| disableCheckbox | Disables the checkbox of the treeNode | boolean | false |
|
| disableCheckbox | Disables the checkbox of the treeNode | boolean | false |
|
||||||
| disabled | Disabled or not | boolean | false |
|
| disabled | Disabled or not | boolean | false |
|
||||||
| isLeaf | Leaf node or not | boolean | false |
|
| isLeaf | Leaf node or not | boolean | false |
|
||||||
|
|
|
@ -136,10 +136,12 @@ const TreeSelect = {
|
||||||
dropdownStyle: { maxHeight: '100vh', overflow: 'auto', ...dropdownStyle },
|
dropdownStyle: { maxHeight: '100vh', overflow: 'auto', ...dropdownStyle },
|
||||||
treeCheckable: checkable,
|
treeCheckable: checkable,
|
||||||
notFoundContent: notFoundContent || locale.notFoundContent,
|
notFoundContent: notFoundContent || locale.notFoundContent,
|
||||||
|
__propsSymbol__: Symbol(),
|
||||||
},
|
},
|
||||||
class: cls,
|
class: cls,
|
||||||
on: { ...this.$listeners, change: this.onChange },
|
on: { ...this.$listeners, change: this.onChange },
|
||||||
ref: 'vcTreeSelect',
|
ref: 'vcTreeSelect',
|
||||||
|
scopedSlots: this.$scopedSlots,
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<VcTreeSelect {...VcTreeSelectProps}>{filterEmpty(this.$slots.default)}</VcTreeSelect>
|
<VcTreeSelect {...VcTreeSelectProps}>{filterEmpty(this.$slots.default)}</VcTreeSelect>
|
||||||
|
|
|
@ -21,24 +21,26 @@
|
||||||
| showCheckedStrategy | 定义选中项回填的方式。`TreeSelect.SHOW_ALL`: 显示所有选中节点(包括父节点). `TreeSelect.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时). 默认只显示子节点. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD |
|
| showCheckedStrategy | 定义选中项回填的方式。`TreeSelect.SHOW_ALL`: 显示所有选中节点(包括父节点). `TreeSelect.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时). 默认只显示子节点. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD |
|
||||||
| showSearch | 在下拉中显示搜索框(仅在单选模式下生效) | boolean | false |
|
| showSearch | 在下拉中显示搜索框(仅在单选模式下生效) | boolean | false |
|
||||||
| size | 选择框大小,可选 `large` `small` | string | 'default' |
|
| size | 选择框大小,可选 `large` `small` | string | 'default' |
|
||||||
|
| suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - |
|
||||||
| treeCheckable | 显示 checkbox | boolean | false |
|
| treeCheckable | 显示 checkbox | boolean | false |
|
||||||
| treeCheckStrictly | checkable 状态下节点选择完全受控(父子节点选中状态不再关联),会使得 `labelInValue` 强制为 true | boolean | false |
|
| treeCheckStrictly | checkable 状态下节点选择完全受控(父子节点选中状态不再关联),会使得 `labelInValue` 强制为 true | boolean | false |
|
||||||
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点(value 在整个树范围内唯一) | array<{value, label, children, [disabled, disableCheckbox, selectable]}> | \[] |
|
| treeData | treeNodes 数据,如果设置则不需要手动构造 TreeNode 节点(value 在整个树范围内唯一) | array<{value, label, children, [disabled, disableCheckbox, selectable]}> | \[] |
|
||||||
| treeDataSimpleMode | 使用简单格式的 treeData,具体设置参考可设置的类型 (此时 treeData 应变为这样的数据结构: [{id:1, pId:0, value:'1', label:"test1",...},...], `pId` 是父节点的 id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
|
| treeDataSimpleMode | 使用简单格式的 treeData,具体设置参考可设置的类型 (此时 treeData 应变为这样的数据结构: [{id:1, pId:0, value:'1', label:"test1",...},...], `pId` 是父节点的 id) | false\|Array<{ id: string, pId: string, rootPId: null }> | false |
|
||||||
| treeDefaultExpandAll | 默认展开所有树节点 | boolean | false |
|
| treeDefaultExpandAll | 默认展开所有树节点 | boolean | false |
|
||||||
| treeDefaultExpandedKeys | 默认展开的树节点 | string\[] | - |
|
| treeDefaultExpandedKeys | 默认展开的树节点 | string\[] | - |
|
||||||
|
| treeExpandedKeys | 设置展开的树节点 | string\[] | - |
|
||||||
| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | 'value' |
|
| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | string | 'value' |
|
||||||
| treeNodeLabelProp | 作为显示的 prop 设置 | string | 'title' |
|
| treeNodeLabelProp | 作为显示的 prop 设置 | string | 'title' |
|
||||||
| value(v-model) | 指定当前选中的条目 | string/string\[] | - |
|
| value(v-model) | 指定当前选中的条目 | string/string\[] | - |
|
||||||
| suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - |
|
|
||||||
|
|
||||||
### 事件
|
### 事件
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 |
|
| 事件名称 | 说明 | 回调参数 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| change | 选中树节点时调用此函数 | function(value, label, extra) | - |
|
| change | 选中树节点时调用此函数 | function(value, label, extra) |
|
||||||
| search | 文本框值变化时回调 | function(value: string) | - |
|
| search | 文本框值变化时回调 | function(value: string) |
|
||||||
| select | 被选中时调用 | function(value, node, extra) | - |
|
| select | 被选中时调用 | function(value, node, extra) |
|
||||||
|
| treeExpand | 展开节点时调用 | function(expandedKeys) |
|
||||||
|
|
||||||
### Tree 方法
|
### Tree 方法
|
||||||
|
|
||||||
|
@ -53,6 +55,7 @@
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| selectable | 是否可选 | boolean | true |
|
||||||
| disableCheckbox | 禁掉 checkbox | boolean | false |
|
| disableCheckbox | 禁掉 checkbox | boolean | false |
|
||||||
| disabled | 是否禁用 | boolean | false |
|
| disabled | 是否禁用 | boolean | false |
|
||||||
| isLeaf | 是否是叶子节点 | boolean | false |
|
| isLeaf | 是否是叶子节点 | boolean | false |
|
||||||
|
|
|
@ -11,6 +11,14 @@ export const TreeData = PropTypes.shape({
|
||||||
|
|
||||||
export const TreeSelectProps = () => ({
|
export const TreeSelectProps = () => ({
|
||||||
...AbstractSelectProps(),
|
...AbstractSelectProps(),
|
||||||
|
autoFocus: PropTypes.bool,
|
||||||
|
dropdownStyle: PropTypes.object,
|
||||||
|
filterTreeNode: PropTypes.oneOfType([Function, Boolean]),
|
||||||
|
getPopupContainer: PropTypes.func,
|
||||||
|
labelInValue: PropTypes.bool,
|
||||||
|
loadData: PropTypes.func,
|
||||||
|
maxTagCount: PropTypes.number,
|
||||||
|
maxTagPlaceholder: PropTypes.any,
|
||||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array]),
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object, PropTypes.array]),
|
||||||
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
||||||
multiple: PropTypes.bool,
|
multiple: PropTypes.bool,
|
||||||
|
@ -18,21 +26,18 @@ export const TreeSelectProps = () => ({
|
||||||
// onChange: (value: any, label: any) => void,
|
// onChange: (value: any, label: any) => void,
|
||||||
// onSearch: (value: any) => void,
|
// onSearch: (value: any) => void,
|
||||||
searchPlaceholder: PropTypes.string,
|
searchPlaceholder: PropTypes.string,
|
||||||
dropdownClassName: PropTypes.string,
|
showCheckedStrategy: PropTypes.oneOf(['SHOW_ALL', 'SHOW_PARENT', 'SHOW_CHILD']),
|
||||||
dropdownStyle: PropTypes.object,
|
suffixIcon: PropTypes.any,
|
||||||
dropdownMatchSelectWidth: PropTypes.bool,
|
|
||||||
treeDefaultExpandAll: PropTypes.bool,
|
|
||||||
treeCheckable: PropTypes.bool,
|
treeCheckable: PropTypes.bool,
|
||||||
treeDefaultExpandedKeys: PropTypes.arrayOf(String),
|
treeCheckStrictly: PropTypes.bool,
|
||||||
filterTreeNode: PropTypes.func,
|
|
||||||
treeNodeFilterProp: PropTypes.string,
|
|
||||||
treeNodeLabelProp: PropTypes.string,
|
|
||||||
treeData: PropTypes.arrayOf(Object),
|
treeData: PropTypes.arrayOf(Object),
|
||||||
treeDataSimpleMode: PropTypes.oneOfType([Boolean, Object]),
|
treeDataSimpleMode: PropTypes.oneOfType([Boolean, Object]),
|
||||||
loadData: PropTypes.func,
|
|
||||||
showCheckedStrategy: PropTypes.oneOf(['SHOW_ALL', 'SHOW_PARENT', 'SHOW_CHILD']),
|
dropdownClassName: PropTypes.string,
|
||||||
labelInValue: PropTypes.bool,
|
dropdownMatchSelectWidth: PropTypes.bool,
|
||||||
treeCheckStrictly: PropTypes.bool,
|
treeDefaultExpandAll: PropTypes.bool,
|
||||||
getPopupContainer: PropTypes.func,
|
treeExpandedKeys: PropTypes.arrayOf(String),
|
||||||
suffixIcon: PropTypes.any,
|
treeDefaultExpandedKeys: PropTypes.arrayOf(String),
|
||||||
|
treeNodeFilterProp: PropTypes.string,
|
||||||
|
treeNodeLabelProp: PropTypes.string,
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,7 +2,7 @@ import warning from 'warning'
|
||||||
import { Tree as VcTree, TreeNode } from '../vc-tree'
|
import { Tree as VcTree, TreeNode } from '../vc-tree'
|
||||||
import animation from '../_util/openAnimation'
|
import animation from '../_util/openAnimation'
|
||||||
import PropTypes from '../_util/vue-types'
|
import PropTypes from '../_util/vue-types'
|
||||||
import { initDefaultProps, getOptionProps } from '../_util/props-util'
|
import { initDefaultProps, getOptionProps, filterEmpty } from '../_util/props-util'
|
||||||
import Icon from '../icon'
|
import Icon from '../icon'
|
||||||
|
|
||||||
function TreeProps () {
|
function TreeProps () {
|
||||||
|
@ -179,7 +179,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
...props,
|
...props,
|
||||||
checkable: checkable ? <span class={`${prefixCls}-checkbox-inner`} /> : checkable,
|
checkable: checkable ? <span class={`${prefixCls}-checkbox-inner`} /> : checkable,
|
||||||
children: this.$slots.default || [],
|
children: filterEmpty(this.$slots.default || []),
|
||||||
__propsSymbol__: Symbol(),
|
__propsSymbol__: Symbol(),
|
||||||
switcherIcon: this.renderSwitcherIcon,
|
switcherIcon: this.renderSwitcherIcon,
|
||||||
},
|
},
|
||||||
|
|
|
@ -107,7 +107,7 @@ const Select = {
|
||||||
this.__propsSymbol__,
|
this.__propsSymbol__,
|
||||||
'Replace slots.default with props.children and pass props.__propsSymbol__'
|
'Replace slots.default with props.children and pass props.__propsSymbol__'
|
||||||
)
|
)
|
||||||
return {
|
const state = {
|
||||||
_value: this.getValueFromProps(props, true), // true: use default value
|
_value: this.getValueFromProps(props, true), // true: use default value
|
||||||
_inputValue: props.combobox ? this.getInputValueForCombobox(
|
_inputValue: props.combobox ? this.getInputValueForCombobox(
|
||||||
props,
|
props,
|
||||||
|
@ -119,10 +119,10 @@ const Select = {
|
||||||
// a flag for aviod redundant getOptionsInfoFromProps call
|
// a flag for aviod redundant getOptionsInfoFromProps call
|
||||||
_skipBuildOptionsInfo: true,
|
_skipBuildOptionsInfo: true,
|
||||||
}
|
}
|
||||||
},
|
return {
|
||||||
beforeMount () {
|
...state,
|
||||||
const state = this.getDerivedStateFromProps(getOptionProps(this), this.$data)
|
...this.getDerivedStateFromProps(props, state),
|
||||||
Object.assign(this.$data, state)
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
top: 1px;
|
top: 1px;
|
||||||
right: 1px;
|
right: 1px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
b {
|
&:after {
|
||||||
|
content: '';
|
||||||
border-color: #999999 transparent transparent transparent;
|
border-color: #999999 transparent transparent transparent;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 5px 4px 0 4px;
|
border-width: 5px 4px 0 4px;
|
||||||
|
@ -66,14 +67,11 @@
|
||||||
&__clear {
|
&__clear {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
||||||
&:after {
|
|
||||||
content: '×'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-enabled &-selection {
|
&-enabled {
|
||||||
|
.@{selectPrefixCls}-selection {
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #23c0fa;
|
border-color: #23c0fa;
|
||||||
box-shadow: 0 0 2px fadeout(#2db7f5, 20%);
|
box-shadow: 0 0 2px fadeout(#2db7f5, 20%);
|
||||||
|
@ -83,6 +81,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.@{selectPrefixCls}-focused {
|
||||||
|
.@{selectPrefixCls}-selection {
|
||||||
|
//border-color: #23c0fa;
|
||||||
|
border-color: #7700fa;
|
||||||
|
box-shadow: 0 0 2px fadeout(#2db7f5, 20%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
&-selection--single {
|
&-selection--single {
|
||||||
height: 28px;
|
height: 28px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -105,6 +114,9 @@
|
||||||
.@{selectPrefixCls}-selection__clear {
|
.@{selectPrefixCls}-selection__clear {
|
||||||
top: 5px;
|
top: 5px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
&:after {
|
||||||
|
content: '×';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +142,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-search__field__placeholder {
|
&-search__field__placeholder {
|
||||||
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 3px;
|
left: 3px;
|
||||||
|
@ -288,6 +301,7 @@
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
transition: opacity .3s, transform .3s;
|
transition: opacity .3s, transform .3s;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: '×'
|
content: '×'
|
||||||
}
|
}
|
||||||
|
@ -487,7 +501,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&-open {
|
&-open {
|
||||||
.@{selectPrefixCls}-arrow b {
|
.@{selectPrefixCls}-arrow:after {
|
||||||
border-color: transparent transparent #888 transparent;
|
border-color: transparent transparent #888 transparent;
|
||||||
border-width: 0 4px 5px 4px;
|
border-width: 0 4px 5px 4px;
|
||||||
}
|
}
|
||||||
|
@ -498,3 +512,25 @@
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-icon-demo {
|
||||||
|
.@{selectPrefixCls} {
|
||||||
|
&-selection__choice__remove {
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-arrow {
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-selection__clear {
|
||||||
|
&:after {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.filter-node {
|
&.filter-node {
|
||||||
> a {
|
> .@{treePrefixCls}-node-content-wrapper {
|
||||||
color: #a60000!important;
|
color: #a60000!important;
|
||||||
font-weight: bold!important;
|
font-weight: bold!important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/* eslint react/no-multi-comp:0, no-console:0, no-alert: 0 */
|
/* eslint react/no-multi-comp:0, no-console:0, no-alert: 0 */
|
||||||
|
import BaseMixin from '../../_util/BaseMixin'
|
||||||
import '../assets/index.less'
|
import '../assets/index.less'
|
||||||
import './demo.less'
|
|
||||||
|
|
||||||
import '../../vc-dialog/assets/index.less'
|
import '../../vc-dialog/assets/index.less'
|
||||||
import Dialog from '../../vc-dialog'
|
import Dialog from '../../vc-dialog'
|
||||||
import TreeSelect, { TreeNode, SHOW_PARENT } from '../index'
|
import TreeSelect, { TreeNode, SHOW_PARENT } from '../src/index'
|
||||||
import { gData } from './util'
|
import { gData } from './util'
|
||||||
|
import './demo.less'
|
||||||
|
|
||||||
function isLeaf (value) {
|
function isLeaf (value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
|
@ -51,18 +50,19 @@ function findPath (value, data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
mixins: [BaseMixin],
|
||||||
return {
|
data: () => ({
|
||||||
tsOpen: false,
|
tsOpen: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
inputValue: '0-0-0-label',
|
searchValue: '0-0-0-label',
|
||||||
value: '0-0-0-value1',
|
value: '0-0-0-value1',
|
||||||
// value: ['0-0-0-0-value', '0-0-0-1-value', '0-0-0-2-value'],
|
// value: ['0-0-0-0-value', '0-0-0-1-value', '0-0-0-2-value'],
|
||||||
lv: { value: '0-0-0-value', label: 'spe label' },
|
lv: { value: '0-0-0-value', label: 'spe label' },
|
||||||
multipleValue: [],
|
multipleValue: [],
|
||||||
|
simpleSearchValue: 'test111',
|
||||||
simpleTreeData: [
|
simpleTreeData: [
|
||||||
{ key: 1, pId: 0, label: 'test1', value: 'test1' },
|
{ key: 1, pId: 0, label: 'test1', value: 'test1' },
|
||||||
{ key: 121, pId: 0, label: 'test1', value: 'test121' },
|
{ key: 121, pId: 0, label: 'test2', value: 'test2' },
|
||||||
{ key: 11, pId: 1, label: 'test11', value: 'test11' },
|
{ key: 11, pId: 1, label: 'test11', value: 'test11' },
|
||||||
{ key: 12, pId: 1, label: 'test12', value: 'test12' },
|
{ key: 12, pId: 1, label: 'test12', value: 'test12' },
|
||||||
{ key: 111, pId: 11, label: 'test111', value: 'test111' },
|
{ key: 111, pId: 11, label: 'test111', value: 'test111' },
|
||||||
|
@ -71,69 +71,69 @@ export default {
|
||||||
id: 'key',
|
id: 'key',
|
||||||
rootPId: 0,
|
rootPId: 0,
|
||||||
},
|
},
|
||||||
}
|
}),
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
// console.log(this.refs.mul.getInputDOMNode());
|
|
||||||
// this.refs.mul.getInputDOMNode().setAttribute('disabled', true);
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
onClick () {
|
onClick () {
|
||||||
this.visible = true
|
this.setState({
|
||||||
|
visible: true,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onClose () {
|
onClose () {
|
||||||
this.visible = false
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearch (value) {
|
onSearch (value) {
|
||||||
console.log(value, arguments)
|
console.log('Do Search:', value, arguments)
|
||||||
|
this.setState({ searchValue: value })
|
||||||
},
|
},
|
||||||
|
|
||||||
onChange (value) {
|
onChange (value, ...rest) {
|
||||||
console.log('onChange', arguments)
|
console.log('onChange', value, ...rest)
|
||||||
this.value = value
|
this.setState({ value })
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangeChildren (value) {
|
onChangeChildren (...args) {
|
||||||
console.log('onChangeChildren', arguments)
|
console.log('onChangeChildren', ...args)
|
||||||
|
const value = args[0]
|
||||||
const pre = value ? this.value : undefined
|
const pre = value ? this.value : undefined
|
||||||
this.value = isLeaf(value) ? value : pre
|
this.setState({ value: isLeaf(value) ? value : pre })
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangeLV (value) {
|
onChangeLV (value) {
|
||||||
console.log('labelInValue', arguments)
|
console.log('labelInValue', arguments)
|
||||||
if (!value) {
|
if (!value) {
|
||||||
this.lv = undefined
|
this.setState({ lv: undefined })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const path = findPath(value.value, gData).map(i => i.label).reverse().join(' > ')
|
const path = findPath(value.value, gData).map(i => i.label).reverse().join(' > ')
|
||||||
this.lv = { value: value.value, label: path }
|
this.setState({ lv: { value: value.value, label: path }})
|
||||||
},
|
},
|
||||||
|
|
||||||
onMultipleChange (value) {
|
onMultipleChange (value) {
|
||||||
console.log('onMultipleChange', arguments)
|
console.log('onMultipleChange', arguments)
|
||||||
this.multipleValue = value
|
this.setState({ multipleValue: value })
|
||||||
},
|
},
|
||||||
|
|
||||||
onSelect () {
|
onSelect () {
|
||||||
// use onChange instead
|
// use onChange instead
|
||||||
console.log(...arguments)
|
console.log(arguments)
|
||||||
},
|
},
|
||||||
|
|
||||||
onDropdownVisibleChange (visible, info) {
|
onDropdownVisibleChange (visible, info) {
|
||||||
console.log(visible, this.value, info)
|
console.log(visible, this.value, info)
|
||||||
if (Array.isArray(this.value) && this.value.length > 1 &&
|
if (Array.isArray(this.value) && this.value.length > 1 &&
|
||||||
this.value.length < 3) {
|
this.value.length < 3) {
|
||||||
alert('please select more than two item or less than one item.')
|
window.alert('please select more than two item or less than one item.')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
filterTreeNode (input, child) {
|
filterTreeNode (input, child) {
|
||||||
return String(child.title).indexOf(input) === 0
|
return String(child.data.props.title).indexOf(input) === 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -167,10 +167,10 @@ export default {
|
||||||
onSearch={this.onSearch}
|
onSearch={this.onSearch}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Dialog> : null}
|
</Dialog> : null}
|
||||||
|
|
||||||
<h2>single select</h2>
|
<h2>single select</h2>
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
style={{ width: '300px' }}
|
style={{ width: '300px' }}
|
||||||
|
@ -180,31 +180,35 @@ export default {
|
||||||
placeholder={<i>请下拉选择</i>}
|
placeholder={<i>请下拉选择</i>}
|
||||||
searchPlaceholder='please search'
|
searchPlaceholder='please search'
|
||||||
showSearch allowClear treeLine
|
showSearch allowClear treeLine
|
||||||
inputValue={this.inputValue}
|
searchValue={this.searchValue}
|
||||||
value={this.value}
|
value={this.value}
|
||||||
treeData={gData}
|
treeData={gData}
|
||||||
treeNodeFilterProp='label'
|
treeNodeFilterProp='label'
|
||||||
filterTreeNode={false}
|
filterTreeNode={false}
|
||||||
onSearch={this.onSearch}
|
onSearch={this.onSearch}
|
||||||
open={this.tsOpen}
|
open={this.tsOpen}
|
||||||
onChange={(value) => {
|
onChange={(value, ...args) => {
|
||||||
console.log('onChange', value, arguments)
|
console.log('onChange', value, ...args)
|
||||||
if (value === '0-0-0-0-value') {
|
if (value === '0-0-0-0-value') {
|
||||||
this.tsOpen = true
|
this.setState({ tsOpen: true })
|
||||||
} else {
|
} else {
|
||||||
this.tsOpen = false
|
this.setState({ tsOpen: false })
|
||||||
}
|
}
|
||||||
this.value = value
|
this.setState({ value })
|
||||||
} }
|
} }
|
||||||
dropdownVisibleChange={(v, info) => {
|
dropdownVisibleChange={(v, info) => {
|
||||||
console.log('single dropdownVisibleChange', v, info)
|
console.log('single onDropdownVisibleChange', v, info)
|
||||||
// document clicked
|
// document clicked
|
||||||
if (info.documentClickClose && this.value === '0-0-0-0-value') {
|
if (info.documentClickClose && this.value === '0-0-0-0-value') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
this.setState({
|
||||||
|
tsOpen: v,
|
||||||
|
})
|
||||||
return true
|
return true
|
||||||
} }
|
} }
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>single select (just select children)</h2>
|
<h2>single select (just select children)</h2>
|
||||||
|
@ -221,10 +225,11 @@ export default {
|
||||||
treeNodeFilterProp='label'
|
treeNodeFilterProp='label'
|
||||||
filterTreeNode={false}
|
filterTreeNode={false}
|
||||||
onChange={this.onChangeChildren}
|
onChange={this.onChangeChildren}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>multiple select</h2>
|
<h2>multiple select</h2>
|
||||||
<TreeSelect ref='mul'
|
<TreeSelect
|
||||||
style={{ width: '300px' }}
|
style={{ width: '300px' }}
|
||||||
transitionName='rc-tree-select-dropdown-slide-up'
|
transitionName='rc-tree-select-dropdown-slide-up'
|
||||||
choiceTransitionName='rc-tree-select-selection__choice-zoom'
|
choiceTransitionName='rc-tree-select-selection__choice-zoom'
|
||||||
|
@ -238,6 +243,7 @@ export default {
|
||||||
onChange={this.onMultipleChange}
|
onChange={this.onMultipleChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
allowClear
|
allowClear
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>check select</h2>
|
<h2>check select</h2>
|
||||||
|
@ -247,17 +253,23 @@ export default {
|
||||||
choiceTransitionName='rc-tree-select-selection__choice-zoom'
|
choiceTransitionName='rc-tree-select-selection__choice-zoom'
|
||||||
dropdownStyle={{ height: '200px', overflow: 'auto' }}
|
dropdownStyle={{ height: '200px', overflow: 'auto' }}
|
||||||
dropdownPopupAlign={{ overflow: { adjustY: 0, adjustX: 0 }, offset: [0, 2] }}
|
dropdownPopupAlign={{ overflow: { adjustY: 0, adjustX: 0 }, offset: [0, 2] }}
|
||||||
onDropdownVisibleChange={this.onDropdownVisibleChange}
|
dropdownVisibleChange={this.onDropdownVisibleChange}
|
||||||
placeholder={<i>请下拉选择</i>}
|
placeholder={<i>请下拉选择</i>}
|
||||||
searchPlaceholder='please search'
|
searchPlaceholder='please search'
|
||||||
treeLine maxTagTextLength={10}
|
treeLine maxTagTextLength={10}
|
||||||
value={this.value}
|
value={this.value}
|
||||||
inputValue={null}
|
autoClearSearchValue
|
||||||
treeData={gData}
|
treeData={gData}
|
||||||
treeNodeFilterProp='title'
|
treeNodeFilterProp='title'
|
||||||
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
maxTagCount={2}
|
||||||
|
maxTagPlaceholder={(valueList) => {
|
||||||
|
console.log('Max Tag Rest Value:', valueList)
|
||||||
|
return `${valueList.length} rest...`
|
||||||
|
}}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>labelInValue & show path</h2>
|
<h2>labelInValue & show path</h2>
|
||||||
|
@ -274,6 +286,7 @@ export default {
|
||||||
treeNodeFilterProp='label'
|
treeNodeFilterProp='label'
|
||||||
filterTreeNode={false}
|
filterTreeNode={false}
|
||||||
onChange={this.onChangeLV}
|
onChange={this.onChangeLV}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>use treeDataSimpleMode</h2>
|
<h2>use treeDataSimpleMode</h2>
|
||||||
|
@ -283,7 +296,10 @@ export default {
|
||||||
placeholder={<i>请下拉选择</i>}
|
placeholder={<i>请下拉选择</i>}
|
||||||
searchPlaceholder='please search'
|
searchPlaceholder='please search'
|
||||||
treeLine maxTagTextLength={10}
|
treeLine maxTagTextLength={10}
|
||||||
inputValue={'test111'}
|
searchValue={this.simpleSearchValue}
|
||||||
|
onSearch={(simpleSearchValue) => {
|
||||||
|
this.setState({ simpleSearchValue })
|
||||||
|
}}
|
||||||
value={this.value}
|
value={this.value}
|
||||||
treeData={this.simpleTreeData}
|
treeData={this.simpleTreeData}
|
||||||
treeNodeFilterProp='title'
|
treeNodeFilterProp='title'
|
||||||
|
@ -291,13 +307,14 @@ export default {
|
||||||
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>Testing in extreme conditions (Boundary conditions test) </h2>
|
<h2>Testing in extreme conditions (Boundary conditions test) </h2>
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
style={{ width: '200px' }}
|
style={{ width: '200px' }}
|
||||||
dropdownStyle={{ maxHeight: '200px', overflow: 'auto' }}
|
dropdownStyle={{ maxHeight: '200px', overflow: 'auto' }}
|
||||||
defaultValue={'leaf1'} multiple treeCheckable showCheckedStrategy={SHOW_PARENT}
|
defaultValue='leaf1' multiple treeCheckable showCheckedStrategy={SHOW_PARENT}
|
||||||
treeDefaultExpandAll
|
treeDefaultExpandAll
|
||||||
treeData={[
|
treeData={[
|
||||||
{ key: '', value: '', label: 'empty value', children: [] },
|
{ key: '', value: '', label: 'empty value', children: [] },
|
||||||
|
@ -308,18 +325,20 @@ export default {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onChange={(val) => console.log(val, arguments)}
|
onChange={(val, ...args) => console.log(val, ...args)}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>use TreeNode Component (not recommend)</h2>
|
<h2>use TreeNode Component (not recommend)</h2>
|
||||||
<TreeSelect
|
<TreeSelect
|
||||||
style={{ width: '200px' }}
|
style={{ width: '200px' }}
|
||||||
dropdownStyle={{ maxHeight: '200px', overflow: 'auto' }}
|
dropdownStyle={{ maxHeight: '200px', overflow: 'auto' }}
|
||||||
defaultValue={'leaf1'}
|
defaultValue='leaf1'
|
||||||
treeDefaultExpandAll
|
treeDefaultExpandAll
|
||||||
treeNodeFilterProp='title'
|
treeNodeFilterProp='title'
|
||||||
filterTreeNode={this.filterTreeNode}
|
filterTreeNode={this.filterTreeNode}
|
||||||
onChange={(val) => console.log(val, arguments)}
|
onChange={(val, ...args) => console.log(val, ...args)}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
>
|
>
|
||||||
<TreeNode value='' title='parent 1' key=''>
|
<TreeNode value='' title='parent 1' key=''>
|
||||||
<TreeNode value='parent 1-0' title='parent 1-0' key='0-1-0'>
|
<TreeNode value='parent 1-0' title='parent 1-0' key='0-1-0'>
|
||||||
|
@ -331,7 +350,7 @@ export default {
|
||||||
title={<span style={{ color: 'red' }}>sss</span>} key='random3'
|
title={<span style={{ color: 'red' }}>sss</span>} key='random3'
|
||||||
/>
|
/>
|
||||||
<TreeNode value='same value1' title='same txtle' key='0-1-1-1'>
|
<TreeNode value='same value1' title='same txtle' key='0-1-1-1'>
|
||||||
<TreeNode value='same value10' title='same titlexd' key='0-1-1-1-0' />
|
<TreeNode value='same value10' title='same titlexd' key='0-1-1-1-0' style={{ color: 'red', background: 'green' }} />
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
</TreeNode>
|
</TreeNode>
|
||||||
|
|
|
@ -56,6 +56,7 @@ export default {
|
||||||
treeCheckable
|
treeCheckable
|
||||||
showCheckedStrategy={SHOW_PARENT}
|
showCheckedStrategy={SHOW_PARENT}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -70,6 +71,7 @@ export default {
|
||||||
treeCheckStrictly
|
treeCheckStrictly
|
||||||
showCheckedStrategy={SHOW_PARENT}
|
showCheckedStrategy={SHOW_PARENT}
|
||||||
onChange={this.onChangeStrictly}
|
onChange={this.onChangeStrictly}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* eslint react/no-multi-comp:0, no-console:0, no-alert: 0 */
|
||||||
|
|
||||||
|
import BaseMixin from '../../_util/BaseMixin'
|
||||||
|
import '../assets/index.less'
|
||||||
|
import '../../vc-dialog/assets/index.less'
|
||||||
|
import TreeSelect, { TreeNode } from '../src/index'
|
||||||
|
import './demo.less'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
data: () => ({
|
||||||
|
treeExpandedKeys: [],
|
||||||
|
}),
|
||||||
|
methods: {
|
||||||
|
onTreeExpand (treeExpandedKeys) {
|
||||||
|
this.setState({
|
||||||
|
treeExpandedKeys,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
setTreeExpandedKeys () {
|
||||||
|
this.setState({
|
||||||
|
treeExpandedKeys: ['000', '0-1-0'],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { treeExpandedKeys } = this
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Conrolled treeExpandedKeys</h2>
|
||||||
|
<TreeSelect
|
||||||
|
style={{ width: '200px' }}
|
||||||
|
dropdownStyle={{ maxHeight: '200px', overflow: 'auto' }}
|
||||||
|
treeExpandedKeys={treeExpandedKeys}
|
||||||
|
onTreeExpand={this.onTreeExpand}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
|
>
|
||||||
|
<TreeNode value='' title='parent 1' key='000'>
|
||||||
|
<TreeNode value='parent 1-0' title='parent 1-0' key='0-1-0'>
|
||||||
|
<TreeNode value='leaf1' title='my leaf' key='random' />
|
||||||
|
<TreeNode value='leaf2' title='your leaf' key='random1' disabled />
|
||||||
|
</TreeNode>
|
||||||
|
<TreeNode value='parent 1-1' title='parent 1-1' key='0-1-1'>
|
||||||
|
<TreeNode value='sss'
|
||||||
|
title={<span style={{ color: 'red' }}>sss</span>} key='random3'
|
||||||
|
/>
|
||||||
|
<TreeNode value='same value1' title='same txtle' key='0-1-1-1'>
|
||||||
|
<TreeNode value='same value10' title='same titlexd' key='0-1-1-1-0' style={{ color: 'red', background: 'green' }} />
|
||||||
|
</TreeNode>
|
||||||
|
</TreeNode>
|
||||||
|
</TreeNode>
|
||||||
|
<TreeNode value='same value2' title='same title' key='0-2'>
|
||||||
|
<TreeNode value='2same value' title='2same title' key='0-2-0' />
|
||||||
|
</TreeNode>
|
||||||
|
<TreeNode value='same value3' title='same title' key='0-3' />
|
||||||
|
</TreeSelect>
|
||||||
|
<button onClick={this.setTreeExpandedKeys}>
|
||||||
|
Set treeExpandedKeys
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/* eslint react/no-multi-comp:0, no-console:0, no-alert: 0 */
|
||||||
|
|
||||||
|
import '../assets/index.less'
|
||||||
|
import '../../vc-dialog/assets/index.less'
|
||||||
|
import TreeSelect from '../src/index'
|
||||||
|
import { gData } from './util'
|
||||||
|
import './demo.less'
|
||||||
|
|
||||||
|
const bubblePath = 'M632 888H392c-4.4 0-8 3.6-8 8v32c0 ' +
|
||||||
|
'17.7 14.3 32 32 32h192c17.7 0 32-14.3 32-32v-3' +
|
||||||
|
'2c0-4.4-3.6-8-8-8zM512 64c-181.1 0-328 146.9-3' +
|
||||||
|
'28 328 0 121.4 66 227.4 164 284.1V792c0 17.7 1' +
|
||||||
|
'4.3 32 32 32h264c17.7 0 32-14.3 32-32V676.1c98' +
|
||||||
|
'-56.7 164-162.7 164-284.1 0-181.1-146.9-328-32' +
|
||||||
|
'8-328z m127.9 549.8L604 634.6V752H420V634.6l-3' +
|
||||||
|
'5.9-20.8C305.4 568.3 256 484.5 256 392c0-141.4' +
|
||||||
|
' 114.6-256 256-256s256 114.6 256 256c0 92.5-49' +
|
||||||
|
'.4 176.3-128.1 221.8z'
|
||||||
|
|
||||||
|
const clearPath = 'M793 242H366v-74c0-6.7-7.7-10.4-12.9' +
|
||||||
|
'-6.3l-142 112c-4.1 3.2-4.1 9.4 0 12.6l142 112c' +
|
||||||
|
'5.2 4.1 12.9 0.4 12.9-6.3v-74h415v470H175c-4.4' +
|
||||||
|
' 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h618c35.3 0 64-' +
|
||||||
|
'28.7 64-64V306c0-35.3-28.7-64-64-64z'
|
||||||
|
|
||||||
|
const arrowPath = 'M765.7 486.8L314.9 134.7c-5.3-4.1' +
|
||||||
|
'-12.9-0.4-12.9 6.3v77.3c0 4.9 2.3 9.6 6.1 12.6l36' +
|
||||||
|
'0 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6' +
|
||||||
|
'.7 7.7 10.4 12.9 6.3l450.8-352.1c16.4-12.8 16.4-3' +
|
||||||
|
'7.6 0-50.4z'
|
||||||
|
|
||||||
|
const getSvg = (h, path, iStyle = {}, style = {}) => {
|
||||||
|
return (
|
||||||
|
<i style={iStyle}>
|
||||||
|
<svg
|
||||||
|
viewBox='0 0 1024 1024'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
style={{ verticalAlign: '-.125em', ...style }}
|
||||||
|
>
|
||||||
|
<path d={path} />
|
||||||
|
</svg>
|
||||||
|
</i>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
const h = this.$createElement
|
||||||
|
const switcherIcon = (obj) => {
|
||||||
|
if (obj.isLeaf) {
|
||||||
|
return getSvg(h, arrowPath,
|
||||||
|
{ cursor: 'pointer', backgroundColor: 'white' },
|
||||||
|
{ transform: 'rotate(270deg)' })
|
||||||
|
}
|
||||||
|
return getSvg(h, arrowPath,
|
||||||
|
{ cursor: 'pointer', backgroundColor: 'white' },
|
||||||
|
{ transform: `rotate(${obj.expanded ? 90 : 0}deg)` })
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputIcon = getSvg(h, bubblePath)
|
||||||
|
const clearIcon = getSvg(h, clearPath)
|
||||||
|
const removeIcon = getSvg(h, clearPath)
|
||||||
|
return {
|
||||||
|
iconProps: {
|
||||||
|
inputIcon,
|
||||||
|
clearIcon,
|
||||||
|
removeIcon,
|
||||||
|
switcherIcon,
|
||||||
|
},
|
||||||
|
|
||||||
|
iconPropsFunction: {
|
||||||
|
inputIcon: () => inputIcon,
|
||||||
|
clearIcon: () => clearIcon,
|
||||||
|
removeIcon: () => removeIcon,
|
||||||
|
switcherIcon,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div class='custom-icon-demo'>
|
||||||
|
<h2>Single</h2>
|
||||||
|
<TreeSelect
|
||||||
|
treeData={gData}
|
||||||
|
placeholder={<span>Please Select</span>}
|
||||||
|
transitionName='rc-tree-select-dropdown-slide-up'
|
||||||
|
style={{ width: '300px' }}
|
||||||
|
dropdownStyle={{ maxHeight: '200px', overflow: 'auto', zIndex: 1500 }}
|
||||||
|
showSearch allowClear
|
||||||
|
{...{ props: { ...this.iconProps }}}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<h2>Multiple</h2>
|
||||||
|
<TreeSelect
|
||||||
|
treeData={gData}
|
||||||
|
multiple
|
||||||
|
placeholder={<span>Please Select</span>}
|
||||||
|
transitionName='rc-tree-select-dropdown-slide-up'
|
||||||
|
style={{ width: '300px' }}
|
||||||
|
dropdownStyle={{ maxHeight: '200px', overflow: 'auto', zIndex: 1500 }}
|
||||||
|
showSearch allowClear
|
||||||
|
{...{ props: { ...this.iconPropsFunction }}}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
.rc-tree-select-selection--multiple {
|
.rc-tree-select-selection--multiple {
|
||||||
max-height: 50px;
|
max-height: 50px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* eslint react/no-multi-comp:0, no-console:0 */
|
/* eslint react/no-multi-comp:0, no-console:0 */
|
||||||
|
import BaseMixin from '../../_util/BaseMixin'
|
||||||
import '../assets/index.less'
|
import '../assets/index.less'
|
||||||
import TreeSelect from '../index'
|
import TreeSelect from '../src/index'
|
||||||
|
|
||||||
const SHOW_PARENT = TreeSelect.SHOW_PARENT
|
const SHOW_PARENT = TreeSelect.SHOW_PARENT
|
||||||
|
|
||||||
|
@ -33,20 +34,18 @@ const treeData = [{
|
||||||
}]
|
}]
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
mixins: [BaseMixin],
|
||||||
return {
|
data: () => ({
|
||||||
value: ['0-0-0'],
|
value: ['0-0-0'],
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}),
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onChange (value) {
|
onChange (value) {
|
||||||
console.log('onChange ', value, arguments)
|
console.log('onChange ', value, arguments)
|
||||||
this.value = value
|
this.setState({ value })
|
||||||
},
|
},
|
||||||
switch (checked) {
|
switch (checked) {
|
||||||
this.disabled = checked
|
this.setState({ disabled: checked })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -61,6 +60,7 @@ export default {
|
||||||
treeCheckable: true,
|
treeCheckable: true,
|
||||||
showCheckedStrategy: SHOW_PARENT,
|
showCheckedStrategy: SHOW_PARENT,
|
||||||
searchPlaceholder: 'Please select',
|
searchPlaceholder: 'Please select',
|
||||||
|
__propsSymbol__: Symbol(),
|
||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
change: this.onChange,
|
change: this.onChange,
|
||||||
|
@ -77,4 +77,3 @@ export default {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
/* eslint react/no-multi-comp:0, no-console:0 */
|
/* eslint react/no-multi-comp:0, no-console:0 */
|
||||||
|
|
||||||
|
import BaseMixin from '../../_util/BaseMixin'
|
||||||
import '../assets/index.less'
|
import '../assets/index.less'
|
||||||
import TreeSelect from '../index'
|
import TreeSelect from '../src/index'
|
||||||
import { getNewTreeData, generateTreeNodes } from './util'
|
import { getNewTreeData, generateTreeNodes } from './util'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data () {
|
mixins: [BaseMixin],
|
||||||
return {
|
data: () => ({
|
||||||
treeData: [
|
treeData: [
|
||||||
{ label: 'pNode 01', value: '0-0', key: '0-0' },
|
{ label: 'pNode 01', value: '0-0', key: '0-0' },
|
||||||
{ label: 'pNode 02', value: '0-1', key: '0-1' },
|
{ label: 'pNode 02', value: '0-1', key: '0-1' },
|
||||||
|
@ -14,13 +15,13 @@ export default {
|
||||||
],
|
],
|
||||||
// value: '0-0',
|
// value: '0-0',
|
||||||
value: { value: '0-0-0-value', label: '0-0-0-label' },
|
value: { value: '0-0-0-value', label: '0-0-0-label' },
|
||||||
}
|
}),
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onChange (value) {
|
onChange (value) {
|
||||||
console.log(value)
|
console.log(value)
|
||||||
this.value = value
|
this.setState({
|
||||||
|
value,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
onLoadData (treeNode) {
|
onLoadData (treeNode) {
|
||||||
|
@ -29,7 +30,7 @@ export default {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const treeData = [...this.treeData]
|
const treeData = [...this.treeData]
|
||||||
getNewTreeData(treeData, treeNode.eventKey, generateTreeNodes(treeNode), 2)
|
getNewTreeData(treeData, treeNode.eventKey, generateTreeNodes(treeNode), 2)
|
||||||
this.treeData = treeData
|
this.setState({ treeData })
|
||||||
resolve()
|
resolve()
|
||||||
}, 500)
|
}, 500)
|
||||||
})
|
})
|
||||||
|
@ -47,9 +48,9 @@ export default {
|
||||||
value={this.value}
|
value={this.value}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
loadData={this.onLoadData}
|
loadData={this.onLoadData}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ export default {
|
||||||
treeCheckable
|
treeCheckable
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<h2>use treeDataSimpleMode</h2>
|
<h2>use treeDataSimpleMode</h2>
|
||||||
|
@ -89,6 +90,7 @@ export default {
|
||||||
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
treeCheckable showCheckedStrategy={SHOW_PARENT}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSelect={this.onSelect}
|
onSelect={this.onSelect}
|
||||||
|
__propsSymbol__={Symbol()}
|
||||||
/>
|
/>
|
||||||
<button onClick={this.onDataChange}>change data</button>
|
<button onClick={this.onDataChange}>change data</button>
|
||||||
</div>
|
</div>
|
|
@ -25,7 +25,7 @@ const TreeSelectInput = {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<TreeSelect {...{ props: this.$props }} onChange={this.onChange.bind(this)} />
|
<TreeSelect {...{ props: this.$props }} onChange={this.onChange} />
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,7 @@ const Form = {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
treeData: gData,
|
treeData: gData,
|
||||||
treeCheckable: true,
|
treeCheckable: true,
|
||||||
|
__propsSymbol__: Symbol(),
|
||||||
// treeDefaultExpandAll: true,
|
// treeDefaultExpandAll: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,15 @@ export function generateData (x = 3, y = 2, z = 1, gData = []) {
|
||||||
tns[index].children = []
|
tns[index].children = []
|
||||||
return _loop(__level, key, tns[index].children)
|
return _loop(__level, key, tns[index].children)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
_loop(z)
|
_loop(z)
|
||||||
return gData
|
return gData
|
||||||
}
|
}
|
||||||
export function calcTotal (x = 3, y = 2, z = 1) {
|
export function calcTotal (x = 3, y = 2, z = 1) {
|
||||||
/* eslint no-param-reassign:0 */
|
/* eslint no-param-reassign:0 */
|
||||||
const rec = (n) => n >= 0 ? x * Math.pow(y, n--) + rec(n) : 0
|
const rec = (n) => n >= 0 ? x * (y ** (n--)) + rec(n) : 0
|
||||||
return rec(z + 1)
|
return rec(z + 1)
|
||||||
}
|
}
|
||||||
console.log('总节点数(单个tree):', calcTotal())
|
console.log('总节点数(单个tree):', calcTotal())
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
// rc-tree-select 1.12.13 tag
|
|
||||||
// export this package's api
|
// export this package's api
|
||||||
|
// base 2.4.4
|
||||||
|
import Vue from 'vue'
|
||||||
import TreeSelect from './src'
|
import TreeSelect from './src'
|
||||||
|
import ref from 'vue-ref'
|
||||||
|
|
||||||
|
Vue.use(ref, { name: 'ant-ref' })
|
||||||
export default TreeSelect
|
export default TreeSelect
|
||||||
|
|
||||||
export { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './src'
|
export { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './src'
|
||||||
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
import warning from 'warning'
|
||||||
|
import PropTypes from '../../../_util/vue-types'
|
||||||
|
import { Tree } from '../../../vc-tree'
|
||||||
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
|
|
||||||
|
// export const popupContextTypes = {
|
||||||
|
// onPopupKeyDown: PropTypes.func.isRequired,
|
||||||
|
// onTreeNodeSelect: PropTypes.func.isRequired,
|
||||||
|
// onTreeNodeCheck: PropTypes.func.isRequired,
|
||||||
|
// }
|
||||||
|
function getDerivedStateFromProps (nextProps, prevState) {
|
||||||
|
const { _prevProps: prevProps = {},
|
||||||
|
_loadedKeys: loadedKeys,
|
||||||
|
_expandedKeyList: expandedKeyList,
|
||||||
|
_cachedExpandedKeyList: cachedExpandedKeyList,
|
||||||
|
} = prevState || {}
|
||||||
|
const {
|
||||||
|
valueList, valueEntities, keyEntities,
|
||||||
|
treeExpandedKeys, filteredTreeNodes, searchValue,
|
||||||
|
} = nextProps
|
||||||
|
|
||||||
|
const newState = {
|
||||||
|
_prevProps: { ...nextProps },
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check value update
|
||||||
|
if (valueList !== prevProps.valueList) {
|
||||||
|
newState._keyList = valueList
|
||||||
|
.map(({ value }) => valueEntities[value])
|
||||||
|
.filter(entity => entity)
|
||||||
|
.map(({ key }) => key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show all when tree is in filter mode
|
||||||
|
if (
|
||||||
|
!treeExpandedKeys &&
|
||||||
|
filteredTreeNodes &&
|
||||||
|
filteredTreeNodes.length &&
|
||||||
|
filteredTreeNodes !== prevProps.filteredTreeNodes
|
||||||
|
) {
|
||||||
|
newState._expandedKeyList = Object.keys(keyEntities)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache `expandedKeyList` when filter set
|
||||||
|
if (searchValue && !prevProps.searchValue) {
|
||||||
|
newState._cachedExpandedKeyList = expandedKeyList
|
||||||
|
} else if (!searchValue && prevProps.searchValue && !treeExpandedKeys) {
|
||||||
|
newState._expandedKeyList = cachedExpandedKeyList || []
|
||||||
|
newState._cachedExpandedKeyList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use expandedKeys if provided
|
||||||
|
if (prevProps.treeExpandedKeys !== treeExpandedKeys) {
|
||||||
|
newState._expandedKeyList = treeExpandedKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean loadedKeys if key not exist in keyEntities anymore
|
||||||
|
if (nextProps.loadData) {
|
||||||
|
newState._loadedKeys = loadedKeys.filter(key => key in keyEntities)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
const BasePopup = {
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
name: 'BasePopup',
|
||||||
|
props: {
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
upperSearchValue: PropTypes.string,
|
||||||
|
valueList: PropTypes.array,
|
||||||
|
searchHalfCheckedKeys: PropTypes.array,
|
||||||
|
valueEntities: PropTypes.object,
|
||||||
|
keyEntities: PropTypes.object,
|
||||||
|
treeIcon: PropTypes.bool,
|
||||||
|
treeLine: PropTypes.bool,
|
||||||
|
treeNodeFilterProp: PropTypes.string,
|
||||||
|
treeCheckable: PropTypes.any,
|
||||||
|
treeCheckStrictly: PropTypes.bool,
|
||||||
|
treeDefaultExpandAll: PropTypes.bool,
|
||||||
|
treeDefaultExpandedKeys: PropTypes.array,
|
||||||
|
treeExpandedKeys: PropTypes.array,
|
||||||
|
loadData: PropTypes.func,
|
||||||
|
multiple: PropTypes.bool,
|
||||||
|
// onTreeExpand: PropTypes.func,
|
||||||
|
searchValue: PropTypes.string,
|
||||||
|
treeNodes: PropTypes.any,
|
||||||
|
filteredTreeNodes: PropTypes.any,
|
||||||
|
notFoundContent: PropTypes.string,
|
||||||
|
|
||||||
|
ariaId: PropTypes.string,
|
||||||
|
switcherIcon: PropTypes.any,
|
||||||
|
// HOC
|
||||||
|
renderSearch: PropTypes.func,
|
||||||
|
// onTreeExpanded: PropTypes.func,
|
||||||
|
|
||||||
|
__propsSymbol__: PropTypes.any,
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
vcTreeSelect: { default: {}},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
__propsSymbol__ () {
|
||||||
|
const state = getDerivedStateFromProps(this.$props, this.$data)
|
||||||
|
this.setState(state)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
warning(this.$props.__propsSymbol__, 'must pass __propsSymbol__')
|
||||||
|
const {
|
||||||
|
treeDefaultExpandAll, treeDefaultExpandedKeys,
|
||||||
|
keyEntities,
|
||||||
|
} = this.$props
|
||||||
|
|
||||||
|
// TODO: make `expandedKeyList` control
|
||||||
|
let expandedKeyList = treeDefaultExpandedKeys
|
||||||
|
if (treeDefaultExpandAll) {
|
||||||
|
expandedKeyList = Object.keys(keyEntities)
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
_keyList: [],
|
||||||
|
_expandedKeyList: expandedKeyList,
|
||||||
|
// Cache `expandedKeyList` when tree is in filter. This is used in `getDerivedStateFromProps`
|
||||||
|
_cachedExpandedKeyList: [], // eslint-disable-line react/no-unused-state
|
||||||
|
_loadedKeys: [],
|
||||||
|
_prevProps: {},
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
...getDerivedStateFromProps(this.$props, state),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onTreeExpand (expandedKeyList) {
|
||||||
|
const { treeExpandedKeys } = this.$props
|
||||||
|
|
||||||
|
// Set uncontrolled state
|
||||||
|
if (!treeExpandedKeys) {
|
||||||
|
this.setState({ _expandedKeyList: expandedKeyList }, () => {
|
||||||
|
this.__emit('treeExpanded')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.__emit('treeExpand', expandedKeyList)
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoad (loadedKeys) {
|
||||||
|
this.setState({ _loadedKeys: loadedKeys })
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not pass `loadData` when searching. To avoid loop ajax call makes browser crash.
|
||||||
|
*/
|
||||||
|
getLoadData () {
|
||||||
|
const { loadData, searchValue } = this.$props
|
||||||
|
if (searchValue) return null
|
||||||
|
return loadData
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method pass to Tree component which is used for add filtered class
|
||||||
|
* in TreeNode > li
|
||||||
|
*/
|
||||||
|
filterTreeNode (treeNode) {
|
||||||
|
const { upperSearchValue, treeNodeFilterProp } = this.$props
|
||||||
|
|
||||||
|
const filterVal = treeNode[treeNodeFilterProp]
|
||||||
|
if (typeof filterVal === 'string') {
|
||||||
|
return upperSearchValue && (filterVal).toUpperCase().indexOf(upperSearchValue) !== -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
renderNotFound () {
|
||||||
|
const { prefixCls, notFoundContent } = this.$props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span class={`${prefixCls}-not-found`}>
|
||||||
|
{notFoundContent}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { _keyList: keyList, _expandedKeyList: expandedKeyList, _loadedKeys: loadedKeys } = this.$data
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
treeNodes, filteredTreeNodes,
|
||||||
|
treeIcon, treeLine, treeCheckable, treeCheckStrictly, multiple,
|
||||||
|
ariaId,
|
||||||
|
renderSearch,
|
||||||
|
switcherIcon,
|
||||||
|
searchHalfCheckedKeys,
|
||||||
|
} = this.$props
|
||||||
|
const { vcTreeSelect: {
|
||||||
|
onPopupKeyDown,
|
||||||
|
onTreeNodeSelect,
|
||||||
|
onTreeNodeCheck,
|
||||||
|
}} = this
|
||||||
|
|
||||||
|
const loadData = this.getLoadData()
|
||||||
|
|
||||||
|
const treeProps = {}
|
||||||
|
|
||||||
|
if (treeCheckable) {
|
||||||
|
treeProps.checkedKeys = keyList
|
||||||
|
} else {
|
||||||
|
treeProps.selectedKeys = keyList
|
||||||
|
}
|
||||||
|
let $notFound
|
||||||
|
let $treeNodes
|
||||||
|
if (filteredTreeNodes) {
|
||||||
|
if (filteredTreeNodes.length) {
|
||||||
|
treeProps.checkStrictly = true
|
||||||
|
$treeNodes = filteredTreeNodes
|
||||||
|
|
||||||
|
// Fill halfCheckedKeys
|
||||||
|
if (treeCheckable && !treeCheckStrictly) {
|
||||||
|
treeProps.checkedKeys = {
|
||||||
|
checked: keyList,
|
||||||
|
halfChecked: searchHalfCheckedKeys,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$notFound = this.renderNotFound()
|
||||||
|
}
|
||||||
|
} else if (!treeNodes.length) {
|
||||||
|
$notFound = this.renderNotFound()
|
||||||
|
} else {
|
||||||
|
$treeNodes = treeNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
let $tree
|
||||||
|
if ($notFound) {
|
||||||
|
$tree = $notFound
|
||||||
|
} else {
|
||||||
|
const treeAllProps = {
|
||||||
|
props: {
|
||||||
|
prefixCls: `${prefixCls}-tree`,
|
||||||
|
showIcon: treeIcon,
|
||||||
|
showLine: treeLine,
|
||||||
|
selectable: !treeCheckable,
|
||||||
|
checkable: treeCheckable,
|
||||||
|
checkStrictly: treeCheckStrictly,
|
||||||
|
multiple: multiple,
|
||||||
|
loadData: loadData,
|
||||||
|
loadedKeys: loadedKeys,
|
||||||
|
expandedKeys: expandedKeyList,
|
||||||
|
filterTreeNode: this.filterTreeNode,
|
||||||
|
switcherIcon: switcherIcon,
|
||||||
|
...treeProps,
|
||||||
|
__propsSymbol__: Symbol(),
|
||||||
|
children: $treeNodes,
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
select: onTreeNodeSelect,
|
||||||
|
check: onTreeNodeCheck,
|
||||||
|
expand: this.onTreeExpand,
|
||||||
|
load: this.onLoad,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
$tree = (
|
||||||
|
<Tree
|
||||||
|
{...treeAllProps}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role='listbox'
|
||||||
|
id={ariaId}
|
||||||
|
onKeydown={onPopupKeyDown}
|
||||||
|
tabIndex={-1}
|
||||||
|
>
|
||||||
|
{renderSearch ? renderSearch() : null}
|
||||||
|
{$tree}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BasePopup
|
|
@ -0,0 +1,187 @@
|
||||||
|
/**
|
||||||
|
* Input Box is in different position for different mode.
|
||||||
|
* This not the same design as `Select` cause it's followed by antd 0.x `Select`.
|
||||||
|
* We will not follow the new design immediately since antd 3.x is already released.
|
||||||
|
*
|
||||||
|
* So this file named as Selector to avoid confuse.
|
||||||
|
*/
|
||||||
|
import { createRef } from '../util'
|
||||||
|
import PropTypes from '../../../_util/vue-types'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { initDefaultProps, getComponentFromProp } from '../../../_util/props-util'
|
||||||
|
import BaseMixin from '../../../_util/BaseMixin'
|
||||||
|
export const selectorPropTypes = () => ({
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
className: PropTypes.string,
|
||||||
|
open: PropTypes.bool,
|
||||||
|
valueList: PropTypes.array, // Name as valueList to diff the single value
|
||||||
|
allowClear: PropTypes.bool,
|
||||||
|
showArrow: PropTypes.bool,
|
||||||
|
// onClick: PropTypes.func,
|
||||||
|
// onBlur: PropTypes.func,
|
||||||
|
// onFocus: PropTypes.func,
|
||||||
|
removeSelected: PropTypes.func,
|
||||||
|
choiceTransitionName: PropTypes.string,
|
||||||
|
// Pass by component
|
||||||
|
ariaId: PropTypes.string,
|
||||||
|
inputIcon: PropTypes.any,
|
||||||
|
clearIcon: PropTypes.any,
|
||||||
|
removeIcon: PropTypes.any,
|
||||||
|
selectorValueList: PropTypes.array,
|
||||||
|
placeholder: PropTypes.any,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
focused: PropTypes.bool,
|
||||||
|
})
|
||||||
|
|
||||||
|
function noop () {}
|
||||||
|
export default function (modeName) {
|
||||||
|
const BaseSelector = {
|
||||||
|
name: 'BaseSelector',
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
props: initDefaultProps({
|
||||||
|
...selectorPropTypes(),
|
||||||
|
|
||||||
|
// Pass by HOC
|
||||||
|
renderSelection: PropTypes.func.isRequired,
|
||||||
|
renderPlaceholder: PropTypes.func,
|
||||||
|
tabIndex: PropTypes.number,
|
||||||
|
}, {
|
||||||
|
tabIndex: 0,
|
||||||
|
}),
|
||||||
|
inject: {
|
||||||
|
vcTreeSelect: { default: {}},
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.domRef = createRef()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFocus (e) {
|
||||||
|
const { focused } = this.$props
|
||||||
|
const { vcTreeSelect: { onSelectorFocus }} = this
|
||||||
|
|
||||||
|
if (!focused) {
|
||||||
|
onSelectorFocus()
|
||||||
|
}
|
||||||
|
this.__emit('focus', e)
|
||||||
|
},
|
||||||
|
|
||||||
|
onBlur (e) {
|
||||||
|
const { vcTreeSelect: { onSelectorBlur }} = this
|
||||||
|
|
||||||
|
// TODO: Not trigger when is inner component get focused
|
||||||
|
onSelectorBlur()
|
||||||
|
this.__emit('blur', e)
|
||||||
|
},
|
||||||
|
|
||||||
|
focus () {
|
||||||
|
this.domRef.current.focus()
|
||||||
|
},
|
||||||
|
|
||||||
|
blur () {
|
||||||
|
this.domRef.current.blur()
|
||||||
|
},
|
||||||
|
|
||||||
|
renderClear () {
|
||||||
|
const { prefixCls, allowClear, valueList } = this.$props
|
||||||
|
const { vcTreeSelect: { onSelectorClear }} = this
|
||||||
|
|
||||||
|
if (!allowClear || !valueList.length || !valueList[0].value) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const clearIcon = getComponentFromProp(this, 'clearIcon')
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key='clear'
|
||||||
|
class={`${prefixCls}-selection__clear`}
|
||||||
|
onClick={onSelectorClear}
|
||||||
|
>
|
||||||
|
{clearIcon}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
renderArrow () {
|
||||||
|
const { prefixCls, showArrow } = this.$props
|
||||||
|
if (!showArrow) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const inputIcon = getComponentFromProp(this, 'inputIcon')
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
key='arrow'
|
||||||
|
class={`${prefixCls}-arrow`}
|
||||||
|
style={{ outline: 'none' }}
|
||||||
|
>
|
||||||
|
{inputIcon}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
prefixCls, className, style,
|
||||||
|
open, focused, disabled, allowClear,
|
||||||
|
ariaId,
|
||||||
|
renderSelection, renderPlaceholder,
|
||||||
|
tabIndex,
|
||||||
|
} = this.$props
|
||||||
|
const { vcTreeSelect: { onSelectorKeyDown }, $listeners } = this
|
||||||
|
|
||||||
|
let myTabIndex = tabIndex
|
||||||
|
if (disabled) {
|
||||||
|
myTabIndex = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={style}
|
||||||
|
onClick={$listeners.click || noop}
|
||||||
|
class={classNames(
|
||||||
|
className,
|
||||||
|
prefixCls,
|
||||||
|
{
|
||||||
|
[`${prefixCls}-open`]: open,
|
||||||
|
[`${prefixCls}-focused`]: open || focused,
|
||||||
|
[`${prefixCls}-disabled`]: disabled,
|
||||||
|
[`${prefixCls}-enabled`]: !disabled,
|
||||||
|
[`${prefixCls}-allow-clear`]: allowClear,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
{...{
|
||||||
|
directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.domRef,
|
||||||
|
}],
|
||||||
|
}}
|
||||||
|
role='combobox'
|
||||||
|
aria-expanded={open}
|
||||||
|
aria-owns={open ? ariaId : undefined}
|
||||||
|
aria-controls={open ? ariaId : undefined}
|
||||||
|
aria-haspopup='listbox'
|
||||||
|
aria-disabled={disabled}
|
||||||
|
tabIndex={myTabIndex}
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
onKeydown={onSelectorKeyDown}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
key='selection'
|
||||||
|
class={classNames(
|
||||||
|
`${prefixCls}-selection`,
|
||||||
|
`${prefixCls}-selection--${modeName}`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{renderSelection()}
|
||||||
|
{this.renderClear()}
|
||||||
|
{this.renderArrow()}
|
||||||
|
|
||||||
|
{renderPlaceholder && renderPlaceholder()}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return BaseSelector
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
import BasePopup from '../Base/BasePopup'
|
||||||
|
|
||||||
|
export default BasePopup
|
|
@ -0,0 +1,80 @@
|
||||||
|
import PropTypes from '../../../_util/vue-types'
|
||||||
|
import BasePopup from '../Base/BasePopup'
|
||||||
|
import SearchInput from '../SearchInput'
|
||||||
|
import { createRef } from '../util'
|
||||||
|
|
||||||
|
const SinglePopup = {
|
||||||
|
name: 'SinglePopup',
|
||||||
|
props: {
|
||||||
|
...BasePopup.props,
|
||||||
|
...SearchInput.props,
|
||||||
|
searchValue: PropTypes.string,
|
||||||
|
showSearch: PropTypes.bool,
|
||||||
|
dropdownPrefixCls: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
searchPlaceholder: PropTypes.string,
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.inputRef = createRef()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPlaceholderClick () {
|
||||||
|
this.inputRef.current.focus()
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderPlaceholder () {
|
||||||
|
const { searchPlaceholder, searchValue, prefixCls } = this.$props
|
||||||
|
|
||||||
|
if (!searchPlaceholder) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: searchValue ? 'none' : 'block',
|
||||||
|
}}
|
||||||
|
onClick={this.onPlaceholderClick}
|
||||||
|
class={`${prefixCls}-search__field__placeholder`}
|
||||||
|
>
|
||||||
|
{searchPlaceholder}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderSearch () {
|
||||||
|
const { showSearch, dropdownPrefixCls } = this.$props
|
||||||
|
|
||||||
|
if (!showSearch) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span class={`${dropdownPrefixCls}-search`}>
|
||||||
|
<SearchInput
|
||||||
|
{...{
|
||||||
|
props: { ...this.$props, renderPlaceholder: this._renderPlaceholder },
|
||||||
|
on: this.$listeners,
|
||||||
|
directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.inputRef,
|
||||||
|
}],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<BasePopup
|
||||||
|
{...{
|
||||||
|
props: { ...this.$props, renderSearch: this._renderSearch, __propsSymbol__: Symbol() },
|
||||||
|
on: this.$listeners,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SinglePopup
|
|
@ -1,62 +1,46 @@
|
||||||
import PropTypes from '../../_util/vue-types'
|
import PropTypes from '../../_util/vue-types'
|
||||||
import { SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './strategies'
|
import { isLabelInValue } from './util'
|
||||||
|
|
||||||
export const SelectPropTypes = {
|
const internalValProp = PropTypes.oneOfType([
|
||||||
// className: PropTypes.string,
|
PropTypes.string,
|
||||||
prefixCls: PropTypes.string,
|
PropTypes.number,
|
||||||
multiple: PropTypes.bool,
|
])
|
||||||
filterTreeNode: PropTypes.any,
|
|
||||||
showSearch: PropTypes.bool,
|
export function genArrProps (propType) {
|
||||||
disabled: PropTypes.bool,
|
return PropTypes.oneOfType([
|
||||||
showArrow: PropTypes.bool,
|
propType,
|
||||||
allowClear: PropTypes.bool,
|
PropTypes.arrayOf(propType),
|
||||||
defaultOpen: PropTypes.bool,
|
])
|
||||||
open: PropTypes.bool,
|
}
|
||||||
transitionName: PropTypes.string,
|
|
||||||
animation: PropTypes.string,
|
/**
|
||||||
choiceTransitionName: PropTypes.string,
|
* Origin code check `multiple` is true when `treeCheckStrictly` & `labelInValue`.
|
||||||
// onClick: PropTypes.func,
|
* But in process logic is already cover to array.
|
||||||
// onChange: PropTypes.func,
|
* Check array is not necessary. Let's simplify this check logic.
|
||||||
// onSelect: PropTypes.func,
|
*/
|
||||||
// onDeselect: PropTypes.func,
|
export function valueProp (...args) {
|
||||||
// onSearch: PropTypes.func,
|
const [props, propName, Component] = args
|
||||||
searchPlaceholder: PropTypes.string,
|
|
||||||
placeholder: PropTypes.any,
|
if (isLabelInValue(props)) {
|
||||||
inputValue: PropTypes.any,
|
const err = genArrProps(PropTypes.shape({
|
||||||
value: PropTypes.any,
|
label: PropTypes.node,
|
||||||
defaultValue: PropTypes.any,
|
value: internalValProp,
|
||||||
label: PropTypes.any, // vnode
|
}).loose)(...args)
|
||||||
defaultLabel: PropTypes.any,
|
if (err) {
|
||||||
labelInValue: PropTypes.bool,
|
return new Error(
|
||||||
dropdownClassName: PropTypes.string,
|
`Invalid prop \`${propName}\` supplied to \`${Component}\`. ` +
|
||||||
dropdownStyle: PropTypes.object,
|
`You should use { label: string, value: string | number } or [{ label: string, value: string | number }] instead.`
|
||||||
dropdownPopupAlign: PropTypes.object,
|
)
|
||||||
dropdownVisibleChange: PropTypes.func,
|
}
|
||||||
maxTagTextLength: PropTypes.number,
|
return null
|
||||||
showCheckedStrategy: PropTypes.oneOf([
|
}
|
||||||
SHOW_ALL, SHOW_PARENT, SHOW_CHILD,
|
|
||||||
]),
|
const err = genArrProps(internalValProp)(...args)
|
||||||
treeCheckStrictly: PropTypes.bool,
|
if (err) {
|
||||||
treeIcon: PropTypes.bool,
|
return new Error(
|
||||||
treeLine: PropTypes.bool,
|
`Invalid prop \`${propName}\` supplied to \`${Component}\`. ` +
|
||||||
treeDefaultExpandAll: PropTypes.bool,
|
`You should use string or [string] instead.`
|
||||||
treeDefaultExpandedKeys: PropTypes.arrayOf(String),
|
)
|
||||||
treeCheckable: PropTypes.any, // bool vnode
|
}
|
||||||
treeNodeLabelProp: PropTypes.string,
|
return null
|
||||||
treeNodeFilterProp: PropTypes.string,
|
|
||||||
treeData: PropTypes.array,
|
|
||||||
treeDataSimpleMode: PropTypes.oneOfType([
|
|
||||||
PropTypes.bool,
|
|
||||||
PropTypes.object,
|
|
||||||
]),
|
|
||||||
loadData: PropTypes.func,
|
|
||||||
dropdownMatchSelectWidth: PropTypes.bool,
|
|
||||||
notFoundContent: PropTypes.any,
|
|
||||||
children: PropTypes.any,
|
|
||||||
autoFocus: PropTypes.bool,
|
|
||||||
getPopupContainer: PropTypes.func,
|
|
||||||
switcherIcon: PropTypes.func,
|
|
||||||
inputIcon: PropTypes.any,
|
|
||||||
removeIcon: PropTypes.any,
|
|
||||||
clearIcon: PropTypes.any,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,127 @@
|
||||||
|
/**
|
||||||
|
* Since search box is in different position with different mode.
|
||||||
|
* - Single: in the popup box
|
||||||
|
* - multiple: in the selector
|
||||||
|
* Move the code as a SearchInput for easy management.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import PropTypes from '../../_util/vue-types'
|
||||||
|
import { createRef } from './util'
|
||||||
|
|
||||||
|
const SearchInput = {
|
||||||
|
name: 'SearchInput',
|
||||||
|
props: {
|
||||||
|
open: PropTypes.bool,
|
||||||
|
searchValue: PropTypes.string,
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
renderPlaceholder: PropTypes.func,
|
||||||
|
needAlign: PropTypes.bool,
|
||||||
|
ariaId: PropTypes.string,
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
vcTreeSelect: { default: {}},
|
||||||
|
},
|
||||||
|
|
||||||
|
created () {
|
||||||
|
this.inputRef = createRef()
|
||||||
|
this.mirrorInputRef = createRef()
|
||||||
|
this.prevProps = { ...this.$props }
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const { open, needAlign } = this.$props
|
||||||
|
if (needAlign) {
|
||||||
|
this.alignInputWidth()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open) {
|
||||||
|
this.focus(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updated () {
|
||||||
|
const { open, searchValue, needAlign } = this.$props
|
||||||
|
const { prevProps } = this
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (open && prevProps.open !== open) {
|
||||||
|
this.focus()
|
||||||
|
}
|
||||||
|
if (needAlign && searchValue !== prevProps.searchValue) {
|
||||||
|
this.alignInputWidth()
|
||||||
|
}
|
||||||
|
this.prevProps = { ...this.$props }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* `scrollWidth` is not correct in IE, do the workaround.
|
||||||
|
* ref: https://github.com/react-component/tree-select/issues/65
|
||||||
|
* clientWidth 0 when mounted in vue. why?
|
||||||
|
*/
|
||||||
|
alignInputWidth () {
|
||||||
|
this.inputRef.current.style.width =
|
||||||
|
`${this.mirrorInputRef.current.clientWidth || this.mirrorInputRef.current.offsetWidth}px`
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Need additional timeout for focus cause parent dom is not ready when didMount trigger
|
||||||
|
*/
|
||||||
|
focus (isDidMount) {
|
||||||
|
if (this.inputRef.current) {
|
||||||
|
this.inputRef.current.focus()
|
||||||
|
if (isDidMount) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.inputRef.current.focus()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
blur () {
|
||||||
|
if (this.inputRef.current) {
|
||||||
|
this.inputRef.current.blur()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { searchValue, prefixCls, disabled, renderPlaceholder, open, ariaId } = this.$props
|
||||||
|
const { vcTreeSelect: {
|
||||||
|
onSearchInputChange, onSearchInputKeyDown,
|
||||||
|
}} = this
|
||||||
|
return (
|
||||||
|
<span class={`${prefixCls}-search__field__wrap`}>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
{...{ directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.inputRef,
|
||||||
|
}] }}
|
||||||
|
onInput={onSearchInputChange}
|
||||||
|
onKeydown={onSearchInputKeyDown}
|
||||||
|
value={searchValue}
|
||||||
|
disabled={disabled}
|
||||||
|
class={`${prefixCls}-search__field`}
|
||||||
|
aria-label='filter select'
|
||||||
|
aria-autocomplete='list'
|
||||||
|
aria-controls={open ? ariaId : undefined}
|
||||||
|
aria-multiline='false'
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
{...{ directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.mirrorInputRef,
|
||||||
|
}] }}
|
||||||
|
class={`${prefixCls}-search__field__mirror`}
|
||||||
|
>
|
||||||
|
{searchValue}
|
||||||
|
</span>
|
||||||
|
{renderPlaceholder ? renderPlaceholder() : null}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchInput
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,28 @@
|
||||||
|
import { TreeNode } from '../../vc-tree'
|
||||||
|
/**
|
||||||
|
* SelectNode wrapped the tree node.
|
||||||
|
* Let's use SelectNode instead of TreeNode
|
||||||
|
* since TreeNode is so confuse here.
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
functional: true,
|
||||||
|
name: 'SelectNode',
|
||||||
|
isTreeNode: true,
|
||||||
|
props: TreeNode.props,
|
||||||
|
render (h, context) {
|
||||||
|
const { props, slots, listeners, data } = context
|
||||||
|
const $slots = slots()
|
||||||
|
const children = $slots.default
|
||||||
|
delete $slots.default
|
||||||
|
const treeNodeProps = {
|
||||||
|
...data, on: { ...listeners, ...data.nativeOn }, props,
|
||||||
|
}
|
||||||
|
const slotsKey = Object.keys($slots)
|
||||||
|
return <TreeNode {...treeNodeProps}>
|
||||||
|
{children}
|
||||||
|
{slotsKey.length ? slotsKey.map(name => {
|
||||||
|
return <template slot={name}>{$slots[name]}</template>
|
||||||
|
}) : null}
|
||||||
|
</TreeNode>
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,18 +1,8 @@
|
||||||
import PropTypes from '../../_util/vue-types'
|
import PropTypes from '../../_util/vue-types'
|
||||||
import classnames from 'classnames'
|
|
||||||
import Trigger from '../../vc-trigger'
|
|
||||||
import Tree, { TreeNode } from '../../vc-tree'
|
|
||||||
import { SelectPropTypes } from './PropTypes'
|
|
||||||
import BaseMixin from '../../_util/BaseMixin'
|
|
||||||
import {
|
|
||||||
loopAllChildren,
|
|
||||||
flatToHierarchy,
|
|
||||||
getValuePropValue,
|
|
||||||
labelCompatible,
|
|
||||||
} from './util'
|
|
||||||
|
|
||||||
import { cloneElement } from '../../_util/vnode'
|
import Trigger from '../../vc-trigger'
|
||||||
import { getSlotOptions, getKey, getAllProps, getComponentFromProp } from '../../_util/props-util'
|
import { createRef } from './util'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
const BUILT_IN_PLACEMENTS = {
|
const BUILT_IN_PLACEMENTS = {
|
||||||
bottomLeft: {
|
bottomLeft: {
|
||||||
|
@ -22,6 +12,7 @@ const BUILT_IN_PLACEMENTS = {
|
||||||
adjustX: 0,
|
adjustX: 0,
|
||||||
adjustY: 1,
|
adjustY: 1,
|
||||||
},
|
},
|
||||||
|
ignoreShake: true,
|
||||||
},
|
},
|
||||||
topLeft: {
|
topLeft: {
|
||||||
points: ['bl', 'tl'],
|
points: ['bl', 'tl'],
|
||||||
|
@ -30,335 +21,94 @@ const BUILT_IN_PLACEMENTS = {
|
||||||
adjustX: 0,
|
adjustX: 0,
|
||||||
adjustY: 1,
|
adjustY: 1,
|
||||||
},
|
},
|
||||||
|
ignoreShake: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const SelectTrigger = {
|
const SelectTrigger = {
|
||||||
mixins: [BaseMixin],
|
|
||||||
name: 'SelectTrigger',
|
name: 'SelectTrigger',
|
||||||
props: {
|
props: {
|
||||||
...SelectPropTypes,
|
// Pass by outside user props
|
||||||
dropdownMatchSelectWidth: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
dropdownPopupAlign: PropTypes.object,
|
showSearch: PropTypes.bool,
|
||||||
visible: PropTypes.bool,
|
|
||||||
filterTreeNode: PropTypes.any,
|
|
||||||
treeNodes: PropTypes.any,
|
|
||||||
inputValue: PropTypes.string,
|
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
popupClassName: PropTypes.string,
|
dropdownPopupAlign: PropTypes.object,
|
||||||
_cachetreeData: PropTypes.any,
|
dropdownClassName: PropTypes.string,
|
||||||
_treeNodesStates: PropTypes.any,
|
dropdownStyle: PropTypes.object,
|
||||||
halfCheckedValues: PropTypes.any,
|
transitionName: PropTypes.string,
|
||||||
inputElement: PropTypes.any,
|
animation: PropTypes.string,
|
||||||
},
|
getPopupContainer: PropTypes.func,
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
sExpandedKeys: [],
|
|
||||||
fireOnExpand: false,
|
|
||||||
dropdownWidth: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
dropdownMatchSelectWidth: PropTypes.bool,
|
||||||
this.$nextTick(() => {
|
|
||||||
this.setDropdownWidth()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
inputValue (val) {
|
|
||||||
// set autoExpandParent to true
|
|
||||||
this.setState({
|
|
||||||
sExpandedKeys: [],
|
|
||||||
fireOnExpand: false,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
updated () {
|
// Pass by Select
|
||||||
this.$nextTick(() => {
|
isMultiple: PropTypes.bool,
|
||||||
this.setDropdownWidth()
|
dropdownPrefixCls: PropTypes.string,
|
||||||
})
|
dropdownVisibleChange: PropTypes.func,
|
||||||
|
popupElement: PropTypes.node,
|
||||||
|
open: PropTypes.bool,
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.triggerRef = createRef()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onExpand (expandedKeys) {
|
|
||||||
// rerender
|
|
||||||
this.setState({
|
|
||||||
sExpandedKeys: expandedKeys,
|
|
||||||
fireOnExpand: true,
|
|
||||||
}, () => {
|
|
||||||
// Fix https://github.com/ant-design/ant-design/issues/5689
|
|
||||||
if (this.$refs.trigger && this.$refs.trigger.forcePopupAlign) {
|
|
||||||
this.$refs.trigger.forcePopupAlign()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
setDropdownWidth () {
|
|
||||||
const width = this.$el.offsetWidth
|
|
||||||
if (width !== this.dropdownWidth) {
|
|
||||||
this.setState({ dropdownWidth: width })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getPopupEleRefs () {
|
|
||||||
return this.$refs.popupEle
|
|
||||||
},
|
|
||||||
|
|
||||||
getPopupDOMNode () {
|
|
||||||
return this.$refs.trigger.getPopupDomNode()
|
|
||||||
},
|
|
||||||
|
|
||||||
getDropdownTransitionName () {
|
getDropdownTransitionName () {
|
||||||
const props = this.$props
|
const { transitionName, animation, dropdownPrefixCls } = this.$props
|
||||||
let transitionName = props.transitionName
|
if (!transitionName && animation) {
|
||||||
if (!transitionName && props.animation) {
|
return `${dropdownPrefixCls}-${animation}`
|
||||||
transitionName = `${this.getDropdownPrefixCls()}-${props.animation}`
|
|
||||||
}
|
}
|
||||||
return transitionName
|
return transitionName
|
||||||
},
|
},
|
||||||
|
|
||||||
getDropdownPrefixCls () {
|
forcePopupAlign () {
|
||||||
return `${this.prefixCls}-dropdown`
|
const $trigger = this.triggerRef.current
|
||||||
},
|
if ($trigger) {
|
||||||
|
$trigger.forcePopupAlign()
|
||||||
highlightTreeNode (treeNode) {
|
|
||||||
const props = this.$props
|
|
||||||
const filterVal = treeNode.$props[labelCompatible(props.treeNodeFilterProp)]
|
|
||||||
if (typeof filterVal === 'string') {
|
|
||||||
return props.inputValue && filterVal.indexOf(props.inputValue) > -1
|
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
},
|
|
||||||
|
|
||||||
filterTreeNode_ (input, child) {
|
|
||||||
if (!input) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
const filterTreeNode = this.filterTreeNode
|
|
||||||
if (!filterTreeNode) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
const props = getAllProps(child)
|
|
||||||
if (props && props.disabled) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return filterTreeNode.call(this, input, child)
|
|
||||||
},
|
|
||||||
|
|
||||||
processTreeNode (treeNodes) {
|
|
||||||
const filterPoss = []
|
|
||||||
this._expandedKeys = []
|
|
||||||
loopAllChildren(treeNodes, (child, index, pos) => {
|
|
||||||
if (this.filterTreeNode_(this.inputValue, child)) {
|
|
||||||
filterPoss.push(pos)
|
|
||||||
this._expandedKeys.push(String(getKey(child)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Include the filtered nodes's ancestral nodes.
|
|
||||||
const processedPoss = []
|
|
||||||
filterPoss.forEach(pos => {
|
|
||||||
const arr = pos.split('-')
|
|
||||||
arr.reduce((pre, cur) => {
|
|
||||||
const res = `${pre}-${cur}`
|
|
||||||
if (processedPoss.indexOf(res) < 0) {
|
|
||||||
processedPoss.push(res)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
})
|
|
||||||
})
|
|
||||||
const filterNodesPositions = []
|
|
||||||
loopAllChildren(treeNodes, (child, index, pos) => {
|
|
||||||
if (processedPoss.indexOf(pos) > -1) {
|
|
||||||
filterNodesPositions.push({ node: child, pos })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const hierarchyNodes = flatToHierarchy(filterNodesPositions)
|
|
||||||
|
|
||||||
const recursive = children => {
|
|
||||||
return children.map(child => {
|
|
||||||
if (child.children) {
|
|
||||||
return cloneElement(child.node, {
|
|
||||||
children: recursive(child.children),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return child.node
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return recursive(hierarchyNodes)
|
|
||||||
},
|
|
||||||
onSelect () {
|
|
||||||
this.__emit('select', ...arguments)
|
|
||||||
},
|
|
||||||
|
|
||||||
renderTree (keys, halfCheckedKeys, newTreeNodes, multiple) {
|
|
||||||
const props = this.$props
|
|
||||||
|
|
||||||
const trProps = {
|
|
||||||
multiple,
|
|
||||||
prefixCls: `${props.prefixCls}-tree`,
|
|
||||||
showIcon: props.treeIcon,
|
|
||||||
showLine: props.treeLine,
|
|
||||||
defaultExpandAll: props.treeDefaultExpandAll,
|
|
||||||
defaultExpandedKeys: props.treeDefaultExpandedKeys,
|
|
||||||
filterTreeNode: this.highlightTreeNode,
|
|
||||||
}
|
|
||||||
const trListeners = {}
|
|
||||||
|
|
||||||
if (props.treeCheckable) {
|
|
||||||
trProps.selectable = false
|
|
||||||
trProps.checkable = props.treeCheckable
|
|
||||||
trListeners.check = this.onSelect
|
|
||||||
trProps.checkStrictly = props.treeCheckStrictly
|
|
||||||
if (props.inputValue) {
|
|
||||||
// enable checkStrictly when search tree.
|
|
||||||
trProps.checkStrictly = true
|
|
||||||
} else {
|
|
||||||
trProps._treeNodesStates = props._treeNodesStates
|
|
||||||
}
|
|
||||||
if (trProps.treeCheckStrictly && halfCheckedKeys.length) {
|
|
||||||
trProps.checkedKeys = { checked: keys, halfChecked: halfCheckedKeys }
|
|
||||||
} else {
|
|
||||||
trProps.checkedKeys = keys
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trProps.selectedKeys = keys
|
|
||||||
trListeners.select = this.onSelect
|
|
||||||
}
|
|
||||||
|
|
||||||
// expand keys
|
|
||||||
if (!trProps.defaultExpandAll && !trProps.defaultExpandedKeys && !props.loadData) {
|
|
||||||
trProps.expandedKeys = keys
|
|
||||||
}
|
|
||||||
trProps.autoExpandParent = true
|
|
||||||
trListeners.expand = this.onExpand
|
|
||||||
if (this._expandedKeys && this._expandedKeys.length) {
|
|
||||||
trProps.expandedKeys = this._expandedKeys
|
|
||||||
}
|
|
||||||
if (this.fireOnExpand) {
|
|
||||||
trProps.expandedKeys = this.sExpandedKeys
|
|
||||||
trProps.autoExpandParent = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// async loadData
|
|
||||||
if (props.loadData) {
|
|
||||||
trProps.loadData = props.loadData
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Tree ref='popupEle' {...{ props: trProps, on: trListeners }}>
|
|
||||||
{newTreeNodes}
|
|
||||||
</Tree>
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const props = this.$props
|
const {
|
||||||
const multiple = props.multiple
|
disabled, isMultiple,
|
||||||
const dropdownPrefixCls = this.getDropdownPrefixCls()
|
dropdownPopupAlign, dropdownMatchSelectWidth, dropdownClassName,
|
||||||
const popupClassName = {
|
dropdownStyle, dropdownVisibleChange, getPopupContainer,
|
||||||
[props.dropdownClassName]: !!props.dropdownClassName,
|
dropdownPrefixCls, popupElement, open,
|
||||||
[`${dropdownPrefixCls}--${multiple ? 'multiple' : 'single'}`]: 1,
|
} = this.$props
|
||||||
}
|
|
||||||
let visible = props.visible
|
|
||||||
const search = multiple || !props.showSearch ? null : (
|
|
||||||
<span class={`${dropdownPrefixCls}-search`}>{props.inputElement}</span>
|
|
||||||
)
|
|
||||||
const recursive = children => {
|
|
||||||
return children.map(function handler(child) { // eslint-disable-line
|
|
||||||
// if (isEmptyElement(child) || (child.data && child.data.slot)) {
|
|
||||||
// return null
|
|
||||||
// }
|
|
||||||
if (!getSlotOptions(child).__ANT_TREE_SELECT_NODE) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const treeNodeProps = {
|
|
||||||
...child.data,
|
|
||||||
props: {
|
|
||||||
...getAllProps(child),
|
|
||||||
switcherIcon: props.switcherIcon,
|
|
||||||
title: getComponentFromProp(child, 'title') || getComponentFromProp(child, 'label'),
|
|
||||||
},
|
|
||||||
key: String(child.key),
|
|
||||||
}
|
|
||||||
if (child && child.componentOptions.children) {
|
|
||||||
// null or String has no Prop
|
|
||||||
return (
|
|
||||||
<TreeNode {...treeNodeProps}>
|
|
||||||
{recursive(child.componentOptions.children) }
|
|
||||||
</TreeNode>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return <TreeNode {...treeNodeProps} />
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// const s = Date.now();
|
|
||||||
let treeNodes
|
|
||||||
if (props._cachetreeData && this.cacheTreeNodes) {
|
|
||||||
treeNodes = this.cacheTreeNodes
|
|
||||||
} else {
|
|
||||||
treeNodes = recursive(props.treeData || props.treeNodes)
|
|
||||||
this.cacheTreeNodes = treeNodes
|
|
||||||
}
|
|
||||||
// console.log(Date.now()-s);
|
|
||||||
|
|
||||||
if (props.inputValue) {
|
// TODO: [Legacy] Use new action when trigger fixed: https://github.com/react-component/trigger/pull/86
|
||||||
treeNodes = this.processTreeNode(treeNodes)
|
|
||||||
}
|
|
||||||
|
|
||||||
const keys = []
|
// When false do nothing with the width
|
||||||
const halfCheckedKeys = []
|
// ref: https://github.com/ant-design/ant-design/issues/10927
|
||||||
loopAllChildren(treeNodes, (child) => {
|
let stretch
|
||||||
if (props.value.some(item => item.value === getValuePropValue(child))) {
|
if (dropdownMatchSelectWidth !== false) {
|
||||||
keys.push(String(getKey(child)))
|
stretch = dropdownMatchSelectWidth ? 'width' : 'minWidth'
|
||||||
}
|
}
|
||||||
if (props.halfCheckedValues &&
|
|
||||||
props.halfCheckedValues.some(item => item.value === getValuePropValue(child))) {
|
|
||||||
halfCheckedKeys.push(String(getKey(child)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let notFoundContent
|
|
||||||
if (!treeNodes.length) {
|
|
||||||
if (props.notFoundContent) {
|
|
||||||
notFoundContent = (
|
|
||||||
<span class={`${props.prefixCls}-not-found`}>
|
|
||||||
{props.notFoundContent}
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
} else if (!search) {
|
|
||||||
visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const popupElement = (
|
|
||||||
<div>
|
|
||||||
{search}
|
|
||||||
{notFoundContent || this.renderTree(keys, halfCheckedKeys, treeNodes, multiple)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
const popupStyle = { ...props.dropdownStyle }
|
|
||||||
const widthProp = props.dropdownMatchSelectWidth ? 'width' : 'minWidth'
|
|
||||||
if (this.dropdownWidth) {
|
|
||||||
popupStyle[widthProp] = `${this.dropdownWidth}px`
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Trigger
|
<Trigger
|
||||||
action={props.disabled ? [] : ['click']}
|
{...{ directives: [{
|
||||||
ref='trigger'
|
name: 'ant-ref',
|
||||||
|
value: this.triggerRef,
|
||||||
|
}] }}
|
||||||
|
action={disabled ? [] : ['click']}
|
||||||
popupPlacement='bottomLeft'
|
popupPlacement='bottomLeft'
|
||||||
builtinPlacements={BUILT_IN_PLACEMENTS}
|
builtinPlacements={BUILT_IN_PLACEMENTS}
|
||||||
popupAlign={props.dropdownPopupAlign}
|
popupAlign={dropdownPopupAlign}
|
||||||
prefixCls={dropdownPrefixCls}
|
prefixCls={dropdownPrefixCls}
|
||||||
popupTransitionName={this.getDropdownTransitionName()}
|
popupTransitionName={this.getDropdownTransitionName()}
|
||||||
onPopupVisibleChange={props.dropdownVisibleChange}
|
onPopupVisibleChange={dropdownVisibleChange}
|
||||||
popup={popupElement}
|
popup={popupElement}
|
||||||
popupVisible={visible}
|
popupVisible={open}
|
||||||
getPopupContainer={props.getPopupContainer}
|
getPopupContainer={getPopupContainer}
|
||||||
popupClassName={classnames(popupClassName)}
|
stretch={stretch}
|
||||||
popupStyle={popupStyle}
|
popupClassName={classNames(
|
||||||
|
dropdownClassName,
|
||||||
|
{
|
||||||
|
[`${dropdownPrefixCls}--multiple`]: isMultiple,
|
||||||
|
[`${dropdownPrefixCls}--single`]: !isMultiple,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
popupStyle={dropdownStyle}
|
||||||
>
|
>
|
||||||
{this.$slots.default}
|
{this.$slots.default}
|
||||||
</Trigger>
|
</Trigger>
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
import PropTypes from '../../../../_util/vue-types'
|
||||||
|
import {
|
||||||
|
toTitle,
|
||||||
|
UNSELECTABLE_ATTRIBUTE, UNSELECTABLE_STYLE,
|
||||||
|
} from '../../util'
|
||||||
|
import { getComponentFromProp } from '../../../../_util/props-util'
|
||||||
|
import BaseMixin from '../../../../_util/BaseMixin'
|
||||||
|
|
||||||
|
const Selection = {
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
props: {
|
||||||
|
prefixCls: PropTypes.string,
|
||||||
|
maxTagTextLength: PropTypes.number,
|
||||||
|
// onRemove: PropTypes.func,
|
||||||
|
|
||||||
|
label: PropTypes.any,
|
||||||
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
|
removeIcon: PropTypes.any,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onRemove (event) {
|
||||||
|
const { value } = this.$props
|
||||||
|
this.__emit('remove', event, value)
|
||||||
|
event.stopPropagation()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const {
|
||||||
|
prefixCls, maxTagTextLength,
|
||||||
|
label, value,
|
||||||
|
} = this.$props
|
||||||
|
const { $listeners } = this
|
||||||
|
let content = label || value
|
||||||
|
if (maxTagTextLength && typeof content === 'string' && content.length > maxTagTextLength) {
|
||||||
|
content = `${content.slice(0, maxTagTextLength)}...`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
style={UNSELECTABLE_STYLE}
|
||||||
|
{...{ attrs: UNSELECTABLE_ATTRIBUTE }}
|
||||||
|
role='menuitem'
|
||||||
|
class={`${prefixCls}-selection__choice`}
|
||||||
|
title={toTitle(label)}
|
||||||
|
>
|
||||||
|
{$listeners.remove &&
|
||||||
|
<span
|
||||||
|
class={`${prefixCls}-selection__choice__remove`}
|
||||||
|
onClick={this.onRemove}
|
||||||
|
>
|
||||||
|
{getComponentFromProp(this, 'removeIcon')}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
<span class={`${prefixCls}-selection__choice__content`}>
|
||||||
|
{content}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Selection
|
|
@ -0,0 +1,192 @@
|
||||||
|
import PropTypes from '../../../../_util/vue-types'
|
||||||
|
import { createRef } from '../../util'
|
||||||
|
import generateSelector, { selectorPropTypes } from '../../Base/BaseSelector'
|
||||||
|
import SearchInput from '../../SearchInput'
|
||||||
|
import Selection from './Selection'
|
||||||
|
import { getComponentFromProp } from '../../../../_util/props-util'
|
||||||
|
import getTransitionProps from '../../../../_util/getTransitionProps'
|
||||||
|
import BaseMixin from '../../../../_util/BaseMixin'
|
||||||
|
const TREE_SELECT_EMPTY_VALUE_KEY = 'RC_TREE_SELECT_EMPTY_VALUE_KEY'
|
||||||
|
|
||||||
|
const Selector = generateSelector('multiple')
|
||||||
|
|
||||||
|
// export const multipleSelectorContextTypes = {
|
||||||
|
// onMultipleSelectorRemove: PropTypes.func.isRequired,
|
||||||
|
// }
|
||||||
|
|
||||||
|
const MultipleSelector = {
|
||||||
|
mixins: [BaseMixin],
|
||||||
|
props: {
|
||||||
|
...selectorPropTypes(),
|
||||||
|
...SearchInput.props,
|
||||||
|
selectorValueList: PropTypes.array,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
searchValue: PropTypes.string,
|
||||||
|
labelInValue: PropTypes.bool,
|
||||||
|
maxTagCount: PropTypes.number,
|
||||||
|
maxTagPlaceholder: PropTypes.any,
|
||||||
|
|
||||||
|
// onChoiceAnimationLeave: PropTypes.func,
|
||||||
|
},
|
||||||
|
inject: {
|
||||||
|
vcTreeSelect: { default: {}},
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.inputRef = createRef()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPlaceholderClick () {
|
||||||
|
this.inputRef.current.focus()
|
||||||
|
},
|
||||||
|
|
||||||
|
focus () {
|
||||||
|
this.inputRef.current.focus()
|
||||||
|
},
|
||||||
|
blur () {
|
||||||
|
this.inputRef.current.blur()
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderPlaceholder () {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
placeholder, searchPlaceholder,
|
||||||
|
searchValue, selectorValueList,
|
||||||
|
} = this.$props
|
||||||
|
|
||||||
|
const currentPlaceholder = placeholder || searchPlaceholder
|
||||||
|
|
||||||
|
if (!currentPlaceholder) return null
|
||||||
|
|
||||||
|
const hidden = searchValue || selectorValueList.length
|
||||||
|
|
||||||
|
// [Legacy] Not remove the placeholder
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: hidden ? 'none' : 'block',
|
||||||
|
}}
|
||||||
|
onClick={this.onPlaceholderClick}
|
||||||
|
class={`${prefixCls}-search__field__placeholder`}
|
||||||
|
>
|
||||||
|
{currentPlaceholder}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onChoiceAnimationLeave (...args) {
|
||||||
|
this.__emit('choiceAnimationLeave', ...args)
|
||||||
|
},
|
||||||
|
renderSelection () {
|
||||||
|
const {
|
||||||
|
selectorValueList, choiceTransitionName, prefixCls,
|
||||||
|
labelInValue, maxTagCount,
|
||||||
|
} = this.$props
|
||||||
|
const { vcTreeSelect: { onMultipleSelectorRemove }, $listeners, $slots } = this
|
||||||
|
|
||||||
|
// Check if `maxTagCount` is set
|
||||||
|
let myValueList = selectorValueList
|
||||||
|
if (maxTagCount >= 0) {
|
||||||
|
myValueList = selectorValueList.slice(0, maxTagCount)
|
||||||
|
}
|
||||||
|
// Selector node list
|
||||||
|
const selectedValueNodes = myValueList.map(({ label, value }) => (
|
||||||
|
<Selection
|
||||||
|
{...{
|
||||||
|
props: {
|
||||||
|
...this.$props,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
on: { ...$listeners, remove: onMultipleSelectorRemove },
|
||||||
|
}}
|
||||||
|
key={value || TREE_SELECT_EMPTY_VALUE_KEY}
|
||||||
|
>{$slots.default}</Selection>
|
||||||
|
))
|
||||||
|
|
||||||
|
// Rest node count
|
||||||
|
if (maxTagCount >= 0 && maxTagCount < selectorValueList.length) {
|
||||||
|
let content = `+ ${selectorValueList.length - maxTagCount} ...`
|
||||||
|
const maxTagPlaceholder = getComponentFromProp(this, 'maxTagPlaceholder', {}, false)
|
||||||
|
if (typeof maxTagPlaceholder === 'string') {
|
||||||
|
content = maxTagPlaceholder
|
||||||
|
} else if (typeof maxTagPlaceholder === 'function') {
|
||||||
|
const restValueList = selectorValueList.slice(maxTagCount)
|
||||||
|
content = maxTagPlaceholder(
|
||||||
|
labelInValue ? restValueList : restValueList.map(({ value }) => value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const restNodeSelect = (
|
||||||
|
<Selection
|
||||||
|
{...{
|
||||||
|
props: {
|
||||||
|
...this.$props,
|
||||||
|
label: content,
|
||||||
|
value: null,
|
||||||
|
},
|
||||||
|
on: $listeners,
|
||||||
|
}}
|
||||||
|
key='rc-tree-select-internal-max-tag-counter'
|
||||||
|
>{$slots.default}</Selection>
|
||||||
|
)
|
||||||
|
|
||||||
|
selectedValueNodes.push(restNodeSelect)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedValueNodes.push(<li
|
||||||
|
class={`${prefixCls}-search ${prefixCls}-search--inline`}
|
||||||
|
key='__input'
|
||||||
|
>
|
||||||
|
<SearchInput {...{
|
||||||
|
props: {
|
||||||
|
...this.$props,
|
||||||
|
needAlign: true,
|
||||||
|
},
|
||||||
|
on: $listeners,
|
||||||
|
directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.inputRef,
|
||||||
|
}],
|
||||||
|
}}>{$slots.default}</SearchInput>
|
||||||
|
</li>)
|
||||||
|
const className = `${prefixCls}-selection__rendered`
|
||||||
|
if (choiceTransitionName) {
|
||||||
|
const transitionProps = getTransitionProps(choiceTransitionName, {
|
||||||
|
tag: 'ul',
|
||||||
|
afterLeave: this.onChoiceAnimationLeave,
|
||||||
|
})
|
||||||
|
return (<transition-group
|
||||||
|
class={className}
|
||||||
|
{...transitionProps}
|
||||||
|
>
|
||||||
|
{selectedValueNodes}
|
||||||
|
</transition-group>)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ul class={className} role='menubar'>
|
||||||
|
{selectedValueNodes}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { $listeners, $slots } = this
|
||||||
|
return (
|
||||||
|
<Selector
|
||||||
|
{...{
|
||||||
|
props: {
|
||||||
|
...this.$props,
|
||||||
|
tabIndex: -1,
|
||||||
|
showArrow: false,
|
||||||
|
renderSelection: this.renderSelection,
|
||||||
|
renderPlaceholder: this._renderPlaceholder,
|
||||||
|
},
|
||||||
|
on: $listeners,
|
||||||
|
}}
|
||||||
|
|
||||||
|
>{$slots.default}</Selector>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultipleSelector
|
|
@ -0,0 +1,75 @@
|
||||||
|
import generateSelector, { selectorPropTypes } from '../Base/BaseSelector'
|
||||||
|
import { toTitle } from '../util'
|
||||||
|
import { getOptionProps } from '../../../_util/props-util'
|
||||||
|
import { createRef } from '../util'
|
||||||
|
const Selector = generateSelector('single')
|
||||||
|
|
||||||
|
const SingleSelector = {
|
||||||
|
name: 'SingleSelector',
|
||||||
|
props: selectorPropTypes(),
|
||||||
|
created () {
|
||||||
|
this.selectorRef = createRef()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
focus () {
|
||||||
|
this.selectorRef.current.focus()
|
||||||
|
},
|
||||||
|
blur () {
|
||||||
|
this.selectorRef.current.blur()
|
||||||
|
},
|
||||||
|
renderSelection () {
|
||||||
|
const { selectorValueList, placeholder, prefixCls } = this.$props
|
||||||
|
|
||||||
|
let innerNode
|
||||||
|
|
||||||
|
if (selectorValueList.length) {
|
||||||
|
const { label, value } = selectorValueList[0]
|
||||||
|
innerNode = (
|
||||||
|
<span
|
||||||
|
key='value'
|
||||||
|
title={toTitle(label)}
|
||||||
|
class={`${prefixCls}-selection-selected-value`}
|
||||||
|
>
|
||||||
|
{label || value}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
innerNode = (
|
||||||
|
<span
|
||||||
|
key='placeholder'
|
||||||
|
class={`${prefixCls}-selection__placeholder`}
|
||||||
|
>
|
||||||
|
{placeholder}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span class={`${prefixCls}-selection__rendered`}>
|
||||||
|
{innerNode}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const props = {
|
||||||
|
props: {
|
||||||
|
...getOptionProps(this),
|
||||||
|
renderSelection: this.renderSelection,
|
||||||
|
},
|
||||||
|
on: this.$listeners,
|
||||||
|
directives: [{
|
||||||
|
name: 'ant-ref',
|
||||||
|
value: this.selectorRef,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Selector
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleSelector
|
|
@ -1,12 +0,0 @@
|
||||||
import { TreeNode } from '../../vc-tree'
|
|
||||||
export default {
|
|
||||||
name: 'TreeNode',
|
|
||||||
__ANT_TREE_SELECT_NODE: true,
|
|
||||||
props: {
|
|
||||||
...TreeNode.props,
|
|
||||||
value: String,
|
|
||||||
},
|
|
||||||
render () {
|
|
||||||
return this
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,26 +1,7 @@
|
||||||
// export this package's api
|
import Select from './Select'
|
||||||
import TreeSelect from './Select'
|
import SelectNode from './SelectNode'
|
||||||
import TreeNode from './TreeNode'
|
|
||||||
import omit from 'omit.js'
|
|
||||||
import { SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from './strategies'
|
|
||||||
TreeSelect.TreeNode = TreeNode
|
|
||||||
|
|
||||||
export default {
|
export { SHOW_ALL, SHOW_CHILD, SHOW_PARENT } from './strategies'
|
||||||
functional: true,
|
export const TreeNode = SelectNode
|
||||||
render (h, context) {
|
|
||||||
const { props, listeners, children = [], data } = context
|
export default Select
|
||||||
const treeSelectProps = {
|
|
||||||
...omit(data, ['attrs']),
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
children,
|
|
||||||
__propsSymbol__: Symbol(),
|
|
||||||
},
|
|
||||||
on: listeners,
|
|
||||||
}
|
|
||||||
return <TreeSelect {...treeSelectProps}/>
|
|
||||||
},
|
|
||||||
TreeNode,
|
|
||||||
SHOW_ALL, SHOW_PARENT, SHOW_CHILD,
|
|
||||||
}
|
|
||||||
export { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD }
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import PropTypes from '../../_util/vue-types'
|
||||||
|
import { isLabelInValue } from './util'
|
||||||
|
|
||||||
|
const internalValProp = PropTypes.oneOfType([
|
||||||
|
PropTypes.string,
|
||||||
|
PropTypes.number,
|
||||||
|
])
|
||||||
|
|
||||||
|
export function genArrProps (propType) {
|
||||||
|
return PropTypes.oneOfType([
|
||||||
|
propType,
|
||||||
|
PropTypes.arrayOf(propType),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Origin code check `multiple` is true when `treeCheckStrictly` & `labelInValue`.
|
||||||
|
* But in process logic is already cover to array.
|
||||||
|
* Check array is not necessary. Let's simplify this check logic.
|
||||||
|
*/
|
||||||
|
export function valueProp (...args) {
|
||||||
|
const [props, propName, Component] = args
|
||||||
|
|
||||||
|
if (isLabelInValue(props)) {
|
||||||
|
const err = genArrProps(PropTypes.shape({
|
||||||
|
label: PropTypes.node,
|
||||||
|
value: internalValProp,
|
||||||
|
}).loose)(...args)
|
||||||
|
if (err) {
|
||||||
|
return new Error(
|
||||||
|
`Invalid prop \`${propName}\` supplied to \`${Component}\`. ` +
|
||||||
|
`You should use { label: string, value: string | number } or [{ label: string, value: string | number }] instead.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const err = genArrProps(internalValProp)(...args)
|
||||||
|
if (err) {
|
||||||
|
return new Error(
|
||||||
|
`Invalid prop \`${propName}\` supplied to \`${Component}\`. ` +
|
||||||
|
`You should use string or [string] instead.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
|
@ -1,5 +1,17 @@
|
||||||
import { getPropsData, getAllProps, getKey, getAttrs, getSlotOptions, getSlots } from '../../_util/props-util'
|
import warning from 'warning'
|
||||||
import { cloneVNodes, cloneElement } from '../../_util/vnode'
|
import omit from 'omit.js'
|
||||||
|
import {
|
||||||
|
convertDataToTree as vcConvertDataToTree,
|
||||||
|
convertTreeToEntities as vcConvertTreeToEntities,
|
||||||
|
conductCheck as rcConductCheck,
|
||||||
|
} from '../../vc-tree/src/util'
|
||||||
|
import SelectNode from './SelectNode'
|
||||||
|
import { SHOW_CHILD, SHOW_PARENT } from './strategies'
|
||||||
|
import { getSlots, getPropsData } from '../../_util/props-util'
|
||||||
|
|
||||||
|
let warnDeprecatedLabel = false
|
||||||
|
|
||||||
|
// =================== MISC ====================
|
||||||
export function toTitle (title) {
|
export function toTitle (title) {
|
||||||
if (typeof title === 'string') {
|
if (typeof title === 'string') {
|
||||||
return title
|
return title
|
||||||
|
@ -7,58 +19,20 @@ export function toTitle (title) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getValuePropValue (child) {
|
export function toArray (data) {
|
||||||
const props = getAllProps(child)
|
if (!data) return []
|
||||||
if ('value' in props) {
|
|
||||||
return props.value
|
return Array.isArray(data) ? data : [data]
|
||||||
}
|
|
||||||
if (getKey(child) !== undefined) {
|
|
||||||
return getKey(child)
|
|
||||||
}
|
|
||||||
throw new Error(`no key or value for ${child}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPropValue (child, prop) {
|
export function createRef () {
|
||||||
if (prop === 'value') {
|
const func = function setRef (node) {
|
||||||
return getValuePropValue(child)
|
func.current = node
|
||||||
}
|
|
||||||
const slots = getSlots(child)
|
|
||||||
if (prop === 'children') {
|
|
||||||
const newChild = child.$slots ? cloneVNodes(child.$slots.default, true) : cloneVNodes(child.componentOptions.children, true)
|
|
||||||
if (newChild.length === 1 && !newChild[0].tag) {
|
|
||||||
return newChild[0].text
|
|
||||||
}
|
|
||||||
return newChild
|
|
||||||
}
|
|
||||||
if (slots[prop]) {
|
|
||||||
return cloneVNodes(slots[prop], true)
|
|
||||||
}
|
|
||||||
const data = getPropsData(child)
|
|
||||||
if (prop in data) {
|
|
||||||
return data[prop]
|
|
||||||
} else {
|
|
||||||
return getAttrs(child)[prop]
|
|
||||||
}
|
}
|
||||||
|
return func
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMultiple (props) {
|
// =============== Legacy ===============
|
||||||
return !!(props.multiple || props.treeCheckable)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toArray (value) {
|
|
||||||
let ret = value
|
|
||||||
if (value === undefined) {
|
|
||||||
ret = []
|
|
||||||
} else if (!Array.isArray(value)) {
|
|
||||||
ret = [value]
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preventDefaultEvent (e) {
|
|
||||||
e.preventDefault()
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UNSELECTABLE_STYLE = {
|
export const UNSELECTABLE_STYLE = {
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
WebkitUserSelect: 'none',
|
WebkitUserSelect: 'none',
|
||||||
|
@ -68,502 +42,389 @@ export const UNSELECTABLE_ATTRIBUTE = {
|
||||||
unselectable: 'unselectable',
|
unselectable: 'unselectable',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function labelCompatible (prop) {
|
/**
|
||||||
let newProp = prop
|
* Convert position list to hierarchy structure.
|
||||||
if (newProp === 'label') {
|
* This is little hack since use '-' to split the position.
|
||||||
newProp = 'title'
|
|
||||||
}
|
|
||||||
return newProp
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isInclude (smallArray, bigArray) {
|
|
||||||
// attention: [0,0,1] [0,0,10]
|
|
||||||
return smallArray.every((ii, i) => {
|
|
||||||
return ii === bigArray[i]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isPositionPrefix (smallPos, bigPos) {
|
|
||||||
if (!bigPos || !smallPos) {
|
|
||||||
// console.log(smallPos, bigPos);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (bigPos.length < smallPos.length) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// attention: "0-0-1" "0-0-10"
|
|
||||||
if ((bigPos.length > smallPos.length) && (bigPos.charAt(smallPos.length) !== '-')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return bigPos.substr(0, smallPos.length) === smallPos
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
export function getCheckedKeys(node, checkedKeys, allCheckedNodesKeys) {
|
|
||||||
const nodeKey = node.props.eventKey;
|
|
||||||
let newCks = [...checkedKeys];
|
|
||||||
let nodePos;
|
|
||||||
const unCheck = allCheckedNodesKeys.some(item => {
|
|
||||||
if (item.key === nodeKey) {
|
|
||||||
nodePos = item.pos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (unCheck) {
|
|
||||||
newCks = [];
|
|
||||||
allCheckedNodesKeys.forEach(item => {
|
|
||||||
if (isPositionPrefix(item.pos, nodePos) || isPositionPrefix(nodePos, item.pos)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
newCks.push(item.key);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
newCks.push(nodeKey);
|
|
||||||
}
|
|
||||||
return newCks;
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
export function flatToHierarchy (positionList) {
|
||||||
function getChildrenlength (children) {
|
if (!positionList.length) {
|
||||||
let len = 1
|
return []
|
||||||
if (Array.isArray(children)) {
|
|
||||||
len = children.length
|
|
||||||
}
|
|
||||||
return len
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSiblingPosition (index, len, siblingPosition) {
|
const entrances = {}
|
||||||
if (len === 1) {
|
|
||||||
siblingPosition.first = true
|
// Prepare the position map
|
||||||
siblingPosition.last = true
|
const posMap = {}
|
||||||
|
const parsedList = positionList.slice().map(entity => {
|
||||||
|
const clone = {
|
||||||
|
...entity,
|
||||||
|
fields: entity.pos.split('-'),
|
||||||
|
}
|
||||||
|
delete clone.children
|
||||||
|
return clone
|
||||||
|
})
|
||||||
|
|
||||||
|
parsedList.forEach((entity) => {
|
||||||
|
posMap[entity.pos] = entity
|
||||||
|
})
|
||||||
|
|
||||||
|
parsedList.sort((a, b) => {
|
||||||
|
return a.fields.length - b.fields.length
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create the hierarchy
|
||||||
|
parsedList.forEach((entity) => {
|
||||||
|
const parentPos = entity.fields.slice(0, -1).join('-')
|
||||||
|
const parentEntity = posMap[parentPos]
|
||||||
|
|
||||||
|
if (!parentEntity) {
|
||||||
|
entrances[entity.pos] = entity
|
||||||
} else {
|
} else {
|
||||||
siblingPosition.first = index === 0
|
parentEntity.children = parentEntity.children || []
|
||||||
siblingPosition.last = index === len - 1
|
parentEntity.children.push(entity)
|
||||||
}
|
|
||||||
return siblingPosition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterChild (childs) {
|
// Some time position list provide `key`, we don't need it
|
||||||
const newChilds = []
|
delete entity.key
|
||||||
childs.forEach(child => {
|
delete entity.fields
|
||||||
const options = getSlotOptions(child)
|
|
||||||
if (options.__ANT_TREE_NODE || options.__ANT_TREE_SELECT_NODE) {
|
|
||||||
newChilds.push(child)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
return newChilds
|
|
||||||
|
return Object.keys(entrances).map(key => entrances[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loopAllChildren (childs, callback, parent) {
|
// =============== Accessibility ===============
|
||||||
const loop = (children, level, _parent) => {
|
let ariaId = 0
|
||||||
const len = getChildrenlength(children)
|
|
||||||
children.forEach(function handler(item, index) { // eslint-disable-line
|
export function resetAriaId () {
|
||||||
const pos = `${level}-${index}`
|
ariaId = 0
|
||||||
if (item && item.componentOptions && item.componentOptions.children) {
|
|
||||||
loop(filterChild(item.componentOptions.children), pos, { node: item, pos })
|
|
||||||
}
|
|
||||||
if (item) {
|
|
||||||
callback(item, index, pos, item.key || pos, getSiblingPosition(index, len, {}), _parent)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
loop(filterChild(childs), 0, parent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// export function loopAllChildren(childs, callback) {
|
export function generateAriaId (prefix) {
|
||||||
// const loop = (children, level) => {
|
ariaId += 1
|
||||||
// React.Children.forEach(children, (item, index) => {
|
return `${prefix}_${ariaId}`
|
||||||
// const pos = `${level}-${index}`;
|
|
||||||
// if (item && item.props.children) {
|
|
||||||
// loop(item.props.children, pos);
|
|
||||||
// }
|
|
||||||
// if (item) {
|
|
||||||
// callback(item, index, pos, getValuePropValue(item));
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
// loop(childs, 0);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Here has the side effect. Update node children data affect.
|
|
||||||
export function flatToHierarchy (arr) {
|
|
||||||
if (!arr.length) {
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
const hierarchyNodes = []
|
|
||||||
const levelObj = {}
|
|
||||||
arr.forEach((item) => {
|
|
||||||
if (!item.pos) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const posLen = item.pos.split('-').length
|
|
||||||
if (!levelObj[posLen]) {
|
|
||||||
levelObj[posLen] = []
|
|
||||||
}
|
|
||||||
levelObj[posLen].push(item)
|
|
||||||
})
|
|
||||||
const levelArr = Object.keys(levelObj).sort((a, b) => b - a)
|
|
||||||
// const s = Date.now();
|
|
||||||
// todo: there are performance issues!
|
|
||||||
levelArr.reduce((pre, cur) => {
|
|
||||||
if (cur && cur !== pre) {
|
|
||||||
levelObj[pre].forEach((item) => {
|
|
||||||
let haveParent = false
|
|
||||||
levelObj[cur].forEach((ii) => {
|
|
||||||
if (isPositionPrefix(ii.pos, item.pos)) {
|
|
||||||
haveParent = true
|
|
||||||
if (!ii.children) {
|
|
||||||
ii.children = []
|
|
||||||
}
|
|
||||||
ii.children.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!haveParent) {
|
|
||||||
hierarchyNodes.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return cur
|
|
||||||
})
|
|
||||||
// console.log(Date.now() - s);
|
|
||||||
return levelObj[levelArr[levelArr.length - 1]].concat(hierarchyNodes)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// arr.length === 628, use time: ~20ms
|
export function isLabelInValue (props) {
|
||||||
export function filterParentPosition (arr) {
|
const { treeCheckable, treeCheckStrictly, labelInValue } = props
|
||||||
const levelObj = {}
|
if (treeCheckable && treeCheckStrictly) {
|
||||||
arr.forEach((item) => {
|
return true
|
||||||
const posLen = item.split('-').length
|
|
||||||
if (!levelObj[posLen]) {
|
|
||||||
levelObj[posLen] = []
|
|
||||||
}
|
}
|
||||||
levelObj[posLen].push(item)
|
return labelInValue || false
|
||||||
})
|
|
||||||
const levelArr = Object.keys(levelObj).sort()
|
|
||||||
for (let i = 0; i < levelArr.length; i++) {
|
|
||||||
if (levelArr[i + 1]) {
|
|
||||||
levelObj[levelArr[i]].forEach(ii => {
|
|
||||||
for (let j = i + 1; j < levelArr.length; j++) {
|
|
||||||
levelObj[levelArr[j]].forEach((_i, index) => {
|
|
||||||
if (isPositionPrefix(ii, _i)) {
|
|
||||||
levelObj[levelArr[j]][index] = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
levelObj[levelArr[j]] = levelObj[levelArr[j]].filter(p => p)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let nArr = []
|
|
||||||
levelArr.forEach(i => {
|
|
||||||
nArr = nArr.concat(levelObj[i])
|
|
||||||
})
|
|
||||||
return nArr
|
|
||||||
}
|
|
||||||
// console.log(filterParentPosition(
|
|
||||||
// ['0-2', '0-3-3', '0-10', '0-10-0', '0-0-1', '0-0', '0-1-1', '0-1']
|
|
||||||
// ));
|
|
||||||
|
|
||||||
function stripTail (str) {
|
|
||||||
const arr = str.match(/(.+)(-[^-]+)$/)
|
|
||||||
let st = ''
|
|
||||||
if (arr && arr.length === 3) {
|
|
||||||
st = arr[1]
|
|
||||||
}
|
|
||||||
return st
|
|
||||||
}
|
|
||||||
function splitPosition (pos) {
|
|
||||||
return pos.split('-')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: do optimization.
|
// =================== Tree ====================
|
||||||
export function handleCheckState (obj, checkedPositionArr, checkIt) {
|
export function parseSimpleTreeData (treeData, { id, pId, rootPId }) {
|
||||||
// console.log(stripTail('0-101-000'));
|
const keyNodes = {}
|
||||||
// let s = Date.now();
|
const rootNodeList = []
|
||||||
let objKeys = Object.keys(obj)
|
|
||||||
|
|
||||||
objKeys.forEach((i, index) => {
|
// Fill in the map
|
||||||
const iArr = splitPosition(i)
|
const nodeList = treeData.map((node) => {
|
||||||
let saved = false
|
const clone = { ...node }
|
||||||
checkedPositionArr.forEach((_pos) => {
|
const key = clone[id]
|
||||||
const _posArr = splitPosition(_pos)
|
keyNodes[key] = clone
|
||||||
if (iArr.length > _posArr.length && isInclude(_posArr, iArr)) {
|
clone.key = clone.key || key
|
||||||
obj[i].halfChecked = false
|
return clone
|
||||||
obj[i].checked = checkIt
|
|
||||||
objKeys[index] = null
|
|
||||||
}
|
|
||||||
if (iArr[0] === _posArr[0] && iArr[1] === _posArr[1]) {
|
|
||||||
saved = true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
if (!saved) {
|
|
||||||
objKeys[index] = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
objKeys = objKeys.filter(i => i) // filter non null;
|
|
||||||
|
|
||||||
for (let pIndex = 0; pIndex < checkedPositionArr.length; pIndex++) {
|
// Connect tree
|
||||||
// loop to set ancestral nodes's `checked` or `halfChecked`
|
nodeList.forEach((node) => {
|
||||||
const loop = (__pos) => {
|
const parentKey = node[pId]
|
||||||
const _posLen = splitPosition(__pos).length
|
const parent = keyNodes[parentKey]
|
||||||
if (_posLen <= 2) { // e.g. '0-0', '0-1'
|
|
||||||
return
|
// Fill parent
|
||||||
}
|
if (parent) {
|
||||||
let sibling = 0
|
parent.children = parent.children || []
|
||||||
let siblingChecked = 0
|
parent.children.push(node)
|
||||||
const parentPosition = stripTail(__pos)
|
|
||||||
objKeys.forEach((i /* , index*/) => {
|
|
||||||
const iArr = splitPosition(i)
|
|
||||||
if (iArr.length === _posLen && isInclude(splitPosition(parentPosition), iArr)) {
|
|
||||||
sibling++
|
|
||||||
if (obj[i].checked) {
|
|
||||||
siblingChecked++
|
|
||||||
const _i = checkedPositionArr.indexOf(i)
|
|
||||||
if (_i > -1) {
|
|
||||||
checkedPositionArr.splice(_i, 1)
|
|
||||||
if (_i <= pIndex) {
|
|
||||||
pIndex--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (obj[i].halfChecked) {
|
|
||||||
siblingChecked += 0.5
|
|
||||||
}
|
|
||||||
// objKeys[index] = null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// objKeys = objKeys.filter(i => i); // filter non null;
|
|
||||||
const parent = obj[parentPosition]
|
|
||||||
// not check, checked, halfChecked
|
|
||||||
if (siblingChecked === 0) {
|
|
||||||
parent.checked = false
|
|
||||||
parent.halfChecked = false
|
|
||||||
} else if (siblingChecked === sibling) {
|
|
||||||
parent.checked = true
|
|
||||||
parent.halfChecked = false
|
|
||||||
} else {
|
|
||||||
parent.halfChecked = true
|
|
||||||
parent.checked = false
|
|
||||||
}
|
|
||||||
loop(parentPosition)
|
|
||||||
}
|
|
||||||
loop(checkedPositionArr[pIndex], pIndex)
|
|
||||||
}
|
|
||||||
// console.log(Date.now()-s, objKeys.length, checkIt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCheck (treeNodesStates, checkedPositions) {
|
// Fill root tree node
|
||||||
const halfCheckedKeys = []
|
if (parentKey === rootPId || (!parent && rootPId === null)) {
|
||||||
const checkedKeys = []
|
rootNodeList.push(node)
|
||||||
const checkedNodes = []
|
|
||||||
Object.keys(treeNodesStates).forEach((item) => {
|
|
||||||
const itemObj = treeNodesStates[item]
|
|
||||||
if (itemObj.checked) {
|
|
||||||
checkedKeys.push(itemObj.key)
|
|
||||||
// checkedNodes.push(getValuePropValue(itemObj.node));
|
|
||||||
checkedNodes.push({ ...itemObj, pos: item })
|
|
||||||
} else if (itemObj.halfChecked) {
|
|
||||||
halfCheckedKeys.push(itemObj.key)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return rootNodeList
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if position has relation.
|
||||||
|
* e.g. 1-2 related with 1-2-3
|
||||||
|
* e.g. 1-3-2 related with 1
|
||||||
|
* e.g. 1-2 not related with 1-21
|
||||||
|
*/
|
||||||
|
export function isPosRelated (pos1, pos2) {
|
||||||
|
const fields1 = pos1.split('-')
|
||||||
|
const fields2 = pos2.split('-')
|
||||||
|
|
||||||
|
const minLen = Math.min(fields1.length, fields2.length)
|
||||||
|
for (let i = 0; i < minLen; i += 1) {
|
||||||
|
if (fields1[i] !== fields2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is only used on treeNode check (none treeCheckStrictly but has searchInput).
|
||||||
|
* We convert entity to { node, pos, children } format.
|
||||||
|
* This is legacy bug but we still need to do with it.
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
export function cleanEntity ({ node, pos, children }) {
|
||||||
|
const instance = {
|
||||||
|
node,
|
||||||
|
pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children) {
|
||||||
|
instance.children = children.map(cleanEntity)
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a filtered TreeNode list by provided treeNodes.
|
||||||
|
* [Legacy] Since `Tree` use `key` as map but `key` will changed by React,
|
||||||
|
* we have to convert `treeNodes > data > treeNodes` to keep the key.
|
||||||
|
* Such performance hungry!
|
||||||
|
*/
|
||||||
|
export function getFilterTree (h, treeNodes, searchValue, filterFunc, valueEntities) {
|
||||||
|
if (!searchValue) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapFilteredNodeToData (node) {
|
||||||
|
if (!node) return null
|
||||||
|
|
||||||
|
let match = false
|
||||||
|
if (filterFunc(searchValue, node)) {
|
||||||
|
match = true
|
||||||
|
}
|
||||||
|
const $slots = getSlots(node)
|
||||||
|
const children = ($slots.default || []).map(mapFilteredNodeToData).filter(n => n)
|
||||||
|
delete $slots.default
|
||||||
|
const slotsKey = Object.keys($slots)
|
||||||
|
if (children.length || match) {
|
||||||
|
return (
|
||||||
|
<SelectNode
|
||||||
|
{...node.data}
|
||||||
|
key={valueEntities[getPropsData(node).value].key}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
{slotsKey.length ? slotsKey.map(name => {
|
||||||
|
return <template slot={name}>{$slots[name][0].tag === 'template' ? $slots[name][0].children : $slots[name]}</template>
|
||||||
|
}) : null}
|
||||||
|
</SelectNode>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return treeNodes.map(mapFilteredNodeToData).filter(node => node)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================== Value ===================
|
||||||
|
/**
|
||||||
|
* Convert value to array format to make logic simplify.
|
||||||
|
*/
|
||||||
|
export function formatInternalValue (value, props) {
|
||||||
|
const valueList = toArray(value)
|
||||||
|
|
||||||
|
// Parse label in value
|
||||||
|
if (isLabelInValue(props)) {
|
||||||
|
return valueList.map((val) => {
|
||||||
|
if (typeof val !== 'object' || !val) {
|
||||||
return {
|
return {
|
||||||
halfCheckedKeys, checkedKeys, checkedNodes, treeNodesStates, checkedPositions,
|
value: '',
|
||||||
|
label: '',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTreeNodesStates (children, values) {
|
return val
|
||||||
const checkedPositions = []
|
|
||||||
const treeNodesStates = {}
|
|
||||||
loopAllChildren(children, (item, index, pos, keyOrPos, siblingPosition) => {
|
|
||||||
treeNodesStates[pos] = {
|
|
||||||
node: item,
|
|
||||||
key: keyOrPos,
|
|
||||||
checked: false,
|
|
||||||
halfChecked: false,
|
|
||||||
siblingPosition,
|
|
||||||
}
|
|
||||||
if (values.indexOf(getValuePropValue(item)) !== -1) {
|
|
||||||
treeNodesStates[pos].checked = true
|
|
||||||
checkedPositions.push(pos)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
handleCheckState(treeNodesStates, filterParentPosition(checkedPositions.sort()), true)
|
|
||||||
|
|
||||||
return getCheck(treeNodesStates, checkedPositions)
|
|
||||||
}
|
|
||||||
|
|
||||||
// can add extra prop to every node.
|
|
||||||
export function recursiveCloneChildren (children, cb = ch => ch) {
|
|
||||||
// return React.Children.map(children, child => {
|
|
||||||
return Array.from(children).map(child => {
|
|
||||||
const newChild = cb(child)
|
|
||||||
if (newChild && newChild.props && newChild.props.children) {
|
|
||||||
return cloneElement(newChild, {
|
|
||||||
children: recursiveCloneChildren(newChild.props.children, cb),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return newChild
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// const newChildren = recursiveCloneChildren(children, child => {
|
|
||||||
// const extraProps = {};
|
|
||||||
// if (child && child.type && child.type.xxx) {
|
|
||||||
// extraProps._prop = true;
|
|
||||||
// return React.cloneElement(child, extraProps);
|
|
||||||
// }
|
|
||||||
// return child;
|
|
||||||
// });
|
|
||||||
|
|
||||||
function recursiveGen (children, level = 0) {
|
return valueList.map(val => ({
|
||||||
return children.map((child, index) => {
|
value: val,
|
||||||
const pos = `${level}-${index}`
|
}))
|
||||||
const props = getAllProps(child)
|
}
|
||||||
const { title, label, value, ...rest } = props
|
|
||||||
const { children: subChildren } = child.componentOptions
|
export function getLabel (wrappedValue, entity, treeNodeLabelProp) {
|
||||||
const o = {
|
if (wrappedValue.label) {
|
||||||
...rest,
|
return wrappedValue.label
|
||||||
title,
|
}
|
||||||
label: label || title,
|
|
||||||
|
if (entity) {
|
||||||
|
const props = getPropsData(entity.node)
|
||||||
|
if (Object.keys(props).length) {
|
||||||
|
return props[treeNodeLabelProp]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since value without entity will be in missValueList.
|
||||||
|
// This code will never reached, but we still need this in case.
|
||||||
|
return wrappedValue.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert internal state `valueList` to user needed value list.
|
||||||
|
* This will return an array list. You need check if is not multiple when return.
|
||||||
|
*
|
||||||
|
* `allCheckedNodes` is used for `treeCheckStrictly`
|
||||||
|
*/
|
||||||
|
export function formatSelectorValue (valueList, props, valueEntities) {
|
||||||
|
const {
|
||||||
|
treeNodeLabelProp,
|
||||||
|
treeCheckable, treeCheckStrictly, showCheckedStrategy,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
// Will hide some value if `showCheckedStrategy` is set
|
||||||
|
if (treeCheckable && !treeCheckStrictly) {
|
||||||
|
const values = {}
|
||||||
|
valueList.forEach((wrappedValue) => {
|
||||||
|
values[wrappedValue.value] = wrappedValue
|
||||||
|
})
|
||||||
|
const hierarchyList = flatToHierarchy(valueList.map(({ value }) => valueEntities[value]))
|
||||||
|
|
||||||
|
if (showCheckedStrategy === SHOW_PARENT) {
|
||||||
|
// Only get the parent checked value
|
||||||
|
return hierarchyList.map(({ node }) => {
|
||||||
|
const value = getPropsData(node).value
|
||||||
|
return {
|
||||||
|
label: getLabel(values[value], valueEntities[value], treeNodeLabelProp),
|
||||||
value,
|
value,
|
||||||
key: child.key,
|
|
||||||
_pos: pos,
|
|
||||||
}
|
|
||||||
if (subChildren) {
|
|
||||||
o.children = recursiveGen(subChildren, pos)
|
|
||||||
}
|
|
||||||
return o
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function recursive (children, cb) {
|
|
||||||
children.forEach(item => {
|
|
||||||
cb(item)
|
|
||||||
if (item.children) {
|
|
||||||
recursive(item.children, cb)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
} else if (showCheckedStrategy === SHOW_CHILD) {
|
||||||
|
// Only get the children checked value
|
||||||
|
const targetValueList = []
|
||||||
|
|
||||||
// Get the tree's checkedNodes (todo: can merge to the `handleCheckState` function)
|
// Find the leaf children
|
||||||
// If one node checked, it's all children nodes checked.
|
const traverse = ({ node, children }) => {
|
||||||
// If sibling nodes all checked, the parent checked.
|
const value = getPropsData(node).value
|
||||||
export function filterAllCheckedData (vs, treeNodes) {
|
if (!children || children.length === 0) {
|
||||||
const vals = [...vs]
|
targetValueList.push({
|
||||||
if (!vals.length) {
|
label: getLabel(values[value], valueEntities[value], treeNodeLabelProp),
|
||||||
return vals
|
value,
|
||||||
}
|
})
|
||||||
|
|
||||||
const data = recursiveGen(treeNodes)
|
|
||||||
const checkedNodesPositions = []
|
|
||||||
|
|
||||||
function checkChildren (children) {
|
|
||||||
children.forEach(item => {
|
|
||||||
if (item.__checked) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const ci = vals.indexOf(item.value)
|
|
||||||
const childs = item.children
|
children.forEach((entity) => {
|
||||||
if (ci > -1) {
|
traverse(entity)
|
||||||
item.__checked = true
|
|
||||||
checkedNodesPositions.push({ node: item, pos: item._pos })
|
|
||||||
vals.splice(ci, 1)
|
|
||||||
if (childs) {
|
|
||||||
recursive(childs, child => {
|
|
||||||
child.__checked = true
|
|
||||||
checkedNodesPositions.push({ node: child, pos: child._pos })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (childs) {
|
|
||||||
checkChildren(childs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkParent (children, parent = { root: true }) {
|
hierarchyList.forEach((entity) => {
|
||||||
let siblingChecked = 0
|
traverse(entity)
|
||||||
children.forEach(item => {
|
})
|
||||||
const childs = item.children
|
|
||||||
if (childs && !item.__checked && !item.__halfChecked) {
|
return targetValueList
|
||||||
const p = checkParent(childs, item)
|
|
||||||
if (p.__checked) {
|
|
||||||
siblingChecked++
|
|
||||||
} else if (p.__halfChecked) {
|
|
||||||
siblingChecked += 0.5
|
|
||||||
}
|
}
|
||||||
} else if (item.__checked) {
|
}
|
||||||
siblingChecked++
|
|
||||||
} else if (item.__halfChecked) {
|
return valueList.map(wrappedValue => ({
|
||||||
siblingChecked += 0.5
|
label: getLabel(wrappedValue, valueEntities[wrappedValue.value], treeNodeLabelProp),
|
||||||
|
value: wrappedValue.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use `rc-tree` convertDataToTree to convert treeData to TreeNodes.
|
||||||
|
* This will change the label to title value
|
||||||
|
*/
|
||||||
|
function processProps (props) {
|
||||||
|
const { title, label, key, value, class: cls, style, on = {}} = props
|
||||||
|
const p = {
|
||||||
|
props: omit(props, ['on', 'key', 'class', 'className', 'style']),
|
||||||
|
on,
|
||||||
|
class: cls || props.className,
|
||||||
|
style: style,
|
||||||
|
key: typeof key === 'number' ? String(key) : (key || value),
|
||||||
|
}
|
||||||
|
// Warning user not to use deprecated label prop.
|
||||||
|
if (label && !title) {
|
||||||
|
if (!warnDeprecatedLabel) {
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
'\'label\' in treeData is deprecated. Please use \'title\' instead.'
|
||||||
|
)
|
||||||
|
warnDeprecatedLabel = true
|
||||||
|
}
|
||||||
|
|
||||||
|
p.props.title = label
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertDataToTree (h, treeData) {
|
||||||
|
return vcConvertDataToTree(h, treeData, { processProps })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use `rc-tree` convertTreeToEntities for entities calculation.
|
||||||
|
* We have additional entities of `valueEntities`
|
||||||
|
*/
|
||||||
|
function initWrapper (wrapper) {
|
||||||
|
return {
|
||||||
|
...wrapper,
|
||||||
|
valueEntities: {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processEntity (entity, wrapper) {
|
||||||
|
const value = getPropsData(entity.node).value
|
||||||
|
entity.value = value
|
||||||
|
|
||||||
|
// This should be empty, or will get error message.
|
||||||
|
const currentEntity = wrapper.valueEntities[value]
|
||||||
|
if (currentEntity) {
|
||||||
|
warning(
|
||||||
|
false,
|
||||||
|
`Conflict! value of node '${entity.key}' (${value}) has already used by node '${currentEntity.key}'.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
wrapper.valueEntities[value] = entity
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertTreeToEntities (treeNodes) {
|
||||||
|
return vcConvertTreeToEntities(treeNodes, {
|
||||||
|
initWrapper,
|
||||||
|
processEntity,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/ant-design/ant-design/issues/13328
|
||||||
|
* We need calculate the half check key when searchValue is set.
|
||||||
|
*/
|
||||||
|
// TODO: This logic may better move to rc-tree
|
||||||
|
export function getHalfCheckedKeys (valueList, valueEntities) {
|
||||||
|
const values = {}
|
||||||
|
|
||||||
|
// Fill checked keys
|
||||||
|
valueList.forEach(({ value }) => {
|
||||||
|
values[value] = false
|
||||||
|
})
|
||||||
|
|
||||||
|
// Fill half checked keys
|
||||||
|
valueList.forEach(({ value }) => {
|
||||||
|
let current = valueEntities[value]
|
||||||
|
|
||||||
|
while (current && current.parent) {
|
||||||
|
const parentValue = current.parent.value
|
||||||
|
if (parentValue in values) break
|
||||||
|
values[parentValue] = true
|
||||||
|
|
||||||
|
current = current.parent
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const len = children.length
|
|
||||||
if (siblingChecked === len) {
|
|
||||||
parent.__checked = true
|
|
||||||
checkedNodesPositions.push({ node: parent, pos: parent._pos })
|
|
||||||
} else if (siblingChecked < len && siblingChecked > 0) {
|
|
||||||
parent.__halfChecked = true
|
|
||||||
}
|
|
||||||
if (parent.root) {
|
|
||||||
return children
|
|
||||||
}
|
|
||||||
return parent
|
|
||||||
}
|
|
||||||
checkChildren(data)
|
|
||||||
checkParent(data)
|
|
||||||
|
|
||||||
checkedNodesPositions.forEach((i, index) => {
|
// Get half keys
|
||||||
// clear private metadata
|
return Object.keys(values).filter(value => values[value]).map(value => valueEntities[value].key)
|
||||||
delete checkedNodesPositions[index].node.__checked
|
|
||||||
delete checkedNodesPositions[index].node._pos
|
|
||||||
// create the same structure of `onCheck`'s return.
|
|
||||||
checkedNodesPositions[index].node.props = {
|
|
||||||
title: checkedNodesPositions[index].node.title,
|
|
||||||
label: checkedNodesPositions[index].node.label || checkedNodesPositions[index].node.title,
|
|
||||||
value: checkedNodesPositions[index].node.value,
|
|
||||||
}
|
|
||||||
if (checkedNodesPositions[index].node.children) {
|
|
||||||
checkedNodesPositions[index].node.props.children = checkedNodesPositions[index].node.children
|
|
||||||
}
|
|
||||||
delete checkedNodesPositions[index].node.title
|
|
||||||
delete checkedNodesPositions[index].node.label
|
|
||||||
delete checkedNodesPositions[index].node.value
|
|
||||||
delete checkedNodesPositions[index].node.children
|
|
||||||
})
|
|
||||||
return checkedNodesPositions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processSimpleTreeData (treeData, format) {
|
export const conductCheck = rcConductCheck
|
||||||
function unflatten2 (array, parent = { [format.id]: format.rootPId }) {
|
|
||||||
const children = []
|
|
||||||
for (let i = 0; i < array.length; i++) {
|
|
||||||
array[i] = { ...array[i] } // copy, can not corrupts original data
|
|
||||||
if (array[i][format.pId] === parent[format.id]) {
|
|
||||||
array[i].key = array[i][format.id]
|
|
||||||
children.push(array[i])
|
|
||||||
array.splice(i--, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (children.length) {
|
|
||||||
parent.children = children
|
|
||||||
children.forEach(child => unflatten2(array, child))
|
|
||||||
}
|
|
||||||
if (parent[format.id] === format.rootPId) {
|
|
||||||
return children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return unflatten2(treeData)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveRef (instance, name) {
|
|
||||||
if (!instance.saveRefs) {
|
|
||||||
instance.saveRefs = {}
|
|
||||||
}
|
|
||||||
if (!instance.saveRefs[name]) {
|
|
||||||
instance.saveRefs[name] = (node) => {
|
|
||||||
instance[name] = node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return instance.saveRefs[name]
|
|
||||||
}
|
|
||||||
|
|
|
@ -101,6 +101,8 @@ const Tree = {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
|
warning(this.$props.__propsSymbol__, 'must pass __propsSymbol__')
|
||||||
|
warning(this.$props.children, 'please children prop replace slots.default')
|
||||||
this.needSyncKeys = {}
|
this.needSyncKeys = {}
|
||||||
const state = {
|
const state = {
|
||||||
_posEntities: {},
|
_posEntities: {},
|
||||||
|
@ -119,12 +121,6 @@ const Tree = {
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
// ...this.getSyncProps(props),
|
|
||||||
// dragOverNodeKey: '',
|
|
||||||
// dropPosition: null,
|
|
||||||
// dragNodesKeys: [],
|
|
||||||
// sLoadedKeys: [],
|
|
||||||
// sLoadingKeys: [],
|
|
||||||
...this.getDerivedStateFromProps(getOptionProps(this), state),
|
...this.getDerivedStateFromProps(getOptionProps(this), state),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -478,7 +474,7 @@ const Tree = {
|
||||||
event: 'load',
|
event: 'load',
|
||||||
node: treeNode,
|
node: treeNode,
|
||||||
}
|
}
|
||||||
this.__emit('load', eventObj)
|
this.__emit('load', newLoadedKeys, eventObj)
|
||||||
this.setUncontrolledState({
|
this.setUncontrolledState({
|
||||||
_loadedKeys: newLoadedKeys,
|
_loadedKeys: newLoadedKeys,
|
||||||
})
|
})
|
||||||
|
@ -593,7 +589,6 @@ const Tree = {
|
||||||
|
|
||||||
return cloneElement(child, {
|
return cloneElement(child, {
|
||||||
props: {
|
props: {
|
||||||
key,
|
|
||||||
eventKey: key,
|
eventKey: key,
|
||||||
expanded: expandedKeys.indexOf(key) !== -1,
|
expanded: expandedKeys.indexOf(key) !== -1,
|
||||||
selected: selectedKeys.indexOf(key) !== -1,
|
selected: selectedKeys.indexOf(key) !== -1,
|
||||||
|
@ -608,6 +603,7 @@ const Tree = {
|
||||||
dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
|
dragOverGapTop: dragOverNodeKey === key && dropPosition === -1,
|
||||||
dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1,
|
dragOverGapBottom: dragOverNodeKey === key && dropPosition === 1,
|
||||||
},
|
},
|
||||||
|
key,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,6 +46,9 @@ const TreeNode = {
|
||||||
icon: PropTypes.any,
|
icon: PropTypes.any,
|
||||||
dataRef: PropTypes.object,
|
dataRef: PropTypes.object,
|
||||||
switcherIcon: PropTypes.any,
|
switcherIcon: PropTypes.any,
|
||||||
|
|
||||||
|
label: PropTypes.any,
|
||||||
|
value: PropTypes.any,
|
||||||
}, {}),
|
}, {}),
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
|
|
|
@ -4,8 +4,10 @@ import Align from '../vc-align'
|
||||||
import PopupInner from './PopupInner'
|
import PopupInner from './PopupInner'
|
||||||
import LazyRenderBox from './LazyRenderBox'
|
import LazyRenderBox from './LazyRenderBox'
|
||||||
import animate from '../_util/css-animation'
|
import animate from '../_util/css-animation'
|
||||||
|
import BaseMixin from '../_util/BaseMixin'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
mixins: [BaseMixin],
|
||||||
props: {
|
props: {
|
||||||
visible: PropTypes.bool,
|
visible: PropTypes.bool,
|
||||||
getClassNameFromAlign: PropTypes.func,
|
getClassNameFromAlign: PropTypes.func,
|
||||||
|
@ -165,7 +167,7 @@ export default {
|
||||||
|
|
||||||
// Delay force align to makes ui smooth
|
// Delay force align to makes ui smooth
|
||||||
if (!stretchChecked) {
|
if (!stretchChecked) {
|
||||||
sizeStyle.visibility = 'hidden'
|
// sizeStyle.visibility = 'hidden'
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.$refs.alignInstance) {
|
if (this.$refs.alignInstance) {
|
||||||
this.$refs.alignInstance.forceAlign()
|
this.$refs.alignInstance.forceAlign()
|
||||||
|
|
Loading…
Reference in New Issue