@nxgt/material 3.21.0 → 3.22.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 (73) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/README.md +6 -4
  3. package/bin/nxgt-backdrop-sprite.js +15 -0
  4. package/dist/background-BtSZsTvY.js +286 -0
  5. package/dist/backgrounds/css-react/icons-quiet.css +5 -5
  6. package/dist/backgrounds/css-react/icons-tint.css +98 -0
  7. package/dist/backgrounds/css-react/icons.css +100 -33
  8. package/dist/backgrounds.js +1 -1
  9. package/dist/{celestial-scene-DaOsRFF3.js → celestial-scene-8Muu6f7O.js} +1 -1
  10. package/dist/components/background-shared.css +5 -0
  11. package/dist/components/components.css +4 -7
  12. package/dist/components/ui/fields/attributes/attributes.css +3 -0
  13. package/dist/components/ui/layout/app-shell/activity-backdrop-shapes.css +1 -1
  14. package/dist/components/ui/layout/auth-card/auth-card-backdrop.css +30 -0
  15. package/dist/{components-CbD5WNVO.js → components-B0oezhGe.js} +10424 -10394
  16. package/dist/components.js +16 -16
  17. package/dist/editor.js +1 -1
  18. package/dist/{empty-state-CJh9f2pc.js → empty-state-lj7vjYWG.js} +1 -1
  19. package/dist/icon-sprites-CaYXzOL4.js +46 -0
  20. package/dist/icons-scene-M4HBeN2c.js +54 -0
  21. package/dist/{illustration-BmQmvW_4.js → illustration-B4_W-OUS.js} +2 -2
  22. package/dist/illustrations.js +1 -1
  23. package/dist/lib/backgrounds/background/partials/icons-check.d.ts +2 -2
  24. package/dist/lib/backgrounds/background/partials/icons-keys.d.ts +21 -1
  25. package/dist/lib/backgrounds/background/partials/icons-scene.d.ts +15 -6
  26. package/dist/lib/backgrounds/background/partials/use-icons-scene.d.ts +13 -8
  27. package/dist/lib/backgrounds/background/types.d.ts +26 -12
  28. package/dist/lib/backgrounds/index.d.ts +1 -1
  29. package/dist/lib/components/ui/layout/app-shell/keep-shapes-inside.d.ts +7 -2
  30. package/dist/lib/components/ui/layout/app-shell/shapes-clear-content.d.ts +10 -3
  31. package/dist/lib/components/ui/layout/app-shell/theme-backdrop.d.ts +3 -1
  32. package/dist/lib/components/ui/layout/app-shell/use-keep-shapes-inside.d.ts +3 -3
  33. package/dist/lib/components/ui/layout/app-shell/watch-content.d.ts +28 -8
  34. package/dist/lib/components/ui/layout/auth-card/auth-card-backdrop.d.ts +23 -0
  35. package/dist/lib/components/ui/layout/auth-card/auth-card.d.ts +15 -1
  36. package/dist/lib/components/ui/primitives/icon/icon-sprites.d.ts +40 -1
  37. package/dist/lib/themes/define-theme.d.ts +8 -0
  38. package/dist/lib/themes/index.d.ts +2 -1
  39. package/dist/lib/vite/index.d.ts +1 -1
  40. package/dist/main.js +28 -28
  41. package/dist/material.css +1 -1
  42. package/dist/pdf-reader.js +1 -1
  43. package/dist/{public-DWuBn4t_.js → public-DAF5SCWH.js} +1 -1
  44. package/dist/{scene-options-CCy3V7XS.js → scene-options-2zNF3ZkQ.js} +4 -2
  45. package/dist/theme-picker.js +3 -3
  46. package/dist/themes.js +9 -4
  47. package/dist/{use-chat-composer-BBFuKNqC.js → use-chat-composer-B0ze1cU9.js} +3 -3
  48. package/docs/components/navigation-and-layout.md +22 -0
  49. package/docs/components/primitives.md +21 -0
  50. package/docs/guides/app-shell.md +9 -8
  51. package/docs/guides/backgrounds.md +214 -16
  52. package/docs/guides/icon-motifs.md +30 -12
  53. package/docs/guides/themes.md +25 -4
  54. package/docs/guides/theming.md +7 -0
  55. package/docs/guides/vite-plugin.md +26 -0
  56. package/docs/previews/backgrounds-background-from-theme.webp +0 -0
  57. package/docs/previews/backgrounds-icons.webp +0 -0
  58. package/docs/previews/backgrounds-matrix.webp +0 -0
  59. package/docs/previews/foundations-themes-icon-motifs.webp +0 -0
  60. package/docs/roadmap.md +6 -0
  61. package/docs/troubleshooting.md +46 -3
  62. package/lib/backgrounds/css-react/icons-quiet.css +5 -5
  63. package/lib/backgrounds/css-react/icons-tint.css +98 -0
  64. package/lib/backgrounds/css-react/icons.css +100 -33
  65. package/lib/components/background-shared.css +5 -0
  66. package/lib/components/components.css +4 -7
  67. package/lib/components/ui/fields/attributes/attributes.css +3 -0
  68. package/lib/components/ui/layout/app-shell/activity-backdrop-shapes.css +1 -1
  69. package/lib/components/ui/layout/auth-card/auth-card-backdrop.css +30 -0
  70. package/package.json +8 -3
  71. package/dist/background-Ce7M5V42.js +0 -250
  72. package/dist/icon-sprites-FxHyqyhg.js +0 -30
  73. package/dist/icons-scene-BpIauJ5d.js +0 -27
@@ -54,14 +54,35 @@ export default defineTheme({
54
54
  - `Background`, `ActivityLayout` and every `NxgtTheme` zone read it: no props, and a prop you pass still wins.
55
55
  Serve the sprites (`/assets/icons/sprites/` or your `IconSpritesProvider base`) and import
56
56
  `@nxgt/material/backgrounds/icons.css` (or `backgrounds.css`); see [backgrounds](backgrounds.md#icons).
57
- - `extends` merges `iconMotif` and an `iconStyle` object key by key; `icons` and an `iconStyle` list or file name are
58
- replaced whole. A derived theme that leaves them out inherits them.
59
- - `defineTheme` checks them when it is defined: `name` for an unknown pack, a bad icon name or style, `range` for the
60
- rest (more than 48 icons, a layout, a size range).
57
+ - `extends` merges `motif`, `iconMotif` and an `iconStyle` object key by key; `icons`, `motif.icons` and an `iconStyle`
58
+ list (weighted or not) or file name are replaced whole. A derived theme that leaves them out inherits them.
59
+ - `defineTheme` checks them when it is defined: `name` for an unknown pack, a bad icon name or style or an unknown key,
60
+ `range` for the rest (more than 48 icons, a layout, a size range, a weight).
61
+ A bad `motif` key or value is dropped, not thrown: `defineTheme` from `@nxgt/material/themes` warns for each one in development, the `@nxgt/material-core/theme/define` one only through its `{ warn }` option (4.0: an error; see [troubleshooting](../troubleshooting.md#definetheme-theme-x-backgroundmotif-unknown-key-spin-ignored)).
61
62
  - `ThemePicker` draws the theme's first four icons in its tile, from the same sprite base. A sprite that is not served
62
63
  draws nothing, and the tile keeps its wash.
63
64
  - The 14 shipped themes name no icons and are unchanged.
64
65
 
66
+ ### The calm backdrop's keys (3.22)
67
+
68
+ `preset: 'icons'` is the calm mix by default; a theme tunes it with the same keys as the props:
69
+
70
+ ```ts
71
+ background: {
72
+ preset: 'icons',
73
+ icons: 'school',
74
+ // a share each (default 1); a style the app does not serve is dropped, the rest keep their proportions
75
+ iconStyle: [{ style: 'light', weight: 3 }, { style: 'sharp-regular', weight: 2 }, { style: 'duotone-thin' }],
76
+ iconMotif: { layout: 'even', colors: 'one' }, // colors: 'one' | 'palette' | 'classic'
77
+ motif: { density: 'medium', icons: { ratio: 0.2 } }, // density: 'low' | 'medium' | 'high' | a count from 1 to 600
78
+ }
79
+ ```
80
+
81
+ `layout: 'even'` is the mix of shapes and icons; any other layout draws icons only. `motif.icons` is
82
+ `{ pack?, style?, ratio }` and also works on `preset: 'shapes'`. The previous look is
83
+ `iconStyle: 'duotone-thin', iconMotif: { layout: 'scatter', colors: 'classic' }`. Every key reaches the scene, and a
84
+ prop on `Background` still wins. See [backgrounds](backgrounds.md#defaults-from-the-theme).
85
+
65
86
  ## Generate the files
66
87
 
67
88
  With Vite:
@@ -1166,6 +1166,13 @@ Lavande tokens on `:root`.
1166
1166
  selector after the theme (`[data-nxgt-theme="ocean"] { --primary: … }`).
1167
1167
  - **Fonts.** The theme sets `font-family` on its own element; a font stack that
1168
1168
  is not installed falls back to the system face.
1169
+ - **Background.** A theme's `background` is read by `Background`, `ActivityLayout`
1170
+ and `AuthCard`. Since 3.22 it takes the calm backdrop's keys: `iconMotif.layout:
1171
+ 'even'` and `colors: 'one' | 'palette' | 'classic'`, a weighted `iconStyle`
1172
+ list, `motif.icons { pack, style, ratio }` and `motif.density` (`'low'`,
1173
+ `'medium'`, `'high'` or a count). They are checked by `defineTheme`. A bad `motif` key or value is dropped, not thrown: `defineTheme` from `@nxgt/material/themes` warns for each one in development, the `@nxgt/material-core/theme/define` one only through its `{ warn }` option (4.0: an error; see [troubleshooting](../troubleshooting.md#definetheme-theme-x-backgroundmotif-unknown-key-spin-ignored)). See
1174
+ [the calm backdrop in a theme](./backgrounds.md#the-calm-backdrop-in-a-theme)
1175
+ and [Themes for your app](./themes.md#icon-motifs-in-a-theme).
1169
1176
 
1170
1177
  ### The provider and zones
1171
1178
 
@@ -33,6 +33,7 @@ Every part is on by default and has an opt-out. It needs `vite` 5.2 or later (6,
33
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
34
  | `styles.check` | `true` | Fails `vite build` when the library's stylesheet is never imported (`@nxgt/material/styles.css`, or the compiled one through `@import "@nxgt/material";`), or `styles.css` is imported without the `@source` line Tailwind needs |
35
35
  | `themes` | off | Generates your themes' stylesheets and types and injects the boot script: see [Themes](#themes) |
36
+ | `backdropSprite` | off | Builds the reduced backdrop sprite (one `<symbol>` per icon name and style, from your `@fortawesome/*` install) at build and serves it in dev; `packs` or `icons` is required, `true` is not accepted: see [The reduced backdrop sprite](#the-reduced-backdrop-sprite) |
36
37
  | `pdf` | on | pdfkit's standard fonts (`pdfkitStandardFonts()`): a no-op unless pdfkit goes through the bundle; and a dev-server route for the pdf.js worker (the `pdf.worker` row). `pdf: false` turns both off |
37
38
  | `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)) |
38
39
  | `pdf.worker` | `true` | Dev server only: answers `pdf.worker.min.mjs` in Vite's pre-bundle folder (`…/deps/`, any `cacheDir`, so Storybook and Vitest browser mode too) with the installed `@nxgt/material/dist/pdf.worker.min.mjs` (else `pdfjs-dist/build/…`). Vite 5 to 7 pre-bundle the library without the worker, so the readers' worker URL is a 404 there; Vite 8 needs no route, and `@nxgt/material-vue` none (it imports the worker with `?url`). `pdf: { worker: false }` drops it; then set `configurePdfReader({ workerSrc })` instead (see [the PDF reader guide](pdf-reader.md#bundlers)) |
@@ -159,6 +160,31 @@ message names the exact line to add.
159
160
  Opt out with `styles: false` (a Storybook build, for instance, may not import
160
161
  it).
161
162
 
163
+ ## The reduced backdrop sprite
164
+
165
+ `backdropSprite` runs the same builder as the `nxgt-backdrop-sprite` command: one SVG sprite that holds only the icon
166
+ packs' names in the chosen styles, read from the Font Awesome packages in your `node_modules`
167
+ (`@fortawesome/fontawesome-pro`, else `@fortawesome/fontawesome-free`). There is no default pack: name the `packs` your backdrops draw, or an `icons` list; without either the plugin throws at startup (see [troubleshooting](../troubleshooting.md#backdropsprite-needs-the-icon-packs-your-backdrops-draw)).
168
+
169
+ ```ts
170
+ nxgtMaterial({
171
+ backdropSprite: {
172
+ packs: ['health'], // required (or icons): the icon packs whose names go in
173
+ icons: ['rocket'], // names for your own `icons` list, alone or with packs
174
+ styles: ['light', 'thin'], // default: the backdrop's styles that the install has, else regular and solid
175
+ base: '/sprites/', // where it is served from (root-relative), default '/sprites/'
176
+ outFile: 'backdrop.svg', // the file name under base, default 'backdrop.svg'
177
+ sources: ['node_modules/@fortawesome/fontawesome-pro'], // folders to read, default: the installed packages
178
+ },
179
+ })
180
+ ```
181
+
182
+ The build emits `dist/sprites/backdrop.svg` and the dev server answers `/sprites/backdrop.svg`; the plugin logs the
183
+ `IconSpritesProvider` value (`backdropSprite={{ href, styles }}`) to use.
184
+ The plugin's `base` is relative to the output folder; Vite's own `base` (`base: '/app/'`) prefixes the served and logged href, not the emitted file: the build still writes `dist/sprites/backdrop.svg`, the dev server answers `/app/sprites/backdrop.svg`, and the plugin logs `href: "/app/sprites/backdrop.svg"`. A plugin `base` that already starts with Vite's `base` has it stripped from the file name. A style you name that the install lacks fails
185
+ the build. Use the plugin or the `nxgt-backdrop-sprite` command, not both: a `public/sprites/backdrop.svg` the command wrote is served before the plugin's route and shadows it. A Pro-only name built from a Free install is written under its Free twin and the build warns; set `edition="free"` on `IconSpritesProvider`. A sprite built from a Pro install is never committed or published. Restart the dev server after installing another Font Awesome package. See
186
+ [the backgrounds guide](backgrounds.md#a-reduced-sprite-for-the-backdrop) for the runtime side.
187
+
162
188
  ## Rendering PDFs on a bundled server
163
189
 
164
190
  `pdf` is on by default and costs nothing for an app that never renders a PDF:
package/docs/roadmap.md CHANGED
@@ -204,6 +204,12 @@ version they shipped in, and planned entries may name the major they target.
204
204
 
205
205
  ## Later
206
206
 
207
+ - **A strict theme `motif` (4.0)** — a theme background's `motif` with an
208
+ unknown key, a `layout` or `density` outside its list or a bad `icons` is
209
+ dropped in 3.22 (`@nxgt/material/themes`'s `defineTheme` warns for each one in
210
+ development; core's only through `{ warn }`); in 4.0 `defineTheme` throws
211
+ (`name` for a key, `range` for a value), as it does for the icon keys.
212
+
207
213
  - **More illustration sets** — finance, travel and tech scenes beside the
208
214
  health and education sets, each in its own subpath.
209
215
  - **More generic scenes** — further base scenes for `Illustration` beyond the
@@ -31,6 +31,10 @@ words in your error.
31
31
  - [A theme's colours do not show](#a-themes-colours-do-not-show)
32
32
  - [Math renders in the system fonts](#math-renders-in-the-system-fonts)
33
33
  - [`<Icon>` renders nothing](#icon-renders-nothing)
34
+ - [`backdropSprite needs the icon packs your backdrops draw`](#backdropsprite-needs-the-icon-packs-your-backdrops-draw)
35
+ - [Backdrop icons are blank with a reduced sprite](#backdrop-icons-are-blank-with-a-reduced-sprite)
36
+ - [The `icons` backdrop looks different after 3.22](#the-icons-backdrop-looks-different-after-322)
37
+ - [`defineTheme: Theme "x" background.motif: unknown key spin. Ignored.`](#definetheme-theme-x-backgroundmotif-unknown-key-spin-ignored)
34
38
  - [A background, an illustration or a theme tile draws no icons](#a-background-an-illustration-or-a-theme-tile-draws-no-icons)
35
39
  - [`Background: icons cannot be drawn (…); drawing "scatter-icons" instead.`](#background-icons-cannot-be-drawn--drawing-scatter-icons-instead)
36
40
  - [`IconRefError` from `IconSpritesProvider`](#iconreferror-from-iconspritesprovider)
@@ -798,11 +802,50 @@ public/assets/icons/sprites/sharp-solid.svg ← <Icon name="atom" family="sharp"
798
802
 
799
803
  Serve one sheet per style you use, from your own Font Awesome Pro kit. With Font Awesome Free (`solid.svg`, `regular.svg`, `brands.svg`), set `edition="free"` on `IconSpritesProvider`: the library's own icons (the app shell menu, `AccountMenu`, pagination…) are duotone, and they then draw from `solid.svg`.
800
804
 
805
+ ### `backdropSprite needs the icon packs your backdrops draw`
806
+
807
+ **When:** `nxgt-backdrop-sprite` exits with this message, or `vite` stops at startup with it, or `nxgtMaterial({ backdropSprite: {} })` throws it (`true` is a type error, and throws the same in plain JavaScript).
808
+ **Why:** the reduced sprite holds only the icon names you ask for, and no pack is assumed: a default would ship names your backdrops may never draw, or miss the ones they do.
809
+ **Fix:** name the packs your `Background` draws (`icons="health"`, or the default `school`), or the names of your own `icons` list:
810
+
811
+ ```sh
812
+ npx nxgt-backdrop-sprite --pack health --pack school
813
+ npx nxgt-backdrop-sprite --icon heart-pulse --icon stethoscope
814
+ ```
815
+
816
+ ```ts
817
+ nxgtMaterial({ backdropSprite: { packs: ['health'] } }) // or { icons: ['heart-pulse'] }
818
+ ```
819
+
820
+ ### Backdrop icons are blank with a reduced sprite
821
+
822
+ **When:** `IconSpritesProvider` has `backdropSprite`, and `Background preset="icons"` draws its shapes but no icons. The network tab shows a `404` (or an HTML page) for `/sprites/backdrop.svg`, or the file loads and the icons stay empty.
823
+ **Why:** the sprite is missing, its `href` does not match where you serve it (a different `base` or `outFile`, a sub-path deployment), or it does not hold the symbol the backdrop asks for: a name from an `icons` list or pack you did not give the build, or a style you listed in `styles` that the sprite was not built with. A symbol is `<file>--<name>` (`thin--book-open`).
824
+ **Fix:** run `npx nxgt-backdrop-sprite --pack health --out public/sprites/backdrop.svg --base /sprites/` (or add `nxgtMaterial({ backdropSprite: { packs: ['health'] } })`), serve the file at the `href` you give the provider, and give the build every pack (`--pack`) and name (`--icon`) your backdrops use. Open the file: `grep -c "<symbol" public/sprites/backdrop.svg`, and `grep 'id="thin--book-open"'`. `IconRefError` (`base`) from the provider means the `href` is not a root-relative `.svg` path. A build that fails with "no <style> sheet" or "No Font Awesome install" names a style or package the install lacks. Copy the printed `backdropSprite={{ href, styles }}` so the styles match the build; with the string form, set `servedStyles` to the styles the sprite holds. `edition="free"` with a sprite built from Pro styles only is blank too: the Free edition asks for `regular` and `solid` symbols, so build with `--style regular --style solid`. The opposite case: a sprite built from a Free install writes each Pro-only name (`backpack`, `chevrons-left`) under its Free twin's id (`school`, `angles-left`), and the command or the build warns "Pro-only names written under their Free twin"; the Pro edition then asks for the Pro name and draws nothing, so set `edition="free"` on `IconSpritesProvider`. A `public/sprites/backdrop.svg` written by the command also shadows the plugin's sprite: use one of the two. If `nxgt-backdrop-sprite` prints "@nxgt/material-core is not built", build or reinstall `@nxgt/material-core`.
825
+
826
+ ### The `icons` backdrop looks different after 3.22
827
+
828
+ **When:** after upgrading to 3.22, `Background preset="icons"` (or a theme that names it) draws shapes among a few icons, in one soft tint, in several styles, and the glyphs stay clear of the cards, lists and text of the page.
829
+ **Why:** that is the new default: motif shapes and about one icon in five on an even grid (`motif.icons.ratio` 0.2, `density` `medium`), `iconMotif.colors: 'one'`, a weighted `iconStyle` of five styles, and the drop rule (a glyph whose box meets a surface, a text or a control is dropped, not moved). No prop was removed. A style whose sprite the app does not serve is dropped; with none served the scene draws Free `regular` and `solid`, so a Free-only or half-served app needs `servedStyles` or `edition="free"` on `IconSpritesProvider`.
830
+ **Fix:** to keep what you had, pass the three props below (in a theme, the same keys under `background`). To keep the new look and shrink the download, build the reduced sprite (`npx nxgt-backdrop-sprite --pack school`). For fewer or more glyphs, `motif={{ density: 'low' }}` or a number; for no icons, `motif={{ icons: { ratio: 0 } }}`.
831
+
832
+ ```tsx
833
+ <Background preset="icons" iconStyle="duotone-thin" iconMotif={{ layout: 'scatter', colors: 'classic' }} />
834
+ ```
835
+
836
+ See [the previous look](guides/backgrounds.md#the-look-before-322) and [the drop rule](guides/backgrounds.md#the-drop-rule).
837
+
838
+ ### `defineTheme: Theme "x" background.motif: unknown key spin. Ignored.`
839
+
840
+ **When:** in development, `defineTheme` from `@nxgt/material/themes` logs a line such as `Theme "x" background.motif: unknown key spin. Ignored.`, `Theme "x" background.motif: density: low, default, medium, high or a count from 1 to 600. Ignored.`, `Theme "x" background.motif: layout: not scatter, even. Ignored.`, `Theme "x" background.motif: expected an object. Ignored.` or, for a bad `motif.icons`, the reason (`… background.motif.icons.ratio: a number from 0 to 1. Ignored.`), and the setting has no effect. Nothing throws, and nothing is logged in production.
841
+ **Why:** since 3.22 a bad key or value under a theme background's `motif` (a misspelt key, a `layout` or `density` outside its list, a bad `motif.icons`) is dropped and the rest of the theme is kept; 4.0 makes it a `ThemeDefinitionError`. Core's `defineTheme` (`@nxgt/material-core/theme/define`) drops it silently unless you pass `{ warn }`.
842
+ **Fix:** use a known key and a valid value: `motif: { density: 'medium', layout: 'even', icons: { ratio: 0.2 } }` (`density` is `low`, `default`, `medium`, `high` or a count from 1 to 600).
843
+
801
844
  ### A background, an illustration or a theme tile draws no icons
802
845
 
803
- **When:** `Background preset="icons"`, an `Illustration`, an `EmptyState` with an `illustration`, or a `ThemePicker` tile shows its wash or its plate and no icons. The network tab shows a `404` for `/assets/icons/sprites/duotone-thin.svg` (the default style), or for the sheet of the `iconStyle` you chose. No error is thrown.
804
- **Why:** these icons are `<use>` references to sprite sheets your app serves; the library ships none (the Font Awesome licence does not allow it). The default style is `duotone-thin`, so a Free-only app, which has `solid.svg`, `regular.svg` and `brands.svg`, draws nothing until it asks for a Free style. A name the sheet does not hold is blank too, such as `backpack` or `books`, which exist in Pro only. A theme tile with no icons keeps its wash: that is the intended fallback, not a bug.
805
- **Fix:** serve the sheet (or move the base with `IconSpritesProvider`). With only the Free sheets, say so: `<IconSpritesProvider base="/assets/icons/sprites/" edition="free">` draws every style Free lacks from `solid.svg` and the Pro-only names as their Free twin, so the app shell's menu, `AccountMenu` and the rest need nothing else (do not copy `solid.svg` to `duotone.svg`). Or choose a style you serve, and give Free names:
846
+ **When:** `Background preset="icons"`, an `Illustration`, an `EmptyState` with an `illustration`, or a `ThemePicker` tile shows its wash or its plate and no icons. The network tab shows a `404` for the sheets of the default mix of `preset="icons"` (`light.svg`, `thin.svg`, `sharp-regular.svg`, `sharp-light.svg`, `duotone-thin.svg` under `/assets/icons/sprites/`; `Illustration` and `Icon` default to `duotone-thin.svg`), or for the sheet of the `iconStyle` you chose. No error is thrown.
847
+ **Why:** these icons are `<use>` references to sprite sheets your app serves; the library ships none (the Font Awesome licence does not allow it). `Illustration` and `Icon` default to `duotone-thin`, and `preset="icons"` draws a weighted mix of five styles (it drops the ones `IconSpritesProvider`'s `servedStyles` does not list), so a Free-only app, which has `solid.svg`, `regular.svg` and `brands.svg`, draws nothing until it asks for a Free style. A name the sheet does not hold is blank too, such as `backpack` or `books`, which exist in Pro only. A theme tile with no icons keeps its wash: that is the intended fallback, not a bug.
848
+ **Fix:** serve the sheet (or move the base with `IconSpritesProvider`, and list the sheets you serve in its `servedStyles`). With only the Free sheets, say so: `<IconSpritesProvider base="/assets/icons/sprites/" edition="free">` draws every style Free lacks from `solid.svg` and the Pro-only names as their Free twin, so the app shell's menu, `AccountMenu` and the rest need nothing else (do not copy `solid.svg` to `duotone.svg`). Or choose a style you serve, and give Free names:
806
849
 
807
850
  ```tsx
808
851
  // Free sprites copied to public/assets/icons/sprites/solid.svg
@@ -4,7 +4,7 @@
4
4
  * band is `--background-quiet` wide (42%), then the icons fade back in over
5
5
  * 30%. `start` and `end` follow the reading direction. A mask, not a colour:
6
6
  * the text underneath keeps the wash's own contrast. */
7
- [data-background="icons"] > [data-scene] > :is(.ic-q-start, .ic-q-end) {
7
+ [data-background] > [data-scene] > :is(.ic-q-start, .ic-q-end) {
8
8
  --nxgt-quiet-to: to right;
9
9
  -webkit-mask-image: linear-gradient(
10
10
  var(--nxgt-quiet-to),
@@ -17,14 +17,14 @@
17
17
  #000 calc(var(--background-quiet, 42%) + 30%)
18
18
  );
19
19
  }
20
- [data-background="icons"] > [data-scene] > .ic-q-end,
21
- [data-background="icons"] > [data-scene]:dir(rtl) > .ic-q-start {
20
+ [data-background] > [data-scene] > .ic-q-end,
21
+ [data-background] > [data-scene]:dir(rtl) > .ic-q-start {
22
22
  --nxgt-quiet-to: to left;
23
23
  }
24
- [data-background="icons"] > [data-scene]:dir(rtl) > .ic-q-end {
24
+ [data-background] > [data-scene]:dir(rtl) > .ic-q-end {
25
25
  --nxgt-quiet-to: to right;
26
26
  }
27
- [data-background="icons"] > [data-scene] > .ic-q-center {
27
+ [data-background] > [data-scene] > .ic-q-center {
28
28
  -webkit-mask-image: linear-gradient(
29
29
  to right,
30
30
  #000 calc(50% - var(--background-quiet, 42%) / 2 - 30%),
@@ -0,0 +1,98 @@
1
+ /* The tint of the icons scene (`iconMotif.colors`, React only): a class on the
2
+ * scene root. `ic-c-one` (default) draws every glyph in the primary tone
3
+ * mixed toward transparent, a low contrast on any surface and a soft one in
4
+ * dark, never bright; `ic-c-palette` spreads primary, secondary and tertiary
5
+ * (`k1..k3`) at the same contrast; the rules out-rank icons.css's `.ic.k1..k3` tones; `ic-c-classic` has no rule here (icons.css
6
+ * gives the tones at full strength). The icons read `--fa-primary-color`
7
+ * (duotone and the sprites' paint) and `currentColor` (the flat styles), so the
8
+ * tint sets both. The motif shapes of the mix sit at 0.8 of the icons' tint. */
9
+ @layer components {
10
+ [data-background] > [data-scene] > :is(.ic-c-one, .ic-c-palette) {
11
+ --ic-soft: 46%;
12
+ }
13
+ :is(.dark, [data-theme="dark"])
14
+ [data-background]
15
+ > [data-scene]
16
+ > :is(.ic-c-one, .ic-c-palette),
17
+ [data-background]:is(.dark, [data-theme="dark"])
18
+ > [data-scene]
19
+ > :is(.ic-c-one, .ic-c-palette) {
20
+ --ic-soft: 44%;
21
+ }
22
+
23
+ /* One tint. */
24
+ [data-background] > [data-scene] > .ic-c-one .ic:is(.k1, .k2, .k3) {
25
+ --ic-tint: color-mix(
26
+ in oklab,
27
+ var(--nxgt-bg-t1) var(--ic-soft),
28
+ transparent
29
+ );
30
+ --fa-primary-color: var(--ic-tint);
31
+ --fa-secondary-color: var(--ic-tint);
32
+ color: var(--ic-tint);
33
+ }
34
+ [data-background] > [data-scene] > .ic-c-one :is(.k1, .k2, .k3):not(.ic) {
35
+ color: color-mix(
36
+ in oklab,
37
+ var(--nxgt-bg-t1) calc(var(--ic-soft) * 0.8),
38
+ transparent
39
+ );
40
+ }
41
+ [data-background] > [data-scene] > .ic-c-one :is(.ic-ln, .ic-dt) {
42
+ stroke: color-mix(in oklab, var(--nxgt-bg-t1) var(--ic-soft), transparent);
43
+ fill: none;
44
+ }
45
+ [data-background] > [data-scene] > .ic-c-one .ic-dt {
46
+ fill: color-mix(in oklab, var(--nxgt-bg-t1) var(--ic-soft), transparent);
47
+ stroke: none;
48
+ }
49
+
50
+ /* Three tints, the same contrast. */
51
+ [data-background] > [data-scene] > .ic-c-palette .ic.k1 {
52
+ --ic-tint: color-mix(
53
+ in oklab,
54
+ var(--nxgt-bg-c1) var(--ic-soft),
55
+ transparent
56
+ );
57
+ }
58
+ [data-background] > [data-scene] > .ic-c-palette .ic.k2 {
59
+ --ic-tint: color-mix(
60
+ in oklab,
61
+ var(--nxgt-bg-c2) var(--ic-soft),
62
+ transparent
63
+ );
64
+ }
65
+ [data-background] > [data-scene] > .ic-c-palette .ic.k3 {
66
+ --ic-tint: color-mix(
67
+ in oklab,
68
+ var(--nxgt-bg-c3) var(--ic-soft),
69
+ transparent
70
+ );
71
+ }
72
+ [data-background] > [data-scene] > .ic-c-palette .ic:is(.k1, .k2, .k3) {
73
+ --fa-primary-color: var(--ic-tint);
74
+ --fa-secondary-color: var(--ic-tint);
75
+ color: var(--ic-tint);
76
+ }
77
+ [data-background] > [data-scene] > .ic-c-palette .k1:not(.ic) {
78
+ color: color-mix(
79
+ in oklab,
80
+ var(--nxgt-bg-c1) calc(var(--ic-soft) * 0.8),
81
+ transparent
82
+ );
83
+ }
84
+ [data-background] > [data-scene] > .ic-c-palette .k2:not(.ic) {
85
+ color: color-mix(
86
+ in oklab,
87
+ var(--nxgt-bg-c2) calc(var(--ic-soft) * 0.8),
88
+ transparent
89
+ );
90
+ }
91
+ [data-background] > [data-scene] > .ic-c-palette .k3:not(.ic) {
92
+ color: color-mix(
93
+ in oklab,
94
+ var(--nxgt-bg-c3) calc(var(--ic-soft) * 0.8),
95
+ transparent
96
+ );
97
+ }
98
+ }
@@ -4,7 +4,10 @@
4
4
  * its constellation threads and its motion. A scene holds no `style`: an icon
5
5
  * carries a tone class (`k1..k3`, colours in scene.css) and the root carries
6
6
  * `ic-so0..ic-so10` and `ic-so85` (a duotone icon's second layer, in tenths, or 0.85) and, for
7
- * `duotone: 'tones'`, `ic-tones`.
7
+ * `duotone: 'tones'`, `ic-tones`. The rules are keyed on `icons` and `shapes`
8
+ * (the `shapes` preset with `motif.icons` draws the same icons). The
9
+ * tint (`ic-c-one`, `ic-c-palette`) is icons-tint.css; `ic-c-classic` is the
10
+ * tones below at full strength.
8
11
  *
9
12
  * The sprites read `--fa-primary-color`, `--fa-secondary-color` and
10
13
  * `--fa-secondary-opacity`; custom properties inherit into the `<use>` copy.
@@ -17,6 +20,7 @@
17
20
  @import "../css/motifs.css";
18
21
 
19
22
  @import "./icons-quiet.css";
23
+ @import "./icons-tint.css";
20
24
 
21
25
  @layer components {
22
26
  [data-background="icons"] > [data-layer="wash"] {
@@ -35,95 +39,158 @@
35
39
  );
36
40
  }
37
41
 
38
- [data-background="icons"] > [data-scene] {
42
+ :is([data-background="icons"], [data-background="shapes"]) > [data-scene] {
39
43
  overflow: hidden;
40
44
  }
41
45
 
42
46
  /* Primary layer: the icon's tone. Second layer: the same tone, faded. */
43
- [data-background="icons"] > [data-scene] .ic.k1 {
47
+ :is([data-background="icons"], [data-background="shapes"])
48
+ > [data-scene]
49
+ .ic.k1 {
44
50
  --fa-primary-color: var(--nxgt-bg-c1);
45
51
  --fa-secondary-color: var(--nxgt-bg-c1);
46
52
  }
47
- [data-background="icons"] > [data-scene] .ic.k2 {
53
+ :is([data-background="icons"], [data-background="shapes"])
54
+ > [data-scene]
55
+ .ic.k2 {
48
56
  --fa-primary-color: var(--nxgt-bg-c2);
49
57
  --fa-secondary-color: var(--nxgt-bg-c2);
50
58
  }
51
- [data-background="icons"] > [data-scene] .ic.k3 {
59
+ :is([data-background="icons"], [data-background="shapes"])
60
+ > [data-scene]
61
+ .ic.k3 {
52
62
  --fa-primary-color: var(--nxgt-bg-c3);
53
63
  --fa-secondary-color: var(--nxgt-bg-c3);
54
64
  }
55
65
 
56
66
  /* Two tones: the second layer takes the next tone. */
57
- [data-background="icons"] > [data-scene] > .ic-tones .ic.k1 {
67
+ :is([data-background="icons"], [data-background="shapes"])
68
+ > [data-scene]
69
+ > .ic-tones
70
+ .ic.k1 {
58
71
  --fa-secondary-color: var(--nxgt-bg-c2);
59
72
  }
60
- [data-background="icons"] > [data-scene] > .ic-tones .ic.k2 {
73
+ :is([data-background="icons"], [data-background="shapes"])
74
+ > [data-scene]
75
+ > .ic-tones
76
+ .ic.k2 {
61
77
  --fa-secondary-color: var(--nxgt-bg-c3);
62
78
  }
63
- [data-background="icons"] > [data-scene] > .ic-tones .ic.k3 {
79
+ :is([data-background="icons"], [data-background="shapes"])
80
+ > [data-scene]
81
+ > .ic-tones
82
+ .ic.k3 {
64
83
  --fa-secondary-color: var(--nxgt-bg-c1);
65
84
  }
66
85
 
67
86
  /* The second layer's opacity, in tenths (`secondaryOpacity`). */
68
- [data-background="icons"] > [data-scene] > .ic-so0 .ic {
87
+ :is([data-background="icons"], [data-background="shapes"])
88
+ > [data-scene]
89
+ > .ic-so0
90
+ .ic {
69
91
  --fa-secondary-opacity: 0;
70
92
  }
71
- [data-background="icons"] > [data-scene] > .ic-so1 .ic {
93
+ :is([data-background="icons"], [data-background="shapes"])
94
+ > [data-scene]
95
+ > .ic-so1
96
+ .ic {
72
97
  --fa-secondary-opacity: 0.1;
73
98
  }
74
- [data-background="icons"] > [data-scene] > .ic-so2 .ic {
99
+ :is([data-background="icons"], [data-background="shapes"])
100
+ > [data-scene]
101
+ > .ic-so2
102
+ .ic {
75
103
  --fa-secondary-opacity: 0.2;
76
104
  }
77
- [data-background="icons"] > [data-scene] > .ic-so3 .ic {
105
+ :is([data-background="icons"], [data-background="shapes"])
106
+ > [data-scene]
107
+ > .ic-so3
108
+ .ic {
78
109
  --fa-secondary-opacity: 0.3;
79
110
  }
80
- [data-background="icons"] > [data-scene] > .ic-so4 .ic {
111
+ :is([data-background="icons"], [data-background="shapes"])
112
+ > [data-scene]
113
+ > .ic-so4
114
+ .ic {
81
115
  --fa-secondary-opacity: 0.4;
82
116
  }
83
- [data-background="icons"] > [data-scene] > .ic-so5 .ic {
117
+ :is([data-background="icons"], [data-background="shapes"])
118
+ > [data-scene]
119
+ > .ic-so5
120
+ .ic {
84
121
  --fa-secondary-opacity: 0.5;
85
122
  }
86
- [data-background="icons"] > [data-scene] > .ic-so6 .ic {
123
+ :is([data-background="icons"], [data-background="shapes"])
124
+ > [data-scene]
125
+ > .ic-so6
126
+ .ic {
87
127
  --fa-secondary-opacity: 0.6;
88
128
  }
89
- [data-background="icons"] > [data-scene] > .ic-so7 .ic {
129
+ :is([data-background="icons"], [data-background="shapes"])
130
+ > [data-scene]
131
+ > .ic-so7
132
+ .ic {
90
133
  --fa-secondary-opacity: 0.7;
91
134
  }
92
- [data-background="icons"] > [data-scene] > .ic-so8 .ic {
135
+ :is([data-background="icons"], [data-background="shapes"])
136
+ > [data-scene]
137
+ > .ic-so8
138
+ .ic {
93
139
  --fa-secondary-opacity: 0.8;
94
140
  }
95
- [data-background="icons"] > [data-scene] > .ic-so9 .ic {
141
+ :is([data-background="icons"], [data-background="shapes"])
142
+ > [data-scene]
143
+ > .ic-so9
144
+ .ic {
96
145
  --fa-secondary-opacity: 0.9;
97
146
  }
98
- [data-background="icons"] > [data-scene] > .ic-so10 .ic {
147
+ :is([data-background="icons"], [data-background="shapes"])
148
+ > [data-scene]
149
+ > .ic-so10
150
+ .ic {
99
151
  --fa-secondary-opacity: 1;
100
152
  }
101
153
  /* 0.85: the default of two tones, or a `secondaryOpacity` of 0.85. */
102
- [data-background="icons"] > [data-scene] > .ic-so85 .ic {
154
+ :is([data-background="icons"], [data-background="shapes"])
155
+ > [data-scene]
156
+ > .ic-so85
157
+ .ic {
103
158
  --fa-secondary-opacity: 0.85;
104
159
  }
105
160
 
106
161
  /* The constellation's threads and dots. */
107
- [data-background="icons"] > [data-scene] .ic-ln {
162
+ :is([data-background="icons"], [data-background="shapes"])
163
+ > [data-scene]
164
+ .ic-ln {
108
165
  stroke: var(--nxgt-bg-c1);
109
166
  stroke-width: 0.7;
110
167
  stroke-linecap: round;
111
168
  opacity: 0.4;
112
169
  }
113
- [data-background="icons"] > [data-scene] .ic-dt {
170
+ :is([data-background="icons"], [data-background="shapes"])
171
+ > [data-scene]
172
+ .ic-dt {
114
173
  fill: var(--nxgt-bg-c1);
115
174
  opacity: 0.5;
116
175
  }
117
- [data-background="icons"] > [data-scene] .ic-ln.k2 {
176
+ :is([data-background="icons"], [data-background="shapes"])
177
+ > [data-scene]
178
+ .ic-ln.k2 {
118
179
  stroke: var(--nxgt-bg-c2);
119
180
  }
120
- [data-background="icons"] > [data-scene] .ic-ln.k3 {
181
+ :is([data-background="icons"], [data-background="shapes"])
182
+ > [data-scene]
183
+ .ic-ln.k3 {
121
184
  stroke: var(--nxgt-bg-c3);
122
185
  }
123
- [data-background="icons"] > [data-scene] .ic-dt.k2 {
186
+ :is([data-background="icons"], [data-background="shapes"])
187
+ > [data-scene]
188
+ .ic-dt.k2 {
124
189
  fill: var(--nxgt-bg-c2);
125
190
  }
126
- [data-background="icons"] > [data-scene] .ic-dt.k3 {
191
+ :is([data-background="icons"], [data-background="shapes"])
192
+ > [data-scene]
193
+ .ic-dt.k3 {
127
194
  fill: var(--nxgt-bg-c3);
128
195
  }
129
196
  }
@@ -151,26 +218,26 @@
151
218
  }
152
219
 
153
220
  @layer components {
154
- [data-background="icons"][data-animated] > [data-scene] .ia {
221
+ [data-background][data-animated] > [data-scene] .ia {
155
222
  animation: nxgt-bg-ic-1 18s ease-in-out infinite alternate
156
223
  var(--nxgt-bg-play, running);
157
224
  }
158
- [data-background="icons"][data-animated] > [data-scene] .iv2 {
225
+ [data-background][data-animated] > [data-scene] .iv2 {
159
226
  animation-name: nxgt-bg-ic-2;
160
227
  }
161
- [data-background="icons"][data-animated] > [data-scene] .iv3 {
228
+ [data-background][data-animated] > [data-scene] .iv3 {
162
229
  animation-name: nxgt-bg-ic-3;
163
230
  }
164
- [data-background="icons"][data-animated] > [data-scene] .iv4 {
231
+ [data-background][data-animated] > [data-scene] .iv4 {
165
232
  animation-name: nxgt-bg-ic-4;
166
233
  }
167
- [data-background="icons"][data-animated] > [data-scene] .id2 {
234
+ [data-background][data-animated] > [data-scene] .id2 {
168
235
  animation-delay: -4s;
169
236
  }
170
- [data-background="icons"][data-animated] > [data-scene] .id3 {
237
+ [data-background][data-animated] > [data-scene] .id3 {
171
238
  animation-delay: -9s;
172
239
  }
173
- [data-background="icons"][data-animated] > [data-scene] .id4 {
240
+ [data-background][data-animated] > [data-scene] .id4 {
174
241
  animation-delay: -13s;
175
242
  }
176
243
  }
@@ -0,0 +1,5 @@
1
+ /* What the Background in `/components` always needs: the base, the gradient
2
+ * preset and the motion rules. Imported once by components/components.css. */
3
+ @import "../backgrounds/css/base.css";
4
+ @import "../backgrounds/css/gradient.css";
5
+ @import "../backgrounds/css/motion.css";
@@ -56,6 +56,7 @@
56
56
  @import "./ui/layout/app-shell/route-transition.css";
57
57
  @import "./ui/layout/app-shell/activity-backdrop.css";
58
58
  @import "./ui/layout/app-shell/activity-backdrop-shapes.css";
59
+ @import "./ui/layout/auth-card/auth-card-backdrop.css";
59
60
  /* DataTable cards and tiles: the item shell (hairline, tint, start bar, columns by the list's width). */
60
61
  @import "./ui/collections/data-table/data-table-items.css";
61
62
  @import "./ui/collections/data-table/data-table-items-compact.css";
@@ -192,12 +193,8 @@
192
193
  /* Gallery: the View Transition from a tile to its lightbox. */
193
194
  @import "./ui/media/galleries/gallery-transitions.css";
194
195
  @import "./print-only.css";
195
- @import "./ui/fields/attributes/attribute-form/attribute-form.css";
196
- @import "./ui/fields/attributes/attribute-values-form/attribute-values-form.css";
197
- /* Background (from /components): the gradient preset's CSS, plain and shared
198
- * (lib/backgrounds/css). The other presets are opt-in: backgrounds.css. */
199
- @import "../backgrounds/css/base.css";
200
- @import "../backgrounds/css/gradient.css";
201
- @import "../backgrounds/css/motion.css";
196
+ @import "./ui/fields/attributes/attributes.css";
197
+ /* Background: the gradient preset's CSS, shared (lib/backgrounds/css); the other presets are opt-in: backgrounds.css. */
198
+ @import "./background-shared.css";
202
199
  @import "./ui/widgets/drawing/drawing.css"; /* @nxgt/material/draw: role colours, focus ring */
203
200
  @import "./ui/widgets/drawing/drawing-animate.css";
@@ -0,0 +1,3 @@
1
+ /* The attribute forms' styles, imported once by components/components.css. */
2
+ @import "./attribute-form/attribute-form.css";
3
+ @import "./attribute-values-form/attribute-values-form.css";
@@ -18,7 +18,7 @@
18
18
  visibility: hidden;
19
19
  }
20
20
 
21
- /* A shape over the page's text or controls fades out and comes back once
21
+ /* A shape over the page's text, controls or surfaces (cards, tables, lists) fades out and comes back once
22
22
  * clear (watch-content.ts): it is hidden, never moved. A compound body (the
23
23
  * moon, the planet, the eclipse: `.pt.mg`) is hidden whole, with its halo
24
24
  * (`.pt.mh`). The scene stays invisible until the first check, so nothing
@@ -0,0 +1,30 @@
1
+ /* An AuthCard's backdrop (auth-card-backdrop.tsx) keeps its shapes the way
2
+ * ActivityLayout's does (activity-backdrop-shapes.css): whole inside its layer
3
+ * and clear of the card and the brand row. Plain CSS in `@layer components`. */
4
+ @layer components {
5
+ [data-slot="auth-card-backdrop"] > [data-background] {
6
+ width: 100%;
7
+ height: 100%;
8
+ }
9
+ /* The scene stays hidden until the first pass; a shape that crosses the
10
+ * layer's edge is hidden, never cut. */
11
+ [data-slot="auth-card-backdrop"] [data-background]:not([data-checked]) .mo,
12
+ [data-slot="auth-card-backdrop"] [data-background] .mo > [data-outside] {
13
+ visibility: hidden;
14
+ }
15
+ /* A shape over the card or the brand row fades out (watch-content.ts). */
16
+ [data-slot="auth-card-backdrop"] [data-background] .mo > *,
17
+ [data-slot="auth-card-backdrop"] [data-background] .pt {
18
+ transition: opacity 150ms ease;
19
+ }
20
+ [data-slot="auth-card-backdrop"] [data-background] .mo > [data-hidden],
21
+ [data-slot="auth-card-backdrop"] [data-background] .pt[data-hidden] {
22
+ opacity: 0 !important;
23
+ }
24
+ @media (prefers-reduced-motion: reduce) {
25
+ [data-slot="auth-card-backdrop"] [data-background] .mo > *,
26
+ [data-slot="auth-card-backdrop"] [data-background] .pt {
27
+ transition: none;
28
+ }
29
+ }
30
+ }