@xleddyl/443-components-vue 0.4.0 → 0.6.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 (323) hide show
  1. package/README.md +25 -6
  2. package/dist/chart/BarChart.vue +11 -4
  3. package/dist/chart/BarChart.vue.d.ts +2 -0
  4. package/dist/chart/ChartLegend.vue +43 -4
  5. package/dist/chart/ChartLegend.vue.d.ts +4 -2
  6. package/dist/chart/ChartPanel.vue +10 -10
  7. package/dist/chart/ChartPanel.vue.d.ts +11 -8
  8. package/dist/chart/ChartSummary.vue +8 -3
  9. package/dist/chart/ChartSummary.vue.d.ts +3 -1
  10. package/dist/chart/DoughnutChart.vue +11 -4
  11. package/dist/chart/LineChart.vue +8 -2
  12. package/dist/chart/LineChart.vue.d.ts +2 -0
  13. package/dist/chart/chart.css +19 -0
  14. package/dist/chart/patterns.d.ts +6 -0
  15. package/dist/chart/patterns.mjs +79 -0
  16. package/dist/chart/types.d.ts +5 -0
  17. package/dist/chart/useChartColors.mjs +1 -1
  18. package/dist/components/core/Button.vue +11 -1
  19. package/dist/components/core/Button.vue.d.ts +1 -1
  20. package/dist/components/core/FieldMessage.vue +6 -0
  21. package/dist/components/core/FieldMessage.vue.d.ts +1 -1
  22. package/dist/components/core/Form.vue +18 -1
  23. package/dist/components/core/FormAlerts.vue +41 -3
  24. package/dist/components/core/FormField.vue +43 -24
  25. package/dist/components/core/Input.vue.d.ts +6 -6
  26. package/dist/components/core/Root.vue +6 -1
  27. package/dist/components/core/Root.vue.d.ts +2 -2
  28. package/dist/components/core/Spinner.vue +6 -11
  29. package/dist/components/core/Spinner.vue.d.ts +2 -2
  30. package/dist/components/core/Textarea.vue.d.ts +2 -2
  31. package/dist/components/core/VisuallyHidden.vue.d.ts +2 -2
  32. package/dist/components/data/Avatar.vue +8 -5
  33. package/dist/components/data/AvatarGroup.vue +6 -3
  34. package/dist/components/data/Badge.vue.d.ts +1 -1
  35. package/dist/components/data/FilterPills.vue +18 -2
  36. package/dist/components/data/Pagination.vue +24 -18
  37. package/dist/components/data/Pagination.vue.d.ts +2 -2
  38. package/dist/components/data/SelectionBar.vue +32 -3
  39. package/dist/components/data/Stat.vue +7 -1
  40. package/dist/components/data/Stat.vue.d.ts +2 -2
  41. package/dist/components/data/Table.vue +62 -14
  42. package/dist/components/data/Tag.vue +24 -4
  43. package/dist/components/data/Tag.vue.d.ts +3 -3
  44. package/dist/components/data/Timeline.vue +12 -1
  45. package/dist/components/data/Tree.vue +137 -36
  46. package/dist/components/data/Tree.vue.d.ts +13 -14
  47. package/dist/components/data/types.d.ts +2 -1
  48. package/dist/components/feedback/Alert.vue +18 -9
  49. package/dist/components/feedback/Alert.vue.d.ts +2 -2
  50. package/dist/components/feedback/LoadingOverlay.vue +35 -3
  51. package/dist/components/feedback/Meter.vue +28 -3
  52. package/dist/components/feedback/Progress.vue +2 -7
  53. package/dist/components/feedback/Progress.vue.d.ts +1 -1
  54. package/dist/components/feedback/ProgressRing.vue +2 -6
  55. package/dist/components/feedback/ProgressRing.vue.d.ts +1 -1
  56. package/dist/components/forms/Calendar.vue +49 -26
  57. package/dist/components/forms/Calendar.vue.d.ts +9 -5
  58. package/dist/components/forms/CheckboxGroup.vue +14 -4
  59. package/dist/components/forms/CheckboxGroup.vue.d.ts +1 -0
  60. package/dist/components/forms/ColorInput.vue +68 -15
  61. package/dist/components/forms/ColorInput.vue.d.ts +16 -13
  62. package/dist/components/forms/Combobox.vue +18 -4
  63. package/dist/components/forms/DateInput.vue.d.ts +6 -6
  64. package/dist/components/forms/DatePicker.vue +23 -7
  65. package/dist/components/forms/DatePicker.vue.d.ts +4 -2
  66. package/dist/components/forms/FileInput.vue +31 -13
  67. package/dist/components/forms/FileInput.vue.d.ts +2 -2
  68. package/dist/components/forms/InputAddon.vue +18 -2
  69. package/dist/components/forms/InputGroup.vue +27 -0
  70. package/dist/components/forms/InputGroup.vue.d.ts +2 -0
  71. package/dist/components/forms/NumberInput.vue +6 -7
  72. package/dist/components/forms/NumberInput.vue.d.ts +6 -6
  73. package/dist/components/forms/PasswordInput.vue +12 -6
  74. package/dist/components/forms/PasswordInput.vue.d.ts +6 -7
  75. package/dist/components/forms/PinInput.vue +11 -1
  76. package/dist/components/forms/PinInput.vue.d.ts +8 -6
  77. package/dist/components/forms/RadioGroup.vue +15 -5
  78. package/dist/components/forms/RadioGroup.vue.d.ts +1 -0
  79. package/dist/components/forms/SegmentedControl.vue +15 -10
  80. package/dist/components/forms/SegmentedControl.vue.d.ts +1 -0
  81. package/dist/components/forms/Slider.vue +9 -0
  82. package/dist/components/forms/Slider.vue.d.ts +8 -6
  83. package/dist/components/forms/Switch.vue +7 -0
  84. package/dist/components/forms/Switch.vue.d.ts +2 -2
  85. package/dist/components/forms/TimeInput.vue.d.ts +6 -6
  86. package/dist/components/forms/types.d.ts +4 -0
  87. package/dist/components/layout/Accordion.vue.d.ts +2 -2
  88. package/dist/components/layout/AppShell.vue +40 -18
  89. package/dist/components/layout/AppShell.vue.d.ts +11 -9
  90. package/dist/components/layout/Card.vue +50 -16
  91. package/dist/components/layout/Card.vue.d.ts +13 -11
  92. package/dist/components/layout/CopyButton.vue +13 -5
  93. package/dist/components/layout/CopyButton.vue.d.ts +3 -3
  94. package/dist/components/layout/NavLink.vue +10 -1
  95. package/dist/components/layout/NavLink.vue.d.ts +2 -2
  96. package/dist/components/layout/PageHeader.vue +2 -2
  97. package/dist/components/layout/Separator.vue +6 -3
  98. package/dist/components/layout/Sidebar.vue +14 -7
  99. package/dist/components/layout/Sidebar.vue.d.ts +0 -2
  100. package/dist/components/layout/SidebarNav.vue +16 -44
  101. package/dist/components/layout/Stack.vue.d.ts +2 -2
  102. package/dist/components/layout/Tabs.vue +10 -18
  103. package/dist/components/layout/Tabs.vue.d.ts +2 -2
  104. package/dist/components/layout/Toolbar.vue +10 -4
  105. package/dist/components/layout/Toolbar.vue.d.ts +1 -0
  106. package/dist/components/layout/types.d.ts +1 -0
  107. package/dist/components/overlays/CommandPalette.vue +8 -4
  108. package/dist/components/overlays/CommandPalette.vue.d.ts +3 -8
  109. package/dist/components/overlays/ConfirmDialog.vue +7 -5
  110. package/dist/components/overlays/ConfirmDialog.vue.d.ts +12 -8
  111. package/dist/components/overlays/ConfirmHost.vue +22 -19
  112. package/dist/components/overlays/ConfirmHost.vue.d.ts +8 -6
  113. package/dist/components/overlays/ContextMenu.vue +9 -11
  114. package/dist/components/overlays/ContextMenu.vue.d.ts +2 -2
  115. package/dist/components/overlays/Drawer.vue +2 -0
  116. package/dist/components/overlays/Drawer.vue.d.ts +4 -2
  117. package/dist/components/overlays/DropdownMenu.vue +13 -21
  118. package/dist/components/overlays/DropdownMenu.vue.d.ts +2 -2
  119. package/dist/components/overlays/HoverCard.vue +8 -2
  120. package/dist/components/overlays/HoverCard.vue.d.ts +2 -2
  121. package/dist/components/overlays/Modal.vue +2 -0
  122. package/dist/components/overlays/Modal.vue.d.ts +4 -2
  123. package/dist/components/overlays/Popover.vue +19 -4
  124. package/dist/components/overlays/Popover.vue.d.ts +2 -2
  125. package/dist/components/overlays/Toaster.vue +71 -8
  126. package/dist/components/overlays/Toaster.vue.d.ts +3 -0
  127. package/dist/components/overlays/Tooltip.vue +39 -14
  128. package/dist/components/overlays/types.d.ts +7 -0
  129. package/dist/components/templates/AccountMenu.vue.d.ts +2 -2
  130. package/dist/components/templates/AppearanceSettings.vue +83 -77
  131. package/dist/components/templates/AppearanceSettings.vue.d.ts +2 -2
  132. package/dist/components/templates/AuthLayout.vue +2 -2
  133. package/dist/components/templates/Brand.vue.d.ts +2 -2
  134. package/dist/components/templates/DashboardLayout.vue +3 -7
  135. package/dist/components/templates/DashboardLayout.vue.d.ts +8 -18
  136. package/dist/components/templates/DetailPage.vue +3 -1
  137. package/dist/components/templates/DetailPage.vue.d.ts +2 -2
  138. package/dist/components/templates/ErrorPage.vue +11 -5
  139. package/dist/components/templates/ErrorPage.vue.d.ts +10 -6
  140. package/dist/components/templates/FormPage.vue +16 -3
  141. package/dist/components/templates/ListPage.vue +19 -6
  142. package/dist/components/templates/ListPage.vue.d.ts +1 -0
  143. package/dist/components/templates/NotFoundPage.vue +2 -0
  144. package/dist/components/templates/NotFoundPage.vue.d.ts +4 -0
  145. package/dist/components/templates/SaveBar.vue +18 -3
  146. package/dist/components/templates/SaveBar.vue.d.ts +5 -5
  147. package/dist/components/templates/SettingsGroup.vue +1 -1
  148. package/dist/components/templates/SettingsGroup.vue.d.ts +3 -1
  149. package/dist/components/templates/SettingsModal.vue +73 -46
  150. package/dist/components/templates/SettingsModal.vue.d.ts +9 -11
  151. package/dist/components/templates/SettingsPage.vue.d.ts +2 -2
  152. package/dist/components/templates/SettingsSection.vue.d.ts +4 -2
  153. package/dist/components/templates/types.d.ts +4 -0
  154. package/dist/composables/useAlert.mjs +5 -10
  155. package/dist/composables/useConfirm.mjs +5 -5
  156. package/dist/composables/useField.d.ts +4 -0
  157. package/dist/composables/useField.mjs +16 -5
  158. package/dist/composables/useFileDrop.mjs +2 -1
  159. package/dist/composables/useOverlay.mjs +2 -1
  160. package/dist/composables/usePreset.mjs +4 -10
  161. package/dist/composables/usePrompt.mjs +6 -13
  162. package/dist/composables/useScrollLock.mjs +4 -3
  163. package/dist/composables/useTheme.mjs +3 -11
  164. package/dist/composables/useToast.mjs +2 -1
  165. package/dist/editor/RichTextEditor.vue +31 -6
  166. package/dist/editor/RichTextEditor.vue.d.ts +2 -2
  167. package/dist/editor/rich-text-editor.css +9 -4
  168. package/dist/grid/DataGrid.vue +72 -12
  169. package/dist/grid/GridToolbar.vue +1 -1
  170. package/dist/grid/GridToolbar.vue.d.ts +2 -2
  171. package/dist/grid/cells/BadgeCell.vue +3 -1
  172. package/dist/grid/cells/BadgeCell.vue.d.ts +17 -3
  173. package/dist/grid/cells/DateCell.vue +3 -1
  174. package/dist/grid/cells/DateCell.vue.d.ts +17 -3
  175. package/dist/grid/cells/EmptyCell.vue +15 -0
  176. package/dist/grid/cells/EmptyCell.vue.d.ts +392 -0
  177. package/dist/grid/cells/LinkCell.vue +9 -2
  178. package/dist/grid/cells/LinkCell.vue.d.ts +17 -3
  179. package/dist/grid/data-grid.css +5 -5
  180. package/dist/grid/types.d.ts +2 -0
  181. package/dist/internal/core/ButtonContent.vue +3 -0
  182. package/dist/internal/core/LiveRegion.vue +26 -0
  183. package/dist/internal/core/LiveRegion.vue.d.ts +393 -0
  184. package/dist/internal/core/copy.d.ts +6 -0
  185. package/dist/internal/core/copy.mjs +14 -0
  186. package/dist/internal/core/focus.d.ts +6 -0
  187. package/dist/internal/core/focus.mjs +46 -0
  188. package/dist/internal/core/intl.d.ts +4 -2
  189. package/dist/internal/core/intl.mjs +23 -22
  190. package/dist/internal/core/live.d.ts +6 -0
  191. package/dist/internal/core/live.mjs +22 -0
  192. package/dist/internal/core/preset.d.ts +0 -1
  193. package/dist/internal/core/preset.mjs +4 -14
  194. package/dist/internal/core/resize.d.ts +1 -0
  195. package/dist/internal/core/resize.mjs +11 -0
  196. package/dist/internal/core/roving.d.ts +7 -0
  197. package/dist/internal/core/roving.mjs +19 -1
  198. package/dist/internal/core/scroll-edges.d.ts +5 -0
  199. package/dist/internal/core/scroll-edges.mjs +63 -0
  200. package/dist/internal/core/storage.d.ts +2 -0
  201. package/dist/internal/core/storage.mjs +8 -0
  202. package/dist/internal/core/theme.d.ts +0 -1
  203. package/dist/internal/core/theme.mjs +4 -13
  204. package/dist/internal/core/tone.d.ts +1 -0
  205. package/dist/internal/core/tone.mjs +4 -0
  206. package/dist/internal/core/transition.d.ts +1 -0
  207. package/dist/internal/core/transition.mjs +20 -0
  208. package/dist/internal/data/rows.mjs +6 -5
  209. package/dist/internal/data/tree.d.ts +2 -3
  210. package/dist/internal/feedback/LoadingHost.vue +16 -6
  211. package/dist/internal/feedback/loading.mjs +2 -1
  212. package/dist/internal/feedback/progress.d.ts +12 -0
  213. package/dist/internal/feedback/progress.mjs +13 -0
  214. package/dist/internal/floating/layer.d.ts +1 -1
  215. package/dist/internal/floating/layer.mjs +17 -10
  216. package/dist/internal/forms/keys.d.ts +4 -0
  217. package/dist/internal/forms/keys.mjs +1 -0
  218. package/dist/internal/forms/name.d.ts +2 -0
  219. package/dist/internal/forms/name.mjs +12 -0
  220. package/dist/internal/forms/standard-schema.d.ts +0 -2
  221. package/dist/internal/forms/standard-schema.mjs +0 -18
  222. package/dist/internal/layout/NavGroup.vue +104 -0
  223. package/dist/internal/layout/NavGroup.vue.d.ts +412 -0
  224. package/dist/internal/layout/route.mjs +1 -1
  225. package/dist/internal/overlays/DialogFrame.vue +53 -6
  226. package/dist/internal/overlays/DialogFrame.vue.d.ts +5 -2
  227. package/dist/internal/overlays/MenuList.vue +4 -11
  228. package/dist/internal/overlays/MenuList.vue.d.ts +6 -6
  229. package/dist/internal/overlays/OverlayView.vue +2 -0
  230. package/dist/internal/overlays/OverlayView.vue.d.ts +8 -6
  231. package/dist/internal/overlays/confirm.d.ts +6 -1
  232. package/dist/internal/overlays/confirm.mjs +5 -2
  233. package/dist/internal/overlays/dialog.d.ts +1 -0
  234. package/dist/internal/overlays/dialog.mjs +9 -9
  235. package/dist/internal/overlays/hover.d.ts +1 -0
  236. package/dist/internal/overlays/hover.mjs +20 -3
  237. package/dist/internal/overlays/menu.d.ts +9 -0
  238. package/dist/internal/overlays/menu.mjs +15 -0
  239. package/dist/internal/overlays/stack.d.ts +1 -0
  240. package/dist/locale/en.mjs +72 -19
  241. package/dist/locale/index.d.ts +1 -1
  242. package/dist/locale/index.mjs +5 -11
  243. package/dist/locale/it.mjs +72 -19
  244. package/dist/locale/types.d.ts +55 -2
  245. package/dist/nuxt/module.mjs +1 -1
  246. package/dist/nuxt/runtime/RouteAnnouncer.vue +21 -0
  247. package/dist/nuxt/runtime/RouteAnnouncer.vue.d.ts +3 -0
  248. package/dist/nuxt/runtime/layout-head.d.ts +2 -0
  249. package/dist/nuxt/runtime/layout-head.mjs +13 -0
  250. package/dist/nuxt/runtime/layouts/auth.vue +4 -0
  251. package/dist/nuxt/runtime/layouts/auth.vue.d.ts +2 -2
  252. package/dist/nuxt/runtime/layouts/dashboard.vue +4 -0
  253. package/dist/nuxt/runtime/layouts/dashboard.vue.d.ts +2 -2
  254. package/dist/nuxt/runtime/locale.mjs +8 -1
  255. package/dist/nuxt/runtime/theme.mjs +17 -12
  256. package/dist/styles/base.css +0 -13
  257. package/dist/styles/core/button.css +8 -8
  258. package/dist/styles/core/field-message.css +2 -2
  259. package/dist/styles/core/form-field.css +13 -4
  260. package/dist/styles/core/input.css +4 -7
  261. package/dist/styles/core/kbd.css +0 -1
  262. package/dist/styles/data/badge.css +8 -4
  263. package/dist/styles/data/description-list.css +7 -5
  264. package/dist/styles/data/filter-pills.css +5 -8
  265. package/dist/styles/data/pagination.css +2 -2
  266. package/dist/styles/data/stat.css +3 -3
  267. package/dist/styles/data/table.css +3 -2
  268. package/dist/styles/data/tag.css +1 -2
  269. package/dist/styles/data/timeline.css +2 -1
  270. package/dist/styles/data/tree.css +31 -10
  271. package/dist/styles/feedback/alert.css +1 -3
  272. package/dist/styles/feedback/empty-state.css +6 -4
  273. package/dist/styles/feedback/loading-host.css +4 -0
  274. package/dist/styles/feedback/loading-overlay.css +4 -0
  275. package/dist/styles/forced-colors.css +215 -0
  276. package/dist/styles/forms/calendar.css +2 -2
  277. package/dist/styles/forms/choice.css +2 -2
  278. package/dist/styles/forms/color-input.css +1 -1
  279. package/dist/styles/forms/combobox.css +2 -24
  280. package/dist/styles/forms/date-input.css +2 -2
  281. package/dist/styles/forms/date-picker.css +3 -7
  282. package/dist/styles/forms/file-input.css +4 -3
  283. package/dist/styles/forms/input-group.css +6 -0
  284. package/dist/styles/forms/number-input.css +2 -2
  285. package/dist/styles/forms/password-input.css +5 -2
  286. package/dist/styles/forms/pin-input.css +4 -2
  287. package/dist/styles/forms/segmented.css +2 -2
  288. package/dist/styles/forms/select.css +6 -6
  289. package/dist/styles/forms/slider.css +5 -4
  290. package/dist/styles/forms/switch.css +5 -1
  291. package/dist/styles/index.css +1 -0
  292. package/dist/styles/layout/accordion.css +1 -1
  293. package/dist/styles/layout/app-shell.css +15 -3
  294. package/dist/styles/layout/card.css +12 -2
  295. package/dist/styles/layout/copy-button.css +1 -1
  296. package/dist/styles/layout/nav-link.css +1 -33
  297. package/dist/styles/layout/page-header.css +2 -1
  298. package/dist/styles/layout/separator.css +1 -1
  299. package/dist/styles/layout/sidebar-nav.css +15 -4
  300. package/dist/styles/layout/sidebar.css +20 -6
  301. package/dist/styles/layout/tabs.css +9 -4
  302. package/dist/styles/layout/theme-switch.css +0 -6
  303. package/dist/styles/overlays/command.css +9 -15
  304. package/dist/styles/overlays/confirm.css +1 -1
  305. package/dist/styles/overlays/drawer.css +23 -3
  306. package/dist/styles/overlays/menu.css +2 -17
  307. package/dist/styles/overlays/modal.css +33 -9
  308. package/dist/styles/overlays/toast.css +1 -2
  309. package/dist/styles/presets.css +4 -4
  310. package/dist/styles/shared.css +96 -3
  311. package/dist/styles/templates/account-menu.css +3 -3
  312. package/dist/styles/templates/auth-layout.css +5 -1
  313. package/dist/styles/templates/brand.css +3 -3
  314. package/dist/styles/templates/empty-page.css +5 -1
  315. package/dist/styles/templates/error-page.css +4 -0
  316. package/dist/styles/templates/form-page.css +10 -0
  317. package/dist/styles/templates/save-bar.css +10 -0
  318. package/dist/styles/templates/settings-modal.css +46 -45
  319. package/dist/styles/templates/settings-page.css +3 -3
  320. package/dist/styles/tokens.css +12 -2
  321. package/package.json +1 -1
  322. package/dist/internal/overlays/focus.d.ts +0 -1
  323. package/dist/internal/overlays/focus.mjs +0 -24
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <ul
3
+ v-if="visible.length"
3
4
  ref="tree"
4
5
  :id="control.id.value"
5
6
  :aria-label="ariaLabel"
@@ -7,20 +8,11 @@
7
8
  v-bind="$attrs"
8
9
  :aria-describedby="joinIds($attrs['aria-describedby'], control.describedBy.value)"
9
10
  :aria-invalid="control.invalid.value ? 'true' : void 0"
10
- :aria-required="control.required.value ? 'true' : void 0"
11
+ :aria-required="control.required.value && !control.labelledBy.value ? 'true' : void 0"
11
12
  :aria-disabled="control.disabled.value ? 'true' : void 0"
12
13
  class="k-tree"
13
14
  role="tree"
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
- ]"
15
+ :class="rootClass"
24
16
  data-k-shake
25
17
  >
26
18
  <li
@@ -35,7 +27,8 @@
35
27
  :aria-expanded="entry.hasChildren ? isExpanded(entry.node.id) : void 0"
36
28
  :aria-selected="selectable ? selected === entry.node.id : void 0"
37
29
  :aria-disabled="entry.node.disabled ? 'true' : void 0"
38
- :aria-describedby="canReorder && !entry.node.disabled ? hintId : void 0"
30
+ :aria-labelledby="$slots.label ? textId(entry.node.id) : labelId(entry.node.id)"
31
+ :aria-describedby="describedBy(entry)"
39
32
  :aria-keyshortcuts="canReorder && !entry.node.disabled ? keyShortcuts : void 0"
40
33
  :tabindex="entry.node.id === rovingId ? 0 : -1"
41
34
  :class="{ 'is-moving': dragId === entry.node.id }"
@@ -76,39 +69,65 @@
76
69
  <span v-if="entry.node.icon" class="k-tree-icon" aria-hidden="true">
77
70
  <Icon :name="entry.node.icon" />
78
71
  </span>
79
- <span class="k-tree-text">
72
+ <span :id="textId(entry.node.id)" class="k-tree-text">
80
73
  <slot name="label" :node="entry.node" :level="entry.level">
81
- <span class="k-tree-label">{{ entry.node.label }}</span>
74
+ <span :id="labelId(entry.node.id)" class="k-tree-label">{{ entry.node.label }}</span>
82
75
  <span
83
76
  v-if="entry.node.description"
77
+ :id="descriptionId(entry.node.id)"
84
78
  class="k-tree-description"
85
79
  :class="`k-tree-description-${entry.node.descriptionVariant ?? descriptionVariant}`"
86
80
  >{{ entry.node.description }}</span
87
81
  >
88
82
  </slot>
89
83
  </span>
90
- <span v-if="entry.node.meta || $slots.meta" class="k-tree-meta">
84
+ <span
85
+ v-if="entry.node.meta || $slots.meta"
86
+ :id="metaId(entry.node.id)"
87
+ class="k-tree-meta"
88
+ >
91
89
  <slot name="meta" :node="entry.node">{{ entry.node.meta }}</slot>
92
90
  </span>
93
91
  <span v-if="checkmark && selectable" class="k-tree-check" aria-hidden="true">
94
92
  <Icon v-if="selected === entry.node.id" name="check" />
95
93
  </span>
96
- </li>
97
- <li v-if="!visible.length" class="k-tree-empty" role="none">
98
- <slot name="empty">{{ emptyLabel }}</slot>
94
+ <span v-if="canReorder && !entry.node.disabled" class="k-tree-actions" @click.stop>
95
+ <Button
96
+ v-for="action in rowActions(entry)"
97
+ :key="action.direction"
98
+ variant="ghost"
99
+ tone="neutral"
100
+ size="xs"
101
+ tabindex="-1"
102
+ :icon="action.icon"
103
+ :aria-label="action.label"
104
+ :title="action.label"
105
+ :disabled="!action.move"
106
+ @click="action.move && commit(action.move)"
107
+ />
108
+ </span>
99
109
  </li>
100
110
  </ul>
111
+ <div v-else :id="control.id.value" v-bind="$attrs" class="k-tree" :class="rootClass">
112
+ <p class="k-tree-empty">
113
+ <slot name="empty">{{ emptyLabel }}</slot>
114
+ </p>
115
+ </div>
101
116
  <template v-if="canReorder">
102
117
  <span :id="hintId" class="k-visually-hidden">{{ hintText }}</span>
103
- <span class="k-visually-hidden" role="status" aria-live="polite">{{ announcement }}</span>
118
+ <LiveRegion :message="live.message.value" />
104
119
  </template>
105
120
  </template>
106
121
 
107
122
  <script setup>
108
- import { computed, nextTick, ref, useId, useTemplateRef } from "vue";
123
+ import { computed, nextTick, ref, useId, useSlots, useTemplateRef } from "vue";
109
124
  import { useFieldControl } from "../../composables/useField";
110
125
  import { useLocale } from "../../composables/useLocale";
126
+ import LiveRegion from "../../internal/core/LiveRegion.vue";
127
+ import { useLiveMessage } from "../../internal/core/live";
128
+ import { useTypeahead } from "../../internal/core/roving";
111
129
  import { joinIds } from "../../internal/forms/control";
130
+ import Button from "../core/Button.vue";
112
131
  import Icon from "../core/Icon.vue";
113
132
  import { rowDelay } from "../../internal/data/stagger";
114
133
  defineOptions({ inheritAttrs: false });
@@ -130,6 +149,7 @@ const props = defineProps({
130
149
  required: { type: Boolean, required: false }
131
150
  });
132
151
  const { t } = useLocale();
152
+ const slots = useSlots();
133
153
  const emit = defineEmits(["select", "move"]);
134
154
  const expanded = defineModel("expanded", { type: Array, ...{ default: () => [] } });
135
155
  const selected = defineModel("selected", { type: [String, Number, null], ...{ default: null } });
@@ -146,14 +166,12 @@ const focusId = ref(selected.value ?? props.nodes[0]?.id ?? null);
146
166
  const revealAnchor = ref(-1);
147
167
  const dragId = ref(null);
148
168
  const dropState = ref(null);
149
- const announcement = ref("");
169
+ const live = useLiveMessage();
150
170
  const ariaLabel = computed(() => {
151
171
  if (props.label) return props.label;
152
- return control.field ? void 0 : t("tree.label");
172
+ return control.labelledBy.value ? void 0 : t("tree.label");
153
173
  });
154
- const ariaLabelledby = computed(
155
- () => !props.label && control.field ? control.field.labelId : void 0
156
- );
174
+ const ariaLabelledby = computed(() => props.label ? void 0 : control.labelledBy.value);
157
175
  const emptyLabel = computed(() => props.emptyText ?? t("tree.empty"));
158
176
  const canReorder = computed(() => props.reorderable && !control.disabled.value);
159
177
  const hintText = computed(
@@ -166,6 +184,36 @@ const expandedSet = computed(() => new Set(expanded.value));
166
184
  function rowId(id) {
167
185
  return `${baseId}-node-${id}`;
168
186
  }
187
+ function labelId(id) {
188
+ return `${rowId(id)}-label`;
189
+ }
190
+ function textId(id) {
191
+ return `${rowId(id)}-text`;
192
+ }
193
+ function descriptionId(id) {
194
+ return `${rowId(id)}-description`;
195
+ }
196
+ function metaId(id) {
197
+ return `${rowId(id)}-meta`;
198
+ }
199
+ const rootClass = computed(() => [
200
+ `k-tree-${props.size}`,
201
+ {
202
+ "is-bordered": props.bordered,
203
+ "is-reorderable": canReorder.value,
204
+ "is-dragging": dragId.value !== null,
205
+ "is-invalid": control.invalid.value,
206
+ "is-disabled": control.disabled.value
207
+ }
208
+ ]);
209
+ function describedBy(entry) {
210
+ const hasMeta = Boolean(entry.node.meta || slots.meta);
211
+ return joinIds(
212
+ !slots.label && entry.node.description ? descriptionId(entry.node.id) : void 0,
213
+ hasMeta ? metaId(entry.node.id) : void 0,
214
+ canReorder.value && !entry.node.disabled ? hintId : void 0
215
+ );
216
+ }
169
217
  function isExpanded(id) {
170
218
  return expandedSet.value.has(id);
171
219
  }
@@ -264,7 +312,7 @@ function announce(move) {
264
312
  parent: parent?.node.label ?? ""
265
313
  };
266
314
  const key = parent && move.to.parent !== move.from.parent ? "tree.movedInto" : "tree.moved";
267
- announcement.value = t(key, params);
315
+ live.announce(t(key, params));
268
316
  }
269
317
  function commit(move) {
270
318
  if (move.to.parent !== null && !isExpanded(move.to.parent))
@@ -273,23 +321,76 @@ function commit(move) {
273
321
  announce(move);
274
322
  focusNode(move.node.id);
275
323
  }
276
- function keyboardMove(event, entry) {
324
+ function moveFor(entry, direction) {
277
325
  const source = index.value.get(entry.node.id);
278
- if (!source) return false;
326
+ if (!source) return null;
279
327
  const previous = source.siblings[source.index - 1];
280
328
  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;
329
+ if (direction === "up") return previous ? buildMove(entry.node.id, previous.id, "before") : null;
330
+ if (direction === "down") return next ? buildMove(entry.node.id, next.id, "after") : null;
331
+ if (!props.nestable) return null;
332
+ if (direction === "indent")
333
+ return previous ? buildMove(entry.node.id, previous.id, "inside") : null;
334
+ return source.parent !== null ? buildMove(entry.node.id, source.parent, "after") : null;
335
+ }
336
+ const moveKeys = {
337
+ ArrowUp: "up",
338
+ ArrowDown: "down",
339
+ ArrowRight: "indent",
340
+ ArrowLeft: "outdent"
341
+ };
342
+ function keyboardMove(event, entry) {
343
+ const direction = moveKeys[event.key];
344
+ if (!direction) return false;
345
+ if ((direction === "indent" || direction === "outdent") && !props.nestable) return false;
346
+ const move = moveFor(entry, direction);
289
347
  if (move) commit(move);
290
348
  return true;
291
349
  }
350
+ const actionIcons = {
351
+ up: "arrow-up",
352
+ down: "arrow-down",
353
+ indent: "arrow-right",
354
+ outdent: "arrow-left"
355
+ };
356
+ const actionKeys = {
357
+ up: "tree.moveUp",
358
+ down: "tree.moveDown",
359
+ indent: "tree.indent",
360
+ outdent: "tree.outdent"
361
+ };
362
+ function rowActions(entry) {
363
+ const directions = props.nestable ? ["up", "down", "outdent", "indent"] : ["up", "down"];
364
+ return directions.map((direction) => ({
365
+ direction,
366
+ icon: actionIcons[direction],
367
+ label: t(actionKeys[direction], { label: entry.node.label }),
368
+ move: moveFor(entry, direction)
369
+ }));
370
+ }
371
+ const typeahead = useTypeahead();
372
+ function onTypeahead(event, position) {
373
+ if (event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey) return false;
374
+ if (event.key === " " && !typeahead.typing()) return false;
375
+ const { query, cycle } = typeahead.type(event.key);
376
+ const list = visible.value;
377
+ const start = cycle ? position + 1 : position;
378
+ for (let offset = 0; offset < list.length; offset++) {
379
+ const entry = list[(start + offset) % list.length];
380
+ if (!entry || entry.node.disabled) continue;
381
+ if (entry.node.label.toLowerCase().startsWith(query)) {
382
+ focusNode(entry.node.id);
383
+ break;
384
+ }
385
+ }
386
+ return true;
387
+ }
292
388
  function onKeydown(event, entry, position) {
389
+ if (event.target !== event.currentTarget) return;
390
+ if (onTypeahead(event, position)) {
391
+ event.preventDefault();
392
+ return;
393
+ }
293
394
  if (event.altKey && canReorder.value && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key)) {
294
395
  if (keyboardMove(event, entry)) event.preventDefault();
295
396
  return;
@@ -1,17 +1,16 @@
1
- import type { TreeDescriptionVariant, TreeMove, TreeNode, TreeSize } from './types';
2
- type NodeId = TreeNode['id'];
1
+ import type { TreeDescriptionVariant, TreeMove, TreeNode, TreeNodeId, TreeSize } from './types';
3
2
  declare var __VLS_12: {
4
3
  node: TreeNode;
5
4
  level: number;
6
5
  }, __VLS_14: {
7
6
  node: TreeNode;
8
- }, __VLS_21: {};
7
+ }, __VLS_29: {};
9
8
  type __VLS_Slots = {} & {
10
9
  label?: (props: typeof __VLS_12) => any;
11
10
  } & {
12
11
  meta?: (props: typeof __VLS_14) => any;
13
12
  } & {
14
- empty?: (props: typeof __VLS_21) => any;
13
+ empty?: (props: typeof __VLS_29) => any;
15
14
  };
16
15
  declare const __VLS_base: import("vue").DefineComponent<{
17
16
  nodes: TreeNode[];
@@ -29,14 +28,15 @@ declare const __VLS_base: import("vue").DefineComponent<{
29
28
  invalid?: boolean;
30
29
  disabled?: boolean;
31
30
  required?: boolean;
32
- expanded?: NodeId[];
33
- selected?: NodeId | null;
31
+ expanded?: TreeNodeId[];
32
+ selected?: TreeNodeId | null;
34
33
  key?: PropertyKey | undefined;
35
34
  prefix?: string | undefined | undefined;
36
35
  title?: string | undefined | undefined;
37
36
  style?: import("vue").StyleValue;
38
37
  results?: (string | number) | undefined;
39
38
  placeholder?: string | undefined | undefined;
39
+ dir?: string | undefined | undefined;
40
40
  class?: import("vue").ClassValue;
41
41
  role?: string | undefined | undefined;
42
42
  'aria-label'?: string | undefined | undefined;
@@ -191,7 +191,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
191
191
  accesskey?: string | undefined | undefined;
192
192
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
193
193
  contextmenu?: string | undefined | undefined;
194
- dir?: string | undefined | undefined;
195
194
  draggable?: (boolean | "true" | "false") | undefined;
196
195
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
197
196
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -225,8 +224,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
225
224
  }, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
226
225
  move: (move: TreeMove) => any;
227
226
  select: (node: TreeNode) => any;
228
- "update:selected": (value: string | number | null) => any;
229
- "update:expanded": (value: (string | number)[]) => any;
227
+ "update:selected": (value: TreeNodeId | null) => any;
228
+ "update:expanded": (value: TreeNodeId[]) => any;
230
229
  }, string, import("vue").PublicProps, Readonly<{
231
230
  nodes: TreeNode[];
232
231
  label?: string;
@@ -243,14 +242,15 @@ declare const __VLS_base: import("vue").DefineComponent<{
243
242
  invalid?: boolean;
244
243
  disabled?: boolean;
245
244
  required?: boolean;
246
- expanded?: NodeId[];
247
- selected?: NodeId | null;
245
+ expanded?: TreeNodeId[];
246
+ selected?: TreeNodeId | null;
248
247
  key?: PropertyKey | undefined;
249
248
  prefix?: string | undefined | undefined;
250
249
  title?: string | undefined | undefined;
251
250
  style?: import("vue").StyleValue;
252
251
  results?: (string | number) | undefined;
253
252
  placeholder?: string | undefined | undefined;
253
+ dir?: string | undefined | undefined;
254
254
  class?: import("vue").ClassValue;
255
255
  role?: string | undefined | undefined;
256
256
  'aria-label'?: string | undefined | undefined;
@@ -405,7 +405,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
405
405
  accesskey?: string | undefined | undefined;
406
406
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
407
407
  contextmenu?: string | undefined | undefined;
408
- dir?: string | undefined | undefined;
409
408
  draggable?: (boolean | "true" | "false") | undefined;
410
409
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
411
410
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -439,8 +438,8 @@ declare const __VLS_base: import("vue").DefineComponent<{
439
438
  }> & Readonly<{
440
439
  onMove?: ((move: TreeMove) => any) | undefined;
441
440
  onSelect?: ((node: TreeNode) => any) | undefined;
442
- "onUpdate:selected"?: ((value: string | number | null) => any) | undefined;
443
- "onUpdate:expanded"?: ((value: (string | number)[]) => any) | undefined;
441
+ "onUpdate:selected"?: ((value: TreeNodeId | null) => any) | undefined;
442
+ "onUpdate:expanded"?: ((value: TreeNodeId[]) => any) | undefined;
444
443
  }>, {
445
444
  invalid: boolean;
446
445
  size: TreeSize;
@@ -53,8 +53,9 @@ export interface TimelineItem {
53
53
  icon?: string;
54
54
  tone?: Tone;
55
55
  }
56
+ export type TreeNodeId = string | number;
56
57
  export interface TreeNode {
57
- id: string | number;
58
+ id: TreeNodeId;
58
59
  label: string;
59
60
  description?: string;
60
61
  descriptionVariant?: TreeDescriptionVariant;
@@ -2,20 +2,22 @@
2
2
  <Transition name="k-alert">
3
3
  <div
4
4
  v-if="open"
5
+ ref="root"
5
6
  class="k-alert"
6
7
  :class="[`k-alert-${tone}`, `k-alert-${variant}`, { 'has-actions': $slots.actions }]"
7
8
  :role="resolvedRole"
8
- :aria-labelledby="title || $slots.title ? titleId : void 0"
9
+ :aria-labelledby="resolvedRole && hasTitle ? titleId : void 0"
9
10
  >
10
11
  <span v-if="resolvedIcon || $slots.icon" class="k-alert-icon" aria-hidden="true">
11
12
  <slot name="icon"><Icon v-if="resolvedIcon" :name="resolvedIcon" /></slot>
12
13
  </span>
13
14
  <div class="k-alert-body">
14
- <p v-if="title || $slots.title" :id="titleId" class="k-alert-title">
15
+ <p v-if="hasTitle" :id="titleId" class="k-alert-title">
15
16
  <slot name="title">{{ title }}</slot>
16
17
  </p>
17
18
  <div v-if="description || $slots.default" class="k-alert-description">
18
- <slot>{{ description }}</slot>
19
+ <span v-if="!hasTitle && toneText" class="k-visually-hidden">{{ toneText }}: </span
20
+ ><slot>{{ description }}</slot>
19
21
  </div>
20
22
  <div v-if="$slots.actions" class="k-alert-actions">
21
23
  <slot name="actions" />
@@ -36,11 +38,12 @@
36
38
  </template>
37
39
 
38
40
  <script setup>
39
- import { computed, useId } from "vue";
41
+ import { computed, useId, useSlots, useTemplateRef } from "vue";
42
+ import { hasFocusWithin, neighborFocusTarget } from "../../internal/core/focus";
40
43
  import { useLocale } from "../../composables/useLocale";
41
44
  import Button from "../core/Button.vue";
42
45
  import Icon from "../core/Icon.vue";
43
- import { toneIcons } from "../../internal/core/tone";
46
+ import { spokenToneKey, toneIcons } from "../../internal/core/tone";
44
47
  const props = defineProps({
45
48
  tone: { type: String, required: false, default: "neutral" },
46
49
  variant: { type: String, required: false, default: "soft" },
@@ -59,12 +62,18 @@ const titleId = useId();
59
62
  const resolvedIcon = computed(
60
63
  () => props.icon === false ? null : props.icon ?? toneIcons[props.tone]
61
64
  );
62
- const resolvedRole = computed(() => {
63
- if (props.role === "none") return void 0;
64
- if (props.role) return props.role;
65
- return props.tone === "danger" || props.tone === "warning" ? "alert" : "status";
65
+ const slots = useSlots();
66
+ const root = useTemplateRef("root");
67
+ const hasTitle = computed(() => Boolean(props.title || slots.title));
68
+ const resolvedRole = computed(() => props.role === "none" ? void 0 : props.role);
69
+ const toneText = computed(() => {
70
+ const key = spokenToneKey(props.tone);
71
+ return key ? t(key) : "";
66
72
  });
67
73
  function dismiss() {
74
+ const element = root.value;
75
+ if (element && hasFocusWithin(element))
76
+ neighborFocusTarget(element)?.focus({ preventScroll: true });
68
77
  open.value = false;
69
78
  emit("dismiss");
70
79
  }
@@ -27,6 +27,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
27
27
  results?: (string | number) | undefined;
28
28
  placeholder?: string | undefined | undefined;
29
29
  name?: string;
30
+ dir?: string | undefined | undefined;
30
31
  class?: import("vue").ClassValue;
31
32
  'aria-label'?: string | undefined | undefined;
32
33
  'aria-hidden'?: (boolean | "true" | "false") | undefined;
@@ -183,7 +184,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
183
184
  accesskey?: string | undefined | undefined;
184
185
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
185
186
  contextmenu?: string | undefined | undefined;
186
- dir?: string | undefined | undefined;
187
187
  draggable?: (boolean | "true" | "false") | undefined;
188
188
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
189
189
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -267,6 +267,7 @@ declare const __VLS_base: import("vue").DefineComponent<{
267
267
  results?: (string | number) | undefined;
268
268
  placeholder?: string | undefined | undefined;
269
269
  name?: string;
270
+ dir?: string | undefined | undefined;
270
271
  class?: import("vue").ClassValue;
271
272
  'aria-label'?: string | undefined | undefined;
272
273
  'aria-hidden'?: (boolean | "true" | "false") | undefined;
@@ -423,7 +424,6 @@ declare const __VLS_base: import("vue").DefineComponent<{
423
424
  accesskey?: string | undefined | undefined;
424
425
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
425
426
  contextmenu?: string | undefined | undefined;
426
- dir?: string | undefined | undefined;
427
427
  draggable?: (boolean | "true" | "false") | undefined;
428
428
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
429
429
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div class="k-loading-overlay" :class="{ 'is-loading': loading, 'is-blur': blur }">
3
3
  <div
4
+ ref="content"
4
5
  class="k-loading-overlay-content"
5
6
  :inert="loading || void 0"
6
7
  :aria-busy="loading ? 'true' : void 0"
@@ -8,21 +9,31 @@
8
9
  <slot />
9
10
  </div>
10
11
  <Transition name="k-loading-overlay">
11
- <div v-if="loading" class="k-loading-overlay-layer">
12
+ <div
13
+ v-if="loading"
14
+ ref="layer"
15
+ class="k-loading-overlay-layer"
16
+ role="group"
17
+ tabindex="-1"
18
+ :aria-label="text"
19
+ >
12
20
  <span class="k-loading-overlay-indicator">
13
- <Spinner :size="spinnerSize" :label="text" />
21
+ <Spinner :size="spinnerSize" decorative />
14
22
  <span v-if="showLabel" class="k-loading-overlay-label" aria-hidden="true">{{
15
23
  text
16
24
  }}</span>
17
25
  </span>
18
26
  </div>
19
27
  </Transition>
28
+ <LiveRegion :message="loading ? text : ''" />
20
29
  </div>
21
30
  </template>
22
31
 
23
32
  <script setup>
24
- import { computed } from "vue";
33
+ import { computed, nextTick, useTemplateRef, watch } from "vue";
25
34
  import { useLocale } from "../../composables/useLocale";
35
+ import LiveRegion from "../../internal/core/LiveRegion.vue";
36
+ import { activeElement, hasFocusWithin, isFocusLost } from "../../internal/core/focus";
26
37
  import Spinner from "../core/Spinner.vue";
27
38
  const props = defineProps({
28
39
  loading: { type: Boolean, required: false },
@@ -33,4 +44,25 @@ const props = defineProps({
33
44
  });
34
45
  const { t } = useLocale();
35
46
  const text = computed(() => props.label ?? t("common.loading"));
47
+ const content = useTemplateRef("content");
48
+ const layer = useTemplateRef("layer");
49
+ let returnTarget = null;
50
+ watch(
51
+ () => props.loading,
52
+ async (loading) => {
53
+ if (loading) {
54
+ returnTarget = hasFocusWithin(content.value) ? activeElement() : null;
55
+ if (!returnTarget) return;
56
+ await nextTick();
57
+ layer.value?.focus({ preventScroll: true });
58
+ return;
59
+ }
60
+ const target = returnTarget;
61
+ returnTarget = null;
62
+ if (!target) return;
63
+ await nextTick();
64
+ if (isFocusLost(layer.value) && target.isConnected) target.focus({ preventScroll: true });
65
+ },
66
+ { flush: "pre" }
67
+ );
36
68
  </script>
@@ -18,7 +18,8 @@
18
18
  :low="low"
19
19
  :high="high"
20
20
  :optimum="optimum"
21
- :aria-valuetext="valueText ? displayValue : void 0"
21
+ :aria-label="label ? void 0 : t('meter.label')"
22
+ :aria-valuetext="ariaValueText"
22
23
  >
23
24
  {{ displayValue }}
24
25
  </meter>
@@ -27,6 +28,8 @@
27
28
 
28
29
  <script setup>
29
30
  import { computed, useId } from "vue";
31
+ import { useLocale } from "../../composables/useLocale";
32
+ import { percentText } from "../../internal/feedback/progress";
30
33
  const props = defineProps({
31
34
  value: { type: Number, required: true },
32
35
  min: { type: Number, required: false, default: 0 },
@@ -41,12 +44,34 @@ const props = defineProps({
41
44
  size: { type: String, required: false, default: "sm" },
42
45
  id: { type: String, required: false }
43
46
  });
47
+ const { t } = useLocale();
44
48
  const generatedId = useId();
45
49
  const meterId = computed(() => props.id ?? generatedId);
46
50
  const displayValue = computed(() => {
47
51
  if (props.valueText) return props.valueText(props.value, props.max);
48
52
  const span = props.max - props.min;
49
- const ratio = span > 0 ? (props.value - props.min) / span : 0;
50
- return `${Math.round(ratio * 100)}%`;
53
+ return percentText(span > 0 ? (props.value - props.min) / span : 0);
54
+ });
55
+ const state = computed(() => {
56
+ if (props.low === void 0 && props.high === void 0 && props.optimum === void 0)
57
+ return null;
58
+ const min = props.min;
59
+ const max = Math.max(props.max, min);
60
+ const clamp = (value2, lower, upper) => Math.min(Math.max(value2, lower), upper);
61
+ const low = clamp(props.low ?? min, min, max);
62
+ const high = clamp(props.high ?? max, low, max);
63
+ const optimum = clamp(props.optimum ?? (min + max) / 2, min, max);
64
+ const value = clamp(props.value, min, max);
65
+ const region = (point) => point < low ? "low" : point > high ? "high" : "middle";
66
+ const best = region(optimum);
67
+ const current = region(value);
68
+ if (current === best) return "good";
69
+ if (best === "middle" || current === "middle") return "fair";
70
+ return "poor";
71
+ });
72
+ const ariaValueText = computed(() => {
73
+ if (state.value)
74
+ return t("meter.valueText", { value: displayValue.value, state: t(`meter.${state.value}`) });
75
+ return props.valueText ? displayValue.value : void 0;
51
76
  });
52
77
  </script>
@@ -20,7 +20,6 @@
20
20
  :aria-valuemax="max"
21
21
  :aria-valuenow="indeterminate ? void 0 : clamped"
22
22
  :aria-valuetext="indeterminate ? void 0 : displayValue"
23
- :aria-busy="indeterminate ? 'true' : void 0"
24
23
  >
25
24
  <span class="k-progress-bar" :style="{ '--k-progress': ratio }" />
26
25
  </div>
@@ -30,6 +29,7 @@
30
29
  <script setup>
31
30
  import { computed, useId } from "vue";
32
31
  import { useLocale } from "../../composables/useLocale";
32
+ import { useProgressValue } from "../../internal/feedback/progress";
33
33
  const props = defineProps({
34
34
  value: { type: [Number, null], required: false, default: null },
35
35
  max: { type: Number, required: false, default: 100 },
@@ -43,10 +43,5 @@ const props = defineProps({
43
43
  const { t } = useLocale();
44
44
  const text = computed(() => props.label ?? t("progress.label"));
45
45
  const labelId = useId();
46
- const indeterminate = computed(() => props.value === null || props.value === void 0);
47
- const clamped = computed(() => Math.min(Math.max(props.value ?? 0, 0), props.max));
48
- const ratio = computed(() => props.max > 0 ? clamped.value / props.max : 0);
49
- const displayValue = computed(
50
- () => props.valueText ? props.valueText(clamped.value, props.max) : `${Math.round(ratio.value * 100)}%`
51
- );
46
+ const { indeterminate, clamped, ratio, displayValue } = useProgressValue(props);
52
47
  </script>
@@ -408,9 +408,9 @@ declare const __VLS_base: import("vue").DefineComponent<{
408
408
  ref_key?: string | undefined | undefined;
409
409
  }> & Readonly<{}>, {
410
410
  value: number | null;
411
+ tone: Tone;
411
412
  max: number;
412
413
  size: ProgressSize;
413
- tone: Tone;
414
414
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
415
415
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
416
416
  declare const _default: typeof __VLS_export;
@@ -37,6 +37,7 @@
37
37
  <script setup>
38
38
  import { computed } from "vue";
39
39
  import { useLocale } from "../../composables/useLocale";
40
+ import { useProgressValue } from "../../internal/feedback/progress";
40
41
  const props = defineProps({
41
42
  value: { type: [Number, null], required: false, default: null },
42
43
  max: { type: Number, required: false, default: 100 },
@@ -53,12 +54,7 @@ const sizeValue = computed(
53
54
  );
54
55
  const radius = computed(() => 18 - props.thickness / 2);
55
56
  const circumference = computed(() => 2 * Math.PI * radius.value);
56
- const indeterminate = computed(() => props.value === null || props.value === void 0);
57
57
  const { t } = useLocale();
58
58
  const text = computed(() => props.label ?? t("progress.label"));
59
- const clamped = computed(() => Math.min(Math.max(props.value ?? 0, 0), props.max));
60
- const ratio = computed(() => props.max > 0 ? clamped.value / props.max : 0);
61
- const displayValue = computed(
62
- () => props.valueText ? props.valueText(clamped.value, props.max) : `${Math.round(ratio.value * 100)}%`
63
- );
59
+ const { indeterminate, clamped, ratio, displayValue } = useProgressValue(props);
64
60
  </script>