@xleddyl/443-components-vue 0.2.3 → 0.4.0

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.
Files changed (236) hide show
  1. package/README.md +106 -19
  2. package/dist/chart/BarChart.vue.d.ts +2 -2
  3. package/dist/chart/ChartLegend.vue.d.ts +4 -4
  4. package/dist/chart/ChartPanel.vue.d.ts +2 -2
  5. package/dist/chart/ChartSummary.vue.d.ts +2 -2
  6. package/dist/chart/DoughnutChart.vue.d.ts +2 -2
  7. package/dist/chart/LineChart.vue.d.ts +2 -2
  8. package/dist/components/core/Button.vue.d.ts +2 -2
  9. package/dist/components/core/FieldBoundary.vue +14 -0
  10. package/dist/components/core/FieldBoundary.vue.d.ts +15 -0
  11. package/dist/components/core/FieldMessage.vue +28 -0
  12. package/dist/components/core/FieldMessage.vue.d.ts +409 -0
  13. package/dist/components/core/Form.vue +109 -11
  14. package/dist/components/core/Form.vue.d.ts +45 -6
  15. package/dist/components/core/FormAlerts.vue +30 -0
  16. package/dist/components/core/FormAlerts.vue.d.ts +393 -0
  17. package/dist/components/core/FormField.vue +54 -17
  18. package/dist/components/core/FormField.vue.d.ts +5 -4
  19. package/dist/components/core/Icon.vue.d.ts +2 -2
  20. package/dist/components/core/Input.vue.d.ts +4 -4
  21. package/dist/components/core/Kbd.vue.d.ts +2 -2
  22. package/dist/components/core/Root.vue.d.ts +6 -6
  23. package/dist/components/core/Spinner.vue +13 -1
  24. package/dist/components/core/Spinner.vue.d.ts +4 -2
  25. package/dist/components/core/Textarea.vue.d.ts +4 -4
  26. package/dist/components/core/VisuallyHidden.vue.d.ts +6 -6
  27. package/dist/components/core/index.d.ts +3 -0
  28. package/dist/components/core/index.mjs +3 -0
  29. package/dist/components/data/Avatar.vue.d.ts +2 -2
  30. package/dist/components/data/AvatarGroup.vue.d.ts +2 -2
  31. package/dist/components/data/Badge.vue.d.ts +2 -2
  32. package/dist/components/data/DescriptionList.vue.d.ts +2 -2
  33. package/dist/components/data/FilterPill.vue +35 -0
  34. package/dist/components/data/FilterPill.vue.d.ts +445 -0
  35. package/dist/components/data/FilterPills.vue +100 -27
  36. package/dist/components/data/FilterPills.vue.d.ts +47 -411
  37. package/dist/components/data/Pagination.vue.d.ts +4 -4
  38. package/dist/components/data/SelectionBar.vue +81 -0
  39. package/dist/components/data/SelectionBar.vue.d.ts +427 -0
  40. package/dist/components/data/Stat.vue.d.ts +8 -8
  41. package/dist/components/data/Tag.vue.d.ts +4 -4
  42. package/dist/components/data/Timeline.vue.d.ts +2 -2
  43. package/dist/components/data/Tree.vue +245 -21
  44. package/dist/components/data/Tree.vue.d.ts +40 -10
  45. package/dist/components/data/index.d.ts +3 -0
  46. package/dist/components/data/index.mjs +3 -0
  47. package/dist/components/data/types.d.ts +26 -2
  48. package/dist/components/feedback/Alert.vue.d.ts +18 -18
  49. package/dist/components/feedback/EmptyState.vue.d.ts +2 -2
  50. package/dist/components/feedback/LoadingOverlay.vue.d.ts +2 -2
  51. package/dist/components/feedback/Meter.vue.d.ts +2 -2
  52. package/dist/components/feedback/Progress.vue.d.ts +2 -2
  53. package/dist/components/feedback/ProgressRing.vue.d.ts +2 -2
  54. package/dist/components/feedback/Skeleton.vue.d.ts +3 -3
  55. package/dist/components/forms/Calendar.vue.d.ts +4 -4
  56. package/dist/components/forms/CheckboxGroup.vue +2 -1
  57. package/dist/components/forms/ColorInput.vue.d.ts +6 -6
  58. package/dist/components/forms/DateInput.vue.d.ts +14 -14
  59. package/dist/components/forms/DatePicker.vue.d.ts +6 -6
  60. package/dist/components/forms/FileInput.vue +160 -34
  61. package/dist/components/forms/FileInput.vue.d.ts +43 -15
  62. package/dist/components/forms/InputAddon.vue.d.ts +2 -2
  63. package/dist/components/forms/InputGroup.vue.d.ts +2 -2
  64. package/dist/components/forms/NumberInput.vue.d.ts +6 -6
  65. package/dist/components/forms/PasswordInput.vue.d.ts +16 -16
  66. package/dist/components/forms/PinInput.vue.d.ts +6 -6
  67. package/dist/components/forms/Radio.vue.d.ts +2 -2
  68. package/dist/components/forms/RadioGroup.vue +2 -1
  69. package/dist/components/forms/SegmentedControl.vue +33 -8
  70. package/dist/components/forms/SegmentedControl.vue.d.ts +15 -7
  71. package/dist/components/forms/Slider.vue.d.ts +6 -6
  72. package/dist/components/forms/Switch.vue.d.ts +6 -6
  73. package/dist/components/forms/TimeInput.vue.d.ts +16 -16
  74. package/dist/components/forms/types.d.ts +17 -0
  75. package/dist/components/layout/Accordion.vue +25 -5
  76. package/dist/components/layout/Accordion.vue.d.ts +11 -8
  77. package/dist/components/layout/AppShell.vue +1 -1
  78. package/dist/components/layout/AppShell.vue.d.ts +7 -7
  79. package/dist/components/layout/Breadcrumbs.vue +28 -20
  80. package/dist/components/layout/Breadcrumbs.vue.d.ts +18 -3
  81. package/dist/components/layout/Card.vue +22 -3
  82. package/dist/components/layout/Card.vue.d.ts +10 -4
  83. package/dist/components/layout/CopyButton.vue.d.ts +4 -4
  84. package/dist/components/layout/Grid.vue.d.ts +2 -2
  85. package/dist/components/layout/NavLink.vue.d.ts +8 -8
  86. package/dist/components/layout/PageHeader.vue +10 -1
  87. package/dist/components/layout/PageHeader.vue.d.ts +17 -9
  88. package/dist/components/layout/Separator.vue.d.ts +2 -2
  89. package/dist/components/layout/Sidebar.vue.d.ts +2 -2
  90. package/dist/components/layout/SidebarSection.vue.d.ts +2 -2
  91. package/dist/components/layout/Stack.vue.d.ts +6 -6
  92. package/dist/components/layout/Tabs.vue +37 -7
  93. package/dist/components/layout/Tabs.vue.d.ts +11 -4
  94. package/dist/components/layout/ThemeSwitch.vue.d.ts +2 -2
  95. package/dist/components/layout/Toolbar.vue.d.ts +2 -2
  96. package/dist/components/layout/types.d.ts +8 -1
  97. package/dist/components/overlays/CommandPalette.vue +35 -8
  98. package/dist/components/overlays/CommandPalette.vue.d.ts +273 -497
  99. package/dist/components/overlays/ConfirmDialog.vue.d.ts +8 -6
  100. package/dist/components/overlays/ConfirmHost.vue +5 -1
  101. package/dist/components/overlays/ConfirmHost.vue.d.ts +10 -8
  102. package/dist/components/overlays/ContextMenu.vue.d.ts +4 -4
  103. package/dist/components/overlays/Drawer.vue +4 -2
  104. package/dist/components/overlays/Drawer.vue.d.ts +8 -6
  105. package/dist/components/overlays/DropdownMenu.vue.d.ts +2 -2
  106. package/dist/components/overlays/HoverCard.vue +2 -1
  107. package/dist/components/overlays/HoverCard.vue.d.ts +8 -8
  108. package/dist/components/overlays/Modal.vue +5 -3
  109. package/dist/components/overlays/Modal.vue.d.ts +8 -6
  110. package/dist/components/overlays/Popover.vue +2 -1
  111. package/dist/components/overlays/Popover.vue.d.ts +8 -8
  112. package/dist/components/overlays/Toaster.vue.d.ts +4 -4
  113. package/dist/components/overlays/Tooltip.vue.d.ts +2 -2
  114. package/dist/components/overlays/types.d.ts +11 -5
  115. package/dist/components/templates/AccountMenu.vue.d.ts +6 -6
  116. package/dist/components/templates/AppearanceSettings.vue.d.ts +2 -2
  117. package/dist/components/templates/AuthLayout.vue.d.ts +2 -2
  118. package/dist/components/templates/Brand.vue +34 -5
  119. package/dist/components/templates/Brand.vue.d.ts +20 -15
  120. package/dist/components/templates/DashboardLayout.vue +49 -10
  121. package/dist/components/templates/DashboardLayout.vue.d.ts +332 -553
  122. package/dist/components/templates/DashboardPage.vue.d.ts +2 -2
  123. package/dist/components/templates/DetailPage.vue.d.ts +4 -4
  124. package/dist/components/templates/EmptyPage.vue.d.ts +2 -2
  125. package/dist/components/templates/ErrorPage.vue.d.ts +2 -2
  126. package/dist/components/templates/ListPage.vue +17 -11
  127. package/dist/components/templates/ListPage.vue.d.ts +3 -3
  128. package/dist/components/templates/NotFoundPage.vue.d.ts +1 -1
  129. package/dist/components/templates/SaveBar.vue.d.ts +4 -4
  130. package/dist/components/templates/SettingsGroup.vue.d.ts +2 -2
  131. package/dist/components/templates/SettingsModal.vue +5 -2
  132. package/dist/components/templates/SettingsModal.vue.d.ts +13 -8
  133. package/dist/components/templates/SettingsPage.vue.d.ts +4 -4
  134. package/dist/components/templates/SettingsSection.vue.d.ts +12 -8
  135. package/dist/components/templates/types.d.ts +25 -2
  136. package/dist/composables/core.d.ts +1 -0
  137. package/dist/composables/core.mjs +1 -0
  138. package/dist/composables/useField.d.ts +8 -1
  139. package/dist/composables/useField.mjs +41 -10
  140. package/dist/composables/useFieldBoundary.d.ts +2 -0
  141. package/dist/composables/useFieldBoundary.mjs +9 -0
  142. package/dist/composables/useFileDrop.d.ts +20 -0
  143. package/dist/composables/useFileDrop.mjs +115 -7
  144. package/dist/composables/useForm.d.ts +36 -19
  145. package/dist/composables/useForm.mjs +258 -51
  146. package/dist/editor/RichTextEditor.vue +32 -4
  147. package/dist/editor/RichTextEditor.vue.d.ts +11 -6
  148. package/dist/editor/rich-text-editor.css +1 -1
  149. package/dist/editor/types.d.ts +3 -0
  150. package/dist/grid/GridToolbar.vue.d.ts +4 -4
  151. package/dist/grid/cells/BadgeCell.vue.d.ts +2 -2
  152. package/dist/grid/cells/BooleanCell.vue.d.ts +2 -2
  153. package/dist/grid/cells/DateCell.vue.d.ts +2 -2
  154. package/dist/grid/cells/ImageCell.vue.d.ts +2 -2
  155. package/dist/grid/cells/LinkCell.vue.d.ts +2 -2
  156. package/dist/internal/core/ButtonElement.d.ts +2 -0
  157. package/dist/internal/core/ButtonElement.mjs +8 -0
  158. package/dist/internal/data/tree.d.ts +8 -0
  159. package/dist/internal/data/tree.mjs +41 -0
  160. package/dist/internal/forms/files.d.ts +9 -0
  161. package/dist/internal/forms/files.mjs +32 -1
  162. package/dist/internal/forms/standard-schema.d.ts +17 -0
  163. package/dist/internal/forms/standard-schema.mjs +40 -0
  164. package/dist/internal/keys.d.ts +2 -1
  165. package/dist/internal/keys.mjs +1 -0
  166. package/dist/internal/overlays/DialogFrame.vue +17 -7
  167. package/dist/internal/overlays/DialogFrame.vue.d.ts +9 -5
  168. package/dist/internal/overlays/MenuList.vue +2 -0
  169. package/dist/internal/overlays/MenuList.vue.d.ts +5 -5
  170. package/dist/internal/overlays/OverlayView.vue +2 -0
  171. package/dist/internal/overlays/OverlayView.vue.d.ts +14 -12
  172. package/dist/internal/overlays/dialog.d.ts +4 -1
  173. package/dist/internal/overlays/dialog.mjs +39 -5
  174. package/dist/internal/overlays/stack.d.ts +2 -1
  175. package/dist/locale/en.mjs +19 -2
  176. package/dist/locale/it.mjs +19 -2
  177. package/dist/locale/types.d.ts +17 -0
  178. package/dist/nuxt/module.d.ts +1 -0
  179. package/dist/nuxt/module.mjs +6 -3
  180. package/dist/nuxt/runtime/layouts/auth.vue.d.ts +8 -8
  181. package/dist/nuxt/runtime/layouts/dashboard.vue.d.ts +8 -8
  182. package/dist/styles/base.css +2 -0
  183. package/dist/styles/core/button.css +1 -13
  184. package/dist/styles/core/field-message.css +34 -0
  185. package/dist/styles/core/form-field.css +0 -23
  186. package/dist/styles/core/form.css +11 -0
  187. package/dist/styles/core/kbd.css +2 -2
  188. package/dist/styles/core/spinner.css +19 -0
  189. package/dist/styles/core.css +1 -0
  190. package/dist/styles/data/avatar.css +1 -1
  191. package/dist/styles/data/badge.css +1 -1
  192. package/dist/styles/data/filter-pills.css +40 -4
  193. package/dist/styles/data/pagination.css +0 -1
  194. package/dist/styles/data/selection-bar.css +89 -0
  195. package/dist/styles/data/stat.css +1 -6
  196. package/dist/styles/data/table.css +1 -3
  197. package/dist/styles/data/tag.css +1 -4
  198. package/dist/styles/data/tree.css +163 -2
  199. package/dist/styles/data.css +1 -0
  200. package/dist/styles/feedback/alert.css +0 -1
  201. package/dist/styles/feedback/empty-state.css +0 -1
  202. package/dist/styles/forms/calendar.css +1 -1
  203. package/dist/styles/forms/color-input.css +1 -1
  204. package/dist/styles/forms/combobox.css +0 -1
  205. package/dist/styles/forms/date-picker.css +1 -1
  206. package/dist/styles/forms/file-input.css +17 -1
  207. package/dist/styles/forms/number-input.css +1 -1
  208. package/dist/styles/forms/password-input.css +1 -5
  209. package/dist/styles/forms/segmented.css +8 -0
  210. package/dist/styles/forms/select.css +1 -1
  211. package/dist/styles/forms/slider.css +2 -2
  212. package/dist/styles/forms/switch.css +0 -1
  213. package/dist/styles/layout/accordion.css +22 -1
  214. package/dist/styles/layout/app-shell.css +4 -0
  215. package/dist/styles/layout/breadcrumbs.css +16 -1
  216. package/dist/styles/layout/card.css +20 -6
  217. package/dist/styles/layout/copy-button.css +2 -2
  218. package/dist/styles/layout/nav-link.css +2 -3
  219. package/dist/styles/layout/sidebar-nav.css +1 -1
  220. package/dist/styles/layout/sidebar.css +2 -2
  221. package/dist/styles/layout/tabs.css +65 -3
  222. package/dist/styles/layout/theme-switch.css +1 -3
  223. package/dist/styles/overlays/command.css +21 -3
  224. package/dist/styles/overlays/confirm.css +0 -1
  225. package/dist/styles/overlays/menu.css +3 -5
  226. package/dist/styles/overlays/modal.css +38 -0
  227. package/dist/styles/overlays/toast.css +0 -1
  228. package/dist/styles/templates/auth-layout.css +0 -1
  229. package/dist/styles/templates/brand.css +15 -0
  230. package/dist/styles/templates/empty-page.css +4 -4
  231. package/dist/styles/templates/form-page.css +1 -1
  232. package/dist/styles/templates/list-page.css +2 -6
  233. package/dist/styles/templates/page.css +1 -1
  234. package/dist/styles/templates/settings-modal.css +2 -3
  235. package/dist/styles/tokens.css +1 -1
  236. package/package.json +1 -1
@@ -1,10 +1,27 @@
1
1
  <template>
2
2
  <ul
3
3
  ref="tree"
4
+ :id="control.id.value"
5
+ :aria-label="ariaLabel"
6
+ :aria-labelledby="ariaLabelledby"
7
+ v-bind="$attrs"
8
+ :aria-describedby="joinIds($attrs['aria-describedby'], control.describedBy.value)"
9
+ :aria-invalid="control.invalid.value ? 'true' : void 0"
10
+ :aria-required="control.required.value ? 'true' : void 0"
11
+ :aria-disabled="control.disabled.value ? 'true' : void 0"
4
12
  class="k-tree"
5
13
  role="tree"
6
- :aria-label="treeText"
7
- :class="{ 'is-bordered': bordered }"
14
+ :class="[
15
+ `k-tree-${size}`,
16
+ {
17
+ 'is-bordered': bordered,
18
+ 'is-reorderable': canReorder,
19
+ 'is-dragging': dragId !== null,
20
+ 'is-invalid': control.invalid.value,
21
+ 'is-disabled': control.disabled.value
22
+ }
23
+ ]"
24
+ data-k-shake
8
25
  >
9
26
  <li
10
27
  v-for="(entry, index) in visible"
@@ -18,7 +35,11 @@
18
35
  :aria-expanded="entry.hasChildren ? isExpanded(entry.node.id) : void 0"
19
36
  :aria-selected="selectable ? selected === entry.node.id : void 0"
20
37
  :aria-disabled="entry.node.disabled ? 'true' : void 0"
38
+ :aria-describedby="canReorder && !entry.node.disabled ? hintId : void 0"
39
+ :aria-keyshortcuts="canReorder && !entry.node.disabled ? keyShortcuts : void 0"
21
40
  :tabindex="entry.node.id === rovingId ? 0 : -1"
41
+ :class="{ 'is-moving': dragId === entry.node.id }"
42
+ :data-drop="dropState?.id === entry.node.id ? dropState.position : void 0"
22
43
  :style="{
23
44
  '--k-tree-level': entry.level - 1,
24
45
  '--k-row-delay': rowDelay(index - revealAnchor - 1)
@@ -26,7 +47,29 @@
26
47
  @click="activate(entry)"
27
48
  @keydown="onKeydown($event, entry, index)"
28
49
  @focus="focusId = entry.node.id"
50
+ @dragover="onDragOver($event, entry)"
51
+ @dragleave="onDragLeave($event, entry)"
52
+ @drop="onDrop($event, entry)"
29
53
  >
54
+ <span
55
+ v-if="canReorder"
56
+ class="k-tree-handle"
57
+ :class="{ 'is-disabled': entry.node.disabled }"
58
+ :draggable="entry.node.disabled ? void 0 : 'true'"
59
+ aria-hidden="true"
60
+ @dragstart="onDragStart($event, entry)"
61
+ @dragend="endDrag"
62
+ @click.stop
63
+ >
64
+ <svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
65
+ <circle cx="6" cy="4" r="1.1" />
66
+ <circle cx="10" cy="4" r="1.1" />
67
+ <circle cx="6" cy="8" r="1.1" />
68
+ <circle cx="10" cy="8" r="1.1" />
69
+ <circle cx="6" cy="12" r="1.1" />
70
+ <circle cx="10" cy="12" r="1.1" />
71
+ </svg>
72
+ </span>
30
73
  <span class="k-tree-toggle" aria-hidden="true" @click.stop="toggle(entry, index)">
31
74
  <Icon v-if="entry.hasChildren" name="chevron-right" />
32
75
  </span>
@@ -36,38 +79,89 @@
36
79
  <span class="k-tree-text">
37
80
  <slot name="label" :node="entry.node" :level="entry.level">
38
81
  <span class="k-tree-label">{{ entry.node.label }}</span>
39
- <span v-if="entry.node.description" class="k-tree-description">{{
40
- entry.node.description
41
- }}</span>
82
+ <span
83
+ v-if="entry.node.description"
84
+ class="k-tree-description"
85
+ :class="`k-tree-description-${entry.node.descriptionVariant ?? descriptionVariant}`"
86
+ >{{ entry.node.description }}</span
87
+ >
42
88
  </slot>
43
89
  </span>
44
90
  <span v-if="entry.node.meta || $slots.meta" class="k-tree-meta">
45
91
  <slot name="meta" :node="entry.node">{{ entry.node.meta }}</slot>
46
92
  </span>
93
+ <span v-if="checkmark && selectable" class="k-tree-check" aria-hidden="true">
94
+ <Icon v-if="selected === entry.node.id" name="check" />
95
+ </span>
96
+ </li>
97
+ <li v-if="!visible.length" class="k-tree-empty" role="none">
98
+ <slot name="empty">{{ emptyLabel }}</slot>
47
99
  </li>
48
100
  </ul>
101
+ <template v-if="canReorder">
102
+ <span :id="hintId" class="k-visually-hidden">{{ hintText }}</span>
103
+ <span class="k-visually-hidden" role="status" aria-live="polite">{{ announcement }}</span>
104
+ </template>
49
105
  </template>
50
106
 
51
107
  <script setup>
52
108
  import { computed, nextTick, ref, useId, useTemplateRef } from "vue";
109
+ import { useFieldControl } from "../../composables/useField";
53
110
  import { useLocale } from "../../composables/useLocale";
111
+ import { joinIds } from "../../internal/forms/control";
54
112
  import Icon from "../core/Icon.vue";
55
113
  import { rowDelay } from "../../internal/data/stagger";
114
+ defineOptions({ inheritAttrs: false });
56
115
  const props = defineProps({
57
116
  nodes: { type: Array, required: true },
58
117
  label: { type: String, required: false },
59
118
  selectable: { type: Boolean, required: false, default: true },
60
- bordered: { type: Boolean, required: false, default: true }
119
+ bordered: { type: Boolean, required: false, default: true },
120
+ size: { type: String, required: false, default: "md" },
121
+ checkmark: { type: Boolean, required: false },
122
+ emptyText: { type: String, required: false },
123
+ descriptionVariant: { type: String, required: false, default: "mono" },
124
+ reorderable: { type: Boolean, required: false },
125
+ nestable: { type: Boolean, required: false },
126
+ canDrop: { type: Function, required: false },
127
+ reorderText: { type: String, required: false },
128
+ invalid: { type: Boolean, required: false, default: void 0 },
129
+ disabled: { type: Boolean, required: false },
130
+ required: { type: Boolean, required: false }
61
131
  });
62
132
  const { t } = useLocale();
63
- const treeText = computed(() => props.label ?? t("tree.label"));
64
- const emit = defineEmits(["select"]);
133
+ const emit = defineEmits(["select", "move"]);
65
134
  const expanded = defineModel("expanded", { type: Array, ...{ default: () => [] } });
66
135
  const selected = defineModel("selected", { type: [String, Number, null], ...{ default: null } });
136
+ const control = useFieldControl({
137
+ invalid: () => props.invalid,
138
+ disabled: () => props.disabled,
139
+ required: () => props.required,
140
+ labelable: false
141
+ });
67
142
  const baseId = useId();
143
+ const hintId = `${baseId}-hint`;
68
144
  const tree = useTemplateRef("tree");
69
145
  const focusId = ref(selected.value ?? props.nodes[0]?.id ?? null);
70
146
  const revealAnchor = ref(-1);
147
+ const dragId = ref(null);
148
+ const dropState = ref(null);
149
+ const announcement = ref("");
150
+ const ariaLabel = computed(() => {
151
+ if (props.label) return props.label;
152
+ return control.field ? void 0 : t("tree.label");
153
+ });
154
+ const ariaLabelledby = computed(
155
+ () => !props.label && control.field ? control.field.labelId : void 0
156
+ );
157
+ const emptyLabel = computed(() => props.emptyText ?? t("tree.empty"));
158
+ const canReorder = computed(() => props.reorderable && !control.disabled.value);
159
+ const hintText = computed(
160
+ () => props.reorderText ?? t(props.nestable ? "tree.reorderNestedHint" : "tree.reorderHint")
161
+ );
162
+ const keyShortcuts = computed(
163
+ () => props.nestable ? "Alt+ArrowUp Alt+ArrowDown Alt+ArrowLeft Alt+ArrowRight" : "Alt+ArrowUp Alt+ArrowDown"
164
+ );
71
165
  const expandedSet = computed(() => new Set(expanded.value));
72
166
  function rowId(id) {
73
167
  return `${baseId}-node-${id}`;
@@ -75,16 +169,27 @@ function rowId(id) {
75
169
  function isExpanded(id) {
76
170
  return expandedSet.value.has(id);
77
171
  }
172
+ const index = computed(() => {
173
+ const map = /* @__PURE__ */ new Map();
174
+ const walk = (nodes, parent) => {
175
+ nodes.forEach((node, position) => {
176
+ map.set(node.id, { node, parent, index: position, siblings: nodes });
177
+ if (node.children?.length) walk(node.children, node.id);
178
+ });
179
+ };
180
+ walk(props.nodes, null);
181
+ return map;
182
+ });
78
183
  const visible = computed(() => {
79
184
  const result = [];
80
185
  const walk = (nodes, level, parentId) => {
81
- nodes.forEach((node, index) => {
186
+ nodes.forEach((node, position) => {
82
187
  const hasChildren = Boolean(node.children?.length);
83
188
  result.push({
84
189
  node,
85
190
  level,
86
191
  setSize: nodes.length,
87
- position: index + 1,
192
+ position: position + 1,
88
193
  parentId,
89
194
  hasChildren
90
195
  });
@@ -99,18 +204,19 @@ const rovingId = computed(() => {
99
204
  if (list.some((entry) => entry.node.id === focusId.value)) return focusId.value;
100
205
  return list.find((entry) => entry.node.id === selected.value)?.node.id ?? list[0]?.node.id;
101
206
  });
102
- function setExpanded(entry, index, open) {
207
+ function setExpanded(entry, position, open) {
103
208
  if (!entry.hasChildren || isExpanded(entry.node.id) === open) return;
104
- revealAnchor.value = index;
209
+ revealAnchor.value = position;
105
210
  expanded.value = open ? [...expanded.value, entry.node.id] : expanded.value.filter((id) => id !== entry.node.id);
106
211
  }
107
- function toggle(entry, index) {
212
+ function toggle(entry, position) {
108
213
  if (entry.node.disabled) return;
109
- setExpanded(entry, index, !isExpanded(entry.node.id));
214
+ setExpanded(entry, position, !isExpanded(entry.node.id));
110
215
  }
111
216
  function activate(entry) {
112
217
  if (entry.node.disabled) return;
113
218
  focusId.value = entry.node.id;
219
+ if (control.disabled.value) return;
114
220
  if (props.selectable) selected.value = entry.node.id;
115
221
  emit("select", entry.node);
116
222
  }
@@ -121,14 +227,80 @@ function focusNode(id) {
121
227
  tree.value?.querySelector(`#${CSS.escape(rowId(id))}`)?.focus();
122
228
  });
123
229
  }
124
- function onKeydown(event, entry, index) {
230
+ function contains(node, id) {
231
+ return Boolean(node.children?.some((child) => child.id === id || contains(child, id)));
232
+ }
233
+ function buildMove(nodeId, targetId, position) {
234
+ const source = index.value.get(nodeId);
235
+ const target = index.value.get(targetId);
236
+ if (!source || !target || nodeId === targetId) return null;
237
+ if (source.node.disabled || contains(source.node, targetId)) return null;
238
+ const from = { parent: source.parent, index: source.index };
239
+ let to;
240
+ if (position === "inside") {
241
+ if (!props.nestable || target.node.disabled) return null;
242
+ const children = target.node.children ?? [];
243
+ const count = children.filter((child) => child.id !== nodeId).length;
244
+ to = { parent: targetId, index: count };
245
+ } else {
246
+ if (!props.nestable && target.parent !== source.parent) return null;
247
+ let at = position === "before" ? target.index : target.index + 1;
248
+ if (target.parent === source.parent && source.index < at) at--;
249
+ to = { parent: target.parent, index: at };
250
+ }
251
+ if (to.parent === from.parent && to.index === from.index) return null;
252
+ const move = { node: source.node, target: target.node, position, from, to };
253
+ if (props.canDrop && !props.canDrop(move)) return null;
254
+ return move;
255
+ }
256
+ function announce(move) {
257
+ const parent = move.to.parent === null ? void 0 : index.value.get(move.to.parent);
258
+ const siblings = parent ? parent.node.children ?? [] : props.nodes;
259
+ const count = move.to.parent === move.from.parent ? siblings.length : siblings.length + 1;
260
+ const params = {
261
+ label: move.node.label,
262
+ position: move.to.index + 1,
263
+ count,
264
+ parent: parent?.node.label ?? ""
265
+ };
266
+ const key = parent && move.to.parent !== move.from.parent ? "tree.movedInto" : "tree.moved";
267
+ announcement.value = t(key, params);
268
+ }
269
+ function commit(move) {
270
+ if (move.to.parent !== null && !isExpanded(move.to.parent))
271
+ expanded.value = [...expanded.value, move.to.parent];
272
+ emit("move", move);
273
+ announce(move);
274
+ focusNode(move.node.id);
275
+ }
276
+ function keyboardMove(event, entry) {
277
+ const source = index.value.get(entry.node.id);
278
+ if (!source) return false;
279
+ const previous = source.siblings[source.index - 1];
280
+ const next = source.siblings[source.index + 1];
281
+ let move = null;
282
+ if (event.key === "ArrowUp" && previous) move = buildMove(entry.node.id, previous.id, "before");
283
+ else if (event.key === "ArrowDown" && next) move = buildMove(entry.node.id, next.id, "after");
284
+ else if (event.key === "ArrowRight" && props.nestable && previous)
285
+ move = buildMove(entry.node.id, previous.id, "inside");
286
+ else if (event.key === "ArrowLeft" && props.nestable && source.parent !== null)
287
+ move = buildMove(entry.node.id, source.parent, "after");
288
+ else return false;
289
+ if (move) commit(move);
290
+ return true;
291
+ }
292
+ function onKeydown(event, entry, position) {
293
+ if (event.altKey && canReorder.value && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key)) {
294
+ if (keyboardMove(event, entry)) event.preventDefault();
295
+ return;
296
+ }
125
297
  const list = visible.value;
126
298
  switch (event.key) {
127
299
  case "ArrowDown":
128
- focusNode(list[index + 1]?.node.id);
300
+ focusNode(list[position + 1]?.node.id);
129
301
  break;
130
302
  case "ArrowUp":
131
- focusNode(list[index - 1]?.node.id);
303
+ focusNode(list[position - 1]?.node.id);
132
304
  break;
133
305
  case "Home":
134
306
  focusNode(list[0]?.node.id);
@@ -138,21 +310,73 @@ function onKeydown(event, entry, index) {
138
310
  break;
139
311
  case "ArrowRight":
140
312
  if (!entry.hasChildren) return;
141
- if (isExpanded(entry.node.id)) focusNode(list[index + 1]?.node.id);
142
- else setExpanded(entry, index, true);
313
+ if (isExpanded(entry.node.id)) focusNode(list[position + 1]?.node.id);
314
+ else setExpanded(entry, position, true);
143
315
  break;
144
316
  case "ArrowLeft":
145
- if (entry.hasChildren && isExpanded(entry.node.id)) setExpanded(entry, index, false);
317
+ if (entry.hasChildren && isExpanded(entry.node.id)) setExpanded(entry, position, false);
146
318
  else focusNode(entry.parentId);
147
319
  break;
148
320
  case "Enter":
149
321
  case " ":
150
322
  activate(entry);
151
- if (event.key === "Enter") toggle(entry, index);
323
+ if (event.key === "Enter") toggle(entry, position);
152
324
  break;
153
325
  default:
154
326
  return;
155
327
  }
156
328
  event.preventDefault();
157
329
  }
330
+ function onDragStart(event, entry) {
331
+ if (!canReorder.value || entry.node.disabled) {
332
+ event.preventDefault();
333
+ return;
334
+ }
335
+ dragId.value = entry.node.id;
336
+ const transfer = event.dataTransfer;
337
+ if (!transfer) return;
338
+ transfer.effectAllowed = "move";
339
+ transfer.setData("text/plain", entry.node.label);
340
+ const row = event.currentTarget?.closest(".k-tree-row");
341
+ if (row) transfer.setDragImage(row, 16, row.offsetHeight / 2);
342
+ }
343
+ function dropPosition(event, row) {
344
+ const rect = row.getBoundingClientRect();
345
+ const ratio = rect.height ? (event.clientY - rect.top) / rect.height : 0.5;
346
+ if (!props.nestable) return ratio < 0.5 ? "before" : "after";
347
+ if (ratio < 0.25) return "before";
348
+ if (ratio > 0.75) return "after";
349
+ return "inside";
350
+ }
351
+ function onDragOver(event, entry) {
352
+ if (dragId.value === null) return;
353
+ const row = event.currentTarget;
354
+ const position = dropPosition(event, row);
355
+ const move = buildMove(dragId.value, entry.node.id, position);
356
+ if (!move) {
357
+ if (dropState.value?.id === entry.node.id) dropState.value = null;
358
+ return;
359
+ }
360
+ event.preventDefault();
361
+ if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
362
+ if (dropState.value?.id !== entry.node.id || dropState.value.position !== position)
363
+ dropState.value = { id: entry.node.id, position };
364
+ }
365
+ function onDragLeave(event, entry) {
366
+ const row = event.currentTarget;
367
+ if (event.relatedTarget instanceof Node && row.contains(event.relatedTarget)) return;
368
+ if (dropState.value?.id === entry.node.id) dropState.value = null;
369
+ }
370
+ function onDrop(event, entry) {
371
+ if (dragId.value === null) return;
372
+ event.preventDefault();
373
+ const position = dropPosition(event, event.currentTarget);
374
+ const move = buildMove(dragId.value, entry.node.id, position);
375
+ endDrag();
376
+ if (move) commit(move);
377
+ }
378
+ function endDrag() {
379
+ dragId.value = null;
380
+ dropState.value = null;
381
+ }
158
382
  </script>
@@ -1,29 +1,42 @@
1
- import type { TreeNode } from './types';
1
+ import type { TreeDescriptionVariant, TreeMove, TreeNode, TreeSize } from './types';
2
+ type NodeId = TreeNode['id'];
2
3
  declare var __VLS_12: {
3
4
  node: TreeNode;
4
5
  level: number;
5
6
  }, __VLS_14: {
6
7
  node: TreeNode;
7
- };
8
+ }, __VLS_21: {};
8
9
  type __VLS_Slots = {} & {
9
10
  label?: (props: typeof __VLS_12) => any;
10
11
  } & {
11
12
  meta?: (props: typeof __VLS_14) => any;
13
+ } & {
14
+ empty?: (props: typeof __VLS_21) => any;
12
15
  };
13
16
  declare const __VLS_base: import("vue").DefineComponent<{
14
17
  nodes: TreeNode[];
15
18
  label?: string;
16
19
  selectable?: boolean;
17
20
  bordered?: boolean;
18
- expanded?: TreeNode["id"][];
19
- selected?: TreeNode["id"] | null;
21
+ size?: TreeSize;
22
+ checkmark?: boolean;
23
+ emptyText?: string;
24
+ descriptionVariant?: TreeDescriptionVariant;
25
+ reorderable?: boolean;
26
+ nestable?: boolean;
27
+ canDrop?: (move: TreeMove) => boolean;
28
+ reorderText?: string;
29
+ invalid?: boolean;
30
+ disabled?: boolean;
31
+ required?: boolean;
32
+ expanded?: NodeId[];
33
+ selected?: NodeId | null;
20
34
  key?: PropertyKey | undefined;
21
35
  prefix?: string | undefined | undefined;
22
36
  title?: string | undefined | undefined;
23
37
  style?: import("vue").StyleValue;
24
38
  results?: (string | number) | undefined;
25
39
  placeholder?: string | undefined | undefined;
26
- ref?: import("vue").VNodeRef | undefined;
27
40
  class?: import("vue").ClassValue;
28
41
  role?: string | undefined | undefined;
29
42
  'aria-label'?: string | undefined | undefined;
@@ -135,7 +148,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
135
148
  'aria-colindex'?: (string | number) | undefined;
136
149
  'aria-colspan'?: (string | number) | undefined;
137
150
  'aria-controls'?: string | undefined | undefined;
138
- 'aria-current'?: "page" | "location" | "time" | (boolean | "true" | "false") | "step" | "date" | undefined;
151
+ 'aria-current'?: "page" | "time" | (boolean | "true" | "false") | "step" | "location" | "date" | undefined;
139
152
  'aria-describedby'?: string | undefined | undefined;
140
153
  'aria-details'?: string | undefined | undefined;
141
154
  'aria-disabled'?: (boolean | "true" | "false") | undefined;
@@ -172,6 +185,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
172
185
  'aria-valuemin'?: (string | number) | undefined;
173
186
  'aria-valuenow'?: (string | number) | undefined;
174
187
  'aria-valuetext'?: string | undefined | undefined;
188
+ ref?: import("vue").VNodeRef | undefined;
175
189
  ref_for?: boolean | undefined | undefined;
176
190
  ref_key?: string | undefined | undefined;
177
191
  accesskey?: string | undefined | undefined;
@@ -209,6 +223,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
209
223
  part?: string | undefined;
210
224
  popover?: (import("../../index.ts").PopoverMode | "" | boolean) | undefined;
211
225
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
226
+ move: (move: TreeMove) => any;
212
227
  select: (node: TreeNode) => any;
213
228
  "update:selected": (value: string | number | null) => any;
214
229
  "update:expanded": (value: (string | number)[]) => any;
@@ -217,15 +232,25 @@ declare const __VLS_base: import("vue").DefineComponent<{
217
232
  label?: string;
218
233
  selectable?: boolean;
219
234
  bordered?: boolean;
220
- expanded?: TreeNode["id"][];
221
- selected?: TreeNode["id"] | null;
235
+ size?: TreeSize;
236
+ checkmark?: boolean;
237
+ emptyText?: string;
238
+ descriptionVariant?: TreeDescriptionVariant;
239
+ reorderable?: boolean;
240
+ nestable?: boolean;
241
+ canDrop?: (move: TreeMove) => boolean;
242
+ reorderText?: string;
243
+ invalid?: boolean;
244
+ disabled?: boolean;
245
+ required?: boolean;
246
+ expanded?: NodeId[];
247
+ selected?: NodeId | null;
222
248
  key?: PropertyKey | undefined;
223
249
  prefix?: string | undefined | undefined;
224
250
  title?: string | undefined | undefined;
225
251
  style?: import("vue").StyleValue;
226
252
  results?: (string | number) | undefined;
227
253
  placeholder?: string | undefined | undefined;
228
- ref?: import("vue").VNodeRef | undefined;
229
254
  class?: import("vue").ClassValue;
230
255
  role?: string | undefined | undefined;
231
256
  'aria-label'?: string | undefined | undefined;
@@ -337,7 +362,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
337
362
  'aria-colindex'?: (string | number) | undefined;
338
363
  'aria-colspan'?: (string | number) | undefined;
339
364
  'aria-controls'?: string | undefined | undefined;
340
- 'aria-current'?: "page" | "location" | "time" | (boolean | "true" | "false") | "step" | "date" | undefined;
365
+ 'aria-current'?: "page" | "time" | (boolean | "true" | "false") | "step" | "location" | "date" | undefined;
341
366
  'aria-describedby'?: string | undefined | undefined;
342
367
  'aria-details'?: string | undefined | undefined;
343
368
  'aria-disabled'?: (boolean | "true" | "false") | undefined;
@@ -374,6 +399,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
374
399
  'aria-valuemin'?: (string | number) | undefined;
375
400
  'aria-valuenow'?: (string | number) | undefined;
376
401
  'aria-valuetext'?: string | undefined | undefined;
402
+ ref?: import("vue").VNodeRef | undefined;
377
403
  ref_for?: boolean | undefined | undefined;
378
404
  ref_key?: string | undefined | undefined;
379
405
  accesskey?: string | undefined | undefined;
@@ -411,12 +437,16 @@ declare const __VLS_base: import("vue").DefineComponent<{
411
437
  part?: string | undefined;
412
438
  popover?: (import("../../index.ts").PopoverMode | "" | boolean) | undefined;
413
439
  }> & Readonly<{
440
+ onMove?: ((move: TreeMove) => any) | undefined;
414
441
  onSelect?: ((node: TreeNode) => any) | undefined;
415
442
  "onUpdate:selected"?: ((value: string | number | null) => any) | undefined;
416
443
  "onUpdate:expanded"?: ((value: (string | number)[]) => any) | undefined;
417
444
  }>, {
445
+ invalid: boolean;
446
+ size: TreeSize;
418
447
  selectable: boolean;
419
448
  bordered: boolean;
449
+ descriptionVariant: TreeDescriptionVariant;
420
450
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
421
451
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
422
452
  declare const _default: typeof __VLS_export;
@@ -2,11 +2,14 @@ export { default as Avatar } from './Avatar.vue';
2
2
  export { default as AvatarGroup } from './AvatarGroup.vue';
3
3
  export { default as Badge } from './Badge.vue';
4
4
  export { default as DescriptionList } from './DescriptionList.vue';
5
+ export { default as FilterPill } from './FilterPill.vue';
5
6
  export { default as FilterPills } from './FilterPills.vue';
6
7
  export { default as Pagination } from './Pagination.vue';
8
+ export { default as SelectionBar } from './SelectionBar.vue';
7
9
  export { default as Stat } from './Stat.vue';
8
10
  export { default as Table } from './Table.vue';
9
11
  export { default as Tag } from './Tag.vue';
10
12
  export { default as Timeline } from './Timeline.vue';
11
13
  export { default as Tree } from './Tree.vue';
12
14
  export type * from './types';
15
+ export { applyTreeMove } from '../../internal/data/tree';
@@ -2,10 +2,13 @@ export { default as Avatar } from "./Avatar.vue";
2
2
  export { default as AvatarGroup } from "./AvatarGroup.vue";
3
3
  export { default as Badge } from "./Badge.vue";
4
4
  export { default as DescriptionList } from "./DescriptionList.vue";
5
+ export { default as FilterPill } from "./FilterPill.vue";
5
6
  export { default as FilterPills } from "./FilterPills.vue";
6
7
  export { default as Pagination } from "./Pagination.vue";
8
+ export { default as SelectionBar } from "./SelectionBar.vue";
7
9
  export { default as Stat } from "./Stat.vue";
8
10
  export { default as Table } from "./Table.vue";
9
11
  export { default as Tag } from "./Tag.vue";
10
12
  export { default as Timeline } from "./Timeline.vue";
11
13
  export { default as Tree } from "./Tree.vue";
14
+ export { applyTreeMove } from "../../internal/data/tree.mjs";
@@ -1,4 +1,5 @@
1
1
  import type { Tone } from '../core/types';
2
+ import type { MenuItems } from '../overlays/types';
2
3
  export type BadgeVariant = 'soft' | 'solid' | 'outline';
3
4
  export type BadgeSize = 'sm' | 'md';
4
5
  export type TableAlign = 'start' | 'center' | 'end';
@@ -56,15 +57,38 @@ export interface TreeNode {
56
57
  id: string | number;
57
58
  label: string;
58
59
  description?: string;
60
+ descriptionVariant?: TreeDescriptionVariant;
59
61
  meta?: string;
60
62
  icon?: string;
61
63
  disabled?: boolean;
62
64
  children?: TreeNode[];
63
65
  }
64
- export interface FilterPillOption {
65
- value: string | number;
66
+ export type TreeDescriptionVariant = 'text' | 'mono';
67
+ export type TreeSize = 'sm' | 'md';
68
+ export type TreeDropPosition = 'before' | 'after' | 'inside';
69
+ export interface TreeLocation {
70
+ parent: TreeNode['id'] | null;
71
+ index: number;
72
+ }
73
+ export interface TreeMove {
74
+ node: TreeNode;
75
+ target: TreeNode;
76
+ position: TreeDropPosition;
77
+ from: TreeLocation;
78
+ to: TreeLocation;
79
+ }
80
+ export type FilterPillValue = string | number;
81
+ export interface FilterPillOption<T extends FilterPillValue = FilterPillValue> {
82
+ value: T;
66
83
  label: string;
84
+ valueLabel?: string;
67
85
  count?: number;
68
86
  icon?: string;
69
87
  disabled?: boolean;
88
+ menu?: MenuItems;
89
+ menuLabel?: string;
90
+ panel?: boolean;
91
+ panelLabel?: string;
92
+ active?: boolean;
70
93
  }
94
+ export type SelectionBarPlacement = 'inline' | 'sticky' | 'floating';