{"version":3,"file":"useDragNode.mjs","sources":["../../../../../../../packages/components/tree/src/model/useDragNode.ts"],"sourcesContent":["import { provide, ref } from 'vue'\nimport { addClass, removeClass } from '@element-plus/utils/dom'\nimport type { InjectionKey } from 'vue'\nimport type Node from './node'\n\ninterface TreeNode {\n  node: Node\n  $el?: HTMLElement\n}\n\ninterface DragOptions {\n  event: DragEvent\n  treeNode: TreeNode\n}\n\nexport interface DragEvents {\n  treeNodeDragStart: (options: DragOptions) => void\n  treeNodeDragOver: (options: DragOptions) => void\n  treeNodeDragEnd: (event: DragEvent) => void\n}\n\nexport const dragEventsKey: InjectionKey<DragEvents> = Symbol('dragEvents')\n\nexport function useDragNodeHandler({ props, ctx, el$, dropIndicator$, store }) {\n  const dragState = ref({\n    showDropIndicator: false,\n    draggingNode: null,\n    dropNode: null,\n    allowDrop: true,\n    dropType: null,\n  })\n\n  const treeNodeDragStart = ({ event, treeNode }: DragOptions) => {\n    if (\n      typeof props.allowDrag === 'function' &&\n      !props.allowDrag(treeNode.node)\n    ) {\n      event.preventDefault()\n      return false\n    }\n    event.dataTransfer.effectAllowed = 'move'\n\n    // wrap in try catch to address IE's error when first param is 'text/plain'\n    try {\n      // setData is required for draggable to work in FireFox\n      // the content has to be '' so dragging a node out of the tree won't open a new tab in FireFox\n      event.dataTransfer.setData('text/plain', '')\n    } catch (e) {}\n    dragState.value.draggingNode = treeNode\n    ctx.emit('node-drag-start', treeNode.node, event)\n  }\n\n  const treeNodeDragOver = ({ event, treeNode }: DragOptions) => {\n    const dropNode = treeNode\n    const oldDropNode = dragState.value.dropNode\n    if (oldDropNode && oldDropNode !== dropNode) {\n      removeClass(oldDropNode.$el, 'is-drop-inner')\n    }\n    const draggingNode = dragState.value.draggingNode\n    if (!draggingNode || !dropNode) return\n\n    let dropPrev = true\n    let dropInner = true\n    let dropNext = true\n    let userAllowDropInner = true\n    if (typeof props.allowDrop === 'function') {\n      dropPrev = props.allowDrop(draggingNode.node, dropNode.node, 'prev')\n      userAllowDropInner = dropInner = props.allowDrop(\n        draggingNode.node,\n        dropNode.node,\n        'inner'\n      )\n      dropNext = props.allowDrop(draggingNode.node, dropNode.node, 'next')\n    }\n    event.dataTransfer.dropEffect = dropInner ? 'move' : 'none'\n    if ((dropPrev || dropInner || dropNext) && oldDropNode !== dropNode) {\n      if (oldDropNode) {\n        ctx.emit('node-drag-leave', draggingNode.node, oldDropNode.node, event)\n      }\n      ctx.emit('node-drag-enter', draggingNode.node, dropNode.node, event)\n    }\n\n    if (dropPrev || dropInner || dropNext) {\n      dragState.value.dropNode = dropNode\n    }\n\n    if (dropNode.node.nextSibling === draggingNode.node) {\n      dropNext = false\n    }\n    if (dropNode.node.previousSibling === draggingNode.node) {\n      dropPrev = false\n    }\n    if (dropNode.node.contains(draggingNode.node, false)) {\n      dropInner = false\n    }\n    if (\n      draggingNode.node === dropNode.node ||\n      draggingNode.node.contains(dropNode.node)\n    ) {\n      dropPrev = false\n      dropInner = false\n      dropNext = false\n    }\n\n    const targetPosition = dropNode.$el.getBoundingClientRect()\n    const treePosition = el$.value.getBoundingClientRect()\n\n    let dropType\n    const prevPercent = dropPrev ? (dropInner ? 0.25 : dropNext ? 0.45 : 1) : -1\n    const nextPercent = dropNext ? (dropInner ? 0.75 : dropPrev ? 0.55 : 0) : 1\n\n    let indicatorTop = -9999\n    const distance = event.clientY - targetPosition.top\n    if (distance < targetPosition.height * prevPercent) {\n      dropType = 'before'\n    } else if (distance > targetPosition.height * nextPercent) {\n      dropType = 'after'\n    } else if (dropInner) {\n      dropType = 'inner'\n    } else {\n      dropType = 'none'\n    }\n\n    const iconPosition = dropNode.$el\n      .querySelector('.el-tree-node__expand-icon')\n      .getBoundingClientRect()\n    const dropIndicator = dropIndicator$.value\n    if (dropType === 'before') {\n      indicatorTop = iconPosition.top - treePosition.top\n    } else if (dropType === 'after') {\n      indicatorTop = iconPosition.bottom - treePosition.top\n    }\n    dropIndicator.style.top = `${indicatorTop}px`\n    dropIndicator.style.left = `${iconPosition.right - treePosition.left}px`\n\n    if (dropType === 'inner') {\n      addClass(dropNode.$el, 'is-drop-inner')\n    } else {\n      removeClass(dropNode.$el, 'is-drop-inner')\n    }\n\n    dragState.value.showDropIndicator =\n      dropType === 'before' || dropType === 'after'\n    dragState.value.allowDrop =\n      dragState.value.showDropIndicator || userAllowDropInner\n    dragState.value.dropType = dropType\n    ctx.emit('node-drag-over', draggingNode.node, dropNode.node, event)\n  }\n\n  const treeNodeDragEnd = (event: DragEvent) => {\n    const { draggingNode, dropType, dropNode } = dragState.value\n    event.preventDefault()\n    event.dataTransfer.dropEffect = 'move'\n\n    if (draggingNode && dropNode) {\n      const draggingNodeCopy = { data: draggingNode.node.data }\n      if (dropType !== 'none') {\n        draggingNode.node.remove()\n      }\n      if (dropType === 'before') {\n        dropNode.node.parent.insertBefore(draggingNodeCopy, dropNode.node)\n      } else if (dropType === 'after') {\n        dropNode.node.parent.insertAfter(draggingNodeCopy, dropNode.node)\n      } else if (dropType === 'inner') {\n        dropNode.node.insertChild(draggingNodeCopy)\n      }\n      if (dropType !== 'none') {\n        store.value.registerNode(draggingNodeCopy)\n      }\n\n      removeClass(dropNode.$el, 'is-drop-inner')\n\n      ctx.emit(\n        'node-drag-end',\n        draggingNode.node,\n        dropNode.node,\n        dropType,\n        event\n      )\n      if (dropType !== 'none') {\n        ctx.emit('node-drop', draggingNode.node, dropNode.node, dropType, event)\n      }\n    }\n    if (draggingNode && !dropNode) {\n      ctx.emit('node-drag-end', draggingNode.node, null, dropType, event)\n    }\n\n    dragState.value.showDropIndicator = false\n    dragState.value.draggingNode = null\n    dragState.value.dropNode = null\n    dragState.value.allowDrop = true\n  }\n\n  provide(dragEventsKey, {\n    treeNodeDragStart,\n    treeNodeDragOver,\n    treeNodeDragEnd,\n  })\n\n  return {\n    dragState,\n  }\n}\n"],"names":[],"mappings":"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"}