UNPKG

vue3-treeview

Version:

A simple vue js 3 treeview component

1,432 lines (1,431 loc) 42.6 kB
var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; import { inject, ref, computed, defineAsyncComponent, resolveComponent, openBlock, createElementBlock, normalizeStyle, Fragment, renderList, createBlock, withCtx, renderSlot, toRefs, provide, onUnmounted, createVNode, mergeProps, watch, nextTick, normalizeClass, createElementVNode, createCommentVNode, onMounted, withKeys, withModifiers, withDirectives, vModelText, toDisplayString, Transition } from "vue"; var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {}; function isNil(value) { return value == null; } var lodash_isnil = isNil; var INFINITY$1 = 1 / 0, MAX_INTEGER = 17976931348623157e292, NAN = 0 / 0; var symbolTag$1 = "[object Symbol]"; var reTrim = /^\s+|\s+$/g; var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; var reIsBinary = /^0b[01]+$/i; var reIsOctal = /^0o[0-7]+$/i; var freeParseInt = parseInt; var objectProto$1 = Object.prototype; var objectToString$1 = objectProto$1.toString; function isObject(value) { var type = typeof value; return !!value && (type == "object" || type == "function"); } function isObjectLike$1(value) { return !!value && typeof value == "object"; } function isSymbol$1(value) { return typeof value == "symbol" || isObjectLike$1(value) && objectToString$1.call(value) == symbolTag$1; } function toFinite(value) { if (!value) { return value === 0 ? value : 0; } value = toNumber(value); if (value === INFINITY$1 || value === -INFINITY$1) { var sign = value < 0 ? -1 : 1; return sign * MAX_INTEGER; } return value === value ? value : 0; } function toInteger(value) { var result = toFinite(value), remainder = result % 1; return result === result ? remainder ? result - remainder : result : 0; } function toNumber(value) { if (typeof value == "number") { return value; } if (isSymbol$1(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == "function" ? value.valueOf() : value; value = isObject(other) ? other + "" : other; } if (typeof value != "string") { return value === 0 ? value : +value; } value = value.replace(reTrim, ""); var isBinary = reIsBinary.test(value); return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value; } var lodash_tointeger = toInteger; const defaultSize = 8; const defaultDisabledClass = "disabled"; const defaultFocusClass = "focused"; const defaultDragClass = "draggable"; const defaultDropClass = "droppable"; const defaultOverClass = "node-over"; const defaultInClass = "node-in"; const defaultUnderClass = "node-under"; const defaultViewBox = "0 0 123.958 123.959"; const defaultOpenDraw = `M117.979,28.017h-112c-5.3,0-8,6.4-4.2,10.2l56,56c2.3,2.3,6.1,2.3,8.401,0l56-56C125.979,34.417,123.279,28.017,117.979,28.017z`; const defaultCloseDraw = `M38.217,1.779c-3.8-3.8-10.2-1.1-10.2,4.2v112c0,5.3,6.4,8,10.2,4.2l56-56c2.3-2.301,2.3-6.101,0-8.401L38.217,1.779z`; const defaultColor = "black"; function createDefaultIcon(draw) { return { type: "shape", width: defaultSize, height: defaultSize, viewBox: defaultViewBox, stroke: defaultColor, fill: defaultColor, draw, name: null, src: null, alt: null, style: null, class: null }; } const defaultConfig = { roots: [], padding: 16, editable: false, editing: null, checkboxes: false, dragAndDrop: false, keyboardNavigation: false, openedIcon: createDefaultIcon(defaultOpenDraw), closedIcon: createDefaultIcon(defaultCloseDraw) }; function useLevel(props) { const state = inject("state"); const config = state.config; const nodes = state.nodes; const depth = ref(props.depth); const parent = ref(props.parentId); const level = computed(() => { const res = []; if (lodash_isnil(parent.value) && config.value.roots && depth.value === 0) { for (const id2 of config.value.roots) { addNode(id2, res); } return res; } if (!lodash_isnil(parent.value)) { const node = nodes.value[parent.value]; if (node && node.children && node.children.length > 0) { for (const id2 of node.children) { addNode(id2, res); } } return res; } return []; }); const addNode = (id2, a) => { if (nodes.value[id2]) { nodes.value[id2].id = id2; nodes.value[id2].parent = parent.value; a.push(nodes.value[id2]); } }; const id = computed(() => { return new Date().valueOf(); }); const padding = computed(() => { if (depth.value === 0) { return 0; } if (lodash_isnil(config.value.padding)) { return defaultConfig.padding; } const p = lodash_tointeger(config.value.padding); return p >= 0 ? p : 0; }); const style = computed(() => { return { "padding-left": `${padding.value}px`, "list-style": "none" }; }); return { id, level, padding, style }; } var _export_sfc = (sfc, props) => { for (const [key, val] of props) { sfc[key] = val; } return sfc; }; const _sfc_main$4 = { components: { TreeNode: defineAsyncComponent(() => Promise.resolve().then(function() { return TreeNode$1; })) }, props: { depth: { required: true, type: Number, default: null }, parentId: { type: String, default: null } }, setup(props) { return __spreadValues({}, useLevel(props)); } }; const _hoisted_1$2 = ["id"]; function _sfc_render$4(_ctx, _cache, $props, $setup, $data, $options) { const _component_TreeNode = resolveComponent("TreeNode"); return openBlock(), createElementBlock("ul", { class: "tree-level", id: _ctx.id, style: normalizeStyle(_ctx.style) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.level, (item, index) => { return openBlock(), createBlock(_component_TreeNode, { key: item.id, node: item, depth: $props.depth, index, "parent-id": $props.parentId }, { "loading-slot": withCtx((props) => [ renderSlot(_ctx.$slots, "loading-slot", { node: props.node }) ]), "before-input": withCtx((props) => [ renderSlot(_ctx.$slots, "before-input", { node: props.node }) ]), "after-input": withCtx((props) => [ renderSlot(_ctx.$slots, "after-input", { node: props.node }) ]), _: 2 }, 1032, ["node", "depth", "index", "parent-id"]); }), 128)) ], 12, _hoisted_1$2); } var TreeLevel = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["render", _sfc_render$4]]); var TreeLevel$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, [Symbol.toStringTag]: "Module", "default": TreeLevel }); var INFINITY = 1 / 0; var symbolTag = "[object Symbol]"; var freeGlobal = typeof commonjsGlobal == "object" && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; var freeSelf = typeof self == "object" && self && self.Object === Object && self; var root = freeGlobal || freeSelf || Function("return this")(); var objectProto = Object.prototype; var idCounter = 0; var objectToString = objectProto.toString; var Symbol$1 = root.Symbol; var symbolProto = Symbol$1 ? Symbol$1.prototype : void 0, symbolToString = symbolProto ? symbolProto.toString : void 0; function baseToString(value) { if (typeof value == "string") { return value; } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ""; } var result = value + ""; return result == "0" && 1 / value == -INFINITY ? "-0" : result; } function isObjectLike(value) { return !!value && typeof value == "object"; } function isSymbol(value) { return typeof value == "symbol" || isObjectLike(value) && objectToString.call(value) == symbolTag; } function toString(value) { return value == null ? "" : baseToString(value); } function uniqueId(prefix) { var id = ++idCounter; return toString(prefix) + id; } var lodash_uniqueid = uniqueId; const states = new Map(); function createState(props) { const { nodes, config } = toRefs(props); const state = { id: lodash_uniqueid(), nodes: computed(() => nodes.value), config: computed(() => config.value), focusable: ref(null), focusFunc: new Map(), dragged: ref({ node: null, element: null, wrapper: null, parentId: null }) }; states.set(state.id, state); return state.id; } function useTree(props, emit) { const element = ref(null); const id = createState(props); const state = states.get(id); provide("emitter", emit); provide("state", state); const style = computed(() => { return { "display": "flex", "align-items": "center" }; }); onUnmounted(() => { states.delete(id); }); return { element, style }; } var material_css_vue_type_style_index_0_src_lang = ""; const _sfc_main$3 = { components: { TreeLevel }, props: { nodes: { required: true, type: Object, default: () => { } }, config: { required: true, type: Object, default: () => { } } }, setup(props, { emit }) { return __spreadValues({}, useTree(props, emit)); }, methods: { setElementRef(elt) { this.element = elt; } } }; function _sfc_render$3(_ctx, _cache, $props, $setup, $data, $options) { const _component_TreeLevel = resolveComponent("TreeLevel"); return openBlock(), createElementBlock("div", { class: "tree", ref: $options.setElementRef, style: normalizeStyle(_ctx.style) }, [ createVNode(_component_TreeLevel, mergeProps({ depth: 0, "parent-id": null }, _ctx.$attrs), { "loading-slot": withCtx((props) => [ renderSlot(_ctx.$slots, "loading-slot", { node: props.node }) ]), "before-input": withCtx((props) => [ renderSlot(_ctx.$slots, "before-input", { node: props.node }) ]), "after-input": withCtx((props) => [ renderSlot(_ctx.$slots, "after-input", { node: props.node }) ]), _: 3 }, 16) ], 4); } var Tree = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["render", _sfc_render$3]]); function eq(value, other) { return value === other || value !== value && other !== other; } var lodash_eq = eq; const nodeEvents = { opened: "nodeOpened", closed: "nodeClosed", focus: "nodeFocus", toggle: "nodeToggle", blur: "nodeBlur", edit: "nodeEdit" }; const checkboxEvents = { checked: "nodeChecked", unchecked: "nodeUnchecked" }; const dragEvents = { start: "nodeDragstart", end: "nodeDragend", enter: "nodeDragenter", leave: "nodeDragleave", over: "nodeOver", drop: "nodeDrop" }; function useInput(cmn) { const node = cmn.node; const config = cmn.config; const wrapper = cmn.wrapper; const editable = cmn.editable; const editing = cmn.editing; const input = ref(null); const text = computed({ get: () => node.value.text, set: (val) => node.value.text = val }); const editableClass = computed(() => { if (!cmn.editable.value) { return null; } return config.value.editableClass ? config.value.editableClass : "editable"; }); watch(editing, (nv, ov) => { if (!lodash_eq(nv, ov) && nv) { nextTick(() => { input.value.focus(); }); } }); const focusInput = () => { if (editable.value && !cmn.disabled.value) { config.value.editing = node.value.id; cmn.root.emit(nodeEvents.edit, node.value); } }; const esc = (event) => { if (editable.value && config.value.keyboardNavigation) { cmn.blur(event); wrapper.value.focus(); } }; const enter = () => { if (editable.value && !cmn.disabled.value && config.value.keyboardNavigation) { focusInput(); } }; return { text, input, editing, editable, editableClass, focusInput, esc, enter }; } function useIcon(props) { const { isLeaf } = toRefs(props); const state = inject("state"); const config = state.config; const openedIcon = computed(() => { return config.value.openedIcon || defaultConfig.openedIcon; }); const closedIcon = computed(() => { return config.value.closedIcon || defaultConfig.closedIcon; }); const hasIcons = computed(() => { return !lodash_isnil(closedIcon.value) && !lodash_isnil(openedIcon.value); }); const useIcons = computed(() => { return !isLeaf.value && hasIcons.value; }); const fakeNodeStyle = computed(() => { return { width: `${defaultSize}px`, height: `${defaultSize}px` }; }); return { hasIcons, openedIcon, closedIcon, useIcons, fakeNodeStyle }; } const _sfc_main$2 = { props: { icon: { required: true, type: Object } } }; const _hoisted_1$1 = ["width", "height", "viewBox"]; const _hoisted_2$1 = ["d", "fill", "stroke", "stroke-width"]; const _hoisted_3$1 = ["src", "alt", "width", "height"]; function _sfc_render$2(_ctx, _cache, $props, $setup, $data, $options) { return $props.icon.type === "shape" ? (openBlock(), createElementBlock("svg", { key: 0, xmlns: "http://www.w3.org/2000/svg", width: $props.icon.width, height: $props.icon.height, class: normalizeClass($props.icon.class), style: normalizeStyle($props.icon.style), viewBox: $props.icon.viewBox }, [ createElementVNode("path", { d: $props.icon.draw, fill: $props.icon.fill, stroke: $props.icon.stroke, "stroke-width": $props.icon.strokeWidth }, null, 8, _hoisted_2$1) ], 14, _hoisted_1$1)) : $props.icon.type === "class" ? (openBlock(), createElementBlock("i", { key: 1, class: normalizeClass($props.icon.class), style: normalizeStyle($props.icon.style) }, null, 6)) : $props.icon.type === "img" ? (openBlock(), createElementBlock("img", { key: 2, src: $props.icon.src, alt: $props.icon.alt, width: $props.icon.width, height: $props.icon.height, class: normalizeClass($props.icon.class), style: normalizeStyle($props.icon.style) }, null, 14, _hoisted_3$1)) : createCommentVNode("", true); } var Icon = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render$2]]); const _sfc_main$1 = { components: { Icon }, props: { isLeaf: { type: Boolean }, opened: { type: Boolean } }, setup(props) { return useIcon(props); }, computed: { fakeIcon() { return createDefaultIcon(null); } } }; function _sfc_render$1(_ctx, _cache, $props, $setup, $data, $options) { const _component_Icon = resolveComponent("Icon"); return _ctx.useIcons ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [ $props.opened ? (openBlock(), createBlock(_component_Icon, { key: 0, icon: _ctx.openedIcon }, null, 8, ["icon"])) : (openBlock(), createBlock(_component_Icon, { key: 1, icon: _ctx.closedIcon }, null, 8, ["icon"])) ], 64)) : (openBlock(), createBlock(_component_Icon, { key: 1, icon: $options.fakeIcon }, null, 8, ["icon"])); } var TreeIcons = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render$1]]); function useNode(cmn, props) { const state = cmn.state; const node = cmn.node; const config = cmn.config; const wrapper = cmn.wrapper; const editing = cmn.editing; const level = ref(null); const depth = ref(props.depth); const index = ref(props.index); if (!node.value.children) { node.value.children = ref([]).value; } const id = computed(() => { return hasNode.value && node.value.id; }); const hasNode = computed(() => { return !lodash_isnil(node); }); const hasState = computed(() => { return hasNode.value && !lodash_isnil(node.value.state); }); const roots = computed(() => { return config.value.roots || []; }); const children = computed(() => { return lodash_isnil(node.value.children) ? [] : node.value.children; }); const nbChildren = computed(() => { return children.value.length; }); const hasChildren = computed(() => { return nbChildren.value > 0; }); const opened = computed(() => { return hasState.value && node.value.state.opened || false; }); const isLoading = computed(() => { return hasState.value && node.value.state.isLoading || false; }); const displayLoading = computed(() => { return isLoading.value && !hasChildren.value && opened.value; }); const displayLevel = computed(() => { return !isLoading.value && hasChildren.value && opened.value; }); const style = computed(() => { return { display: "flex" }; }); const disabledClass = computed(() => { if (!cmn.disabled.value) { return null; } return config.value.disabledClass ? config.value.disabledClass : defaultDisabledClass; }); const hideIcons = computed(() => { for (const id2 of roots.value) { const node2 = state.nodes.value[id2]; if (node2.children && node2.children.length > 0) { return false; } } return true; }); const isLeaf = computed(() => { if (config.value.leaves instanceof Array) { const arr = config.value.leaves; const idx = arr.indexOf(id.value); return Number.isFinite(idx) && idx >= 0; } return !hasChildren.value; }); const isFocusable = computed(() => { return state.focusable.value === node.value.id; }); const tabIndex = computed(() => { if (depth.value === 0 && index.value === 0 && lodash_isnil(state.focusable.value)) { return 0; } return isFocusable.value ? 0 : -1; }); const focusClass = computed(() => { if (!cmn.focused.value) { return null; } return config.value.focusClass ? config.value.focusClass : defaultFocusClass; }); watch(opened, (nv) => { nv ? cmn.root.emit(nodeEvents.opened, node.value) : cmn.root.emit(nodeEvents.closed, node.value); }); const focus = () => { state.focusable.value = node.value.id; nextTick(() => { wrapper.value.focus(); cmn.focused.value = true; cmn.root.emit(nodeEvents.focus, node.value); }); }; const toggle = () => { node.value.state.opened = !node.value.state.opened; cmn.root.emit(nodeEvents.toggle, node.value); }; const right = () => { if (!editing.value && config.value.keyboardNavigation) { node.value.state.opened = true; } }; const left = () => { if (!editing.value && config.value.keyboardNavigation) { node.value.state.opened = false; } }; const move = (getFunc) => { const id2 = getFunc(node.value.id); if (!lodash_isnil(id2) && config.value.keyboardNavigation) { const f = state.focusFunc.get(id2); if (f) { f(); } } }; const up = () => move(prevVisible); const prev = (id2) => { const n = state.nodes.value[id2]; if (n.children && n.children.length > 0) { const idx = n.children.indexOf(node.value.id); const prev2 = n.children[idx - 1]; if (!lodash_isnil(prev2)) { return lastChild(prev2); } } return n.id; }; const prevVisible = (id2) => { const n = state.nodes.value[id2]; const p = state.nodes.value[n.parent]; if (!p) { const idx = roots.value.indexOf(id2); return lastChild(roots.value[idx - 1]) || null; } return prev(p.id); }; const lastChild = (id2) => { const n = state.nodes.value[id2]; if (!n) { return null; } if (n.children && n.children.length > 0 && n.state.opened) { const last = n.children[n.children.length - 1]; if (!lodash_isnil(last)) { return lastChild(last); } } return n.id; }; const down = () => move(nextVisible); const nextRoot = (id2) => { const idx = roots.value.indexOf(id2); return roots.value[idx + 1] || null; }; const next = (p, id2) => { const idx = p.children.indexOf(id2); if (p.children[idx + 1]) { return p.children[idx + 1]; } if (p.parent) { return next(state.nodes.value[p.parent], p.id); } return nextRoot(p.id); }; const nextVisible = (id2) => { const n = state.nodes.value[id2]; if (n.children && n.children.length > 0 && n.state.opened) { return n.children[0]; } const p = state.nodes.value[n.parent]; return p ? next(p, id2) : nextRoot(id2); }; onMounted(() => { state.focusFunc.set(node.value.id, focus); }); onUnmounted(() => { state.focusFunc.delete(node.value.id); }); return { id, level, style, opened, hasNode, hideIcons, hasChildren, tabIndex, focusClass, disabledClass, isLeaf, isLoading, displayLoading, displayLevel, right, left, up, down, toggle, focus, prevVisible, nextVisible }; } function ensureState(node) { if (lodash_isnil(node.state)) { node.state = {}; node.state.checked = false; } } function auto(node, nodes) { const check = (v) => { node.value.state.checked = v; }; const setIndeterminate = (v) => { node.value.state.indeterminate = v; }; const ensureCheck = () => { ensureState(node.value); if (node.value.state.checked || !hasChildren.value) { setIndeterminate(false); } }; const children = computed(() => { return node.value.children; }); const hasChildren = computed(() => { return !lodash_isnil(children.value) && children.value.length > 0 || false; }); const states2 = computed(() => { if (!hasChildren.value) { return []; } const res = []; for (const c of children.value) { const child = nodes.value[c]; if (!lodash_isnil(child)) { ensureState(child); res.push(child.state); } } return res; }); const checked = computed(() => { return node.value.state.checked; }); const indeterminate = computed(() => { return node.value.state.indeterminate; }); const allChecked = computed(() => { return states2.value.every((x) => x.checked); }); const noneChecked = computed(() => { return states2.value.every((x) => !x.checked); }); const someChecked = computed(() => { return !allChecked.value && !noneChecked.value; }); const someIndeterminate = computed(() => { return states2.value.some((x) => x.indeterminate); }); const recurseDown = (n) => { if (!lodash_isnil(n.state) && !lodash_isnil(n.children)) { for (const id of n.children) { const child = nodes.value[id]; if (!lodash_isnil(child)) { ensureState(child); child.state.indeterminate = false; child.state.checked = n.state.checked; recurseDown(child); } } } }; const updateState = () => { if (!hasChildren.value) { return; } if (noneChecked.value && !someIndeterminate.value) { setIndeterminate(false); check(false); return; } if (allChecked.value) { setIndeterminate(false); check(true); return; } setIndeterminate(true); check(false); }; const rebuild = () => { ensureCheck(); recurseDown(node.value); updateState(); }; const click = () => { setIndeterminate(false); check(!node.value.state.checked); }; return { checked, indeterminate, noneChecked, someChecked, allChecked, someIndeterminate, click, rebuild, updateState, recurseDown }; } function manual(node) { const checked = computed(() => { return node.value.state.checked; }); const indeterminate = computed(() => { return node.value.state.indeterminate || false; }); const noneChecked = computed(() => { return false; }); const someChecked = computed(() => { return false; }); const allChecked = computed(() => { return false; }); const someIndeterminate = computed(() => { return false; }); const click = () => { node.value.state.checked = !node.value.state.checked; }; const rebuild = () => { }; const updateState = () => { }; const recurseDown = () => { }; return { checked, indeterminate, noneChecked, someChecked, allChecked, someIndeterminate, click, rebuild, updateState, recurseDown }; } var checkMode; (function(checkMode2) { checkMode2[checkMode2["auto"] = 0] = "auto"; checkMode2[checkMode2["manual"] = 1] = "manual"; })(checkMode || (checkMode = {})); function useCheckBox(cmn) { const node = cmn.node; const config = cmn.config; const nodes = cmn.state.nodes; const mode = computed(() => { return config.value.checkMode === checkMode.auto ? checkMode.auto : checkMode.manual; }); const factory = computed(() => { return mode.value === checkMode.auto ? auto(node, nodes) : manual(node); }); watch(mode, (nv, ov) => { if (!lodash_eq(nv, ov)) { factory.value.rebuild(); } }); const checked = computed(() => { return factory.value.checked.value; }); const indeterminate = computed(() => { return factory.value.indeterminate.value; }); const hasCheckbox = computed(() => { return config.value.checkboxes || defaultConfig.checkboxes; }); const checkedClass = computed(() => { return [ factory.value.checked.value ? config.value.checkedClass ? config.value.checkedClass : "checked" : null, factory.value.indeterminate.value ? config.value.indeterminateClass ? config.value.indeterminateClass : "indeterminate" : null ]; }); const allChecked = computed(() => { return factory.value.allChecked.value; }); const noneChecked = computed(() => { return factory.value.noneChecked.value; }); const someChecked = computed(() => { return factory.value.someChecked.value; }); const someIndeterminate = computed(() => { return factory.value.someIndeterminate.value; }); watch([allChecked, noneChecked, someChecked], ([ov1, ov2, ov3]) => { if (ov1 || ov2 || ov3) { factory.value.updateState(); } }, { deep: true }); watch(someIndeterminate, (nv, ov) => { if (!lodash_eq(nv, ov)) { factory.value.updateState(); } }, { deep: true }); const clickCheckbox = () => { if (!cmn.disabled.value) { factory.value.click(); factory.value.recurseDown(node.value); cmn.root.emit(checked.value ? checkboxEvents.checked : checkboxEvents.unchecked, node.value); } }; const space = () => { if (!cmn.editing.value && config.value.checkboxes && config.value.keyboardNavigation) { clickCheckbox(); } }; return { checked, hasCheckbox, indeterminate, checkedClass, space, clickCheckbox }; } var DragPosition; (function(DragPosition2) { DragPosition2[DragPosition2["over"] = 0] = "over"; DragPosition2[DragPosition2["in"] = 1] = "in"; DragPosition2[DragPosition2["under"] = 2] = "under"; })(DragPosition || (DragPosition = {})); function useDragAndDrop(cmn, props) { const node = cmn.node; const state = cmn.state; const parentId = ref(props.parentId); const config = cmn.config; const nodes = state.nodes; const dragged = ref(state.dragged); const wrapper = cmn.wrapper; const element = ref(null); const pos = ref(null); const draggable = computed(() => { return !cmn.disabled.value && config.value.dragAndDrop && node.value.state.draggable !== false; }); const droppable = computed(() => { return config.value.dragAndDrop && node.value.state.droppable !== false; }); const isDragging = computed(() => { return !lodash_isnil(dragged.value) && !lodash_isnil(dragged.value.node); }); const isSameNode = computed(() => { return isDragging.value && dragged.value.node.id === node.value.id; }); const isSameParent = computed(() => { return targetParent.value === draggedParent.value; }); const draggedParent = computed(() => { return !isDragging.value || !dragged.value.parentId ? null : getParent(dragged.value.parentId); }); const draggedLvl = computed(() => { return getLevel(draggedParent.value); }); const targetParent = computed(() => { return !lodash_isnil(parentId.value) ? getParent(parentId.value) : null; }); const targetLvl = computed(() => { return getLevel(targetParent.value); }); const dragContain = computed(() => { if (!isDragging.value || !dragged.value.wrapper) { return false; } return dragged.value.element.contains(element.value); }); const context = computed(() => { return { dragged: dragged.value, target: { node: node.value.id, element: element.value, wrapper: wrapper.value, parentId: parentId.value } }; }); const dragClass = computed(() => { return [ draggable.value ? defaultDragClass : null, droppable.value ? defaultDropClass : null, pos.value === 0 ? defaultOverClass : null, pos.value === 1 ? defaultInClass : null, pos.value === 2 ? defaultUnderClass : null ]; }); const getParent = (id) => { return !lodash_isnil(id) ? nodes.value[id] : null; }; const getLevel = (node2) => { return !lodash_isnil(node2) ? node2.children : config.value.roots; }; const getDataTransfer = (evt) => { if (!evt || !evt.dataTransfer) return null; const jsonPayload = evt.dataTransfer.getData("application/json"); if (jsonPayload) return JSON.parse(jsonPayload); return evt.dataTransfer.getData("text/plain"); }; const isExternalSrc = (evt) => { var _a, _b; return ((_b = (_a = evt == null ? void 0 : evt.dataTransfer) == null ? void 0 : _a.items) == null ? void 0 : _b.length) > 0; }; const dragstart = (evt) => { if (draggable.value) { dragged.value = { node: node.value, element: element.value, wrapper: wrapper.value, parentId: parentId.value }; cmn.root.emit(dragEvents.start, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); } }; const eventContext = (evt) => { return { evt, external: isExternalSrc(evt), dataTransfer: getDataTransfer(evt) }; }; const dragend = (evt) => { cmn.root.emit(dragEvents.end, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); dragged.value = null; }; const dragenter = (evt) => { cmn.root.emit(dragEvents.enter, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); }; const dragleave = (evt) => { cmn.root.emit(dragEvents.leave, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); pos.value = null; }; const dragover = (evt) => { if (!isSameNode.value && !dragContain.value) { const external = isExternalSrc(evt); if (!isDragging.value && !external) return; cmn.root.emit(dragEvents.over, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); if (!external && wrapper.value) { const factor = 0.3; const y = evt.pageY; const r = wrapper.value.getBoundingClientRect(); const midPoint = r.top + r.height / 2; const midRange = [ midPoint - r.height * factor, midPoint + r.height * factor ]; const idx = draggedLvl.value.indexOf(node.value.id); const idxDrag = draggedLvl.value.indexOf(dragged.value.node.id); if (y < midRange[0] && (!isSameParent.value || isSameParent.value && idx !== idxDrag + 1)) { pos.value = 0; } else if (y > midRange[1] && (!isSameParent.value || isSameParent.value && idx !== idxDrag - 1)) { pos.value = 2; } else { pos.value = 1; } } } }; const drop = (evt) => { if (!isSameNode.value && !dragContain.value) { switch (pos.value) { case 0: { insertAt(0); break; } case 2: { insertAt(1); break; } case 1: { insertIn(); } } } cmn.root.emit(dragEvents.drop, __spreadValues(__spreadValues({}, context.value), eventContext(evt))); pos.value = null; }; const insertAt = (i) => { if (isDragging.value) { const dragId = dragged.value.node.id; const dragIdx = draggedLvl.value.indexOf(dragId); draggedLvl.value.splice(dragIdx, 1); const targetId = node.value.id; const idx = targetLvl.value.indexOf(targetId); targetLvl.value.splice(idx + i, 0, dragId); } }; const insertIn = () => { if (isDragging.value && droppable.value) { const dragId = dragged.value.node.id; if (draggedLvl.value) { const idx = draggedLvl.value.indexOf(dragId); draggedLvl.value.splice(idx, 1); } node.value.children.unshift(dragId); } }; return { pos, element, dragClass, draggable, droppable, dragstart, dragend, dragenter, dragleave, dragover, drop }; } function useCommon(props) { const { node } = toRefs(props); const state = inject("state"); const config = state.config; const wrapper = ref(null); const focused = ref(false); const root2 = { emit: inject("emitter") }; ensureState(node.value); const hasNode = computed(() => { return !lodash_isnil(node); }); const hasConfig = computed(() => { return !lodash_isnil(config.value); }); const hasState = computed(() => { return hasNode.value && !lodash_isnil(node.value.state); }); const disabled = computed(() => { return config.value.disabled || node.value.state.disabled; }); const editable = computed(() => { return config.value.editable && (!lodash_isnil(node.value.state.editable) ? node.value.state.editable : true) || defaultConfig.editable; }); const editing = computed(() => { return editable.value && config.value.editing === node.value.id; }); const blur = (e) => { if (e.type === "blur") { const current = e.currentTarget; const related = e.relatedTarget; if (!current.contains(related)) { config.value.editing = null; focused.value = false; root2.emit(nodeEvents.blur, e, node.value); } } }; return { state, node, config, hasNode, hasState, hasConfig, disabled, wrapper, editable, editing, focused, blur, root: root2 }; } const _sfc_main = { components: { TreeLevel: defineAsyncComponent(() => Promise.resolve().then(function() { return TreeLevel$1; })), TreeIcons }, emits: [ ...Object.values(nodeEvents), ...Object.values(checkboxEvents), ...Object.values(dragEvents) ], props: { depth: { required: true, type: Number }, index: { required: true, type: Number }, node: { required: true, type: Object }, parentId: { default: null, type: String } }, setup(props) { const cmn = useCommon(props); return __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, cmn), useInput(cmn)), useCheckBox(cmn)), useNode(cmn, props)), useDragAndDrop(cmn, props)); }, computed: { nodeClass() { return [ this.focusClass, this.disabledClass, this.checkedClass, this.editableClass, this.dragClass ]; } }, methods: { setWrapperRef(e) { this.wrapper = e; }, setLevelRef(e) { this.level = e; }, setElementRef(e) { this.element = e; }, setInputRef(e) { this.input = e; } } }; const _hoisted_1 = ["aria-expanded"]; const _hoisted_2 = ["draggable", "tabindex"]; const _hoisted_3 = ["checked", "disabled", ".indeterminate"]; const _hoisted_4 = { class: "input-wrapper" }; const _hoisted_5 = ["disabled"]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_TreeIcons = resolveComponent("TreeIcons"); const _component_TreeLevel = resolveComponent("TreeLevel"); return _ctx.hasNode ? (openBlock(), createElementBlock("li", { key: 0, class: "tree-node", ref: $options.setElementRef, "aria-expanded": _ctx.opened, onKeydown: [ _cache[13] || (_cache[13] = withKeys(withModifiers((...args) => _ctx.enter && _ctx.enter(...args), ["stop"]), ["enter"])), _cache[14] || (_cache[14] = withKeys(withModifiers((...args) => _ctx.esc && _ctx.esc(...args), ["stop"]), ["esc"])), _cache[15] || (_cache[15] = withKeys(withModifiers((...args) => _ctx.space && _ctx.space(...args), ["stop"]), ["space"])), _cache[16] || (_cache[16] = withKeys(withModifiers((...args) => _ctx.left && _ctx.left(...args), ["stop"]), ["left"])), _cache[17] || (_cache[17] = withKeys(withModifiers((...args) => _ctx.right && _ctx.right(...args), ["stop"]), ["right"])), _cache[18] || (_cache[18] = withKeys(withModifiers((...args) => _ctx.up && _ctx.up(...args), ["stop"]), ["up"])), _cache[19] || (_cache[19] = withKeys(withModifiers((...args) => _ctx.down && _ctx.down(...args), ["stop"]), ["down"])) ] }, [ createElementVNode("div", { class: normalizeClass(["node-wrapper", $options.nodeClass]), style: normalizeStyle(_ctx.style), ref: $options.setWrapperRef, draggable: _ctx.draggable, tabindex: _ctx.tabIndex, onBlur: _cache[5] || (_cache[5] = (...args) => _ctx.blur && _ctx.blur(...args)), onClick: _cache[6] || (_cache[6] = withModifiers((...args) => _ctx.focus && _ctx.focus(...args), ["stop"])), onDragstart: _cache[7] || (_cache[7] = withModifiers((...args) => _ctx.dragstart && _ctx.dragstart(...args), ["stop"])), onDragend: _cache[8] || (_cache[8] = withModifiers((...args) => _ctx.dragend && _ctx.dragend(...args), ["stop"])), onDragenter: _cache[9] || (_cache[9] = withModifiers((...args) => _ctx.dragenter && _ctx.dragenter(...args), ["prevent", "stop"])), onDragleave: _cache[10] || (_cache[10] = withModifiers((...args) => _ctx.dragleave && _ctx.dragleave(...args), ["prevent", "stop"])), onDragover: _cache[11] || (_cache[11] = withModifiers((...args) => _ctx.dragover && _ctx.dragover(...args), ["prevent", "stop"])), onDrop: _cache[12] || (_cache[12] = withModifiers((...args) => _ctx.drop && _ctx.drop(...args), ["prevent", "stop"])) }, [ !_ctx.hideIcons ? (openBlock(), createElementBlock("div", { key: 0, class: "icon-wrapper", onClick: _cache[0] || (_cache[0] = withModifiers((...args) => _ctx.toggle && _ctx.toggle(...args), ["stop"])) }, [ createVNode(_component_TreeIcons, { "is-leaf": _ctx.isLeaf, opened: _ctx.opened }, null, 8, ["is-leaf", "opened"]) ])) : createCommentVNode("", true), _ctx.hasCheckbox ? (openBlock(), createElementBlock("div", { key: 1, class: normalizeClass(["checkbox-wrapper", _ctx.checkedClass]), onClick: _cache[1] || (_cache[1] = withModifiers((...args) => _ctx.clickCheckbox && _ctx.clickCheckbox(...args), ["stop"])) }, [ createElementVNode("input", { type: "checkbox", tabindex: "-1", class: "node-checkbox", checked: _ctx.checked, disabled: _ctx.disabled, ".indeterminate": _ctx.indeterminate }, null, 40, _hoisted_3) ], 2)) : createCommentVNode("", true), renderSlot(_ctx.$slots, "before-input", { node: $props.node }), createElementVNode("div", _hoisted_4, [ _ctx.editing ? withDirectives((openBlock(), createElementBlock("input", { key: 0, type: "text", tabindex: "0", class: "node-input", "onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => _ctx.text = $event), ref: $options.setInputRef, disabled: _ctx.disabled, onBlur: _cache[3] || (_cache[3] = (...args) => _ctx.blur && _ctx.blur(...args)) }, null, 40, _hoisted_5)), [ [vModelText, _ctx.text] ]) : (openBlock(), createElementBlock("span", { key: 1, class: "node-text", onDblclick: _cache[4] || (_cache[4] = (...args) => _ctx.focusInput && _ctx.focusInput(...args)) }, toDisplayString(_ctx.text), 33)) ]), renderSlot(_ctx.$slots, "after-input", { node: $props.node }) ], 46, _hoisted_2), _ctx.displayLoading ? renderSlot(_ctx.$slots, "loading-slot", { key: 0, node: $props.node }) : createCommentVNode("", true), createVNode(Transition, { name: "level" }, { default: withCtx(() => [ _ctx.displayLevel ? (openBlock(), createBlock(_component_TreeLevel, { key: 0, "parent-id": _ctx.id, depth: $props.depth + 1, ref: $options.setLevelRef }, { "loading-slot": withCtx((props) => [ renderSlot(_ctx.$slots, "loading-slot", { node: props.node }) ]), "before-input": withCtx((props) => [ renderSlot(_ctx.$slots, "before-input", { node: props.node }) ]), "after-input": withCtx((props) => [ renderSlot(_ctx.$slots, "after-input", { node: props.node }) ]), _: 3 }, 8, ["parent-id", "depth"])) : createCommentVNode("", true) ]), _: 3 }) ], 40, _hoisted_1)) : createCommentVNode("", true); } var TreeNode = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); var TreeNode$1 = /* @__PURE__ */ Object.freeze({ __proto__: null, [Symbol.toStringTag]: "Module", "default": TreeNode }); export { Tree as default };