@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,8 +1,8 @@
1
1
  import { useLocale } from "./useLocale.mjs";
2
- import { confirmQueue, hasConfirmHost, nextConfirmId } from "../internal/overlays/confirm.mjs";
2
+ import { isClient } from "../internal/core/env.mjs";
3
+ import { enqueueDialog, hasConfirmHost, nativeDialogMessage } from "../internal/overlays/confirm.mjs";
3
4
  async function nativeConfirm(options, fallback) {
4
- const message = [options.title, options.description].filter(Boolean).join("\n\n");
5
- if (!window.confirm(message || fallback)) return false;
5
+ if (!window.confirm(nativeDialogMessage(options) || fallback)) return false;
6
6
  try {
7
7
  await options.onConfirm?.();
8
8
  return true;
@@ -14,10 +14,10 @@ export function useConfirm() {
14
14
  const { t } = useLocale();
15
15
  return function confirm(input = {}) {
16
16
  const options = typeof input === "string" ? { description: input } : input;
17
- if (typeof window === "undefined") return Promise.resolve(false);
17
+ if (!isClient()) return Promise.resolve(false);
18
18
  if (!hasConfirmHost()) return nativeConfirm(options, t("common.areYouSure"));
19
19
  return new Promise((resolve) => {
20
- confirmQueue.push({ ...options, kind: "confirm", id: nextConfirmId(), resolve });
20
+ enqueueDialog({ ...options, kind: "confirm", resolve });
21
21
  });
22
22
  };
23
23
  }
@@ -2,6 +2,7 @@ import type { ComputedRef, MaybeRefOrGetter } from 'vue';
2
2
  export interface FieldContext {
3
3
  id: string;
4
4
  labelId: string;
5
+ hasLabel?: ComputedRef<boolean>;
5
6
  name: ComputedRef<string | undefined>;
6
7
  describedBy: ComputedRef<string | undefined>;
7
8
  invalid: ComputedRef<boolean>;
@@ -9,6 +10,7 @@ export interface FieldContext {
9
10
  disabled: ComputedRef<boolean>;
10
11
  setControlError: (message: string | undefined, source?: object) => void;
11
12
  setLabelable?: (labelable: boolean | undefined, source: object) => void;
13
+ setRequiredHint?: (hint: boolean | undefined, source: object) => void;
12
14
  }
13
15
  export type FieldControlRole = 'primary' | 'auxiliary';
14
16
  export declare function useField(): FieldContext | null;
@@ -20,6 +22,7 @@ export interface FieldControlOptions {
20
22
  describedBy?: MaybeRefOrGetter<string | undefined>;
21
23
  role?: MaybeRefOrGetter<FieldControlRole | undefined>;
22
24
  labelable?: MaybeRefOrGetter<boolean | undefined>;
25
+ requiredHint?: MaybeRefOrGetter<boolean | undefined>;
23
26
  }
24
27
  export declare function useFieldControl(options?: FieldControlOptions): {
25
28
  readonly field: FieldContext | null;
@@ -28,6 +31,7 @@ export declare function useFieldControl(options?: FieldControlOptions): {
28
31
  required: ComputedRef<boolean>;
29
32
  disabled: ComputedRef<boolean>;
30
33
  describedBy: ComputedRef<string | undefined>;
34
+ labelledBy: ComputedRef<string | undefined>;
31
35
  attrs: ComputedRef<{
32
36
  id: string | undefined;
33
37
  name: string | undefined;
@@ -1,5 +1,6 @@
1
1
  import { computed, getCurrentScope, inject, onScopeDispose, toValue, watch } from "vue";
2
2
  import { FIELD_KEY, FIELD_ROLE_KEY } from "../internal/keys.mjs";
3
+ import { joinIds } from "../internal/forms/control.mjs";
3
4
  export function useField() {
4
5
  return inject(FIELD_KEY, null);
5
6
  }
@@ -14,16 +15,18 @@ export function useFieldControl(options = {}) {
14
15
  () => Boolean(toValue(options.required) || field.value?.required.value)
15
16
  );
16
17
  const disabled = computed(() => Boolean(toValue(options.disabled) || parent?.disabled.value));
17
- const describedBy = computed(() => {
18
- const ids = [toValue(options.describedBy), field.value?.describedBy.value].filter(Boolean);
19
- return ids.length ? ids.join(" ") : void 0;
20
- });
18
+ const describedBy = computed(
19
+ () => joinIds(toValue(options.describedBy), field.value?.describedBy.value)
20
+ );
21
+ const labelledBy = computed(
22
+ () => field.value?.hasLabel?.value === false ? void 0 : field.value?.labelId
23
+ );
21
24
  const attrs = computed(() => ({
22
25
  id: id.value,
23
26
  name: field.value?.name.value,
24
27
  "aria-invalid": invalid.value ? "true" : void 0,
25
28
  "aria-describedby": describedBy.value,
26
- "aria-required": required.value ? "true" : void 0,
29
+ "aria-required": required.value && !toValue(options.requiredHint) ? "true" : void 0,
27
30
  disabled: disabled.value || void 0
28
31
  }));
29
32
  const source = {};
@@ -35,9 +38,16 @@ export function useFieldControl(options = {}) {
35
38
  (labelable) => parent.setLabelable?.(labelable, source),
36
39
  { immediate: true }
37
40
  );
41
+ if (parent.setRequiredHint && options.requiredHint !== void 0)
42
+ watch(
43
+ () => auxiliary.value ? void 0 : toValue(options.requiredHint),
44
+ (hint) => parent.setRequiredHint?.(hint, source),
45
+ { immediate: true }
46
+ );
38
47
  onScopeDispose(() => {
39
48
  parent.setControlError(void 0, source);
40
49
  parent.setLabelable?.(void 0, source);
50
+ parent.setRequiredHint?.(void 0, source);
41
51
  });
42
52
  }
43
53
  return {
@@ -49,6 +59,7 @@ export function useFieldControl(options = {}) {
49
59
  required,
50
60
  disabled,
51
61
  describedBy,
62
+ labelledBy,
52
63
  attrs,
53
64
  auxiliary,
54
65
  setControlError
@@ -1,5 +1,6 @@
1
1
  import { onScopeDispose, ref, toValue, watch } from "vue";
2
2
  import { filesTree, isHiddenName } from "../internal/forms/files.mjs";
3
+ import { isClient } from "../internal/core/env.mjs";
3
4
  const claimedEvents = /* @__PURE__ */ new WeakSet();
4
5
  function carriesFiles(event) {
5
6
  return Array.from(event.dataTransfer?.types ?? []).includes("Files");
@@ -76,7 +77,7 @@ export function useFileDrop(target, options) {
76
77
  over.value = depth > 0 && !covered;
77
78
  }
78
79
  function watchWindow(enable) {
79
- if (typeof window === "undefined" || watching === enable) return;
80
+ if (!isClient() || watching === enable) return;
80
81
  watching = enable;
81
82
  const method = enable ? "addEventListener" : "removeEventListener";
82
83
  window[method]("drop", reset, true);
@@ -1,6 +1,7 @@
1
1
  import { inject, markRaw, reactive } from "vue";
2
2
  import { hasHost } from "../internal/overlays/host.mjs";
3
3
  import { OVERLAY_CONTEXT_KEY, nextOverlayId, overlayStack } from "../internal/overlays/stack.mjs";
4
+ import { isClient } from "../internal/core/env.mjs";
4
5
  function settleEntry(entry, result) {
5
6
  if (!entry.settled) {
6
7
  entry.settled = true;
@@ -11,7 +12,7 @@ function settleEntry(entry, result) {
11
12
  function openOverlay(component, props = {}, options = {}) {
12
13
  let entry;
13
14
  const promise = new Promise((resolve) => {
14
- if (typeof window === "undefined") {
15
+ if (!isClient()) {
15
16
  resolve(void 0);
16
17
  return;
17
18
  }
@@ -1,5 +1,5 @@
1
- import { nextTick, provide } from "vue";
2
- import { isClient, prefersReducedMotion } from "../internal/core/env.mjs";
1
+ import { provide } from "vue";
2
+ import { withViewTransition } from "../internal/core/transition.mjs";
3
3
  import { resolvePresetStore } from "../internal/core/preset.mjs";
4
4
  import { PRESET_KEY } from "../internal/keys.mjs";
5
5
  export {
@@ -28,15 +28,9 @@ export function usePreset() {
28
28
  const preset = resolvePresetStore();
29
29
  function set(value, options = {}) {
30
30
  if (value === preset.value) return;
31
- const doc = isClient() ? document : void 0;
32
- if (!doc?.startViewTransition || prefersReducedMotion() || options.transition === false) {
31
+ withViewTransition(() => {
33
32
  preset.value = value;
34
- return;
35
- }
36
- doc.startViewTransition(async () => {
37
- preset.value = value;
38
- await nextTick();
39
- });
33
+ }, options.transition !== false);
40
34
  }
41
35
  return { preset, options: presetOptions, set };
42
36
  }
@@ -1,22 +1,15 @@
1
1
  import { useLocale } from "./useLocale.mjs";
2
- import { confirmQueue, hasConfirmHost, nextConfirmId } from "../internal/overlays/confirm.mjs";
2
+ import { isClient } from "../internal/core/env.mjs";
3
+ import { enqueueDialog, hasConfirmHost, nativeDialogMessage } from "../internal/overlays/confirm.mjs";
3
4
  export function usePrompt() {
4
5
  const { t } = useLocale();
5
6
  return function prompt(input = {}) {
6
7
  const options = typeof input === "string" ? { title: input } : input;
7
- if (typeof window === "undefined") return Promise.resolve(null);
8
- if (!hasConfirmHost()) {
9
- const message = [options.title, options.description].filter(Boolean).join("\n\n");
10
- return Promise.resolve(window.prompt(message, options.value ?? ""));
11
- }
8
+ if (!isClient()) return Promise.resolve(null);
9
+ if (!hasConfirmHost())
10
+ return Promise.resolve(window.prompt(nativeDialogMessage(options), options.value ?? ""));
12
11
  return new Promise((resolve) => {
13
- confirmQueue.push({
14
- title: t("prompt.title"),
15
- ...options,
16
- kind: "prompt",
17
- id: nextConfirmId(),
18
- resolve
19
- });
12
+ enqueueDialog({ title: t("prompt.title"), ...options, kind: "prompt", resolve });
20
13
  });
21
14
  };
22
15
  }
@@ -1,8 +1,9 @@
1
1
  import { getCurrentScope, onScopeDispose, readonly, ref, toValue, watch } from "vue";
2
+ import { isClient } from "../internal/core/env.mjs";
2
3
  let holders = 0;
3
4
  let saved = null;
4
5
  function applyLock() {
5
- if (typeof document === "undefined") return;
6
+ if (!isClient()) return;
6
7
  const root = document.documentElement;
7
8
  if (holders > 0 && !saved) {
8
9
  const hasScrollbar = window.innerWidth - root.clientWidth > 0;
@@ -24,7 +25,7 @@ function applyLock() {
24
25
  export function useScrollLock(active) {
25
26
  const locked = ref(false);
26
27
  function lock() {
27
- if (locked.value || typeof document === "undefined") return;
28
+ if (locked.value || !isClient()) return;
28
29
  locked.value = true;
29
30
  holders += 1;
30
31
  applyLock();
@@ -39,7 +40,7 @@ export function useScrollLock(active) {
39
40
  watch(
40
41
  () => Boolean(toValue(active)),
41
42
  (value) => value ? lock() : unlock(),
42
- { immediate: typeof document !== "undefined" }
43
+ { immediate: isClient() }
43
44
  );
44
45
  if (getCurrentScope()) onScopeDispose(unlock);
45
46
  return { locked: readonly(locked), lock, unlock };
@@ -1,5 +1,5 @@
1
- import { computed, nextTick, provide } from "vue";
2
- import { isClient, prefersReducedMotion } from "../internal/core/env.mjs";
1
+ import { computed, provide } from "vue";
2
+ import { withViewTransition } from "../internal/core/transition.mjs";
3
3
  import {
4
4
  THEME_ORDER,
5
5
  listenToSystemTheme,
@@ -35,15 +35,7 @@ export function useTheme() {
35
35
  }
36
36
  function set(value, options = {}) {
37
37
  if (value === preference.value) return;
38
- const doc = isClient() ? document : void 0;
39
- if (!doc?.startViewTransition || prefersReducedMotion() || options.transition === false) {
40
- apply(value);
41
- return;
42
- }
43
- doc.startViewTransition(async () => {
44
- apply(value);
45
- await nextTick();
46
- });
38
+ withViewTransition(() => apply(value), options.transition !== false);
47
39
  }
48
40
  function cycle() {
49
41
  set(THEME_ORDER[(THEME_ORDER.indexOf(preference.value) + 1) % THEME_ORDER.length] ?? "system");
@@ -1,5 +1,6 @@
1
1
  import { readonly } from "vue";
2
2
  import { nextToastId, nextToastVersion, toastList } from "../internal/overlays/toast.mjs";
3
+ import { isClient } from "../internal/core/env.mjs";
3
4
  function normalize(input, options) {
4
5
  if (typeof input === "string") return { ...options, title: input };
5
6
  return { ...input, ...options };
@@ -7,7 +8,7 @@ function normalize(input, options) {
7
8
  function show(input, options) {
8
9
  const next = normalize(input, options);
9
10
  const id = next.id ?? nextToastId();
10
- if (typeof window === "undefined") return id;
11
+ if (!isClient()) return id;
11
12
  const index = toastList.findIndex((item) => item.id === id);
12
13
  if (index !== -1) {
13
14
  const previous = toastList[index];
@@ -62,7 +62,7 @@
62
62
  inputmode="url"
63
63
  placeholder="https://"
64
64
  :aria-label="text.linkUrl"
65
- @keydown.esc.stop.prevent="closeLink"
65
+ @keydown.esc.stop.prevent="closeLink(true)"
66
66
  />
67
67
  <Button type="submit" size="xs" :label="text.applyLink" />
68
68
  <Button
@@ -80,10 +80,13 @@
80
80
  <div v-if="showCount" class="k-editor-footer">
81
81
  <span
82
82
  class="k-editor-count k-tabular"
83
- :class="{ 'is-over': maxLength !== void 0 && characters >= maxLength }"
83
+ :class="{ 'is-over': atLimit }"
84
+ aria-hidden="true"
84
85
  >{{ countText }}</span
85
86
  >
87
+ <span :id="countId" class="k-visually-hidden">{{ countLabel }}</span>
86
88
  </div>
89
+ <LiveRegion v-if="maxLength !== void 0" :message="atLimit ? text.limitReached : ''" />
87
90
  </div>
88
91
  </template>
89
92
 
@@ -92,10 +95,12 @@ import CharacterCount from "@tiptap/extension-character-count";
92
95
  import Placeholder from "@tiptap/extension-placeholder";
93
96
  import StarterKit from "@tiptap/starter-kit";
94
97
  import { EditorContent, useEditor } from "@tiptap/vue-3";
95
- import { computed, nextTick, onBeforeUnmount, ref, useTemplateRef, watch } from "vue";
98
+ import { computed, nextTick, onBeforeUnmount, ref, useId, useTemplateRef, watch } from "vue";
96
99
  import Button from "../components/core/Button.vue";
97
100
  import { useFieldControl } from "../composables/useField";
98
101
  import { useRovingTabStops } from "../internal/core/roving";
102
+ import LiveRegion from "../internal/core/LiveRegion.vue";
103
+ import { joinIds } from "../internal/forms/control";
99
104
  import { useLocale } from "../composables/useLocale";
100
105
  import { formatLocaleMessage } from "../locale";
101
106
  const icons = {
@@ -145,12 +150,14 @@ function isSameValue(current, value) {
145
150
  const incoming = value === "" ? null : value;
146
151
  return JSON.stringify(serialize(current)) === JSON.stringify(incoming ?? null);
147
152
  }
153
+ const countId = useId();
148
154
  function describedBy() {
149
- return control.describedBy.value;
155
+ return joinIds(control.describedBy.value, props.showCount && countId);
150
156
  }
151
157
  function labelledBy() {
152
158
  return props.label ? void 0 : control.field?.labelId;
153
159
  }
160
+ const empty = computed(() => model.value === null || model.value === "");
154
161
  function contentAttributes() {
155
162
  return {
156
163
  id: control.id.value ?? "",
@@ -162,6 +169,8 @@ function contentAttributes() {
162
169
  "aria-describedby": describedBy() ?? "",
163
170
  "aria-required": control.required.value ? "true" : "",
164
171
  "aria-readonly": props.readonly ? "true" : "",
172
+ "aria-disabled": control.disabled.value ? "true" : "",
173
+ "aria-placeholder": props.placeholder && empty.value ? props.placeholder : "",
165
174
  class: "k-editor-prose",
166
175
  style: `min-height: ${props.minHeight};${props.maxHeight ? ` max-height: ${props.maxHeight};` : ""}`
167
176
  };
@@ -190,6 +199,13 @@ const countText = computed(() => {
190
199
  });
191
200
  return props.maxLength === void 0 ? base : `${characters.value} / ${props.maxLength}`;
192
201
  });
202
+ const countLabel = computed(
203
+ () => props.maxLength === void 0 ? countText.value : formatLocaleMessage(locale.value.code, text.value.limit, {
204
+ count: characters.value,
205
+ max: props.maxLength
206
+ })
207
+ );
208
+ const atLimit = computed(() => props.maxLength !== void 0 && characters.value >= props.maxLength);
193
209
  watch(model, (value) => {
194
210
  const current = editor.value;
195
211
  if (!current || isSameValue(current, value)) return;
@@ -202,6 +218,10 @@ watch(
202
218
  () => props.minHeight,
203
219
  () => props.maxHeight,
204
220
  () => props.readonly,
221
+ () => props.placeholder,
222
+ () => props.showCount,
223
+ empty,
224
+ control.disabled,
205
225
  control.invalid,
206
226
  control.describedBy,
207
227
  control.required,
@@ -347,6 +367,7 @@ function itemAttributes(item) {
347
367
  return {
348
368
  "aria-label": item.label,
349
369
  title: item.label,
370
+ "data-k-editor-item": item.id,
350
371
  "aria-pressed": item.id === "undo" || item.id === "redo" ? void 0 : item.active(),
351
372
  disabled,
352
373
  onMousedown: (event) => event.preventDefault(),
@@ -362,9 +383,13 @@ function toggleLink() {
362
383
  linkOpen.value = true;
363
384
  nextTick(() => linkInputRef.value?.focus());
364
385
  }
365
- function closeLink() {
386
+ function closeLink(toButton = false) {
366
387
  linkOpen.value = false;
367
- editor.value?.commands.focus();
388
+ if (!toButton) {
389
+ editor.value?.commands.focus();
390
+ return;
391
+ }
392
+ toolbarRef.value?.querySelector('[data-k-editor-item="link"]')?.focus();
368
393
  }
369
394
  function normalizeUrl(value) {
370
395
  const trimmed = value.trim();
@@ -24,6 +24,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
24
24
  title?: string | undefined | undefined;
25
25
  style?: import("vue").StyleValue;
26
26
  results?: (string | number) | undefined;
27
+ dir?: string | undefined | undefined;
27
28
  class?: import("vue").ClassValue;
28
29
  role?: string | undefined | undefined;
29
30
  'aria-label'?: string | undefined | undefined;
@@ -179,7 +180,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
179
180
  accesskey?: string | undefined | undefined;
180
181
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
181
182
  contextmenu?: string | undefined | undefined;
182
- dir?: string | undefined | undefined;
183
183
  draggable?: (boolean | "true" | "false") | undefined;
184
184
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
185
185
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -238,6 +238,7 @@ declare const __VLS_export: import("vue").DefineComponent<{
238
238
  title?: string | undefined | undefined;
239
239
  style?: import("vue").StyleValue;
240
240
  results?: (string | number) | undefined;
241
+ dir?: string | undefined | undefined;
241
242
  class?: import("vue").ClassValue;
242
243
  role?: string | undefined | undefined;
243
244
  'aria-label'?: string | undefined | undefined;
@@ -393,7 +394,6 @@ declare const __VLS_export: import("vue").DefineComponent<{
393
394
  accesskey?: string | undefined | undefined;
394
395
  contenteditable?: (boolean | "true" | "false") | "inherit" | "plaintext-only" | undefined;
395
396
  contextmenu?: string | undefined | undefined;
396
- dir?: string | undefined | undefined;
397
397
  draggable?: (boolean | "true" | "false") | undefined;
398
398
  enterkeyhint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
399
399
  enterKeyHint?: "search" | "done" | "previous" | "next" | "enter" | "go" | "send" | undefined;
@@ -19,7 +19,7 @@
19
19
  }
20
20
 
21
21
  .k-editor:focus-within {
22
- border-color: var(--k-accent);
22
+ border-color: var(--k-ring);
23
23
  box-shadow: var(--k-focus-ring);
24
24
  }
25
25
 
@@ -140,6 +140,11 @@
140
140
  word-break: break-word;
141
141
  }
142
142
 
143
+ .k-editor-prose:focus-visible {
144
+ outline: 2px solid transparent;
145
+ outline-offset: -2px;
146
+ }
147
+
143
148
  .k-editor-prose > :first-child {
144
149
  margin-top: 0;
145
150
  }
@@ -239,7 +244,7 @@
239
244
  .k-editor-prose p.is-editor-empty:first-child::before {
240
245
  float: left;
241
246
  height: 0;
242
- color: var(--k-text-dimmed);
247
+ color: var(--k-text-muted);
243
248
  content: attr(data-placeholder);
244
249
  pointer-events: none;
245
250
  }
@@ -253,9 +258,9 @@
253
258
  justify-content: flex-end;
254
259
  padding: 0.25rem 0.75rem 0.375rem;
255
260
  font-size: 0.75rem;
256
- color: var(--k-text-dimmed);
261
+ color: var(--k-text-muted);
257
262
  }
258
263
 
259
264
  .k-editor-count.is-over {
260
- color: var(--k-danger);
265
+ color: var(--k-danger-text);
261
266
  }
@@ -21,7 +21,7 @@
21
21
  <div
22
22
  class="k-data-grid-body"
23
23
  role="region"
24
- :aria-label="label"
24
+ :aria-label="label ?? text.label"
25
25
  :aria-busy="loading ? 'true' : void 0"
26
26
  :style="autoHeight ? void 0 : { height }"
27
27
  >
@@ -34,7 +34,7 @@
34
34
  :default-col-def="defaultColDef"
35
35
  :get-row-id="props.rowIdKey ? getRowId : void 0"
36
36
  :loading="loading"
37
- :locale-text="localeText"
37
+ :locale-text="gridLocaleText"
38
38
  :context="cellContext"
39
39
  :overlay-no-rows-template="noRowsTemplate"
40
40
  :overlay-loading-template="loadingTemplate"
@@ -50,16 +50,17 @@
50
50
  :suppress-cell-focus="false"
51
51
  v-on="gridEvents"
52
52
  />
53
- <div v-else class="k-data-grid-placeholder" role="status" :aria-label="text.loading">
53
+ <div v-else class="k-data-grid-placeholder" aria-hidden="true">
54
54
  <Spinner decorative />
55
55
  </div>
56
- <p v-if="copied" class="k-data-grid-toast" role="status">{{ text.copied }}</p>
56
+ <p v-if="copied" class="k-data-grid-toast" aria-hidden="true">{{ text.copied }}</p>
57
+ <LiveRegion :message="loading || !mounted ? text.loading : live.message.value" />
57
58
  </div>
58
59
 
59
60
  <div v-if="showFooter" class="k-data-grid-footer">
60
61
  <span class="k-data-grid-footer-info" aria-live="polite">
61
62
  <template v-if="selectedCount > 0">{{
62
- format(text.selected, { count: selectedCount })
63
+ formatLocaleMessage(locale.code, text.selected, { count: selectedCount })
63
64
  }}</template>
64
65
  </span>
65
66
  <Pagination
@@ -79,7 +80,7 @@
79
80
  >
80
81
  <template #summary="{ start, end, total }">
81
82
  <span class="k-tabular">{{
82
- format(text.pageStatus, { from: start, to: end, total })
83
+ formatLocaleMessage(locale.code, text.pageStatus, { from: start, to: end, total })
83
84
  }}</span>
84
85
  </template>
85
86
  </Pagination>
@@ -94,9 +95,12 @@ import Pagination from "../components/data/Pagination.vue";
94
95
  import Spinner from "../components/core/Spinner.vue";
95
96
  import { useCopy } from "../composables/useCopy";
96
97
  import { useLocale } from "../composables/useLocale";
98
+ import LiveRegion from "../internal/core/LiveRegion.vue";
99
+ import { formatLocaleMessage } from "../locale";
100
+ import { useLiveMessage } from "../internal/core/live";
97
101
  import { readStorageJson, removeStorage, writeStorageJson } from "../internal/core/storage";
98
102
  import GridToolbar from "./GridToolbar.vue";
99
- import { escapeHtml, formatMessage as format } from "../internal/core/text";
103
+ import { escapeHtml } from "../internal/core/text";
100
104
  import { registerGridModules } from "./modules";
101
105
  import { getGridTheme } from "./theme";
102
106
  registerGridModules();
@@ -129,15 +133,38 @@ const emit = defineEmits(["rowClick", "selectionChange", "sortChange", "copy"]);
129
133
  const query = defineModel("query", { type: String, ...{ default: "" } });
130
134
  const page = defineModel("page", { type: Number, ...{ default: 1 } });
131
135
  const pageSize = defineModel("pageSize", { type: Number, ...{ default: 25 } });
132
- const { locale } = useLocale();
136
+ const { locale, t } = useLocale();
133
137
  const text = computed(() => ({
134
138
  ...locale.value.messages.grid,
135
139
  ...props.messages
136
140
  }));
137
141
  const cellContext = computed(() => ({
138
142
  messages: text.value,
139
- locale: locale.value.code
143
+ locale: locale.value.code,
144
+ emptyText: t("common.empty"),
145
+ newTabText: t("common.opensInNewTab")
140
146
  }));
147
+ const gridLocaleText = computed(() => ({
148
+ ariaChecked: text.value.checked,
149
+ ariaUnchecked: text.value.unchecked,
150
+ ariaIndeterminate: text.value.indeterminate,
151
+ ariaRowSelect: text.value.selectRowHint,
152
+ ariaRowDeselect: text.value.deselectRowHint,
153
+ ariaRowToggleSelection: text.value.toggleRowHint,
154
+ ariaRowSelectionDisabled: text.value.rowSelectionDisabled,
155
+ ariaRowSelectAll: text.value.selectAllHint,
156
+ ariaHeaderSelection: text.value.selectAllRows,
157
+ ariaSortableColumn: text.value.sortHint,
158
+ ariaLabelTooltip: text.value.tooltip,
159
+ ariaPageSizeSelectorLabel: text.value.rowsPerPage,
160
+ nextPage: text.value.nextPage,
161
+ previousPage: text.value.previousPage,
162
+ noRowsToShow: text.value.noRows,
163
+ loadingOoo: text.value.loading,
164
+ ...props.localeText
165
+ }));
166
+ const live = useLiveMessage();
167
+ let announcedCount = null;
141
168
  const theme = computed(() => getGridTheme(props.density));
142
169
  const mounted = ref(false);
143
170
  const api = shallowRef(null);
@@ -156,7 +183,7 @@ const noRowsTemplate = computed(
156
183
  () => `<div class="k-data-grid-overlay"><span>${escapeHtml(text.value.noRows)}</span></div>`
157
184
  );
158
185
  const loadingTemplate = computed(
159
- () => `<div class="k-data-grid-overlay"><span class="k-spinner k-spinner-md" role="status" aria-label="${escapeHtml(text.value.loading)}"></span></div>`
186
+ () => `<div class="k-data-grid-overlay"><span class="k-spinner k-spinner-md" aria-hidden="true"></span></div>`
160
187
  );
161
188
  const rowSelection = computed(() => {
162
189
  if (!props.selectable) return void 0;
@@ -170,8 +197,28 @@ const defaultColDef = computed(() => ({
170
197
  resizable: true,
171
198
  minWidth: 80,
172
199
  comparator: props.serverSort ? () => 0 : void 0,
173
- valueFormatter: (params) => params.value === null || params.value === void 0 || params.value === "" ? "-" : String(params.value)
200
+ valueFormatter: (params) => isEmpty(params.value) ? "-" : String(params.value),
201
+ cellRenderer: renderCell
174
202
  }));
203
+ function isEmpty(value) {
204
+ return value === null || value === void 0 || value === "";
205
+ }
206
+ function renderCell(params) {
207
+ const element = document.createElement("span");
208
+ if (!isEmpty(params.value)) {
209
+ element.textContent = params.valueFormatted ?? String(params.value);
210
+ return element;
211
+ }
212
+ const dash = document.createElement("span");
213
+ dash.className = "k-data-grid-empty";
214
+ dash.setAttribute("aria-hidden", "true");
215
+ dash.textContent = "-";
216
+ const hidden = document.createElement("span");
217
+ hidden.className = "k-visually-hidden";
218
+ hidden.textContent = cellContext.value.emptyText ?? "";
219
+ element.append(dash, hidden);
220
+ return element;
221
+ }
175
222
  const storageName = computed(() => props.storageKey ? `k-grid:${props.storageKey}` : null);
176
223
  const hasStoredState = ref(false);
177
224
  const autoSizeStrategy = computed(
@@ -208,6 +255,19 @@ function syncPagination() {
208
255
  clientPageCount.value = Math.max(1, current.paginationGetTotalPages());
209
256
  page.value = current.paginationGetCurrentPage() + 1;
210
257
  }
258
+ function onModelUpdated() {
259
+ syncPagination();
260
+ const current = api.value;
261
+ if (!current) return;
262
+ const count = props.serverPagination ? props.total : current.getDisplayedRowCount();
263
+ if (props.loading) return;
264
+ if (announcedCount !== null && announcedCount !== count)
265
+ live.announce(formatLocaleMessage(locale.value.code, text.value.rowCount, { count }));
266
+ announcedCount = count;
267
+ }
268
+ watch(copied, (value) => {
269
+ if (value) live.announce(text.value.copied);
270
+ });
211
271
  function goToPage(next) {
212
272
  const target = Math.min(Math.max(1, next), pageCount.value);
213
273
  page.value = target;
@@ -241,7 +301,7 @@ const gridEvents = {
241
301
  sortChanged: onSortChanged,
242
302
  cellContextMenu: onCellContextMenu,
243
303
  paginationChanged: syncPagination,
244
- modelUpdated: syncPagination,
304
+ modelUpdated: onModelUpdated,
245
305
  columnMoved: persistState,
246
306
  columnResized: persistState,
247
307
  columnVisible: persistState,
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="k-data-grid-toolbar" role="toolbar" :aria-label="text.toolbar">
2
+ <div class="k-data-grid-toolbar" role="group" :aria-label="text.toolbar">
3
3
  <div v-if="searchable" class="k-data-grid-search">
4
4
  <Input
5
5
  v-model="draft"