diff --git a/components/index.js b/components/index.js
index 417087748..1374a81f9 100644
--- a/components/index.js
+++ b/components/index.js
@@ -125,101 +125,60 @@ import { default as Drawer } from './drawer'
const components = [
Affix,
Anchor,
- Anchor.Link,
AutoComplete,
- AutoComplete.Option,
- AutoComplete.OptGroup,
Alert,
Avatar,
BackTop,
Badge,
Breadcrumb,
- Breadcrumb.Item,
Button,
- Button.Group,
Calendar,
Card,
- Card.Meta,
- Card.Grid,
Collapse,
- Collapse.Panel,
Carousel,
Cascader,
Checkbox,
- Checkbox.Group,
Col,
DatePicker,
- DatePicker.MonthPicker,
- DatePicker.RangePicker,
- DatePicker.WeekPicker,
Divider,
Dropdown,
- Dropdown.Button,
Form,
- Form.Item,
Icon,
Input,
- Input.Group,
- Input.Search,
- Input.TextArea,
InputNumber,
Layout,
- Layout.Header,
- Layout.Footer,
- Layout.Sider,
- Layout.Content,
List,
- List.Item,
- List.Item.Meta,
LocaleProvider,
Menu,
- Menu.Item,
- Menu.SubMenu,
- Menu.Divider,
- Menu.ItemGroup,
Modal,
Pagination,
Popconfirm,
Popover,
Progress,
Radio,
- Radio.Group,
- Radio.Button,
Rate,
Row,
Select,
- Select.Option,
- Select.OptGroup,
Slider,
Spin,
Steps,
- Steps.Step,
Switch,
Table,
- Table.Column,
- Table.ColumnGroup,
Transfer,
Tree,
- Tree.TreeNode,
TreeSelect,
- TreeSelect.TreeNode,
Tabs,
- Tabs.TabPane,
- Tabs.TabContent,
Tag,
- Tag.CheckableTag,
TimePicker,
Timeline,
- Timeline.Item,
Tooltip,
Upload,
- Upload.Dragger,
Drawer,
]
const install = function (Vue) {
components.map(component => {
- Vue.component(component.name, component)
+ Vue.use(component)
})
Vue.prototype.$message = message
diff --git a/components/tree/DirectoryTree.jsx b/components/tree/DirectoryTree.jsx
index 99eee935b..12c67659d 100644
--- a/components/tree/DirectoryTree.jsx
+++ b/components/tree/DirectoryTree.jsx
@@ -5,6 +5,7 @@ import { conductExpandParent, convertTreeToEntities } from '../vc-tree/src/util'
import Tree, { TreeProps } from './Tree'
import { calcRangeKeys, getFullKeyList } from './util'
import Icon from '../icon'
+import BaseMixin from '../_util/BaseMixin'
import { initDefaultProps, getOptionProps } from '../_util/props-util'
// export type ExpandAction = false | 'click' | 'doubleClick';
@@ -27,12 +28,13 @@ function getIcon (h, props) {
}
export default {
+ mixins: [BaseMixin],
name: 'ADirectoryTree',
model: {
prop: 'checkedKeys',
event: 'check',
},
- props: initDefaultProps({ ...TreeProps(), expandAction: PropTypes.oneOf([false, 'click', 'doubleClick']) }, {
+ props: initDefaultProps({ ...TreeProps(), expandAction: PropTypes.oneOf([false, 'click', 'doubleclick']) }, {
prefixCls: 'ant-tree',
showIcon: true,
expandAction: 'click',
@@ -55,7 +57,7 @@ export default {
// Expanded keys
if (defaultExpandAll) {
- state._expandedKeys = getFullKeyList(props.children)
+ state._expandedKeys = getFullKeyList(this.$slots.default)
} else if (defaultExpandParent) {
state._expandedKeys = conductExpandParent(expandedKeys || defaultExpandedKeys, keyEntities)
} else {
@@ -102,7 +104,7 @@ export default {
const { expandAction } = this.$props
// Expand the tree
- if (expandAction === 'doubleClick') {
+ if (expandAction === 'doubleclick') {
this.onDebounceExpand(event, node)
}
@@ -117,7 +119,6 @@ export default {
const { eventKey = '' } = node
const newState = {}
-
// Windows / Mac single pick
const ctrlPick = nativeEvent.ctrlKey || nativeEvent.metaKey
const shiftPick = nativeEvent.shiftKey
@@ -171,7 +172,7 @@ export default {
this.$emit('expand', newExpandedKeys, {
expanded: !expanded,
node,
- nativeEvent: event.nativeEvent,
+ nativeEvent: event,
})
},
@@ -195,10 +196,13 @@ export default {
selectedKeys,
},
class: `${prefixCls}-directory`,
- select: this.onSelect,
- click: this.onClick,
- doubleclick: this.onDoubleClick,
- expand: this.onExpand,
+ on: {
+ ...this.$listeners,
+ select: this.onSelect,
+ click: this.onClick,
+ doubleclick: this.onDoubleClick,
+ expand: this.onExpand,
+ },
}
return (
{this.$slots.default}
diff --git a/components/tree/Tree.jsx b/components/tree/Tree.jsx
index 1999db8d8..8dade4555 100644
--- a/components/tree/Tree.jsx
+++ b/components/tree/Tree.jsx
@@ -113,12 +113,8 @@ export default {
const { children, on = {}, slots = {}, scopedSlots = {}, key, class: cls, style, ...restProps } = item
const treeNodeProps = {
...restProps,
- icon: restProps.icon ||
- $slots[slots.icon] ||
- ($scopedSlots[scopedSlots.icon] && $scopedSlots[scopedSlots.icon]),
- title: restProps.title ||
- $slots[slots.title] ||
- ($scopedSlots[scopedSlots.title] && $scopedSlots[scopedSlots.title])(item),
+ icon: $slots[slots.icon] || ($scopedSlots[scopedSlots.icon] && $scopedSlots[scopedSlots.icon]) || restProps.icon,
+ title: $slots[slots.title] || ($scopedSlots[scopedSlots.title] && $scopedSlots[scopedSlots.title](item)) || restProps.title,
dataRef: item,
on,
key,
diff --git a/components/tree/__tests__/__snapshots__/demo.test.js.snap b/components/tree/__tests__/__snapshots__/demo.test.js.snap
index 184b65901..ebf2d87ca 100644
--- a/components/tree/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/tree/__tests__/__snapshots__/demo.test.js.snap
@@ -1,18 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/tree/demo/basic.md correctly 1`] = `
-
- - parent 1
-
- - parent 1-0
-
- - leaf
- - leaf
+
+ - parent 1
+
+ - parent 1-0
+
- - parent 1-1
-
@@ -21,91 +21,108 @@ exports[`renders ./components/tree/demo/basic.md correctly 1`] = `
`;
exports[`renders ./components/tree/demo/basic-controlled.md correctly 1`] = `
-
- - 0-0
-
- - 0-0-0
-
- - 0-0-0-0
- - 0-0-0-1
- - 0-0-0-2
+
+ - 0-0
+
+ - 0-0-0
+
+ - 0-0-0-0
+ - 0-0-0-1
+ - 0-0-0-2
- - 0-0-1
-
- - 0-0-1-0
- - 0-0-1-1
- - 0-0-1-2
+ - 0-0-1
+
+ - 0-0-1-0
+ - 0-0-1-1
+ - 0-0-1-2
- - 0-0-2
+ - 0-0-2
- - 0-1
+
- 0-1
- - 0-2
+ - 0-2
`;
exports[`renders ./components/tree/demo/customized-icon.md correctly 1`] = `
-
- - parent 1
-
- - leaf
- - leaf
+
+`;
+
+exports[`renders ./components/tree/demo/directory.md correctly 1`] = `
+
+ - parent 0
+
+
+ - parent 1
+
`;
exports[`renders ./components/tree/demo/draggable.md correctly 1`] = `
-
- - 0-0
-
- - 0-0-0
-
- - 0-0-0-0
- - 0-0-0-1
- - 0-0-0-2
+
+ - 0-0
+
+ - 0-0-0
+
+ - 0-0-0-0
+ - 0-0-0-1
+ - 0-0-0-2
- - 0-0-1
+
- 0-0-1
- - 0-0-2
+ - 0-0-2
- - 0-1
+
- 0-1
- - 0-2
+ - 0-2
`;
exports[`renders ./components/tree/demo/dynamic.md correctly 1`] = `
-
- - Expand to load
- - Expand to load
- - Tree Node
+
+ - Expand to load
+ - Expand to load
+ - Tree Node
`;
exports[`renders ./components/tree/demo/line.md correctly 1`] = `
-
- - parent 1
-
- - parent 1-0
-
- - leaf
- - leaf
- - leaf
+
+ - parent 1
+
+ - parent 1-0
+
- - parent 1-1
+
- parent 1-1
- - parent 1-2
+
- parent 1-2
@@ -115,22 +132,22 @@ exports[`renders ./components/tree/demo/line.md correctly 1`] = `
exports[`renders ./components/tree/demo/search.md correctly 1`] = `
-
- -
+
+ -
0-0
- -
+
-
0-1
- -
+
-
0-2
diff --git a/components/tree/__tests__/util.test.js b/components/tree/__tests__/util.test.js
new file mode 100644
index 000000000..1fc00945b
--- /dev/null
+++ b/components/tree/__tests__/util.test.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils'
+import Tree from '../index'
+import { calcRangeKeys } from '../util'
+
+const TreeNode = Tree.TreeNode
+
+describe('Tree util', () => {
+ it('calc range keys', () => {
+ const wrapper = mount({
+ render () {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ },
+ })
+
+ const treeWrapper = wrapper.find({ name: 'ATree' })
+ const keys = calcRangeKeys(treeWrapper.vm.$slots.default, ['0-0', '0-2', '0-2-0'], '0-2-0-1', '0-0-0')
+ const target = ['0-0-0', '0-0-1', '0-1', '0-2', '0-2-0', '0-2-0-0', '0-2-0-1']
+ expect(keys.sort()).toEqual(target.sort())
+ })
+})
diff --git a/components/tree/demo/directory.md b/components/tree/demo/directory.md
new file mode 100644
index 000000000..3cf4bc464
--- /dev/null
+++ b/components/tree/demo/directory.md
@@ -0,0 +1,43 @@
+
+#### 目录
+内置的目录树,`multiple` 模式支持 `ctrl(Windows)` / `command(Mac)` 复选。
+
+
+
+#### Directory
+Built-in directory tree. `multiple` support `ctrl(Windows)` / `command(Mac)` selection.
+
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/components/tree/demo/index.vue b/components/tree/demo/index.vue
index 673e0d264..424efbbe5 100644
--- a/components/tree/demo/index.vue
+++ b/components/tree/demo/index.vue
@@ -6,6 +6,7 @@ import Draggable from './draggable'
import Dynamic from './dynamic'
import Line from './line'
import Search from './search'
+import Directory from './directory'
import CN from '../index.zh-CN.md'
import US from '../index.en-US.md'
@@ -20,7 +21,7 @@ const md = {
us: `# Tree
## When To Use
-Almost anything can be represented in a tree structure.
+Almost anything can be represented in a tree structure.
Examples include directories, organization hierarchies, biological classifications, countries, etc. The \`Tree\` component is a way of representing the hierarchical relationship between these things. You can also expand, collapse, and select a treeNode within a \`Tree\`.
## Examples
`,
@@ -41,6 +42,7 @@ export default {
+
diff --git a/components/tree/demo/search.md b/components/tree/demo/search.md
index f9fbd9c86..969155b11 100644
--- a/components/tree/demo/search.md
+++ b/components/tree/demo/search.md
@@ -16,15 +16,15 @@ Searchable Tree.
@expand="onExpand"
:expandedKeys="expandedKeys"
:autoExpandParent="autoExpandParent"
- :treeNodes="gData"
+ :treeData="gData"
>
-
-
- {{key.substr(0, key.indexOf(searchValue))}}
+
+
+ {{title.substr(0, title.indexOf(searchValue))}}
{{searchValue}}
- {{key.substr(key.indexOf(searchValue) + searchValue.length)}}
+ {{title.substr(title.indexOf(searchValue) + searchValue.length)}}
- {{key}}
+ {{title}}
@@ -43,7 +43,7 @@ const generateData = (_level, _preKey, _tns) => {
const children = []
for (let i = 0; i < x; i++) {
const key = `${preKey}-${i}`
- tns.push({ key, scopedSlots: { title: 'title' }})
+ tns.push({ title: key, key, scopedSlots: { title: 'title' }})
if (i < y) {
children.push(key)
}
diff --git a/components/tree/index.jsx b/components/tree/index.jsx
index 435abf909..f1e465b47 100644
--- a/components/tree/index.jsx
+++ b/components/tree/index.jsx
@@ -1,9 +1,6 @@
import Tree from './Tree'
import DirectoryTree from './DirectoryTree'
-// export {
-// TreeProps,
-// } from './Tree'
Tree.TreeNode.name = 'ATreeNode'
Tree.DirectoryTree = DirectoryTree
diff --git a/components/tree/index.old.jsx b/components/tree/index.old.jsx
deleted file mode 100644
index c461f42cc..000000000
--- a/components/tree/index.old.jsx
+++ /dev/null
@@ -1,183 +0,0 @@
-
-import VcTree, { TreeNode } from '../vc-tree'
-import animation from '../_util/openAnimation'
-import PropTypes from '../_util/vue-types'
-import { initDefaultProps, getOptionProps } from '../_util/props-util'
-
-// export interface AntTreeNodeProps {
-// disabled: PropTypes.bool,
-// disableCheckbox: PropTypes.bool,
-// title?: string | React.ReactNode;
-// key?: string;
-// isLeaf: PropTypes.bool,
-// children?: React.ReactNode;
-// }
-
-// export interface AntTreeNode extends React.Component {}
-
-// export interface AntTreeNodeEvent {
-// event: 'check' | 'select';
-// node: AntTreeNode;
-// checked: PropTypes.bool,
-// checkedNodes?: Array;
-// selected: PropTypes.bool,
-// selectedNodes?: Array;
-// }
-
-// export interface AntTreeNodeMouseEvent {
-// node: AntTreeNode;
-// event: React.MouseEventHandler;
-// }
-
-export const TreeProps = () => ({
- treeNodes: PropTypes.array,
- showLine: PropTypes.bool,
- /** 是否支持多选 */
- multiple: PropTypes.boolean,
- /** 是否自动展开父节点 */
- autoExpandParent: PropTypes.boolean,
- /** checkable状态下节点选择完全受控(父子节点选中状态不再关联)*/
- checkStrictly: PropTypes.bool,
- /** 是否支持选中 */
- checkable: PropTypes.bool,
- /** 默认展开所有树节点 */
- defaultExpandAll: PropTypes.bool,
- /** 默认展开指定的树节点 */
- defaultExpandedKeys: PropTypes.arrayOf(PropTypes.string),
- /** (受控)展开指定的树节点 */
- expandedKeys: PropTypes.arrayOf(PropTypes.string),
- /** (受控)选中复选框的树节点 */
- checkedKeys: PropTypes.oneOfType(
- [
- PropTypes.arrayOf(PropTypes.string),
- PropTypes.shape({
- checked: PropTypes.arrayOf(String),
- halfChecked: PropTypes.arrayOf(String),
- }).loose,
- ]
- ),
- /** 默认选中复选框的树节点 */
- defaultCheckedKeys: PropTypes.arrayOf(PropTypes.string),
- /** (受控)设置选中的树节点 */
- selectedKeys: PropTypes.arrayOf(PropTypes.string),
- /** 默认选中的树节点 */
- defaultSelectedKeys: PropTypes.arrayOf(PropTypes.string),
- /** 展开/收起节点时触发 */
- // onExpand?: (expandedKeys: Array, info: { node: AntTreeNode, expanded: boolean }) => void | PromiseLike;
- /** 点击复选框触发 */
- // onCheck?: (checkedKeys: Array, e: AntTreeNodeEvent) => void;
- /** 点击树节点触发 */
- // onSelect?: (selectedKeys: Array, e: AntTreeNodeEvent) => void;
- /** filter some AntTreeNodes as you need. it should return true */
- filterAntTreeNode: PropTypes.func,
- /** 异步加载数据 */
- loadData: PropTypes.func,
- /** 响应右键点击 */
- // onRightClick?: (options: AntTreeNodeMouseEvent) => void;
- /** 设置节点可拖拽(IE>8)*/
- draggable: PropTypes.bool,
- // /** 开始拖拽时调用 */
- // onDragStart?: (options: AntTreeNodeMouseEvent) => void;
- // /** dragenter 触发时调用 */
- // onDragEnter?: (options: AntTreeNodeMouseEvent) => void;
- // /** dragover 触发时调用 */
- // onDragOver?: (options: AntTreeNodeMouseEvent) => void;
- // /** dragleave 触发时调用 */
- // onDragLeave?: (options: AntTreeNodeMouseEvent) => void;
- // /** drop 触发时调用 */
- // onDrop?: (options: AntTreeNodeMouseEvent) => void;
- prefixCls: PropTypes.string,
- filterTreeNode: PropTypes.func,
- showIcon: PropTypes.bool,
- openAnimation: PropTypes.any,
-})
-
-const Tree = {
- name: 'ATree',
- TreeNode: { ...TreeNode, name: 'ATreeNode' },
- props: initDefaultProps(TreeProps(), {
- prefixCls: 'ant-tree',
- checkable: false,
- showIcon: false,
- openAnimation: animation,
- }),
- model: {
- prop: 'checkedKeys',
- event: 'check',
- },
- methods: {
- handleCheck (checkedKeys, e) {
- this.$emit('check', checkedKeys, e)
- },
- handelSelect (selectedKeys, e) {
- this.$emit('select', selectedKeys, e)
- this.$emit('update:select', selectedKeys)
- },
- handleExpand (expandedKeys, info) {
- this.$emit('expand', expandedKeys, info)
- this.$emit('update:expand', expandedKeys)
- },
- renderTreeNodes (data = []) {
- const { $slots, $scopedSlots } = this
- return data.map((item) => {
- const { children, on = {}, slots = {}, scopedSlots = {}, key, class: cls, style, ...restProps } = item
- const treeNodeProps = {
- props: {
- ...restProps,
- icon: restProps.icon ||
- $slots[slots.icon] ||
- ($scopedSlots[scopedSlots.icon] && $scopedSlots[scopedSlots.icon]),
- title: restProps.title ||
- $slots[slots.title] ||
- ($scopedSlots[scopedSlots.title] && $scopedSlots[scopedSlots.title])(item),
- dataRef: item,
- },
- on,
- key,
- class: cls,
- style,
- }
- if (children) {
- return (
-
- {this.renderTreeNodes(children)}
-
- )
- }
- return
- })
- },
- },
-
- render () {
- const props = getOptionProps(this)
- const { prefixCls, checkable, treeNodes, ...restProps } = props
- const { handelSelect, handleCheck, handleExpand, renderTreeNodes } = this
- const vcTreeProps = {
- props: {
- ...restProps,
- prefixCls,
- checkable: checkable ? : checkable,
- },
- on: {
- ...this.$listeners,
- check: handleCheck,
- select: handelSelect,
- expand: handleExpand,
- },
- }
- return (
-
- {treeNodes ? renderTreeNodes(treeNodes) : this.$slots.default}
-
- )
- },
-}
-
-/* istanbul ignore next */
-Tree.install = function (Vue) {
- Vue.component(Tree.name, Tree)
- Vue.component(Tree.TreeNode.name, Tree.TreeNode)
-}
-
-export default Tree
diff --git a/components/tree/util.js b/components/tree/util.js
index 6c2796df8..f5251f203 100644
--- a/components/tree/util.js
+++ b/components/tree/util.js
@@ -1,4 +1,5 @@
import { getNodeChildren, convertTreeToEntities } from '../vc-tree/src/util'
+import { getSlots } from '../_util/props-util'
const Record = {
None: 'node',
@@ -11,7 +12,8 @@ function traverseNodesKey (rootChildren, callback) {
const nodeList = getNodeChildren(rootChildren) || []
function processNode (node) {
- const { key, props: { children }} = node
+ const { key } = node
+ const children = getSlots(node).default
if (callback(key) !== false) {
traverseNodesKey(children, callback)
}
diff --git a/components/vc-tree/src/Tree.jsx b/components/vc-tree/src/Tree.jsx
index b369f2dfb..7e1c09216 100644
--- a/components/vc-tree/src/Tree.jsx
+++ b/components/vc-tree/src/Tree.jsx
@@ -382,7 +382,7 @@ const Tree = {
selected: targetSelected,
node: treeNode,
selectedNodes,
- nativeEvent: e.nativeEvent,
+ nativeEvent: e,
}
this.__emit('select', selectedKeys, eventObj)
},
@@ -397,7 +397,7 @@ const Tree = {
event: 'check',
node: treeNode,
checked,
- nativeEvent: e.nativeEvent,
+ nativeEvent: e,
}
if (checkStrictly) {
@@ -500,7 +500,7 @@ const Tree = {
this.__emit('expand', expandedKeys, {
node: treeNode,
expanded: targetExpanded,
- nativeEvent: e.nativeEvent,
+ nativeEvent: e,
})
// Async Load data
@@ -608,7 +608,7 @@ const Tree = {
class={classNames(prefixCls, {
[`${prefixCls}-show-line`]: showLine,
})}
- role='tree-node'
+ role='tree'
unselectable='on'
tabIndex={focusable ? tabIndex : null}
onKeydown={focusable ? this.onKeydown : () => {}}
diff --git a/components/vc-tree/src/TreeNode.jsx b/components/vc-tree/src/TreeNode.jsx
index 75636dd07..b088b08bf 100644
--- a/components/vc-tree/src/TreeNode.jsx
+++ b/components/vc-tree/src/TreeNode.jsx
@@ -258,10 +258,10 @@ const TreeNode = {
// Load data to avoid default expanded tree without data
syncLoadData (props) {
const { expanded, loading, loaded } = props
- const { vcTree: { onNodeLoad }} = this
+ const { vcTree: { loadData, onNodeLoad }} = this
if (loading) return
// read from state to avoid loadData at same time
- if (expanded && !this.isLeaf2()) {
+ if (loadData && expanded && !this.isLeaf2()) {
// We needn't reload data when has children in sync logic
// It's only needed in node expanded
const hasChildren = this.getNodeChildren().length !== 0
@@ -338,12 +338,11 @@ const TreeNode = {
},
// Icon + Title
- renderSelector () {
- const { selected, icon, loading, dragNodeHighlight, $scopedSlots } = this
- const { vcTree: { prefixCls, showIcon, draggable, loadData }} = this
+ renderSelector (h) {
+ const { selected, icon, loading, dragNodeHighlight } = this
+ const { vcTree: { prefixCls, showIcon, icon: treeIcon, draggable, loadData }} = this
const disabled = this.isDisabled()
const title = getComponentFromProp(this, 'title') || defaultTitle
- const treeIcon = getComponentFromProp(this, 'icon') || $scopedSlots.icon
const wrapClass = `${prefixCls}-node-content-wrapper`
// Icon - Still show loading icon when loading without showIcon
@@ -359,7 +358,7 @@ const TreeNode = {
)}
>
{typeof currentIcon === 'function'
- ? currentIcon({ ...this.$props }) : currentIcon}
+ ? currentIcon(h, { ...this.$props }) : currentIcon}
) : this.renderIcon()
} else if (loadData && loading) {
@@ -446,7 +445,7 @@ const TreeNode = {
},
},
- render () {
+ render (h) {
const {
dragOver, dragOverGapTop, dragOverGapBottom,
isLeaf,
@@ -481,7 +480,7 @@ const TreeNode = {
>
{this.renderSwitcher()}
{this.renderCheckbox()}
- {this.renderSelector()}
+ {this.renderSelector(h)}
{this.renderChildren()}
)
diff --git a/components/vc-tree/src/util.1.js b/components/vc-tree/src/util.1.js
deleted file mode 100644
index 9f1b2c1c4..000000000
--- a/components/vc-tree/src/util.1.js
+++ /dev/null
@@ -1,378 +0,0 @@
-/* eslint no-loop-func: 0*/
-import warning from 'warning'
-import { getSlotOptions, getOptionProps } from '../../_util/props-util'
-const DRAG_SIDE_RANGE = 0.25
-const DRAG_MIN_GAP = 2
-
-let onlyTreeNodeWarned = false
-
-export function warnOnlyTreeNode () {
- if (onlyTreeNodeWarned) return
-
- onlyTreeNodeWarned = true
- warning(false, 'Tree only accept TreeNode as children.')
-}
-
-export function arrDel (list, value) {
- const clone = list.slice()
- const index = clone.indexOf(value)
- if (index >= 0) {
- clone.splice(index, 1)
- }
- return clone
-}
-
-export function arrAdd (list, value) {
- const clone = list.slice()
- if (clone.indexOf(value) === -1) {
- clone.push(value)
- }
- return clone
-}
-
-export function posToArr (pos) {
- return pos.split('-')
-}
-
-export function getPosition (level, index) {
- return `${level}-${index}`
-}
-
-export function isTreeNode (node) {
- return getSlotOptions(node).isTreeNode
-}
-
-export function getNodeChildren (children = []) {
- return children.filter(isTreeNode)
-}
-
-export function isCheckDisabled (node) {
- const { disabled, disableCheckbox } = getOptionProps(node) || {}
- return !!(disabled || disableCheckbox)
-}
-
-export function traverseTreeNodes (treeNodes, subTreeData, callback) {
- function processNode (node, index, parent) {
- const children = node ? node.componentOptions.children : treeNodes
- const pos = node ? getPosition(parent.pos, index) : 0
-
- // Filter children
- const childList = getNodeChildren(children)
-
- // Process node if is not root
- if (node) {
- const data = {
- node,
- index,
- pos,
- key: node.key || pos,
- parentPos: parent.node ? parent.pos : null,
- }
- callback(data)
- }
-
- // Process children node
- childList.forEach((subNode, subIndex) => {
- processNode(subNode, subIndex, { node, pos })
- })
- }
-
- processNode(null)
-}
-
-/**
- * Use `rc-util` `toArray` to get the children list which keeps the key.
- * And return single node if children is only one(This can avoid `key` missing check).
- */
-export function mapChildren (children = [], func) {
- const list = children.map(func)
- if (list.length === 1) {
- return list[0]
- }
- return list
-}
-
-/**
- * [Legacy] Return halfChecked when it has value.
- * @param checkedKeys
- * @param halfChecked
- * @returns {*}
- */
-export function getStrictlyValue (checkedKeys, halfChecked) {
- if (halfChecked) {
- return { checked: checkedKeys, halfChecked }
- }
- return checkedKeys
-}
-
-export function getFullKeyList (treeNodes) {
- const keyList = []
- traverseTreeNodes(treeNodes, ({ key }) => {
- keyList.push(key)
- })
- return keyList
-}
-
-/**
- * Check position relation.
- * @param parentPos
- * @param childPos
- * @param directly only directly parent can be true
- * @returns {boolean}
- */
-export function isParent (parentPos, childPos, directly = false) {
- if (!parentPos || !childPos || parentPos.length > childPos.length) return false
-
- const parentPath = posToArr(parentPos)
- const childPath = posToArr(childPos)
-
- // Directly check
- if (directly && parentPath.length !== childPath.length - 1) return false
-
- const len = parentPath.length
- for (let i = 0; i < len; i += 1) {
- if (parentPath[i] !== childPath[i]) return false
- }
-
- return true
-}
-
-/**
- * Statistic TreeNodes info
- * @param treeNodes
- * @returns {{}}
- */
-export function getNodesStatistic (treeNodes) {
- const statistic = {
- keyNodes: {},
- posNodes: {},
- nodeList: [],
- }
-
- traverseTreeNodes(treeNodes, true, ({ node, index, pos, key, subNodes, parentPos }) => {
- const data = { node, index, pos, key, subNodes, parentPos }
- statistic.keyNodes[key] = data
- statistic.posNodes[pos] = data
- statistic.nodeList.push(data)
- })
-
- return statistic
-}
-
-export function getDragNodesKeys (treeNodes, node) {
- const { eventKey, pos } = getOptionProps(node)
- const dragNodesKeys = []
-
- traverseTreeNodes(treeNodes, ({ pos: nodePos, key }) => {
- if (isParent(pos, nodePos)) {
- dragNodesKeys.push(key)
- }
- })
- dragNodesKeys.push(eventKey || pos)
- return dragNodesKeys
-}
-
-export function calcDropPosition (event, treeNode) {
- const { clientY } = event
- const { top, bottom, height } = treeNode.$refs.selectHandle.getBoundingClientRect()
- const des = Math.max(height * DRAG_SIDE_RANGE, DRAG_MIN_GAP)
-
- if (clientY <= top + des) {
- return -1
- } else if (clientY >= bottom - des) {
- return 1
- }
- return 0
-}
-
-/**
- * Auto expand all related node when sub node is expanded
- * @param keyList
- * @param props
- * @returns [string]
- */
-export function calcExpandedKeys (keyList, props, children = []) {
- if (!keyList) {
- return []
- }
-
- // Fill parent expanded keys
- const { keyNodes, nodeList } = getNodesStatistic(children)
- const needExpandKeys = {}
- const needExpandPathList = []
-
- // Fill expanded nodes
- keyList.forEach((key) => {
- const node = keyNodes[key]
- if (node) {
- needExpandKeys[key] = true
- needExpandPathList.push(node.pos)
- }
- })
-
- // Match parent by path
- nodeList.forEach(({ pos, key }) => {
- if (needExpandPathList.some(childPos => isParent(pos, childPos))) {
- needExpandKeys[key] = true
- }
- })
-
- const calcExpandedKeyList = Object.keys(needExpandKeys)
-
- // [Legacy] Return origin keyList if calc list is empty
- return calcExpandedKeyList.length ? calcExpandedKeyList : keyList
-}
-
-/**
- * Return selectedKeys according with multiple prop
- * @param selectedKeys
- * @param props
- * @returns [string]
- */
-export function calcSelectedKeys (selectedKeys, props) {
- if (!selectedKeys) {
- return undefined
- }
-
- const { multiple } = props
- if (multiple) {
- return selectedKeys.slice()
- }
-
- if (selectedKeys.length) {
- return [selectedKeys[0]]
- }
- return selectedKeys
-}
-
-/**
- * Check conduct is by key level. It pass though up & down.
- * When conduct target node is check means already conducted will be skip.
- * @param treeNodes
- * @param checkedKeys
- * @returns {{checkedKeys: Array, halfCheckedKeys: Array}}
- */
-export function calcCheckStateConduct (treeNodes, checkedKeys) {
- const { keyNodes, posNodes } = getNodesStatistic(treeNodes)
-
- const tgtCheckedKeys = {}
- const tgtHalfCheckedKeys = {}
-
- // Conduct up
- function conductUp (key, halfChecked) {
- if (tgtCheckedKeys[key]) return
-
- const { subNodes = [], parentPos, node } = keyNodes[key]
- if (isCheckDisabled(node)) return
-
- const allSubChecked = !halfChecked && subNodes
- .filter(sub => !isCheckDisabled(sub.node))
- .every(sub => tgtCheckedKeys[sub.key])
-
- if (allSubChecked) {
- tgtCheckedKeys[key] = true
- } else {
- tgtHalfCheckedKeys[key] = true
- }
-
- if (parentPos !== null) {
- conductUp(posNodes[parentPos].key, !allSubChecked)
- }
- }
-
- // Conduct down
- function conductDown (key) {
- if (tgtCheckedKeys[key]) return
- const { subNodes = [], node } = keyNodes[key]
-
- if (isCheckDisabled(node)) return
-
- tgtCheckedKeys[key] = true
-
- subNodes.forEach((sub) => {
- conductDown(sub.key)
- })
- }
-
- function conduct (key) {
- if (!keyNodes[key]) {
- warning(false, `'${key}' does not exist in the tree.`)
- return
- }
-
- const { subNodes = [], parentPos, node } = keyNodes[key]
-
- tgtCheckedKeys[key] = true
-
- if (isCheckDisabled(node)) return
-
- // Conduct down
- subNodes
- .filter(sub => !isCheckDisabled(sub.node))
- .forEach((sub) => {
- conductDown(sub.key)
- })
-
- // Conduct up
- if (parentPos !== null) {
- conductUp(posNodes[parentPos].key)
- }
- }
-
- checkedKeys.forEach((key) => {
- conduct(key)
- })
-
- return {
- checkedKeys: Object.keys(tgtCheckedKeys),
- halfCheckedKeys: Object.keys(tgtHalfCheckedKeys)
- .filter(key => !tgtCheckedKeys[key]),
- }
-}
-
-function keyListToString (keyList) {
- if (!keyList) return keyList
- return keyList.map(key => String(key))
-}
-
-/**
- * Calculate the value of checked and halfChecked keys.
- * This should be only run in init or props changed.
- */
-export function calcCheckedKeys (keys, props, children = []) {
- const { checkable, checkStrictly } = props
-
- if (!checkable || !keys) {
- return null
- }
-
- // Convert keys to object format
- let keyProps
- if (Array.isArray(keys)) {
- // [Legacy] Follow the api doc
- keyProps = {
- checkedKeys: keys,
- halfCheckedKeys: undefined,
- }
- } else if (typeof keys === 'object') {
- keyProps = {
- checkedKeys: keys.checked || undefined,
- halfCheckedKeys: keys.halfChecked || undefined,
- }
- } else {
- warning(false, '`CheckedKeys` is not an array or an object')
- return null
- }
-
- keyProps.checkedKeys = keyListToString(keyProps.checkedKeys)
- keyProps.halfCheckedKeys = keyListToString(keyProps.halfCheckedKeys)
-
- // Do nothing if is checkStrictly mode
- if (checkStrictly) {
- return keyProps
- }
-
- // Conduct calculate the check status
- const { checkedKeys = [] } = keyProps
- return calcCheckStateConduct(children, checkedKeys)
-}