@nxgt/material-vue 0.42.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 +111 -0
- package/README.md +18 -5
- package/dist/{Button-CWmzvv9p.js → Button-C3K6dhqd.js} +4 -4
- package/dist/{HoverCardTrigger-C5AbAyHE.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-C-9slBUV.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-DX4EycMi.js → components-yCdbry6Q.js} +14077 -13577
- package/dist/components.js +8 -8
- package/dist/composables.js +3 -3
- package/dist/dnd.js +1 -1
- package/dist/{form-scope-CN68PTXc.js → form-scope-CkWJrBCu.js} +1 -1
- package/dist/{i18n-provider-DmZSTBnp.js → i18n-provider-tL27-a8y.js} +1 -1
- package/dist/i18n.js +4 -4
- package/dist/{icon-button-DErh1aJS.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/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/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 +24 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +25 -1
- package/dist/lib/i18n/resources/fr/fr.d.ts +24 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +25 -1
- package/dist/lib/i18n/resources/resources.d.ts +48 -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-BU4o_hBI.js → pdf-outline-sidebar-Kqsfd_cO.js} +2 -2
- package/dist/{pdf-page-anNe78Lc.js → pdf-page-Dx3jwxu6.js} +1 -1
- package/dist/{pdf-page-list-CSY76HH6.js → pdf-page-list-BsQmEHaY.js} +2 -2
- package/dist/{pdf-reader-BhZNrW7R.js → pdf-reader-CJo8SQVl.js} +15 -15
- package/dist/{pdf-sidebar-DcIpG7eh.js → pdf-sidebar-CcCUATl-.js} +3 -3
- package/dist/{pdf-thumbnail-sidebar-CUC0V4if.js → pdf-thumbnail-sidebar-BRxNRGfG.js} +4 -4
- package/dist/{pdf-toolbar-C373S-ul.js → pdf-toolbar-B0ckYBJ2.js} +4 -4
- package/dist/pdf.js +2 -2
- package/dist/{print-format.utils-C81c0weJ.js → print-format.utils-51joHpFb.js} +2 -2
- package/dist/{sortable-provider-CL2UGGn8.js → sortable-provider-BEx1B0Ky.js} +2 -2
- package/dist/{stored-language-Wtcj2HsU.js → stored-language-DVP9KzRu.js} +50 -2
- package/dist/{stx-player-CMmM3F5Z.js → stx-player-KPp9c7vS.js} +12 -12
- package/dist/styles.css +4 -0
- package/dist/{translator-D5Dp-dob.js → translator-Bm7i7dv-.js} +1 -1
- package/dist/use-background-activity-DdTBbNpX.js +17 -0
- package/dist/{use-heading-spy-BIBHtUXN.js → use-heading-spy-jn8f2ioE.js} +13 -13
- package/dist/{use-material-translation-COoBTGpB.js → use-material-translation-CfFZPSe0.js} +3 -3
- package/dist/vite.js +7 -2
- package/docs/README.md +3 -0
- 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 +13 -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 +1 -1
- 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 +51 -1
- 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/roadmap.md +60 -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 +1 -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
|
@@ -11,7 +11,8 @@ centre. Everything is imported from `@nxgt/material-vue/components`.
|
|
|
11
11
|
| <img src="../previews/feedback-status-alertdialog.webp" width="96" alt=""> | [AlertDialog](#alertdialog) | Parts for a blocking confirmation dialog |
|
|
12
12
|
| <img src="../previews/feedback-status-confirmdialog.webp" width="96" alt=""> | [ConfirmDialog](#confirmdialog) | Confirm / cancel dialog, `ConfirmationDialog`, `CustomAlertDialog` |
|
|
13
13
|
| <img src="../previews/feedback-status-customdialog.webp" width="96" alt=""> | [CustomDialog](#customdialog) | Ready-made dialog with trigger, icon, title, body and footer |
|
|
14
|
-
| <img src="../previews/feedback-status-emptystate.webp" width="96" alt=""> | [EmptyState](#emptystate) |
|
|
14
|
+
| <img src="../previews/feedback-status-emptystate.webp" width="96" alt=""> | [EmptyState](#emptystate) | Illustration, title, description and action, by kind (empty, search, not-found, unauthorized) |
|
|
15
|
+
| <img src="../previews/feedback-status-errorstate.webp" width="96" alt=""> | [ErrorState](#errorstate) | Failure block with Retry and technical details |
|
|
15
16
|
| <img src="../previews/feedback-status-progress.webp" width="96" alt=""> | [Progress](#progress) | Linear bar, circular ring and labelled progress field |
|
|
16
17
|
| <img src="../previews/feedback-status-scrollprogress.webp" width="96" alt=""> | [ScrollProgress](#scrollprogress) | Hairline tracking the window or a scrollable element |
|
|
17
18
|
| <img src="../previews/feedback-status-spinner.webp" width="96" alt=""> | [Spinner](#spinner) | Loading spinner in several styles and colours |
|
|
@@ -412,8 +413,7 @@ icon for that reason now needs an element such as a `Button` or `IconButton`.
|
|
|
412
413
|
|
|
413
414
|

|
|
414
415
|
|
|
415
|
-
|
|
416
|
-
unauthorized, generic, empty, offline, search and maintenance presets.
|
|
416
|
+
A calm absence: an illustration (an icon when `size="compact"`), title, description and action, for the `empty`, `search`, `not-found` and `unauthorized` kinds. Text is `text-foreground` and reads at 7:1. For something that failed, use an error state instead.
|
|
417
417
|
|
|
418
418
|
```vue
|
|
419
419
|
<script setup lang="ts">
|
|
@@ -423,7 +423,7 @@ function clearFilters() {}
|
|
|
423
423
|
</script>
|
|
424
424
|
|
|
425
425
|
<template>
|
|
426
|
-
<EmptyState
|
|
426
|
+
<EmptyState kind="search">
|
|
427
427
|
<template #action>
|
|
428
428
|
<Button variant="outlined" @click="clearFilters">Clear filters</Button>
|
|
429
429
|
</template>
|
|
@@ -433,17 +433,88 @@ function clearFilters() {}
|
|
|
433
433
|
|
|
434
434
|
| Prop | Type | Default | Effect |
|
|
435
435
|
| --- | --- | --- | --- |
|
|
436
|
-
| `
|
|
437
|
-
|
|
|
438
|
-
| `
|
|
436
|
+
| `kind` | `'empty' \| 'search' \| 'not-found' \| 'unauthorized'` | `'generic'` (legacy, until 1.0) | illustration, icon, title and description |
|
|
437
|
+
| `size` | `'default' \| 'compact'` | `'default'` | `compact` swaps the illustration for a small icon and tightens the spacing |
|
|
438
|
+
| `variant` | the four kinds, plus `'generic' \| 'offline' \| 'maintenance'` | — | **deprecated**, removed in 1.0: use `kind`; the error values render without `role="alert"` |
|
|
439
|
+
| `#illustration` slot | — | the kind's | replaces the illustration |
|
|
440
|
+
| `#icon` slot | — | the kind's | replaces the icon |
|
|
441
|
+
| `title` / `description` | `string` (or `#title` / `#description`) | the kind's (translated) | replace the kind's text; see below |
|
|
439
442
|
| `#action` slot | — | — | shown under the text |
|
|
440
443
|
|
|
441
|
-
The
|
|
444
|
+
The default 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.
|
|
445
|
+
|
|
446
|
+
`EmptyState` cannot hide its media yet, unlike React's `illustration={false}` ([#711](https://github.com/softistx/nxgt-material/issues/711)); `ErrorState` can, with `:illustration="false"`.
|
|
447
|
+
|
|
448
|
+
`<EmptyState />` with no `kind` or `variant` still renders the `generic` (error) copy until 1.0; pass `kind`.
|
|
449
|
+
|
|
450
|
+
### Migrating from `variant`
|
|
451
|
+
|
|
452
|
+
`variant` still works and is removed in 1.0. Until then:
|
|
453
|
+
|
|
454
|
+
| Before | After |
|
|
455
|
+
| --- | --- |
|
|
456
|
+
| `variant="empty"`, `"search"`, `"not-found"`, `"unauthorized"` | `kind="…"` with the same value |
|
|
457
|
+
| `variant="generic"`, `"offline"`, `"maintenance"` | `<ErrorState kind="…">`: it is a `role="alert"` block with Retry and technical details; an `EmptyState` error `variant` has no `role` |
|
|
458
|
+
| no `variant` | pass `kind`: the default stays `generic` until 1.0, then becomes `empty` |
|
|
459
|
+
| class overrides to shrink it (`min-h-0`, smaller padding) | `size="compact"`: a small icon, no minimum height |
|
|
460
|
+
| `material.empty-state.generic\|offline\|maintenance.*` overrides | the same text under `material.error-state.<kind>.*` |
|
|
461
|
+
|
|
462
|
+
```vue
|
|
463
|
+
<!-- before -->
|
|
464
|
+
<EmptyState variant="offline" />
|
|
465
|
+
<EmptyState variant="search" class="min-h-0 py-6" />
|
|
466
|
+
|
|
467
|
+
<!-- after -->
|
|
468
|
+
<ErrorState kind="offline" @retry="refetch" />
|
|
469
|
+
<EmptyState kind="search" size="compact" />
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
In 1.0, `variant` goes, the error kinds leave `EmptyState`, and `kind` defaults to `empty`. The DOM keeps `data-slot="empty-state"` and `data-variant`, and adds `data-kind` and `data-size`.
|
|
442
473
|
|
|
443
474
|
**Storybook:** `Feedback & status/EmptyState` · **React:** `EmptyState`
|
|
444
475
|
|
|
445
476
|
---
|
|
446
477
|
|
|
478
|
+
## ErrorState
|
|
479
|
+
|
|
480
|
+

|
|
481
|
+
|
|
482
|
+
Failure block with `role="alert"`, an illustration, an optional outlined Retry
|
|
483
|
+
and collapsed technical details (name, message and causes, never the stack).
|
|
484
|
+
Text reads at 7:1 in both themes.
|
|
485
|
+
|
|
486
|
+
```vue
|
|
487
|
+
<script setup lang="ts">
|
|
488
|
+
import { ErrorState } from '@nxgt/material-vue/components';
|
|
489
|
+
</script>
|
|
490
|
+
|
|
491
|
+
<template>
|
|
492
|
+
<ErrorState kind="offline" :error="error" @retry="refetch" />
|
|
493
|
+
</template>
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
| Prop | Type | Default | Effect |
|
|
497
|
+
| --- | --- | --- | --- |
|
|
498
|
+
| `kind` | `'generic' \| 'offline' \| 'maintenance'` | `'generic'` | illustration, title and description (`material.error-state.<kind>.*`) |
|
|
499
|
+
| `size` | `'default' \| 'compact'` | `'default'` | compact swaps the illustration for an icon |
|
|
500
|
+
| `title` / `description` | `string` | the kind's (translated) | replace the text; a custom `title` drops the default description |
|
|
501
|
+
| `illustration` | `boolean` | `true` | `:illustration="false"` hides the media |
|
|
502
|
+
| `#illustration` / `#icon` slots | — | the built-in illustration | replace the media |
|
|
503
|
+
| `#details` slot | — | the collapsed technical details | replaces them; React has no equivalent yet ([#712](https://github.com/softistx/nxgt-material/issues/712)) |
|
|
504
|
+
| `error` | `unknown` | none | the thrown value; its name, message and `cause` chain go in the details |
|
|
505
|
+
| `showDetails` | `boolean` | `true` when `error` is set | `false` hides the details |
|
|
506
|
+
| `@retry` | `() => unknown` | none | shows an outlined **Retry** button; a returned promise keeps it loading until it settles |
|
|
507
|
+
| `retrying` / `retryLabel` | `boolean` / `string` | derived / `Retry` | force the loading state; rename the button |
|
|
508
|
+
| `action` | the `#action` slot | none | extra actions after Retry |
|
|
509
|
+
|
|
510
|
+
The details are a native `<details>`: keyboard and server-render friendly.
|
|
511
|
+
Copy keys: `material.error-state.{generic,offline,maintenance}.{title,description}`,
|
|
512
|
+
`error-state.retry`, `error-state.details` and `error-state.details-name|message|cause`.
|
|
513
|
+
|
|
514
|
+
**Storybook:** `Feedback & status/ErrorState` · **React:** `ErrorState`
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
447
518
|
## Progress
|
|
448
519
|
|
|
449
520
|

|
|
@@ -624,6 +624,8 @@ Parts: `PdfReader` (`PdfViewer` is a deprecated alias), `PdfToolbar`, `PdfSideba
|
|
|
624
624
|
`PdfThumbnailSidebar`, `PdfOutlineSidebar`, `PdfPageList`, and the
|
|
625
625
|
`usePdfReader` composable for building your own layout.
|
|
626
626
|
|
|
627
|
+
A failed load shows the reader's own error; the React reader adds a Retry button to it, which is React-only for now ([#702](https://github.com/softistx/nxgt-material/issues/702)).
|
|
628
|
+
|
|
627
629
|
| Prop | Type | Default | Effect |
|
|
628
630
|
| --- | --- | --- | --- |
|
|
629
631
|
| `file` | `PdfSource \| null` | — (required) | a URL (`string` or `URL`), a `File` or `Blob`, an `ArrayBuffer` or `Uint8Array`, or `{ url, httpHeaders?, withCredentials? }`; `null` shows the empty state |
|
|
@@ -78,7 +78,7 @@ which work alone; `findActiveMenuItem`, `isMenuItemActive` and
|
|
|
78
78
|
| `avatarSrc` | `string` | — | avatar image in the header |
|
|
79
79
|
| `logo` (or `#logo`), `name` | `AppLogo` (`string \| AppLogoImage`, `AppLogoImage` = `{ src, alt? }`), `string` | — | the app's logo alone in the collapsed rail, named by `name` (also its tooltip); logo and name side by side in the phone's menu sheet; `#logo` wins over `logo` |
|
|
80
80
|
| `#brand` | slot | — | replaces the sidebar header, in the rail and the menu sheet; wins over `logo` and `name` |
|
|
81
|
-
| `#header-title` | slot | — | the header's leading title (the context: an organisation's name), after the phone's menu button, truncated when long |
|
|
81
|
+
| `#header-title` | slot | — | the header's leading title (the context: an organisation's name), after the phone's menu button, truncated when long; when it is cut off, its full text is the `title` tooltip (#629) |
|
|
82
82
|
| `#header-actions`, `#avatar` | slots | — | header, before the avatar; `#avatar` replaces it |
|
|
83
83
|
| `title`, `subtitle`, `#actions` | `string`, `string`, slot | — | `ActivityContent`'s header card |
|
|
84
84
|
| `#header` / `hideHeader` | slot / `boolean` | — / `false` | `ActivityContent`: replace or drop the header card |
|
|
@@ -780,7 +780,7 @@ Parts: `Doc` (the shell), `DocPage` (header, content, see also and pager);
|
|
|
780
780
|
the pieces it composes — `DocTopbar`, `DocSidebar`, `DocNav`, `DocArticle`,
|
|
781
781
|
`DocToc`, `DocPager`, `DocSearch`, `DocSeeAlso`, `DocChildCards`,
|
|
782
782
|
`DocProgress`, `DocSkipLink`, `DocHeader`, `DocCopyPage`, `DocCopyMarkdown`,
|
|
783
|
-
`DocLink` — and `DocEmpty` for a 404.
|
|
783
|
+
`DocLink` — and `DocEmpty` for a 404. `DocEmpty` is an `EmptyState` (`kind` defaults to `not-found`; `size` is `default` or `compact`): see [EmptyState](./feedback-and-status.md#emptystate).
|
|
784
784
|
`useDoc` / `provideDoc` / `useDocContext` expose the state for a shell of
|
|
785
785
|
your own, built from those parts:
|
|
786
786
|
|
|
@@ -878,9 +878,17 @@ import { Background, Card } from '@nxgt/material-vue/components';
|
|
|
878
878
|
</template>
|
|
879
879
|
```
|
|
880
880
|
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
881
|
+
| Prop | Values | Default |
|
|
882
|
+
| --- | --- | --- |
|
|
883
|
+
| `preset` | `gradient` (the only preset on `/components`) | `gradient` |
|
|
884
|
+
| `tone` | `primary`, `secondary`, `tertiary`, `neutral`, `success`, `warning`, `error`, `info`, `mixed` (primary, secondary and tertiary), `custom` (reads `--nxgt-bg-custom-1..3`) | `primary` |
|
|
885
|
+
| `intensity` | `subtle`, `default`, `vivid` | `default` |
|
|
886
|
+
| `animated` | drifts the blobs; paused while the page is hidden or the background is off screen, and never under reduced motion | `false` |
|
|
887
|
+
|
|
888
|
+
It fills the viewport; pass a `class` such as `h-96 w-full` to use it as a band.
|
|
889
|
+
It is plain CSS from `styles.css`, with no inline `style`, and its colours lift
|
|
890
|
+
in dark. `ActivityLayout` and `ThreadLayout` sit on it. The superset with `grain`,
|
|
891
|
+
`seed`, `fill` and the other presets is `Background` from `/backgrounds`; see the [backgrounds guide](../guides/backgrounds.md).
|
|
884
892
|
|
|
885
893
|
**Storybook:** `Navigation & layout/Background` · **React:** `Background`
|
|
886
894
|
|
|
@@ -39,7 +39,16 @@ default) leave the page as it is.
|
|
|
39
39
|
|
|
40
40
|

|
|
41
41
|
|
|
42
|
-
Modal dialog parts with a close button.
|
|
42
|
+
Modal dialog parts with a close button. An open `SelectField` list inside it has always taken the first Escape, as a layer of its own. So does an open `ComboboxField` or `Autocomplete` list: the second Escape closes the dialog. The same holds in a `Sheet`, a `Drawer`, an `AlertDialog` and a `Popover`.
|
|
43
|
+
|
|
44
|
+
Your own `@escape-key-down` on the content receives the Escape that only closes an open list with `event.defaultPrevented === true`; a handler that asks "close without saving?" returns early on it:
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<DialogContent @escape-key-down="(event) => {
|
|
48
|
+
if (event.defaultPrevented) return; // only an open list is closing
|
|
49
|
+
if (dirty) event.preventDefault(); // ask "close without saving?"
|
|
50
|
+
}">
|
|
51
|
+
```
|
|
43
52
|
|
|
44
53
|
```vue
|
|
45
54
|
<script setup lang="ts">
|
|
@@ -198,6 +207,8 @@ Vue.
|
|
|
198
207
|
|
|
199
208
|
Swipeable bottom or side drawer (Reka UI's drawer).
|
|
200
209
|
|
|
210
|
+
An `Autocomplete` inside a Drawer keeps its list floating, stopped above the Drawer's footer, and a drag that starts on the list scrolls it instead of dragging the Drawer.
|
|
211
|
+
|
|
201
212
|
```vue
|
|
202
213
|
<script setup lang="ts">
|
|
203
214
|
import {
|
|
@@ -638,20 +649,26 @@ Parts: `Command`, `CommandDialog`, `CommandInput`, `CommandList`,
|
|
|
638
649
|
`CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandShortcut`,
|
|
639
650
|
`CommandSeparator`.
|
|
640
651
|
|
|
652
|
+
`CommandEmpty` shows when the search matches nothing. With no children it
|
|
653
|
+
renders a compact `EmptyState` ("No results", `material.command.empty`); give it
|
|
654
|
+
children and they replace that, as before.
|
|
655
|
+
|
|
641
656
|
| Prop | Type | Default | Effect |
|
|
642
657
|
| --- | --- | --- | --- |
|
|
643
658
|
| `value` (`CommandItem`) | `string` | — (required) | the item's value, emitted by `@select` and by `Command`'s `v-model` |
|
|
644
659
|
| `checked` (`CommandItem`) | `boolean` | — | sets `aria-checked` and shows a checkbox indicator, for a multi-choice list; reka's `aria-selected` keeps meaning "selected value" (`multiple` is not used) |
|
|
645
660
|
| `multiselectable` (`CommandList`) | `boolean` | — | sets `aria-multiselectable` on the list |
|
|
646
661
|
| `@select` (`CommandItem`) | `(event) => void` | — | Enter or click on the item; `event.detail.value` is its `value` |
|
|
662
|
+
| `aria-label` (`CommandList`) | `string` | `"Suggestions"` (translated, `material.command.list`) | the list's accessible name; your own `aria-label` replaces the default |
|
|
663
|
+
| `decorative` (`CommandSeparator`) | `boolean` | `true` | the separator is purely visual (`role="none"`): a `role="separator"` is not allowed inside the listbox |
|
|
647
664
|
| `heading` (`CommandGroup`) | `string` | — | the group's label |
|
|
648
665
|
| `title` / `description` (`CommandDialog`) | `string` | `"Command Palette"` / `"Search for a command to run..."` (translated) | the dialog's title and description, visually hidden |
|
|
649
666
|
| `v-model:open` (`CommandDialog`) | `boolean` | — | `CommandDialog` takes every `Dialog` prop |
|
|
650
667
|
|
|
651
668
|
The filter matches the item's text, case- and accent-insensitive; there is no
|
|
652
669
|
`shouldFilter` or `keywords` in Vue. `CommandDialog`'s default title and
|
|
653
|
-
description
|
|
654
|
-
keyboard shortcut: listen for ⌘K yourself (`useMagicKeys` from VueUse) and set
|
|
670
|
+
description follow `I18nProvider` (`material.command.title` / `description`).
|
|
671
|
+
It does not bind a keyboard shortcut: listen for ⌘K yourself (`useMagicKeys` from VueUse) and set
|
|
655
672
|
`open`.
|
|
656
673
|
|
|
657
674
|
**Storybook:** `Overlays & menus/Command` · **React:** `Command`, `CommandDialog` (same parts)
|
|
@@ -193,7 +193,7 @@ import { Typography } from '@nxgt/material-vue/components';
|
|
|
193
193
|
| Prop | Type | Default | Effect |
|
|
194
194
|
| --- | --- | --- | --- |
|
|
195
195
|
| `variant` | `'huge-larger' \| 'huge-large' \| 'huge-medium' \| 'huge-small' \| 'headline-larger' \| 'headline-large' \| 'headline-medium' \| 'headline-small' \| 'title-large' \| 'title-medium' \| 'title-small' \| 'body-medium' \| 'body-small' \| 'caption' \| 'normal'` | `'normal'` | size and weight; `caption` is also muted |
|
|
196
|
-
| `tone` | `'default' \| 'muted' \| 'primary' \| 'error'` | `'default'` | text colour: `muted` is `text-muted-foreground`, `primary` is `text-primary
|
|
196
|
+
| `tone` | `'default' \| 'muted' \| 'primary' \| 'error'` | `'default'` | text colour: `muted` is `text-muted-foreground`, `primary` is `text-primary-text` (primary lightened in dark), `error` is `text-error-text`; `default` inherits (a `class` colour still wins) |
|
|
197
197
|
| `as` | a tag name or a component | `'div'` | the element to render, keeping the variant, e.g. `as="h2"` or `as="span"` |
|
|
198
198
|
| `asChild` | `boolean` | `false` | merge the classes onto the single child instead of rendering an element |
|
|
199
199
|
|
|
@@ -364,6 +364,8 @@ Takes every `<input>` attribute. `v-model` carries `string | number`;
|
|
|
364
364
|
the error outline. For a labelled field with helper text and a form wrapper,
|
|
365
365
|
use `TextField` on the [Form fields](form-fields.md) page.
|
|
366
366
|
|
|
367
|
+
In an input group (`InputGroupInput`, `InputGroupField`) the fill tint follows the value: an empty field is not tinted, with or without a `placeholder` (one without renders a blank `placeholder=" "` so that CSS can tell). The bare `Input` and `Textarea` have no tint and get no placeholder.
|
|
368
|
+
|
|
367
369
|
**Emits:** `update:modelValue` — `string | number`.
|
|
368
370
|
**Storybook:** `Primitives/Input` · **React:** `Input`
|
|
369
371
|
|
|
@@ -461,7 +463,7 @@ import { Icon } from '@nxgt/material-vue/components';
|
|
|
461
463
|
|
|
462
464
|
<template>
|
|
463
465
|
<Icon name="bell" />
|
|
464
|
-
<Icon name="bell" type="solid" class="size-6 text-primary" aria-hidden="true" />
|
|
466
|
+
<Icon name="bell" type="solid" class="size-6 text-primary-text" aria-hidden="true" />
|
|
465
467
|
</template>
|
|
466
468
|
```
|
|
467
469
|
|
|
@@ -901,7 +903,7 @@ defineProps<{ nonce?: string }>();
|
|
|
901
903
|
|
|
902
904
|
| Prop | Type | Default | Effect |
|
|
903
905
|
| --- | --- | --- | --- |
|
|
904
|
-
| `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 (
|
|
906
|
+
| `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, else, on the client from the first render (read in `setup`), the page's own (`csp-nonce` meta tag, …); a server has no page, so it passes the prop |
|
|
905
907
|
|
|
906
908
|
`useCspNonce()` (`@nxgt/material-vue/composables`) reads it in a component of
|
|
907
909
|
your own; `getCspNonce()` and `setCspNonce()` (`@nxgt/material-vue/lib`) read
|
|
@@ -238,7 +238,7 @@ props below, and `option` for anything else.
|
|
|
238
238
|
| `height` | `string \| number` | `320` | the container's height; the chart fills it |
|
|
239
239
|
| `loading` | `boolean` | `false` | a skeleton instead of the chart |
|
|
240
240
|
| `empty` | `boolean` | when `data` is empty | force the empty state on or off |
|
|
241
|
-
| `#emptyState` | slot | built-in
|
|
241
|
+
| `#emptyState` | slot | the built-in compact `EmptyState` | what an empty chart shows; a custom slot keeps its centring wrapper |
|
|
242
242
|
| `colors` | `string[]` | from the `--chart-*` tokens | override the palette; any CSS colour, `oklch()` included (converted to `rgb()` for ECharts) |
|
|
243
243
|
| `margin` | `ChartMargin` | — | plot padding |
|
|
244
244
|
| `option` | `EChartsOption` | — | merged into the generated ECharts option |
|
|
@@ -234,6 +234,8 @@ options by label. Picking the selected option again clears it.
|
|
|
234
234
|
|
|
235
235
|
Single or multiple (chips) autocomplete typed by its options, with free-solo values, accent-insensitive matching, a debounced server search and option slots.
|
|
236
236
|
|
|
237
|
+
The input is a `combobox` (`aria-expanded`, `aria-controls`, `aria-activedescendant`) and the list a `listbox` of `option`s, as in `@nxgt/material`; the list opens on a click or on typing, not on focus alone. In tests, use `getByRole('combobox', { name })` and `getByRole('option', { name })`.
|
|
238
|
+
|
|
237
239
|
```vue
|
|
238
240
|
<script setup lang="ts">
|
|
239
241
|
import { ref } from 'vue';
|
|
@@ -336,15 +338,23 @@ update them on `@query-change`, and pass `filter="none"` when the server
|
|
|
336
338
|
already filtered.
|
|
337
339
|
|
|
338
340
|
A disabled option (`disabled: true` on it, in `options` or in what `on-search`
|
|
339
|
-
returns) is greyed out, carries `aria-disabled` and a native `disabled`, so
|
|
340
|
-
|
|
341
|
-
enabled option), in `single` and `multiple` mode.
|
|
341
|
+
returns) is greyed out, carries `aria-disabled` and a native `disabled`, so the arrow keys skip it, and is never picked, by click or by Enter (which picks the
|
|
342
|
+
highlighted option, the first enabled one until the arrows move it), in `single` and `multiple` mode.
|
|
342
343
|
|
|
343
344
|
**Accessibility.** A polite live region (`role="status"`) says "Loading…",
|
|
344
345
|
then "3 results" or "No results" (or the failure) once the search answers or
|
|
345
346
|
typing pauses — never on every keystroke. The list is `aria-busy` while
|
|
346
347
|
loading. The strings are `material.autocomplete.loading`, `.results`,
|
|
347
|
-
`.search-error` and `.min-query`.
|
|
348
|
+
`.search-error` and `.min-query`.
|
|
349
|
+
|
|
350
|
+
**Keyboard.** The input keeps the focus and points at the highlighted option
|
|
351
|
+
with `aria-activedescendant`. `ArrowDown` and `ArrowUp` open a closed list
|
|
352
|
+
and move the highlight over the enabled options (wrapping at the ends); with
|
|
353
|
+
an empty query `Home` and `End` jump to the first and last one. `Enter`
|
|
354
|
+
picks the highlighted option (or adds the free-solo value when "Add …" stands
|
|
355
|
+
for it) and, with the list closed, submits the form; hovering an option moves
|
|
356
|
+
the highlight. `Escape` closes the list, and `Backspace` on an empty query removes
|
|
357
|
+
the last chip. The options are not tab stops: Tab leaves the field.
|
|
348
358
|
|
|
349
359
|
It is a generic component: `T` is inferred from `options`, and the slots —
|
|
350
360
|
React's render props — receive it whole:
|
package/docs/getting-started.md
CHANGED
|
@@ -35,7 +35,7 @@ does not import that entry never has them in its tree.
|
|
|
35
35
|
The tarball contains the built `dist/` (with KaTeX's fonts in
|
|
36
36
|
`dist/fonts/katex/`, which the compiled stylesheet loads),
|
|
37
37
|
`lib/styles.css`, the component
|
|
38
|
-
stylesheets it imports (`lib/components/**/*.css`), `lib/map/map.css`, the
|
|
38
|
+
stylesheets it imports (`lib/components/**/*.css`), `lib/map/map.css`, `lib/backgrounds/backgrounds.css`, `lib/backgrounds/css/*.css`, the
|
|
39
39
|
Nuxt module (`lib/nuxt`, with the
|
|
40
40
|
`lib/vite/index.ts` it imports), these docs and `CHANGELOG.md` (from the
|
|
41
41
|
release after 0.25.1). There is no `postinstall` build step.
|
|
@@ -112,6 +112,18 @@ Your own components can use the same per-instance store factory
|
|
|
112
112
|
(`defineLocalStore` and the status, filter and step-form stores) from
|
|
113
113
|
`@nxgt/material-vue/lib`; see [helpers](guides/helpers.md#pinia-store-factories).
|
|
114
114
|
|
|
115
|
+
## The Vite plugin
|
|
116
|
+
|
|
117
|
+
In `vite.config.ts`, add the plugin after `tailwindcss()`:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { nxgtMaterial } from '@nxgt/material-vue/vite';
|
|
121
|
+
|
|
122
|
+
export default defineConfig({ plugins: [/* …, */ tailwindcss(), ...nxgtMaterial()] });
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
It sets up a strict Content Security Policy (the header is written to `dist/.vite/nxgt-csp.json`), keeps fonts out of `data:` URIs, loads Inter when `@fontsource-variable/inter` is installed and fails the build when the stylesheet above is not imported. Each part has an opt-out: [Vite plugin guide](guides/vite-plugin.md). On Nuxt, see the guide's note.
|
|
126
|
+
|
|
115
127
|
## Icons
|
|
116
128
|
|
|
117
129
|
`Icon` renders a Font Awesome **sprite** referenced by a root-relative URL on
|
|
@@ -174,7 +186,9 @@ export default defineNuxtConfig({
|
|
|
174
186
|
// prefix: 'Nxgt', // <NxgtButton />
|
|
175
187
|
// components: true, // auto-import components
|
|
176
188
|
// imports: true, // auto-import composables and i18n helpers
|
|
177
|
-
// pdf: {
|
|
189
|
+
// pdf: { bundle: true }, // a server with no node_modules that renders /pdf
|
|
190
|
+
// fonts: { sans: 'inter' }, // self-hosted Inter (bun add @fontsource-variable/inter)
|
|
191
|
+
// csp: { zodJitless: true }, // zod's jitless script in every head (needs nuxt-security's nonce or hash)
|
|
178
192
|
},
|
|
179
193
|
});
|
|
180
194
|
```
|
|
@@ -184,7 +198,10 @@ export default defineNuxtConfig({
|
|
|
184
198
|
| `prefix` | `string` | `''` | Prepended to every auto-imported component name |
|
|
185
199
|
| `components` | `boolean` | `true` | Registers the components of `@nxgt/material-vue/components` for use without an import |
|
|
186
200
|
| `imports` | `boolean` | `true` | Auto-imports the composables (`useTheme`, `useIsMobile`, `useIsClient`, `useLocalizedDate`, `useFormatters`, `useNumberFormatter`, `useSearchParam`, …) and `useMaterialTranslation`, `createTypedTranslation`, `useOptionalI18nContext` |
|
|
187
|
-
| `pdf.
|
|
201
|
+
| `pdf.bundle` | `boolean` | `false` | Adds `pdfkitStandardFonts()` to the Nitro build, for a server that renders with `@nxgt/material-vue/pdf` and runs without `node_modules` ([PDF documents](guides/pdf.md#fonts-on-a-fully-inlined-server)). `pdf.bundleStandardFonts` is its deprecated name |
|
|
202
|
+
| `fonts` | `boolean \| { katex?, sans? }` | `{ katex: true, sans: false }` | `katex`: a font is never inlined as a `data:` URI (`font-src 'self'`). `sans: 'inter'`: loads self-hosted Inter and sets `--font-sans` through `css` (a missing `@fontsource-variable/inter` warns once and keeps the system font). `false` turns both off |
|
|
203
|
+
| `csp.zodJitless` | `boolean` | `false` | Puts zod's jitless inline script in every page's `<head>` (`tagPriority: 'critical'`). It is an inline script: a strict CSP needs `nuxt-security` with `nonce: true` (or its script hashes) to allow it. The module sets no CSP itself ([Vite plugin guide](guides/vite-plugin.md#nuxt)) |
|
|
204
|
+
| `styles` | `boolean \| { check? }` | `false` | The `vite build` check that the stylesheet is imported, off by default under Nuxt because the module cannot see how `css` entries are resolved. `true` opts in |
|
|
188
205
|
|
|
189
206
|
The module also:
|
|
190
207
|
|
|
@@ -223,6 +240,7 @@ export default defineConfig({
|
|
|
223
240
|
| `@nxgt/material-vue` | Everything from `/components`, `/composables`, `/i18n`, `/lib`, `/models` and `/types` in one barrel, plus the compiled `style` condition (`dist/material-vue.css`, for apps without Tailwind) |
|
|
224
241
|
| `@nxgt/material-vue/components` | UI components and `*FormField` wrappers ([components](components/README.md)) |
|
|
225
242
|
| `@nxgt/material-vue/map` | Leaflet maps, markers, a location field. **Its own entry, not in the barrel above** ([maps](guides/maps.md)) |
|
|
243
|
+
| `@nxgt/material-vue/backgrounds` | Background presets: `Background` (a superset of the `/components` one: `preset` `gradient` or `grain`, `tone`, `intensity`, `animated`, `grain`, `seed`, `fill`), and the types and tables re-exported from `@nxgt/material-core/backgrounds`; more presets are coming. **Its own entry**, with an opt-in stylesheet ([backgrounds](guides/backgrounds.md)) |
|
|
226
244
|
| `@nxgt/material-vue/pdf` | PDF files from plain data: builders, `usePdf`, `PdfDownloadButton`, `pdfResponse`. **Its own entry, not in the barrel above** ([PDF documents](guides/pdf.md)) |
|
|
227
245
|
| `@nxgt/material-vue/composables` | `useTheme`, `useIsClient`, `useIsMobile`, `useLocalizedDate`, `useSearchParam`, … ([helpers](guides/helpers.md#nxgtmaterial-vuecomposables)) |
|
|
228
246
|
| `@nxgt/material-vue/dnd` | Drag-and-drop primitives ([helpers](guides/helpers.md#nxgtmaterial-vuednd)) |
|
|
@@ -232,6 +250,7 @@ export default defineConfig({
|
|
|
232
250
|
| `@nxgt/material-vue/types` | Shared function types (`PromiseOr`, `FunctionOr`, …) |
|
|
233
251
|
| `@nxgt/material-vue/styles.css` | Source Tailwind v4 tokens. **This** is the stylesheet a Tailwind app imports |
|
|
234
252
|
| `@nxgt/material-vue/map.css` | Leaflet's stylesheet, for apps that use `/map`. Not part of `styles.css` |
|
|
253
|
+
| `@nxgt/material-vue/backgrounds.css` | Every background preset's CSS, for apps that use `/backgrounds`; `@nxgt/material-vue/backgrounds/<preset>.css` loads one. Not part of `styles.css` |
|
|
235
254
|
| `@nxgt/material-vue/nuxt` | The Nuxt module ([above](#nuxt)) |
|
|
236
255
|
| `@nxgt/material-vue/vite` | `pdfkitStandardFonts()`, a Vite plugin for a server that inlines `/pdf` ([PDF documents](guides/pdf.md#fonts-on-a-fully-inlined-server)). Build-time code for `vite.config.ts` |
|
|
237
256
|
|
package/docs/guides/app-shell.md
CHANGED
|
@@ -180,7 +180,7 @@ partitionMenu(items); // { content, footer }
|
|
|
180
180
|
| `#logo` | slot | — | The logo as a node (an inline SVG), in place of `logo`; it wins when both are given |
|
|
181
181
|
| `name` | `string` | — | The app's name, already translated: the logo's accessible name and tooltip in the rail, shown beside it in the sheet |
|
|
182
182
|
| `#brand` | slot | — | Replaces the sidebar header entirely, in the rail and in the menu sheet; wins over `logo` and `name` |
|
|
183
|
-
| `#header-title` | slot | — | The header's leading title: the context the app is in (the active organisation's name), right after the phone's menu button, truncated when long |
|
|
183
|
+
| `#header-title` | slot | — | The header's leading title: the context the app is in (the active organisation's name), right after the phone's menu button, truncated when long; when it is cut off, its full text is the `title` tooltip (#629) |
|
|
184
184
|
| `#header-actions` | slot | — | In the header, before the avatar: notifications, help, `LanguageSwitcher`, `ThemeToggle` |
|
|
185
185
|
| `#avatar` | slot | the `avatar-src` image | Replaces the avatar entirely |
|
|
186
186
|
| default | slot | — | The routed content, usually `<RouterView />` |
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Backgrounds
|
|
2
|
+
|
|
3
|
+
`Background` is a backdrop that centres its content. The one in
|
|
4
|
+
`@nxgt/material-vue/components` is the **gradient**: a tint with three blurred blobs, and
|
|
5
|
+
it needs only `styles.css`. `@nxgt/material-vue/backgrounds` is the entry for the
|
|
6
|
+
preset family and shares its tones, its intensities and its CSS with
|
|
7
|
+
that gradient. There, `Background` is a superset of the `/components` one under
|
|
8
|
+
the same name (same props, plus the preset ones); the other presets are being
|
|
9
|
+
added slice by slice, so for now it draws the gradient and the grain.
|
|
10
|
+
|
|
11
|
+
## Tone and intensity
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { Background } from '@nxgt/material-vue/components';
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<Background tone="success" intensity="subtle" class="h-96 w-full">
|
|
20
|
+
...
|
|
21
|
+
</Background>
|
|
22
|
+
</template>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| Prop | Values | Default |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `tone` | `primary`, `secondary`, `tertiary`, `neutral`, `success`, `warning`, `error`, `info`, `mixed`, `custom` | `primary` |
|
|
28
|
+
| `intensity` | `subtle`, `default`, `vivid` | `default` |
|
|
29
|
+
| `preset` | `gradient` (the only one on `/components`; `/backgrounds` adds `grain`) | `gradient` |
|
|
30
|
+
|
|
31
|
+
`mixed` draws from primary, secondary and tertiary; `custom` reads your own
|
|
32
|
+
colours (see below).
|
|
33
|
+
|
|
34
|
+
## The `/backgrounds` component
|
|
35
|
+
|
|
36
|
+
`Background` from `@nxgt/material-vue/backgrounds` takes everything the `/components` one
|
|
37
|
+
takes, and more. Import the stylesheet of the presets you use (below).
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<script setup lang="ts">
|
|
41
|
+
import { Background } from '@nxgt/material-vue/backgrounds';
|
|
42
|
+
import '@nxgt/material-vue/backgrounds.css';
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<Background preset="grain" tone="mixed" animated class="h-96 w-full">
|
|
47
|
+
...
|
|
48
|
+
</Background>
|
|
49
|
+
</template>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Prop | Values | Default |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `preset` | `gradient`, `grain` (`SHIPPED_BACKGROUND_PRESETS`); any other id draws the gradient and warns outside production | `gradient` |
|
|
55
|
+
| `tone`, `intensity` | as above | `primary`, `default` |
|
|
56
|
+
| `animated` | `boolean`: drifts the layers, see Motion | `false` |
|
|
57
|
+
| `grain` | `boolean`: film noise over the preset; needs `grain.css` | `false` |
|
|
58
|
+
| `seed` | `number`: moves a seeded preset's geometry and the grain | `0` |
|
|
59
|
+
| `fill` | `viewport` (the viewport's size) or `container` (its parent's size: the parent needs a definite height) | `viewport` |
|
|
60
|
+
|
|
61
|
+
`BACKGROUND_PRESETS` is the planned table of all twenty presets, with their
|
|
62
|
+
family and kind; `SHIPPED_BACKGROUND_PRESETS` is what `Background` draws today.
|
|
63
|
+
|
|
64
|
+
The root states `preset`, `tone`, `intensity`, `animated`, `grain` and `fill` as
|
|
65
|
+
`data-*` attributes (`data-animated` and `data-grain` are empty attributes), and
|
|
66
|
+
`data-paused` while it is paused. Select on `data-preset` (`grain` for the grain
|
|
67
|
+
preset), not on `data-background`. That one is the CSS key and stays
|
|
68
|
+
`gradient` for it. The default slot is centred above the
|
|
69
|
+
decoration.
|
|
70
|
+
|
|
71
|
+
`grain` draws an SVG `feTurbulence` filter above the preset's layers, under
|
|
72
|
+
your content; `intensity` scales its opacity. `preset="grain"` is the gradient
|
|
73
|
+
with the grain on. The grain's look may still change. Its SVG is built from
|
|
74
|
+
plain data by `@nxgt/material-core/backgrounds` (`buildGrain`), with no `style`
|
|
75
|
+
attribute: ids come from `useId`, so the server and the client render the same
|
|
76
|
+
markup, and nothing is random or measured.
|
|
77
|
+
|
|
78
|
+
## Dark mode
|
|
79
|
+
|
|
80
|
+
In dark the drawn colours are lifted to a lightness floor: the dark `--primary` is as dim as the light one, which made the
|
|
81
|
+
gradient dull. The lift uses the relative colour syntax (Chrome 119, Safari 18,
|
|
82
|
+
Firefox 128); older browsers get a `color-mix()` toward white.
|
|
83
|
+
|
|
84
|
+
## Your own colours
|
|
85
|
+
|
|
86
|
+
`tone="custom"` reads `--nxgt-bg-custom-1` to `--nxgt-bg-custom-3`, which you set in your
|
|
87
|
+
own stylesheet. There is no colour prop, because one would write a `style`
|
|
88
|
+
attribute.
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
.brand-backdrop {
|
|
92
|
+
--nxgt-bg-custom-1: oklch(0.62 0.2 30);
|
|
93
|
+
--nxgt-bg-custom-2: oklch(0.7 0.15 80);
|
|
94
|
+
--nxgt-bg-custom-3: var(--primary);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Overriding the drawn colours
|
|
99
|
+
|
|
100
|
+
The tone sets `--nxgt-bg-c1..c3`, the three colours the layers draw with. Set
|
|
101
|
+
them on the element to pick your own. The element carries `data-background`, `data-tone` and `data-intensity`, which
|
|
102
|
+
you can select on:
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
[data-background][data-tone="primary"] {
|
|
106
|
+
--nxgt-bg-c1: oklch(0.62 0.2 30);
|
|
107
|
+
--nxgt-bg-c2: oklch(0.7 0.15 80);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Stylesheets
|
|
112
|
+
|
|
113
|
+
`styles.css` carries the base, the gradient and the motion rules. Everything
|
|
114
|
+
else is opt-in, because CSS cannot be tree-shaken. `animated` on the
|
|
115
|
+
`/components` `Background` needs only `styles.css`; `grain` needs `grain.css` (or
|
|
116
|
+
`backgrounds.css`) and renders nothing, with no error, without it:
|
|
117
|
+
|
|
118
|
+
```css
|
|
119
|
+
@import "@nxgt/material-vue/backgrounds.css"; /* every opt-in file */
|
|
120
|
+
/* or just the one you use: */
|
|
121
|
+
@import "@nxgt/material-vue/backgrounds/grain.css"; /* the grain overlay, over any preset */
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The base, the gradient and the motion already come with `styles.css`: the
|
|
125
|
+
`/components` `Background` needs none of `base.css`, `gradient.css` or
|
|
126
|
+
`motion.css`. Only `grain.css` is extra.
|
|
127
|
+
|
|
128
|
+
The CSS sits in `@layer components`: a utility such as `h-96 w-full` or
|
|
129
|
+
`overflow-hidden` on the element beats it.
|
|
130
|
+
|
|
131
|
+
## Motion, accessibility and CSP
|
|
132
|
+
|
|
133
|
+
- Static by default. `animated` drifts the layers, and only under
|
|
134
|
+
`@media (prefers-reduced-motion: no-preference)`: with reduced motion it
|
|
135
|
+
never moves. It sets `data-paused`, which stops the animation, while the page
|
|
136
|
+
is hidden (another tab) or the background is off screen. The observers start
|
|
137
|
+
once mounted and only when `animated` is set, and are removed on unmount.
|
|
138
|
+
`animated` is on the `/components` `Background` too, with the same behaviour.
|
|
139
|
+
- Every decorative layer is `aria-hidden="true"` and takes no pointer; under
|
|
140
|
+
`forced-colors: active` the layers are hidden. Put text on a `Card` when you
|
|
141
|
+
use `vivid`.
|
|
142
|
+
- The markup carries no `style` attribute and no `<style>` element, so a
|
|
143
|
+
strict CSP needs nothing beyond the [baseline](csp.md).
|