@nxgt/material 3.50.0 → 3.52.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 (95) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/{async-slice-3loEtzUY.js → async-slice-BGtmF3K5.js} +2 -2
  3. package/dist/{button-BRUaHD8z.js → button-Ct0KRBsN.js} +1 -1
  4. package/dist/charts.js +3 -3
  5. package/dist/{chip-DneTrtNj.js → chip-Ca1SEd70.js} +2 -2
  6. package/dist/{code-editor-R_nPN_-d.js → code-editor-DtwRhK8B.js} +6 -6
  7. package/dist/code-editor.js +5 -5
  8. package/dist/{code-language-items-BKEUhQlF.js → code-language-items-CEclGxhA.js} +2 -2
  9. package/dist/components/ui/layout/app-shell/activity-backdrop-shapes.css +14 -9
  10. package/dist/components/ui/layout/auth-card/auth-card-backdrop.css +2 -2
  11. package/dist/{components-D6xFLcoE.js → components-CzELzsOi.js} +6006 -5824
  12. package/dist/components.js +19 -19
  13. package/dist/{dialog-S7dLsYRZ.js → dialog-BIy04Hpd.js} +4 -4
  14. package/dist/dnd.js +1 -1
  15. package/dist/{dropdown-menu-XLlxfDgq.js → dropdown-menu-B0Kd8x3G.js} +1 -1
  16. package/dist/editor.js +9 -9
  17. package/dist/{empty-state-Dsf6R-Zo.js → empty-state-CKxORwFE.js} +2 -2
  18. package/dist/{escape-owner-B9eCwjLw.js → escape-owner-BGKjiglh.js} +1 -1
  19. package/dist/{field-blur-5uRDFHvB.js → field-blur-Dz1zPaYK.js} +1 -1
  20. package/dist/{field-blur-context-Cwt4TuBq.js → field-blur-context-1T6GkSNc.js} +1 -1
  21. package/dist/hooks.js +2 -2
  22. package/dist/{hover-card-PHUgRSjJ.js → hover-card-BwQ9IRxa.js} +2 -2
  23. package/dist/{i18n-provider-DPM_ALQ4.js → i18n-provider-BFNrM0Qu.js} +14 -12
  24. package/dist/i18n.js +5 -5
  25. package/dist/{icon-badge-Dh6-FNOF.js → icon-badge-D5Ns7ndZ.js} +3 -3
  26. package/dist/{icon-button-DSC2-IAG.js → icon-button-VzdqY_Tv.js} +1 -1
  27. package/dist/lib/components/ui/collections/data-table/data-table-selection-host.d.ts +7 -0
  28. package/dist/lib/components/ui/collections/data-table/internal.d.ts +1 -0
  29. package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-list-bar.d.ts +2 -1
  30. package/dist/lib/components/ui/collections/server-table/partials/filtered-server-table.d.ts +9 -0
  31. package/dist/lib/components/ui/collections/server-table/partials/server-table-band-view.d.ts +18 -0
  32. package/dist/lib/components/ui/collections/server-table/partials/server-table-band.d.ts +10 -1
  33. package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-buttons.d.ts +3 -2
  34. package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-more.d.ts +4 -2
  35. package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk.d.ts +2 -1
  36. package/dist/lib/components/ui/collections/server-table/partials/server-table-controls.d.ts +16 -0
  37. package/dist/lib/components/ui/collections/server-table/partials/server-table-grid.d.ts +3 -1
  38. package/dist/lib/components/ui/collections/server-table/partials/server-table-selection-bar.d.ts +17 -0
  39. package/dist/lib/components/ui/collections/server-table/partials/server-table-view.d.ts +15 -0
  40. package/dist/lib/components/ui/collections/server-table/partials/use-server-table-list-root.d.ts +10 -0
  41. package/dist/lib/components/ui/collections/server-table/partials/use-server-table-phone-row.d.ts +15 -0
  42. package/dist/lib/components/ui/collections/server-table/partials/use-server-table-selection-slots.d.ts +24 -0
  43. package/dist/lib/components/ui/collections/server-table/use-selection-band.d.ts +14 -0
  44. package/dist/lib/components/ui/display/change-history/types.d.ts +2 -1
  45. package/dist/lib/components/ui/display/description/description.d.ts +2 -2
  46. package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
  47. package/dist/lib/components/ui/fields/verification-code/use-resend-focus.d.ts +4 -1
  48. package/dist/lib/components/ui/layout/app-shell/use-keep-shapes-inside.d.ts +12 -1
  49. package/dist/lib/components/ui/primitives/tabs/tabs-overflow-classes.d.ts +8 -5
  50. package/dist/lib/components/ui/primitives/tabs/use-tabs-overflow.d.ts +4 -3
  51. package/dist/lib/i18n/i18n-provider.d.ts +14 -3
  52. package/dist/lib/i18n/resources/en/en.d.ts +3 -0
  53. package/dist/lib/i18n/resources/en/material.json.d.ts +4 -1
  54. package/dist/lib/i18n/resources/fr/fr.d.ts +3 -0
  55. package/dist/lib/i18n/resources/fr/material.json.d.ts +4 -1
  56. package/dist/lib/i18n/resources/resources.d.ts +6 -0
  57. package/dist/lib/i18n/translate-material.d.ts +7 -1
  58. package/dist/lib/i18n/translator.d.ts +1 -1
  59. package/dist/lib/i18n/types.d.ts +6 -0
  60. package/dist/lib/i18n/use-material-translation.d.ts +4 -0
  61. package/dist/lib.js +1 -1
  62. package/dist/main.js +25 -25
  63. package/dist/map.js +8 -8
  64. package/dist/material.css +1 -1
  65. package/dist/pdf-reader.js +1 -1
  66. package/dist/print.js +5 -4
  67. package/dist/{public-vxiijIJF.js → public-D-J3nZFm.js} +9 -9
  68. package/dist/{rich-code-block-BwvCXPqq.js → rich-code-block-Ig0ERAa2.js} +5 -5
  69. package/dist/{sortable-provider-D2pAFWQB.js → sortable-provider-DfPkSN90.js} +2 -2
  70. package/dist/{spinner-BpVwI1ps.js → spinner-KQb3YuR_.js} +1 -1
  71. package/dist/{stored-language-Beyj2ult.js → stored-language-Cb9FMEwk.js} +8 -2
  72. package/dist/theme-picker.js +2 -2
  73. package/dist/{theme-toggle-BTYRPkP4.js → theme-toggle-BY-SpsFV.js} +1 -1
  74. package/dist/{toolbar-items-CIMo4F9q.js → toolbar-items-30w9rG5h.js} +4 -4
  75. package/dist/translate-material-BPl8TQLg.js +20 -0
  76. package/dist/{translator-CBgIb3zP.js → translator-BnQXtpSZ.js} +1 -1
  77. package/dist/{use-chat-composer-D8UAsX0f.js → use-chat-composer-BSKJRYMB.js} +1678 -1656
  78. package/dist/{use-heading-spy-C5LXtA8Z.js → use-heading-spy-BgXA8uz6.js} +1 -1
  79. package/dist/use-material-translation-ByM3gD9R.js +14 -0
  80. package/docs/components/data-display.md +3 -3
  81. package/docs/components/data-table-filter-and-lists.md +38 -5
  82. package/docs/components/primitives.md +1 -1
  83. package/docs/guides/backgrounds.md +3 -1
  84. package/docs/guides/cards-and-tiles.md +3 -0
  85. package/docs/guides/helpers.md +1 -1
  86. package/docs/guides/i18n.md +30 -8
  87. package/docs/guides/two-factor.md +2 -1
  88. package/docs/previews/guides-i18n-i18nprovider.webp +0 -0
  89. package/docs/previews/guides-i18n-translated-components.webp +0 -0
  90. package/docs/troubleshooting.md +3 -2
  91. package/lib/components/ui/layout/app-shell/activity-backdrop-shapes.css +14 -9
  92. package/lib/components/ui/layout/auth-card/auth-card-backdrop.css +2 -2
  93. package/package.json +1 -1
  94. package/dist/translate-material-DEUlaL_1.js +0 -12
  95. package/dist/use-material-translation-DWWeeg-B.js +0 -14
@@ -1,4 +1,4 @@
1
- import { r as e } from "./i18n-provider-DPM_ALQ4.js";
1
+ import { r as e } from "./i18n-provider-BFNrM0Qu.js";
2
2
  import { _ as t, g as n, h as r, n as i, v as a, y as o } from "./number.utils-BG_eEt5g.js";
3
3
  import { useCallback as s, useEffect as c, useMemo as l, useRef as u, useState as d } from "react";
4
4
  import { busySettler as f, busySettler as p, createSubmitGuard as m, createSubmitGuard as h } from "@nxgt/material-core/submit-guard";
@@ -0,0 +1,14 @@
1
+ import { r as e } from "./i18n-provider-BFNrM0Qu.js";
2
+ import { t } from "./translate-material-BPl8TQLg.js";
3
+ import { useCallback as n } from "react";
4
+ //#region lib/i18n/use-material-translation.ts
5
+ function r() {
6
+ let r = e(), i = r?.language, a = r?.resources;
7
+ return {
8
+ t: n((e, n, r) => t(i, e, n, r, a), [i, a]),
9
+ language: i,
10
+ hasProvider: !!r
11
+ };
12
+ }
13
+ //#endregion
14
+ export { r as t };
@@ -642,7 +642,7 @@ import { Description } from '@nxgt/material/components';
642
642
  </div>
643
643
  ```
644
644
 
645
- `label` and `value` are its main props; the rest go to the `div`. A `value` of `null`, `undefined`, `false` or `''` renders nothing (`0` is shown), so optional fields need no guard. Inside a `variant="panels"` list a `Description` must sit in a `DescriptionList.Group`; otherwise it renders its stand-alone markup. The label is a small
645
+ `label` and `value` are its main props; the rest go to the `div`. A `value` of `null`, `undefined`, `false` or `''` with no `lines` and no `children` renders nothing (`0` is shown), so optional fields need no guard. `children` alone are the value (`<Description label="Note">text</Description>`); after a `value` they follow it. Inside a `variant="panels"` list a `Description` must sit in a `DescriptionList.Group`; otherwise it renders its stand-alone markup. The label is a small
646
646
  muted caption above the value (not a title). `Description` takes one cell of
647
647
  the grid it is in; pass `className="col-start-full"` for a full-width row. It takes `lines` anywhere; inside a [`DescriptionList`](#descriptionlist) also `span` and `labelPosition`.
648
648
 
@@ -686,7 +686,7 @@ row) or a number of columns (used once that many fit; at most `maxColumns`, and
686
686
  field uses dense packing: the fields after it fill the cells before it, so they
687
687
  may be drawn above it while the DOM and reading order stay the source order.
688
688
  Put the full-width field where that reads fine, or last. A multi-line value
689
- (an address) takes `lines={[…]}` or `children`, never a string to split. Entries of `lines` that are `null`, `false` or `""` are skipped, and a `Description` whose `lines` are all empty and that has no `value` renders nothing.
689
+ (an address) takes `lines={[…]}` or `children`, never a string to split. Entries of `lines` that are `null`, `false` or `""` are skipped, and a `Description` whose `lines` are all empty and that has no `value` or `children` renders nothing.
690
690
 
691
691
  ```tsx
692
692
  <DescriptionList variant="panels">
@@ -1087,7 +1087,7 @@ yours, the component names no domain.
1087
1087
 
1088
1088
  | Prop | Type | Default | Effect |
1089
1089
  | --- | --- | --- | --- |
1090
- | `entries` | `ChangeHistoryEntry[]` | — | `id`, `kind`, `at` (`Date`, string or number), `author` (`name`, `src`), `changes` (`ChangeHistoryChange[]`: `field`, `before`, `after`, `redacted`) |
1090
+ | `entries` | `ChangeHistoryEntry[]` | — | `id`, `kind`, `at` (`Date`, string or number), `author` (`name`, `src`), `changes` (optional, `ChangeHistoryChange[]`: `field`, `before`, `after`, `redacted`; left out or `[]`, the entry shows its sentence, author and time with no change list) |
1091
1091
  | `kinds` | `Record<string, ChangeHistoryKindOverride>` | built-ins | `label`, `verb`, `icon` (`null` removes it), `tone` per kind; `creation` (default true for `created`) makes an entry list values only |
1092
1092
  | `variant` | `'rail' \| 'cards'` | `'rail'` | the look |
1093
1093
  | `groupBy` | `'day' \| 'none'` | `'day'` | a heading per day (sticky on the rail), or one list in the order given |
@@ -244,8 +244,10 @@ with a `select` column and `actions`, the toolbar keeps its band while
244
244
  nothing is selected, so the first selection does not move the rows (on a
245
245
  wide screen; on a phone the extra lines still push them down). Below 768px
246
246
  the declarative `bulkActions` fold past the third into a "More" menu in the
247
- toolbar too, so a list that stays a table on a phone (`layout="table"`) shows
248
- three actions and "More", as the cards and tiles do (#1797).
247
+ toolbar (a `ServerTable` without `filter`, or with the facets panel) and in a
248
+ phone's second row (#1719), as the cards and tiles do (#1797). The
249
+ [selection band](#the-selection-band) keeps one action and puts the rest in
250
+ "More".
249
251
 
250
252
  ```tsx
251
253
  <DataTable
@@ -293,6 +295,33 @@ press elsewhere is never pulled back. The footer's selected count is a polite
293
295
  status, so the first selection is announced ("1 row selected") when its bar
294
296
  shows up.
295
297
 
298
+ ### The selection band
299
+
300
+ With `bulkActions` and a `filter` (not `variant: 'facets'`), the first
301
+ selected row turns the band that holds the filter bar into a selection bar, in
302
+ place and on the same row: "N selected", the bulk actions, and a tonal
303
+ "Cancel" that clears the selection (#1718). The search and the page's
304
+ `actions` stay mounted, hidden (`invisible`, `inert`) and keep their size, so
305
+ the table does not move; clearing the selection brings them back. The bar's
306
+ height is the row's (40px, 44px on a coarse pointer). From 768px every
307
+ declarative action keeps its button; below it the bar is one row: the first
308
+ action keeps its button, the others go into "More" (an icon, still named),
309
+ and "Cancel" is an icon (its name and tooltip stay). Bulk actions written as a
310
+ function are rendered as they are, in the same place.
311
+
312
+ After "Cancel" the focus goes back to the control that started the selection
313
+ (the row's or the header's checkbox) when it is still on the page, else to the
314
+ list; a selection cleared another way (a bulk action's `selection.clear()`, a
315
+ new query) keeps its own focus rule. While rows are selected the search is
316
+ `inert`, so `filterRef.focus()` does nothing: cancel the selection first. The count is told once, politely, by the
317
+ footer's status ("N rows selected"); the bar's own count is plain text. The
318
+ cards' and tiles' list bar leaves its count and "Clear selection" to the bar.
319
+ A phone's second row of a list in cards or tiles with `actions` (#1719) is the
320
+ selection bar there, as before. Without `filter` (or with the facets panel) the
321
+ band has no filter bar to replace, and the bulk actions stay in the table's
322
+ toolbar. Text keys: `material.server-table.bulk-selected`, `bulk-cancel`,
323
+ `bulk-bar` (English and French).
324
+
296
325
  ### Focus after a bulk action
297
326
 
298
327
  When a bulk action clears the selection, its buttons unmount and the focus
@@ -410,7 +439,9 @@ grow the toolbar. Without the `select` column, or without `actions`, no band
410
439
  is kept above the table. `reserveActions={false}` keeps none either: the bar
411
440
  arrives on the first selection with a short grow (none under reduced motion),
412
441
  and the rows move down by its height. `ServerTable` passes `false`, so its
413
- bulk bar leaves no empty row under the band while nothing is selected.
442
+ bulk bar leaves no empty row under the band while nothing is selected. With
443
+ `filter` it has no toolbar row at all: the band's selection bar holds the bulk
444
+ actions ([the selection band](#the-selection-band)).
414
445
 
415
446
  ```tsx
416
447
  <DataTable
@@ -843,7 +874,8 @@ export default function Students() {
843
874
  onRetry={() => fetcher.reload()}
844
875
  />
845
876
  ```
846
- - **Selection.** With `bulkActions(ids, selection)`, rows are selectable;
877
+ - **Selection.** With `bulkActions(ids, selection)`, rows are selectable
878
+ (see [the selection band](#the-selection-band) for where the bulk actions show);
847
879
  the selection is kept across pages and drops on a new query.
848
880
  `selection.clear()` empties it and moves the focus to the table
849
881
  (`tabindex="-1"`, by script only; the list of cards or tiles in those layouts); `selection.deselect(ids)` drops rows
@@ -1036,7 +1068,8 @@ rows (the bulk bar is not drawn under it). With the declarative list form of
1036
1068
  (2)", named "Publish 2 rows"), hidden at 0 rows; the buttons wrap onto a second
1037
1069
  line rather than scroll, and past the third action the rest go into a "More"
1038
1070
  menu (`material.server-table.bulk-more`), each item keeping its count (the same
1039
- fold applies below 768px to every layout, a phone table included). From
1071
+ fold applies below 768px to every layout in the toolbar and in this row; the
1072
+ [selection band](#the-selection-band) of a list with `filter` keeps one action). From
1040
1073
  768px the buttons read "Label (n)" as before. When the focused button
1041
1074
  disappears the focus goes to the next one, else to "More", else to "Select all"; an action past `max` shows its notice there (an inline text, or a disabled More item). The function
1042
1075
  form (`bulkActions={(ids) => node}`) is drawn whole in the row, so keep it to
@@ -735,7 +735,7 @@ reached with the arrow keys. The list scrolls sideways when the tabs do not
735
735
  fit (its scrollbar hidden), which suits a phone or a narrow popover. While it
736
736
  overflows, each side with hidden tabs fades and gets a small scroll button
737
737
  ("Scroll tabs left" / "Scroll tabs right", from `material.tabs.*`; out of the
738
- tab order, 44px on a touch screen); the selected and the focused tab are
738
+ tab order; on a touch screen 44px wide and as tall as the list, so it never covers content); the selected and the focused tab are
739
739
  scrolled into view, instantly under reduced motion. A list that fits has
740
740
  neither, and neither is in the server markup. `segmented` does the same.
741
741
 
@@ -545,7 +545,9 @@ good.
545
545
  - The server renders every glyph. The drop happens after the first measure, on the client, in one frame (boxes read
546
546
  before any write), so the markup never differs between server and client.
547
547
  - A dropped glyph fades out in 150 ms (none under `prefers-reduced-motion`) and fades back when the content moves
548
- away. It runs again on resize and when the content changes.
548
+ away. It runs again on resize and when the content changes. A glyph the first pass drops is hidden at once: the fade
549
+ starts a frame later (`data-settled` on the scene), so no glyph is seen over a paragraph for the length of a fade on
550
+ a reload.
549
551
  - The open areas keep their glyphs; the space behind and between cards is empty. `keepClear={false}` on an `AuthCard`
550
552
  lets the glyphs run under the card.
551
553
  - **`keepClear="gaps"`** (on `ActivityLayout` and `AuthCard`, opt-in; `true` stays the default) lets a glyph stay between
@@ -144,6 +144,9 @@ is not `focusable`). On a narrow list (under 30rem) the bar stays on one row and
144
144
  Clear shrinks to an icon button; its label stays its accessible name, and it has
145
145
  a tooltip. Do not add your own in `actions`: that one is the bulk bar's.
146
146
  Once a bulk action clears the selection and the focus is lost, the list takes it.
147
+ In a `ServerTable` with `filter` and `bulkActions`, the band's own selection bar
148
+ tells the count and has "Cancel" (#1718), so the list bar leaves its count and
149
+ "Clear selection" out ([the selection band](../components/data-table-filter-and-lists.md#the-selection-band)).
147
150
 
148
151
  Inside a `ServerTable` with `filter` and `actions`, below 768px, the bar has no
149
152
  row of its own: its "Select all" (with a short visible label, "Select all"),
@@ -265,7 +265,7 @@ flag. Storybook: `Guides/Hooks/useSubmitOnce`.
265
265
  | `formatMessage(message, language, values?, { onError }?)` | Formats one ICU message (`{name}`, plurals, selects) in any BCP 47 `language` with the translator's engine, for a message that is not in a bundle (a server-side catalogue). Cached per message; one that does not format is logged and returned unformatted, or passed to `onError` as a `FormatMessageError` (reason, key, source) without logging. |
266
266
  | `createTypedTranslation(translate)` | Turns a translator into a typed `useTranslation()` hook. |
267
267
  | `translate`, `useMaterialTranslation()` | Translator / hook bound to the package's own `material.*` keys. `useMaterialTranslation().t(key, fallback)` returns `fallback` without a provider. |
268
- | `translateMaterial(language, key, fallback, values?)` | The same as `useMaterialTranslation().t`, with the language passed as a value: no provider, no hook. For a PDF `footer` function or a server. `'fr-CA'` reads `fr`; an unknown language formats `fallback`. |
268
+ | `translateMaterial(language, key, fallback, values?, resources?)` | The same as `useMaterialTranslation().t`, with the language passed as a value: no provider, no hook. `resources` is your merged bundle (stable object), read before the base one. For a PDF `footer` function or a server. `'fr-CA'` reads `fr`; an unknown language formats `fallback`. |
269
269
  | `getLanguage()` | Language read from `localStorage`, else `FALLBACK_LANGUAGE`. |
270
270
  | `LANGUAGE_KEY`, `FALLBACK_LANGUAGE`, `SUPPORTED_LANGUAGES` | Storage key (`'language'`), fallback (`'en'`) and supported languages (`en`, `fr`). |
271
271
 
@@ -63,6 +63,7 @@ function translateMaterial(
63
63
  key: MaterialLocaleKey,
64
64
  fallback: string,
65
65
  values?: TranslationContext,
66
+ resources?: ResourceBundle, // your merged bundle, a stable object (module scope)
66
67
  ): string;
67
68
  ```
68
69
 
@@ -189,6 +190,7 @@ if (failure) {
189
190
  | `initialLanguage` | `Language` | — | Used as-is for the first render when supported, and `localStorage` is not read. Set it in SSR. See [below](#server-rendering) |
190
191
  | `storageKey` | `string` | `'language'` | `localStorage` key the choice is read from and written to |
191
192
  | `supportedLanguages` | `Language[]` | `['en', 'fr']` | What `changeLanguage` accepts and `LanguageSwitcher` lists |
193
+ | `resources` | `ResourceBundle` | — | Your `mergeResources(...)` result: the components read their `material.*` words from it before the base bundle. Pass a stable object (module scope) |
192
194
  | `onLanguageChange` | `(language) => void` | — | Called after a successful change: save it to a cookie, a profile, analytics |
193
195
 
194
196
  `changeLanguage` with an unsupported value logs
@@ -208,7 +210,8 @@ const context = useOptionalI18nContext(); // null outside the provider
208
210
  third language is not in the type today, so adding one to
209
211
  `supportedLanguages` takes a cast. The runtime accepts it: your translator
210
212
  uses your strings for it, and the components fall back to their English copy,
211
- formatted.
213
+ formatted. A third language you define under `material.*` and give through
214
+ `resources` now reaches the components.
212
215
 
213
216
  ```tsx
214
217
  const LANGUAGES = ['en', 'fr', 'de'] as Language[];
@@ -498,8 +501,8 @@ material.emoji.groups.flags; // "Flags" / "Drapeaux"
498
501
 
499
502
  A group your `EmojiItem`s name that is not in this list (`hand_signs`) reads
500
503
  as its words in English (`Hand signs`). As for every `material.*` key above,
501
- the components read their own bundle: your own translator sees a key you add,
502
- the tab does not.
504
+ your own translator sees a key you add; the components see it too once you hand
505
+ them the merged resources (see "Overriding a component's words" below).
503
506
 
504
507
  ```tsx
505
508
  // Under <I18nProvider defaultLanguage="fr">
@@ -509,11 +512,30 @@ the tab does not.
509
512
  <Spinner variant="4" /> // role="img" aria-label="Chargement..."
510
513
  ```
511
514
 
512
- That override is visible only through **your** translator. The components
513
- translate through the package's own bundle, so defining
514
- `material.command.title` in your resources changes what
515
- `t('material.command.title')` returns in your code, but not the title
516
- `CommandDialog` renders.
515
+ ### Overriding a component's words
516
+
517
+ Give the provider the merged resources and every component translates through
518
+ them, so an override under `material.*` changes what it renders:
519
+
520
+ ```tsx
521
+ import { mergeResources, resources as materialResources } from '@nxgt/material/i18n';
522
+
523
+ const resources = mergeResources(materialResources, {
524
+ en: { material: { 'recovery-codes-status': { title: 'Backup codes' } } },
525
+ });
526
+
527
+ <I18nProvider defaultLanguage="en" resources={resources}>
528
+ <RecoveryCodesStatus remaining={3} onRegenerate={regenerate} /> {/* title: "Backup codes" */}
529
+ </I18nProvider>
530
+ ```
531
+
532
+ Without `resources`, the components read the package's own bundle: an override
533
+ is visible only through **your** translator, and defining `material.command.title`
534
+ does not change the title `CommandDialog` renders. Pass a stable object
535
+ (module scope), not one built in a render. A component's `labels` prop still
536
+ wins over both. Outside a component, `translateMaterial` takes the merged
537
+ resources as a fifth argument and `zodLocaleError` takes `translate`; the
538
+ toast presets and the toast close label still read the package's bundle.
517
539
 
518
540
  Each time `mergeResources` runs outside production, overlapping leaves are
519
541
  reported, one line per language:
@@ -62,7 +62,8 @@ in `@nxgt/material-core/two-factor`.
62
62
  What stays in the app: every request, the mapping of a server error to the
63
63
  props above, where the challenge is kept, the replay of the action a step-up
64
64
  unblocked, the leave guard around the new recovery codes, and all wording
65
- (`labels`, or your translations under `material.*`).
65
+ (`labels`, or your translations under `material.*`, given to
66
+ `I18nProvider` as `resources`, see [i18n](i18n.md#overriding-a-components-words)).
66
67
 
67
68
  ## On a phone and for assistive technology
68
69
 
@@ -3902,8 +3902,9 @@ followed by the list of keys, e.g. `"en": material.command.title. App resources
3902
3902
  take precedence over the base bundle at these keys.`
3903
3903
  **Why:** your resources define leaves under the `material` namespace, which
3904
3904
  this package reserves for its own strings. The override reaches your app's
3905
- own translator only: the package's components translate from their own
3906
- bundle, so their text does **not** change.
3905
+ own translator only, unless you also give the merged object to
3906
+ `<I18nProvider resources={resources}>`: without it the package's components
3907
+ translate from their own bundle, so their text does **not** change.
3907
3908
  **Fix:**
3908
3909
 
3909
3910
  ```ts
@@ -18,15 +18,20 @@
18
18
  visibility: hidden;
19
19
  }
20
20
 
21
- /* A shape over the page's text, controls or surfaces (cards, tables, lists) fades out and comes back once
22
- * clear (watch-content.ts): it is hidden, never moved. A compound body (the
23
- * moon, the planet, the eclipse: `.pt.mg`) is hidden whole, with its halo
24
- * (`.pt.mh`). The scene stays invisible until the first check, so nothing
25
- * flashes over the content. */
26
- [data-keep-inside] .mo > *,
27
- [data-keep-inside] .pt,
28
- [data-slot="activity-layout-backdrop"] [data-background] .mo > *,
29
- [data-slot="activity-layout-backdrop"] [data-background] .pt {
21
+ /* A shape over the page's text, controls or surfaces (cards, tables, lists)
22
+ * fades out and comes back once clear (watch-content.ts): it is hidden,
23
+ * never moved. A compound body (the moon, the planet, the eclipse: `.pt.mg`)
24
+ * is hidden whole, with its halo (`.pt.mh`). The scene stays invisible until
25
+ * the first check, so nothing flashes over the content. The fade waits for
26
+ * `data-settled`, set a frame after the first pass: a shape that pass drops
27
+ * is hidden at once, never seen fading out over the text on a reload. */
28
+ [data-keep-inside][data-settled] .mo > *,
29
+ [data-keep-inside][data-settled] .pt,
30
+ [data-slot="activity-layout-backdrop"]
31
+ [data-background][data-settled]
32
+ .mo
33
+ > *,
34
+ [data-slot="activity-layout-backdrop"] [data-background][data-settled] .pt {
30
35
  transition: opacity 150ms ease;
31
36
  }
32
37
  /* Important: a preset sets its own opacity on a body (`.md`, the dark
@@ -13,8 +13,8 @@
13
13
  visibility: hidden;
14
14
  }
15
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 {
16
+ [data-slot="auth-card-backdrop"] [data-background][data-settled] .mo > *,
17
+ [data-slot="auth-card-backdrop"] [data-background][data-settled] .pt {
18
18
  transition: opacity 150ms ease;
19
19
  }
20
20
  [data-slot="auth-card-backdrop"] [data-background] .mo > [data-hidden],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.50.0",
3
+ "version": "3.52.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"
@@ -1,12 +0,0 @@
1
- import "./stored-language-Beyj2ult.js";
2
- import { a as e, r as t } from "./translator-CBgIb3zP.js";
3
- //#region lib/i18n/translate-material.ts
4
- function n(n, r, i, a) {
5
- if (n) for (let e of /* @__PURE__ */ new Set([n, n.split("-")[0]])) {
6
- let n = t(r, a, () => e);
7
- if (n !== r) return n;
8
- }
9
- return e(i, n || "en", a);
10
- }
11
- //#endregion
12
- export { n as t };
@@ -1,14 +0,0 @@
1
- import { r as e } from "./i18n-provider-DPM_ALQ4.js";
2
- import { t } from "./translate-material-DEUlaL_1.js";
3
- import { useCallback as n } from "react";
4
- //#region lib/i18n/use-material-translation.ts
5
- function r() {
6
- let r = e(), i = r?.language;
7
- return {
8
- t: n((e, n, r) => t(i, e, n, r), [i]),
9
- language: i,
10
- hasProvider: !!r
11
- };
12
- }
13
- //#endregion
14
- export { r as t };