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