@nxgt/material 3.21.0 → 3.23.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 (81) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +7 -5
  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-BaUx5Nax.js} +13693 -13611
  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/collections/data-table/partials/data-table-page-control.d.ts +7 -2
  30. package/dist/lib/components/ui/collections/data-table/partials/data-table-toolbar.d.ts +6 -2
  31. package/dist/lib/components/ui/collections/data-table/types.d.ts +4 -0
  32. package/dist/lib/components/ui/collections/data-table/use-pager-focus.d.ts +30 -0
  33. package/dist/lib/components/ui/collections/server-table/partials/server-table-band-classes.d.ts +6 -0
  34. package/dist/lib/components/ui/collections/server-table/partials/server-table-band.d.ts +3 -1
  35. package/dist/lib/components/ui/collections/server-table/types.d.ts +3 -0
  36. package/dist/lib/components/ui/layout/app-shell/keep-shapes-inside.d.ts +7 -2
  37. package/dist/lib/components/ui/layout/app-shell/shapes-clear-content.d.ts +10 -3
  38. package/dist/lib/components/ui/layout/app-shell/theme-backdrop.d.ts +3 -1
  39. package/dist/lib/components/ui/layout/app-shell/use-keep-shapes-inside.d.ts +3 -3
  40. package/dist/lib/components/ui/layout/app-shell/watch-content.d.ts +28 -8
  41. package/dist/lib/components/ui/layout/auth-card/auth-card-backdrop.d.ts +23 -0
  42. package/dist/lib/components/ui/layout/auth-card/auth-card.d.ts +15 -1
  43. package/dist/lib/components/ui/primitives/icon/icon-sprites.d.ts +40 -1
  44. package/dist/lib/themes/define-theme.d.ts +8 -0
  45. package/dist/lib/themes/index.d.ts +2 -1
  46. package/dist/lib/vite/index.d.ts +1 -1
  47. package/dist/main.js +28 -28
  48. package/dist/material.css +1 -1
  49. package/dist/pdf-reader.js +1 -1
  50. package/dist/{public-DWuBn4t_.js → public-DAF5SCWH.js} +1 -1
  51. package/dist/{scene-options-CCy3V7XS.js → scene-options-2zNF3ZkQ.js} +4 -2
  52. package/dist/theme-picker.js +3 -3
  53. package/dist/themes.js +9 -4
  54. package/dist/{use-chat-composer-BBFuKNqC.js → use-chat-composer-B0ze1cU9.js} +3 -3
  55. package/docs/components/data-table-filter-and-lists.md +24 -2
  56. package/docs/components/navigation-and-layout.md +22 -0
  57. package/docs/components/primitives.md +21 -0
  58. package/docs/guides/app-shell.md +9 -8
  59. package/docs/guides/backgrounds.md +214 -16
  60. package/docs/guides/icon-motifs.md +30 -12
  61. package/docs/guides/themes.md +25 -4
  62. package/docs/guides/theming.md +7 -0
  63. package/docs/guides/vite-plugin.md +26 -0
  64. package/docs/previews/backgrounds-background-from-theme.webp +0 -0
  65. package/docs/previews/backgrounds-icons.webp +0 -0
  66. package/docs/previews/backgrounds-matrix.webp +0 -0
  67. package/docs/previews/foundations-themes-icon-motifs.webp +0 -0
  68. package/docs/roadmap.md +6 -0
  69. package/docs/troubleshooting.md +65 -3
  70. package/lib/backgrounds/css-react/icons-quiet.css +5 -5
  71. package/lib/backgrounds/css-react/icons-tint.css +98 -0
  72. package/lib/backgrounds/css-react/icons.css +100 -33
  73. package/lib/components/background-shared.css +5 -0
  74. package/lib/components/components.css +4 -7
  75. package/lib/components/ui/fields/attributes/attributes.css +3 -0
  76. package/lib/components/ui/layout/app-shell/activity-backdrop-shapes.css +1 -1
  77. package/lib/components/ui/layout/auth-card/auth-card-backdrop.css +30 -0
  78. package/package.json +8 -3
  79. package/dist/background-Ce7M5V42.js +0 -250
  80. package/dist/icon-sprites-FxHyqyhg.js +0 -30
  81. package/dist/icons-scene-BpIauJ5d.js +0 -27
@@ -16,7 +16,7 @@ Free works the same way.
16
16
 
17
17
  | You have | Serve | Use |
18
18
  | --- | --- | --- |
19
- | the Pro 7.3 pack | one sheet per style you draw, in `public/assets/icons/sprites/`: `duotone-thin.svg` (the default look), `duotone.svg`, `solid.svg`, `sharp-solid.svg`… A non-classic family is `<family>-<style>.svg` | the defaults |
19
+ | the Pro 7.3 pack | one sheet per style you draw, in `public/assets/icons/sprites/`: the icon backgrounds' default mix needs `light.svg`, `thin.svg`, `sharp-regular.svg`, `sharp-light.svg` and `duotone-thin.svg`; `Icon`'s default look `duotone-thin.svg`; then `duotone.svg`, `solid.svg`, `sharp-solid.svg`… A non-classic family is `<family>-<style>.svg` | the defaults |
20
20
  | Font Awesome Free | `solid.svg`, `regular.svg` and `brands.svg` from `@fortawesome/fontawesome-free/sprites/`, copied to the same folder | `<IconSpritesProvider base="…" edition="free">` once at the root ([Free edition](#the-free-edition)) |
21
21
 
22
22
  The Free icons are CC BY 4.0: credit Font Awesome where you show them (the
@@ -54,23 +54,39 @@ import { Background } from '@nxgt/material/backgrounds';
54
54
  preset="icons"
55
55
  tone="mixed"
56
56
  icons="health" // a pack, or up to 48 names and { name, family?, type? }
57
- iconStyle={['duotone-thin', 'duotone-light']} // one style, or a list of up to 8
58
- iconMotif={{ layout: 'constellation', duotone: 'opacity' }}
57
+ iconStyle={[{ style: 'light', weight: 3 }, { style: 'duotone-thin' }]} // one style, a list of up to 8, or a weighted list
58
+ iconMotif={{ colors: 'one' }} // 'one', 'palette' or 'classic'
59
+ motif={{ icons: { ratio: 0.2 }, density: 'medium' }} // the share of icons among the shapes
59
60
  />;
60
61
  ```
61
62
 
62
- <img src="../previews/backgrounds-icons.webp" width="480" alt="The school pack of icons scattered over a faint wash, around a card">
63
+ Since 3.22 this draws a **calm mix**: motif shapes and, in about one cell in
64
+ five, an icon, all in one soft primary tint on an even grid over the whole
65
+ frame (`preset="shapes"` with `motif.icons` draws the same). The [backgrounds
66
+ guide](backgrounds.md#icons) lists the options.
67
+
68
+ <img src="../previews/backgrounds-icons.webp" width="480" alt="The calm mix of shapes and a few school icons in one soft tint, in the open space below a dashboard">
63
69
 
64
70
  - **`icons`**: a pack name (`school`, `health`, `finance`, `travel`, `nature`,
65
71
  `tech`: lists of names, drawn in any style) or your own names and
66
72
  `{ name, family?, type? }` references. No `icons` draws the `school` pack.
67
- - **`iconStyle`**: one style (`'duotone-thin'`, `{ family: 'sharp', type: 'solid' }`)
68
- or a list of up to 8. Each icon takes one style from the list by the seeded
69
- pick, so a seed always draws the same picture. An icon's own `family` / `type`
70
- always wins. Keep a list to styles that share your names.
71
- - **`iconMotif`**: `layout` (`scatter`, `grid`, `constellation`, `drift`),
72
- `sizeRange`, `rotation`, `duotone` (`'opacity'`: the second layer is the same
73
- tone at 0.4; `'tones'`: the next tone) and `secondaryOpacity`.
73
+ - **`iconStyle`**: one style (`'duotone-thin'`, `{ family: 'sharp', type: 'solid' }`),
74
+ a list of up to 8, or a weighted list `[{ style, weight? }]`. Each icon takes
75
+ one style by the seeded pick, so a seed always draws the same picture. An
76
+ icon's own `family` / `type` always wins. Keep a list to styles that share
77
+ your names. The default is a weighted list (light 3, thin 3, sharp-regular 2,
78
+ sharp-light 2, duotone-thin 1): a weighted list is cut to the sprites your app
79
+ serves (`IconSpritesProvider`'s `servedStyles`, or the Free edition's
80
+ `regular` and `solid`), keeps the others' proportions, and draws Free
81
+ `regular` and `solid` when nothing is left.
82
+ - **`iconMotif`**: `layout` (`even`, the default mix of shapes and icons;
83
+ `scatter`, `grid`, `constellation`, `drift`: icons only), `colors` (`'one'`,
84
+ `'palette'`, `'classic'`), `sizeRange`, `rotation`, `duotone` (`'opacity'`:
85
+ the second layer is the same tone at 0.4; `'tones'`: the next tone) and
86
+ `secondaryOpacity`.
87
+ - **The look before 3.22** is icons only, scattered, in duotone thin and the
88
+ three tones at full strength:
89
+ `<Background preset="icons" iconStyle="duotone-thin" iconMotif={{ layout: 'scatter', colors: 'classic' }} />`.
74
90
  - `animated` drifts each icon a little; nothing moves under
75
91
  `prefers-reduced-motion`. Icons that cannot be drawn (an unknown pack or style,
76
92
  a bad name, more than 48) draw `scatter-icons`, with a console warning outside
@@ -192,7 +208,9 @@ Below it, in every `Icon` (so the app shell's menu, `AccountMenu`,
192
208
  every theme tile:
193
209
 
194
210
  - a style Free lacks is drawn from `solid.svg`: the default duotone, `thin`,
195
- `light`, `sharp-*` and every other family. `regular` and `brands` stay;
211
+ `light`, `sharp-*` and every other family. `regular` and `brands` stay. An
212
+ icon background's weighted `iconStyle` (the default mix included) draws
213
+ `regular` and `solid` instead, since no Pro style is served;
196
214
  - a Pro-only name is renamed to its Free twin, the same one in every place
197
215
  (the table below, plus `chevrons-*` to `angles-*`, `badge-check` to
198
216
  `circle-check`, `loader` to `spinner`).
@@ -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)
@@ -352,6 +356,8 @@ words in your error.
352
356
  - [A `ServerTable` search shows older text, or a write is lost, over a slow router](#a-servertable-search-shows-older-text-or-a-write-is-lost-over-a-slow-router)
353
357
  - [`ListEmpty`'s title is now a heading](#listempty-title-is-now-a-heading)
354
358
  - [`ServerTable` keeps showing the empty page or the old rows after a failed fetch](#servertable-keeps-showing-the-empty-page-or-the-old-rows-after-a-failed-fetch)
359
+ - [The focus falls to `<body>` after Previous / Next on a `ServerTable`](#the-focus-falls-to-body-after-previous--next-on-a-servertable)
360
+ - [An empty gap under the `ServerTable` band while nothing is selected](#an-empty-gap-under-the-servertable-band-while-nothing-is-selected)
355
361
  - [The focus falls to the page after a `DataTable` bulk action](#the-focus-falls-to-the-page-after-a-datatable-bulk-action)
356
362
  - [A test's `getByText('No data available')` finds two elements after a change](#a-tests-getbytextno-data-available-finds-two-elements-after-a-change)
357
363
  - [`` [@nxgt/material] DataTable: `virtual` needs `maxHeight`; the rows are not virtualized. ``](#nxgtmaterial-datatable-virtual-needs-maxheight-the-rows-are-not-virtualized)
@@ -798,11 +804,50 @@ public/assets/icons/sprites/sharp-solid.svg ← <Icon name="atom" family="sharp"
798
804
 
799
805
  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
806
 
807
+ ### `backdropSprite needs the icon packs your backdrops draw`
808
+
809
+ **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).
810
+ **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.
811
+ **Fix:** name the packs your `Background` draws (`icons="health"`, or the default `school`), or the names of your own `icons` list:
812
+
813
+ ```sh
814
+ npx nxgt-backdrop-sprite --pack health --pack school
815
+ npx nxgt-backdrop-sprite --icon heart-pulse --icon stethoscope
816
+ ```
817
+
818
+ ```ts
819
+ nxgtMaterial({ backdropSprite: { packs: ['health'] } }) // or { icons: ['heart-pulse'] }
820
+ ```
821
+
822
+ ### Backdrop icons are blank with a reduced sprite
823
+
824
+ **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.
825
+ **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`).
826
+ **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`.
827
+
828
+ ### The `icons` backdrop looks different after 3.22
829
+
830
+ **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.
831
+ **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`.
832
+ **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 } }}`.
833
+
834
+ ```tsx
835
+ <Background preset="icons" iconStyle="duotone-thin" iconMotif={{ layout: 'scatter', colors: 'classic' }} />
836
+ ```
837
+
838
+ See [the previous look](guides/backgrounds.md#the-look-before-322) and [the drop rule](guides/backgrounds.md#the-drop-rule).
839
+
840
+ ### `defineTheme: Theme "x" background.motif: unknown key spin. Ignored.`
841
+
842
+ **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.
843
+ **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 }`.
844
+ **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).
845
+
801
846
  ### A background, an illustration or a theme tile draws no icons
802
847
 
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:
848
+ **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.
849
+ **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.
850
+ **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
851
 
807
852
  ```tsx
808
853
  // Free sprites copied to public/assets/icons/sprites/solid.svg
@@ -6459,6 +6504,23 @@ const columns = [{ accessorKey: 'name', header: NameHeader }];
6459
6504
  **Why:** `ServerTable` cannot tell a failed fetch from an empty answer: `error` was never passed, or it was passed and never cleared (`null`) when the next answer landed, so the failure stays on screen.
6460
6505
  **Fix:** pass `error` while the fetch has failed, with `onRetry`, and set it back to `null` as soon as the next answer lands. See [ServerTable](components/data-table-filter-and-lists.md#servertable).
6461
6506
 
6507
+ ### The focus falls to `<body>` after Previous / Next on a `ServerTable`
6508
+
6509
+ Versions before `reserveActions` landed swapped a page link for a disabled
6510
+ button while the next page loaded, which dropped the focus to `<body>`
6511
+ (always on a phone's tiles). Upgrade: the control now stays, `aria-disabled`,
6512
+ and the focus moves to its counterpart when one goes (Next on the last page).
6513
+ See [Focus while paging](components/data-table-filter-and-lists.md#focus-while-paging).
6514
+ A custom `linkComponent` must render an element that can take the focus (an
6515
+ `<a href>`).
6516
+
6517
+ ### An empty gap under the `ServerTable` band while nothing is selected
6518
+
6519
+ Versions before `reserveActions` reserved the toolbar's 68px (`header-placeholder`) for the
6520
+ bulk actions. `ServerTable` now reserves nothing. On `DataTable` itself the
6521
+ default is still `reserveActions` `true`: pass `reserveActions={false}` to get
6522
+ the same.
6523
+
6462
6524
  ### The focus falls to the page after a `DataTable` bulk action
6463
6525
 
6464
6526
  **When:** a bulk action clears the selection, its buttons unmount, and the next Tab starts from the top of the page.
@@ -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
+ }