@nxgt/material-vue 0.32.0 → 0.34.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 (74) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +19 -6
  3. package/dist/{camera-DlWK0PLP.js → camera-C52IuvMH.js} +1 -1
  4. package/dist/components/components.css +3 -1
  5. package/dist/components/ui/fields/otp-field/input-otp.css +48 -0
  6. package/dist/{components-Dqg7KwA2.js → components-DFEmacXJ.js} +12895 -16816
  7. package/dist/components.js +8 -8
  8. package/dist/composables.js +24 -24
  9. package/dist/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
  10. package/dist/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
  11. package/dist/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
  12. package/dist/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
  13. package/dist/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
  14. package/dist/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
  15. package/dist/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
  16. package/dist/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
  17. package/dist/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
  18. package/dist/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
  19. package/dist/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
  20. package/dist/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
  21. package/dist/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
  22. package/dist/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
  23. package/dist/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
  24. package/dist/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
  25. package/dist/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
  26. package/dist/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
  27. package/dist/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
  28. package/dist/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
  29. package/dist/{form-scope-btEYYnGW.js → form-scope-CaYs-o2w.js} +1 -1
  30. package/dist/lib/components/ui/fields/attributes/form-schema.d.ts +11 -2
  31. package/dist/lib/components/ui/fields/opening-hours/consts.d.ts +12 -1
  32. package/dist/lib/components/ui/primitives/index.d.ts +1 -0
  33. package/dist/lib/components/ui/primitives/nonce-provider/index.d.ts +2 -0
  34. package/dist/lib/components/ui/primitives/nonce-provider/nonce-provider.vue.d.ts +20 -0
  35. package/dist/lib/components/ui/primitives/typography/typography.vue.d.ts +7 -4
  36. package/dist/lib/composables/index.d.ts +1 -0
  37. package/dist/lib/composables/use-csp-nonce.d.ts +18 -0
  38. package/dist/lib/lib/index.d.ts +1 -0
  39. package/dist/lib/nuxt/auto-imports.d.ts +1 -1
  40. package/dist/lib/nuxt/component-names.d.ts +1 -1
  41. package/dist/lib/vite/index.d.ts +3 -2
  42. package/dist/lib.js +49 -48
  43. package/dist/main.js +17 -17
  44. package/dist/material-vue.css +1 -1
  45. package/dist/{number.utils-Cy1z6qI7.js → number.utils-Bpo9tUaJ.js} +20 -20
  46. package/dist/{pdf-outline-sidebar-DchMD-_k.js → pdf-outline-sidebar-C_iJ8gqD.js} +1 -1
  47. package/dist/{pdf-page-D-kDQq5h.js → pdf-page-DOiJlWQn.js} +1 -1
  48. package/dist/{pdf-page-list-Cta0S89W.js → pdf-page-list-BTmUd7Ga.js} +2 -2
  49. package/dist/{pdf-reader-BwWozoIQ.js → pdf-reader-CEMMLJnB.js} +48 -45
  50. package/dist/{pdf-sidebar-B0Addf1P.js → pdf-sidebar-KLd76E5S.js} +2 -2
  51. package/dist/{pdf-thumbnail-sidebar-Dsptq4fb.js → pdf-thumbnail-sidebar-B4JkT_LV.js} +2 -2
  52. package/dist/{print-format.utils-DwJfU1tK.js → print-format.utils-DpBtUJvL.js} +1 -1
  53. package/dist/{stx-player-Bpnir1KO.js → stx-player-B6-PSgzP.js} +13 -13
  54. package/dist/{use-heading-spy-Czi_Xv3u.js → use-heading-spy-ClhUg50z.js} +54 -46
  55. package/dist/vite.js +2 -2
  56. package/docs/README.md +1 -0
  57. package/docs/components/data-display.md +5 -0
  58. package/docs/components/date-and-time.md +6 -0
  59. package/docs/components/feedback-and-status.md +3 -1
  60. package/docs/components/form-fields.md +23 -0
  61. package/docs/components/primitives.md +51 -2
  62. package/docs/getting-started.md +5 -1
  63. package/docs/guides/csp.md +420 -0
  64. package/docs/guides/helpers.md +2 -0
  65. package/docs/guides/i18n.md +2 -0
  66. package/docs/guides/theming.md +27 -0
  67. package/docs/roadmap.md +17 -0
  68. package/docs/troubleshooting.md +161 -0
  69. package/lib/components/components.css +3 -1
  70. package/lib/components/ui/fields/otp-field/input-otp.css +48 -0
  71. package/lib/nuxt/auto-imports.ts +1 -0
  72. package/lib/nuxt/component-names.ts +1 -0
  73. package/lib/vite/index.ts +6 -2
  74. package/package.json +4 -4
@@ -1,28 +1,29 @@
1
1
  import { a as e } from "./i18n-provider-CiVi05fs.js";
2
- import { c as t, d as n, f as r, l as i, n as a, u as o } from "./number.utils-Cy1z6qI7.js";
3
- import { computed as s, getCurrentInstance as c, onMounted as l, ref as u, toValue as d } from "vue";
4
- import { useIntersectionObserver as f, useMediaQuery as p, useSSRWidth as m, useStorage as h } from "@vueuse/core";
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
+ import { computed as s, getCurrentInstance as c, inject as l, onMounted as u, ref as d, toValue as f } from "vue";
4
+ import { injectConfigProviderContext as p } from "reka-ui";
5
+ import { useIntersectionObserver as m, useMediaQuery as h, useSSRWidth as g, useStorage as _ } from "@vueuse/core";
5
6
  //#region lib/composables/resolve-theme.ts
6
- function g(e, t) {
7
+ function v(e, t) {
7
8
  let n = e === "light" || e === "dark" ? e : "system";
8
9
  return {
9
10
  theme: n === "system" ? t ? "dark" : "light" : n,
10
11
  preference: n
11
12
  };
12
13
  }
13
- function _(e) {
14
+ function y(e) {
14
15
  typeof document > "u" || (document.documentElement.classList.toggle("dark", e === "dark"), document.documentElement.style.colorScheme = e);
15
16
  }
16
17
  //#endregion
17
18
  //#region lib/composables/use-ssr-media-query.ts
18
- var v = 1024;
19
- function y(e) {
20
- return c() ? p(e, { ssrWidth: m() ?? v }) : p(e);
19
+ var b = 1024;
20
+ function x(e) {
21
+ return c() ? h(e, { ssrWidth: g() ?? b }) : h(e);
21
22
  }
22
23
  //#endregion
23
24
  //#region lib/composables/use-theme.ts
24
- function b() {
25
- let e = y("(prefers-color-scheme: dark)"), t = h("theme", null, void 0, { initOnMounted: !0 }), n = s(() => g(t.value, !!e.value));
25
+ function S() {
26
+ let e = x("(prefers-color-scheme: dark)"), t = _("theme", null, void 0, { initOnMounted: !0 }), n = s(() => v(t.value, !!e.value));
26
27
  return {
27
28
  get theme() {
28
29
  return n.value.theme;
@@ -31,19 +32,19 @@ function b() {
31
32
  return n.value.preference;
32
33
  },
33
34
  updateTheme: (n) => {
34
- n === "system" ? t.value = null : t.value = n, _(g(n === "system" ? void 0 : n, !!e.value).theme);
35
+ n === "system" ? t.value = null : t.value = n, y(v(n === "system" ? void 0 : n, !!e.value).theme);
35
36
  }
36
37
  };
37
38
  }
38
39
  //#endregion
39
40
  //#region lib/composables/use-mobile.ts
40
- var x = 768;
41
- function S() {
42
- return y(`(max-width: ${x - 1}px)`);
41
+ var C = 768;
42
+ function w() {
43
+ return x(`(max-width: ${C - 1}px)`);
43
44
  }
44
45
  //#endregion
45
46
  //#region ../../node_modules/date-fns/locale/fr/_lib/formatDistance.js
46
- var C = {
47
+ var T = {
47
48
  lessThanXSeconds: {
48
49
  one: "moins d’une seconde",
49
50
  other: "moins de {{count}} secondes"
@@ -105,10 +106,10 @@ var C = {
105
106
  one: "presqu’un an",
106
107
  other: "presque {{count}} ans"
107
108
  }
108
- }, w = (e, t, n) => {
109
- let r, i = C[e];
109
+ }, E = (e, t, n) => {
110
+ let r, i = T[e];
110
111
  return r = typeof i == "string" ? i : t === 1 ? i.one : i.other.replace("{{count}}", String(t)), n?.addSuffix ? n.comparison && n.comparison > 0 ? "dans " + r : "il y a " + r : r;
111
- }, T = {
112
+ }, D = {
112
113
  date: r({
113
114
  formats: {
114
115
  full: "EEEE d MMMM y",
@@ -136,18 +137,18 @@ var C = {
136
137
  },
137
138
  defaultWidth: "full"
138
139
  })
139
- }, E = {
140
+ }, O = {
140
141
  lastWeek: "eeee 'dernier à' p",
141
142
  yesterday: "'hier à' p",
142
143
  today: "'aujourd’hui à' p",
143
144
  tomorrow: "'demain à' p'",
144
145
  nextWeek: "eeee 'prochain à' p",
145
146
  other: "P"
146
- }, D = (e, t, n, r) => E[e], O = {
147
+ }, k = (e, t, n, r) => O[e], A = {
147
148
  narrow: ["av. J.-C", "ap. J.-C"],
148
149
  abbreviated: ["av. J.-C", "ap. J.-C"],
149
150
  wide: ["avant Jésus-Christ", "après Jésus-Christ"]
150
- }, k = {
151
+ }, j = {
151
152
  narrow: [
152
153
  "T1",
153
154
  "T2",
@@ -166,7 +167,7 @@ var C = {
166
167
  "3ème trimestre",
167
168
  "4ème trimestre"
168
169
  ]
169
- }, A = {
170
+ }, M = {
170
171
  narrow: [
171
172
  "J",
172
173
  "F",
@@ -209,7 +210,7 @@ var C = {
209
210
  "novembre",
210
211
  "décembre"
211
212
  ]
212
- }, j = {
213
+ }, N = {
213
214
  narrow: [
214
215
  "D",
215
216
  "L",
@@ -246,7 +247,7 @@ var C = {
246
247
  "vendredi",
247
248
  "samedi"
248
249
  ]
249
- }, M = {
250
+ }, P = {
250
251
  narrow: {
251
252
  am: "AM",
252
253
  pm: "PM",
@@ -277,7 +278,7 @@ var C = {
277
278
  evening: "du soir",
278
279
  night: "du matin"
279
280
  }
280
- }, N = (e, t) => {
281
+ }, F = (e, t) => {
281
282
  let n = Number(e), r = t?.unit;
282
283
  if (n === 0) return "0";
283
284
  let i = [
@@ -288,38 +289,38 @@ var C = {
288
289
  "second"
289
290
  ], a;
290
291
  return a = n === 1 ? r && i.includes(r) ? "ère" : "er" : "ème", n + a;
291
- }, P = ["MMM", "MMMM"], F = {
292
+ }, I = ["MMM", "MMMM"], L = {
292
293
  en: t,
293
294
  fr: {
294
295
  code: "fr",
295
- formatDistance: w,
296
- formatLong: T,
297
- formatRelative: D,
296
+ formatDistance: E,
297
+ formatLong: D,
298
+ formatRelative: k,
298
299
  localize: {
299
- preprocessor: (e, t) => e.getDate() === 1 || !t.some((e) => e.isToken && P.includes(e.value)) ? t : t.map((e) => e.isToken && e.value === "do" ? {
300
+ preprocessor: (e, t) => e.getDate() === 1 || !t.some((e) => e.isToken && I.includes(e.value)) ? t : t.map((e) => e.isToken && e.value === "do" ? {
300
301
  isToken: !0,
301
302
  value: "d"
302
303
  } : e),
303
- ordinalNumber: N,
304
+ ordinalNumber: F,
304
305
  era: n({
305
- values: O,
306
+ values: A,
306
307
  defaultWidth: "wide"
307
308
  }),
308
309
  quarter: n({
309
- values: k,
310
+ values: j,
310
311
  defaultWidth: "wide",
311
312
  argumentCallback: (e) => e - 1
312
313
  }),
313
314
  month: n({
314
- values: A,
315
+ values: M,
315
316
  defaultWidth: "wide"
316
317
  }),
317
318
  day: n({
318
- values: j,
319
+ values: N,
319
320
  defaultWidth: "wide"
320
321
  }),
321
322
  dayPeriod: n({
322
- values: M,
323
+ values: P,
323
324
  defaultWidth: "wide"
324
325
  })
325
326
  },
@@ -449,8 +450,8 @@ var C = {
449
450
  }
450
451
  }
451
452
  };
452
- function I() {
453
- let n = e(), r = s(() => n?.language ?? "en"), i = s(() => F[r.value] ?? t);
453
+ function R() {
454
+ let n = e(), r = s(() => n?.language ?? "en"), i = s(() => L[r.value] ?? t);
454
455
  return {
455
456
  get language() {
456
457
  return r.value;
@@ -462,19 +463,26 @@ function I() {
462
463
  };
463
464
  }
464
465
  //#endregion
466
+ //#region lib/composables/use-csp-nonce.ts
467
+ var z = Symbol("nxgt-csp-nonce"), B = Symbol("nxgt-csp-nonce-depth");
468
+ function V() {
469
+ let e = l(z, null), t = p(null);
470
+ return s(() => e?.value || t?.nonce?.value || void 0);
471
+ }
472
+ //#endregion
465
473
  //#region lib/composables/use-heading-spy.ts
466
- var L = "0px 0px -65% 0px", R = [0, 1];
467
- function z(e, t, n) {
468
- let r = u(!1);
469
- l(() => {
474
+ var H = "0px 0px -65% 0px", U = [0, 1];
475
+ function W(e, t, n) {
476
+ let r = d(!1);
477
+ u(() => {
470
478
  r.value = !0;
471
- }), f(s(() => r.value ? d(e).map((e) => document.getElementById(e)).filter((e) => e != null) : []), (e) => {
479
+ }), m(s(() => r.value ? f(e).map((e) => document.getElementById(e)).filter((e) => e != null) : []), (e) => {
472
480
  let n = e.filter((e) => e.isIntersecting).sort((e, t) => e.boundingClientRect.top - t.boundingClientRect.top)[0]?.target.id;
473
481
  n && t(n);
474
482
  }, {
475
- rootMargin: n?.rootMargin ?? L,
476
- threshold: n?.threshold ?? R
483
+ rootMargin: n?.rootMargin ?? H,
484
+ threshold: n?.threshold ?? U
477
485
  });
478
486
  }
479
487
  //#endregion
480
- export { y as a, b as i, I as n, _ as o, S as r, g as s, z as t };
488
+ export { R as a, x as c, V as i, y as l, B as n, w as o, z as r, S as s, W as t, v as u };
package/dist/vite.js CHANGED
@@ -1,2 +1,2 @@
1
- import { pdfkitStandardFonts as e } from "@nxgt/material-core/vite";
2
- export { e as pdfkitStandardFonts };
1
+ import { cspAssetsInlineLimit as e, pdfkitStandardFonts as t } from "@nxgt/material-core/vite";
2
+ export { e as cspAssetsInlineLimit, t as pdfkitStandardFonts };
package/docs/README.md CHANGED
@@ -15,6 +15,7 @@ detail: every option, the second example, and the traps.
15
15
  | [PDF documents](guides/pdf.md) | You produce a PDF file from data with `@nxgt/material-vue/pdf`: in the browser (`usePdf`, `PdfDownloadButton`) or from a Nuxt server route (`pdfResponse`), fonts on an inlined server |
16
16
  | [Maps](guides/maps.md) | You render Leaflet maps or a location field with `@nxgt/material-vue/map` |
17
17
  | [SSR](guides/ssr.md) | Your app renders on a server — Nuxt or a Vite SSR server — and bundles this package |
18
+ | [Content Security Policy](guides/csp.md) | Your app sends a strict CSP: the directives to use, the components that still inject a `<style>`, the zod and KaTeX settings, self-hosting a font, the per-request nonce |
18
19
  | [Helpers](guides/helpers.md) | You need a utility, composable, Pinia store factory or type from `/lib`, `/composables`, `/i18n`, `/models`, `/types` or `/dnd` |
19
20
  | [Troubleshooting](troubleshooting.md) | Something failed and you have an error message or a symptom |
20
21
  | [Roadmap](roadmap.md) | You want to know what is planned, what shipped, and what will not be done |
@@ -706,6 +706,11 @@ left alone. Mermaid diagrams
706
706
  render in the browser only, after mount; on the server the fence is left
707
707
  empty.
708
708
 
709
+ Math needs no import of its own: KaTeX's CSS is in the stylesheet, and its
710
+ fonts are files the stylesheet loads (`dist/fonts/katex/` on the compiled
711
+ route), allowed by `font-src 'self'`. Math in system fonts means the fonts
712
+ were not served ([troubleshooting](../troubleshooting.md#math-renders-in-the-system-fonts)).
713
+
709
714
  `MermaidDiagram` renders one chart outside markdown, the same way: client-only,
710
715
  with `mermaid` imported on mount.
711
716
 
@@ -101,6 +101,8 @@ No form wrapper — use `DateFormField`.
101
101
 
102
102
  Labelled trigger that opens a calendar popover, with an optional time picker and `disabled-days`.
103
103
 
104
+ The trigger writes the date in the `I18nProvider` language, else English.
105
+
104
106
  ```vue
105
107
  <script setup lang="ts">
106
108
  import { ref } from 'vue';
@@ -159,6 +161,8 @@ before your `aria-describedby` ids.
159
161
 
160
162
  From / to range picked in a popover calendar, with `disabled-days`, presets and times.
161
163
 
164
+ The trigger writes each date in the `I18nProvider` language, else English.
165
+
162
166
  ```vue
163
167
  <script setup lang="ts">
164
168
  import { ref } from 'vue';
@@ -304,6 +308,8 @@ where `to` stays `undefined` until the second day is picked.
304
308
 
305
309
  Opens a `TimePicker` in a popover, or in a dialog on mobile.
306
310
 
311
+ The trigger writes the time in the `I18nProvider` language, else English.
312
+
307
313
  ```vue
308
314
  <script setup lang="ts">
309
315
  import { ref } from 'vue';
@@ -432,9 +432,11 @@ function clearFilters() {}
432
432
  | --- | --- | --- | --- |
433
433
  | `variant` | `'not-found' \| 'unauthorized' \| 'generic' \| 'empty' \| 'offline' \| 'search' \| 'maintenance'` | `'generic'` | preset icon, well colour, title and description |
434
434
  | `#icon` slot | — | the preset's | replaces the icon |
435
- | `title` / `description` | `string` (or `#title` / `#description`) | the preset's (translated) | replace the preset text |
435
+ | `title` / `description` | `string` (or `#title` / `#description`) | the preset's (translated) | replace the preset text; see below |
436
436
  | `#action` slot | — | — | shown under the text |
437
437
 
438
+ The preset's description is the companion of its title: with your own `title` and no `description`, no description is rendered. Pass `description` to keep a line under your own title. A `#title` slot counts as your own title; a `#description` slot always renders.
439
+
438
440
  **Storybook:** `Feedback & status/EmptyState` · **React:** `EmptyState`
439
441
 
440
442
  ---
@@ -499,6 +499,7 @@ const code = ref('');
499
499
  | `v-model` | `string` | — | the digits typed so far |
500
500
  | `@complete` | `(value: string) => void` | — | once every slot is filled (from `vue-input-otp`) |
501
501
  | `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 |
502
+ | `nonce` | `string` | the `NonceProvider`'s | the CSP nonce of the `<style>` `vue-input-otp` injects; an explicit one wins (passed down to `InputOTP`, [CSP](../guides/csp.md)) |
502
503
  | `id` | `string` | from `useId()` | the input's id, which the label points to; it differs per field — `OtpFormField` too (not the field `name`), so two code forms on one page each keep their name |
503
504
 
504
505
  `InputOTP`, `InputOTPGroup`, `InputOTPSlot` and `InputOTPSeparator` are the
@@ -891,6 +892,16 @@ attribute), `AttributeValuesForm` (fill values for a set of attributes).
891
892
  Form wrappers: `AttributesFormField` (the definitions),
892
893
  `AttributeValuesFormFieldSet` and `AttributeValueFormField` (the values).
893
894
  Add and edit confirmations use a toast, so mount a `Toaster` once in the app.
895
+ `attributeFormSchema()` returns `AttributeForm`'s zod schema, built on the
896
+ first call (in the form's setup), and `toAttributeFormSchema()` the same as
897
+ vee-validate's typed schema; the `schema` constant is **deprecated** and
898
+ removed in 1.0 ([CSP](../guides/csp.md#zod-and-unsafe-eval)).
899
+
900
+ ```ts
901
+ import { attributeFormSchema } from '@nxgt/material-vue/components';
902
+
903
+ const result = attributeFormSchema().safeParse({ label: 'Color', name: 'color', type: 'COLOR' });
904
+ ```
894
905
 
895
906
  | Prop | Type | Default | Effect |
896
907
  | --- | --- | --- | --- |
@@ -1046,6 +1057,18 @@ function onEdit(value: OpeningHour, index: number) {}
1046
1057
  Parts: `OpeningHours` (the list) and `OpeningHoursDialog` (add / edit).
1047
1058
  `OpeningHoursItem`, a day row bound to a vee-validate array, is
1048
1059
  **deprecated** and removed in 1.0: use `OpeningHoursFormField`.
1060
+ `openingHoursSchema()` returns the zod schema of one `OpeningHour`
1061
+ (`dayOfWeek` coerced from a string), built on the first call; the
1062
+ `OpeningHoursSchema` constant is **deprecated** and removed in 1.0. Under a
1063
+ strict CSP, call `z.config({ jitless: true })` first: see
1064
+ [CSP](../guides/csp.md#zod-and-unsafe-eval).
1065
+
1066
+ ```ts
1067
+ import { openingHoursSchema } from '@nxgt/material-vue/components';
1068
+ import { z } from 'zod';
1069
+
1070
+ const schema = z.object({ hours: z.array(openingHoursSchema()) });
1071
+ ```
1049
1072
 
1050
1073
  | Prop | Type | Default | Effect |
1051
1074
  | --- | --- | --- | --- |
@@ -29,6 +29,7 @@ work on them unchanged.
29
29
  | <img src="../previews/primitives-togglegroup.webp" width="96" alt=""> | [ToggleGroup](#togglegroup) | Single or multiple toggle group |
30
30
  | <img src="../previews/primitives-activity.webp" width="96" alt=""> | [Activity](#activity) | Keeps its content mounted and hides it with a boolean |
31
31
  | <img src="../previews/primitives-scrollarea.webp" width="96" alt=""> | [ScrollArea](#scrollarea) | Scroll container with a thin custom scrollbar |
32
+ | | [NonceProvider](#nonceprovider) | Gives the page's CSP nonce to every component below |
32
33
 
33
34
  ## Accordion
34
35
 
@@ -192,9 +193,17 @@ import { Typography } from '@nxgt/material-vue/components';
192
193
  | Prop | Type | Default | Effect |
193
194
  | --- | --- | --- | --- |
194
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
+ | `as` | a tag name or a component | `'div'` | the element to render, keeping the variant, e.g. `as="h2"` or `as="span"` |
197
+ | `asChild` | `boolean` | `false` | merge the classes onto the single child instead of rendering an element |
195
198
 
196
- It renders a `<div>`; the variants are also exported as `typographyVariants`
197
- for use on your own elements. Vue has one more step than React, `huge-larger`.
199
+ It renders a `<div>` unless `as` or `asChild` says otherwise:
200
+
201
+ ```vue
202
+ <Typography as="span" variant="title-small">Inline</Typography>
203
+ <Typography as-child variant="body-medium"><a href="/docs">Docs</a></Typography>
204
+ ```
205
+
206
+ The variants are also exported as `typographyVariants` for use on your own elements. Vue has one more step than React, `huge-larger`.
198
207
 
199
208
  **Storybook:** `Primitives/Typography` · **React:** `Typography`
200
209
 
@@ -859,3 +868,43 @@ through.
859
868
  The React `ScrollArea` takes the same props, camel-cased (`scrollHideDelay`).
860
869
 
861
870
  **Storybook:** `Primitives/ScrollArea` · **React:** `ScrollArea`, `ScrollBar`
871
+
872
+ ---
873
+
874
+ ## NonceProvider
875
+
876
+ No preview: it draws nothing of its own, it hands the page's Content Security
877
+ Policy nonce down.
878
+
879
+ Gives this request's CSP nonce to every component below it: reka's `Select`,
880
+ `Combobox`, `ScrollArea` and `Splitter` (it renders a reka `ConfigProvider`
881
+ with `nonce`, carrying over a parent `ConfigProvider`'s other settings),
882
+ `InputOTP` when it has no `nonce` of its own, and the stylesheet tiptap
883
+ injects for `RichTextEditor`. Render it once, at the root, on the server and
884
+ on the client, with the same nonce. The Nuxt module registers it.
885
+
886
+ ```vue
887
+ <script setup lang="ts">
888
+ import { NonceProvider } from '@nxgt/material-vue/components';
889
+
890
+ defineProps<{ nonce?: string }>();
891
+ </script>
892
+
893
+ <template>
894
+ <NonceProvider :nonce="nonce">
895
+ <RouterView />
896
+ </NonceProvider>
897
+ </template>
898
+ ```
899
+
900
+ | Prop | Type | Default | Effect |
901
+ | --- | --- | --- | --- |
902
+ | `nonce` | `string` | `undefined` | the nonce of the page's `style-src-elem 'nonce-…'`; `undefined` or `''` inherits the nearest outer `NonceProvider`'s (or `ConfigProvider`'s) nonce (none at the root) |
903
+
904
+ `useCspNonce()` (`@nxgt/material-vue/composables`) reads it in a component of
905
+ your own; `getCspNonce()` and `setCspNonce()` (`@nxgt/material-vue/lib`) read
906
+ and keep the page's nonce outside Vue. The Nuxt `app.vue`, the client entry
907
+ and what each component needs are in the [Content Security Policy
908
+ guide](../guides/csp.md#nonceprovider).
909
+
910
+ **Storybook:** `Primitives/NonceProvider` · **React:** `NonceProvider`
@@ -32,7 +32,9 @@ does not import that entry never has them in its tree.
32
32
  | `@nxgt/material-vue/pdf` | `bun add react @react-pdf/renderer@^4.9`, to render; building documents needs neither ([PDF documents](guides/pdf.md)) |
33
33
  | `@nxgt/material-vue/nuxt` | a Nuxt app, `nuxt >= 3.13` ([below](#nuxt)) |
34
34
 
35
- The tarball contains the built `dist/`, `lib/styles.css`, the component
35
+ The tarball contains the built `dist/` (with KaTeX's fonts in
36
+ `dist/fonts/katex/`, which the compiled stylesheet loads),
37
+ `lib/styles.css`, the component
36
38
  stylesheets it imports (`lib/components/**/*.css`), `lib/map/map.css`, the
37
39
  Nuxt module (`lib/nuxt`, with the
38
40
  `lib/vite/index.ts` it imports), these docs and `CHANGELOG.md` (from the
@@ -48,6 +50,8 @@ In the app's root stylesheet, right after Tailwind:
48
50
  @import "@nxgt/material-vue/styles.css";
49
51
  ```
50
52
 
53
+ Toaster and InputOTP take their CSS from this stylesheet: without it they render unstyled.
54
+
51
55
  - **`styles.css` is source, not compiled CSS.** It holds the Tailwind v4
52
56
  `@theme` layer (colours, `--radius`, the `dark` variant, base styles, a few
53
57
  utilities), so it runs through *your* Tailwind build. Nothing injects it,