@nxgt/material 3.7.5 → 3.8.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 (176) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +39 -6
  3. package/bin/nxgt-theme.js +6 -0
  4. package/dist/{async-slice-o_fpqeGX.js → async-slice-DDjaJY_F.js} +2 -2
  5. package/dist/background--Bf_EbFR.js +159 -0
  6. package/dist/backgrounds/backgrounds.css +2 -0
  7. package/dist/backgrounds/css-react/moon.css +97 -0
  8. package/dist/backgrounds.js +3 -139
  9. package/dist/browser-only-DQ94lWF8.js +18 -0
  10. package/dist/bubble-input-B7BVd9fX.js +237 -0
  11. package/dist/{button--cF4gY14.js → button-DbfdITBB.js} +51 -57
  12. package/dist/charts.js +3 -3
  13. package/dist/{chip-D1B1dL77.js → chip-DpySRqCy.js} +2 -2
  14. package/dist/{client-only.utils-lQ7GqP8w.js → client-only.utils-3nHNzCki.js} +1 -1
  15. package/dist/{code-editor-0CdGwKDg.js → code-editor-BiA14xua.js} +7 -7
  16. package/dist/code-editor.js +6 -6
  17. package/dist/{code-language-items-CGARRbVm.js → code-language-items-C_dJ6GVs.js} +2 -2
  18. package/dist/components/theme-tokens.css +34 -35
  19. package/dist/components/tones/app-tones.css +2 -1
  20. package/dist/components/tones/containers.css +4 -1
  21. package/dist/components/tones/index.css +2 -0
  22. package/dist/components/tones/surface.css +1 -0
  23. package/dist/components/tones/tokens.css +8 -3
  24. package/dist/components/tones/zone-paint.css +15 -0
  25. package/dist/components/ui/feedback/toast/toast-tokens.css +1 -0
  26. package/dist/components/ui/layout/app-shell/activity-backdrop.css +26 -0
  27. package/dist/components/ui/layout/sidebar/sidebar-tokens.css +5 -2
  28. package/dist/components/ui/media/media-player/nxgt-media-player.css +7 -32
  29. package/dist/components/ui/primitives/field-box/field-box-tokens.css +5 -2
  30. package/dist/{components-CDrQCOsU.js → components-B9EIfMdd.js} +18622 -18531
  31. package/dist/components.js +24 -22
  32. package/dist/{dialog-DdJ1C4BR.js → dialog-CkIYpJXk.js} +55 -53
  33. package/dist/dist-B7RjY7SL.js +158 -0
  34. package/dist/dist-C4wtXCjf.js +593 -0
  35. package/dist/dist-DVRQkaTK.js +111 -0
  36. package/dist/dist-lmHmz_bu.js +419 -0
  37. package/dist/dnd.js +1 -1
  38. package/dist/dropdown-menu-BC5Tbhb9.js +908 -0
  39. package/dist/editor.js +527 -527
  40. package/dist/empty-state-s2CSjKXJ.js +126 -0
  41. package/dist/{escape-owner-B8k7DvFa.js → escape-owner-CripBce_.js} +2 -1
  42. package/dist/{field-blur-DFUazxsL.js → field-blur-DPLsMufs.js} +1 -1
  43. package/dist/{field-blur-context-Dw9ZAgBr.js → field-blur-context-1ZwJgsHE.js} +2 -2
  44. package/dist/has-text-content-Ds2dkHX_.js +10 -0
  45. package/dist/hooks.js +35 -33
  46. package/dist/{hover-card-D5iHS9q1.js → hover-card-Cox-tPDz.js} +41 -39
  47. package/dist/{i18n-provider-C6SBK_nO.js → i18n-provider-C6HhBw34.js} +1 -1
  48. package/dist/i18n.js +6 -6
  49. package/dist/{icon-badge-Bb5-73XP.js → icon-badge-q3Ve8gra.js} +3 -3
  50. package/dist/{icon-button-5A6Mrj6w.js → icon-button-DJcWpIhu.js} +2 -1
  51. package/dist/{in-dialog-AiwTD3DK.js → in-dialog-Vwkyp-M5.js} +6 -5
  52. package/dist/lib/backgrounds/background/available.d.ts +3 -3
  53. package/dist/lib/backgrounds/background/background.d.ts +7 -3
  54. package/dist/lib/backgrounds/background/types.d.ts +7 -1
  55. package/dist/lib/backgrounds/index.d.ts +1 -1
  56. package/dist/lib/components/ui/layout/app-shell/activity-chrome.d.ts +17 -0
  57. package/dist/lib/components/ui/layout/app-shell/activity-layout.d.ts +6 -4
  58. package/dist/lib/components/ui/layout/app-shell/backdrop-layer.d.ts +11 -0
  59. package/dist/lib/components/ui/layout/app-shell/keep-shapes-inside.d.ts +17 -0
  60. package/dist/lib/components/ui/layout/app-shell/theme-backdrop.d.ts +6 -0
  61. package/dist/lib/components/ui/layout/app-shell/use-activity-backdrop.d.ts +18 -0
  62. package/dist/lib/components/ui/layout/app-shell/use-keep-shapes-inside.d.ts +9 -0
  63. package/dist/lib/hooks/resolve-theme.d.ts +46 -1
  64. package/dist/lib/hooks/theme-store.d.ts +35 -4
  65. package/dist/lib/hooks/use-theme.d.ts +20 -4
  66. package/dist/lib/i18n/resources/en/en.d.ts +4 -0
  67. package/dist/lib/i18n/resources/en/material.json.d.ts +4 -0
  68. package/dist/lib/i18n/resources/fr/fr.d.ts +4 -0
  69. package/dist/lib/i18n/resources/fr/material.json.d.ts +4 -0
  70. package/dist/lib/i18n/resources/resources.d.ts +8 -0
  71. package/dist/lib/i18n/translator.d.ts +1 -1
  72. package/dist/lib/theme-picker/index.d.ts +7 -0
  73. package/dist/lib/theme-picker/partials/mini-background.d.ts +10 -0
  74. package/dist/lib/theme-picker/partials/mode-control.d.ts +5 -0
  75. package/dist/lib/theme-picker/partials/theme-tile.d.ts +12 -0
  76. package/dist/lib/theme-picker/theme-label.d.ts +7 -0
  77. package/dist/lib/theme-picker/theme-picker.d.ts +25 -0
  78. package/dist/lib/themes/index.d.ts +14 -0
  79. package/dist/lib/themes/nxgt-theme-provider.d.ts +29 -0
  80. package/dist/lib/themes/nxgt-theme.d.ts +22 -0
  81. package/dist/lib/themes/theme-context.d.ts +28 -0
  82. package/dist/lib/themes/theme-value.d.ts +5 -0
  83. package/dist/lib/vite/index.d.ts +1 -1
  84. package/dist/lib.js +3 -3
  85. package/dist/main.js +43 -39
  86. package/dist/map.js +8 -8
  87. package/dist/material.css +1 -1
  88. package/dist/nxgt-theme-CgSb9Obl.js +37 -0
  89. package/dist/pdf-reader.js +1 -1
  90. package/dist/print.js +2 -2
  91. package/dist/{public-SsiazLEv.js → public-Ce30uvp0.js} +591 -587
  92. package/dist/read-storage-C2J90bNm.js +10 -0
  93. package/dist/{rich-code-block-CwNwQs5z.js → rich-code-block-C2Fp_FDU.js} +5 -5
  94. package/dist/{sortable-provider-BvD98s8Y.js → sortable-provider-pVaEZzty.js} +3 -3
  95. package/dist/{spinner-CtGCPza-.js → spinner-CsHcmcpF.js} +2 -2
  96. package/dist/{stored-language-Bb7yX5uE.js → stored-language-BeIKw3-K.js} +15 -15
  97. package/dist/styles.css +8 -1
  98. package/dist/theme-context-BagPvRcz.js +16 -0
  99. package/dist/theme-picker.js +118 -0
  100. package/dist/theme-store-CSl51uNH.js +91 -0
  101. package/dist/theme-toggle-C8os82b4.js +48 -0
  102. package/dist/themes.js +42 -0
  103. package/dist/toggle-group-j8zaxEg1.js +69 -0
  104. package/dist/{toolbar-items-DsDDD5AY.js → toolbar-items-CqHvlTU8.js} +443 -589
  105. package/dist/tooltip-rhbqNmr3.js +1064 -0
  106. package/dist/{translate-material-Bsjc4Tow.js → translate-material-CGZljjp1.js} +2 -2
  107. package/dist/{translator-or2y0JJB.js → translator-DCYO4Ij3.js} +3 -3
  108. package/dist/{use-background-activity-B8jLHNop.js → use-background-activity-KxQgelFF.js} +1 -1
  109. package/dist/{use-chat-composer-DZ01a16D.js → use-chat-composer-CDrgWGMM.js} +4684 -4886
  110. package/dist/{use-heading-spy-ByOQNnFZ.js → use-heading-spy-DXo6IOX9.js} +52 -121
  111. package/dist/{use-material-translation-hLQzOjF0.js → use-material-translation-DkxcLbLM.js} +2 -2
  112. package/dist/use-slice-reducer-BGkeGtML.js +42 -0
  113. package/dist/use-theme-Cd-aiDJo.js +31 -0
  114. package/docs/README.md +2 -1
  115. package/docs/components/foundations.md +39 -0
  116. package/docs/components/navigation-and-layout.md +3 -3
  117. package/docs/getting-started.md +1 -1
  118. package/docs/guides/app-shell.md +41 -6
  119. package/docs/guides/backgrounds.md +43 -7
  120. package/docs/guides/i18n.md +1 -1
  121. package/docs/guides/themes.md +103 -0
  122. package/docs/guides/theming.md +288 -84
  123. package/docs/guides/vite-plugin.md +26 -0
  124. package/docs/previews/backgrounds-background-from-theme.webp +0 -0
  125. package/docs/previews/backgrounds-geometry-more.webp +0 -0
  126. package/docs/previews/backgrounds-geometry.webp +0 -0
  127. package/docs/previews/backgrounds-illustrated-scenes.webp +0 -0
  128. package/docs/previews/backgrounds-light-more.webp +0 -0
  129. package/docs/previews/backgrounds-light.webp +0 -0
  130. package/docs/previews/backgrounds-material-more.webp +0 -0
  131. package/docs/previews/backgrounds-matrix.webp +0 -0
  132. package/docs/previews/backgrounds-moon.webp +0 -0
  133. package/docs/previews/backgrounds-motif-shapes.webp +0 -0
  134. package/docs/previews/backgrounds-motifs.webp +0 -0
  135. package/docs/previews/foundations-themes-themepicker.webp +0 -0
  136. package/docs/roadmap.md +25 -0
  137. package/docs/troubleshooting.md +35 -7
  138. package/lib/backgrounds/backgrounds.css +2 -0
  139. package/lib/backgrounds/css-react/moon.css +97 -0
  140. package/lib/components/theme-tokens.css +34 -35
  141. package/lib/components/tones/app-tones.css +2 -1
  142. package/lib/components/tones/containers.css +4 -1
  143. package/lib/components/tones/index.css +2 -0
  144. package/lib/components/tones/surface.css +1 -0
  145. package/lib/components/tones/tokens.css +8 -3
  146. package/lib/components/tones/zone-paint.css +15 -0
  147. package/lib/components/ui/feedback/toast/toast-tokens.css +1 -0
  148. package/lib/components/ui/layout/app-shell/activity-backdrop.css +26 -0
  149. package/lib/components/ui/layout/sidebar/sidebar-tokens.css +5 -2
  150. package/lib/components/ui/media/media-player/nxgt-media-player.css +7 -32
  151. package/lib/components/ui/primitives/field-box/field-box-tokens.css +5 -2
  152. package/lib/styles.css +8 -1
  153. package/lib/theme-picker/theme-picker-list.css +29 -0
  154. package/lib/theme-picker/theme-picker.css +192 -0
  155. package/lib/theme-picker/theme-tile-background.css +77 -0
  156. package/lib/theme-picker/theme-tile-textures-night.css +63 -0
  157. package/lib/theme-picker/theme-tile-textures.css +153 -0
  158. package/lib/themes/ambre.css +134 -0
  159. package/lib/themes/ardoise.css +133 -0
  160. package/lib/themes/bleumono.css +136 -0
  161. package/lib/themes/bluemoon.css +136 -0
  162. package/lib/themes/corail.css +136 -0
  163. package/lib/themes/foret.css +133 -0
  164. package/lib/themes/lavande.css +133 -0
  165. package/lib/themes/menthe.css +136 -0
  166. package/lib/themes/ocean.css +136 -0
  167. package/lib/themes/pink.css +134 -0
  168. package/lib/themes/prune.css +133 -0
  169. package/lib/themes/sable.css +133 -0
  170. package/lib/themes/slate.css +133 -0
  171. package/lib/themes/teal.css +137 -0
  172. package/package.json +30 -2
  173. package/dist/dropdown-menu-DWtgUVW7.js +0 -1490
  174. package/dist/empty-state-CRWLQ1sM.js +0 -191
  175. package/dist/tooltip-tmFoTU_d.js +0 -1582
  176. package/dist/use-slice-reducer-0r5dXnJe.js +0 -58
@@ -45,19 +45,20 @@ import '@nxgt/material/backgrounds.css';
45
45
 
46
46
  | Prop | Values | Default |
47
47
  | --- | --- | --- |
48
- | `preset` | `gradient`, `grain`, `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`, `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport` (`AVAILABLE_BACKGROUND_PRESETS`, the ids this library draws); any other id draws the gradient and warns outside production | `gradient` |
48
+ | `preset` | `gradient`, `grain`, `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`, `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport`, `moon` (`AVAILABLE_BACKGROUND_PRESETS`, the ids this library draws); any other id draws the gradient and warns outside production | `gradient` |
49
49
  | `tone`, `intensity` | as above | `primary`, `default` |
50
50
  | `animated` | `boolean`: drifts the layers, see Motion | `false` |
51
51
  | `grain` | `boolean`: film noise over the preset; needs `grain.css` | `false` |
52
52
  | `seed` | `number`: moves a seeded preset's geometry and the grain | `0` |
53
53
  | `motif` | a `MotifOptions` object (`shapes`, `density`, `size`, `rotate`, `shapeFill`, `opacitySpread`), see [Motif presets](#motif-presets) | all fields optional |
54
+ | `moon` | a `MoonOptions` object for `preset="moon"`: `position` (`{ x, y }`, fractions of the container), `phase`, `halo`; see [Moon](#moon) | `{ position: { x: 0.8, y: 0.2 }, phase: 0.78, halo: 2.6 }` |
54
55
  | `fill` | `viewport` (the viewport's size) or `container` (its parent's size: the parent needs a definite height) | `viewport` |
55
56
 
56
- `BACKGROUND_PRESETS` is the table of all 44 presets with their family and
57
+ `BACKGROUND_PRESETS` is the table of all 45 presets with their family and
57
58
  kind; `AVAILABLE_BACKGROUND_PRESETS` lists the ids this library draws (all
58
- 44; `SHIPPED_BACKGROUND_PRESETS` is the common floor every library draws).
59
+ 45; `SHIPPED_BACKGROUND_PRESETS` is the common floor every library draws).
59
60
 
60
- <img src="../previews/backgrounds-matrix.webp" width="640" alt="The 44 presets, each in a card with its name">
61
+ <img src="../previews/backgrounds-matrix.webp" width="640" alt="The presets, each in a card with its name">
61
62
 
62
63
  The root states `preset`, `tone`, `intensity`, `animated`, `grain` and `fill` as
63
64
  `data-*` attributes (`data-animated` and `data-grain` are empty attributes), and
@@ -257,7 +258,18 @@ Each is about 14 to 16 KB of markup at the defaults and 24 to 28 KB at `density:
257
258
  classes (a pace `p1..p3`, a delay `l1..l4`), so it needs no inline style under a strict CSP, and it stops under
258
259
  `prefers-reduced-motion` or while the page is hidden. CSS: `backgrounds/illustrated.css` (shared, imported by each
259
260
  preset's file) plus `school.css`, `night-sky.css`, `bubbles.css`, `leaves.css`, `science.css`, `music.css`,
260
- `travel.css` and `sport.css`; one alone works. React only: `@nxgt/material-vue` does not draw them.
261
+ `travel.css` and `sport.css`; one alone works. React only: `@nxgt/material-vue` does not draw them. (`moon.css` is below.)
262
+
263
+ ### Moon
264
+
265
+ `moon` is a thin crescent at the top right in a wide halo of the tertiary colour, among nine sparse stars: calmer than
266
+ `constellation`, and the background of the Blue moon theme. The moon is drawn in the tone's second colour (silver
267
+ in dark, a lighter multiplied crescent in light), the halo in its third and the stars in its first and second, so `tone="mixed"` is the intended look. It
268
+ follows `intensity` (`subtle` is a faint watermark, `vivid` the strongest; the stars and the moon keep off the middle of the frame, where the content sits), and reads `size` (the moon's radius) and `density`
269
+ (5, 9 or 15 stars) from `motif`. With `animated` the stars twinkle (8 s a leg), and nothing moves under
270
+ `prefers-reduced-motion` or while the page is hidden. About 3 KB of markup. The moon stays the same size (80 px, half that in a container under 640 px wide) and sits at 80% across and 20% down, whatever the container's shape. CSS: `backgrounds/moon.css` (it imports
271
+ `scene.css`); one alone works. React only: `@nxgt/material-vue` does not draw it. The moon's `position`, `phase` and
272
+ `halo` come from the `moon` prop (`<Background preset="moon" moon={{ position: { x: 0.2, y: 0.25 }, phase: 0.6 }} />`).
261
273
 
262
274
  ## Dark mode
263
275
 
@@ -296,10 +308,34 @@ you can select on:
296
308
  The gradient ends on `--nxgt-bg-cp`, not `--nxgt-bg-c2`: to recolour it, set
297
309
  `--nxgt-bg-cp` too.
298
310
 
311
+ ## Defaults from the theme
312
+
313
+ The `Background` of `@nxgt/material/backgrounds` takes what you leave out
314
+ (`preset`, `tone`, `intensity`, `seed`, `motif`, `grain`, `animated`) from the
315
+ nearest theme (`NxgtThemeProvider` or an `NxgtTheme` zone, see
316
+ [the provider and zones](./theming.md#the-provider-and-zones)), then from the
317
+ defaults above. A prop you pass always wins; the others still come from the theme.
318
+
319
+ ```tsx
320
+ import { NxgtTheme, ocean } from '@nxgt/material/themes';
321
+ import { Background } from '@nxgt/material/backgrounds';
322
+
323
+ <NxgtTheme theme={ocean}>
324
+ <Background /> {/* Ocean's waves, tone and intensity */}
325
+ <Background preset="dots" /> {/* dots, with Ocean's tone and intensity */}
326
+ </NxgtTheme>
327
+ ```
328
+
329
+ Outside any theme nothing changes. The preset's stylesheet is still yours to
330
+ import. The `/components` `Background` is the gradient alone and does not read
331
+ the theme.
332
+
299
333
  ## Behind the app shell
300
334
 
301
- `ActivityLayout` takes a preset as its `backdrop`, replacing the gradient and
302
- its blobs: `backdrop={<Background preset="shapes" motif={{ shapes: MOTIF_SHAPES_ALL }} />}`.
335
+ `ActivityLayout` draws the theme's background by default (Lavande's is the
336
+ built-in gradient and its blobs). Its `backdrop` prop is the exception: a node
337
+ such as `backdrop={<Background preset="shapes" motif={{ shapes: MOTIF_SHAPES_ALL }} />}`
338
+ replaces it for one screen, and `backdrop={false}` removes it.
303
339
  See [Use a background preset behind the shell](./app-shell.md#use-a-background-preset-behind-the-shell).
304
340
 
305
341
  ## Recolour the blobs
@@ -252,7 +252,7 @@ single value's input, when nothing names the slider, `material.slider.value`
252
252
  `ComboboxField` (`showClear`), "Clear" / "Effacer" (`material.combobox.clear`),
253
253
  their chevron, "Show the options" / "Afficher les options"
254
254
  (`material.combobox.toggle`),
255
- the `LocationPreview` trigger
255
+ the `ThemePicker`'s group and mode names (`material.theme-picker.label` "Theme" / "Thème", `material.theme-picker.mode` "Mode"; the Light, Dark and System names are `ThemeToggle`'s own), the `LocationPreview` trigger
256
256
  (`material.map.preview` / `preview-named`), and the delete buttons of the
257
257
  `Contacts` / `OpeningHours` rows. `FacetGroup`'s toggle is named "Level, 2 selected" / "Level, 2 sélectionnés" (`material.facet-group.name`, over `{title}` and `{count}`: plain in English, an ICU plural in French) and its Clear button "Clear Level" / "Effacer Level" (`material.facet-group.clear-label`, with the visible `material.facet-group.clear`). `AccountMenu`'s avatar button is named "Account menu, {name}" / "Menu du compte, {name}" (`material.account-menu.trigger`, over `{name}`) and its last item reads "Sign out" / "Se déconnecter" (`material.account-menu.sign-out`), unless you pass `signOutLabel`; with `themeChoice` its "Theme" group reads "Theme" / "Thème", "Light" / "Clair", "Dark" / "Sombre", "System" / "Système" (`material.account-menu.theme.label`, `light`, `dark`, `system`). `LocalizedTextFields`' reset button is named "Reset {language} to the default" / "Rétablir la valeur par défaut ({language})" (`material.localized-text-fields.reset`), its tooltip reads "Default: {value}" (`reset-tooltip`) and its polite status "{language}: back to the default" (`reset-done`). Its "Other languages" trigger reads "Other languages ({count})" / "Autres langues ({count})" (`others-count`; `others` names the folded rows' group), and while closed over errors it is described by "{count} errors" / "{count} erreurs" (`others-errors`, an ICU plural over `{count}`). The language names come from `material.language.<code>` (English and French ship), then `Intl.DisplayNames`. `PrintDocument`'s page numbers
258
258
  read `material.print.page-of` ("Page {page} of {pages}", "Page {page} sur
@@ -0,0 +1,103 @@
1
+ # Themes for your app: define, generate, check
2
+
3
+ An app theme is a `defineTheme()` module. A build step turns it into a stylesheet
4
+ (`<name>.css`) and a `.d.ts` that you commit; there is no style injection at
5
+ runtime, so a strict Content Security Policy needs nothing extra. Two tools do the
6
+ build step: the `themes` option of the [Vite plugin](vite-plugin.md#themes), and the
7
+ `nxgt-theme` command for builds without Vite and for CI.
8
+
9
+ See also [Theming](theming.md) for the tokens a theme sets.
10
+
11
+ ## Define a theme
12
+
13
+ ```ts
14
+ // src/themes/ecole.ts
15
+ import { defineTheme, ocean } from '@nxgt/material/themes';
16
+
17
+ export default defineTheme({
18
+ name: 'ecole',
19
+ label: 'École',
20
+ extends: ocean,
21
+ colors: { primary: '#0b7a75' },
22
+ tones: { maths: '#0b7a75', art: { light: '#a33', dark: '#f99' } },
23
+ });
24
+ ```
25
+
26
+ A module exports its themes as the default export (one theme or an array) or as
27
+ named exports. The seeds, `extends`, `tones`, `fonts`, `radius` and `tokens` are
28
+ documented in [`@nxgt/material-core`'s themes page](https://cdn.jsdelivr.net/npm/@nxgt/material-core@0/docs/theme.md).
29
+
30
+ ## Generate the files
31
+
32
+ With Vite:
33
+
34
+ ```ts
35
+ // vite.config.ts
36
+ import { nxgtMaterial } from '@nxgt/material/vite';
37
+ import tailwindcss from '@tailwindcss/vite';
38
+ import react from '@vitejs/plugin-react';
39
+ import { defineConfig } from 'vite';
40
+
41
+ export default defineConfig({
42
+ plugins: [
43
+ react(),
44
+ tailwindcss(),
45
+ ...nxgtMaterial({ themes: { entries: 'src/themes/*.ts' } }),
46
+ ],
47
+ });
48
+ ```
49
+
50
+ Or from a shell:
51
+
52
+ ```sh
53
+ nxgt-theme build "src/themes/*.ts" --out src/themes/generated
54
+ ```
55
+
56
+ Both write `src/themes/generated/ecole.css` and `nxgt-themes.d.ts`, and only when
57
+ the bytes changed. **Commit them.** Import the stylesheet after the library's:
58
+
59
+ ```css
60
+ @import "@nxgt/material/styles.css";
61
+ @import "./themes/generated/ecole.css"; /* after styles.css */
62
+ ```
63
+
64
+ `nxgt-themes.d.ts` merges your tone names into `AppTones` and your theme names into
65
+ `NxgtThemes`, so `useTheme().themeName`, `ThemeName` (from `@nxgt/material/hooks`) and the `data-tone` values are typed with
66
+ them. Include it in your `tsconfig`.
67
+
68
+ ## The CLI
69
+
70
+ ```
71
+ nxgt-theme build <entries…> [--out src/themes/generated] [--no-types] [--strict] [--module @nxgt/material]
72
+ nxgt-theme check <entries…> [--out …] [--no-types] [--module …]
73
+ nxgt-theme inspect <entry> [--name x]
74
+ ```
75
+
76
+ - `build` writes the files. Warnings go to stderr; `--strict` makes them exit 1.
77
+ - `check` writes nothing. It exits 1 when a generated file is stale or missing, or when a
78
+ contrast pair fails (an override that broke one). Run it in CI to catch a
79
+ theme edited without a rebuild:
80
+
81
+ ```yaml
82
+ - run: npx nxgt-theme check "src/themes/*.ts" --out src/themes/generated
83
+ ```
84
+
85
+ - `inspect` prints every token and the contrast table, light and dark.
86
+
87
+ Entries are `.js` or `.mjs` files, or `.ts` / `.mts` files through Node's own type
88
+ stripping (Node 22.18 or newer, no loader to install). Type stripping handles
89
+ erasable syntax only: write the theme as a plain object, with no `enum`,
90
+ `namespace` or parameter property. The command ships in `@nxgt/material` and in
91
+ `@nxgt/material-core`; with pnpm or bun only the bin of a direct dependency is
92
+ linked, so call it through `@nxgt/material`.
93
+
94
+ ## Warnings
95
+
96
+ - A token override that breaks a documented contrast pair, with its ratio.
97
+ - **A tone declared in one theme and missing from another**: in the other theme the
98
+ name falls back to the inherited value. Declare it in every theme that should differ.
99
+ - The palette generator's own notices (a lightness moved for AA, a chroma lowered,
100
+ a hue near a status colour).
101
+
102
+ With the plugin they go to Vite's logger, or fail the build with
103
+ `onWarning: 'error'`.