pxd 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/_internal/calendar-day.vue +19 -19
- package/dist/components/_internal/dismiss-container.d.vue.ts +1 -1
- package/dist/components/_internal/dismiss-container.vue +19 -19
- package/dist/components/_internal/loading-mask.vue +9 -1
- package/dist/components/_internal/mention-editor.d.vue.ts +1 -1
- package/dist/components/_internal/mention-editor.vue +1 -1
- package/dist/components/_internal/popover-arrow.d.vue.ts +1 -1
- package/dist/components/_internal/popover-arrow.vue +1 -1
- package/dist/components/{steps → _internal}/step-item.d.vue.ts +1 -1
- package/dist/components/{steps → _internal}/step-item.vue +1 -1
- package/dist/components/_internal/tree-node.d.vue.ts +20 -20
- package/dist/components/_internal/tree-node.vue +53 -45
- package/dist/components/active-graph/index.d.vue.ts +2 -2
- package/dist/components/approval-card/index.d.vue.ts +1 -1
- package/dist/components/approval-card/index.vue +34 -17
- package/dist/components/approval-card/types.d.ts +1 -1
- package/dist/components/avatar/index.d.vue.ts +2 -2
- package/dist/components/avatar/index.vue +1 -1
- package/dist/components/backtop/index.d.vue.ts +3 -3
- package/dist/components/backtop/index.vue +17 -17
- package/dist/components/backtop/types.d.ts +1 -1
- package/dist/components/badge/index.d.vue.ts +3 -3
- package/dist/components/badge/index.vue +43 -43
- package/dist/components/badge/types.d.ts +1 -1
- package/dist/components/book/types.d.ts +1 -1
- package/dist/components/border-beam/index.vue +1 -1
- package/dist/components/border-beam/types.d.ts +1 -1
- package/dist/components/bubble/index.vue +1 -1
- package/dist/components/bubble-group/index.d.vue.ts +4 -4
- package/dist/components/button/index.d.vue.ts +5 -5
- package/dist/components/button/index.vue +13 -13
- package/dist/components/button/types.d.ts +1 -1
- package/dist/components/button-group/types.d.ts +1 -1
- package/dist/components/calendar/index.d.vue.ts +2 -2
- package/dist/components/calendar/index.vue +5 -5
- package/dist/components/calendar/types.d.ts +1 -1
- package/dist/components/card/types.d.ts +1 -1
- package/dist/components/carousel/index.d.vue.ts +7 -7
- package/dist/components/carousel/index.vue +1 -1
- package/dist/components/carousel/types.d.ts +1 -1
- package/dist/components/checkbox/index.vue +1 -1
- package/dist/components/checkbox/types.d.ts +1 -1
- package/dist/components/checkbox-group/index.d.vue.ts +2 -2
- package/dist/components/checkbox-group/types.d.ts +1 -1
- package/dist/components/chip/index.d.vue.ts +1 -1
- package/dist/components/chip/types.d.ts +1 -1
- package/dist/components/choicebox/index.d.vue.ts +3 -3
- package/dist/components/choicebox/types.d.ts +1 -1
- package/dist/components/choicebox-item/index.vue +8 -8
- package/dist/components/choicebox-item/types.d.ts +1 -1
- package/dist/components/collapse/index.vue +2 -2
- package/dist/components/collapse-group/index.vue +1 -1
- package/dist/components/collapse-group/types.d.ts +1 -1
- package/dist/components/command-menu/index.d.vue.ts +5 -5
- package/dist/components/command-menu/index.vue +10 -3
- package/dist/components/config-provider/index.d.vue.ts +40 -5
- package/dist/components/config-provider/types.d.ts +2 -1
- package/dist/components/confirm-popover/index.d.vue.ts +39 -0
- package/dist/components/confirm-popover/index.vue +177 -0
- package/dist/components/confirm-popover/types.d.ts +23 -0
- package/dist/components/copy-button/index.d.vue.ts +2 -6
- package/dist/components/copy-button/index.vue +4 -6
- package/dist/components/dash-line/index.d.vue.ts +1 -1
- package/dist/components/dash-line/index.vue +8 -8
- package/dist/components/dash-line/types.d.ts +1 -1
- package/dist/components/date-picker/index.d.vue.ts +1 -1
- package/dist/components/date-picker/index.vue +3 -3
- package/dist/components/date-picker/types.d.ts +1 -1
- package/dist/components/drawer/index.d.vue.ts +7 -7
- package/dist/components/drawer/index.vue +30 -15
- package/dist/components/drawer/types.d.ts +2 -2
- package/dist/components/effort-slider/index.vue +12 -18
- package/dist/components/effort-slider/types.d.ts +1 -1
- package/dist/components/ellipsis-text/index.d.vue.ts +2 -2
- package/dist/components/ellipsis-text/index.vue +75 -75
- package/dist/components/error/types.d.ts +1 -1
- package/dist/components/fader/index.vue +2 -2
- package/dist/components/fader/types.d.ts +1 -1
- package/dist/components/gauge/index.vue +2 -2
- package/dist/components/gauge/types.d.ts +1 -1
- package/dist/components/grid/types.d.ts +1 -1
- package/dist/components/grid-item/types.d.ts +1 -1
- package/dist/components/hint/index.d.vue.ts +32 -0
- package/dist/components/hint/index.vue +239 -0
- package/dist/components/hint/types.d.ts +17 -0
- package/dist/components/hold-button/index.d.vue.ts +4 -4
- package/dist/components/hold-button/index.vue +10 -10
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +4 -0
- package/dist/components/input/index.d.vue.ts +1 -1
- package/dist/components/input/index.vue +14 -7
- package/dist/components/input/types.d.ts +1 -1
- package/dist/components/intersection-observer/index.vue +3 -3
- package/dist/components/kbd/index.vue +2 -2
- package/dist/components/kbd/types.d.ts +1 -1
- package/dist/components/link-button/index.d.vue.ts +5 -5
- package/dist/components/list/index.d.vue.ts +4 -4
- package/dist/components/list/index.vue +126 -47
- package/dist/components/list/types.d.ts +1 -1
- package/dist/components/list-group/types.d.ts +1 -1
- package/dist/components/list-item/index.d.vue.ts +2 -2
- package/dist/components/list-item/index.vue +26 -8
- package/dist/components/loading-bar/index.vue +5 -5
- package/dist/components/marching-ants/index.d.vue.ts +2 -2
- package/dist/components/marching-ants/index.vue +56 -56
- package/dist/components/marching-ants/types.d.ts +1 -1
- package/dist/components/marquee/index.d.vue.ts +6 -6
- package/dist/components/marquee/index.vue +16 -16
- package/dist/components/marquee/types.d.ts +1 -1
- package/dist/components/material/index.d.vue.ts +3 -3
- package/dist/components/mention/index.d.vue.ts +5 -5
- package/dist/components/mention/index.vue +68 -68
- package/dist/components/menu/index.d.vue.ts +4 -4
- package/dist/components/menu/index.vue +10 -10
- package/dist/components/menu/types.d.ts +1 -1
- package/dist/components/message/index.d.vue.ts +1 -1
- package/dist/components/message/index.vue +19 -25
- package/dist/components/message/types.d.ts +1 -1
- package/dist/components/message-item/index.vue +2 -6
- package/dist/components/modal/index.d.vue.ts +7 -7
- package/dist/components/modal/index.vue +26 -11
- package/dist/components/modal/types.d.ts +2 -2
- package/dist/components/noise-background/types.d.ts +1 -1
- package/dist/components/note/index.vue +6 -2
- package/dist/components/note/types.d.ts +2 -1
- package/dist/components/number-input/index.d.vue.ts +11 -6
- package/dist/components/number-input/index.vue +57 -16
- package/dist/components/number-input/types.d.ts +2 -1
- package/dist/components/overlay/index.d.vue.ts +2 -3
- package/dist/components/overlay/index.vue +10 -62
- package/dist/components/overlay/types.d.ts +0 -2
- package/dist/components/page-number/index.vue +30 -29
- package/dist/components/page-number/types.d.ts +1 -1
- package/dist/components/pin-input/index.d.vue.ts +1 -1
- package/dist/components/pin-input/index.vue +6 -6
- package/dist/components/pin-input/types.d.ts +1 -1
- package/dist/components/popover/index.vue +49 -21
- package/dist/components/popover/types.d.ts +3 -1
- package/dist/components/progress/index.d.vue.ts +2 -2
- package/dist/components/progress/index.vue +12 -12
- package/dist/components/progress/types.d.ts +1 -1
- package/dist/components/project-banner/types.d.ts +1 -1
- package/dist/components/questionnaire/index.vue +14 -14
- package/dist/components/radio/index.vue +1 -1
- package/dist/components/radio/types.d.ts +1 -1
- package/dist/components/radio-group/index.d.vue.ts +2 -2
- package/dist/components/radio-group/types.d.ts +1 -1
- package/dist/components/rating/index.vue +28 -28
- package/dist/components/rating/types.d.ts +1 -1
- package/dist/components/resizable/index.d.vue.ts +1 -0
- package/dist/components/resizable/index.vue +130 -195
- package/dist/components/resizable/types.d.ts +2 -10
- package/dist/components/reveal/index.d.vue.ts +3 -3
- package/dist/components/reveal/index.vue +4 -4
- package/dist/components/reveal/types.d.ts +1 -1
- package/dist/components/rolling-number/index.d.vue.ts +2 -2
- package/dist/components/rolling-number/index.vue +15 -15
- package/dist/components/scalable-text/index.vue +9 -9
- package/dist/components/scroll-text/index.d.vue.ts +3 -3
- package/dist/components/scroll-text/index.vue +6 -6
- package/dist/components/scroll-text/types.d.ts +1 -1
- package/dist/components/scrollable/types.d.ts +2 -1
- package/dist/components/search-input/index.d.vue.ts +5 -5
- package/dist/components/search-input/index.vue +2 -1
- package/dist/components/select/index.d.vue.ts +12 -9
- package/dist/components/select/index.vue +165 -42
- package/dist/components/select/types.d.ts +3 -1
- package/dist/components/separator/index.d.vue.ts +1 -1
- package/dist/components/separator/types.d.ts +1 -1
- package/dist/components/skeleton/index.d.vue.ts +1 -1
- package/dist/components/skeleton/index.vue +11 -11
- package/dist/components/skeleton/types.d.ts +1 -1
- package/dist/components/slider/index.d.vue.ts +1 -1
- package/dist/components/slider/index.vue +1 -1
- package/dist/components/slider/types.d.ts +1 -1
- package/dist/components/snippet/index.d.vue.ts +3 -3
- package/dist/components/snippet/index.vue +7 -5
- package/dist/components/snippet/types.d.ts +1 -1
- package/dist/components/spinner/index.vue +5 -1
- package/dist/components/spinner-dots/index.d.vue.ts +1 -1
- package/dist/components/split-button/index.d.vue.ts +5 -5
- package/dist/components/split-button/types.d.ts +1 -1
- package/dist/components/stack/index.d.vue.ts +3 -3
- package/dist/components/stack/index.vue +28 -29
- package/dist/components/stack/types.d.ts +1 -1
- package/dist/components/status-dot/types.d.ts +1 -1
- package/dist/components/steps/index.d.vue.ts +2 -2
- package/dist/components/steps/index.vue +6 -6
- package/dist/components/steps/types.d.ts +1 -1
- package/dist/components/stick-to-bottom/types.d.ts +1 -1
- package/dist/components/swipe-cell/index.d.vue.ts +6 -6
- package/dist/components/swipe-cell/index.vue +64 -64
- package/dist/components/swipe-cell/types.d.ts +2 -1
- package/dist/components/switch/index.vue +1 -1
- package/dist/components/switch/types.d.ts +1 -1
- package/dist/components/switch-item/index.vue +1 -1
- package/dist/components/switch-item/types.d.ts +1 -1
- package/dist/components/tabs/index.d.vue.ts +1 -1
- package/dist/components/tabs/index.vue +48 -51
- package/dist/components/tabs/types.d.ts +1 -1
- package/dist/components/teleport/index.vue +2 -2
- package/dist/components/text/index.d.vue.ts +3 -3
- package/dist/components/text/index.vue +11 -11
- package/dist/components/text/types.d.ts +1 -1
- package/dist/components/textarea/index.vue +1 -1
- package/dist/components/textarea/types.d.ts +1 -1
- package/dist/components/theme-switcher/index.d.vue.ts +3 -2
- package/dist/components/theme-switcher/index.vue +15 -7
- package/dist/components/theme-switcher/types.d.ts +2 -2
- package/dist/components/time-ago/index.d.vue.ts +6 -0
- package/dist/components/time-ago/index.vue +143 -0
- package/dist/components/time-ago/types.d.ts +4 -0
- package/dist/components/time-picker/index.d.vue.ts +1 -1
- package/dist/components/time-picker/index.vue +7 -7
- package/dist/components/time-picker/types.d.ts +1 -1
- package/dist/components/toc/index.d.vue.ts +2 -2
- package/dist/components/toc/index.vue +1 -1
- package/dist/components/todo-list/index.d.vue.ts +4 -4
- package/dist/components/todo-list/index.vue +15 -15
- package/dist/components/todo-list/types.d.ts +1 -1
- package/dist/components/toggle/index.vue +3 -3
- package/dist/components/toggle/types.d.ts +1 -1
- package/dist/components/toggle-button/index.vue +14 -11
- package/dist/components/toggle-button/types.d.ts +2 -2
- package/dist/components/toggle-button-group/index.d.vue.ts +3 -3
- package/dist/components/toggle-button-group/index.vue +2 -2
- package/dist/components/toggle-button-group/types.d.ts +2 -2
- package/dist/components/tool-call/index.vue +5 -5
- package/dist/components/tooltip/index.d.vue.ts +4 -5
- package/dist/components/tooltip/index.vue +4 -49
- package/dist/components/tooltip/types.d.ts +3 -7
- package/dist/components/tour/index.d.vue.ts +33 -0
- package/dist/components/tour/index.vue +302 -0
- package/dist/components/tour/types.d.ts +29 -0
- package/dist/components/tree/index.d.vue.ts +24 -28
- package/dist/components/tree/index.vue +290 -223
- package/dist/components/tree/types.d.ts +38 -13
- package/dist/components/virtual-list/index.d.vue.ts +4 -4
- package/dist/composables/_internal/use-list-keyboard-controller.js +9 -10
- package/dist/composables/_internal/use-list-rows.d.ts +4 -0
- package/dist/composables/_internal/use-list-rows.js +12 -4
- package/dist/composables/_internal/use-list-selection.d.ts +1 -1
- package/dist/composables/_internal/use-lock-scroll.d.ts +8 -1
- package/dist/composables/_internal/use-lock-scroll.js +57 -36
- package/dist/composables/_internal/use-mention-editor.js +1 -1
- package/dist/composables/_internal/use-message-group.d.ts +22 -0
- package/dist/composables/_internal/use-message-group.js +143 -0
- package/dist/composables/_internal/use-overlay-dialog.js +1 -3
- package/dist/composables/_internal/use-overlay-manager.d.ts +4 -1
- package/dist/composables/_internal/use-overlay-manager.js +67 -8
- package/dist/composables/_internal/use-swipe-gesture.d.ts +1 -1
- package/dist/composables/_internal/use-tour-target.d.ts +29 -0
- package/dist/composables/_internal/use-tour-target.js +201 -0
- package/dist/composables/_internal/use-tree.d.ts +103 -0
- package/dist/composables/_internal/use-tree.js +676 -0
- package/dist/composables/_internal/use-word-limit.d.ts +1 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +1 -0
- package/dist/composables/use-color-scheme.d.ts +1 -1
- package/dist/composables/use-color-scheme.js +7 -6
- package/dist/composables/use-delay-destroy.d.ts +1 -1
- package/dist/composables/use-document-hidden.d.ts +1 -1
- package/dist/composables/use-intersection-observer.d.ts +1 -1
- package/dist/composables/use-intersection-observer.js +1 -1
- package/dist/composables/{_internal/use-motion-reduce.js → use-motion-reduce.js} +2 -2
- package/dist/composables/use-mutation-observer.d.ts +1 -1
- package/dist/composables/use-mutation-observer.js +1 -1
- package/dist/composables/use-resize-observer.d.ts +1 -1
- package/dist/composables/use-resize-observer.js +1 -1
- package/dist/composables/use-view-transition.js +1 -0
- package/dist/composables/use-virtual-list.d.ts +1 -1
- package/dist/constants/tooltip-variants.d.ts +28 -0
- package/dist/constants/tooltip-variants.js +27 -0
- package/dist/contexts/avatar.js +1 -1
- package/dist/contexts/breadcrumb.js +1 -1
- package/dist/contexts/button.js +1 -1
- package/dist/contexts/checkbox.js +1 -1
- package/dist/contexts/choicebox.js +1 -1
- package/dist/contexts/collapse.js +1 -1
- package/dist/contexts/config-provider.js +1 -1
- package/dist/contexts/list.js +1 -1
- package/dist/contexts/radio.js +1 -1
- package/dist/contexts/switch.js +1 -1
- package/dist/contexts/toggle-button.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/locales/en-us.d.ts +35 -0
- package/dist/locales/en-us.js +20 -0
- package/dist/locales/zh-cn.d.ts +35 -0
- package/dist/locales/zh-cn.js +20 -0
- package/dist/styles/styles.css +1 -1
- package/dist/styles/tw.css +43 -30
- package/dist/utils/{context.js → _internal/context.js} +1 -1
- package/dist/utils/{observer.d.ts → _internal/observer.d.ts} +1 -1
- package/dist/utils/{observer.js → _internal/observer.js} +4 -4
- package/dist/{components/swipe-cell/instances.d.ts → utils/_internal/swipe-cell-instances.d.ts} +1 -1
- package/dist/utils/event.d.ts +2 -1
- package/dist/utils/event.js +3 -0
- package/package.json +26 -50
- package/volar.d.ts +4 -0
- package/dist/components/message/composables/use-group-expand.d.ts +0 -13
- package/dist/components/message/composables/use-group-expand.js +0 -50
- package/dist/components/message/composables/use-message-timer.d.ts +0 -9
- package/dist/components/message/composables/use-message-timer.js +0 -62
- package/dist/components/message/composables/use-promise-message.d.ts +0 -4
- package/dist/components/message/composables/use-promise-message.js +0 -49
- package/dist/components/resizable/utils.d.ts +0 -4
- package/dist/components/resizable/utils.js +0 -10
- package/dist/composables/_internal/use-tree-drag.d.ts +0 -23
- package/dist/composables/_internal/use-tree-drag.js +0 -196
- package/dist/composables/_internal/use-tree-move.d.ts +0 -20
- package/dist/composables/_internal/use-tree-move.js +0 -96
- package/dist/composables/_internal/use-tree-rows.d.ts +0 -46
- package/dist/composables/_internal/use-tree-rows.js +0 -101
- package/dist/composables/_internal/use-tree-selection.d.ts +0 -22
- package/dist/composables/_internal/use-tree-selection.js +0 -87
- package/dist/styles/source.css +0 -675
- package/dist/types/shared/index.d.ts +0 -2
- /package/dist/composables/{_internal/use-motion-reduce.d.ts → use-motion-reduce.d.ts} +0 -0
- /package/dist/utils/{context.d.ts → _internal/context.d.ts} +0 -0
- /package/dist/utils/{mention-html.d.ts → _internal/mention-html.d.ts} +0 -0
- /package/dist/utils/{mention-html.js → _internal/mention-html.js} +0 -0
- /package/dist/{components/swipe-cell/instances.js → utils/_internal/swipe-cell-instances.js} +0 -0
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, shallowRef, useSlots } from "vue";
|
|
2
|
+
import { computed, shallowRef, useSlots, watch } from "vue";
|
|
3
3
|
import { useListKeyboardController } from "../../composables/_internal/use-list-keyboard-controller.js";
|
|
4
4
|
import { useListNavigation } from "../../composables/_internal/use-list-navigation.js";
|
|
5
|
-
import { useTreeDrag } from "../../composables/_internal/use-tree
|
|
6
|
-
import { isTreeDescendant, moveTreeNode } from "../../composables/_internal/use-tree-move.js";
|
|
7
|
-
import { useTreeIndex, useTreeMatched, useTreeRows } from "../../composables/_internal/use-tree-rows.js";
|
|
8
|
-
import { useTreeSelection } from "../../composables/_internal/use-tree-selection.js";
|
|
5
|
+
import { graftLoadedChildren, isTreeDescendant, moveTreeNode, useTreeDrag, useTreeIndex, useTreeMatched, useTreeRows, useTreeSearch, useTreeSelection } from "../../composables/_internal/use-tree.js";
|
|
9
6
|
import { useVirtualList } from "../../composables/use-virtual-list.js";
|
|
10
|
-
import { getElement } from "../../utils/dom.js";
|
|
11
7
|
import { getUniqueId } from "../../utils/helper.js";
|
|
12
8
|
import { isNumber } from "../../utils/is.js";
|
|
9
|
+
import PLoadingMask from "../_internal/loading-mask.vue";
|
|
13
10
|
import PTreeNode from "../_internal/tree-node.vue";
|
|
14
11
|
import PSearchInput from "../search-input/index.vue";
|
|
15
12
|
import PTeleport from "../teleport/index.vue";
|
|
@@ -51,7 +48,11 @@ const props = defineProps({
|
|
|
51
48
|
required: false,
|
|
52
49
|
default: false
|
|
53
50
|
},
|
|
54
|
-
|
|
51
|
+
selectable: {
|
|
52
|
+
type: Function,
|
|
53
|
+
required: false
|
|
54
|
+
},
|
|
55
|
+
expandOnly: {
|
|
55
56
|
type: Boolean,
|
|
56
57
|
required: false,
|
|
57
58
|
default: false
|
|
@@ -65,10 +66,10 @@ const props = defineProps({
|
|
|
65
66
|
type: Function,
|
|
66
67
|
required: false
|
|
67
68
|
},
|
|
68
|
-
|
|
69
|
+
dropInsideLeaf: {
|
|
69
70
|
type: Boolean,
|
|
70
71
|
required: false,
|
|
71
|
-
default:
|
|
72
|
+
default: false
|
|
72
73
|
},
|
|
73
74
|
virtual: {
|
|
74
75
|
type: Boolean,
|
|
@@ -107,6 +108,20 @@ const props = defineProps({
|
|
|
107
108
|
required: false,
|
|
108
109
|
default: "children"
|
|
109
110
|
},
|
|
111
|
+
lazy: {
|
|
112
|
+
type: Boolean,
|
|
113
|
+
required: false,
|
|
114
|
+
default: false
|
|
115
|
+
},
|
|
116
|
+
load: {
|
|
117
|
+
type: Function,
|
|
118
|
+
required: false
|
|
119
|
+
},
|
|
120
|
+
loading: {
|
|
121
|
+
type: Boolean,
|
|
122
|
+
required: false,
|
|
123
|
+
default: false
|
|
124
|
+
},
|
|
110
125
|
filterable: {
|
|
111
126
|
type: Boolean,
|
|
112
127
|
required: false,
|
|
@@ -116,6 +131,10 @@ const props = defineProps({
|
|
|
116
131
|
type: Function,
|
|
117
132
|
required: false
|
|
118
133
|
},
|
|
134
|
+
remoteFilter: {
|
|
135
|
+
type: Function,
|
|
136
|
+
required: false
|
|
137
|
+
},
|
|
119
138
|
searchMatchesOnly: {
|
|
120
139
|
type: Boolean,
|
|
121
140
|
required: false
|
|
@@ -159,33 +178,226 @@ const emits = defineEmits([
|
|
|
159
178
|
"update:searchValue"
|
|
160
179
|
]);
|
|
161
180
|
const uid = getUniqueId();
|
|
181
|
+
/** A query still on its way shows no row at all, rather than letting the local filter answer it. */
|
|
182
|
+
const NO_MATCHED = {
|
|
183
|
+
visible: new Set(),
|
|
184
|
+
exact: new Set()
|
|
185
|
+
};
|
|
186
|
+
const KEYMAP = {
|
|
187
|
+
ArrowDown: "next",
|
|
188
|
+
ArrowUp: "previous",
|
|
189
|
+
ArrowRight: "enter-child",
|
|
190
|
+
ArrowLeft: "leave-parent",
|
|
191
|
+
End: "last",
|
|
192
|
+
Enter: "activate",
|
|
193
|
+
Home: "first",
|
|
194
|
+
" ": "activate"
|
|
195
|
+
};
|
|
162
196
|
const containerRef = shallowRef();
|
|
163
197
|
const internalSearchValue = shallowRef(props.defaultSearchValue ?? "");
|
|
164
|
-
// Controlled when `searchValue` is given, the internal copy otherwise, exactly like expandedKeys.
|
|
165
198
|
const searchValue = computed(() => props.searchValue ?? internalSearchValue.value);
|
|
166
199
|
const internalExpandedKeys = shallowRef([...props.defaultExpandedKeys ?? []]);
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
const
|
|
200
|
+
const loadedChildren = shallowRef(new Map());
|
|
201
|
+
const loadingKeys = shallowRef(new Set());
|
|
202
|
+
const treeData = computed(() => graftLoadedChildren(props.data, loadedChildren.value, props.childrenField));
|
|
203
|
+
const expandedKeys = computed(() => props.expandedKeys ?? internalExpandedKeys.value);
|
|
204
|
+
const expanded = computed(() => new Set(expandedKeys.value));
|
|
205
|
+
const highlightQuery = computed(() => props.highlightMatch ? searchValue.value.trim() : "");
|
|
206
|
+
const containerStyle = computed(() => {
|
|
207
|
+
const height = props.height;
|
|
208
|
+
if (height == null) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
return { height: isNumber(height) ? height + "px" : height };
|
|
212
|
+
});
|
|
213
|
+
/** Painted only while focused: a marker on a blurred element lies about where the focus is. */
|
|
214
|
+
const focused = shallowRef(false);
|
|
215
|
+
/** Dragging while a query is active would drop a node relative to an incomplete neighbourhood. */
|
|
216
|
+
const dragEnabled = computed(() => props.draggable && !props.disabled && searchValue.value.trim().length === 0);
|
|
217
|
+
const slots = useSlots();
|
|
218
|
+
const hasNodeSlot = computed(() => !!slots["node-switcher"] || !!slots["node-icon"] || !!slots["node-content"] || !!slots["node-suffix"]);
|
|
219
|
+
const { matches: remoteMatches, remote: remoteMode, pending: searchPending, active: remoteActive } = useTreeSearch({
|
|
220
|
+
query: () => searchValue.value,
|
|
221
|
+
remoteFilter: () => props.remoteFilter
|
|
222
|
+
});
|
|
223
|
+
const searchData = computed(() => remoteActive.value ? remoteMatches.value ?? [] : treeData.value);
|
|
224
|
+
const index = useTreeIndex(() => searchData.value, () => props.childrenField);
|
|
225
|
+
const localMatched = useTreeMatched(index, () => searchValue.value, () => props.filter);
|
|
226
|
+
const matched = computed(() => {
|
|
227
|
+
if (!remoteMode.value) {
|
|
228
|
+
return localMatched.value;
|
|
229
|
+
}
|
|
230
|
+
if (!remoteActive.value) {
|
|
231
|
+
return NO_MATCHED;
|
|
232
|
+
}
|
|
233
|
+
// The whole returned forest shows: an ancestor is as much a hit as the node at the end of it.
|
|
234
|
+
const visible = new Set(index.value.list.map((meta) => meta.node.value));
|
|
235
|
+
return {
|
|
236
|
+
visible,
|
|
237
|
+
exact: visible
|
|
238
|
+
};
|
|
239
|
+
});
|
|
240
|
+
const { checked, indeterminate, toggle, extend, isSelectable } = useTreeSelection({
|
|
170
241
|
index,
|
|
171
242
|
modelValue: () => props.modelValue,
|
|
172
243
|
multiple: () => props.multiple,
|
|
173
|
-
checkStrictly: () => props.checkStrictly
|
|
244
|
+
checkStrictly: () => props.checkStrictly,
|
|
245
|
+
selectable: () => props.selectable
|
|
174
246
|
});
|
|
175
|
-
const expandedKeys = computed(() => props.expandedKeys ?? internalExpandedKeys.value);
|
|
176
|
-
const expanded = computed(() => new Set(expandedKeys.value));
|
|
177
247
|
const rows = useTreeRows(index, {
|
|
178
248
|
query: () => searchValue.value,
|
|
179
249
|
expanded,
|
|
180
250
|
matched: () => matched.value.visible,
|
|
181
251
|
exactMatched: () => matched.value.exact,
|
|
182
|
-
matchesOnly: () => props.searchMatchesOnly
|
|
252
|
+
matchesOnly: () => props.searchMatchesOnly,
|
|
253
|
+
canLoad: () => canLoad
|
|
183
254
|
});
|
|
255
|
+
/** Not `reactive()`: the virtualizer would get a deep proxy of the rows instead of the rows. */
|
|
256
|
+
const virtualOptions = {
|
|
257
|
+
dataKey: "key",
|
|
258
|
+
get enabled() {
|
|
259
|
+
return props.virtual;
|
|
260
|
+
},
|
|
261
|
+
get items() {
|
|
262
|
+
return rows.value;
|
|
263
|
+
},
|
|
264
|
+
get itemSize() {
|
|
265
|
+
return props.itemSize;
|
|
266
|
+
},
|
|
267
|
+
get overScan() {
|
|
268
|
+
return props.overScan;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
184
271
|
const rowByKey = computed(() => {
|
|
185
272
|
const result = new Map();
|
|
186
273
|
rows.value.forEach((row) => result.set(row.key, row));
|
|
187
274
|
return result;
|
|
188
275
|
});
|
|
276
|
+
const { totalSize, virtualItems, scrollToIndex } = useVirtualList(containerRef, virtualOptions);
|
|
277
|
+
const contentStyle = computed(() => props.virtual ? { height: totalSize.value + "px" } : undefined);
|
|
278
|
+
/** Keyboard only: a pointer-set marker would outlive the pointer and duplicate `checked`. */
|
|
279
|
+
const { activeIndex, dispatch, setActiveIndex } = useListNavigation({
|
|
280
|
+
count: () => rows.value.length,
|
|
281
|
+
isDisabled: (index) => isNodeDisabled(rows.value[index]),
|
|
282
|
+
onActivateItem: (index) => {
|
|
283
|
+
const row = rows.value[index];
|
|
284
|
+
if (row) {
|
|
285
|
+
onCheck(row);
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
onRight: (index) => {
|
|
289
|
+
const row = rows.value[index];
|
|
290
|
+
if (!row) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (row.hasChildren && !row.expanded) {
|
|
294
|
+
setExpandedByValue(row.key, true);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (row.hasChildren && index + 1 < rows.value.length) {
|
|
298
|
+
setActiveIndex(index + 1);
|
|
299
|
+
scrollRowIntoView(index + 1);
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
onLeft: () => {
|
|
303
|
+
const row = rows.value[activeIndex.value];
|
|
304
|
+
if (!row) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (row.hasChildren && row.expanded) {
|
|
308
|
+
setExpandedByValue(row.key, false);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (row.parentValue === undefined) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const parentIndex = getRow(row.parentValue)?.index;
|
|
315
|
+
if (parentIndex === undefined) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
setActiveIndex(parentIndex);
|
|
319
|
+
scrollRowIntoView(parentIndex);
|
|
320
|
+
},
|
|
321
|
+
scrollToIndex: scrollRowIntoView
|
|
322
|
+
});
|
|
323
|
+
const activeDescendant = computed(() => activeIndex.value >= 0 ? uid + "-" + activeIndex.value : undefined);
|
|
324
|
+
const renderEntries = computed(() => {
|
|
325
|
+
if (props.virtual) {
|
|
326
|
+
return virtualItems.value.flatMap((virtualItem) => {
|
|
327
|
+
const row = rows.value[virtualItem.index];
|
|
328
|
+
return row ? [{
|
|
329
|
+
...row,
|
|
330
|
+
id: uid + "-" + row.index,
|
|
331
|
+
start: virtualItem.start,
|
|
332
|
+
active: focused.value && activeIndex.value === row.index
|
|
333
|
+
}] : [];
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
const entries = [];
|
|
337
|
+
for (const row of rows.value) {
|
|
338
|
+
entries.push({
|
|
339
|
+
...row,
|
|
340
|
+
id: uid + "-" + row.index,
|
|
341
|
+
active: focused.value && activeIndex.value === row.index
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return entries;
|
|
345
|
+
});
|
|
346
|
+
const { onKeydown } = useListKeyboardController({
|
|
347
|
+
keymap: KEYMAP,
|
|
348
|
+
enabled: () => !props.disabled && !props.loading,
|
|
349
|
+
onCommand: (command) => dispatch(command)
|
|
350
|
+
});
|
|
351
|
+
const { value: dragValue, target: dropTarget, x: dragX, y: dragY, onPointerDown: onDragPointerdown, didDrag } = useTreeDrag({
|
|
352
|
+
container: containerRef,
|
|
353
|
+
rows: () => rows.value,
|
|
354
|
+
enabled: () => dragEnabled.value,
|
|
355
|
+
dropInsideLeaf: () => props.dropInsideLeaf,
|
|
356
|
+
canDrop,
|
|
357
|
+
onExpand: (value) => {
|
|
358
|
+
if (getRow(value)?.hasChildren) {
|
|
359
|
+
setExpandedByValue(value, true);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
onCommit
|
|
363
|
+
});
|
|
364
|
+
const dragNode = computed(() => dragValue.value === undefined ? undefined : index.value.byValue.get(dragValue.value)?.node);
|
|
365
|
+
function canLoad(value) {
|
|
366
|
+
if (!props.lazy || !props.load || loadedChildren.value.has(value)) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
const meta = index.value.byValue.get(value);
|
|
370
|
+
return meta !== undefined && meta.node.isLeaf !== true && meta.children.length === 0;
|
|
371
|
+
}
|
|
372
|
+
function commitLoading(value, next) {
|
|
373
|
+
const keys = new Set(loadingKeys.value);
|
|
374
|
+
if (next) {
|
|
375
|
+
keys.add(value);
|
|
376
|
+
} else {
|
|
377
|
+
keys.delete(value);
|
|
378
|
+
}
|
|
379
|
+
loadingKeys.value = keys;
|
|
380
|
+
}
|
|
381
|
+
/** Reads the open set rather than the click, so a drag hover and a controlled key reach it too. */
|
|
382
|
+
function ensureLoaded(value) {
|
|
383
|
+
const load = props.load;
|
|
384
|
+
const meta = index.value.byValue.get(value);
|
|
385
|
+
if (!load || !meta || loadingKeys.value.has(value) || !canLoad(value)) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const parentValue = meta.parentValue;
|
|
389
|
+
commitLoading(value, true);
|
|
390
|
+
load({
|
|
391
|
+
node: meta.node,
|
|
392
|
+
depth: meta.depth,
|
|
393
|
+
parent: parentValue === undefined ? undefined : index.value.byValue.get(parentValue)?.node
|
|
394
|
+
}, (children) => {
|
|
395
|
+
commitLoading(value, false);
|
|
396
|
+
const next = new Map(loadedChildren.value);
|
|
397
|
+
next.set(value, children);
|
|
398
|
+
loadedChildren.value = next;
|
|
399
|
+
}, () => commitLoading(value, false));
|
|
400
|
+
}
|
|
189
401
|
function getRow(value) {
|
|
190
402
|
return rowByKey.value.get(value);
|
|
191
403
|
}
|
|
@@ -233,11 +445,11 @@ function toValues(value) {
|
|
|
233
445
|
}
|
|
234
446
|
return value == null ? [] : [value];
|
|
235
447
|
}
|
|
236
|
-
function onCheck(row) {
|
|
237
|
-
if (props.disabled || row.
|
|
448
|
+
function onCheck(row, event) {
|
|
449
|
+
if (props.disabled || !isSelectable(row.key)) {
|
|
238
450
|
return;
|
|
239
451
|
}
|
|
240
|
-
const next = toggle(row.key);
|
|
452
|
+
const next = event?.shiftKey ? extend(row.key) : toggle(row.key);
|
|
241
453
|
const checkedValues = toValues(next.value);
|
|
242
454
|
emits("update:modelValue", next.value);
|
|
243
455
|
emits("change", {
|
|
@@ -249,39 +461,12 @@ function onCheck(row) {
|
|
|
249
461
|
});
|
|
250
462
|
}
|
|
251
463
|
function onSearchInput(value) {
|
|
464
|
+
if (props.loading) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
252
467
|
internalSearchValue.value = value;
|
|
253
468
|
emits("update:searchValue", value);
|
|
254
469
|
}
|
|
255
|
-
/**
|
|
256
|
-
* A plain getter object, not `reactive()`: `useVirtualList` reads these inside computeds and
|
|
257
|
-
* watchers, which track the getter just the same, while a reactive wrapper would hand the
|
|
258
|
-
* virtualizer a deep proxy of the rows instead of the rows themselves.
|
|
259
|
-
*/
|
|
260
|
-
const virtualOptions = {
|
|
261
|
-
dataKey: "key",
|
|
262
|
-
get enabled() {
|
|
263
|
-
return props.virtual;
|
|
264
|
-
},
|
|
265
|
-
get items() {
|
|
266
|
-
return rows.value;
|
|
267
|
-
},
|
|
268
|
-
get itemSize() {
|
|
269
|
-
return props.itemSize;
|
|
270
|
-
},
|
|
271
|
-
get overScan() {
|
|
272
|
-
return props.overScan;
|
|
273
|
-
}
|
|
274
|
-
};
|
|
275
|
-
const { totalSize, virtualItems, scrollToIndex } = useVirtualList(containerRef, virtualOptions);
|
|
276
|
-
const highlightQuery = computed(() => props.highlightMatch ? searchValue.value.trim() : "");
|
|
277
|
-
const containerStyle = computed(() => {
|
|
278
|
-
const height = props.height;
|
|
279
|
-
if (height == null) {
|
|
280
|
-
return undefined;
|
|
281
|
-
}
|
|
282
|
-
return { height: isNumber(height) ? height + "px" : height };
|
|
283
|
-
});
|
|
284
|
-
const contentStyle = computed(() => props.virtual ? { height: totalSize.value + "px" } : undefined);
|
|
285
470
|
function isNodeDisabled(row) {
|
|
286
471
|
return props.disabled || row.node.disabled === true;
|
|
287
472
|
}
|
|
@@ -293,149 +478,51 @@ function scrollRowIntoView(index) {
|
|
|
293
478
|
});
|
|
294
479
|
return;
|
|
295
480
|
}
|
|
296
|
-
const
|
|
297
|
-
|
|
481
|
+
const row = containerRef.value?.querySelector(`[data-tree-item][data-index="${index}"]`);
|
|
482
|
+
row?.scrollIntoView({
|
|
298
483
|
block: "nearest",
|
|
299
484
|
behavior: "instant"
|
|
300
485
|
});
|
|
301
486
|
}
|
|
302
|
-
function
|
|
303
|
-
return
|
|
487
|
+
function isDragClick() {
|
|
488
|
+
return didDrag();
|
|
304
489
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
* and duplicate what `checked` already shows.
|
|
309
|
-
*/
|
|
310
|
-
const { activeIndex, dispatch, setActiveIndex } = useListNavigation({
|
|
311
|
-
count: () => rows.value.length,
|
|
312
|
-
isDisabled: isNavDisabled,
|
|
313
|
-
onActivateItem: (index) => {
|
|
314
|
-
const row = rows.value[index];
|
|
315
|
-
if (row) {
|
|
316
|
-
onCheck(row);
|
|
317
|
-
}
|
|
318
|
-
},
|
|
319
|
-
onRight: (index) => {
|
|
320
|
-
const row = rows.value[index];
|
|
321
|
-
if (!row) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
if (row.hasChildren && !row.expanded) {
|
|
325
|
-
setExpandedByValue(row.key, true);
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (row.hasChildren && index + 1 < rows.value.length) {
|
|
329
|
-
setActiveIndex(index + 1);
|
|
330
|
-
scrollRowIntoView(index + 1);
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
onLeft: () => {
|
|
334
|
-
const row = rows.value[activeIndex.value];
|
|
335
|
-
if (!row) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
if (row.hasChildren && row.expanded) {
|
|
339
|
-
setExpandedByValue(row.key, false);
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
if (row.parentValue === undefined) {
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
const parentIndex = getRow(row.parentValue)?.index;
|
|
346
|
-
if (parentIndex === undefined) {
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
setActiveIndex(parentIndex);
|
|
350
|
-
scrollRowIntoView(parentIndex);
|
|
351
|
-
},
|
|
352
|
-
scrollToIndex: scrollRowIntoView
|
|
353
|
-
});
|
|
354
|
-
const KEYMAP = {
|
|
355
|
-
ArrowDown: "next",
|
|
356
|
-
ArrowUp: "previous",
|
|
357
|
-
ArrowRight: "enter-child",
|
|
358
|
-
ArrowLeft: "leave-parent",
|
|
359
|
-
End: "last",
|
|
360
|
-
Enter: "activate",
|
|
361
|
-
Home: "first",
|
|
362
|
-
" ": "activate"
|
|
363
|
-
};
|
|
364
|
-
const { onKeydown } = useListKeyboardController({
|
|
365
|
-
keymap: KEYMAP,
|
|
366
|
-
enabled: () => !props.disabled,
|
|
367
|
-
onCommand: (command) => dispatch(command)
|
|
368
|
-
});
|
|
369
|
-
/**
|
|
370
|
-
* A focus indicator left on a blurred element lies about where the focus is, so the
|
|
371
|
-
* active row is only painted while the tree holds it. The index itself is kept:
|
|
372
|
-
* tabbing back in resumes on the row the user left from.
|
|
373
|
-
*/
|
|
374
|
-
const focused = shallowRef(false);
|
|
375
|
-
const activeDescendant = computed(() => activeIndex.value >= 0 ? uid + "-" + activeIndex.value : undefined);
|
|
376
|
-
const renderEntries = computed(() => {
|
|
377
|
-
if (props.virtual) {
|
|
378
|
-
// Only the window is ever built here: materialising an entry per row would cost more than
|
|
379
|
-
// the rows the virtual layout shows, and it would redo that on every scroll frame.
|
|
380
|
-
return virtualItems.value.flatMap((virtualItem) => {
|
|
381
|
-
const row = rows.value[virtualItem.index];
|
|
382
|
-
return row ? [{
|
|
383
|
-
...row,
|
|
384
|
-
id: uid + "-" + row.index,
|
|
385
|
-
start: virtualItem.start,
|
|
386
|
-
active: focused.value && activeIndex.value === row.index
|
|
387
|
-
}] : [];
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
const entries = [];
|
|
391
|
-
for (const row of rows.value) {
|
|
392
|
-
entries.push({
|
|
393
|
-
...row,
|
|
394
|
-
id: uid + "-" + row.index,
|
|
395
|
-
active: focused.value && activeIndex.value === row.index
|
|
396
|
-
});
|
|
490
|
+
function onRowClick(value, event) {
|
|
491
|
+
if (isDragClick()) {
|
|
492
|
+
return;
|
|
397
493
|
}
|
|
398
|
-
return entries;
|
|
399
|
-
});
|
|
400
|
-
const slots = useSlots();
|
|
401
|
-
/**
|
|
402
|
-
* A row rendered with slot children carries the DYNAMIC_SLOTS patch flag, so it re-renders
|
|
403
|
-
* with every tree update no matter which row changed. Without a node slot the flag stays
|
|
404
|
-
* off and each row is skipped unless one of its own props moved.
|
|
405
|
-
*/
|
|
406
|
-
const hasDragHandle = computed(() => !!slots["node-drag-handle"]);
|
|
407
|
-
/** A drag handle is a node slot too: forwarding it puts every row back on the dynamic path. */
|
|
408
|
-
const hasNodeSlot = computed(() => hasDragHandle.value || !!slots.node || !!slots["node-switcher"] || !!slots["node-icon"] || !!slots["node-content"] || !!slots["node-suffix"]);
|
|
409
|
-
function onRowClick(value) {
|
|
410
494
|
const row = getRow(value);
|
|
411
495
|
if (!row) {
|
|
412
496
|
return;
|
|
413
497
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
498
|
+
if (props.expandOnly && !event?.shiftKey) {
|
|
499
|
+
if (row.hasChildren) {
|
|
500
|
+
toggleNode(row);
|
|
501
|
+
}
|
|
502
|
+
if (props.multiple || row.hasChildren) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
419
505
|
}
|
|
506
|
+
onCheck(row, event);
|
|
420
507
|
}
|
|
421
508
|
function onSwitcherClick(value) {
|
|
509
|
+
if (isDragClick()) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
422
512
|
const row = getRow(value);
|
|
423
513
|
if (row) {
|
|
424
514
|
toggleNode(row);
|
|
425
515
|
}
|
|
426
516
|
}
|
|
427
|
-
function onCheckboxClick(value) {
|
|
517
|
+
function onCheckboxClick(value, event) {
|
|
518
|
+
if (isDragClick()) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
428
521
|
const row = getRow(value);
|
|
429
522
|
if (row) {
|
|
430
|
-
onCheck(row);
|
|
523
|
+
onCheck(row, event);
|
|
431
524
|
}
|
|
432
525
|
}
|
|
433
|
-
function onContainerFocus() {
|
|
434
|
-
focused.value = true;
|
|
435
|
-
}
|
|
436
|
-
function onContainerBlur() {
|
|
437
|
-
focused.value = false;
|
|
438
|
-
}
|
|
439
526
|
function scrollToKey(value) {
|
|
440
527
|
const index = getRow(value)?.index;
|
|
441
528
|
if (index !== undefined) {
|
|
@@ -444,18 +531,14 @@ function scrollToKey(value) {
|
|
|
444
531
|
}
|
|
445
532
|
function setActiveKey(value) {
|
|
446
533
|
const at = getRow(value)?.index;
|
|
447
|
-
// Without the scroll
|
|
448
|
-
// would then point at an id nothing in the document carries.
|
|
534
|
+
// Without the scroll, aria-activedescendant can point at a row outside the virtual window.
|
|
449
535
|
if (at === undefined) {
|
|
450
536
|
return;
|
|
451
537
|
}
|
|
452
538
|
setActiveIndex(at);
|
|
453
539
|
scrollRowIntoView(at);
|
|
454
540
|
}
|
|
455
|
-
/**
|
|
456
|
-
* Reads the whole index rather than the rendered rows: a collapsed subtree still holds checked
|
|
457
|
-
* nodes, and this is the same set, in the same document order, that `change` reports.
|
|
458
|
-
*/
|
|
541
|
+
/** The whole index, not the rendered rows: a collapsed subtree still holds checked nodes. */
|
|
459
542
|
function getCheckedKeys(includeIndeterminate = false) {
|
|
460
543
|
const result = [];
|
|
461
544
|
for (const meta of index.value.list) {
|
|
@@ -469,20 +552,14 @@ function getCheckedKeys(includeIndeterminate = false) {
|
|
|
469
552
|
function getVisibleKeys() {
|
|
470
553
|
return rows.value.map((row) => row.key);
|
|
471
554
|
}
|
|
472
|
-
/**
|
|
473
|
-
* A search hides whole subtrees, so a row only tells you where it sits among what is left.
|
|
474
|
-
* Dragging while a query is active would drop a node relative to an incomplete neighbourhood.
|
|
475
|
-
*/
|
|
476
|
-
const dragEnabled = computed(() => props.draggable && !props.disabled && searchValue.value.trim().length === 0);
|
|
477
555
|
function canDrop(value, targetValue, position) {
|
|
478
556
|
const meta = index.value.byValue.get(targetValue);
|
|
479
557
|
const dragNode = index.value.byValue.get(value)?.node;
|
|
480
|
-
// Structural:
|
|
481
|
-
|
|
558
|
+
// Structural: never on itself or inside its own subtree, and never inside an unloaded parent —
|
|
559
|
+
// the tree a drop proposes would lose the subtree nobody has seen yet.
|
|
560
|
+
if (!meta || !dragNode || targetValue === value || isTreeDescendant(index.value, value, targetValue) || position === "inside" && canLoad(targetValue)) {
|
|
482
561
|
return false;
|
|
483
562
|
}
|
|
484
|
-
// Policy: `allow-drop` takes it over, so a consumer can allow what the tree forbids by
|
|
485
|
-
// default (a disabled target) and forbid what it would otherwise allow.
|
|
486
563
|
if (props.allowDrop) {
|
|
487
564
|
return props.allowDrop({
|
|
488
565
|
dragValue: value,
|
|
@@ -494,31 +571,28 @@ function canDrop(value, targetValue, position) {
|
|
|
494
571
|
}
|
|
495
572
|
return meta.node.disabled !== true;
|
|
496
573
|
}
|
|
497
|
-
const { value: dragValue, target: dropTarget, x: dragX, y: dragY, onPointerDown: onDragPointerdown } = useTreeDrag({
|
|
498
|
-
container: containerRef,
|
|
499
|
-
rows: () => rows.value,
|
|
500
|
-
enabled: () => dragEnabled.value,
|
|
501
|
-
canDrop,
|
|
502
|
-
onExpand: (value) => setExpandedByValue(value, true),
|
|
503
|
-
onCommit
|
|
504
|
-
});
|
|
505
|
-
const dragNode = computed(() => dragValue.value === undefined ? undefined : index.value.byValue.get(dragValue.value)?.node);
|
|
506
|
-
/** The source node behind a key, collapsed subtree included, so callers never lose data the tree hides. */
|
|
507
574
|
function getData(value) {
|
|
508
575
|
return index.value.byValue.get(value)?.node;
|
|
509
576
|
}
|
|
510
|
-
/**
|
|
511
|
-
* The tree never writes `data` itself: the caller owns it, so a drop only proposes the next
|
|
512
|
-
* tree through `update:data`. A move that resolves to the current shape emits nothing.
|
|
513
|
-
*/
|
|
577
|
+
/** The caller owns `data`: a drop only proposes the next tree, and a no-op move is silent. */
|
|
514
578
|
function onCommit(value, target) {
|
|
515
|
-
|
|
579
|
+
// The grafted tree, not the prop: nodes that arrived through `load` live only in there.
|
|
580
|
+
const result = moveTreeNode(treeData.value, props.childrenField, value, target);
|
|
516
581
|
if (!result) {
|
|
517
582
|
return;
|
|
518
583
|
}
|
|
519
584
|
emits("update:data", result.data);
|
|
520
585
|
emits("move", result.detail);
|
|
586
|
+
if (target.position === "inside") {
|
|
587
|
+
setExpandedByValue(target.targetValue, true);
|
|
588
|
+
}
|
|
521
589
|
}
|
|
590
|
+
// `treeData` too: a key below a parent still on its way only becomes loadable once it arrives.
|
|
591
|
+
watch([expanded, treeData], ([keys]) => {
|
|
592
|
+
for (const value of keys) {
|
|
593
|
+
ensureLoaded(value);
|
|
594
|
+
}
|
|
595
|
+
}, { immediate: true });
|
|
522
596
|
defineExpose({
|
|
523
597
|
focus: () => containerRef.value?.focus(),
|
|
524
598
|
scrollToKey,
|
|
@@ -535,17 +609,13 @@ defineExpose({
|
|
|
535
609
|
</script>
|
|
536
610
|
|
|
537
611
|
<template>
|
|
538
|
-
<!--
|
|
539
|
-
The filter sits outside the tree on purpose: a text field is not a node, and `role="tree"`
|
|
540
|
-
owns only `treeitem` content. Keeping it a sibling also leaves it on screen while the tree
|
|
541
|
-
scrolls.
|
|
542
|
-
-->
|
|
543
612
|
<div data-tree class="pxd-tree-root w-full max-w-full">
|
|
544
613
|
<div v-if="filterable" data-tree-search class="pxd-tree--search mbe-1">
|
|
545
614
|
<slot name="search">
|
|
546
615
|
<PSearchInput
|
|
547
616
|
:model-value="searchValue"
|
|
548
617
|
:placeholder="searchPlaceholder"
|
|
618
|
+
:loading="loading || searchPending"
|
|
549
619
|
@update:model-value="onSearchInput"
|
|
550
620
|
/>
|
|
551
621
|
</slot>
|
|
@@ -555,14 +625,16 @@ defineExpose({
|
|
|
555
625
|
ref="containerRef"
|
|
556
626
|
role="tree"
|
|
557
627
|
tabindex="0"
|
|
558
|
-
class="pxd-tree m-0
|
|
628
|
+
class="pxd-tree m-0 relative w-full max-w-full overflow-auto rounded-inherit bg-background-100 outline-none"
|
|
629
|
+
:class="{ 'min-h-22': loading && !rows.length }"
|
|
559
630
|
:style="containerStyle"
|
|
631
|
+
:aria-busy="loading"
|
|
560
632
|
:aria-multiselectable="multiple || void 0"
|
|
561
633
|
:aria-activedescendant="focused ? activeDescendant : void 0"
|
|
562
634
|
v-bind="$attrs"
|
|
563
635
|
@keydown="onKeydown"
|
|
564
|
-
@focus="
|
|
565
|
-
@blur="
|
|
636
|
+
@focus="focused = true"
|
|
637
|
+
@blur="focused = false"
|
|
566
638
|
>
|
|
567
639
|
<div class="pxd-tree--content w-full" :class="{ relative: virtual }" :style="contentStyle">
|
|
568
640
|
<div
|
|
@@ -582,6 +654,7 @@ defineExpose({
|
|
|
582
654
|
:index="entry.index"
|
|
583
655
|
:has-children="entry.hasChildren"
|
|
584
656
|
:expanded="entry.expanded"
|
|
657
|
+
:loading="loadingKeys.has(entry.key)"
|
|
585
658
|
:checked="checked.has(entry.key)"
|
|
586
659
|
:indeterminate="indeterminate.has(entry.key)"
|
|
587
660
|
:active="entry.active"
|
|
@@ -589,11 +662,10 @@ defineExpose({
|
|
|
589
662
|
:disabled="disabled"
|
|
590
663
|
:set-size="rows.length"
|
|
591
664
|
:indent="indent"
|
|
665
|
+
:selectable="isSelectable(entry.key)"
|
|
592
666
|
:highlight-query="highlightQuery"
|
|
593
|
-
:show-icon="showIcon"
|
|
594
667
|
:item-class="itemClass"
|
|
595
668
|
:draggable="dragEnabled"
|
|
596
|
-
:drag-handle="hasDragHandle"
|
|
597
669
|
:dragging="entry.key === dragValue"
|
|
598
670
|
:drop-position="dropTarget?.targetValue === entry.key ? dropTarget.position : void 0"
|
|
599
671
|
@row-click="onRowClick"
|
|
@@ -601,10 +673,6 @@ defineExpose({
|
|
|
601
673
|
@check="onCheckboxClick"
|
|
602
674
|
@toggle="onSwitcherClick"
|
|
603
675
|
>
|
|
604
|
-
<template #node="scope">
|
|
605
|
-
<slot name="node" v-bind="scope" />
|
|
606
|
-
</template>
|
|
607
|
-
|
|
608
676
|
<template #node-switcher="scope">
|
|
609
677
|
<slot name="node-switcher" v-bind="scope" />
|
|
610
678
|
</template>
|
|
@@ -620,10 +688,6 @@ defineExpose({
|
|
|
620
688
|
<template #node-suffix="scope">
|
|
621
689
|
<slot name="node-suffix" v-bind="scope" />
|
|
622
690
|
</template>
|
|
623
|
-
|
|
624
|
-
<template #node-drag-handle="scope">
|
|
625
|
-
<slot name="node-drag-handle" v-bind="scope" />
|
|
626
|
-
</template>
|
|
627
691
|
</PTreeNode>
|
|
628
692
|
|
|
629
693
|
<PTreeNode
|
|
@@ -635,6 +699,7 @@ defineExpose({
|
|
|
635
699
|
:index="entry.index"
|
|
636
700
|
:has-children="entry.hasChildren"
|
|
637
701
|
:expanded="entry.expanded"
|
|
702
|
+
:loading="loadingKeys.has(entry.key)"
|
|
638
703
|
:checked="checked.has(entry.key)"
|
|
639
704
|
:indeterminate="indeterminate.has(entry.key)"
|
|
640
705
|
:active="entry.active"
|
|
@@ -642,11 +707,10 @@ defineExpose({
|
|
|
642
707
|
:disabled="disabled"
|
|
643
708
|
:set-size="rows.length"
|
|
644
709
|
:indent="indent"
|
|
710
|
+
:selectable="isSelectable(entry.key)"
|
|
645
711
|
:highlight-query="highlightQuery"
|
|
646
|
-
:show-icon="showIcon"
|
|
647
712
|
:item-class="itemClass"
|
|
648
713
|
:draggable="dragEnabled"
|
|
649
|
-
:drag-handle="hasDragHandle"
|
|
650
714
|
:dragging="entry.key === dragValue"
|
|
651
715
|
:drop-position="dropTarget?.targetValue === entry.key ? dropTarget.position : void 0"
|
|
652
716
|
@row-click="onRowClick"
|
|
@@ -657,9 +721,11 @@ defineExpose({
|
|
|
657
721
|
</div>
|
|
658
722
|
</div>
|
|
659
723
|
|
|
724
|
+
<PLoadingMask v-if="loading" />
|
|
725
|
+
|
|
660
726
|
<div
|
|
661
|
-
v-if="!rows.length"
|
|
662
|
-
class="pxd-tree--empty py-
|
|
727
|
+
v-else-if="!rows.length"
|
|
728
|
+
class="pxd-tree--empty py-8.5 text-sm text-center text-foreground-secondary"
|
|
663
729
|
>
|
|
664
730
|
<slot name="empty" />
|
|
665
731
|
</div>
|
|
@@ -668,6 +734,7 @@ defineExpose({
|
|
|
668
734
|
<PTeleport to="body">
|
|
669
735
|
<div
|
|
670
736
|
v-if="dragValue !== void 0"
|
|
737
|
+
aria-hidden="true"
|
|
671
738
|
class="pxd-tree--drag-preview px-2 py-1 text-sm shadow-lg pointer-events-none fixed z-50 rounded-md border border-gray-300 bg-background-100 text-foreground"
|
|
672
739
|
:style="{ left: dragX + 'px', top: dragY + 'px' }"
|
|
673
740
|
>
|