@nxgt/material-vue 0.40.1 → 0.41.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 (77) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +1 -1
  3. package/dist/{Button-teS2p_af.js → Button-BG3oDkrl.js} +132 -94
  4. package/dist/{HoverCardTrigger-BEzEsgBo.js → HoverCardTrigger-Dh1ar_W4.js} +2 -2
  5. package/dist/{camera-1QRTmpnM.js → camera-DV9jcl_3.js} +4 -4
  6. package/dist/components/base-content.css +14 -4
  7. package/dist/{components-XJ95qxB1.js → components-C1JYYoQ4.js} +7297 -7245
  8. package/dist/components.js +6 -6
  9. package/dist/composables.js +2 -2
  10. package/dist/dnd.js +1 -1
  11. package/dist/{form-scope-BtEP6yC2.js → form-scope-CeD0v_mw.js} +1 -1
  12. package/dist/{i18n-provider-BpNC9SxV.js → i18n-provider-D5XyLQ3P.js} +1 -1
  13. package/dist/i18n.js +4 -4
  14. package/dist/{icon-button-Vz4NECf1.js → icon-button-DXrmfs6e.js} +43 -5
  15. package/dist/lib/components/ui/actions/button/Button.vue.d.ts +1 -1
  16. package/dist/lib/components/ui/actions/button/button.compound-variants.d.ts +28 -0
  17. package/dist/lib/components/ui/actions/button/button.variants.d.ts +8 -2
  18. package/dist/lib/components/ui/actions/copy-button/copy-button.vue.d.ts +1 -1
  19. package/dist/lib/components/ui/actions/copy-button/use-copy-status.d.ts +3 -1
  20. package/dist/lib/components/ui/actions/icon-button/icon-button.compound-variants.d.ts +28 -0
  21. package/dist/lib/components/ui/actions/icon-button/icon-button.variants.d.ts +8 -2
  22. package/dist/lib/components/ui/actions/icon-button/icon-button.vue.d.ts +1 -1
  23. package/dist/lib/components/ui/actions/link/icon-link-button.vue.d.ts +1 -1
  24. package/dist/lib/components/ui/actions/link/link-button.vue.d.ts +1 -1
  25. package/dist/lib/components/ui/actions/link/responsive-link-button.vue.d.ts +1 -1
  26. package/dist/lib/components/ui/actions/load-more-button/load-more-button.vue.d.ts +1 -1
  27. package/dist/lib/components/ui/actions/scroll-to-top/scroll-to-top.vue.d.ts +1 -1
  28. package/dist/lib/components/ui/display/cards/cards.gallery.d.ts +3 -3
  29. package/dist/lib/components/ui/display/chip/chip.utils.d.ts +1 -1
  30. package/dist/lib/components/ui/display/enrolment-secret/enrolment-secret.vue.d.ts +17 -1
  31. package/dist/lib/components/ui/display/qrcode/qrcode.vue.d.ts +6 -0
  32. package/dist/lib/components/ui/display/recovery-codes/index.d.ts +1 -1
  33. package/dist/lib/components/ui/display/recovery-codes/partials/recovery-codes-actions.vue.d.ts +20 -2
  34. package/dist/lib/components/ui/display/recovery-codes/recovery-codes.vue.d.ts +9 -1
  35. package/dist/lib/components/ui/display/recovery-codes/types.d.ts +4 -0
  36. package/dist/lib/components/ui/display/recovery-codes/use-recovery-codes-labels.d.ts +1 -0
  37. package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
  38. package/dist/lib/components/ui/fields/otp-field/otp-field.vue.d.ts +2 -0
  39. package/dist/lib/components/ui/layout/stepper/stepper.vue.d.ts +7 -2
  40. package/dist/lib/components/ui/media/carousel/carousel-next.vue.d.ts +1 -1
  41. package/dist/lib/components/ui/media/carousel/carousel-previous.vue.d.ts +1 -1
  42. package/dist/lib/components/ui/primitives/input-group/input-group-button.vue.d.ts +1 -1
  43. package/dist/lib/i18n/resources/en/en.d.ts +1 -0
  44. package/dist/lib/i18n/resources/en/material.json.d.ts +1 -0
  45. package/dist/lib/i18n/resources/fr/fr.d.ts +1 -0
  46. package/dist/lib/i18n/resources/fr/material.json.d.ts +3 -2
  47. package/dist/lib/i18n/resources/resources.d.ts +2 -0
  48. package/dist/lib/i18n/translator.d.ts +1 -1
  49. package/dist/lib.js +1 -1
  50. package/dist/main.js +11 -11
  51. package/dist/map.js +4 -4
  52. package/dist/material-vue.css +1 -1
  53. package/dist/{pdf-outline-sidebar-DINCjWKk.js → pdf-outline-sidebar-CgmJjhUz.js} +2 -2
  54. package/dist/{pdf-page-BLJ0xkS3.js → pdf-page-BjQNWV72.js} +1 -1
  55. package/dist/{pdf-page-list-BNUPVA9x.js → pdf-page-list-nG0l4SjH.js} +2 -2
  56. package/dist/{pdf-reader-BcB_Kd_F.js → pdf-reader-Dekd4Ymw.js} +8 -8
  57. package/dist/{pdf-sidebar-B7WgcY77.js → pdf-sidebar-gDj63dRH.js} +3 -3
  58. package/dist/{pdf-thumbnail-sidebar-BRtyyBPt.js → pdf-thumbnail-sidebar-C5ikii1Z.js} +3 -3
  59. package/dist/{pdf-toolbar-_CBHSMnH.js → pdf-toolbar-DmmrSlCq.js} +4 -4
  60. package/dist/pdf.js +2 -2
  61. package/dist/{print-format.utils-k5W0GBRF.js → print-format.utils-CiUiQE-i.js} +2 -2
  62. package/dist/{sortable-provider-Dw9TBAlq.js → sortable-provider-lK0srHJF.js} +2 -2
  63. package/dist/{stored-language-DEyPmUzl.js → stored-language-dM2e5qaS.js} +4 -2
  64. package/dist/{stx-player-CgwzX7_k.js → stx-player-C2VQCXFc.js} +2 -2
  65. package/dist/{translator-B62GlCBp.js → translator-DXL5RDRg.js} +1 -1
  66. package/dist/{use-heading-spy-T94lNeNA.js → use-heading-spy-Btwc0yad.js} +1 -1
  67. package/dist/{use-material-translation-DxU51--g.js → use-material-translation-Du3Wvsk1.js} +3 -3
  68. package/docs/components/buttons-and-actions.md +2 -2
  69. package/docs/components/data-display.md +14 -7
  70. package/docs/components/data-table-filter-and-lists.md +3 -1
  71. package/docs/components/feedback-and-status.md +7 -2
  72. package/docs/components/form-fields.md +2 -1
  73. package/docs/components/navigation-and-layout.md +6 -1
  74. package/docs/guides/forms.md +10 -4
  75. package/docs/troubleshooting.md +31 -0
  76. package/lib/components/base-content.css +14 -4
  77. package/package.json +1 -1
@@ -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 { Lf as n } from "./components-XJ95qxB1.js";
4
- import { t as r } from "./use-material-translation-DxU51--g.js";
3
+ import { Lf as n } from "./components-C1JYYoQ4.js";
4
+ import { t as r } from "./use-material-translation-Du3Wvsk1.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 { Kp as t } from "./components-XJ95qxB1.js";
2
+ import { Kp as t } from "./components-C1JYYoQ4.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 { Lf as t } from "./components-XJ95qxB1.js";
3
- import { t as n } from "./pdf-page-BLJ0xkS3.js";
2
+ import { Lf as t } from "./components-C1JYYoQ4.js";
3
+ import { t as n } from "./pdf-page-BjQNWV72.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-XJ95qxB1.js";
3
- import { t as n } from "./use-material-translation-DxU51--g.js";
4
- import { t as r } from "./Button-teS2p_af.js";
5
- import { o as i } from "./HoverCardTrigger-BEzEsgBo.js";
6
- import { n as a } from "./pdf-page-BLJ0xkS3.js";
7
- import { t as o } from "./pdf-page-list-BNUPVA9x.js";
8
- import { t as s } from "./pdf-sidebar-B7WgcY77.js";
9
- import { t as c } from "./pdf-toolbar-_CBHSMnH.js";
2
+ import { kn as t } from "./components-C1JYYoQ4.js";
3
+ import { t as n } from "./use-material-translation-Du3Wvsk1.js";
4
+ import { t as r } from "./Button-BG3oDkrl.js";
5
+ import { o as i } from "./HoverCardTrigger-Dh1ar_W4.js";
6
+ import { n as a } from "./pdf-page-BjQNWV72.js";
7
+ import { t as o } from "./pdf-page-list-nG0l4SjH.js";
8
+ import { t as s } from "./pdf-sidebar-gDj63dRH.js";
9
+ import { t as c } from "./pdf-toolbar-DmmrSlCq.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-DxU51--g.js";
4
- import { t as r } from "./pdf-outline-sidebar-DINCjWKk.js";
5
- import { t as i } from "./pdf-thumbnail-sidebar-BRtyyBPt.js";
3
+ import { t as n } from "./use-material-translation-Du3Wvsk1.js";
4
+ import { t as r } from "./pdf-outline-sidebar-CgmJjhUz.js";
5
+ import { t as i } from "./pdf-thumbnail-sidebar-C5ikii1Z.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 { Lf as n } from "./components-XJ95qxB1.js";
4
- import { t as r } from "./use-material-translation-DxU51--g.js";
5
- import { t as i } from "./pdf-page-BLJ0xkS3.js";
3
+ import { Lf as n } from "./components-C1JYYoQ4.js";
4
+ import { t as r } from "./use-material-translation-Du3Wvsk1.js";
5
+ import { t as i } from "./pdf-page-BjQNWV72.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-DxU51--g.js";
4
- import { f as r } from "./Button-teS2p_af.js";
5
- import { t as i } from "./icon-button-Vz4NECf1.js";
3
+ import { t as n } from "./use-material-translation-Du3Wvsk1.js";
4
+ import { f as r } from "./Button-BG3oDkrl.js";
5
+ import { t as i } from "./icon-button-DXrmfs6e.js";
6
6
  import { a, i as o, n as s, o as c, r as l, t as u } from "./DropdownMenuTrigger-C7uYPf_9.js";
7
- import { o as d } from "./HoverCardTrigger-BEzEsgBo.js";
7
+ import { o as d } from "./HoverCardTrigger-Dh1ar_W4.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-DxU51--g.js";
2
- import { t as n } from "./Button-teS2p_af.js";
1
+ import { n as e, t } from "./use-material-translation-Du3Wvsk1.js";
2
+ import { t as n } from "./Button-BG3oDkrl.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-DEyPmUzl.js";
2
- import { r } from "./translator-B62GlCBp.js";
1
+ import { i as e, r as t, t as n } from "./stored-language-dM2e5qaS.js";
2
+ import { r } from "./translator-DXL5RDRg.js";
3
3
  import { t as i } from "./_baseIsEqual-BUD8VQJE.js";
4
4
  import { E as a } from "./number.utils-C1eB3GDr.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-DxU51--g.js";
3
- import { t as n } from "./icon-button-Vz4NECf1.js";
2
+ import { t } from "./use-material-translation-Du3Wvsk1.js";
3
+ import { t as n } from "./icon-button-DXrmfs6e.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";
@@ -1226,6 +1226,7 @@ var e = {
1226
1226
  copy: "Copy codes",
1227
1227
  copied: "Codes copied",
1228
1228
  "copy-failed": "Copy failed",
1229
+ "copy-failed-hint": "Download or print the codes instead.",
1229
1230
  download: "Download",
1230
1231
  print: "Print",
1231
1232
  saved: "I have saved these codes",
@@ -1578,8 +1579,8 @@ var e = {
1578
1579
  table: {
1579
1580
  loading: "Chargement des données…",
1580
1581
  labels: {
1581
- asc: "Asc",
1582
- desc: "Desc",
1582
+ asc: "Croissant",
1583
+ desc: "Décroissant",
1583
1584
  hide: "Cacher",
1584
1585
  view: "Voir",
1585
1586
  actions: "Actions",
@@ -2469,6 +2470,7 @@ var e = {
2469
2470
  copy: "Copier les codes",
2470
2471
  copied: "Codes copiés",
2471
2472
  "copy-failed": "Échec de la copie",
2473
+ "copy-failed-hint": "Téléchargez ou imprimez plutôt les codes.",
2472
2474
  download: "Télécharger",
2473
2475
  print: "Imprimer",
2474
2476
  saved: "J'ai enregistré ces codes",
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-CykWQ0iJ.js";
2
- import { $t as t, Jt as n, Qt as r, Xt as i, Yp as a, Yt as o, en as s, tn as c } from "./components-XJ95qxB1.js";
3
- import { t as l } from "./use-material-translation-DxU51--g.js";
2
+ import { $t as t, Jt as n, Qt as r, Xt as i, Yp as a, Yt as o, en as s, tn as c } from "./components-C1JYYoQ4.js";
3
+ import { t as l } from "./use-material-translation-Du3Wvsk1.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 = {
@@ -1,4 +1,4 @@
1
- import { a as e, i as t, r as n, t as r } from "./stored-language-DEyPmUzl.js";
1
+ import { a as e, i as t, r as n, t as r } from "./stored-language-dM2e5qaS.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-BpNC9SxV.js";
1
+ import { a as e } from "./i18n-provider-D5XyLQ3P.js";
2
2
  import { c as t, d as n, l as r, n as i, s as a, u as o } from "./number.utils-C1eB3GDr.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-DEyPmUzl.js";
2
- import { a as e } from "./i18n-provider-BpNC9SxV.js";
3
- import { i as t, r as n } from "./translator-B62GlCBp.js";
1
+ import "./stored-language-dM2e5qaS.js";
2
+ import { a as e } from "./i18n-provider-D5XyLQ3P.js";
3
+ import { i as t, r as n } from "./translator-DXL5RDRg.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]])) {
@@ -52,7 +52,7 @@ function save() {
52
52
  | Prop | Type | Default | Effect |
53
53
  | --- | --- | --- | --- |
54
54
  | `variant` | `'filled' \| 'tonal' \| 'outlined' \| 'ghost' \| 'link'` | `'filled'` | the style |
55
- | `color` | `'primary' \| 'secondary' \| 'success' \| 'info' \| 'warning' \| 'error' \| 'default'` | `'primary'` | the colour; `default` is the foreground colour |
55
+ | `color` | `'primary' \| 'secondary' \| 'success' \| 'info' \| 'warning' \| 'error' \| 'default'` | `'primary'` | the colour; `default` is the foreground colour. A `ghost` button in `secondary`, `success`, `info`, `warning` or `error` takes that colour's text and a tint of it on hover, at 4.5:1 on the page and on a card in both themes; in `primary` or `default` it keeps the foreground text |
56
56
  | `size` | `'default' \| 'xs' \| 'sm' \| 'lg' \| 'icon' \| 'icon-xs' \| 'icon-sm' \| 'icon-lg'` | — (36 px) | height; the `icon*` sizes are square |
57
57
  | `loading` | `boolean` | — | busy: a spinner, `aria-busy="true"` and `aria-disabled="true"`, and every click cancelled before your `@click` — a submit button submits neither on a click nor on Enter in a field. It stays focusable (no native `disabled`), so focus is not lost |
58
58
  | `lock-on-click` | `boolean` | — | a click makes the button busy at once, until `loading` has turned true and back (or for one second when it never does): for a `loading` that turns true only after an `await` |
@@ -148,7 +148,7 @@ import { Pencil, Trash2 } from '@lucide/vue';
148
148
  | Prop | Type | Default | Effect |
149
149
  | --- | --- | --- | --- |
150
150
  | `variant` | `'filled' \| 'tonal' \| 'outlined' \| 'ghost' \| 'link'` | `'filled'` | the style; a round 36 px button |
151
- | `color` | as `Button` | `'primary'` | the colour |
151
+ | `color` | as `Button` | `'primary'` | the colour; a `ghost` one in a colour other than `primary` or `default` draws its icon in it, as `Button` does |
152
152
  | `tooltip` | `string` | — | wraps it in a `Tooltip`; names the button when there is no `aria-label` |
153
153
  | `aria-label` | `string` | the tooltip | the button's accessible name, set on the `<button>`; wins over the tooltip |
154
154
  | `name` | `IconName` | — | renders that [`Icon`](primitives.md#icon) before the slot |
@@ -203,7 +203,7 @@ function remove(id: string) {
203
203
  | `active` | `boolean` | — | filled appearance |
204
204
  | `variant` | Button `variant`, or `'dashed'` | `'outlined'` | appearance when not active; `dashed` is a muted dashed pill (a "+ Field" pill) that turns solid and normal once `active` |
205
205
  | `size` | `'default' \| 'sm'` | `'default'` | `sm` is a compact chip; the ✕ and every target stay at least 24px |
206
- | `color` | Button `color` | — | tone |
206
+ | `color` | Button `color` | — | tone; a `ghost` chip shows it too, as a ghost `Button` does |
207
207
  | `disabled` | `boolean` | — | disables the chip and its ✕ |
208
208
  | `@dismiss` | `() => void` | — | a listener adds the ✕ button, named "Remove {label}" (`material.chip.dismiss-label`), `{label}` being the text the chip shows: the default slot's when given, else `label`; "Remove" when it shows none; the ✕ is a 24px target |
209
209
  | `dismissLabel` | `string \| ((label: string) => string)` | — | names the ✕ instead of "Remove {label}": a string as is, or a function of the text the chip shows |
@@ -898,6 +898,7 @@ import { QRCode } from '@nxgt/material-vue/components';
898
898
  | `size` | `number` | `128` | pixels (React defaults to `256`) |
899
899
  | `level` | `'L' \| 'M' \| 'Q' \| 'H'` | `'L'` | error correction; use `H` with a logo |
900
900
  | `fgColor`, `bgColor` | `string` | `'#000000'`, `'#FFFFFF'` | colours |
901
+ | `quietZone` | `number` | — (a fixed `p-4` tile) | the blank margin around the code, in modules (the QR spec asks for 4): drawn inside the svg (its viewBox widens by `quietZone` modules per side, the tile's `p-4` goes), so it follows the size and the density, and there is no inline `style`; `size` stays the code's own width, the tile grows by the margin |
901
902
  | `title` | `string` | — | accessible label of the SVG |
902
903
  | `aria-label` | `string` | — | the SVG's name too, and wins over `title` |
903
904
  | `#logo` | slot | — | the logo, centred over the code on a white pad (React's `logo`); the default slot still works |
@@ -965,7 +966,9 @@ import { EnrolmentSecret } from '@nxgt/material-vue/components';
965
966
  | `secret` | `string` | — | shown as `JBSW Y3DP EHPK 3PXP`; the copy button copies it without spaces |
966
967
  | `showQrCode` | `boolean` | `true` | `false`: the link and the key alone |
967
968
  | `qrSize` | `number` | `192` | the QR code's size in pixels (it shrinks to fit a narrower box) |
969
+ | `qrQuietZone` | `number` | `4` | the blank margin around the QR code, in modules; the spec asks scanners for 4, which a fixed `p-4` fell short of at larger sizes. The tile's size can differ from before (a 4-module margin instead of 16px) |
968
970
  | `qrLabel`, `openAppLabel`, `manualLabel`, `secretLabel`, `copyLabel`, `copiedLabel` | `string` | translated | the QR code's name, the link, the line before the key, the key's group name, the copy button's name, what it announces |
971
+ | `#copy-icon` | slot | Lucide's copy | replaces the copy button's icon with your app's own, so one icon set shows; a check or a cross still follows a copy |
969
972
 
970
973
  The QR code sits beside the rest once the component is 28rem wide (a
971
974
  container query), above it on a phone. The key is a `<code>` in a
@@ -975,7 +978,7 @@ region; it wraps at the group boundaries, never past the card's edge.
975
978
  `groupSecret(secret, size?)` (from `@nxgt/material-core/two-factor`) is
976
979
  re-exported for a layout of your own.
977
980
 
978
- **Storybook:** `Data display/EnrolmentSecret` · **React:** `EnrolmentSecret`
981
+ **Storybook:** `Data display/EnrolmentSecret` · **React:** `EnrolmentSecret` (`copyIcon`)
979
982
 
980
983
  ---
981
984
 
@@ -1016,12 +1019,16 @@ const saved = ref(false);
1016
1019
  | `focusTitle` | `boolean` | `true` | the heading takes the focus once shown: the codes replaced what the user acted on |
1017
1020
  | `fileName`, `fileHeading`, `fileNote` | `string` | `"recovery-codes.txt"`, the title, the warning | the downloaded file and its first two lines |
1018
1021
  | `onDone` (`@done`) | `() => void` | — | shows "Done", which calls it once the confirmation is ticked |
1022
+ | `@copy` | `(result: 'copied' \| 'failed') => void` | — | fires once "Copy codes" has an outcome, so the app can toast it |
1023
+ | `#copy-icon`, `#download-icon`, `#print-icon` | slots | Lucide's | replace the buttons' icons with your app's own (a Font Awesome `Icon`, say); the copy one still turns into a check or a cross after a copy |
1019
1024
  | `v-model:saved` | `boolean` | uncontrolled | the confirmation |
1020
- | `labels` | `Partial<RecoveryCodesLabels>` | translated | `list`, `copy`, `copied`, `copyFailed`, `download`, `print`, `saved`, `savedRequired`, `done` |
1025
+ | `labels` | `Partial<RecoveryCodesLabels>` | translated | `list`, `copy`, `copied`, `copyFailed`, `copyFailedHint`, `download`, `print`, `saved`, `savedRequired`, `done` |
1021
1026
 
1022
- - **Copy** puts the codes on the clipboard one per line; "Codes copied" (or
1023
- "Copy failed") is announced by the component's own polite status region,
1024
- so it needs no `Toaster`.
1027
+ - **Copy** puts the codes on the clipboard one per line. The outcome is
1028
+ written beside the buttons ("Codes copied", or "Copy failed. Download or
1029
+ print the codes instead.") and the button's icon turns into a check or a
1030
+ cross for a moment (a refusal stays, with its way out, until the next copy, download or print); the same text is the component's polite status region,
1031
+ so it needs no `Toaster`. `@copy` hears `'copied'` or `'failed'` too, to toast it.
1025
1032
  - **Download** saves `recoveryCodesText(codes, { heading, note })` with
1026
1033
  `downloadText` (both re-exported from `@nxgt/material-core/two-factor`).
1027
1034
  - **Print** prints the card and nothing else, with no inline style and no new
@@ -1046,4 +1053,4 @@ useEventListener(window, 'beforeunload', (event) => {
1046
1053
  });
1047
1054
  ```
1048
1055
 
1049
- **Storybook:** `Data display/RecoveryCodes` · **React:** `RecoveryCodes` (`saved` / `onSavedChange`, `onDone`; props for the slots)
1056
+ **Storybook:** `Data display/RecoveryCodes` · **React:** `RecoveryCodes` (`saved` / `onSavedChange`, `onDone`, `onCopy`, `icons`; props for the slots)
@@ -59,7 +59,9 @@ const columns = columnHelper.columns([
59
59
  ```
60
60
 
61
61
  Parts: `DataTable`; `DataTableColumnHeader` (a sortable header with a hide
62
- action); `DataTablePagination`, `DataTableServerFooter` and
62
+ action; the sorted column's header cell carries `aria-sort`, and the
63
+ button keeps the column's title as its name); `DataTablePagination`,
64
+ `DataTableServerFooter` and
63
65
  `DataTableViewOptions` (used by the table, exported for a table or a footer
64
66
  of your own; both footers take `disabled`);
65
67
  `useColumnHelpers<T>()` returns a
@@ -92,7 +92,7 @@ const open = ref(true);
92
92
  | --- | --- | --- | --- |
93
93
  | `tone` | `'info' \| 'success' \| 'warning' \| 'error'` | `'info'` | colours and the default icon |
94
94
  | `#icon` slot | — | the tone's icon | replaces the default icon |
95
- | `#action` slot | — | — | rendered at the end of the banner; under `sm` it drops below the text, in line with it |
95
+ | `#action` slot | — | — | rendered at the end of the banner; under `sm` it drops below the text, in line with it; there a `ghost` or `link` button (a `LinkButton` too, any size) that is the action itself, not wrapped in another element, is pulled back by its own padding, so its label (or leading icon) starts at the text's edge |
96
96
  | `dismissible` | `boolean` | `false` | shows a close button that emits `dismiss`; the banner does not hide itself |
97
97
 
98
98
  Where React shows the close button when `onDismiss` is passed, Vue asks for
@@ -223,7 +223,8 @@ async function remove() {
223
223
 
224
224
  `on-confirm` is a function prop, so `@confirm="fn"` binds it as before and its
225
225
  promise is awaited; a plain `@confirm="open = false"` keeps working. The error
226
- clears when the dialog opens again.
226
+ clears when the dialog opens again. On closing, the focus goes back to what
227
+ opened it — to the menu's trigger when that was a `DropdownMenuItem`.
227
228
 
228
229
  ![ConfirmationDialog](../previews/feedback-status-confirmationdialog.webp)
229
230
 
@@ -590,6 +591,10 @@ async function upload() {
590
591
  | `role` | `'status' \| 'alert'` | none (`toasts.error`: `'alert'`) | live-region role. Toasts are already announced politely by the `Toaster`'s region; `alert` interrupts, and may be read twice by some screen readers |
591
592
  | `options` | vue-sonner `ExternalToast` | `duration: 5000` for presets, `Infinity` for `loading` and for any toast with your own `action` (a preset's fallback "Close" still times out at 5000) unless a `duration` is passed | passed to Sonner (`id`, `duration`, `position`…) |
592
593
 
594
+ A toast's text wraps between words, beside an action and its X too; a word
595
+ longer than the toast (a URL) breaks at its edge instead of pushing the
596
+ action out.
597
+
593
598
  The toast id defaults to the title, so two toasts with the same title
594
599
  replace each other; pass `options: { id }` to show both. `Toaster` wraps
595
600
  vue-sonner's and takes its props (`position`, `expand`, `rich-colors`…), all
@@ -716,13 +716,14 @@ const code = ref('');
716
716
  </script>
717
717
 
718
718
  <template>
719
- <OtpField v-model="code" label="Enter OTP" :length="6" @complete="(value) => console.log(value)" />
719
+ <OtpField v-model="code" label="Enter OTP" :length="6" placeholder="123456" @complete="(value) => console.log(value)" />
720
720
  </template>
721
721
  ```
722
722
 
723
723
  | Prop / event | Type | Default | Effect |
724
724
  | --- | --- | --- | --- |
725
725
  | `length` | `number` | `6` | number of slots, split in two groups |
726
+ | `placeholder` | `string` | — | a format hint, one character per slot (`"123456"`), drawn muted in the empty slots until the first character is typed; also on `InputOTP`, shown by `InputOTPSlot` |
726
727
  | `v-model` | `string` | — | the digits typed so far |
727
728
  | `@complete` | `(value: string) => void` | — | once every slot is filled (from `vue-input-otp`) |
728
729
  | `error` | `boolean` | — | error colour on the slots (`data-invalid` on each); `aria-invalid` goes on the input only, the one element a screen reader reads |
@@ -603,13 +603,18 @@ step has no `icon`, and there is no separate `StepperIndicator`.
603
603
  | `steps` | `{ title; description?; status? }[]` | — | `status`: `'completed' \| 'error' \| 'upcoming'`, else derived from `active` |
604
604
  | `active` | `number` | `0` | current step; its `description` is shown as helper text below, and in a hover tooltip on a decorative info icon |
605
605
  | `@change` | `(index: number) => void` | — | a step was clicked |
606
- | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | vertical from `md` only; phones get the compact bar |
606
+ | `orientation` | `'horizontal' \| 'vertical' \| 'responsive'` | `'horizontal'` | `'vertical'`: a column from `md`, phones get the compact bar. `'responsive'`: every step in a column below `sm` (640px), a row from `sm` |
607
607
  | `name` | `string` | — | the stepper's `data-pw` (`stepper` without it), and the prefix of each step's: `<name>-step-N` instead of `step-N` |
608
608
 
609
609
  Each step is an `<li>` with `data-pw="step-N"` (`<name>-step-N` with `name`),
610
610
  N counted from 0, for tests to select; the current step's button carries
611
611
  `aria-current="step"`, and a completed or failed step is announced as such.
612
612
 
613
+ A server renders the desktop layout (every step, at `provideSSRWidth()` or
614
+ 1024px), as does a hydrating client; a phone switches to the compact bar
615
+ right after hydrating (with `orientation="responsive"`, to the column of every
616
+ step).
617
+
613
618
  **Storybook:** `Navigation & layout/Stepper` · **React:** `Stepper`
614
619
 
615
620
  ---
@@ -315,10 +315,16 @@ shows them right under its fields.
315
315
  `form-actions` gets the same sticky footer.
316
316
  - A focused control or link is scrolled into view clear of the actions and
317
317
  a line of helper text below it (`scroll-margin-bottom` on the fields'
318
- controls: 6rem, plus a dialog's bottom padding, 7.5rem above a
319
- `ConfirmationDialog`'s stacked footer), so a field you tab to is never
320
- hidden behind them (WCAG 2.4.11). It is set on the controls, so it holds
321
- in a scroll box of your own too.
318
+ controls: 6rem, 8rem on a phone, plus a dialog's bottom padding, plus the
319
+ safe-area inset beyond 1rem, 7.5rem above a `ConfirmationDialog`'s stacked
320
+ footer), so a field you tab to is never hidden behind them (WCAG 2.4.11).
321
+ It is set on the controls, so it holds in a scroll box of your own too.
322
+ - The actions pad their bottom for the safe area
323
+ (`max(1rem, env(safe-area-inset-bottom))`): in an installed app with
324
+ `viewport-fit=cover`, they clear the home indicator. The phone default
325
+ (below `sm`, where the buttons share the row) comes from
326
+ `--form-actions-clearance-default`, which is internal: override
327
+ `--form-actions-clearance` instead.
322
328
  - Taller actions (a third button, labels that wrap) or helper text on
323
329
  several lines need more room: raise `--form-actions-clearance` on the
324
330
  form. A dialog whose bottom padding is not the default 1.5rem (`p-0` and
@@ -28,6 +28,7 @@ words in your error.
28
28
  - [A Button's label overflows a card on a phone](#a-buttons-label-overflows-a-card-on-a-phone)
29
29
  - [A dialog or sheet scrolls, or clips a child, after upgrading](#a-dialog-or-sheet-scrolls-or-clips-a-child-after-upgrading)
30
30
  - [A form's fields no longer scroll in their own box after upgrading](#a-forms-fields-no-longer-scroll-in-their-own-box-after-upgrading)
31
+ - [axe reports `target-size` on a control under a form's sticky actions](#axe-reports-target-size-on-a-control-under-a-forms-sticky-actions)
31
32
  - [`JsBarcode is not a function`](#jsbarcode-is-not-a-function)
32
33
  - [A `LinkButton` selected as a `button` stops matching](#a-linkbutton-selected-as-a-button-stops-matching)
33
34
  - [A `Toc`, `Pager`, `SeeAlso` or `ScrollProgress` inside `Doc` selected by `data-slot` stops matching](#a-toc-pager-seealso-or-scrollprogress-inside-doc-selected-by-data-slot-stops-matching)
@@ -190,6 +191,7 @@ words in your error.
190
191
  - [A test's `getByRole('region')` finds more than one region](#a-tests-getbyroleregion-finds-more-than-one-region)
191
192
  - [A `DataTable` toolbar is gone](#a-datatable-toolbar-is-gone)
192
193
  - [axe reports `target-size` on a `DataTable`'s "Select all"](#axe-reports-target-size-on-a-datatables-select-all)
194
+ - [A French test no longer finds the sort menu's "Asc" or "Desc"](#a-french-test-no-longer-finds-the-sort-menus-asc-or-desc)
193
195
 
194
196
  **PDF reader**
195
197
 
@@ -1311,6 +1313,26 @@ actions where they are, make them static:
1311
1313
  An app's own fixed bottom bar or floating action button now sits under the
1312
1314
  sticky actions (`z-index: 10`): give it a z-index above 10 (`class="z-20"`).
1313
1315
 
1316
+ ### axe reports `target-size` on a control under a form's sticky actions
1317
+
1318
+ **When:** since the form's actions stick to the bottom (see above), axe's
1319
+ `target-size` (WCAG 2.5.8) flags a field's control, a link or a button
1320
+ that sits half under the sticky `[data-slot="form-actions"]` bar, wherever
1321
+ the page happens to stop scrolling when the scan runs. The same control passes once scrolled into view.
1322
+ **Why:** axe measures what is visible of a target: the sticky bar covers part
1323
+ of the control, so axe sees a target smaller than 24 by 24 px, or one whose
1324
+ circle meets Cancel or Save. A user scrolls the control out from under the
1325
+ bar; a scan does not.
1326
+ **Fix:** scan with the actions put back in the flow, so nothing covers the
1327
+ fields, and keep the bar's own buttons in the scan:
1328
+
1329
+ ```ts
1330
+ await page.addStyleTag({
1331
+ content: '[data-slot="form-actions"] { position: static !important; }',
1332
+ });
1333
+ await expectAccessible(page);
1334
+ ```
1335
+
1314
1336
  ## Feedback
1315
1337
 
1316
1338
  ### A toast with an action never goes away
@@ -3580,6 +3602,15 @@ page.getByRole('region', { name: 'Invoices' });
3580
3602
  **Why:** axe measures the 16px box itself, not its 24px `::before`, so it asks for a 24px circle around the box clear of every other control. The sort button reaches 12px back into its cell's padding (`-ml-3`), and the `select` cell had no padding after its checkbox: the circle met the button.
3581
3603
  **Fix:** upgrade: the `select` column's checkboxes now keep a 12px margin after them. Drop any axe `exclude` of `thead [data-slot="checkbox-field"]` you kept for it. A `select` column of your own (not `predefinedColumns().select`) needs the same: `me-3` on its checkboxes.
3582
3604
 
3605
+ ### A French test no longer finds the sort menu's "Asc" or "Desc"
3606
+
3607
+ **When:** after upgrading, a test running in French clicks the
3608
+ `DataTableColumnHeader` menu item "Asc" or "Desc" and finds nothing.
3609
+ **Why:** `material.table.labels.asc` / `desc` are now translated in French,
3610
+ "Croissant" / "Décroissant" (#612); English keeps "Asc" / "Desc".
3611
+ **Fix:** look for `getByRole('menuitem', { name: 'Croissant' })` (or
3612
+ `'Décroissant'`) in French.
3613
+
3583
3614
  ---
3584
3615
 
3585
3616
  ---
@@ -139,13 +139,23 @@
139
139
  [contenteditable]
140
140
  ) {
141
141
  scroll-margin-bottom: calc(
142
- var(--form-actions-clearance, 6rem) +
143
- var(--form-actions-fill, 0px)
142
+ var(
143
+ --form-actions-clearance,
144
+ var(--form-actions-clearance-default, 6rem)
145
+ ) +
146
+ var(--form-actions-fill, 0px) +
147
+ max(0px, calc(env(safe-area-inset-bottom, 0px) - 1rem))
144
148
  );
145
149
  }
146
- /* Sticky at the bottom of whatever scrolls the form: in reach. */
150
+ /* A phone's actions wrap their labels over two lines and a field has an
151
+ error line: 8rem covers both (`--form-actions-clearance` still wins). */
152
+ @variant max-sm {
153
+ --form-actions-clearance-default: 8rem;
154
+ }
155
+ /* Sticky at the bottom of whatever scrolls the form: in reach. Padded
156
+ for the safe area (`viewport-fit=cover`: the home indicator). */
147
157
  [data-slot="form-actions"] {
148
- @apply sticky bottom-0 z-10 flex w-full justify-end gap-2 bg-background/90 p-4 backdrop-blur-sm max-sm:*:flex-1;
158
+ @apply sticky bottom-0 z-10 flex w-full justify-end gap-2 bg-background/90 p-4 pb-[max(1rem,env(safe-area-inset-bottom))] backdrop-blur-sm max-sm:*:flex-1;
149
159
  }
150
160
  }
151
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material-vue",
3
- "version": "0.40.1",
3
+ "version": "0.41.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"