mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
refactor(components): [tree] remove ts-nocheck (#21097)
* chore: wip * chore: wip * chore: wip * chore: wip * chore: fix * chore: fix * chore: cleanup * chore: fix * fix: review Co-authored-by: btea <2356281422@qq.com> --------- Co-authored-by: btea <2356281422@qq.com>
This commit is contained in:
@@ -68,7 +68,7 @@ const append = (data: Data) => {
|
||||
|
||||
const remove = (node: Node, data: Data) => {
|
||||
const parent = node.parent
|
||||
const children: Tree[] = parent.data.children || parent.data
|
||||
const children: Tree[] = parent?.data.children || parent?.data
|
||||
const index = children.findIndex((d) => d.id === data.id)
|
||||
children.splice(index, 1)
|
||||
dataSource.value = [...dataSource.value]
|
||||
|
||||
@@ -5,11 +5,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { LoadFunction } from 'element-plus'
|
||||
|
||||
interface Tree {
|
||||
name: string
|
||||
leaf?: boolean
|
||||
}
|
||||
|
||||
const props = {
|
||||
label: 'name',
|
||||
children: 'zones',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck
|
||||
import { reactive } from 'vue'
|
||||
import { isNil } from 'lodash-unified'
|
||||
import {
|
||||
hasOwn,
|
||||
isArray,
|
||||
@@ -67,7 +67,7 @@ const reInitChecked = function (node: Node): void {
|
||||
const getPropertyFromData = function (node: Node, prop: string): any {
|
||||
const props = node.store.props
|
||||
const data = node.data || {}
|
||||
const config = props[prop]
|
||||
const config = (props as any)[prop]
|
||||
|
||||
if (isFunction(config)) {
|
||||
return config(data, node)
|
||||
@@ -83,17 +83,17 @@ let nodeIdSeed = 0
|
||||
|
||||
class Node {
|
||||
id: number
|
||||
text: string
|
||||
text: string | null
|
||||
checked: boolean
|
||||
indeterminate: boolean
|
||||
data: TreeNodeData
|
||||
expanded: boolean
|
||||
parent: Node
|
||||
parent: Node | null
|
||||
visible: boolean
|
||||
isCurrent: boolean
|
||||
store: TreeStore
|
||||
isLeafByUser: boolean
|
||||
isLeaf: boolean
|
||||
store!: TreeStore
|
||||
isLeafByUser: boolean | undefined = undefined
|
||||
isLeaf: boolean | undefined = undefined
|
||||
canFocus: boolean
|
||||
|
||||
level: number
|
||||
@@ -106,9 +106,9 @@ class Node {
|
||||
this.text = null
|
||||
this.checked = false
|
||||
this.indeterminate = false
|
||||
this.data = null
|
||||
this.data = null as unknown as TreeNodeData
|
||||
this.expanded = false
|
||||
this.parent = null
|
||||
this.parent = null as Node | null
|
||||
this.visible = true
|
||||
this.isCurrent = false
|
||||
this.canFocus = false
|
||||
@@ -168,7 +168,12 @@ class Node {
|
||||
const defaultExpandedKeys = store.defaultExpandedKeys
|
||||
const key = store.key
|
||||
|
||||
if (key && defaultExpandedKeys && defaultExpandedKeys.includes(this.key)) {
|
||||
if (
|
||||
key &&
|
||||
!isNil(this.key) &&
|
||||
defaultExpandedKeys &&
|
||||
defaultExpandedKeys.includes(this.key)
|
||||
) {
|
||||
this.expand(null, store.autoExpandParent)
|
||||
}
|
||||
|
||||
@@ -186,8 +191,7 @@ class Node {
|
||||
}
|
||||
|
||||
this.updateLeafState()
|
||||
if (this.parent && (this.level === 1 || this.parent.expanded === true))
|
||||
this.canFocus = true
|
||||
if (this.level === 1 || this.parent?.expanded === true) this.canFocus = true
|
||||
}
|
||||
|
||||
setData(data: TreeNodeData): void {
|
||||
@@ -214,7 +218,7 @@ class Node {
|
||||
return getPropertyFromData(this, 'label')
|
||||
}
|
||||
|
||||
get key(): TreeKey {
|
||||
get key(): TreeKey | null | undefined {
|
||||
const nodeKey = this.store.key
|
||||
if (this.data) return this.data[nodeKey]
|
||||
return null
|
||||
@@ -265,11 +269,11 @@ class Node {
|
||||
if (!(child instanceof Node)) {
|
||||
if (!batch) {
|
||||
const children = this.getChildren(true)
|
||||
if (!children.includes(child.data)) {
|
||||
if (!children?.includes(child.data)) {
|
||||
if (isUndefined(index) || index < 0) {
|
||||
children.push(child.data)
|
||||
children?.push(child.data)
|
||||
} else {
|
||||
children.splice(index, 0, child.data)
|
||||
children?.splice(index, 0, child.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,8 +333,8 @@ class Node {
|
||||
this.updateLeafState()
|
||||
}
|
||||
|
||||
removeChildByData(data: TreeNodeData): void {
|
||||
let targetNode: Node = null
|
||||
removeChildByData(data: TreeNodeData | null): void {
|
||||
let targetNode: Node | null = null
|
||||
|
||||
for (let i = 0; i < this.childNodes.length; i++) {
|
||||
if (this.childNodes[i].data === data) {
|
||||
@@ -344,11 +348,11 @@ class Node {
|
||||
}
|
||||
}
|
||||
|
||||
expand(callback?: () => void, expandParent?: boolean): void {
|
||||
const done = (): void => {
|
||||
expand(callback?: (() => void) | null, expandParent?: boolean): void {
|
||||
const done = () => {
|
||||
if (expandParent) {
|
||||
let parent = this.parent
|
||||
while (parent.level > 0) {
|
||||
while (parent && parent.level > 0) {
|
||||
parent.expanded = true
|
||||
parent = parent.parent
|
||||
}
|
||||
@@ -396,8 +400,8 @@ class Node {
|
||||
})
|
||||
}
|
||||
|
||||
shouldLoadData(): boolean {
|
||||
return this.store.lazy === true && this.store.load && !this.loaded
|
||||
shouldLoadData() {
|
||||
return Boolean(this.store.lazy === true && this.store.load && !this.loaded)
|
||||
}
|
||||
|
||||
updateLeafState(): void {
|
||||
@@ -481,7 +485,7 @@ class Node {
|
||||
}
|
||||
}
|
||||
|
||||
getChildren(forceInit = false): TreeNodeData | TreeNodeData[] {
|
||||
getChildren(forceInit = false): TreeNodeData | TreeNodeData[] | null {
|
||||
// this is data
|
||||
if (this.level === 0) return this.data
|
||||
const data = this.data
|
||||
@@ -508,13 +512,13 @@ class Node {
|
||||
const newData = (this.getChildren() || []) as TreeNodeData[]
|
||||
const oldData = this.childNodes.map((node) => node.data)
|
||||
|
||||
const newDataMap = {}
|
||||
const newNodes = []
|
||||
const newDataMap: Record<TreeKey, TreeNodeData> = {}
|
||||
const newNodes: TreeNodeData[] = []
|
||||
|
||||
newData.forEach((item, index) => {
|
||||
const key = item[NODE_KEY]
|
||||
const isNodeExists =
|
||||
!!key && oldData.findIndex((data) => data[NODE_KEY] === key) >= 0
|
||||
!!key && oldData.findIndex((data) => data?.[NODE_KEY] === key) >= 0
|
||||
if (isNodeExists) {
|
||||
newDataMap[key] = { index, data: item }
|
||||
} else {
|
||||
@@ -524,7 +528,7 @@ class Node {
|
||||
|
||||
if (!this.store.lazy) {
|
||||
oldData.forEach((item) => {
|
||||
if (!newDataMap[item[NODE_KEY]]) this.removeChildByData(item)
|
||||
if (!newDataMap[item?.[NODE_KEY]]) this.removeChildByData(item)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -536,7 +540,7 @@ class Node {
|
||||
}
|
||||
|
||||
loadData(
|
||||
callback: (node: Node) => void,
|
||||
callback: (data?: TreeNodeData[]) => void,
|
||||
defaultProps: TreeNodeLoadedDefaultProps = {}
|
||||
) {
|
||||
if (
|
||||
@@ -547,7 +551,7 @@ class Node {
|
||||
) {
|
||||
this.loading = true
|
||||
|
||||
const resolve = (children) => {
|
||||
const resolve = (children: TreeNodeData[]) => {
|
||||
this.childNodes = []
|
||||
|
||||
this.doCreateChildren(children, defaultProps)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @ts-nocheck
|
||||
import { nextTick } from 'vue'
|
||||
import { hasOwn, isObject, isPropAbsent } from '@element-plus/utils'
|
||||
import { isNil } from 'lodash-unified'
|
||||
import { NOOP, hasOwn, isObject, isPropAbsent } from '@element-plus/utils'
|
||||
import Node from './node'
|
||||
import { getNodeKey } from './util'
|
||||
|
||||
@@ -17,22 +17,22 @@ import type {
|
||||
} from '../tree.type'
|
||||
|
||||
export default class TreeStore {
|
||||
currentNode: Node
|
||||
currentNodeKey: TreeKey
|
||||
currentNode: Node | null
|
||||
currentNodeKey: TreeKey | null
|
||||
nodesMap: TreeStoreNodesMap
|
||||
root: Node
|
||||
data: TreeData
|
||||
lazy: boolean
|
||||
load: LoadFunction
|
||||
filterNodeMethod: FilterNodeMethodFunction
|
||||
key: TreeKey
|
||||
defaultCheckedKeys: TreeKey[]
|
||||
checkStrictly: boolean
|
||||
defaultExpandedKeys: TreeKey[]
|
||||
autoExpandParent: boolean
|
||||
defaultExpandAll: boolean
|
||||
checkDescendants: boolean
|
||||
props: TreeOptionProps
|
||||
root!: Node
|
||||
data!: TreeData
|
||||
lazy = false
|
||||
load?: LoadFunction
|
||||
filterNodeMethod?: FilterNodeMethodFunction
|
||||
key!: TreeKey
|
||||
defaultCheckedKeys?: TreeKey[]
|
||||
checkStrictly = false
|
||||
defaultExpandedKeys?: TreeKey[]
|
||||
autoExpandParent = false
|
||||
defaultExpandAll = false
|
||||
checkDescendants = false
|
||||
props!: TreeOptionProps
|
||||
|
||||
constructor(options: TreeStoreOptions) {
|
||||
this.currentNode = null
|
||||
@@ -56,10 +56,14 @@ export default class TreeStore {
|
||||
|
||||
if (this.lazy && this.load) {
|
||||
const loadFn = this.load
|
||||
loadFn(this.root, (data) => {
|
||||
this.root.doCreateChildren(data)
|
||||
this._initDefaultCheckedNodes()
|
||||
})
|
||||
loadFn(
|
||||
this.root,
|
||||
(data) => {
|
||||
this.root.doCreateChildren(data)
|
||||
this._initDefaultCheckedNodes()
|
||||
},
|
||||
NOOP
|
||||
)
|
||||
} else {
|
||||
this._initDefaultCheckedNodes()
|
||||
}
|
||||
@@ -74,7 +78,12 @@ export default class TreeStore {
|
||||
: (node as Node).childNodes
|
||||
|
||||
for (const [index, child] of childNodes.entries()) {
|
||||
child.visible = filterNodeMethod.call(child, value, child.data, child)
|
||||
child.visible = !!filterNodeMethod?.call(
|
||||
child,
|
||||
value,
|
||||
child.data,
|
||||
child
|
||||
)
|
||||
|
||||
if (index % 80 === 0 && index > 0) {
|
||||
await nextTick()
|
||||
@@ -95,7 +104,7 @@ export default class TreeStore {
|
||||
if (!value) return
|
||||
|
||||
if ((node as Node).visible && !(node as Node).isLeaf) {
|
||||
if (!lazy || node.loaded) {
|
||||
if (!lazy || (node as Node).loaded) {
|
||||
;(node as Node).expand()
|
||||
}
|
||||
}
|
||||
@@ -127,7 +136,7 @@ export default class TreeStore {
|
||||
refData: TreeKey | TreeNodeData | Node
|
||||
): void {
|
||||
const refNode = this.getNode(refData)
|
||||
refNode.parent.insertBefore({ data }, refNode)
|
||||
refNode.parent?.insertBefore({ data }, refNode)
|
||||
}
|
||||
|
||||
insertAfter(
|
||||
@@ -135,7 +144,7 @@ export default class TreeStore {
|
||||
refData: TreeKey | TreeNodeData | Node
|
||||
): void {
|
||||
const refNode = this.getNode(refData)
|
||||
refNode.parent.insertAfter({ data }, refNode)
|
||||
refNode.parent?.insertAfter({ data }, refNode)
|
||||
}
|
||||
|
||||
remove(data: TreeNodeData | Node): void {
|
||||
@@ -175,7 +184,7 @@ export default class TreeStore {
|
||||
_initDefaultCheckedNode(node: Node): void {
|
||||
const defaultCheckedKeys = this.defaultCheckedKeys || []
|
||||
|
||||
if (defaultCheckedKeys.includes(node.key)) {
|
||||
if (!isNil(node.key) && defaultCheckedKeys.includes(node.key)) {
|
||||
node.setChecked(true, !this.checkStrictly)
|
||||
}
|
||||
}
|
||||
@@ -195,7 +204,7 @@ export default class TreeStore {
|
||||
this.nodesMap[node.id] = node
|
||||
} else {
|
||||
const nodeKey = node.key
|
||||
if (nodeKey !== undefined) this.nodesMap[node.key] = node
|
||||
if (!isNil(nodeKey)) this.nodesMap[nodeKey] = node
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +216,7 @@ export default class TreeStore {
|
||||
this.deregisterNode(child)
|
||||
})
|
||||
|
||||
delete this.nodesMap[node.key]
|
||||
delete this.nodesMap[node.key!]
|
||||
}
|
||||
|
||||
getCheckedNodes(
|
||||
@@ -296,12 +305,12 @@ export default class TreeStore {
|
||||
key: TreeKey,
|
||||
leafOnly = false,
|
||||
checkedKeys: { [key: string]: boolean }
|
||||
): void {
|
||||
) {
|
||||
const allNodes = this._getAllNodes().sort((a, b) => a.level - b.level)
|
||||
const cache = Object.create(null)
|
||||
const cache: Record<TreeKey, boolean> = Object.create(null)
|
||||
const keys = Object.keys(checkedKeys)
|
||||
allNodes.forEach((node) => node.setChecked(false, false))
|
||||
const cacheCheckedChild = (node) => {
|
||||
const cacheCheckedChild = (node: Node) => {
|
||||
node.childNodes.forEach((child) => {
|
||||
cache[child.data[key]] = true
|
||||
if (child.childNodes?.length) {
|
||||
@@ -311,7 +320,7 @@ export default class TreeStore {
|
||||
}
|
||||
for (let i = 0, j = allNodes.length; i < j; i++) {
|
||||
const node = allNodes[i]
|
||||
const nodeKey = node.data[key].toString()
|
||||
const nodeKey: string = node.data[key].toString()
|
||||
const checked = keys.includes(nodeKey)
|
||||
if (!checked) {
|
||||
if (node.checked && !cache[nodeKey]) {
|
||||
@@ -348,9 +357,9 @@ export default class TreeStore {
|
||||
|
||||
setCheckedNodes(array: Node[], leafOnly = false): void {
|
||||
const key = this.key
|
||||
const checkedKeys = {}
|
||||
const checkedKeys: Record<TreeKey, boolean> = {}
|
||||
array.forEach((item) => {
|
||||
checkedKeys[(item || {})[key]] = true
|
||||
checkedKeys[((item || {}) as any)[key]] = true
|
||||
})
|
||||
|
||||
this._setCheckedKeys(key, leafOnly, checkedKeys)
|
||||
@@ -359,7 +368,7 @@ export default class TreeStore {
|
||||
setCheckedKeys(keys: TreeKey[], leafOnly = false): void {
|
||||
this.defaultCheckedKeys = keys
|
||||
const key = this.key
|
||||
const checkedKeys = {}
|
||||
const checkedKeys: Record<TreeKey, boolean> = {}
|
||||
keys.forEach((key) => {
|
||||
checkedKeys[key] = true
|
||||
})
|
||||
@@ -388,7 +397,7 @@ export default class TreeStore {
|
||||
}
|
||||
}
|
||||
|
||||
getCurrentNode(): Node {
|
||||
getCurrentNode() {
|
||||
return this.currentNode
|
||||
}
|
||||
|
||||
@@ -402,15 +411,19 @@ export default class TreeStore {
|
||||
}
|
||||
|
||||
setUserCurrentNode(node: Node, shouldAutoExpandParent = true): void {
|
||||
const key = node[this.key]
|
||||
const key = (node as any)[this.key]
|
||||
const currNode = this.nodesMap[key]
|
||||
this.setCurrentNode(currNode)
|
||||
if (shouldAutoExpandParent && this.currentNode.level > 1) {
|
||||
this.currentNode.parent.expand(null, true)
|
||||
if (
|
||||
shouldAutoExpandParent &&
|
||||
this.currentNode &&
|
||||
this.currentNode.level > 1
|
||||
) {
|
||||
this.currentNode.parent?.expand(null, true)
|
||||
}
|
||||
}
|
||||
|
||||
setCurrentNodeKey(key?: TreeKey, shouldAutoExpandParent = true): void {
|
||||
setCurrentNodeKey(key: TreeKey | null, shouldAutoExpandParent = true): void {
|
||||
this.currentNodeKey = key
|
||||
if (isPropAbsent(key)) {
|
||||
this.currentNode && (this.currentNode.isCurrent = false)
|
||||
@@ -420,8 +433,12 @@ export default class TreeStore {
|
||||
const node = this.getNode(key)
|
||||
if (node) {
|
||||
this.setCurrentNode(node)
|
||||
if (shouldAutoExpandParent && this.currentNode.level > 1) {
|
||||
this.currentNode.parent.expand(null, true)
|
||||
if (
|
||||
shouldAutoExpandParent &&
|
||||
this.currentNode &&
|
||||
this.currentNode.level > 1
|
||||
) {
|
||||
this.currentNode.parent?.expand(null, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
// @ts-nocheck
|
||||
import { provide, ref } from 'vue'
|
||||
import { addClass, isFunction, removeClass } from '@element-plus/utils'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
|
||||
import type { InjectionKey } from 'vue'
|
||||
import type { InjectionKey, Ref, SetupContext } from 'vue'
|
||||
import type {
|
||||
AllowDragFunction,
|
||||
AllowDropFunction,
|
||||
FakeNode,
|
||||
NodeDropType,
|
||||
} from '../tree.type'
|
||||
import type TreeStore from './tree-store'
|
||||
import type Node from './node'
|
||||
import type { NodeDropType } from '../tree.type'
|
||||
|
||||
interface TreeNode {
|
||||
node: Node
|
||||
@@ -17,6 +22,17 @@ interface DragOptions {
|
||||
treeNode: TreeNode
|
||||
}
|
||||
|
||||
interface Props {
|
||||
props: {
|
||||
allowDrag?: AllowDragFunction
|
||||
allowDrop?: AllowDropFunction
|
||||
}
|
||||
ctx: SetupContext<string[]>
|
||||
el$: Ref<HTMLElement | null>
|
||||
dropIndicator$: Ref<HTMLElement | null>
|
||||
store: Ref<TreeStore>
|
||||
}
|
||||
|
||||
export interface DragEvents {
|
||||
treeNodeDragStart: (options: DragOptions) => void
|
||||
treeNodeDragOver: (options: DragOptions) => void
|
||||
@@ -25,9 +41,21 @@ export interface DragEvents {
|
||||
|
||||
export const dragEventsKey: InjectionKey<DragEvents> = Symbol('dragEvents')
|
||||
|
||||
export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
export function useDragNodeHandler({
|
||||
props,
|
||||
ctx,
|
||||
el$,
|
||||
dropIndicator$,
|
||||
store,
|
||||
}: Props) {
|
||||
const ns = useNamespace('tree')
|
||||
const dragState = ref({
|
||||
const dragState = ref<{
|
||||
allowDrop: boolean
|
||||
dropType: NodeDropType | null
|
||||
draggingNode: TreeNode | null
|
||||
showDropIndicator: boolean
|
||||
dropNode: TreeNode | null
|
||||
}>({
|
||||
showDropIndicator: false,
|
||||
draggingNode: null,
|
||||
dropNode: null,
|
||||
@@ -36,6 +64,7 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
})
|
||||
|
||||
const treeNodeDragStart = ({ event, treeNode }: DragOptions) => {
|
||||
if (!event.dataTransfer) return
|
||||
if (isFunction(props.allowDrag) && !props.allowDrag(treeNode.node)) {
|
||||
event.preventDefault()
|
||||
return false
|
||||
@@ -53,10 +82,11 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
}
|
||||
|
||||
const treeNodeDragOver = ({ event, treeNode }: DragOptions) => {
|
||||
if (!event.dataTransfer) return
|
||||
const dropNode = treeNode
|
||||
const oldDropNode = dragState.value.dropNode
|
||||
if (oldDropNode && oldDropNode.node.id !== dropNode.node.id) {
|
||||
removeClass(oldDropNode.$el, ns.is('drop-inner'))
|
||||
removeClass(oldDropNode.$el!, ns.is('drop-inner'))
|
||||
}
|
||||
const draggingNode = dragState.value.draggingNode
|
||||
if (!draggingNode || !dropNode) return
|
||||
@@ -110,12 +140,13 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
dropInner = false
|
||||
dropNext = false
|
||||
}
|
||||
const dropEl = dropNode.$el!
|
||||
|
||||
// find target node without children, just calc content node height
|
||||
const targetPosition = dropNode.$el
|
||||
.querySelector(`.${ns.be('node', 'content')}`)
|
||||
const targetPosition = dropEl
|
||||
.querySelector(`.${ns.be('node', 'content')}`)!
|
||||
.getBoundingClientRect()
|
||||
const treePosition = el$.value.getBoundingClientRect()
|
||||
const treePosition = el$.value!.getBoundingClientRect()
|
||||
|
||||
let dropType: NodeDropType
|
||||
const prevPercent = dropPrev ? (dropInner ? 0.25 : dropNext ? 0.45 : 1) : -1
|
||||
@@ -133,8 +164,8 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
dropType = 'none'
|
||||
}
|
||||
|
||||
const iconPosition = dropNode.$el
|
||||
.querySelector(`.${ns.be('node', 'expand-icon')}`)
|
||||
const iconPosition = dropEl
|
||||
.querySelector(`.${ns.be('node', 'expand-icon')}`)!
|
||||
.getBoundingClientRect()
|
||||
const dropIndicator = dropIndicator$.value
|
||||
if (dropType === 'before') {
|
||||
@@ -142,13 +173,13 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
} else if (dropType === 'after') {
|
||||
indicatorTop = iconPosition.bottom - treePosition.top
|
||||
}
|
||||
dropIndicator.style.top = `${indicatorTop}px`
|
||||
dropIndicator.style.left = `${iconPosition.right - treePosition.left}px`
|
||||
dropIndicator!.style.top = `${indicatorTop}px`
|
||||
dropIndicator!.style.left = `${iconPosition.right - treePosition.left}px`
|
||||
|
||||
if (dropType === 'inner') {
|
||||
addClass(dropNode.$el, ns.is('drop-inner'))
|
||||
addClass(dropEl, ns.is('drop-inner'))
|
||||
} else {
|
||||
removeClass(dropNode.$el, ns.is('drop-inner'))
|
||||
removeClass(dropEl, ns.is('drop-inner'))
|
||||
}
|
||||
|
||||
dragState.value.showDropIndicator =
|
||||
@@ -168,20 +199,20 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
event.dataTransfer.dropEffect = 'move'
|
||||
}
|
||||
|
||||
if (draggingNode && dropNode) {
|
||||
const draggingNodeCopy = { data: draggingNode.node.data }
|
||||
if (draggingNode?.node.data && dropNode) {
|
||||
const draggingNodeCopy: FakeNode = { data: draggingNode.node.data }
|
||||
if (dropType !== 'none') {
|
||||
draggingNode.node.remove()
|
||||
}
|
||||
if (dropType === 'before') {
|
||||
dropNode.node.parent.insertBefore(draggingNodeCopy, dropNode.node)
|
||||
dropNode.node.parent?.insertBefore(draggingNodeCopy, dropNode.node)
|
||||
} else if (dropType === 'after') {
|
||||
dropNode.node.parent.insertAfter(draggingNodeCopy, dropNode.node)
|
||||
dropNode.node.parent?.insertAfter(draggingNodeCopy, dropNode.node)
|
||||
} else if (dropType === 'inner') {
|
||||
dropNode.node.insertChild(draggingNodeCopy)
|
||||
}
|
||||
if (dropType !== 'none') {
|
||||
store.value.registerNode(draggingNodeCopy)
|
||||
store.value.registerNode(draggingNodeCopy as any)
|
||||
if (store.value.key) {
|
||||
//restore checkbox state after dragging
|
||||
draggingNode.node.eachNode((node) => {
|
||||
@@ -193,7 +224,7 @@ export function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {
|
||||
}
|
||||
}
|
||||
|
||||
removeClass(dropNode.$el, ns.is('drop-inner'))
|
||||
removeClass(dropNode.$el!, ns.is('drop-inner'))
|
||||
|
||||
ctx.emit(
|
||||
'node-drag-end',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck
|
||||
import { onMounted, onUpdated } from 'vue'
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
import { EVENT_CODE } from '@element-plus/constants'
|
||||
@@ -9,7 +8,7 @@ import type { Ref } from 'vue'
|
||||
import type { Nullable } from '@element-plus/utils'
|
||||
|
||||
interface UseKeydownOption {
|
||||
el$: Ref<HTMLElement>
|
||||
el$: Ref<HTMLElement | null>
|
||||
}
|
||||
export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
const ns = useNamespace('tree')
|
||||
@@ -20,7 +19,7 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
|
||||
onUpdated(() => {
|
||||
const checkboxItems = Array.from(
|
||||
el$.value.querySelectorAll('input[type=checkbox]')
|
||||
el$.value!.querySelectorAll('input[type=checkbox]')
|
||||
)
|
||||
checkboxItems.forEach((checkbox) => {
|
||||
checkbox.setAttribute('tabindex', '-1')
|
||||
@@ -28,11 +27,11 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
})
|
||||
|
||||
const handleKeydown = (ev: KeyboardEvent): void => {
|
||||
const currentItem = ev.target as HTMLElement
|
||||
const currentItem = ev.target as HTMLDivElement
|
||||
if (!currentItem.className.includes(ns.b('node'))) return
|
||||
const code = ev.code
|
||||
const treeItems = Array.from(
|
||||
el$.value.querySelectorAll(`.${ns.is('focusable')}[role=treeitem]`)
|
||||
const treeItems: HTMLElement[] = Array.from(
|
||||
el$.value!.querySelectorAll(`.${ns.is('focusable')}[role=treeitem]`)
|
||||
)
|
||||
const currentIndex = treeItems.indexOf(currentItem)
|
||||
let nextIndex
|
||||
@@ -47,7 +46,7 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
: treeItems.length - 1
|
||||
const startIndex = nextIndex
|
||||
while (true) {
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key).canFocus)
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key!).canFocus)
|
||||
break
|
||||
nextIndex--
|
||||
if (nextIndex === startIndex) {
|
||||
@@ -67,7 +66,7 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
: 0
|
||||
const startIndex = nextIndex
|
||||
while (true) {
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key).canFocus)
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key!).canFocus)
|
||||
break
|
||||
nextIndex++
|
||||
if (nextIndex === startIndex) {
|
||||
@@ -102,6 +101,7 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
useEventListener(el$, 'keydown', handleKeydown)
|
||||
|
||||
const initTabIndex = (): void => {
|
||||
if (!el$.value) return
|
||||
const treeItems = Array.from(
|
||||
el$.value.querySelectorAll(`.${ns.is('focusable')}[role=treeitem]`)
|
||||
)
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
// @ts-nocheck
|
||||
import { inject, provide } from 'vue'
|
||||
import { TREE_NODE_MAP_INJECTION_KEY } from '../tokens'
|
||||
|
||||
import type Node from '../model/node'
|
||||
|
||||
interface NodeMap {
|
||||
treeNodeExpand(node: Node): void
|
||||
treeNodeExpand(node?: Node): void
|
||||
children: NodeMap[]
|
||||
}
|
||||
|
||||
export function useNodeExpandEventBroadcast(props) {
|
||||
const parentNodeMap = inject<NodeMap>(TREE_NODE_MAP_INJECTION_KEY, null)
|
||||
interface Props {
|
||||
node?: Node
|
||||
accordion: boolean
|
||||
}
|
||||
|
||||
export function useNodeExpandEventBroadcast(props: Props) {
|
||||
const parentNodeMap = inject(
|
||||
TREE_NODE_MAP_INJECTION_KEY,
|
||||
null
|
||||
) as NodeMap | null
|
||||
const currentNodeMap: NodeMap = {
|
||||
treeNodeExpand: (node) => {
|
||||
if (props.node !== node) {
|
||||
props.node.collapse()
|
||||
props.node?.collapse()
|
||||
}
|
||||
},
|
||||
children: [],
|
||||
@@ -27,7 +34,7 @@ export function useNodeExpandEventBroadcast(props) {
|
||||
provide(TREE_NODE_MAP_INJECTION_KEY, currentNodeMap)
|
||||
|
||||
return {
|
||||
broadcastExpanded: (node: Node): void => {
|
||||
broadcastExpanded: (node?: Node): void => {
|
||||
if (!props.accordion) return
|
||||
for (const childNode of currentNodeMap.children) {
|
||||
childNode.treeNodeExpand(node)
|
||||
|
||||
@@ -4,7 +4,10 @@ import type { RootTreeType, TreeKey, TreeNodeData } from '../tree.type'
|
||||
|
||||
export const NODE_KEY = '$treeNodeId'
|
||||
|
||||
export const markNodeData = function (node: Node, data: TreeNodeData): void {
|
||||
export const markNodeData = function (
|
||||
node: Node,
|
||||
data: TreeNodeData | null
|
||||
): void {
|
||||
if (!data || data[NODE_KEY]) return
|
||||
Object.defineProperty(data, NODE_KEY, {
|
||||
value: node.id,
|
||||
@@ -14,7 +17,7 @@ export const markNodeData = function (node: Node, data: TreeNodeData): void {
|
||||
})
|
||||
}
|
||||
|
||||
export const getNodeKey = (key: TreeKey, data: TreeNodeData) =>
|
||||
export const getNodeKey = (key: TreeKey | undefined, data: TreeNodeData) =>
|
||||
data?.[key || NODE_KEY]
|
||||
|
||||
export const handleCurrentChange = (
|
||||
|
||||
@@ -43,19 +43,19 @@ export interface TreeStoreNodesMap {
|
||||
[key: string]: Node
|
||||
}
|
||||
export interface TreeStoreOptions {
|
||||
key: TreeKey
|
||||
key?: TreeKey
|
||||
data: TreeData
|
||||
lazy: boolean
|
||||
props: TreeOptionProps
|
||||
load: LoadFunction
|
||||
currentNodeKey: TreeKey
|
||||
load?: LoadFunction
|
||||
currentNodeKey?: TreeKey
|
||||
checkStrictly: boolean
|
||||
checkDescendants: boolean
|
||||
defaultCheckedKeys: TreeKey[]
|
||||
defaultExpandedKeys: TreeKey[]
|
||||
defaultCheckedKeys?: TreeKey[]
|
||||
defaultExpandedKeys?: TreeKey[]
|
||||
autoExpandParent: boolean
|
||||
defaultExpandAll: boolean
|
||||
filterNodeMethod: FilterNodeMethodFunction
|
||||
filterNodeMethod?: FilterNodeMethodFunction
|
||||
}
|
||||
export interface TreeOptionProps {
|
||||
children?: string
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
@@ -47,7 +46,7 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import { iconPropType } from '@element-plus/utils'
|
||||
import { definePropType, iconPropType } from '@element-plus/utils'
|
||||
import { useLocale, useNamespace } from '@element-plus/hooks'
|
||||
import { formItemContextKey } from '@element-plus/components/form'
|
||||
import { selectKey } from '@element-plus/components/select/src/token'
|
||||
@@ -63,6 +62,10 @@ import type Node from './model/node'
|
||||
import type { ComponentInternalInstance, PropType } from 'vue'
|
||||
import type { Nullable } from '@element-plus/utils'
|
||||
import type {
|
||||
AllowDragFunction,
|
||||
AllowDropFunction,
|
||||
FilterValue,
|
||||
RenderContentFunction,
|
||||
TreeComponentProps,
|
||||
TreeData,
|
||||
TreeKey,
|
||||
@@ -74,7 +77,7 @@ export default defineComponent({
|
||||
components: { ElTreeNode },
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
type: definePropType<TreeData>(Array),
|
||||
default: () => [],
|
||||
},
|
||||
emptyText: {
|
||||
@@ -111,7 +114,9 @@ export default defineComponent({
|
||||
TreeComponentProps['defaultExpandedKeys']
|
||||
>,
|
||||
currentNodeKey: [String, Number] as PropType<string | number>,
|
||||
renderContent: Function,
|
||||
renderContent: {
|
||||
type: definePropType<RenderContentFunction>(Function),
|
||||
},
|
||||
showCheckbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -120,8 +125,12 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
allowDrag: Function,
|
||||
allowDrop: Function,
|
||||
allowDrag: {
|
||||
type: definePropType<AllowDragFunction>(Function),
|
||||
},
|
||||
allowDrop: {
|
||||
type: definePropType<AllowDropFunction>(Function),
|
||||
},
|
||||
props: {
|
||||
type: Object as PropType<TreeComponentProps['props']>,
|
||||
default: () => ({
|
||||
@@ -162,7 +171,7 @@ export default defineComponent({
|
||||
'node-drag-leave',
|
||||
'node-drag-enter',
|
||||
'node-drag-over',
|
||||
],
|
||||
] as string[],
|
||||
setup(props, ctx) {
|
||||
const { t } = useLocale()
|
||||
const ns = useNamespace('tree')
|
||||
@@ -189,7 +198,7 @@ export default defineComponent({
|
||||
store.value.initialize()
|
||||
|
||||
const root = ref<Node>(store.value.root)
|
||||
const currentNode = ref<Node>(null)
|
||||
const currentNode = ref<Node | null>(null)
|
||||
const el$ = ref<Nullable<HTMLElement>>(null)
|
||||
const dropIndicator$ = ref<Nullable<HTMLElement>>(null)
|
||||
|
||||
@@ -208,7 +217,7 @@ export default defineComponent({
|
||||
const isEmpty = computed(() => {
|
||||
const { childNodes } = root.value
|
||||
const hasFilteredOptions = selectInfo
|
||||
? selectInfo.hasFilteredOptions !== 0
|
||||
? (selectInfo as any).hasFilteredOptions !== 0
|
||||
: false
|
||||
return (
|
||||
(!childNodes ||
|
||||
@@ -221,21 +230,21 @@ export default defineComponent({
|
||||
watch(
|
||||
() => props.currentNodeKey,
|
||||
(newVal) => {
|
||||
store.value.setCurrentNodeKey(newVal)
|
||||
store.value.setCurrentNodeKey(newVal ?? null)
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.defaultCheckedKeys,
|
||||
(newVal) => {
|
||||
store.value.setDefaultCheckedKey(newVal)
|
||||
store.value.setDefaultCheckedKey(newVal ?? [])
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.defaultExpandedKeys,
|
||||
(newVal) => {
|
||||
store.value.setDefaultExpandedKeys(newVal)
|
||||
store.value.setDefaultExpandedKeys(newVal ?? [])
|
||||
}
|
||||
)
|
||||
|
||||
@@ -254,7 +263,7 @@ export default defineComponent({
|
||||
}
|
||||
)
|
||||
|
||||
const filter = (value) => {
|
||||
const filter = (value: FilterValue) => {
|
||||
if (!props.filterNodeMethod)
|
||||
throw new Error('[Tree] filterNodeMethod is required when filter')
|
||||
store.value.filter(value)
|
||||
@@ -289,12 +298,12 @@ export default defineComponent({
|
||||
return store.value.getCheckedKeys(leafOnly)
|
||||
}
|
||||
|
||||
const getCurrentNode = (): TreeNodeData => {
|
||||
const getCurrentNode = () => {
|
||||
const currentNode = store.value.getCurrentNode()
|
||||
return currentNode ? currentNode.data : null
|
||||
}
|
||||
|
||||
const getCurrentKey = (): any => {
|
||||
const getCurrentKey = (): TreeKey | null => {
|
||||
if (!props.nodeKey)
|
||||
throw new Error('[Tree] nodeKey is required in getCurrentKey')
|
||||
const currentNode = getCurrentNode()
|
||||
@@ -345,7 +354,7 @@ export default defineComponent({
|
||||
|
||||
handleCurrentChange(store, ctx.emit, () => {
|
||||
broadcastExpanded()
|
||||
store.value.setCurrentNodeKey(key, shouldAutoExpandParent)
|
||||
store.value.setCurrentNodeKey(key ?? null, shouldAutoExpandParent)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -400,7 +409,7 @@ export default defineComponent({
|
||||
root,
|
||||
currentNode,
|
||||
instance: getCurrentInstance(),
|
||||
} as any)
|
||||
})
|
||||
|
||||
provide(formItemContextKey, undefined)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user