@nxgt/material-vue 0.37.1 → 0.38.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 (76) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +1 -0
  3. package/dist/{Button-CurFF4Zt.js → Button-5UyKA-x_.js} +1 -1
  4. package/dist/{HoverCardTrigger-jCXl6TrX.js → HoverCardTrigger-CmCDiTn8.js} +2 -2
  5. package/dist/{camera-CYwiFuGE.js → camera-BWzF8sOW.js} +4 -4
  6. package/dist/components/base.css +3 -1
  7. package/dist/{components--v_k8diD.js → components-B_s5oxUp.js} +11816 -11302
  8. package/dist/components.js +8 -8
  9. package/dist/composables.js +2 -2
  10. package/dist/dnd.js +1 -1
  11. package/dist/{form-scope-B2oJ5fHr.js → form-scope-UzoU38db.js} +1 -1
  12. package/dist/{i18n-provider-B2q6vp6H.js → i18n-provider-BEvjls8b.js} +1 -1
  13. package/dist/i18n.js +4 -4
  14. package/dist/{icon-button-CIUc1bEp.js → icon-button-DhqJE6Ej.js} +1 -1
  15. package/dist/lib/components/ui/feedback/banner/banner.vue.d.ts +1 -1
  16. package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
  17. package/dist/lib/components/ui/fields/index.d.ts +1 -0
  18. package/dist/lib/components/ui/fields/repeatable-group/index.d.ts +4 -0
  19. package/dist/lib/components/ui/fields/repeatable-group/partials/repeatable-group-footer.vue.d.ts +14 -0
  20. package/dist/lib/components/ui/fields/repeatable-group/partials/repeatable-group-row.vue.d.ts +33 -0
  21. package/dist/lib/components/ui/fields/repeatable-group/repeatable-group-classes.d.ts +33 -0
  22. package/dist/lib/components/ui/fields/repeatable-group/repeatable-group-form-field.vue.d.ts +44 -0
  23. package/dist/lib/components/ui/fields/repeatable-group/repeatable-group-names.d.ts +16 -0
  24. package/dist/lib/components/ui/fields/repeatable-group/repeatable-group.vue.d.ts +69 -0
  25. package/dist/lib/components/ui/fields/repeatable-group/use-repeatable-group.d.ts +39 -0
  26. package/dist/lib/components/ui/fields/search-field/search-field.vue.d.ts +10 -1
  27. package/dist/lib/components/ui/media/stx-player/stx-player-extras.vue.d.ts +1 -1
  28. package/dist/lib/components/ui/overlays/command/CommandItem.vue.d.ts +10 -3
  29. package/dist/lib/components/ui/overlays/command/CommandList.vue.d.ts +4 -2
  30. package/dist/lib/components/ui/primitives/typography/typography.variants.d.ts +1 -0
  31. package/dist/lib/components/ui/primitives/typography/typography.vue.d.ts +2 -0
  32. package/dist/lib/components/ui/selection/checkbox-group/checkbox-group.vue.d.ts +2 -0
  33. package/dist/lib/components/ui/selection/option-count/option-count.vue.d.ts +25 -0
  34. package/dist/lib/components/ui/selection/option-count/use-option-count-text.d.ts +10 -0
  35. package/dist/lib/components/ui/selection/radio-group/radio-group-field.vue.d.ts +2 -0
  36. package/dist/lib/components/ui/selection/select-chip-field/select-chip-field.vue.d.ts +11 -0
  37. package/dist/lib/components/ui/selection/sortable-list/sortable-list.vue.d.ts +1 -1
  38. package/dist/lib/components/ui/selection/transfer-list/transfer-list.vue.d.ts +1 -1
  39. package/dist/lib/i18n/resources/en/en.d.ts +14 -0
  40. package/dist/lib/i18n/resources/en/material.json.d.ts +14 -0
  41. package/dist/lib/i18n/resources/fr/fr.d.ts +14 -0
  42. package/dist/lib/i18n/resources/fr/material.json.d.ts +14 -0
  43. package/dist/lib/i18n/resources/resources.d.ts +28 -0
  44. package/dist/lib/i18n/translator.d.ts +1 -1
  45. package/dist/lib/nuxt/component-names.d.ts +1 -1
  46. package/dist/lib.js +1 -1
  47. package/dist/main.js +17 -17
  48. package/dist/map.js +4 -4
  49. package/dist/material-vue.css +1 -1
  50. package/dist/{pdf-outline-sidebar-DJJ-ARco.js → pdf-outline-sidebar-BsePJlTi.js} +2 -2
  51. package/dist/{pdf-page-CRt6KXdJ.js → pdf-page-Ct313mNF.js} +1 -1
  52. package/dist/{pdf-page-list-BgCp5Asx.js → pdf-page-list-JrRo2BeU.js} +2 -2
  53. package/dist/{pdf-reader-BGxqEx8O.js → pdf-reader-tABBZMbZ.js} +8 -8
  54. package/dist/{pdf-sidebar-Cvtuomgp.js → pdf-sidebar-Caw9rzU-.js} +3 -3
  55. package/dist/{pdf-thumbnail-sidebar-CeWPs7o7.js → pdf-thumbnail-sidebar-ZybLeUG7.js} +3 -3
  56. package/dist/{pdf-toolbar-BtXcyEpd.js → pdf-toolbar-BM8Sz_JN.js} +4 -4
  57. package/dist/pdf.js +2 -2
  58. package/dist/{print-format.utils-keJqahvw.js → print-format.utils-CQFIVeUA.js} +2 -2
  59. package/dist/{sortable-provider-DMu8DL2z.js → sortable-provider-CKkWYijj.js} +2 -2
  60. package/dist/{stored-language-dtksFoGO.js → stored-language-CvOHC8AD.js} +24 -0
  61. package/dist/{stx-player-nDsDyvc-.js → stx-player-CsVKbwFk.js} +5 -5
  62. package/dist/{translator-DqiGrSH_.js → translator-k1rKIgC7.js} +1 -1
  63. package/dist/{use-heading-spy-BZ7ctGZ5.js → use-heading-spy-D-ipoQwl.js} +1 -1
  64. package/dist/{use-material-translation-DRB6oPdF.js → use-material-translation-1FdRx9I7.js} +3 -3
  65. package/docs/components/README.md +1 -1
  66. package/docs/components/form-fields.md +146 -0
  67. package/docs/components/overlays-and-menus.md +2 -0
  68. package/docs/components/primitives.md +3 -1
  69. package/docs/components/selection-and-choice.md +28 -4
  70. package/docs/guides/forms.md +34 -0
  71. package/docs/previews/form-fields-repeatablegroup.webp +0 -0
  72. package/docs/roadmap.md +7 -0
  73. package/docs/troubleshooting.md +43 -0
  74. package/lib/components/base.css +3 -1
  75. package/lib/nuxt/component-names.ts +2 -0
  76. package/package.json +2 -2
@@ -1,7 +1,7 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { Bf as n } from "./components--v_k8diD.js";
4
- import { t as r } from "./use-material-translation-DRB6oPdF.js";
3
+ import { Hf as n } from "./components-B_s5oxUp.js";
4
+ import { t as r } from "./use-material-translation-1FdRx9I7.js";
5
5
  import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, defineComponent as u, normalizeClass as d, normalizeStyle as f, openBlock as p, ref as m, renderList as h, toDisplayString as g, unref as _, withCtx as v } from "vue";
6
6
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-outline-row.vue?vue&type=script&setup=true&lang.ts
7
7
  var y = {
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { Up as t } from "./components--v_k8diD.js";
2
+ import { Gp as t } from "./components-B_s5oxUp.js";
3
3
  import { computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, defineComponent as s, nextTick as c, normalizeClass as l, normalizeStyle as u, onBeforeUnmount as d, openBlock as f, ref as p, shallowRef as m, unref as h, watch as g } from "vue";
4
4
  import { DEFAULT_PAGE_SIZE as _, escapeHtml as v, findTextMatches as y, highlightItemHtml as b, placeholderSize as x, rotatedSize as S } from "@nxgt/material-core/pdf-viewer";
5
5
  //#region lib/components/ui/media/pdf-viewer/pdf-note-icons.ts
@@ -1,6 +1,6 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
- import { Bf as t } from "./components--v_k8diD.js";
3
- import { t as n } from "./pdf-page-CRt6KXdJ.js";
2
+ import { Hf as t } from "./components-B_s5oxUp.js";
3
+ import { t as n } from "./pdf-page-Ct313mNF.js";
4
4
  import { Fragment as r, createBlock as i, createElementBlock as a, createElementVNode as o, defineComponent as s, openBlock as c, renderList as l, withCtx as u } from "vue";
5
5
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-page-list.vue?vue&type=script&setup=true&lang.ts
6
6
  var d = { class: "flex flex-col items-center gap-4 px-4 py-4" }, f = /*@__PURE__*/ s({
@@ -1,12 +1,12 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { kn as t } from "./components--v_k8diD.js";
3
- import { t as n } from "./use-material-translation-DRB6oPdF.js";
4
- import { t as r } from "./Button-CurFF4Zt.js";
5
- import { o as i } from "./HoverCardTrigger-jCXl6TrX.js";
6
- import { n as a } from "./pdf-page-CRt6KXdJ.js";
7
- import { t as o } from "./pdf-page-list-BgCp5Asx.js";
8
- import { t as s } from "./pdf-sidebar-Cvtuomgp.js";
9
- import { t as c } from "./pdf-toolbar-BtXcyEpd.js";
2
+ import { kn as t } from "./components-B_s5oxUp.js";
3
+ import { t as n } from "./use-material-translation-1FdRx9I7.js";
4
+ import { t as r } from "./Button-5UyKA-x_.js";
5
+ import { o as i } from "./HoverCardTrigger-CmCDiTn8.js";
6
+ import { n as a } from "./pdf-page-Ct313mNF.js";
7
+ import { t as o } from "./pdf-page-list-JrRo2BeU.js";
8
+ import { t as s } from "./pdf-sidebar-Caw9rzU-.js";
9
+ import { t as c } from "./pdf-toolbar-BM8Sz_JN.js";
10
10
  import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, nextTick as _, normalizeClass as v, onBeforeUnmount as y, onMounted as b, openBlock as x, reactive as S, ref as C, shallowRef as w, toDisplayString as T, toRef as E, unref as D, useId as O, watch as k, withCtx as A } from "vue";
11
11
  import { AlertCircle as j, FileX2 as M, KeyRound as N, Loader2 as P } from "@lucide/vue";
12
12
  import { pdfSourceKey as F, toPdfjsParams as I } from "@nxgt/material-core/pdf-source";
@@ -1,8 +1,8 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { t as n } from "./use-material-translation-DRB6oPdF.js";
4
- import { t as r } from "./pdf-outline-sidebar-DJJ-ARco.js";
5
- import { t as i } from "./pdf-thumbnail-sidebar-CeWPs7o7.js";
3
+ import { t as n } from "./use-material-translation-1FdRx9I7.js";
4
+ import { t as r } from "./pdf-outline-sidebar-BsePJlTi.js";
5
+ import { t as i } from "./pdf-thumbnail-sidebar-ZybLeUG7.js";
6
6
  import { createElementBlock as a, createElementVNode as o, createVNode as s, defineComponent as c, normalizeClass as l, openBlock as u, toDisplayString as d, unref as f, useId as p, useTemplateRef as m } from "vue";
7
7
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-sidebar.vue?vue&type=script&setup=true&lang.ts
8
8
  var h = ["aria-label"], g = ["aria-label"], _ = [
@@ -1,8 +1,8 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { Bf as n } from "./components--v_k8diD.js";
4
- import { t as r } from "./use-material-translation-DRB6oPdF.js";
5
- import { t as i } from "./pdf-page-CRt6KXdJ.js";
3
+ import { Hf as n } from "./components-B_s5oxUp.js";
4
+ import { t as r } from "./use-material-translation-1FdRx9I7.js";
5
+ import { t as i } from "./pdf-page-Ct313mNF.js";
6
6
  import { Fragment as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createVNode as l, defineComponent as u, normalizeClass as d, openBlock as f, renderList as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
7
7
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-thumbnail-sidebar.vue?vue&type=script&setup=true&lang.ts
8
8
  var _ = ["aria-label"], v = {
@@ -1,10 +1,10 @@
1
1
  import { n as e } from "./rolldown-runtime-CWhphoD1.js";
2
2
  import { t } from "./utils-CykWQ0iJ.js";
3
- import { t as n } from "./use-material-translation-DRB6oPdF.js";
4
- import { d as r } from "./Button-CurFF4Zt.js";
5
- import { t as i } from "./icon-button-CIUc1bEp.js";
3
+ import { t as n } from "./use-material-translation-1FdRx9I7.js";
4
+ import { d as r } from "./Button-5UyKA-x_.js";
5
+ import { t as i } from "./icon-button-DhqJE6Ej.js";
6
6
  import { a, i as o, n as s, o as c, r as l, t as u } from "./DropdownMenuTrigger-BsuyNVzV.js";
7
- import { o as d } from "./HoverCardTrigger-jCXl6TrX.js";
7
+ import { o as d } from "./HoverCardTrigger-CmCDiTn8.js";
8
8
  import { Fragment as f, computed as p, createBlock as m, createCommentVNode as h, createElementBlock as g, createElementVNode as _, createTextVNode as v, createVNode as y, defineComponent as b, nextTick as x, normalizeClass as S, openBlock as C, ref as w, renderList as T, toDisplayString as E, unref as D, useTemplateRef as O, watch as k, withCtx as A } from "vue";
9
9
  import { ChevronDown as j, ChevronLeft as M, ChevronRight as N, ChevronUp as P, Download as F, Maximize2 as I, Minimize2 as L, Moon as R, Printer as z, RotateCw as B, Search as V, Sidebar as H, ZoomIn as U, ZoomOut as W } from "@lucide/vue";
10
10
  //#region lib/components/ui/media/pdf-viewer/partials/pdf-toolbar-search.vue?vue&type=script&setup=true&lang.ts
package/dist/pdf.js CHANGED
@@ -1,5 +1,5 @@
1
- import { n as e, t } from "./use-material-translation-DRB6oPdF.js";
2
- import { t as n } from "./Button-CurFF4Zt.js";
1
+ import { n as e, t } from "./use-material-translation-1FdRx9I7.js";
2
+ import { t as n } from "./Button-5UyKA-x_.js";
3
3
  import { computed as r, createBlock as i, createTextVNode as a, defineComponent as o, getCurrentInstance as s, nextTick as c, onMounted as l, onScopeDispose as u, openBlock as d, ref as f, renderSlot as p, shallowRef as m, toDisplayString as ee, toValue as h, unref as g, watch as te, withCtx as ne } from "vue";
4
4
  import { contentDisposition as re, pdfBytesResponse as ie, toWebStream as ae } from "@nxgt/material-core/pdf/http";
5
5
  import { badge as oe, dataTable as se, defaultPdfTheme as ce, definePdfDocument as _, divider as v, header as y, heading as b, image as x, keyValue as S, keyValueOf as C, link as w, metric as T, page as E, pageBreak as D, pageNumber as O, pdfDocument as k, resolvePdfColor as A, resolvePdfTheme as j, row as M, section as N, spacer as P, stack as F, table as I, text as L, totals as R } from "@nxgt/material-core/pdf/model";
@@ -1,5 +1,5 @@
1
- import { i as e, r as t, t as n } from "./stored-language-dtksFoGO.js";
2
- import { r } from "./translator-DqiGrSH_.js";
1
+ import { i as e, r as t, t as n } from "./stored-language-CvOHC8AD.js";
2
+ import { r } from "./translator-k1rKIgC7.js";
3
3
  import { t as i } from "./_baseIsEqual-BUD8VQJE.js";
4
4
  import { n as a } from "./number.utils-Bpo9tUaJ.js";
5
5
  import { defineComponent as o, getCurrentInstance as s, h as c, inject as l, provide as u, useId as d } from "vue";
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { t } from "./use-material-translation-DRB6oPdF.js";
3
- import { t as n } from "./icon-button-CIUc1bEp.js";
2
+ import { t } from "./use-material-translation-1FdRx9I7.js";
3
+ import { t as n } from "./icon-button-DhqJE6Ej.js";
4
4
  import { Teleport as r, computed as i, createBlock as a, createCommentVNode as o, createElementBlock as s, createVNode as c, defineComponent as l, inject as u, mergeProps as d, normalizeStyle as f, onUnmounted as p, openBlock as m, provide as h, reactive as g, ref as _, renderSlot as v, toValue as y, unref as b, useAttrs as x, watch as S, watchEffect as C, withCtx as w, withModifiers as T } from "vue";
5
5
  import { GripVertical as E } from "@lucide/vue";
6
6
  import { Primitive as D } from "reka-ui";
@@ -752,6 +752,7 @@ var e = {
752
752
  placeholder: "Search…",
753
753
  empty: "No results"
754
754
  },
755
+ "option-count": { label: "{count, plural, one {result} other {results}}" },
755
756
  autocomplete: {
756
757
  empty: "No option found.",
757
758
  add: "Add \"{query}\"",
@@ -1223,6 +1224,17 @@ var e = {
1223
1224
  saved: "I have saved these codes",
1224
1225
  "saved-required": "Tick the box once your codes are safe",
1225
1226
  done: "Done"
1227
+ },
1228
+ "repeatable-group": {
1229
+ row: "row",
1230
+ add: "Add {label}",
1231
+ remove: "Remove {label} {index}",
1232
+ "move-up": "Move {label} {index} up",
1233
+ "move-down": "Move {label} {index} down",
1234
+ added: "Added {label} {index}",
1235
+ removed: "Removed {label} {index}",
1236
+ moved: "Moved {label} {from} to position {to}",
1237
+ "max-reached": "Maximum reached ({max})"
1226
1238
  }
1227
1239
  } },
1228
1240
  fr: { material: {
@@ -1976,6 +1988,7 @@ var e = {
1976
1988
  placeholder: "Rechercher…",
1977
1989
  empty: "Aucun résultat"
1978
1990
  },
1991
+ "option-count": { label: "{count, plural, one {résultat} other {résultats}}" },
1979
1992
  autocomplete: {
1980
1993
  empty: "Aucune option.",
1981
1994
  add: "Ajouter « {query} »",
@@ -2447,6 +2460,17 @@ var e = {
2447
2460
  saved: "J'ai enregistré ces codes",
2448
2461
  "saved-required": "Cochez la case une fois vos codes en lieu sûr",
2449
2462
  done: "Terminé"
2463
+ },
2464
+ "repeatable-group": {
2465
+ row: "ligne",
2466
+ add: "Ajouter une {label}",
2467
+ remove: "Retirer la {label} {index}",
2468
+ "move-up": "Monter la {label} {index}",
2469
+ "move-down": "Descendre la {label} {index}",
2470
+ added: "Ajout : {label} {index}",
2471
+ removed: "Suppression : {label} {index}",
2472
+ moved: "Déplacement : {label} {from} en position {to}",
2473
+ "max-reached": "Maximum atteint ({max})"
2450
2474
  }
2451
2475
  } }
2452
2476
  }, t = "language", n = "en", r = Object.keys(e);
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { $t as t, Jt as n, Kp as r, Qt as i, Xt as a, Yt as o, en as s, tn as c } from "./components--v_k8diD.js";
3
- import { t as l } from "./use-material-translation-DRB6oPdF.js";
2
+ import { $t as t, Jp as n, Jt as r, Qt as i, Xt as a, Yt as o, en as s, tn as c } from "./components-B_s5oxUp.js";
3
+ import { t as l } from "./use-material-translation-1FdRx9I7.js";
4
4
  import { createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, normalizeClass as _, openBlock as v, toDisplayString as y, unref as b, withCtx as x } from "vue";
5
5
  //#region lib/components/ui/media/stx-player/partials/stx-player-frame.vue?vue&type=script&setup=true&lang.ts
6
6
  var S = ["data-layout", "aria-label"], C = {
@@ -35,17 +35,17 @@ var S = ["data-layout", "aria-label"], C = {
35
35
  key: 1,
36
36
  class: _(b(e)("grid gap-3", a.showQueue && "@min-[768px]:grid-cols-[minmax(0,1fr)_18rem] @min-[768px]:items-stretch"))
37
37
  }, [p("div", { class: _(b(e)("bg-card overflow-hidden rounded border", b(w).current?.kind === "audio" && "flex flex-col gap-4 p-6")) }, [
38
- b(w).current?.kind === "audio" ? (v(), f("div", C, [h(r, { variant: "title-medium" }, {
38
+ b(w).current?.kind === "audio" ? (v(), f("div", C, [h(n, { variant: "title-medium" }, {
39
39
  default: x(() => [m(y(b(w).current.title), 1)]),
40
40
  _: 1
41
- }), b(w).current.artist ? (v(), u(r, {
41
+ }), b(w).current.artist ? (v(), u(n, {
42
42
  key: 0,
43
43
  class: "text-muted-foreground"
44
44
  }, {
45
45
  default: x(() => [m(y(b(w).current.artist) + " " + y(b(w).current.album ? ` · ${b(w).current.album}` : ""), 1)]),
46
46
  _: 1
47
47
  })) : d("", !0)])) : d("", !0),
48
- h(n, null, {
48
+ h(r, null, {
49
49
  default: x(() => [b(w).current?.kind === "audio" ? d("", !0) : (v(), u(s, {
50
50
  key: 0,
51
51
  tone: "overlay"
@@ -1,4 +1,4 @@
1
- import { a as e, i as t, r as n, t as r } from "./stored-language-dtksFoGO.js";
1
+ import { a as e, i as t, r as n, t as r } from "./stored-language-CvOHC8AD.js";
2
2
  import { t as i } from "./get-CTzJAwfc.js";
3
3
  //#region ../../node_modules/@formatjs/fast-memoize/index.js
4
4
  function a(e, t) {
@@ -1,4 +1,4 @@
1
- import { a as e } from "./i18n-provider-B2q6vp6H.js";
1
+ import { a as e } from "./i18n-provider-BEvjls8b.js";
2
2
  import { c as t, d as n, f as r, l as i, r as a, u as o } from "./number.utils-Bpo9tUaJ.js";
3
3
  import { computed as s, getCurrentInstance as c, inject as l, onMounted as u, ref as d, shallowRef as f, toValue as p, watch as m } from "vue";
4
4
  import { injectConfigProviderContext as h } from "reka-ui";
@@ -1,6 +1,6 @@
1
- import "./stored-language-dtksFoGO.js";
2
- import { a as e } from "./i18n-provider-B2q6vp6H.js";
3
- import { i as t, r as n } from "./translator-DqiGrSH_.js";
1
+ import "./stored-language-CvOHC8AD.js";
2
+ import { a as e } from "./i18n-provider-BEvjls8b.js";
3
+ import { i as t, r as n } from "./translator-k1rKIgC7.js";
4
4
  //#region lib/i18n/translate-material.ts
5
5
  function r(e, r, i, a) {
6
6
  if (e) for (let t of /* @__PURE__ */ new Set([e, e.split("-")[0]])) {
@@ -26,7 +26,7 @@ Anything you press that is not a field: buttons, link buttons, copy, load more,
26
26
 
27
27
  ## [Form fields](form-fields.md)
28
28
 
29
- Labelled inputs with a value, each with its form-library wrapper, and the composite values (attributes, contacts, address, opening hours), and the titled sections a long form is laid out in. 25 entries.
29
+ Labelled inputs with a value, each with its form-library wrapper, and the composite values (attributes, contacts, address, opening hours), the titled sections a long form is laid out in, and the rows a user adds and removes. 26 entries.
30
30
 
31
31
  [<img src="../previews/form-fields-textfield.webp" height="72" alt="TextField">](form-fields.md#textfield)
32
32
  [<img src="../previews/form-fields-phonefield.webp" height="72" alt="PhoneField">](form-fields.md#phonefield)
@@ -12,6 +12,7 @@ value type each one writes. Everything is imported from
12
12
  | --- | --- | --- |
13
13
  | <img src="../previews/form-fields-field.webp" width="96" alt=""> | [Field](#field) | Renders the field matching a config `type` |
14
14
  | <img src="../previews/form-fields-formsection.webp" width="96" alt=""> | [FormSection](#formsection) | Titled section of a form, one column on a phone |
15
+ | <img src="../previews/form-fields-repeatablegroup.webp" width="96" alt=""> | [RepeatableGroup](#repeatablegroup) | Rows a user adds, removes and reorders |
15
16
  | <img src="../previews/form-fields-textfield.webp" width="96" alt=""> | [TextField](#textfield) | Labelled input with adornments and helper text |
16
17
  | <img src="../previews/form-fields-textareafield.webp" width="96" alt=""> | [TextareaField](#textareafield) | Labelled textarea with row sizing and a counter |
17
18
  | <img src="../previews/form-fields-emailfield.webp" width="96" alt=""> | [EmailField](#emailfield) | Validates on blur, `mailto:` button |
@@ -171,6 +172,125 @@ semibold, uppercase and muted, set apart from the fields' labels, and reads
171
172
 
172
173
  ---
173
174
 
175
+ ## RepeatableGroup
176
+
177
+ ![RepeatableGroup](../previews/form-fields-repeatablegroup.webp)
178
+
179
+ Rows of fields a user adds, removes and, optionally, reorders — a school
180
+ year's periods, a list of contacts. `RepeatableGroupFormField` wires it to
181
+ vee-validate's `useFieldArray`; each row's fields are your own form wrappers,
182
+ rendered by its `row` slot.
183
+
184
+ ```vue
185
+ <script setup lang="ts">
186
+ import { useForm } from 'vee-validate';
187
+ import {
188
+ Button,
189
+ DateFormField,
190
+ RepeatableGroupFormField,
191
+ TextFormField,
192
+ } from '@nxgt/material-vue/components';
193
+
194
+ type Period = { name: string; start?: Date; end?: Date };
195
+
196
+ const { handleSubmit } = useForm<{ periods: Period[] }>({
197
+ initialValues: { periods: [{ name: 'Term 1' }] },
198
+ });
199
+ const onSubmit = handleSubmit((values) => console.log(values));
200
+ const newRow = (): Period => ({ name: '' });
201
+ </script>
202
+
203
+ <template>
204
+ <form class="form-grid-layout" @submit="onSubmit">
205
+ <div data-slot="form-fields">
206
+ <RepeatableGroupFormField
207
+ name="periods"
208
+ label="Periods"
209
+ row-label="period"
210
+ add-label="Add period"
211
+ :max="6"
212
+ reorderable
213
+ empty-title="No periods yet"
214
+ :new-row="newRow"
215
+ >
216
+ <template #row="{ path }">
217
+ <TextFormField :name="`${path}.name`" label="Name" />
218
+ <DateFormField :name="`${path}.start`" label="Start date" />
219
+ <DateFormField :name="`${path}.end`" label="End date" />
220
+ </template>
221
+ </RepeatableGroupFormField>
222
+ </div>
223
+ <div data-slot="form-actions">
224
+ <Button type="submit">Save</Button>
225
+ </div>
226
+ </form>
227
+ </template>
228
+ ```
229
+
230
+ | Prop / slot | Type | Default | Effect |
231
+ | --- | --- | --- | --- |
232
+ | `name` | `string` | — | the array's path in the form (`RepeatableGroupFormField`) |
233
+ | `new-row` | `() => TRow` | — | the value Add pushes |
234
+ | `#row` | slot | — | one row's fields; its props are `{ field, index, position, path }` (`index` 0-based, `position` 1-based, `path` `${name}[${index}]`) |
235
+ | `label` / `#label` | `string` / slot | — | names the group (the list inside it is not named again) |
236
+ | `row-label` | `string` | `'row'` (translated) | names each row's buttons ("Remove period 2") and the announcements |
237
+ | `add-label` | `string` | `'Add {rowLabel}'` | the Add button's text |
238
+ | `reorderable` | `boolean` | `false` | move up / move down buttons on each row |
239
+ | `max` | `number` | — | at this many rows, Add is disabled and says why |
240
+ | `min` | `number` | — | at this many rows, Remove is disabled |
241
+ | `empty-title`, `empty-description` / `#empty` | `string` / slot | — | an `EmptyState` when there is no row; the slot replaces it |
242
+ | `disabled` | `boolean` | `false` | disables every button |
243
+
244
+ Without a form library, `RepeatableGroup` takes the rows and listens to the
245
+ actions; the move buttons show only with a `@move` listener:
246
+
247
+ ```vue
248
+ <script setup lang="ts">
249
+ import { ref } from 'vue';
250
+ import { RepeatableGroup, TextField } from '@nxgt/material-vue/components';
251
+
252
+ type Guest = { id: string; name: string };
253
+ const guests = ref<Guest[]>([]);
254
+ const add = () => guests.value.push({ id: crypto.randomUUID(), name: '' });
255
+ const remove = (index: number) => guests.value.splice(index, 1);
256
+ </script>
257
+
258
+ <template>
259
+ <RepeatableGroup label="Guests" row-label="guest" :items="guests" @add="add" @remove="remove">
260
+ <template #row="{ item }">
261
+ <TextField v-model="item.name" label="Name" />
262
+ </template>
263
+ </RepeatableGroup>
264
+ </template>
265
+ ```
266
+
267
+ `get-key` defaults to the item's `key`, then its `id`, then the index.
268
+ vee-validate's `useFieldArray` gives each entry a `key`, so
269
+ `RepeatableGroupFormField` needs none; a plain list keyed by `id` needs none
270
+ either. `error` shows an error under the rows.
271
+
272
+ `row-label` is a lower-case noun. The French templates carry the feminine
273
+ article ("Ajouter une ligne", "Retirer la ligne 2"), so a French app passes a
274
+ feminine noun (`row-label="période"`), or overrides `add-label` and the
275
+ `material.repeatable-group.*` keys in its own bundle (`mergeResources`) for a
276
+ masculine one.
277
+
278
+ - **Semantics:** a `role="group"` named by `label`, its rows a list
279
+ (`getAllByRole('listitem')`), each row's icon buttons named after it
280
+ ("Remove period 2", "Move period 2 up").
281
+ - **Focus and announcements:** see
282
+ [Rows a user adds and removes](../guides/forms.md#rows-a-user-adds-and-removes);
283
+ at `max`, Add stays focusable (`aria-disabled`) and is described by
284
+ "Maximum reached (6)".
285
+ - **Errors:** the array's own error (the error at `name`) describes the group;
286
+ each row's fields show their own.
287
+ - **Layout:** one column on a phone, columns of at least 11rem from a container
288
+ width of `@xl`; no inline style.
289
+
290
+ **Storybook:** `Form fields/RepeatableGroup` · **React:** `RepeatableGroup`, `RepeatableGroupFormField`
291
+
292
+ ---
293
+
174
294
  ## TextField
175
295
 
176
296
  ![TextField](../previews/form-fields-textfield.webp)
@@ -513,8 +633,34 @@ const query = ref('');
513
633
  | `@value-change` | `(value: string) => void` | — | the text, debounced when `debounce-ms` is set |
514
634
  | `debounce-ms` | `number` | `0` | delay before `value-change`; `0` emits it on every key |
515
635
  | `loading` | `boolean` | `false` | spinner in the input |
636
+ | `shortcut` | `string` | — | a hint for the key that focuses the field, e.g. `"/"`: a `Kbd` at the end while the field is empty, not loading and not disabled (`aria-hidden`) and `aria-keyshortcuts` on the input. It binds no key; your page listens and calls `focus()` on the component ref (exposed) |
516
637
  | `v-model` | `string` | — | still updated on every key, undebounced |
517
638
 
639
+ The `shortcut` hint binds no key; the page does, and calls the exposed
640
+ `focus()`:
641
+
642
+ ```vue
643
+ <script setup lang="ts">
644
+ import { onMounted, onUnmounted, ref } from 'vue';
645
+ import { SearchField } from '@nxgt/material-vue/components';
646
+
647
+ const searchRef = ref<InstanceType<typeof SearchField> | null>(null);
648
+ const onKey = (event: KeyboardEvent) => {
649
+ const target = event.target as HTMLElement;
650
+ if (event.key === '/' && !target.closest('input, textarea, [contenteditable]')) {
651
+ event.preventDefault();
652
+ searchRef.value?.focus();
653
+ }
654
+ };
655
+ onMounted(() => document.addEventListener('keydown', onKey));
656
+ onUnmounted(() => document.removeEventListener('keydown', onKey));
657
+ </script>
658
+
659
+ <template>
660
+ <SearchField ref="searchRef" shortcut="/" />
661
+ </template>
662
+ ```
663
+
518
664
  **Emits:** `update:modelValue` and `value-change`, both `string`;
519
665
  `SearchFormField` stores `string`.
520
666
  **Form wrapper:** `SearchFormField` — `name` inside a vee-validate form, see
@@ -637,6 +637,8 @@ Parts: `Command`, `CommandDialog`, `CommandInput`, `CommandList`,
637
637
  | Prop | Type | Default | Effect |
638
638
  | --- | --- | --- | --- |
639
639
  | `value` (`CommandItem`) | `string` | — (required) | the item's value, emitted by `@select` and by `Command`'s `v-model` |
640
+ | `checked` (`CommandItem`) | `boolean` | — | sets `aria-checked` and shows a checkbox indicator, for a multi-choice list; reka's `aria-selected` keeps meaning "selected value" (`multiple` is not used) |
641
+ | `multiselectable` (`CommandList`) | `boolean` | — | sets `aria-multiselectable` on the list |
640
642
  | `@select` (`CommandItem`) | `(event) => void` | — | Enter or click on the item; `event.detail.value` is its `value` |
641
643
  | `heading` (`CommandGroup`) | `string` | — | the group's label |
642
644
  | `title` / `description` (`CommandDialog`) | `string` | `"Command Palette"` / `"Search for a command to run..."` (translated) | the dialog's title and description, visually hidden |
@@ -193,14 +193,16 @@ import { Typography } from '@nxgt/material-vue/components';
193
193
  | Prop | Type | Default | Effect |
194
194
  | --- | --- | --- | --- |
195
195
  | `variant` | `'huge-larger' \| 'huge-large' \| 'huge-medium' \| 'huge-small' \| 'headline-larger' \| 'headline-large' \| 'headline-medium' \| 'headline-small' \| 'title-large' \| 'title-medium' \| 'title-small' \| 'body-medium' \| 'body-small' \| 'caption' \| 'normal'` | `'normal'` | size and weight; `caption` is also muted |
196
+ | `tone` | `'default' \| 'muted' \| 'primary' \| 'error'` | `'default'` | text colour: `muted` is `text-muted-foreground`, `primary` is `text-primary`, `error` is `text-error-text`; `default` inherits (a `class` colour still wins) |
196
197
  | `as` | a tag name or a component | `'div'` | the element to render, keeping the variant, e.g. `as="h2"` or `as="span"` |
197
198
  | `asChild` | `boolean` | `false` | merge the classes onto the single child instead of rendering an element |
198
199
 
199
- It renders a `<div>` unless `as` or `asChild` says otherwise:
200
+ It renders a `<div>` unless `as` or `asChild` says otherwise. Use `as="span"` inside a `<button>` or a link, where a `<div>` is invalid HTML. It sets no `overflow`, so it is never a scroll region: text with break points wraps, while an unbreakable string can overflow its box (add `wrap-anywhere` or `min-w-0`; put your own wrapper with `overflow-auto` and `tabindex="0"` around it to scroll):
200
201
 
201
202
  ```vue
202
203
  <Typography as="span" variant="title-small">Inline</Typography>
203
204
  <Typography as-child variant="body-medium"><a href="/docs">Docs</a></Typography>
205
+ <Typography tone="muted" variant="body-medium">Jan 3 to Jan 9</Typography>
204
206
  ```
205
207
 
206
208
  The variants are also exported as `typographyVariants` for use on your own elements. Vue has one more step than React, `huge-larger`.
@@ -463,7 +463,7 @@ const picked = ref<string[]>(['astro']);
463
463
 
464
464
  | Prop | Type | Default | Effect |
465
465
  | --- | --- | --- | --- |
466
- | `options` | `{ value: string; label: string }[]` | — | required; the boxes |
466
+ | `options` | `{ value: string; label: string; count?: number }[]` | — | required; the boxes; `count`: see [option counts](#option-counts). |
467
467
  | `v-model` | `string[]` | `[]` | the checked values; the new list on each toggle |
468
468
  | `orientation` | `'vertical' \| 'horizontal'` | `'horizontal'` | layout |
469
469
  | `label`, `helper-text` | `string` | — | the question and its help or error text, above the boxes |
@@ -487,6 +487,10 @@ stops matching.
487
487
  The `#helper-text` slot replaces the helper text's content (shown only while
488
488
  `helper-text` is set) and stays part of the group's description.
489
489
 
490
+ #### Option counts
491
+
492
+ `count` on an option of `CheckboxGroup`, `RadioGroupField` or `SelectChipField` shows a number after the label, in muted `tabular-nums` text, and joins the accessible name: the number as plain text plus a visually hidden unit word, so the option is named "CE1 24 results" (it starts with the visible label). The unit is the ICU plural `material.option-count.label` (`result` / `results`; `résultat` / `résultats` in French), so override it in your resources for another noun. `0` is a valid count.
493
+
490
494
  **Emits:** `update:modelValue` with `string[]`.
491
495
  **Form wrapper:** `CheckboxGroupFormField` — `name` inside a vee-validate form, see
492
496
  [forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
@@ -524,7 +528,7 @@ React the labelled one is called `RadioGroup`.
524
528
 
525
529
  | Prop | Type | Default | Effect |
526
530
  | --- | --- | --- | --- |
527
- | `options` | `{ value: string; label: string; disabled?: boolean }[]` | — | required; the radios; `disabled` on an option disables only it |
531
+ | `options` | `{ value: string; label: string; disabled?: boolean; count?: number }[]` | — | required; the radios; `disabled` on an option disables only it; `count`: see [option counts](#option-counts). |
528
532
  | `v-model` | `string` | — | the selected `value` |
529
533
  | `orientation` | `'vertical' \| 'horizontal'` | `'horizontal'` | layout |
530
534
  | `label`, `helper-text`, `error`, `disabled` | | — | the field's text and state |
@@ -652,11 +656,31 @@ const picked = ref<string[]>([]);
652
656
  </template>
653
657
  ```
654
658
 
659
+ With icons, counts, and a single choice that stays chosen when pressed again:
660
+
661
+ ```vue
662
+ <script setup lang="ts">
663
+ import { AtomIcon } from '@lucide/vue';
664
+ import { markRaw, ref } from 'vue';
665
+
666
+ const level = ref<string[]>([]);
667
+ const levels = [
668
+ { value: 'ce1', label: 'CE1', count: 24, icon: markRaw(AtomIcon) },
669
+ { value: 'ce2', label: 'CE2', count: 1 },
670
+ ];
671
+ </script>
672
+
673
+ <template>
674
+ <SelectChipField v-model="level" label="Level" :options="levels" :deselectable="false" />
675
+ </template>
676
+ ```
677
+
655
678
  | Prop | Type | Default | Effect |
656
679
  | --- | --- | --- | --- |
657
- | `mode` | `'single' \| 'multiple'` | `'single'` | clicking the selected chip in `single` mode clears it |
680
+ | `mode` | `'single' \| 'multiple'` | `'single'` | clicking the selected chip in `single` mode clears it, unless `deselectable` is `false` |
681
+ | `deselectable` | `boolean` | `true` | `false`: in `single` mode a second press keeps the chosen chip chosen, as a radio group does; another chip still replaces it |
658
682
  | `v-model` | `string[]` | `[]` | the selected values, even in `single` mode |
659
- | `options` | `{ value: string; label: string }[]` | — | required; the chips |
683
+ | `options` | `{ value: string; label: string; icon?: Component; count?: number }[]` | — | required; the chips (`icon`: a component, such as a `@lucide/vue` icon, shown before the label); `count`: see [option counts](#option-counts). |
660
684
  | `label`, `helper-text`, `error`, `disabled` | | — | the field's text and state |
661
685
 
662
686
  **Accessibility:** the chips are toggle buttons in a `role="group"` named by
@@ -619,6 +619,40 @@ const onSubmit = handleSubmit((values) => emit('save', values));
619
619
  `{ [attribute.name]: value }` to its `name`. Its starting values come from
620
620
  its `default-values` prop, not from the form.
621
621
 
622
+ ### Rows a user adds and removes
623
+
624
+ When the rows are fields of their own — a school year's periods, each with a
625
+ name, a start date and an end date — use
626
+ [`RepeatableGroupFormField`](../components/form-fields.md#repeatablegroup)
627
+ over vee-validate's `useFieldArray`, and render each row's fields with the
628
+ form's own wrappers in its `row` slot:
629
+
630
+ ```vue
631
+ <RepeatableGroupFormField
632
+ name="periods"
633
+ label="Periods"
634
+ row-label="period"
635
+ :max="6"
636
+ reorderable
637
+ :new-row="() => ({ name: '' })"
638
+ >
639
+ <template #row="{ path }">
640
+ <TextFormField :name="`${path}.name`" label="Name" />
641
+ <DateFormField :name="`${path}.start`" label="Start date" />
642
+ </template>
643
+ </RepeatableGroupFormField>
644
+ ```
645
+
646
+ - A row's field shows its own error (`periods[1].name`); the array's own
647
+ error (`.min(2)` on the array) shows under the rows and describes the group.
648
+ - The slot's `path` is `periods[1]`, not `name`: a slot's `name` attribute is
649
+ the slot's own.
650
+ - The group moves the focus as rows come and go (an added row's first field,
651
+ a removed row's neighbour or Add, a moved row's move button) and announces each change politely
652
+ ("Added period 3"), after its own buttons only: a row your
653
+ own code pushes leaves the focus where it is
654
+ ([what to do](../troubleshooting.md#the-focus-does-not-move-to-a-new-row-of-a-repeatablegroupformfield)).
655
+
622
656
  ## Config-driven forms
623
657
 
624
658
  `Field` renders the field that matches a config `type`, which is useful when
package/docs/roadmap.md CHANGED
@@ -162,6 +162,13 @@ version they shipped in, and planned entries may name the major they target.
162
162
 
163
163
  ## Shipped
164
164
 
165
+ - **Rows a user adds, removes and reorders** — `RepeatableGroup` and
166
+ `RepeatableGroupFormField` over the form library's field array: rows from
167
+ the `row` slot, a list for assistive tech, Remove and move buttons named after
168
+ the row ("Remove period 2"), `max` and `min`, an empty state, focus that
169
+ follows each change, polite announcements, and the array's own error under
170
+ the rows. One column on a phone. 0.38.0.
171
+
165
172
  - **Signed-out pages and two-step verification** — `AuthCard`, the frame of a
166
173
  sign-in page (one `main`, the card's title its `h1`, a status or alert
167
174
  notice, safe-area padding); `EnrolmentSecret`, a TOTP enrolment's QR code,