@nxgt/material-vue 0.23.4 → 0.25.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 (182) hide show
  1. package/README.md +30 -28
  2. package/dist/{Button-CVIR6uLK.js → Button-C1aaI0Gw.js} +95 -72
  3. package/dist/{HoverCardTrigger-iAL5ALrL.js → HoverCardTrigger-JtHn0IFQ.js} +2 -2
  4. package/dist/{camera-Gvg5N956.js → camera-BacVyXl0.js} +6 -6
  5. package/dist/{components-AScwCcds.js → components-DRBKkOqk.js} +15764 -13833
  6. package/dist/components.js +8 -8
  7. package/dist/composables.js +2 -2
  8. package/dist/dnd.js +1 -1
  9. package/dist/form-scope-VxlJuvFe.js +43 -0
  10. package/dist/{i18n-provider-BqWxpaKu.js → i18n-provider-D0oYv0XS.js} +1 -1
  11. package/dist/i18n.js +4 -4
  12. package/dist/{icon-button-DbEME76t.js → icon-button-B2FQtIHS.js} +34 -37
  13. package/dist/lib/components/ui/actions/button/has-text-content.d.ts +10 -0
  14. package/dist/lib/components/ui/actions/copy-button/copy-value.vue.d.ts +21 -0
  15. package/dist/lib/components/ui/actions/copy-button/index.d.ts +2 -0
  16. package/dist/lib/components/ui/collections/data-table/data-table-context.d.ts +6 -0
  17. package/dist/lib/components/ui/collections/data-table/data-table-pagination.vue.d.ts +2 -0
  18. package/dist/lib/components/ui/collections/data-table/data-table.vue.d.ts +17 -27
  19. package/dist/lib/components/ui/collections/data-table/index.d.ts +1 -1
  20. package/dist/lib/components/ui/collections/data-table/partials/data-table-body.vue.d.ts +10 -1
  21. package/dist/lib/components/ui/collections/data-table/partials/data-table-empty.vue.d.ts +13 -1
  22. package/dist/lib/components/ui/collections/data-table/partials/data-table-head.vue.d.ts +22 -0
  23. package/dist/lib/components/ui/collections/data-table/partials/data-table-skeleton-rows.vue.d.ts +10 -0
  24. package/dist/lib/components/ui/collections/data-table/use-data-table.d.ts +17 -0
  25. package/dist/lib/components/ui/collections/filter/partials/filter-field-slider-range.vue.d.ts +1 -4
  26. package/dist/lib/components/ui/collections/pagination/index.d.ts +5 -0
  27. package/dist/lib/components/ui/collections/pagination/pagination-bar.vue.d.ts +21 -0
  28. package/dist/lib/components/ui/collections/pagination/pagination-items.d.ts +2 -0
  29. package/dist/lib/components/ui/collections/pagination/pagination-link.vue.d.ts +18 -0
  30. package/dist/lib/components/ui/collections/tree/use-tree.d.ts +2 -0
  31. package/dist/lib/components/ui/dates/date-field/date-field.vue.d.ts +10 -1
  32. package/dist/lib/components/ui/dates/date-field/date-form-field.vue.d.ts +3 -1
  33. package/dist/lib/components/ui/dates/date-field/day-matcher.d.ts +26 -0
  34. package/dist/lib/components/ui/dates/date-field/index.d.ts +1 -0
  35. package/dist/lib/components/ui/dates/date-field/partials/date-field-content.vue.d.ts +2 -0
  36. package/dist/lib/components/ui/dates/date-range-field/date-range-field.utils.d.ts +11 -0
  37. package/dist/lib/components/ui/dates/date-range-field/date-range-field.vue.d.ts +26 -1
  38. package/dist/lib/components/ui/dates/date-range-field/date-range-form-field.vue.d.ts +3 -1
  39. package/dist/lib/components/ui/dates/date-range-field/index.d.ts +1 -0
  40. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-calendar.vue.d.ts +5 -0
  41. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-field-trigger.vue.d.ts +2 -0
  42. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-presets.vue.d.ts +12 -0
  43. package/dist/lib/components/ui/dates/date-range-field/partials/date-range-times.vue.d.ts +13 -0
  44. package/dist/lib/components/ui/dates/date-range-field/use-date-range-presets.d.ts +23 -0
  45. package/dist/lib/components/ui/dates/time-picker/time-picker-utils.d.ts +7 -0
  46. package/dist/lib/components/ui/display/accordion-card/accordion-card.vue.d.ts +29 -1
  47. package/dist/lib/components/ui/display/avatar/Avatar.vue.d.ts +14 -3
  48. package/dist/lib/components/ui/display/avatar/index.d.ts +1 -0
  49. package/dist/lib/components/ui/display/cards/cards.gallery.d.ts +5 -9
  50. package/dist/lib/components/ui/display/markdown/index.d.ts +18 -0
  51. package/dist/lib/components/ui/display/qrcode/qrcode.vue.d.ts +5 -3
  52. package/dist/lib/components/ui/display/status-indicator/status-tone.d.ts +3 -0
  53. package/dist/lib/components/ui/feedback/confirmation-dialog/async-form-scope.d.ts +15 -0
  54. package/dist/lib/components/ui/feedback/confirmation-dialog/confirmation-dialog.vue.d.ts +37 -24
  55. package/dist/lib/components/ui/feedback/confirmation-dialog/index.d.ts +1 -1
  56. package/dist/lib/components/ui/feedback/confirmation-dialog/partials/confirmation-dialog-form-error.vue.d.ts +3 -0
  57. package/dist/lib/components/ui/feedback/skeleton/skeleton-text.vue.d.ts +1 -1
  58. package/dist/lib/components/ui/feedback/spinner/spinner.compound-variants.d.ts +4 -0
  59. package/dist/lib/components/ui/fields/attributes/form-schema.d.ts +24 -22
  60. package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
  61. package/dist/lib/components/ui/fields/inline-edit/index.d.ts +1 -0
  62. package/dist/lib/components/ui/fields/inline-edit/inline-edit-form-field.vue.d.ts +7 -0
  63. package/dist/lib/components/ui/fields/number-field/number-field.vue.d.ts +2 -0
  64. package/dist/lib/components/ui/fields/slider/partials/slider-field-row.vue.d.ts +32 -0
  65. package/dist/lib/components/ui/fields/slider/slider-field.vue.d.ts +22 -1
  66. package/dist/lib/components/ui/fields/slider/slider-form-field.vue.d.ts +13 -1
  67. package/dist/lib/components/ui/forms/form-scope-schema.d.ts +43 -0
  68. package/dist/lib/components/ui/forms/form-scope.vue.d.ts +33 -0
  69. package/dist/lib/components/ui/layout/doc/doc.vue.d.ts +5 -5
  70. package/dist/lib/components/ui/layout/doc/index.d.ts +8 -1
  71. package/dist/lib/components/ui/layout/doc/partials/default-doc-link.vue.d.ts +14 -0
  72. package/dist/lib/components/ui/layout/doc/partials/doc-copy-page.vue.d.ts +6 -0
  73. package/dist/lib/components/ui/layout/doc/partials/doc-link.vue.d.ts +3 -7
  74. package/dist/lib/components/ui/layout/doc/types.d.ts +6 -1
  75. package/dist/lib/components/ui/media/file-preview/file-preview-pdf.lazy.d.ts +8 -0
  76. package/dist/lib/components/ui/media/file-preview/file-preview.vue.d.ts +9 -0
  77. package/dist/lib/components/ui/media/file-preview/index.d.ts +3 -0
  78. package/dist/lib/components/ui/media/file-preview/partials/file-preview-body.vue.d.ts +21 -0
  79. package/dist/lib/components/ui/media/file-preview/partials/file-preview-card.vue.d.ts +15 -0
  80. package/dist/lib/components/ui/media/file-preview/partials/file-preview-download.vue.d.ts +11 -0
  81. package/dist/lib/components/ui/media/file-preview/partials/file-preview-media.vue.d.ts +17 -0
  82. package/dist/lib/components/ui/media/file-preview/partials/file-preview-pdf.vue.d.ts +21 -0
  83. package/dist/lib/components/ui/media/file-preview/partials/file-preview-status.vue.d.ts +22 -0
  84. package/dist/lib/components/ui/media/file-preview/partials/file-preview-text.vue.d.ts +16 -0
  85. package/dist/lib/components/ui/media/file-preview/types.d.ts +19 -0
  86. package/dist/lib/components/ui/media/file-preview/use-file-preview.d.ts +21 -0
  87. package/dist/lib/components/ui/media/file-preview/use-text-preview.d.ts +17 -0
  88. package/dist/lib/components/ui/media/files-form-field/files-form-field.vue.d.ts +29 -0
  89. package/dist/lib/components/ui/media/files-form-field/index.d.ts +2 -0
  90. package/dist/lib/components/ui/media/image-cropper/partials/image-cropper-canvas.vue.d.ts +1 -1
  91. package/dist/lib/components/ui/media/index.d.ts +2 -0
  92. package/dist/lib/components/ui/media/pdf-viewer/index.d.ts +6 -6
  93. package/dist/lib/components/ui/media/pdf-viewer/partials/pdf-page.vue.d.ts +1 -1
  94. package/dist/lib/components/ui/media/pdf-viewer/partials/pdf-reader-body.vue.d.ts +2 -2
  95. package/dist/lib/components/ui/media/pdf-viewer/pdf-reader.vue.d.ts +2 -2
  96. package/dist/lib/components/ui/media/upload/network-upload-field/use-image-preview.d.ts +9 -1
  97. package/dist/lib/components/ui/primitives/icon/icon-context.d.ts +1 -1
  98. package/dist/lib/components/ui/primitives/tabs/Tabs.vue.d.ts +3 -0
  99. package/dist/lib/components/ui/primitives/tabs/index.d.ts +1 -0
  100. package/dist/lib/components/ui/primitives/tabs/tabs-variant.d.ts +9 -0
  101. package/dist/lib/components/ui/selection/autocomplete/autocomplete-form-field.vue.d.ts +31 -5
  102. package/dist/lib/components/ui/selection/autocomplete/autocomplete-items.d.ts +23 -0
  103. package/dist/lib/components/ui/selection/autocomplete/autocomplete.vue.d.ts +48 -13
  104. package/dist/lib/components/ui/selection/autocomplete/filter-options.d.ts +2 -1
  105. package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-box.vue.d.ts +13 -1
  106. package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-list.vue.d.ts +17 -3
  107. package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-items.d.ts +15 -0
  108. package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-open.d.ts +15 -0
  109. package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-texts.d.ts +14 -0
  110. package/dist/lib/components/ui/selection/autocomplete/use-autocomplete.d.ts +34 -0
  111. package/dist/lib/components/ui/selection/checkbox/Checkbox.vue.d.ts +21 -5
  112. package/dist/lib/components/ui/selection/checkbox/checkbox-form-field.vue.d.ts +17 -0
  113. package/dist/lib/components/ui/selection/checkbox/index.d.ts +2 -0
  114. package/dist/lib/components/ui/selection/index.d.ts +1 -0
  115. package/dist/lib/components/ui/selection/select-field/select-field.vue.d.ts +16 -1
  116. package/dist/lib/components/ui/selection/select-field/select-form-field.vue.d.ts +16 -2
  117. package/dist/lib/components/ui/selection/tree-select-field/index.d.ts +3 -0
  118. package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-panel.vue.d.ts +27 -0
  119. package/dist/lib/components/ui/selection/tree-select-field/partials/tree-select-trigger.vue.d.ts +28 -0
  120. package/dist/lib/components/ui/selection/tree-select-field/tree-select-field.vue.d.ts +8 -0
  121. package/dist/lib/components/ui/selection/tree-select-field/tree-select-form-field.vue.d.ts +8 -0
  122. package/dist/lib/components/ui/selection/tree-select-field/tree-select.utils.d.ts +29 -0
  123. package/dist/lib/components/ui/selection/tree-select-field/types.d.ts +28 -0
  124. package/dist/lib/components/ui/selection/tree-select-field/use-tree-select-field.d.ts +19 -0
  125. package/dist/lib/components/ui/widgets/charts/chart-container.vue.d.ts +1 -1
  126. package/dist/lib/components/ui/widgets/code-editor/code-editor-form-field.vue.d.ts +13 -0
  127. package/dist/lib/components/ui/widgets/code-editor/code-editor-options.d.ts +4 -1
  128. package/dist/lib/components/ui/widgets/code-editor/code-editor.vue.d.ts +7 -0
  129. package/dist/lib/components/ui/widgets/code-editor/index.d.ts +2 -0
  130. package/dist/lib/components/ui/widgets/code-editor/monaco-editor.vue.d.ts +3 -0
  131. package/dist/lib/i18n/resources/en/en.d.ts +40 -0
  132. package/dist/lib/i18n/resources/en/material.json.d.ts +43 -3
  133. package/dist/lib/i18n/resources/fr/fr.d.ts +40 -0
  134. package/dist/lib/i18n/resources/fr/material.json.d.ts +43 -3
  135. package/dist/lib/i18n/resources/resources.d.ts +80 -0
  136. package/dist/lib/i18n/translator.d.ts +1 -1
  137. package/dist/lib/nuxt/component-names.d.ts +1 -1
  138. package/dist/lib.js +2 -2
  139. package/dist/main.js +17 -17
  140. package/dist/map.js +4 -4
  141. package/dist/material-vue.css +1 -1
  142. package/dist/{pdf-outline-sidebar-oz9wdBhB.js → pdf-outline-sidebar-jJfhNjnN.js} +2 -2
  143. package/dist/{pdf-page-0rlq1Lo6.js → pdf-page-BW1hXzPu.js} +1 -1
  144. package/dist/{pdf-page-list-DfhjNHoI.js → pdf-page-list-D277RtWS.js} +2 -2
  145. package/dist/{pdf-reader-Dr8RVcs4.js → pdf-reader-BReUTsn_.js} +73 -71
  146. package/dist/{pdf-sidebar-VXPQbC_R.js → pdf-sidebar-Bk6PowY1.js} +3 -3
  147. package/dist/{pdf-thumbnail-sidebar-BpgXrVBj.js → pdf-thumbnail-sidebar-BcNDFsks.js} +3 -3
  148. package/dist/{pdf-toolbar-B6gRRcsv.js → pdf-toolbar-CHjaMhH9.js} +4 -4
  149. package/dist/pdf.js +2 -2
  150. package/dist/{sortable-provider-oEVjQiCl.js → sortable-provider-C83VBfGl.js} +2 -2
  151. package/dist/{stored-language-rjOMJkyX.js → stored-language-CC_vdcCN.js} +90 -6
  152. package/dist/{stx-player-DNADkQ31.js → stx-player-BMQ1D2Li.js} +20 -20
  153. package/dist/{translator-BCSJSO1-.js → translator-B-X_1taI.js} +1 -1
  154. package/dist/{use-heading-spy-d50_nxgR.js → use-heading-spy-C_ySuvTl.js} +1 -1
  155. package/dist/{use-material-translation-C5zPFhbk.js → use-material-translation-B6sIk0mF.js} +3 -3
  156. package/docs/components/README.md +2 -1
  157. package/docs/components/buttons-and-actions.md +19 -3
  158. package/docs/components/data-display.md +65 -11
  159. package/docs/components/data-table-filter-and-lists.md +94 -8
  160. package/docs/components/date-and-time.md +116 -9
  161. package/docs/components/feedback-and-status.md +57 -5
  162. package/docs/components/form-fields.md +21 -9
  163. package/docs/components/media-and-files.md +120 -6
  164. package/docs/components/navigation-and-layout.md +68 -7
  165. package/docs/components/primitives.md +25 -6
  166. package/docs/components/rich-widgets.md +21 -3
  167. package/docs/components/selection-and-choice.md +151 -22
  168. package/docs/guides/forms.md +16 -8
  169. package/docs/guides/i18n.md +50 -6
  170. package/docs/guides/ssr.md +2 -0
  171. package/docs/previews/buttons-actions-copybutton.webp +0 -0
  172. package/docs/previews/data-table-filter-lists-pagination.webp +0 -0
  173. package/docs/previews/date-time-daterangefield.webp +0 -0
  174. package/docs/previews/form-fields-slider.webp +0 -0
  175. package/docs/previews/media-files-filepreview.webp +0 -0
  176. package/docs/previews/navigation-layout-stepper.webp +0 -0
  177. package/docs/previews/selection-choice-checkbox.webp +0 -0
  178. package/docs/previews/selection-choice-treeselectfield.webp +0 -0
  179. package/docs/roadmap.md +47 -1
  180. package/docs/troubleshooting.md +213 -0
  181. package/lib/nuxt/component-names.ts +16 -0
  182. package/package.json +2 -2
@@ -23,6 +23,7 @@ value type each one writes. Everything is imported from
23
23
  | <img src="../previews/selection-choice-selectchipfield.webp" width="96" alt=""> | [SelectChipField](#selectchipfield) | Choice shown as chips |
24
24
  | <img src="../previews/selection-choice-transferlist.webp" width="96" alt=""> | [TransferList](#transferlist) | Two-pane picker |
25
25
  | <img src="../previews/selection-choice-sortablelist.webp" width="96" alt=""> | [SortableList](#sortablelist) | Reorderable list of strings |
26
+ | <img src="../previews/selection-choice-treeselectfield.webp" width="96" alt=""> | [TreeSelectField](#treeselectfield) | Pick from a tree, single or multiple |
26
27
  | <img src="../previews/selection-choice-switcher.webp" width="96" alt=""> | [Switcher](#switcher) | Workspace or account switcher |
27
28
 
28
29
  ## Select
@@ -105,7 +106,7 @@ const food = ref('banana');
105
106
 
106
107
  **Emits:** `update:modelValue` with the item value (`string` here). For a
107
108
  form, use `SelectField` / `SelectFormField`.
108
- **Storybook:** `Selection & choice/Select` · **React:** `Select` (same parts)
109
+ **Storybook:** `Selection & choice/Select` · **React:** `Select` (same parts), `NativeSelect` (same parts)
109
110
 
110
111
  ---
111
112
 
@@ -113,7 +114,7 @@ form, use `SelectField` / `SelectFormField`.
113
114
 
114
115
  ![SelectField](../previews/selection-choice-selectfield.webp)
115
116
 
116
- Labelled select built from `options`.
117
+ Labelled select built from `options`, with an `#option` slot.
117
118
 
118
119
  ```vue
119
120
  <script setup lang="ts">
@@ -142,7 +143,23 @@ const framework = ref('nuxt');
142
143
  | `required` | `boolean` | — | an asterisk after the label, and the select's `required` |
143
144
  | `label`, `helper-text`, `error`, `disabled` | | — | the field's text and state |
144
145
 
145
- React's `renderOption` is not in Vue: an option shows its `label`.
146
+ `#option` renders each option's content in the list (React's
147
+ `renderOption`); it receives `{ option, index, selected }`. The trigger shows
148
+ the picked option's text.
149
+
150
+ ```vue
151
+ <template>
152
+ <SelectField v-model="framework" label="Framework" :options="frameworks">
153
+ <template #option="{ option, selected }">
154
+ {{ option.label }} <small v-if="selected">current</small>
155
+ </template>
156
+ </SelectField>
157
+ </template>
158
+ ```
159
+
160
+ (with the script of the example above).
161
+
162
+ `SelectFormField` passes the slot through.
146
163
 
147
164
  **Emits:** `update:modelValue` with `string`.
148
165
  **Form wrapper:** `SelectFormField` — `name` inside a vee-validate form, see
@@ -208,7 +225,7 @@ options by label. Picking the selected option again clears it.
208
225
 
209
226
  ![Autocomplete](../previews/selection-choice-autocomplete.webp)
210
227
 
211
- Single or multiple (chips) autocomplete with free-solo values and a query event.
228
+ Single or multiple (chips) autocomplete typed by its options, with free-solo values, a query event and option slots.
212
229
 
213
230
  ```vue
214
231
  <script setup lang="ts">
@@ -239,23 +256,64 @@ const picked = ref<string[]>(['nuxt']);
239
256
  | --- | --- | --- | --- |
240
257
  | `mode` | `'single' \| 'multiple'` | `'single'` | decides the `v-model` type |
241
258
  | `v-model` | `string \| string[] \| null` | `null` | per `mode` |
242
- | `options` | `{ value: string; label: string }[]` | — | required; the items |
259
+ | `options` | `T[]`, `T extends { value: string; label: string }` | — | required; the items, typed by your own option type |
260
+ | `get-option-value` | `(option: T) => string` | `option.value` | the value an option stands for |
261
+ | `get-option-label` | `(option: T) => string` | `option.label` | the text it shows and is searched by |
243
262
  | `free-solo` | `boolean` | `false` | accept a typed value that is not an option ("Add …") |
263
+ | `free-solo-label` | `(query: string) => string` | `Add "{query}"`, translated | the free-solo button's text |
244
264
  | `@query-change` | `(query: string) => void` | — | the typed text, debounced 300 ms — fetch options here |
245
265
  | `empty` | `string` | "No option found." | text when nothing matches |
246
266
  | `required` | `boolean` | — | the asterisk, and `aria-required` on the input, which the label names |
247
267
  | `error` | `boolean` | — | red border on the box, error helper text, `aria-invalid` on the input |
248
268
 
249
- React's `getOptionValue` / `getOptionLabel` and `actions` are not in Vue:
250
- options are `{ value, label }`. In `multiple` mode each chip is a dismissible
251
- `Chip`: its remove button is named "Remove {label}", and is disabled with the
252
- field.
269
+ It is a generic component: `T` is inferred from `options`, and the slots —
270
+ React's render props — receive it whole:
271
+
272
+ | Slot | Props | Replaces React's |
273
+ | --- | --- | --- |
274
+ | `#option` | `{ option: T, index, selected }` | `renderOption` |
275
+ | `#selected-leading` | `{ option: T }` | `renderSelectedLeading` (before a chip's label) |
276
+ | `#actions` | `{ query }` | `actions` (above the list) |
277
+
278
+ ```vue
279
+ <script setup lang="ts">
280
+ import { ref } from 'vue';
281
+ import { Autocomplete } from '@nxgt/material-vue/components';
282
+
283
+ type Country = { value: string; label: string; flag: string; capital: string };
284
+ const countries: Country[] = [
285
+ { value: 'fr', label: 'France', flag: '🇫🇷', capital: 'Paris' },
286
+ { value: 'ch', label: 'Switzerland', flag: '🇨🇭', capital: 'Bern' },
287
+ ];
288
+ const picked = ref<string[]>([]);
289
+ </script>
290
+
291
+ <template>
292
+ <Autocomplete
293
+ v-model="picked"
294
+ mode="multiple"
295
+ label="Countries"
296
+ :options="countries"
297
+ :get-option-label="(country) => `${country.label} (${country.capital})`"
298
+ >
299
+ <template #option="{ option }">{{ option.flag }} {{ option.label }}</template>
300
+ <template #selected-leading="{ option }">{{ option.flag }}</template>
301
+ </Autocomplete>
302
+ </template>
303
+ ```
304
+
305
+ The value stays the options' values (`string` or `string[]`), as in React. In
306
+ `multiple` mode each chip is a dismissible `Chip`: its remove button is named
307
+ "Remove {label}", and is disabled with the field. `AutocompleteFormField` is
308
+ generic too, and passes the slots through. A generic component's ref is typed
309
+ with `ComponentExposed`, not `InstanceType`
310
+ ([troubleshooting](../troubleshooting.md#does-not-satisfy-the-constraint-abstract-new-args-any--any)).
253
311
 
254
312
  **Emits:** `update:modelValue` with `string | null` in `single` mode,
255
313
  `string[]` in `multiple`.
256
314
  **Form wrapper:** `AutocompleteFormField` — `name` inside a vee-validate form, see
257
315
  [forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
258
- **Storybook:** `Selection & choice/Autocomplete` · **React:** `Autocomplete`, `AutocompleteFormField`
316
+ **Storybook:** `Selection & choice/Autocomplete` (stories `TypedOptions`, `FilesFormField`) · **React:** `Autocomplete`, `AutocompleteFormField`
259
317
 
260
318
  ---
261
319
 
@@ -263,35 +321,38 @@ field.
263
321
 
264
322
  ![Checkbox](../previews/selection-choice-checkbox.webp)
265
323
 
266
- Reka UI checkbox with an indeterminate state; pair it with a `Label`.
324
+ Checkbox with label, helper text and an indeterminate state.
267
325
 
268
326
  ```vue
269
327
  <script setup lang="ts">
270
328
  import { ref } from 'vue';
271
- import { Checkbox, Label } from '@nxgt/material-vue/components';
329
+ import { Checkbox } from '@nxgt/material-vue/components';
272
330
 
273
331
  const receipts = ref(true);
274
332
  </script>
275
333
 
276
334
  <template>
277
- <div class="flex items-center gap-2">
278
- <Checkbox id="receipts" v-model="receipts" />
279
- <Label for="receipts">Email me receipts</Label>
280
- </div>
335
+ <Checkbox v-model="receipts" label="Email me receipts" helper-text="Sent after every payment." />
281
336
  </template>
282
337
  ```
283
338
 
284
339
  | Prop | Type | Default | Effect |
285
340
  | --- | --- | --- | --- |
286
341
  | `v-model` / `default-value` | `boolean \| 'indeterminate'` | — | Reka UI checkbox state |
287
- | `disabled`, `required`, `name`, `value` | | — | as on a native checkbox |
342
+ | `label` / `#label` slot | `string` | — | renders the box in a row with this label, which names and toggles it |
343
+ | `helper-text` / `#helper-text` slot | `string` | — | a line under the label |
344
+ | `class` | | — | the row when labelled, else the box |
345
+ | `disabled`, `required`, `name`, `value`, `id` | | — | as on a native checkbox; a labelled box gets an id when it has none |
288
346
 
289
- Unlike React, `Checkbox` has no `label` / `helper-text` of its own, and there
290
- is no `CheckboxFormField`: bind `v-model` to a `useField` value, or use
291
- `CheckboxGroup` / `SwitchFormField`.
347
+ Without `label` or `helper-text` it is the bare Reka UI box, as before: pair
348
+ it with your own `Label`. The default slot replaces the check mark (its
349
+ props give `state`, to draw a dash for `'indeterminate'`). Attributes such as
350
+ `aria-*` always reach the box, not the row.
292
351
 
293
352
  **Emits:** `update:modelValue` with `boolean | 'indeterminate'`.
294
- **Form wrapper:** none — `useField` + `v-model`, see [forms](../guides/forms.md#the-pair).
353
+ **Form wrapper:** `CheckboxFormField` (`name` plus the same props): an unset
354
+ value shows as indeterminate, and an indeterminate value is written as `null`;
355
+ the error message replaces `helper-text`. See [forms](../guides/forms.md#the-pair).
295
356
  **Storybook:** `Selection & choice/Checkbox` · **React:** `Checkbox`, `CheckboxFormField`
296
357
 
297
358
  ---
@@ -399,7 +460,7 @@ the layout wrapper): your own `aria-label` / `aria-labelledby` wins, and your
399
460
  **Emits:** `update:modelValue` with `string`.
400
461
  **Form wrapper:** `RadioGroupFormField` — `name` inside a vee-validate form, see
401
462
  [forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
402
- **Storybook:** `Selection & choice/RadioGroup` · **React:** `RadioGroup`, `RadioGroupItem`, `RadioGroupFormField`
463
+ **Storybook:** `Selection & choice/RadioGroup` · **React:** `RadioGroupField` (an alias of `RadioGroup`), `RadioGroup`, `RadioGroupItem`, `RadioGroupFormField`
403
464
 
404
465
  ---
405
466
 
@@ -612,6 +673,74 @@ The `#item` slot replaces a row's content.
612
673
 
613
674
  ---
614
675
 
676
+ ## TreeSelectField
677
+
678
+ ![TreeSelectField](../previews/selection-choice-treeselectfield.webp)
679
+
680
+ A field that opens a `Tree` in a popover: pick one node, or several as chips,
681
+ with an optional filter.
682
+
683
+ The field is controlled only: it holds no value of its own. Bind it with `v-model`;
684
+ without it, a pick changes nothing on screen.
685
+
686
+ ```vue
687
+ <script setup lang="ts">
688
+ import { ref } from 'vue';
689
+ import { TreeSelectField, type TreeNode } from '@nxgt/material-vue/components';
690
+
691
+ const regions: TreeNode[] = [
692
+ {
693
+ id: 'europe',
694
+ label: 'Europe',
695
+ children: [
696
+ { id: 'france', label: 'France' },
697
+ { id: 'spain', label: 'Spain' },
698
+ ],
699
+ },
700
+ { id: 'africa', label: 'Africa', children: [{ id: 'cameroon', label: 'Cameroon' }] },
701
+ ];
702
+
703
+ const picked = ref<string[]>(['france']);
704
+ </script>
705
+
706
+ <template>
707
+ <TreeSelectField v-model="picked" label="Regions" :items="regions" multiple searchable />
708
+ </template>
709
+ ```
710
+
711
+ Single mode (no `multiple`): a pick closes the popover and the trigger shows
712
+ the node's label. Multiple: the tree has checkboxes, and each pick is a
713
+ dismissible `Chip` beside the trigger, its remove button named "Remove
714
+ {label}" (`material.chip.dismiss-label`). The trigger is a `combobox`, named by
715
+ the label, with `aria-expanded` and `aria-controls`. Opening moves focus into
716
+ the filter, else into the tree on the pick (its branches unfolded); the tree
717
+ keeps its own keys (arrows, Home / End, Enter / Space), ↓ from the filter
718
+ enters it, and Escape closes the popover and hands focus back to the trigger.
719
+
720
+ | Prop | Type | Default | Effect |
721
+ | --- | --- | --- | --- |
722
+ | `items` | `TreeNode[]` | — | required; `Tree`'s nodes: `{ id, label, icon?, trailing?, disabled?, children? }` |
723
+ | `v-model` | `string \| null` / `string[]` | — | the picked id, or ids with `multiple` |
724
+ | `multiple` | `boolean` | `false` | checkboxes and chips; decides the value type |
725
+ | `searchable` | `boolean` | `false` | a filter above the tree; each match stays under its ancestors, which open |
726
+ | `placeholder` | `string` | "Select…" | shown while nothing is picked (`material.tree-select-field.placeholder`) |
727
+ | `search-placeholder` | `string` | "Search" | the filter's placeholder and name (`material.tree-select-field.search`) |
728
+ | `required` | `boolean` | — | the asterisk, and `aria-required` on the `combobox` |
729
+ | `disabled` | `boolean` | — | disables the trigger and each chip's remove button |
730
+ | `error` | `boolean` | — | error border, error helper text, `aria-invalid` on the `combobox` |
731
+ | `id`, `aria-describedby`, `data-*` | | — | on the trigger: the label is `for` the `id`, the description follows the helper text's |
732
+
733
+ Its copy is `material.tree-select-field.*`: `placeholder`, `search`, `empty` ("No
734
+ match found.") and `selected` ("{count} selected", the trigger's text in
735
+ multiple mode).
736
+
737
+ **Emits:** `update:modelValue` with `string | null` (single) or `string[]` (multiple).
738
+ **Form wrapper:** `TreeSelectFormField` — `name` (and `multiple`) inside a vee-validate form, see
739
+ [forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
740
+ **Storybook:** `Selection & choice/TreeSelectField` · **React:** `TreeSelectField`, `TreeSelectFormField`
741
+
742
+ ---
743
+
615
744
  ## Switcher
616
745
 
617
746
  ![Switcher](../previews/selection-choice-switcher.webp)
@@ -107,10 +107,10 @@ useForm({
107
107
  | --- | --- |
108
108
  | one input (`TextFormField`, `NumberFormField`, `SwitchFormField`, …) | its input loses focus, as a native `blur` |
109
109
  | several controls (`DateRangeFormField`, `SliderFormField` with two thumbs, `OtpFormField`, `PhoneFormField`, `TransferListFormField`, …) | focus leaves all of them; moving between them is not leaving |
110
- | a picker (`SelectFormField`, `DateFormField`, `TimeFormField`, `ComboboxFormField`, `CountryFormField`, …) | focus leaves the trigger **and** the popover it opened. Opening the popover, or picking in it, is not leaving; closing it hands focus back to the trigger, and the next Tab or click elsewhere is |
110
+ | a picker (`SelectFormField`, `DateFormField`, `TimeFormField`, `ComboboxFormField`, `TreeSelectFormField`, `CountryFormField`, …) | focus leaves the trigger **and** the popover it opened. Opening the popover, or picking in it, is not leaving; closing it hands focus back to the trigger, and the next Tab or click elsewhere is |
111
111
  | a dialog editor (`PostalAddressFormField`, `ContactsFormField`, `OpeningHoursFormField`, `AttributesFormField`, and `LocationFormField` from `@nxgt/material-vue/map`) | focus leaves its buttons and the dialog they open |
112
112
  | an upload (`UploadFormField`, `NetworkUploadFormField`, `ImageFormField`, `FileListFormField` and their S3 variants) | focus leaves the drop zone and its buttons. Choosing a file in the browser's own dialog is not leaving |
113
- | `RichTextEditorFormField` | focus leaves the editor and its toolbar |
113
+ | `RichTextEditorFormField`, `CodeEditorFormField` | focus leaves the editor and its toolbar |
114
114
  | `FilterFormField` | the filter is applied (or on every change, with `live-update`) — not on blur |
115
115
 
116
116
  "Opened" means named by one of the field's controls as the popup it controls
@@ -344,7 +344,7 @@ or fails validation.
344
344
  | `ColorField` · `ColorFormField` | `string` (hex, `'#1e293b'`), written when a valid colour is committed | `''` |
345
345
  | `OtpField` · `OtpFormField` | `string` of up to `length` (default 6) characters | `''` |
346
346
  | `InputGroupField` · `InputGroupFormField` | `string` | `''` |
347
- | `InlineEdit` | `string`, written on save only. No form wrapper: bind it with `useField` | `''` |
347
+ | `InlineEdit` · `InlineEditFormField` | `string`, written on save only | `''` |
348
348
  | `CountryField` · `CountryFormField` | `mode="single"` (default): ISO code `string \| null` (`'FR'`). `mode="multiple"`: `string[]` | `null` / `[]` |
349
349
  | `TimezoneField` · `TimezoneFormField` | IANA `string \| null` (`'Europe/Paris'`) | `null` |
350
350
  | `RatingField` · `RatingFormField` | `number`, `0` for no rating | `0` |
@@ -372,7 +372,7 @@ or fails validation.
372
372
  | `SelectField` · `SelectFormField` | `string` (an option `value`) | `''` |
373
373
  | `ComboboxField` · `ComboboxFormField` | `string \| null`; picking the selected option again clears it | `null` |
374
374
  | `Autocomplete` · `AutocompleteFormField` | `mode="single"` (default): `string \| null`. `mode="multiple"`: `string[]` | `null` / `[]` |
375
- | `Checkbox` | `boolean` (`'indeterminate'` / `null` for the third state). No form wrapper: use `SwitchFormField`, or bind it with `useField` | `false` |
375
+ | `Checkbox` · `CheckboxFormField` | `boolean`; an indeterminate value is written as `null` | `false` (see [Traps](#traps)) |
376
376
  | `CheckboxGroup` · `CheckboxGroupFormField` | `string[]` | `[]` |
377
377
  | `RadioGroupField` · `RadioGroupFormField` | `string` | `''` |
378
378
  | `CheckCardField` · `CheckCardFormField` | `boolean`: `true` for the first card, `false` for the second | `false` |
@@ -380,6 +380,7 @@ or fails validation.
380
380
  | `SelectChipField` · `SelectChipFormField` | same as `SelectCardField` | `[]` |
381
381
  | `TransferList` · `TransferListFormField` | `string[]`: the selected `value`s, in order | `[]` |
382
382
  | `SortableList` · `SortableListFormField` | `string[]`: the `value`s, in the user's order | `[]` |
383
+ | `TreeSelectField` · `TreeSelectFormField` | `string \| null` (a node `id`). With `multiple`: `string[]`, in the order picked | `null` / `[]` |
383
384
 
384
385
  ### Media & files
385
386
 
@@ -389,8 +390,10 @@ or fails validation.
389
390
  | `S3UploadField` · `S3UploadFormField` | as above; the value is `publicUrl` from `get-presigned-url` | `undefined` / `[]` |
390
391
  | `ImageField`, `ImageS3Field` · `ImageFormField`, `ImageS3FormField` | `string \| undefined` (the uploaded URL) | `undefined` |
391
392
  | `FileListField`, `FileListS3Field` · `FileListFormField`, `FileListS3FormField` | `string[]` | `[]` |
393
+ | `FilesFormField` | `mode="single"`: `string \| null`. `mode="multiple"`: `string[]` (typed or picked URLs) | `null` / `[]` |
392
394
  | `UploadField` · `UploadFormField` | a `File`, or `File[]` with `multiple`. Nothing is uploaded | `undefined` / `[]` |
393
395
  | `RichTextEditor` · `RichTextEditorFormField` | `string`: the editor's HTML | `''` |
396
+ | `CodeEditor` · `CodeEditorFormField` | `string`: the source | `''` |
394
397
  | `LocationField` · `LocationFormField` (from `@nxgt/material-vue/map`) | `[lat, lng]`, rounded to 7 decimals | `null` |
395
398
 
396
399
  An upload field emits a **string** because it uploads as soon as a file is
@@ -399,10 +402,6 @@ dropped: the form holds where the file went, never the file.
399
402
  handler sends it (with `convertToFormData` from `@nxgt/material-vue/lib`,
400
403
  for example).
401
404
 
402
- Not in `@nxgt/material-vue`: `FilesFormField` (use `NetworkUploadFormField`
403
- or `FileListFormField`) and `CheckboxFormField` / `InlineEditFormField` (see
404
- the rows above).
405
-
406
405
  ## Composite values
407
406
 
408
407
  A composite field edits a structured value through its own dialog. The form
@@ -947,6 +946,15 @@ Type the schema as an array:
947
946
  z.object({ plan: z.array(z.string()).length(1, { error: 'Pick a plan' }) });
948
947
  ```
949
948
 
949
+ **A checkbox with no initial value is indeterminate.** `CheckboxFormField`
950
+ renders `undefined` as the indeterminate state (and writes `null` for it), as
951
+ in `@nxgt/material`. A `validationSchema` alone gives it no initial value.
952
+ Give it a boolean:
953
+
954
+ ```ts
955
+ useForm({ initialValues: { terms: false } });
956
+ ```
957
+
950
958
  **A field re-mounted on every render loses its state.** A `:key` that changes
951
959
  on each render (`:key="Math.random()"`) mounts a new field every time: focus,
952
960
  the `PhoneField` draft and the `NumberField` text are lost as you type, and
@@ -280,14 +280,18 @@ checkboxes, the filter's presets and `Min`/`Max` fields, the `variant="4"` spinn
280
280
  `You are here` and zoom buttons, and the close button of dialogs, sheets and
281
281
  `DialogFooter`. The other icon-only buttons are named from it too: the
282
282
  `Sidebar` toggle (`material.sidebar.toggle`), the data table's row expander
283
- (`material.table.labels.toggle-row`), a `Chip`'s remove button, which the
283
+ (`material.table.labels.toggle-row`), its loading status, "Loading data…" /
284
+ "Chargement des données…" (`material.table.loading`), a `Chip`'s remove button, which the
284
285
  `Autocomplete` chips use ("Remove {label}", `material.chip.dismiss-label`),
285
286
  the `LocationPreview` trigger (`material.map.preview` / `preview-named`),
286
287
  `DurationField`'s inputs, "Hours" and "Minutes"
287
288
  (`material['duration-field']['hours-label']` / `minutes-label`), and
288
289
  the delete button of the deprecated `ContactItem` / `OpeningHoursItem`
289
290
  (`material.contacts.buttons.remove`,
290
- `material['opening-hours'].buttons.remove`). The keys and the French are the
291
+ `material['opening-hours'].buttons.remove`). When the form of a
292
+ `ConfirmationDialog` with `form-options` cannot be loaded, it says so in the
293
+ form's place: "The form could not be loaded." / "Le formulaire n’a pas pu être
294
+ chargé." (`material.confirm-dialog.form-failed`). The keys and the French are the
291
295
  same in `@nxgt/material`, so one set of overrides fits both. Text you pass yourself always wins over the
292
296
  translation: a `label`, an `aria-label` on `Spinner`, `ScrollToTop`,
293
297
  `CalendarPrevButton` or `CalendarNextButton`, and `LocationMarker`'s
@@ -298,7 +302,10 @@ names and text, which reka-ui left in English (`material.pagination.first`,
298
302
  `previous`, `next`, `last`, `page`, and `more` for the ellipsis), and the
299
303
  `aria-label` of `Pagination` and `Breadcrumb` and the breadcrumb ellipsis's
300
304
  "More" (`material.pagination.label`, `material.breadcrumb.*`), and
301
- `DocHeader`'s breadcrumb (`material.doc.breadcrumb`); `CommandDialog`'s
305
+ `DocHeader`'s breadcrumb (`material.doc.breadcrumb`); the status a `Stepper`
306
+ step announces after its title, "Completed" or "Error"
307
+ (`material.stepper.completed` / `error`, "Terminée" / "Erreur" in French);
308
+ `CommandDialog`'s
302
309
  default title and description (`material.command.*`); the carousel's
303
310
  `aria-roledescription` (`material.carousel.roledescription` / `slide`); the
304
311
  filter's empty state and `+N more` chip (`material.filter.empty` / `more`) and
@@ -319,10 +326,47 @@ buttons (`material['rich-text-editor'].placeholder` / `insert-emoji`);
319
326
  (`material['circular-progress'].label`); `StxPlayer`'s "Media player" for a
320
327
  track without a title (`material['stx-player'].label`); `PaneLayoutPane`'s
321
328
  sheet title on a phone (`material['pane-layout']['sheet-title']`);
322
- `JsonViewer`'s "Empty JSON" (`material['json-viewer'].empty`); and
329
+ `JsonViewer`'s "Empty JSON" (`material['json-viewer'].empty`);
323
330
  `TimePicker`'s AM/PM (`material['time-picker'].am` / `pm`, "a.m." / "p.m." in
324
- French). Your `placeholder`, `sheetTitle`, `title`, `description` and
325
- `aria-label` still win.
331
+ French). `TreeSelectField`'s placeholder, search box, empty message and
332
+ "{count} selected" follow the language too (`material['tree-select-field'].placeholder` /
333
+ `search` / `empty` / `selected`; in French `selected` is an ICU plural,
334
+ `{count, plural, …}`); the `placeholder` and `search-placeholder` props take
335
+ precedence over them. Your `placeholder`, `sheetTitle`, `title`, `description`
336
+ and `aria-label` still win. The names of
337
+ `TimePicker`'s inputs read `material.time-picker.hours` and
338
+ `material.time-picker.minutes` ("Hours" / "Minutes", "Heures" / "Minutes").
339
+ `DateRangeField`'s preset list is a group named by
340
+ `material.date-range-field.presets` ("Presets", "Plages prédéfinies"); its
341
+ built-in presets read `material.date-range-field.preset.today`,
342
+ `material.date-range-field.preset.yesterday`,
343
+ `material.date-range-field.preset.last-7-days`,
344
+ `material.date-range-field.preset.last-30-days`,
345
+ `material.date-range-field.preset.this-month`,
346
+ `material.date-range-field.preset.last-month` and
347
+ `material.date-range-field.preset.this-year` ("Today", "Yesterday", "Last 7
348
+ days", "Last 30 days", "This month", "Last month", "This year"; "Aujourd’hui",
349
+ "Hier", "7 derniers jours", "30 derniers jours", "Ce mois-ci", "Le mois
350
+ dernier", "Cette année"), and with times its two groups
351
+ `material.date-range-field.start-time` and `material.date-range-field.end-time`
352
+ ("Start time" / "End time", "Heure de début" / "Heure de fin"); its OK button
353
+ reads `material.buttons.ok`. The label of a preset of your own is yours.
354
+ `FilePreview`'s figure is named by `material.file-preview.label` ("Preview
355
+ of {name}", "Aperçu de {name}"), with `material.file-preview.untitled`
356
+ ("Untitled file", "Fichier sans nom") as the name of a file that has none; it
357
+ reads `material.file-preview.loading` ("Loading preview…", "Chargement de
358
+ l’aperçu…") while it reads the file, `material.file-preview.error` ("This
359
+ file could not be previewed.", "Impossible d’afficher l’aperçu de ce
360
+ fichier.") when it cannot show it, `material.file-preview.download`
361
+ ("Download", "Télécharger") on its download link, and
362
+ `material.file-preview.truncated` ("Showing the first {size} of this file.",
363
+ "Seuls les premiers {size} de ce fichier sont affichés.") under a text cut
364
+ by the size cap; the text or Markdown it shows scrolls in a region named by
365
+ `material.file-preview.content` ("Contents of {name}", "Contenu de {name}").
366
+ `material.slider.value` / `minimum` / `maximum`
367
+ ("Value", "Minimum", "Maximum") are there for `@nxgt/material`'s editable
368
+ `Slider` readout inputs (this package's readout is text), so the bundles hold
369
+ the same keys.
326
370
 
327
371
  To format filter values yourself in the provider's language, pass
328
372
  `formatFilterValue` the same words `FilterChips` uses (`FilterValueWords`; the
@@ -42,12 +42,14 @@ at import time would crash the server before it answers anything.
42
42
  | --- | --- |
43
43
  | `PdfReader`, `PdfSidebar`, `PdfPageList`, `PdfThumbnailSidebar` | `pdfjs-dist` runs `new DOMMatrix()` when it is imported |
44
44
  | `CodeEditor`, `CodeDiff` | Monaco |
45
+ | `CodeEditorFormField` | it renders `CodeEditor`, whose Monaco is client-only |
45
46
  | `Camera` | `getUserMedia` |
46
47
  | `StxPlayer` | media element APIs |
47
48
  | the charts (`BarChart`, `AreaChart`, `HeatmapChart`, …) | ECharts draws on a canvas it sizes from the DOM |
48
49
  | `ImageCropper` (its canvas) | canvas cropping |
49
50
  | `RichTextEditor` (its editor) | Tiptap / ProseMirror |
50
51
  | mermaid diagrams inside `Markdown` | mermaid renders in the browser; the rest of the Markdown renders on the server |
52
+ | `MermaidDiagram` | the same mermaid chart on its own, rendered in the browser |
51
53
 
52
54
  - **The map entry is importable, but draws in the browser only.**
53
55
  `@nxgt/material-vue/map` is its own entry because `leaflet` and
package/docs/roadmap.md CHANGED
@@ -6,7 +6,22 @@ the version something shipped in.
6
6
 
7
7
  ## Now
8
8
 
9
- Nothing in progress right now; see Next.
9
+ - **TreeSelectField** — pick one or several items from a tree inside a form
10
+ field, as chips when several, with an optional filter that keeps each match
11
+ under its ancestors (`TreeSelectField`, `TreeSelectFormField`).
12
+ - **The same options as `@nxgt/material`** — a generic `Autocomplete` and
13
+ `FilesFormField` typed by your items, a `ConfirmationDialog` that holds a
14
+ form, date fields that disable chosen days, `SliderField` ticks and
15
+ leading/trailing content, a presence status on `Avatar`, a logo slot on the
16
+ QR code, slots on `AccordionCard`, an option slot on `SelectField`, Monaco's
17
+ own options on `CodeEditor` and a line variant for `Tabs`.
18
+ - **DateRangeField presets and time** — one-click ranges such as Today, Last 7
19
+ days and This month, or your own, beside the calendar (`presets`), and a time
20
+ of day on each end of the range (`with-time`), and `min-date` / `max-date`.
21
+ - **FilePreview** — preview a file picked by its type, in one component: an
22
+ image, a PDF in `PdfReader`, a video or audio file, the text of a text, JSON,
23
+ CSV or Markdown file, or a card with a download link for anything else
24
+ (`FilePreview`, `@error`). Safe on a server.
10
25
 
11
26
  ## Next
12
27
 
@@ -14,6 +29,8 @@ Nothing in progress right now; see Next.
14
29
  their table header on every printed page, keep rows and totals whole, print
15
30
  their colours, and a `PrintPage` sets size and margins for `window.print()`.
16
31
  Vue only: `@nxgt/material`'s print blocks already produce a PDF.
32
+ - **`StepperIndicator`, as in `@nxgt/material`** — the step markers on their
33
+ own, for a stepper laid out your way.
17
34
 
18
35
  ## Later
19
36
 
@@ -53,6 +70,8 @@ Nothing in progress right now; see Next.
53
70
 
54
71
  ## Not planned
55
72
 
73
+ - **The `Combobox` primitive family** — `ComboboxFormField` covers forms; the
74
+ low-level `Combobox` parts stay in `@nxgt/material` only.
56
75
  - **The React library's state and form stacks** — widgets keep their state in
57
76
  per-instance Pinia stores (`defineLocalStore`), forms use vee-validate, the
58
77
  primitives Reka UI, the charts ECharts through `vue-echarts`, and routing
@@ -88,6 +107,33 @@ Nothing in progress right now; see Next.
88
107
 
89
108
  ## Shipped
90
109
 
110
+ - **Spinner `light` colour renders** — a `Spinner` with `color="light"` shows
111
+ its light ring, for loading states on dark or coloured surfaces. 0.24.0.
112
+ - **Range filters announce their field name** — the slider thumbs and the
113
+ `Min`/`Max` inputs of a `slider-range` or `number-range` filter are named
114
+ after the field, so a screen reader says which range is changing. 0.24.0.
115
+ - **Alert keeps long content inside** — a long title, description or unbroken
116
+ string wraps inside the `Alert` instead of running past its edge. 0.24.0.
117
+ - **Slider thumb follows the theme in dark mode** — the `Slider` thumb takes
118
+ the dark theme's colours instead of staying light. Vue only. 0.24.0.
119
+ - **Stepper: unique ids, announced steps and truncated titles** — two steppers
120
+ on one page no longer share ids, a screen reader hears which step is current
121
+ and whether each is done or in error, and a long step title truncates. 0.24.0.
122
+ - **Layouts that hold long content** — `ListTile`, `StatCard` and `Banner`
123
+ keep long titles, values and actions inside their box instead of overflowing.
124
+ 0.24.0.
125
+ - **The same exports as `@nxgt/material`** — a `Checkbox` with its own
126
+ `label` and `helper-text` (the bare box is unchanged) and
127
+ `CheckboxFormField`, `InlineEditFormField`, `CodeEditorFormField`,
128
+ `PaginationBar` with `paginationItems` and `PaginationLink`, `CopyValue`,
129
+ `MermaidDiagram`, and the `Doc` parts `DocArticle`, `DocNav`, `DocLink`,
130
+ `DefaultDocLink` and `DocCopyPage`, under the names they have in React.
131
+ 0.24.0.
132
+ ([forms](guides/forms.md#what-each-field-emits))
133
+ - **DataTable loading and empty states** — skeleton rows while the data loads
134
+ (the rows already shown stay in place, dimmed, during a refresh), the table
135
+ announced as busy, and your own content when there are no rows, told
136
+ whether a filter emptied it. 0.24.0.
91
137
  - **One copy of the framework-free code, shared with `@nxgt/material`** —
92
138
  the PDF document model and renderer, the print formatters, the PDF file
93
139
  helpers, `PdfReader`'s page geometry, scroll spy and search, the