@nxgt/material-vue 0.41.0 → 0.43.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.
- package/CHANGELOG.md +124 -0
- package/README.md +20 -6
- package/dist/{Button-BG3oDkrl.js → Button-C3K6dhqd.js} +4 -4
- package/dist/{HoverCardTrigger-Dh1ar_W4.js → HoverCardTrigger-Bga4YjEr.js} +69 -62
- package/dist/backgrounds/backgrounds.css +8 -0
- package/dist/backgrounds/css/base.css +169 -0
- package/dist/backgrounds/css/gradient.css +53 -0
- package/dist/backgrounds/css/grain.css +19 -0
- package/dist/backgrounds/css/motion.css +30 -0
- package/dist/backgrounds.js +111 -0
- package/dist/{camera-DV9jcl_3.js → camera-BbF9_-ys.js} +4 -4
- package/dist/components/base.css +5 -2
- package/dist/components/components.css +5 -0
- package/dist/components/theme-tokens.css +21 -0
- package/dist/{components-C1JYYoQ4.js → components-yCdbry6Q.js} +13880 -13101
- package/dist/components.js +8 -8
- package/dist/composables.js +3 -3
- package/dist/dnd.js +1 -1
- package/dist/{form-scope-CeD0v_mw.js → form-scope-CkWJrBCu.js} +1 -1
- package/dist/{i18n-provider-D5XyLQ3P.js → i18n-provider-tL27-a8y.js} +1 -1
- package/dist/i18n.js +4 -4
- package/dist/{icon-button-DXrmfs6e.js → icon-button-MyFFJpXA.js} +4 -4
- package/dist/lib/backgrounds/background/background.vue.d.ts +22 -0
- package/dist/lib/backgrounds/background/index.d.ts +2 -0
- package/dist/lib/backgrounds/background/partials/background-layers.vue.d.ts +9 -0
- package/dist/lib/backgrounds/background/partials/scene-svg.d.ts +10 -0
- package/dist/lib/backgrounds/background/types.d.ts +24 -0
- package/dist/lib/backgrounds/index.d.ts +13 -0
- package/dist/lib/components/ui/actions/button/button-tones.d.ts +3 -3
- package/dist/lib/components/ui/actions/responsive-button/responsive-button.vue.d.ts +3 -3
- package/dist/lib/components/ui/collections/data-table/data-table-context.d.ts +4 -0
- package/dist/lib/components/ui/collections/data-table/data-table.vue.d.ts +8 -0
- package/dist/lib/components/ui/collections/data-table/partials/data-table-body.vue.d.ts +8 -0
- package/dist/lib/components/ui/collections/data-table/partials/data-table-empty.vue.d.ts +5 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-toolbar.d.ts +16 -3
- package/dist/lib/components/ui/collections/data-table/select-checkbox.d.ts +36 -0
- package/dist/lib/components/ui/collections/data-table/types.d.ts +15 -0
- package/dist/lib/components/ui/collections/data-table/use-data-table.d.ts +2 -0
- package/dist/lib/components/ui/feedback/circular-progress/circular-progress.vue.d.ts +1 -1
- package/dist/lib/components/ui/feedback/empty-state/empty-state.vue.d.ts +21 -8
- package/dist/lib/components/ui/feedback/empty-state/index.d.ts +1 -1
- package/dist/lib/components/ui/feedback/error-state/error-state.vue.d.ts +54 -0
- package/dist/lib/components/ui/feedback/error-state/index.d.ts +3 -0
- package/dist/lib/components/ui/feedback/error-state/partials/error-state-details.vue.d.ts +7 -0
- package/dist/lib/components/ui/feedback/index.d.ts +1 -0
- package/dist/lib/components/ui/feedback/state-frame/state-frame.vue.d.ts +36 -0
- package/dist/lib/components/ui/feedback/state-frame/state-icon.vue.d.ts +7 -0
- package/dist/lib/components/ui/feedback/state-frame/state-illustration.vue.d.ts +8 -0
- package/dist/lib/components/ui/feedback/state-frame/state-tones.d.ts +11 -0
- package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
- package/dist/lib/components/ui/layout/account-menu/account-menu-avatar.vue.d.ts +9 -0
- package/dist/lib/components/ui/layout/account-menu/account-menu.vue.d.ts +38 -0
- package/dist/lib/components/ui/layout/account-menu/index.d.ts +3 -0
- package/dist/lib/components/ui/layout/account-menu/types.d.ts +10 -0
- package/dist/lib/components/ui/layout/app-shell/activity-layout.vue.d.ts +21 -5
- package/dist/lib/components/ui/layout/app-shell/app-brand-logo.vue.d.ts +20 -0
- package/dist/lib/components/ui/layout/app-shell/app-brand.vue.d.ts +30 -0
- package/dist/lib/components/ui/layout/app-shell/app-header.vue.d.ts +13 -5
- package/dist/lib/components/ui/layout/app-shell/app-sidebar.vue.d.ts +12 -2
- package/dist/lib/components/ui/layout/app-shell/index.d.ts +1 -1
- package/dist/lib/components/ui/layout/app-shell/types.d.ts +10 -0
- package/dist/lib/components/ui/layout/app-shell/use-truncated-title.d.ts +10 -0
- package/dist/lib/components/ui/layout/background/background.vue.d.ts +18 -3
- package/dist/lib/components/ui/layout/doc/partials/doc-empty.vue.d.ts +7 -4
- package/dist/lib/components/ui/layout/index.d.ts +1 -0
- package/dist/lib/components/ui/media/stx-player/stx-player-viewport.vue.d.ts +2 -2
- package/dist/lib/components/ui/overlays/command/CommandSeparator.vue.d.ts +3 -1
- package/dist/lib/components/ui/overlays/dialog/in-dialog.d.ts +1 -1
- package/dist/lib/components/ui/overlays/dialog/use-escape-forward.d.ts +13 -0
- package/dist/lib/components/ui/overlays/dialog/use-modal-content.d.ts +2 -0
- package/dist/lib/components/ui/primitives/nonce-provider/nonce-provider.vue.d.ts +4 -1
- package/dist/lib/components/ui/selection/autocomplete/autocomplete-keyboard.d.ts +22 -4
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-box.vue.d.ts +6 -2
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-list.vue.d.ts +7 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-active.d.ts +17 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-keydown.d.ts +21 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-open.d.ts +3 -3
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete.d.ts +2 -1
- package/dist/lib/components/ui/selection/autocomplete/use-drawer-room.d.ts +11 -0
- package/dist/lib/components/ui/selection/autocomplete/use-query-change.d.ts +8 -0
- package/dist/lib/components/ui/widgets/charts/chart-container.vue.d.ts +2 -2
- package/dist/lib/components/ui/widgets/kanban/partials/kanban-empty.vue.d.ts +1 -0
- package/dist/lib/composables/use-background-activity.d.ts +8 -0
- package/dist/lib/i18n/resources/en/en.d.ts +28 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +29 -1
- package/dist/lib/i18n/resources/fr/fr.d.ts +28 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +29 -1
- package/dist/lib/i18n/resources/resources.d.ts +56 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib/lib/index.d.ts +1 -0
- package/dist/lib/nuxt/component-names.d.ts +1 -1
- package/dist/lib/nuxt/module.d.ts +2 -11
- package/dist/lib/nuxt/pdf-fonts.d.ts +1 -1
- package/dist/lib/nuxt/plugin-options.d.ts +58 -0
- package/dist/lib/vite/index.d.ts +4 -8
- package/dist/lib.js +52 -51
- package/dist/main.js +17 -17
- package/dist/map.js +4 -4
- package/dist/material-vue.css +1 -1
- package/dist/{pdf-outline-sidebar-CgmJjhUz.js → pdf-outline-sidebar-Kqsfd_cO.js} +2 -2
- package/dist/{pdf-page-BjQNWV72.js → pdf-page-Dx3jwxu6.js} +1 -1
- package/dist/{pdf-page-list-nG0l4SjH.js → pdf-page-list-BsQmEHaY.js} +2 -2
- package/dist/{pdf-reader-Dekd4Ymw.js → pdf-reader-CJo8SQVl.js} +15 -15
- package/dist/{pdf-sidebar-gDj63dRH.js → pdf-sidebar-CcCUATl-.js} +3 -3
- package/dist/{pdf-thumbnail-sidebar-C5ikii1Z.js → pdf-thumbnail-sidebar-BRxNRGfG.js} +4 -4
- package/dist/{pdf-toolbar-DmmrSlCq.js → pdf-toolbar-B0ckYBJ2.js} +4 -4
- package/dist/pdf.js +2 -2
- package/dist/{print-format.utils-CiUiQE-i.js → print-format.utils-51joHpFb.js} +2 -2
- package/dist/{sortable-provider-lK0srHJF.js → sortable-provider-BEx1B0Ky.js} +2 -2
- package/dist/{stored-language-dM2e5qaS.js → stored-language-DVP9KzRu.js} +58 -2
- package/dist/{stx-player-C2VQCXFc.js → stx-player-KPp9c7vS.js} +5 -5
- package/dist/styles.css +4 -0
- package/dist/{translator-DXL5RDRg.js → translator-Bm7i7dv-.js} +1 -1
- package/dist/use-background-activity-DdTBbNpX.js +17 -0
- package/dist/{use-heading-spy-Btwc0yad.js → use-heading-spy-jn8f2ioE.js} +13 -13
- package/dist/{use-material-translation-Du3Wvsk1.js → use-material-translation-CfFZPSe0.js} +3 -3
- package/dist/vite.js +7 -2
- package/docs/README.md +3 -0
- package/docs/components/README.md +2 -1
- package/docs/components/buttons-and-actions.md +2 -0
- package/docs/components/data-table-filter-and-lists.md +59 -8
- package/docs/components/feedback-and-status.md +79 -8
- package/docs/components/media-and-files.md +2 -0
- package/docs/components/navigation-and-layout.md +68 -5
- package/docs/components/overlays-and-menus.md +20 -3
- package/docs/components/primitives.md +5 -3
- package/docs/components/rich-widgets.md +1 -1
- package/docs/components/selection-and-choice.md +14 -4
- package/docs/getting-started.md +22 -3
- package/docs/guides/app-shell.md +99 -19
- package/docs/guides/backgrounds.md +143 -0
- package/docs/guides/csp.md +48 -6
- package/docs/guides/helpers.md +1 -0
- package/docs/guides/i18n.md +52 -2
- package/docs/guides/migrate-to-vite-plugin.md +259 -0
- package/docs/guides/pdf.md +11 -4
- package/docs/guides/ssr.md +1 -1
- package/docs/guides/theming.md +52 -4
- package/docs/guides/vite-plugin.md +194 -0
- package/docs/previews/backgrounds-matrix.webp +0 -0
- package/docs/previews/feedback-status-emptystate.webp +0 -0
- package/docs/previews/feedback-status-errorstate.webp +0 -0
- package/docs/previews/navigation-layout-accountmenu.webp +0 -0
- package/docs/roadmap.md +69 -32
- package/docs/troubleshooting.md +251 -7
- package/lib/backgrounds/backgrounds.css +8 -0
- package/lib/backgrounds/css/base.css +169 -0
- package/lib/backgrounds/css/gradient.css +53 -0
- package/lib/backgrounds/css/grain.css +19 -0
- package/lib/backgrounds/css/motion.css +30 -0
- package/lib/components/base.css +5 -2
- package/lib/components/components.css +5 -0
- package/lib/components/theme-tokens.css +21 -0
- package/lib/nuxt/component-names.ts +2 -0
- package/lib/nuxt/module.ts +29 -15
- package/lib/nuxt/pdf-fonts.ts +1 -1
- package/lib/nuxt/plugin-options.ts +92 -0
- package/lib/nuxt/runtime/inter.css +6 -0
- package/lib/styles.css +4 -0
- package/lib/vite/index.ts +19 -2
- package/package.json +24 -2
package/docs/guides/theming.md
CHANGED
|
@@ -40,6 +40,10 @@ build:
|
|
|
40
40
|
and `[data-theme="dark"]`;
|
|
41
41
|
- a `@theme` block that maps each token to a Tailwind colour, so `bg-primary`,
|
|
42
42
|
`text-error-foreground`, `border-border` are real utilities;
|
|
43
|
+
- the **background presets' base, gradient and motion CSS** (`lib/backgrounds/css/`),
|
|
44
|
+
which `Background` from `/components` draws with: plain CSS keyed on
|
|
45
|
+
`data-background`, in `@layer components`, so a utility on the element wins.
|
|
46
|
+
The other presets are opt-in ([backgrounds](backgrounds.md));
|
|
43
47
|
- a `dark` custom variant, base styles (scrollbars, borders, selection, body
|
|
44
48
|
colours), and a few utilities: `center`, `size-lv`, `col-start-full`,
|
|
45
49
|
`h-fill`, `w-fill`, `size-fill`.
|
|
@@ -51,10 +55,12 @@ build:
|
|
|
51
55
|
| `--background`, `--foreground` | `bg-background`, `text-foreground` | page and text |
|
|
52
56
|
| `--primary`, `--primary-foreground` | `bg-primary`, `text-primary-foreground` | filled buttons, active states, focus |
|
|
53
57
|
| `--secondary`, `--secondary-foreground` | `bg-secondary`, … | the secondary colour |
|
|
58
|
+
| `--tertiary`, `--tertiary-foreground` | `bg-tertiary`, `text-tertiary`, `bg-tertiary-container`, … | the tertiary colour (strix violet) |
|
|
54
59
|
| `--muted`, `--muted-foreground` | `bg-muted`, `text-muted-foreground` | quiet surfaces, hints, placeholders |
|
|
55
60
|
| `--track`, `--track-fill` | `bg-track`, `bg-track-fill`, `border-track-fill` | the empty part of a slider or meter, the drawer handle; the slider range and thumb |
|
|
56
61
|
| `--accent`, `--accent-foreground` | `bg-accent`, … | hover surfaces |
|
|
57
62
|
| `--error`, `--success`, `--info`, `--warning` (+ `-foreground`) | `bg-error`, `text-success`, … | the status colours of `Button`, `Alert`, `Badge`, toasts |
|
|
63
|
+
| `--primary-text` | `text-primary-text` | primary drawn as text or an icon on a page, card or popover surface: `Typography tone="primary"`, links, the `Alert` primary icon, selected labels. Equal to `--primary` in light; in dark, `--primary` mixed 60 % with white (`color-mix(in oklab, var(--primary) 40%, white)`), well over 4.5:1 on `--background` and `--card` |
|
|
58
64
|
| `--error-text` | `text-error-text` | error drawn as text: field messages, `HelperText` in its error state, form and dialog errors, `variant="error"` menu items |
|
|
59
65
|
| `--destructive` | `bg-destructive`, `text-destructive` | deprecated alias of `--error`: the light theme sets it to `var(--error)`, the dark theme keeps its own value; use `--error` |
|
|
60
66
|
| `--card`, `--popover`, `--tooltip` (+ `-foreground`) | `bg-card`, `bg-popover`, `bg-tooltip` | surfaces |
|
|
@@ -130,6 +136,26 @@ import { Button } from '@nxgt/material-vue/components';
|
|
|
130
136
|
</template>
|
|
131
137
|
```
|
|
132
138
|
|
|
139
|
+
## Links
|
|
140
|
+
|
|
141
|
+
`styles.css` styles every bare `<a>` as a link in running text: the info
|
|
142
|
+
colour, an underline on hover and focus, an info tint behind it. Links the
|
|
143
|
+
components render with a look of their own (`Toc`, `SeeAlso`, `Pager`,
|
|
144
|
+
`LinkCard`, `ListTile`, the doc shell's links, `BreadcrumbLink`, `SkipLink`,
|
|
145
|
+
the sidebar entries) opt out of it. Do the same for an anchor of yours that
|
|
146
|
+
has its own look, such as a card, a menu entry or a button-like link: add the
|
|
147
|
+
`nxgt-plain-link` class.
|
|
148
|
+
|
|
149
|
+
```vue
|
|
150
|
+
<a href="/pricing" class="nxgt-plain-link flex items-center gap-2 rounded p-2 hover:bg-muted">
|
|
151
|
+
Pricing
|
|
152
|
+
</a>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The class only removes the prose style (colour, underline, tint, pointer);
|
|
156
|
+
the anchor then inherits its text colour like any other element, so style
|
|
157
|
+
the rest yourself. Without the class the anchor keeps the prose style.
|
|
158
|
+
|
|
133
159
|
## Contrast and reduced motion
|
|
134
160
|
|
|
135
161
|
**Contrast.** The shipped light palette keeps the text of every filled status
|
|
@@ -139,7 +165,10 @@ colour at 4.5:1 or more (WCAG 1.4.3): `--secondary` 5.7:1, `--success` 5.6:1,
|
|
|
139
165
|
`--background`, 4.8:1 on its own 15 % `tonal` tint.
|
|
140
166
|
|
|
141
167
|
The dark theme keeps brighter values, read as text on the dark surfaces: the
|
|
142
|
-
dark `--
|
|
168
|
+
dark `--tertiary` (`oklch(0.7 0.15 310.75)`) is 7.0:1 on `--background` and
|
|
169
|
+
6.3:1 on `--card`, with a dark `--tertiary-foreground` that keeps 7.0:1 on
|
|
170
|
+
a filled tertiary surface (light: 7.6:1 under near-white). The dark
|
|
171
|
+
`--secondary` (`oklch(0.66 0.1135 245.65)`) is 6.5:1 on `--background`
|
|
143
172
|
and 5.8:1 on `--card` (a `tonal` secondary `Button` 5.4:1 and 4.6:1). Under
|
|
144
173
|
near-white text those brights are too light, so every filled surface built on
|
|
145
174
|
them is tinted in the dark theme: a filled `secondary` `Button`, `IconButton`
|
|
@@ -162,12 +191,12 @@ their text and icon in one tone per colour, read on `--background`, on
|
|
|
162
191
|
the light theme `primary`, `secondary`, `info` and `success` use the token
|
|
163
192
|
itself (5.8, 4.8, 4.9 and 4.7:1 at their lowest) and `warning` and `error` the
|
|
164
193
|
token mixed with 15 % black (6.4 and 5.4:1). In the dark theme `primary` is
|
|
165
|
-
mixed with 60 % white (8.1:1 on `--card`: the token itself is a dark indigo,
|
|
194
|
+
mixed with 60 % white, the `--primary-text` token (8.1:1 on `--card`: the token itself is a dark indigo,
|
|
166
195
|
2.2:1), `success` and `warning` with 15 % white (5.0 and 6.3:1), `error` with
|
|
167
196
|
30 % white (5.9:1), and `secondary` and `info` use the token (4.6 and 5.3:1).
|
|
168
197
|
The tones are mixed from the tokens (`color-mix(in oklab, var(--color-error)
|
|
169
198
|
85%, black)`), so an override of a token moves its tone with it; a text colour
|
|
170
|
-
of your own on one of those buttons (`class="text-primary"`) replaces the tone
|
|
199
|
+
of your own on one of those buttons (`class="text-primary-text"`) replaces the tone
|
|
171
200
|
and is yours to check.
|
|
172
201
|
|
|
173
202
|
A `Badge` used as a link (`as-child` around an `<a>`) darkens on hover like a filled
|
|
@@ -230,12 +259,31 @@ and `.dark, [data-theme="dark"]` moves it, but setting `--error-text` or
|
|
|
230
259
|
`--color-error-text` (and `--color-error` for fills) on that element, or put
|
|
231
260
|
the override on the root.
|
|
232
261
|
|
|
262
|
+
**Primary text has a token of its own**, `--primary-text` (`text-primary-text`),
|
|
263
|
+
for the same reason: the brand colour is a dark fill (it keeps near-white text
|
|
264
|
+
readable on a button) and reads at only about 2:1 as text on the dark surfaces.
|
|
265
|
+
The light value is `var(--primary)`; the dark one is
|
|
266
|
+
`color-mix(in oklab, var(--primary) 40%, white)` (primary mixed 60 % with
|
|
267
|
+
white, the recipe of the tonal `Button` labels). `Typography tone="primary"`,
|
|
268
|
+
the `Alert` primary icon, links, selected labels and the other primary text of
|
|
269
|
+
the catalogue use it.
|
|
270
|
+
|
|
271
|
+
- **`text-primary-text`** for primary written as text, or an icon beside that
|
|
272
|
+
text, on a page, card or popover surface.
|
|
273
|
+
- **`text-primary`** (with `bg-primary`, `border-primary`, `ring-primary`) for
|
|
274
|
+
fills, borders and rings. Text on a primary fill is `text-primary-foreground`.
|
|
275
|
+
|
|
276
|
+
Like `--error-text`, it is computed where it is declared, on the root: an
|
|
277
|
+
override of `--primary` under `:root` and `.dark, [data-theme="dark"]` moves it
|
|
278
|
+
(override `--primary-text` itself after it to pick another dark colour); below
|
|
279
|
+
the root, set `--color-primary-text` on the element.
|
|
280
|
+
|
|
233
281
|
Storybook's `Guides/Theming/Contrast` measures all of this in both themes:
|
|
234
282
|
the surfaces' text, the error text (`HelperText` and a field's message on
|
|
235
283
|
`--background` and `--card`), the `Alert`s and the `Timeline`, `Button` and
|
|
236
284
|
`IconButton` in every variant and colour, and a `Badge` link in every colour,
|
|
237
285
|
at rest, hovered, focused and pressed, the tracks and the tabs;
|
|
238
|
-
`Data display/ListTile` measures the selected tile, `Data table, filter & lists/DataTable/On a card` the header, the cells, the links and the selected rows on a page and on a `Card` (also right-to-left), and `Feedback & status/Alert/Tones contrast`
|
|
286
|
+
`Data display/ListTile` measures the selected tile, `Data table, filter & lists/DataTable/On a card` the header, the cells, the links and the selected rows on a page and on a `Card` (also right-to-left), and `Feedback & status/Alert/Tones contrast` every alert tone there, and `Primitives/Typography/Tones contrast` the text tones (primary included). Run them against your own
|
|
239
287
|
tokens after an override.
|
|
240
288
|
|
|
241
289
|
**Tabs.** An `underline` tab's active label is `--primary` in the light
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# The Vite plugin: `nxgtMaterial()`
|
|
2
|
+
|
|
3
|
+
One plugin for the build-time work `@nxgt/material-vue` asks of a Vite app: a strict
|
|
4
|
+
Content Security Policy that needs no hand-written nonce, fonts that survive
|
|
5
|
+
`font-src 'self'`, and a build that fails, with the exact fix, when the
|
|
6
|
+
stylesheet is not wired.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
// vite.config.ts
|
|
10
|
+
import { nxgtMaterial } from '@nxgt/material-vue/vite';
|
|
11
|
+
import vue from '@vitejs/plugin-vue';
|
|
12
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
13
|
+
import { defineConfig } from 'vite';
|
|
14
|
+
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
plugins: [vue(), tailwindcss(), ...nxgtMaterial()],
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`nxgtMaterial()` returns an array of plugins, hence the spread. Put it last in `plugins` and add no HTML minifier or rewriting plugin after it: a hash covers exact text, and anything that changes the inline scripts later invalidates it.
|
|
21
|
+
|
|
22
|
+
Every part is on by default and has an opt-out. It needs `vite` 5.2 or later (6, 7, 8; on Vite 5, as under Nuxt 3, every check runs as for the client).
|
|
23
|
+
|
|
24
|
+
| Option | Default | What it does |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `csp` | on, `mode: 'hash'` | Puts zod's jitless script in `index.html`, then writes the hash of every inline script and style of the built HTML to `nxgt-csp.json`; the header uses the script hashes. `csp: false` turns it all off |
|
|
27
|
+
| `csp.mode` | `'hash'` | `'hash'`: no placeholder ever lands in the HTML. `'nonce'`: the HTML carries a placeholder your server replaces on every request |
|
|
28
|
+
| `csp.placeholder` | `CSP_NONCE_PLACEHOLDER` | Nonce mode only: your own placeholder (or set Vite's `html.cspNonce`, which the plugin then reuses) |
|
|
29
|
+
| `csp.zodJitless` | `true` | The inline script that switches zod's `new Function` probe off |
|
|
30
|
+
| `csp.dev` | `true` | A `Content-Security-Policy-Report-Only` header on the dev server |
|
|
31
|
+
| `csp.policy` | `{}` | `cspPolicy` options (`directives`, `hashes`) added to the dev and generated headers |
|
|
32
|
+
| `fonts.katex` | `true` | Never inline a font as a `data:` URI (`cspAssetsInlineLimit`), composed with your own `build.assetsInlineLimit` |
|
|
33
|
+
| `fonts.sans` | `'inter'` | Loads self-hosted Inter when `@fontsource-variable/inter` is installed (otherwise warns and keeps the system stack), in your root stylesheet, and sets `--font-sans`; `false` to keep the system stack and silence the warning. `fonts: false` turns both off |
|
|
34
|
+
| `styles.check` | `true` | Fails `vite build` when the library's stylesheet is never imported (`@nxgt/material-vue/styles.css`, or the compiled one through `@import "@nxgt/material-vue";`) |
|
|
35
|
+
| `pdf` | on | pdfkit's standard fonts (`pdfkitStandardFonts()`): a no-op unless pdfkit goes through the bundle. `pdf: false` turns it off |
|
|
36
|
+
| `pdf.bundle` | `false` | Also adds the renderer to `ssr.noExternal`, for a server whose runtime image has no `node_modules` (see [Rendering PDFs on a bundled server](#rendering-pdfs-on-a-bundled-server)) |
|
|
37
|
+
|
|
38
|
+
## The two CSP modes
|
|
39
|
+
|
|
40
|
+
### Hash mode (default): safe on a static host
|
|
41
|
+
|
|
42
|
+
The build computes the sha256 of every inline `<script>` and `<style>` of the
|
|
43
|
+
built `index.html` (zod's jitless script, and anything of yours) and writes:
|
|
44
|
+
|
|
45
|
+
- `dist/.vite/nxgt-csp.json`: `{ mode, scriptHashes, styleHashes, header }`;
|
|
46
|
+
- a line in the build log with the ready-to-paste header.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-…'; style-src-elem 'self' 'unsafe-inline'; …
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Scripts are allowed by hash only. `<style>` elements are allowed by
|
|
53
|
+
`'unsafe-inline'`: the components create some at runtime (`ScrollArea` and
|
|
54
|
+
`Select`, the modals' scroll lock, the rich text editor), which no build can
|
|
55
|
+
hash, and a browser ignores `'unsafe-inline'` as soon as a hash or a nonce is
|
|
56
|
+
in the same directive. So the header carries no style hash; `styleHashes` in
|
|
57
|
+
the JSON is there for a stricter policy you write yourself (it would block
|
|
58
|
+
those runtime `<style>` elements). An inline style runs no code; for a
|
|
59
|
+
`style-src-elem` without `'unsafe-inline'`, use nonce mode.
|
|
60
|
+
|
|
61
|
+
Send that header from your host (a `_headers` file, a CDN rule, the web
|
|
62
|
+
server). The HTML holds no placeholder and no nonce, so nothing public can be
|
|
63
|
+
mistaken for a secret. Rebuild, and the hashes follow the HTML. A hash covers
|
|
64
|
+
exact text: an inline script a CDN or a tag manager rewrites no longer matches.
|
|
65
|
+
|
|
66
|
+
### Nonce mode: for an app with a server
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
nxgtMaterial({ csp: { mode: 'nonce' } })
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Vite's `html.cspNonce` is set to `NXGT_CSP_NONCE`, so every script, link and
|
|
73
|
+
`meta` of `index.html` carries `nonce="NXGT_CSP_NONCE"`. **That value is
|
|
74
|
+
public: never serve it as it is.** On every request, replace it:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { applyCspNonce, cspPolicy, createCspNonce } from '@nxgt/material-vue/lib';
|
|
78
|
+
|
|
79
|
+
const nonce = createCspNonce();
|
|
80
|
+
const html = applyCspNonce(builtHtml, nonce);
|
|
81
|
+
res.setHeader('Content-Security-Policy', cspPolicy({ nonce }).header);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
`applyCspNonce` and `cspPolicy({ nonce })` throw when given the placeholder as
|
|
85
|
+
the nonce. `nxgt-csp.json` still lists the header, with the placeholder in
|
|
86
|
+
it, as a template to read, not to serve.
|
|
87
|
+
|
|
88
|
+
Pick nonce mode when a server renders or serves your HTML and can run
|
|
89
|
+
`applyCspNonce`; pick hash mode for a static host. Nonce mode is also the
|
|
90
|
+
strict option for styles: `style-src-elem 'self' 'nonce-…'`, no
|
|
91
|
+
`'unsafe-inline'`.
|
|
92
|
+
|
|
93
|
+
## The dev server
|
|
94
|
+
|
|
95
|
+
`csp.dev` sends `Content-Security-Policy-Report-Only` (hash mode: no nonce,
|
|
96
|
+
and the hash of zod's jitless script when `csp.zodJitless` is on; nonce mode:
|
|
97
|
+
the placeholder, as the dev HTML carries it) with `ws:` for HMR.
|
|
98
|
+
Report-Only never blocks, so Vite's own inline scripts are reported and
|
|
99
|
+
that is expected. Vite's dev `<style>` elements (your CSS, injected in dev
|
|
100
|
+
only: `vite build` emits stylesheet files) are allowed by `'unsafe-inline'` in
|
|
101
|
+
hash mode and carry the placeholder in nonce mode.
|
|
102
|
+
|
|
103
|
+
## Fonts
|
|
104
|
+
|
|
105
|
+
- **`fonts.katex`**: Vite inlines an asset under 4096 bytes as a `data:` URI,
|
|
106
|
+
and `font-src 'self'` blocks it (KaTeX's `KaTeX_Size3-Regular.woff2` is
|
|
107
|
+
3.6 KB). The plugin sets `build.assetsInlineLimit` so a font is always a
|
|
108
|
+
file. Your own function or number still applies to every other asset.
|
|
109
|
+
- **`fonts.sans: 'inter'`**: in the stylesheet that imports
|
|
110
|
+
`@nxgt/material-vue/styles.css`, the plugin imports `@fontsource-variable/inter` first
|
|
111
|
+
and appends an unlayered `:root { --font-sans: "Inter Variable", … }` that
|
|
112
|
+
beats Tailwind's layered theme variable. Nothing is added when that
|
|
113
|
+
stylesheet (or a file it imports) already imports Inter or sets
|
|
114
|
+
`--font-sans` itself. A JavaScript `import '@fontsource-variable/inter'` is
|
|
115
|
+
not detected: pair it with `fonts: { sans: false }`. The package is an optional peer
|
|
116
|
+
and Inter loads only when your app has it installed:
|
|
117
|
+
`bun add @fontsource-variable/inter`. Without it the plugin warns once, in
|
|
118
|
+
dev and in `vite build`, keeps the system font stack and never fails the
|
|
119
|
+
build; `fonts: { sans: false }` turns Inter off and silences the warning.
|
|
120
|
+
|
|
121
|
+
## The styles check
|
|
122
|
+
|
|
123
|
+
`vite build` (client only; not under Vitest, not for `build.ssr`) fails when
|
|
124
|
+
the library's stylesheet is imported by no stylesheet and no module. Either
|
|
125
|
+
route passes: `@nxgt/material-vue/styles.css` (with Tailwind; it already
|
|
126
|
+
scans the package, so Vue needs no `@source`), or the compiled stylesheet of
|
|
127
|
+
an app without Tailwind, `@import "@nxgt/material-vue";` (the package's
|
|
128
|
+
`style` condition, see [theming](theming.md#without-tailwind)). The error message names the
|
|
129
|
+
exact `@import` line to add.
|
|
130
|
+
|
|
131
|
+
Opt out with `styles: false` (a Storybook build, for instance, may not import
|
|
132
|
+
it).
|
|
133
|
+
|
|
134
|
+
## Rendering PDFs on a bundled server
|
|
135
|
+
|
|
136
|
+
`pdf` is on by default and costs nothing for an app that never renders a PDF:
|
|
137
|
+
the transform only touches modules whose id contains `pdfkit`. Add
|
|
138
|
+
`pdf: { bundle: true }` to a Vite SSR server whose runtime image ships the
|
|
139
|
+
bundle alone:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
// vite.config.ts (an SSR server)
|
|
143
|
+
export default defineConfig({
|
|
144
|
+
plugins: [...nxgtMaterial({ pdf: { bundle: true } })],
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`bundle: true` puts `@nxgt/material-vue`, `@nxgt/material-core`, `pdfkit`, `@react-pdf/*`
|
|
149
|
+
and every dependency the renderer, pdfkit and core need at runtime (fontkit, yoga, png-js… read
|
|
150
|
+
from your installed packages, so the list follows the renderer's releases) into
|
|
151
|
+
`ssr.noExternal`, merged with your own array; `ssr.noExternal: true` is left as
|
|
152
|
+
it is. What it does not touch is yours to bundle the way you bundle the rest of
|
|
153
|
+
your server: `react` (the renderer's peer) and your app's other dependencies,
|
|
154
|
+
for example `ssr: { noExternal: ['react'] }`. The library's own
|
|
155
|
+
dependencies (a router, charts) are not walked, so a second copy never splits
|
|
156
|
+
their contexts. Under Yarn PnP there is no `node_modules` to read: only the
|
|
157
|
+
fixed names apply, and you list the renderer's dependencies yourself. Without `bundle`, the renderer
|
|
158
|
+
stays external and loads pdfkit's fonts from `node_modules`, as designed. See
|
|
159
|
+
[PDF documents](pdf.md#fonts-on-a-fully-inlined-server).
|
|
160
|
+
|
|
161
|
+
## Nuxt
|
|
162
|
+
|
|
163
|
+
The Nuxt module (`@nxgt/material-vue/nuxt`) calls `nxgtMaterial()` for you and
|
|
164
|
+
maps its own options onto it. Under Nuxt:
|
|
165
|
+
|
|
166
|
+
| Part | What the module does |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `csp` | **Off.** Nuxt has no `index.html` for the plugin to hash or stamp, and a header on Vite's dev server never reaches the pages Nitro renders. The module sets no policy and sends no header: use `nuxt-security` for the CSP (its `nonce: true`, or its script hashes for prerendered pages) |
|
|
169
|
+
| `csp.zodJitless` | Opt-in (`nxgtMaterial: { csp: { zodJitless: true } }`): the script goes into `app.head.script` with `tagPriority: 'critical'`. It is inline: `nuxt-security` with `nonce: true` stamps it, otherwise a strict `script-src` blocks it |
|
|
170
|
+
| `fonts.katex` | On: a font is never inlined as a `data:` URI |
|
|
171
|
+
| `fonts.sans: 'inter'` | Opt-in: `@fontsource-variable/inter` and the `--font-sans` override are put first in `nuxt.options.css`. A missing package warns once and keeps the system font; the build never fails |
|
|
172
|
+
| `styles` | **Off** by default: Nuxt resolves `css` entries before Vite sees them. `styles: true` opts in |
|
|
173
|
+
| `pdf` | Nitro owns it, not Vite: `pdf.bundle` adds `pdfkitStandardFonts()` to the Nitro Rollup config (`pdf.bundleStandardFonts` is its deprecated name), and the module always traces pdfkit's font files into `.output/server/node_modules` |
|
|
174
|
+
|
|
175
|
+
Why hash mode is not used under Nuxt: a Nuxt app is server-rendered, so its
|
|
176
|
+
HTML is built per request, not once at build time. A policy that lists hashes
|
|
177
|
+
of a build-time `index.html` would describe a file that does not exist.
|
|
178
|
+
|
|
179
|
+
## Other frameworks without an `index.html`
|
|
180
|
+
|
|
181
|
+
Other SSR frameworks have no `index.html` to transform either: the CSP part
|
|
182
|
+
finds nothing to hash, the build warns once (`no index.html in this build: the
|
|
183
|
+
CSP part did nothing`) and the dev header only fits Vite's own server. On a
|
|
184
|
+
server, send `cspPolicy({ nonce }).header` and `zodJitlessTag(nonce)` per
|
|
185
|
+
request, or pass `csp: false`. The fonts part still works there, since it
|
|
186
|
+
rewrites the stylesheet rather than the HTML.
|
|
187
|
+
|
|
188
|
+
## Without the plugin
|
|
189
|
+
|
|
190
|
+
Everything above has a manual route: [CSP guide](csp.md) (KaTeX, Inter, zod,
|
|
191
|
+
SSR).
|
|
192
|
+
|
|
193
|
+
Migrating an app that wrote its own CSP header, nonce, zod setting or PDF bundling:
|
|
194
|
+
[Migrating to the Vite plugin](migrate-to-vite-plugin.md).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/roadmap.md
CHANGED
|
@@ -6,41 +6,15 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
6
6
|
|
|
7
7
|
## Now
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
`ErrorState` in three sizes (`default`, `compact`, `inline`), with in-house
|
|
11
|
-
inline SVG illustrations or a slot for your own. `ErrorState` is a
|
|
12
|
-
`role="alert"` with a Retry action and collapsible technical details. Every
|
|
13
|
-
built-in empty or error state uses them — the `DataTable` default (your
|
|
14
|
-
`#empty` slot and `empty` prop still replace it), `PdfReader`, `CommandEmpty`,
|
|
15
|
-
the gallery, the kanban board, chat and the partials. Ships in
|
|
16
|
-
`@nxgt/material-vue` 1.0, with the rest of the redesign.
|
|
9
|
+
Nothing is in progress right now.
|
|
17
10
|
|
|
18
11
|
## Next
|
|
19
12
|
|
|
20
|
-
- **
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
helpers that exist today stay exported.
|
|
26
|
-
- `csp`: a nonce placeholder through `html.cspNonce` and
|
|
27
|
-
`applyCspNonce(html, nonce)` to fill it; zod's jitless mode set by an
|
|
28
|
-
inline nonced script in `index.html` (`ZOD_JITLESS_SCRIPT` for a server
|
|
29
|
-
that renders the page itself); and the recommended policy sent by the dev
|
|
30
|
-
server as Report-Only.
|
|
31
|
-
- `fonts`: the KaTeX fonts emitted as files, and `sans: 'inter'` for a
|
|
32
|
-
self-hosted Inter.
|
|
33
|
-
- `styles`: a build that fails with the exact fix when the stylesheet import
|
|
34
|
-
or the `@source` line is missing.
|
|
35
|
-
- `pdf`: pdfkit's standard fonts handled automatically when
|
|
36
|
-
`@react-pdf/renderer` is installed, and `bundle: true` (the Nuxt module's
|
|
37
|
-
`pdf.bundleStandardFonts` today) for a server that has no
|
|
38
|
-
`node_modules`.
|
|
39
|
-
- Nuxt: the Nuxt module takes the same options.
|
|
40
|
-
- On the server, `@nxgt/material-core` gains `createCspNonce()` (Web Crypto)
|
|
41
|
-
and `cspPolicy({ ... })`, which returns `{ directives, header }` as the
|
|
42
|
-
[Content Security Policy guide](guides/csp.md) describes; `NonceProvider`'s
|
|
43
|
-
`nonce` becomes optional on the client. Ships as minors.
|
|
13
|
+
- **1.0: `EmptyState` is only about absence** — `variant` is removed, the
|
|
14
|
+
`generic`, `offline` and `maintenance` kinds leave `EmptyState` for
|
|
15
|
+
`ErrorState`, and `kind` defaults to `empty` (it is `generic` until then).
|
|
16
|
+
The upgrade is in
|
|
17
|
+
[Migrating from `variant`](components/feedback-and-status.md#migrating-from-variant).
|
|
44
18
|
- **One media player, video and audio** — `MediaPlayer`, `MediaPlayerMini`,
|
|
45
19
|
`useMediaPlayer` and `AudioPlayer`, built on the native `<video>` / `<audio>`.
|
|
46
20
|
`StxPlayer` and `VideoPlayer` are removed in `@nxgt/material-vue` 1.0, with a
|
|
@@ -94,6 +68,15 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
94
68
|
|
|
95
69
|
## Later
|
|
96
70
|
|
|
71
|
+
- **`PdfReader` can retry a failed load** — its empty and error blocks become
|
|
72
|
+
`EmptyState` and `ErrorState` (compact) with a Retry button and the error's
|
|
73
|
+
details, as in the React reader. Only on the owner's request:
|
|
74
|
+
softistx/nxgt-material#702.
|
|
75
|
+
- **Vue /backgrounds: more presets and motifs** — the presets and motifs added
|
|
76
|
+
to React after the base (more gradients, geometric patterns, motif scenes)
|
|
77
|
+
reach `@nxgt/material-vue/backgrounds` on the owner's explicit ask. Until
|
|
78
|
+
then a preset id the Vue build lacks draws the gradient (and warns in
|
|
79
|
+
development). Tracked in softistx/nxgt-material#706.
|
|
97
80
|
- **A CSP without `style-src-attr 'unsafe-inline'`** — the four form controls'
|
|
98
81
|
hidden inputs no longer need it; the checked `Checkbox` indicator,
|
|
99
82
|
`SelectValue`, the `RadioGroup` root, `Slider` and popper positioning still
|
|
@@ -167,6 +150,60 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
167
150
|
|
|
168
151
|
## Shipped
|
|
169
152
|
|
|
153
|
+
- **Empty and error states that look designed** — `EmptyState` with its
|
|
154
|
+
`kind` (`empty`, `search`, `not-found`, `unauthorized`) and a new
|
|
155
|
+
`ErrorState` (`generic`, `offline`, `maintenance`), each in two sizes
|
|
156
|
+
(`default`, `compact`), with in-house inline SVG illustrations or your own in
|
|
157
|
+
the `#illustration` slot. `ErrorState` is a `role="alert"` with a Retry
|
|
158
|
+
action and collapsible technical details. The `DataTable` default (your
|
|
159
|
+
`#empty` slot still replaces it, and `#empty-filtered` covers a filter that
|
|
160
|
+
hides every row), `CommandEmpty` and the built-in empty states that were
|
|
161
|
+
hand-rolled (notifications, gallery, quiz, sortable and transfer lists,
|
|
162
|
+
kanban, chat, charts, contacts, postal address, attributes, opening hours,
|
|
163
|
+
the player and the event calendar) use them. `variant` still works and is
|
|
164
|
+
deprecated. 0.43.0.
|
|
165
|
+
([EmptyState](components/feedback-and-status.md#emptystate),
|
|
166
|
+
[ErrorState](components/feedback-and-status.md#errorstate))
|
|
167
|
+
- **Background presets, the base** — `Background` from `@nxgt/material-vue/backgrounds`,
|
|
168
|
+
a superset of the one in `/components`: `preset` (`gradient` or `grain`),
|
|
169
|
+
`tone`, `intensity`, `animated` (drifts, and pauses while the page is hidden,
|
|
170
|
+
the background is off screen or the user prefers reduced motion), `grain`,
|
|
171
|
+
`seed` and `fill`. The SVG is built from plain data, so the server and the
|
|
172
|
+
client render the same markup and a strict CSP accepts it. The stylesheets
|
|
173
|
+
(`backgrounds.css`, `backgrounds/<preset>.css`) are opt-in. The grain's look
|
|
174
|
+
may still change.
|
|
175
|
+
|
|
176
|
+
- **One Vite plugin for the whole setup** — `nxgtMaterial()` from
|
|
177
|
+
`@nxgt/material/vite` and `@nxgt/material-vue/vite` (one implementation in
|
|
178
|
+
`@nxgt/material-core/vite`) wires the library into a Vite app, each part on
|
|
179
|
+
by default and each switchable off; the helpers that existed before stay
|
|
180
|
+
exported ([Vite plugin guide](guides/vite-plugin.md), and the migration guide moves a hand-written setup over). You get:
|
|
181
|
+
- `csp`: `mode: 'hash'` (default) writes the sha256 of every inline script
|
|
182
|
+
and style to `dist/.vite/nxgt-csp.json` with the header, or `mode: 'nonce'`
|
|
183
|
+
leaves a placeholder for `applyCspNonce`; zod's jitless script; a
|
|
184
|
+
Report-Only header on the dev server. `createCspNonce()`, `cspPolicy()`
|
|
185
|
+
and `cspHash()` ship in `@nxgt/material-core/csp`.
|
|
186
|
+
- `fonts`: `katex` (fonts stay files) and `sans: 'inter'` (self-hosted Inter).
|
|
187
|
+
- `styles`: a build that fails with the exact fix when the stylesheet import
|
|
188
|
+
or React's `@source` line is missing.
|
|
189
|
+
- `pdf`: pdfkit's standard fonts handled by the same plugin, with
|
|
190
|
+
`bundle: true` for an SSR server with no `node_modules`. The Nuxt module
|
|
191
|
+
calls `nxgtMaterial()` with the same `fonts`, `styles` and `pdf` options
|
|
192
|
+
(`pdf.bundleStandardFonts` is deprecated for `pdf.bundle`) and adds zod's
|
|
193
|
+
jitless script to the head on request; its CSP stays `nuxt-security`'s.
|
|
194
|
+
- `NonceProvider`'s `nonce` is optional on the client (it reads the page's
|
|
195
|
+
nonce from its first render).
|
|
196
|
+
Shipped in 0.43.0.
|
|
197
|
+
|
|
198
|
+
- **The app's brand, a header title and an account menu** — the app shell
|
|
199
|
+
takes the app's `logo` and `name`: the logo alone in the collapsed rail,
|
|
200
|
+
named by the app's name and shown as its tooltip, the logo and the name side
|
|
201
|
+
by side expanded and in the phone's menu sheet, which now shows `brand` too;
|
|
202
|
+
`#header-title`, the context the app is in, right after the phone's menu
|
|
203
|
+
button and truncated when long; and `AccountMenu`, the avatar button named
|
|
204
|
+
"Account menu, <name>" that opens the account's name and e-mail, the app's
|
|
205
|
+
links and a busy-aware Sign out (`sign-out`).
|
|
206
|
+
|
|
170
207
|
- **Rows a user adds, removes and reorders** — `RepeatableGroup` and
|
|
171
208
|
`RepeatableGroupFormField` over the form library's field array: rows from
|
|
172
209
|
the `row` slot, a list for assistive tech, Remove and move buttons named after
|