@nxgt/material 3.15.0 → 3.17.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 (67) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +1 -1
  3. package/dist/{async-slice-ChtlTP8W.js → async-slice-BA7wI9qp.js} +2 -2
  4. package/dist/{button-BrgyWw7T.js → button-DOYHfcMJ.js} +1 -1
  5. package/dist/charts.js +3 -3
  6. package/dist/{chip-BZu-bvAJ.js → chip-C8MB2xzb.js} +1 -1
  7. package/dist/{code-editor-DjY7_8TH.js → code-editor-BqeS_XMJ.js} +4 -4
  8. package/dist/code-editor.js +4 -4
  9. package/dist/{code-language-items-D1lpNQ6J.js → code-language-items-DOr9J9yu.js} +2 -2
  10. package/dist/{components-j0Iv8MZi.js → components-D5-uZqnU.js} +9235 -9077
  11. package/dist/components.js +15 -15
  12. package/dist/{dialog-YHZJjDrI.js → dialog-CFIn1NPR.js} +1 -1
  13. package/dist/dnd.js +1 -1
  14. package/dist/{dropdown-menu-BEyP-A0J.js → dropdown-menu-CL6mNhgT.js} +1 -1
  15. package/dist/editor.js +7 -7
  16. package/dist/{empty-state-ZtqqpX0S.js → empty-state-BNljKZLV.js} +1 -1
  17. package/dist/hooks.js +2 -2
  18. package/dist/{i18n-provider-GV4Ukoe2.js → i18n-provider-WReTVxE3.js} +1 -1
  19. package/dist/i18n.js +5 -5
  20. package/dist/{icon-badge-C0TGvF9o.js → icon-badge-lfAUxNe8.js} +1 -1
  21. package/dist/lib/components/ui/collections/filter/editors/text-editor.d.ts +6 -1
  22. package/dist/lib/components/ui/collections/filter/index.d.ts +1 -1
  23. package/dist/lib/components/ui/collections/filter/query/types.d.ts +20 -1
  24. package/dist/lib/components/ui/collections/filter/query/use-filter-query-value.d.ts +3 -0
  25. package/dist/lib/components/ui/collections/filter/query/use-filter-query.d.ts +6 -2
  26. package/dist/lib/components/ui/collections/filter/sections/filter-search.d.ts +7 -1
  27. package/dist/lib/components/ui/collections/server-table/types.d.ts +12 -1
  28. package/dist/lib/components/ui/collections/server-table/use-table-answer.d.ts +1 -1
  29. package/dist/lib/components/ui/fields/search-field/search-field.d.ts +6 -1
  30. package/dist/lib/components/ui/layout/app-shell/activity-content-aside.d.ts +22 -0
  31. package/dist/lib/components/ui/layout/app-shell/activity-content-aside.types.d.ts +36 -0
  32. package/dist/lib/components/ui/layout/app-shell/activity-content.d.ts +15 -2
  33. package/dist/lib/components/ui/layout/app-shell/index.d.ts +1 -0
  34. package/dist/lib/i18n/resources/en/en.d.ts +1 -0
  35. package/dist/lib/i18n/resources/en/material.json.d.ts +1 -0
  36. package/dist/lib/i18n/resources/fr/fr.d.ts +1 -0
  37. package/dist/lib/i18n/resources/fr/material.json.d.ts +1 -0
  38. package/dist/lib/i18n/resources/resources.d.ts +2 -0
  39. package/dist/lib/i18n/translator.d.ts +1 -1
  40. package/dist/lib.js +1 -1
  41. package/dist/main.js +21 -21
  42. package/dist/map.js +4 -4
  43. package/dist/material.css +1 -1
  44. package/dist/pdf-reader.js +1 -1
  45. package/dist/print.js +2 -2
  46. package/dist/{public-Bj3rGSfS.js → public-B4lpmahC.js} +6 -6
  47. package/dist/{rich-code-block-RN-EpeTA.js → rich-code-block-CvqJmvuT.js} +4 -4
  48. package/dist/{sortable-provider-Iej7IS4n.js → sortable-provider-DE692phf.js} +1 -1
  49. package/dist/{spinner-BwWDXIbg.js → spinner-CGgOgUCe.js} +1 -1
  50. package/dist/{stored-language-BAAP7qS3.js → stored-language-DiCe2ZcR.js} +2 -0
  51. package/dist/theme-picker.js +2 -2
  52. package/dist/{theme-toggle-8zHeXSD1.js → theme-toggle-O6z6PokP.js} +1 -1
  53. package/dist/{toolbar-items-CVQBYp4K.js → toolbar-items-DCZxamGy.js} +2 -2
  54. package/dist/{translate-material-C0aOnHpZ.js → translate-material-DZ_i8xJx.js} +2 -2
  55. package/dist/{translator-BU07gNva.js → translator-Ch1dEqFf.js} +1 -1
  56. package/dist/{use-chat-composer-CoXmJCkr.js → use-chat-composer-ByWwRuYg.js} +52 -52
  57. package/dist/{use-heading-spy-DETdqnB6.js → use-heading-spy-S6PT8wPG.js} +1 -1
  58. package/dist/{use-material-translation-DGeVp-qP.js → use-material-translation-C4ysFJtw.js} +2 -2
  59. package/docs/components/data-table-filter-and-lists.md +35 -3
  60. package/docs/components/form-fields.md +1 -0
  61. package/docs/components/navigation-and-layout.md +3 -0
  62. package/docs/guides/app-shell.md +52 -0
  63. package/docs/guides/i18n.md +1 -1
  64. package/docs/guides/server-lists-url.md +12 -0
  65. package/docs/guides/theming.md +1 -0
  66. package/docs/troubleshooting.md +24 -0
  67. package/package.json +2 -2
@@ -1,3 +1,3 @@
1
- import { t as e } from "./public-Bj3rGSfS.js";
1
+ import { t as e } from "./public-B4lpmahC.js";
2
2
  import { configurePdfReader as t } from "@nxgt/material-core/pdf-reader";
3
3
  export { e as PdfReader, t as configurePdfReader };
package/dist/print.js CHANGED
@@ -1,5 +1,5 @@
1
- import { r as e } from "./i18n-provider-GV4Ukoe2.js";
2
- import { t } from "./translate-material-C0aOnHpZ.js";
1
+ import { r as e } from "./i18n-provider-WReTVxE3.js";
2
+ import { t } from "./translate-material-DZ_i8xJx.js";
3
3
  import { Children as n, createContext as r, isValidElement as i, useCallback as a, useContext as o, useEffect as s, useMemo as c, useState as l } from "react";
4
4
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
5
5
  import { resolvePdfFileName as f } from "@nxgt/material-core/pdf-file-name";
@@ -6,18 +6,18 @@ import { c as i, i as a, l as o, n as s, o as c, s as l } from "./dist-lmHmz_bu.
6
6
  import { a as u, o as d } from "./tooltip-CkttDIab.js";
7
7
  import { i as f } from "./dist-C4wtXCjf.js";
8
8
  import { r as p, t as m } from "./in-dialog-Vwkyp-M5.js";
9
- import { C as h, D as g, E as _, O as v, S as y, T as b, _ as x, f as S, g as ee, k as te, r as ne, t as C, u as re, w } from "./dialog-YHZJjDrI.js";
10
- import { c as T, d as ie, f as E, i as ae, l as oe, n as se, o as D, t as ce, u as O } from "./dropdown-menu-BEyP-A0J.js";
11
- import { S as le, a as k, d as A, g as ue, h as de, i as fe, m as pe, n as j, r as me, t as M, u as he, w as ge } from "./toolbar-items-CVQBYp4K.js";
12
- import { t as N } from "./use-material-translation-DGeVp-qP.js";
13
- import { t as _e } from "./button-BrgyWw7T.js";
9
+ import { C as h, D as g, E as _, O as v, S as y, T as b, _ as x, f as S, g as ee, k as te, r as ne, t as C, u as re, w } from "./dialog-CFIn1NPR.js";
10
+ import { c as T, d as ie, f as E, i as ae, l as oe, n as se, o as D, t as ce, u as O } from "./dropdown-menu-CL6mNhgT.js";
11
+ import { S as le, a as k, d as A, g as ue, h as de, i as fe, m as pe, n as j, r as me, t as M, u as he, w as ge } from "./toolbar-items-DCZxamGy.js";
12
+ import { t as N } from "./use-material-translation-C4ysFJtw.js";
13
+ import { t as _e } from "./button-DOYHfcMJ.js";
14
14
  import { n as ve, t as ye } from "./icon-button-ifTpXt0A.js";
15
15
  import { t as be } from "./useEvent-2fKq-6w8.js";
16
16
  import { n as xe, t as Se } from "./toggle-group-BMJNcFAC.js";
17
17
  import { o as Ce } from "./escape-owner-C4W_sOAU.js";
18
18
  import { n as we } from "./use-slice-reducer-BGkeGtML.js";
19
19
  import { r as Te } from "./use-csp-nonce-ZKs9k-ov.js";
20
- import { n as Ee, t as De } from "./empty-state-ZtqqpX0S.js";
20
+ import { n as Ee, t as De } from "./empty-state-BNljKZLV.js";
21
21
  import { t as Oe } from "./client-only.utils-3nHNzCki.js";
22
22
  import { t as ke } from "./use-scroll-away-PQRFZkT2.js";
23
23
  import { ArrowLeft as Ae, BookOpenText as je, ChevronDown as Me, ChevronLeft as Ne, ChevronRight as Pe, ChevronUp as Fe, Download as Ie, Eraser as Le, FileText as Re, FileWarning as ze, FileX2 as Be, Highlighter as Ve, KeyRound as He, LayoutGrid as Ue, List as We, Loader2 as Ge, Maximize as Ke, MessageSquareText as qe, Minimize as Je, MoreVertical as Ye, MousePointer2 as Xe, MoveHorizontal as Ze, PanelLeft as Qe, Pen as $e, PencilLine as et, Printer as tt, RotateCw as nt, Search as rt, StickyNote as it, Type as at, Underline as ot, Undo2 as st, Volume2 as ct, X as lt, XIcon as ut, ZoomIn as dt, ZoomOut as ft } from "lucide-react";
@@ -1,7 +1,7 @@
1
1
  import { t as e } from "./tooltip-CkttDIab.js";
2
- import { c as t, n, t as r } from "./dropdown-menu-BEyP-A0J.js";
3
- import { t as i } from "./use-material-translation-DGeVp-qP.js";
4
- import { a, i as o, n as s, o as c, t as l } from "./code-language-items-D1lpNQ6J.js";
2
+ import { c as t, n, t as r } from "./dropdown-menu-CL6mNhgT.js";
3
+ import { t as i } from "./use-material-translation-C4ysFJtw.js";
4
+ import { a, i as o, n as s, o as c, t as l } from "./code-language-items-DOr9J9yu.js";
5
5
  import { i as u, n as d, r as f, s as p } from "./dist-C3GR7kJd.js";
6
6
  import { t as m } from "./code-block-spec-CGLKRhwD.js";
7
7
  import { Check as h, ChevronDown as g, Copy as _, Maximize2 as v, WrapText as y } from "lucide-react";
@@ -143,7 +143,7 @@ function M({ node: e, editor: t, updateAttributes: n, editable: r, wrap: a, onWr
143
143
  }
144
144
  //#endregion
145
145
  //#region lib/components/ui/widgets/editor/extensions/code/code-block-open.tsx
146
- var N = x(() => import("./code-editor-DjY7_8TH.js").then((e) => e.n).then((e) => ({ default: e.CodeEditor })));
146
+ var N = x(() => import("./code-editor-BqeS_XMJ.js").then((e) => e.n).then((e) => ({ default: e.CodeEditor })));
147
147
  function P() {
148
148
  let { t: e } = i();
149
149
  return /* @__PURE__ */ T("div", {
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-BLfntITJ.js";
2
2
  import { t } from "./dist-DVRQkaTK.js";
3
- import { t as n } from "./use-material-translation-DGeVp-qP.js";
3
+ import { t as n } from "./use-material-translation-C4ysFJtw.js";
4
4
  import { t as r } from "./icon-button-ifTpXt0A.js";
5
5
  import { t as i } from "./compose-refs-DZ0iIVF-.js";
6
6
  import { GripVertical as a } from "lucide-react";
@@ -1,6 +1,6 @@
1
1
  import { t as e } from "./utils-BLfntITJ.js";
2
2
  import { o as t } from "./tooltip-CkttDIab.js";
3
- import { t as n } from "./use-material-translation-DGeVp-qP.js";
3
+ import { t as n } from "./use-material-translation-C4ysFJtw.js";
4
4
  import { jsx as r } from "react/jsx-runtime";
5
5
  //#region lib/components/ui/feedback/spinner/spinner.tsx
6
6
  var i = t("transition-all duration-500", {
@@ -1275,6 +1275,7 @@ var t = {
1275
1275
  bar: {
1276
1276
  label: "Filters",
1277
1277
  search: "Search",
1278
+ "search-min": "Type at least {min, plural, one {# character} other {# characters}} to search",
1278
1279
  active: "Active filters",
1279
1280
  locked: "Locked",
1280
1281
  "locked-reason": "Locked: {reason}",
@@ -3874,6 +3875,7 @@ var t = {
3874
3875
  bar: {
3875
3876
  label: "Filtres",
3876
3877
  search: "Rechercher",
3878
+ "search-min": "Saisissez au moins {min, plural, one {# caractère} other {# caractères}} pour rechercher",
3877
3879
  active: "Filtres actifs",
3878
3880
  locked: "Verrouillé",
3879
3881
  "locked-reason": "Verrouillé : {reason}",
@@ -1,10 +1,10 @@
1
1
  import { t as e } from "./utils-BLfntITJ.js";
2
2
  import { a as t, i as n, n as r, o as i, r as a, t as o } from "./bubble-input-B7BVd9fX.js";
3
- import { t as s } from "./use-material-translation-DGeVp-qP.js";
3
+ import { t as s } from "./use-material-translation-C4ysFJtw.js";
4
4
  import { n as c, r as l } from "./icon-sprites-FxHyqyhg.js";
5
5
  import { t as u } from "./use-theme-DMcyJ52N.js";
6
6
  import { a as d, r as f } from "./theme-context-Cofk6vgs.js";
7
- import { t as p } from "./theme-toggle-8zHeXSD1.js";
7
+ import { t as p } from "./theme-toggle-O6z6PokP.js";
8
8
  import { n as m, t as h } from "./nxgt-theme-ZS945iMP.js";
9
9
  import { Check as g } from "lucide-react";
10
10
  import { useContext as _ } from "react";
@@ -1,4 +1,4 @@
1
- import { t as e } from "./use-material-translation-DGeVp-qP.js";
1
+ import { t as e } from "./use-material-translation-C4ysFJtw.js";
2
2
  import { i as t } from "./theme-store-CSl51uNH.js";
3
3
  import { n, t as r } from "./use-theme-DMcyJ52N.js";
4
4
  import { r as i } from "./theme-context-Cofk6vgs.js";
@@ -4,9 +4,9 @@ import { a as i, c as a, i as o, l as s, r as c, s as l } from "./dist-lmHmz_bu.
4
4
  import { b as u, c as d, d as f, f as p, l as m, t as h, u as g, x as _ } from "./tooltip-CkttDIab.js";
5
5
  import { i as v, n as y, r as b, t as x } from "./dist-C4wtXCjf.js";
6
6
  import { a as S, c as C, l as w, o as T, r as ee, s as te, t as E } from "./in-dialog-Vwkyp-M5.js";
7
- import { A as ne, M as re, N as ie, b as ae, d as oe, f as se, i as ce, j as le, l as ue, n as de, o as fe, r as pe, t as me, u as he, y as ge } from "./dropdown-menu-BEyP-A0J.js";
7
+ import { A as ne, M as re, N as ie, b as ae, d as oe, f as se, i as ce, j as le, l as ue, n as de, o as fe, r as pe, t as me, u as he, y as ge } from "./dropdown-menu-CL6mNhgT.js";
8
8
  import { a as _e, n as ve, r as ye, t as be } from "./dist-B7RjY7SL.js";
9
- import { t as xe } from "./use-material-translation-DGeVp-qP.js";
9
+ import { t as xe } from "./use-material-translation-C4ysFJtw.js";
10
10
  import { t as Se } from "./warn-once-C_e47JM8.js";
11
11
  import { o as Ce } from "./escape-owner-C4W_sOAU.js";
12
12
  import { ChevronLeft as we, ChevronRightIcon as Te, MoreVertical as Ee } from "lucide-react";
@@ -1,5 +1,5 @@
1
- import "./stored-language-BAAP7qS3.js";
2
- import { a as e, r as t } from "./translator-BU07gNva.js";
1
+ import "./stored-language-DiCe2ZcR.js";
2
+ import { a as e, r as t } from "./translator-Ch1dEqFf.js";
3
3
  //#region lib/i18n/translate-material.ts
4
4
  function n(n, r, i, a) {
5
5
  if (n) for (let e of /* @__PURE__ */ new Set([n, n.split("-")[0]])) {
@@ -1,5 +1,5 @@
1
1
  import { t as e } from "./is-production-GLw59WU8.js";
2
- import { a as t, i as n, r, t as i } from "./stored-language-BAAP7qS3.js";
2
+ import { a as t, i as n, r, t as i } from "./stored-language-DiCe2ZcR.js";
3
3
  import { t as a } from "./get-CTzJAwfc.js";
4
4
  //#region ../../node_modules/@formatjs/fast-memoize/index.js
5
5
  function o(e, t) {
@@ -7,21 +7,21 @@ import { a as o, c as s, i as c, l, n as u, o as d, r as f, s as p, t as m } fro
7
7
  import { _ as h, a as g, g as _, h as v, m as y, o as b, p as x, t as S, v as C, y as w } from "./tooltip-CkttDIab.js";
8
8
  import { a as T, i as E, n as D, r as O, t as k } from "./dist-C4wtXCjf.js";
9
9
  import { i as A, n as ee, t as j } from "./in-dialog-Vwkyp-M5.js";
10
- import { A as M, C as N, D as te, E as ne, O as P, S as re, T as ie, _ as F, b as ae, f as oe, g as se, k as I, l as ce, m as le, n as ue, o as de, r as fe, s as pe, t as me, u as he, v as ge, w as _e, x as ve, y as ye } from "./dialog-YHZJjDrI.js";
10
+ import { A as M, C as N, D as te, E as ne, O as P, S as re, T as ie, _ as F, b as ae, f as oe, g as se, k as I, l as ce, m as le, n as ue, o as de, r as fe, s as pe, t as me, u as he, v as ge, w as _e, x as ve, y as ye } from "./dialog-CFIn1NPR.js";
11
11
  import { A as be, C as xe, D as Se, E as Ce, O as we, S as Te, T as Ee, _ as De, a as Oe, b as ke, d as Ae, f as je, g as Me, h as Ne, i as Pe, k as Fe, l as Ie, m as Le, n as Re, o as ze, p as Be, r as Ve, s as He, t as Ue, u as We, v as Ge, w as Ke, x as qe, y as Je } from "./floating-ui.dom-KkZSW8_E.js";
12
- import { D as Ye, E as Xe, N as Ze, O as Qe, c as $e, d as et, f as tt, i as nt, k as rt, m as it, n as at, o as ot, p as st, t as ct, u as lt } from "./dropdown-menu-BEyP-A0J.js";
12
+ import { D as Ye, E as Xe, N as Ze, O as Qe, c as $e, d as et, f as tt, i as nt, k as rt, m as it, n as at, o as ot, p as st, t as ct, u as lt } from "./dropdown-menu-CL6mNhgT.js";
13
13
  import { a as ut, i as dt, n as ft } from "./field-blur-context-Cft9s7Hg.js";
14
- import { C as pt, S as mt, a as ht, c as gt, d as _t, l as vt, n as yt, o as bt, s as xt, u as St } from "./toolbar-items-CVQBYp4K.js";
14
+ import { C as pt, S as mt, a as ht, c as gt, d as _t, l as vt, n as yt, o as bt, s as xt, u as St } from "./toolbar-items-DCZxamGy.js";
15
15
  import { a as Ct, i as wt, n as Tt, o as Et, t as Dt } from "./bubble-input-B7BVd9fX.js";
16
16
  import { i as Ot } from "./dist-B7RjY7SL.js";
17
- import "./stored-language-BAAP7qS3.js";
18
- import { a as kt } from "./translator-BU07gNva.js";
17
+ import "./stored-language-DiCe2ZcR.js";
18
+ import { a as kt } from "./translator-Ch1dEqFf.js";
19
19
  import { h as At } from "./get-CTzJAwfc.js";
20
20
  import { t as jt } from "./isEmpty-F_g3jLf8.js";
21
- import { t as L } from "./use-material-translation-DGeVp-qP.js";
22
- import { t as Mt } from "./spinner-BwWDXIbg.js";
21
+ import { t as L } from "./use-material-translation-C4ysFJtw.js";
22
+ import { t as Mt } from "./spinner-CGgOgUCe.js";
23
23
  import { a as Nt } from "./button-tones-BwuVvAmd.js";
24
- import { a as Pt, i as Ft, n as It, r as Lt, t as Rt } from "./button-BrgyWw7T.js";
24
+ import { a as Pt, i as Ft, n as It, r as Lt, t as Rt } from "./button-DOYHfcMJ.js";
25
25
  import { t as R } from "./icon-button-ifTpXt0A.js";
26
26
  import { n as zt, r as Bt } from "./icon-sprites-FxHyqyhg.js";
27
27
  import { t as Vt } from "./use-ssr-media-query-C6M5m8sf.js";
@@ -35,10 +35,10 @@ import { a as tn, i as nn, o as rn } from "./escape-owner-C4W_sOAU.js";
35
35
  import { n as an } from "./use-slice-reducer-BGkeGtML.js";
36
36
  import { t as on } from "./browser-only-DQ94lWF8.js";
37
37
  import { t as sn } from "./compose-refs-DZ0iIVF-.js";
38
- import { n as cn, r as ln, t as un } from "./chip-BZu-bvAJ.js";
39
- import { n as dn, t as fn } from "./icon-badge-C0TGvF9o.js";
38
+ import { n as cn, r as ln, t as un } from "./chip-C8MB2xzb.js";
39
+ import { n as dn, t as fn } from "./icon-badge-lfAUxNe8.js";
40
40
  import { r as pn } from "./use-csp-nonce-ZKs9k-ov.js";
41
- import { t as mn } from "./empty-state-ZtqqpX0S.js";
41
+ import { t as mn } from "./empty-state-BNljKZLV.js";
42
42
  import { t as hn } from "./skeleton-DSdtr2qc.js";
43
43
  import { H as gn, V as _n, X as vn, bt as yn, it as bn, lt as xn, n as Sn, t as Cn, xt as wn, yt as Tn } from "./dist-moutbfbd.js";
44
44
  import { t as En } from "./markdown-Dw_uH7j7.js";
@@ -10782,7 +10782,7 @@ var CS = (e = {}) => Dn({
10782
10782
  let [{ default: t }, { lowlight: n }, { richCodeBlock: r }] = await Promise.all([
10783
10783
  import("./dist-CRMFGjng.js"),
10784
10784
  import("./lowlight-OtcjU2Sa.js"),
10785
- import("./rich-code-block-RN-EpeTA.js")
10785
+ import("./rich-code-block-CvqJmvuT.js")
10786
10786
  ]);
10787
10787
  return [r(t, {
10788
10788
  lowlight: n,
@@ -12053,35 +12053,35 @@ function WC({ shortcut: e, loading: t, filled: n, disabled: r, onClear: i }) {
12053
12053
  }
12054
12054
  //#endregion
12055
12055
  //#region lib/components/ui/fields/search-field/search-field.tsx
12056
- function GC({ id: e, value: t, defaultValue: r = "", onChange: i, onValueChange: a, debounceMs: o = 0, loading: s = !1, placeholder: c, label: l, helperText: u, error: d, disabled: f, required: p, name: m, className: h, onKeyDown: g, shortcut: _, ...v }) {
12057
- let { t: y } = L(), b = eo(), x = eo(), [S, C] = W(String(r ?? "")), w = t !== void 0, T = w ? String(t ?? "") : S, E = Gt(a), D = a !== void 0, O = H(() => o ? Po((e) => E.current?.(e), o) : null, [o, E]);
12058
- V(() => () => O?.cancel(), [O]);
12059
- let k = (e, t = !1) => {
12060
- if (w || C(e), D) {
12061
- if (t || !O) {
12062
- O?.cancel(), E.current?.(e);
12056
+ function GC({ id: e, value: t, defaultValue: r = "", onChange: i, onValueChange: a, onClear: o, debounceMs: s = 0, loading: c = !1, placeholder: l, label: u, helperText: d, error: f, disabled: p, required: m, name: h, className: g, onKeyDown: _, shortcut: v, ...y }) {
12057
+ let { t: b } = L(), x = eo(), S = eo(), [C, w] = W(String(r ?? "")), T = t !== void 0, E = T ? String(t ?? "") : C, D = Gt(a), O = a !== void 0, k = H(() => s ? Po((e) => D.current?.(e), s) : null, [s, D]);
12058
+ V(() => () => k?.cancel(), [k]);
12059
+ let A = (e, t = !1) => {
12060
+ if (T || w(e), O) {
12061
+ if (t || !k) {
12062
+ k?.cancel(), D.current?.(e);
12063
12063
  return;
12064
12064
  }
12065
- O(e);
12065
+ k(e);
12066
12066
  }
12067
- }, A = () => {
12068
- k("", !0), i?.({
12067
+ }, ee = () => {
12068
+ A("", !0), o?.(), i?.({
12069
12069
  target: { value: "" },
12070
12070
  currentTarget: { value: "" }
12071
12071
  });
12072
- }, ee = e ?? b, j = po(v["aria-describedby"], !!u && x);
12072
+ }, j = e ?? x, M = po(y["aria-describedby"], !!d && S);
12073
12073
  return /* @__PURE__ */ K("div", {
12074
12074
  "data-slot": "search-field",
12075
- "data-pw": m ?? "search-field",
12076
- className: n("grid w-full content-start gap-1.5", h),
12075
+ "data-pw": h ?? "search-field",
12076
+ className: n("grid w-full content-start gap-1.5", g),
12077
12077
  children: [
12078
- l && /* @__PURE__ */ G(dt, {
12079
- htmlFor: ee,
12080
- withAsterisk: p,
12081
- children: l
12078
+ u && /* @__PURE__ */ G(dt, {
12079
+ htmlFor: j,
12080
+ withAsterisk: m,
12081
+ children: u
12082
12082
  }),
12083
12083
  /* @__PURE__ */ K(lv, {
12084
- "data-disabled": f || void 0,
12084
+ "data-disabled": p || void 0,
12085
12085
  children: [
12086
12086
  /* @__PURE__ */ G(dv, {
12087
12087
  align: "inline-start",
@@ -12093,39 +12093,39 @@ function GC({ id: e, value: t, defaultValue: r = "", onChange: i, onValueChange:
12093
12093
  })
12094
12094
  }),
12095
12095
  /* @__PURE__ */ G(mv, {
12096
- ...v,
12097
- id: ee,
12098
- name: m,
12096
+ ...y,
12097
+ id: j,
12098
+ name: h,
12099
12099
  type: "search",
12100
- value: T,
12101
- disabled: f,
12102
- required: p,
12103
- "aria-invalid": d || void 0,
12104
- "aria-busy": s || void 0,
12105
- "aria-describedby": j,
12106
- "aria-keyshortcuts": _,
12107
- placeholder: c ?? y("material.search-field.placeholder", "Search"),
12100
+ value: E,
12101
+ disabled: p,
12102
+ required: m,
12103
+ "aria-invalid": f || void 0,
12104
+ "aria-busy": c || void 0,
12105
+ "aria-describedby": M,
12106
+ "aria-keyshortcuts": v,
12107
+ placeholder: l ?? b("material.search-field.placeholder", "Search"),
12108
12108
  className: "[&::-webkit-search-cancel-button]:hidden",
12109
12109
  onChange: (e) => {
12110
- k(e.target.value), i?.(e);
12110
+ A(e.target.value), i?.(e);
12111
12111
  },
12112
12112
  onKeyDown: (e) => {
12113
- e.key === "Escape" && T && (e.preventDefault(), A()), g?.(e);
12113
+ e.key === "Escape" && E && (e.preventDefault(), ee()), _?.(e);
12114
12114
  }
12115
12115
  }),
12116
12116
  /* @__PURE__ */ G(WC, {
12117
- shortcut: _,
12118
- loading: s,
12119
- filled: T !== "",
12120
- disabled: f,
12121
- onClear: A
12117
+ shortcut: v,
12118
+ loading: c,
12119
+ filled: E !== "",
12120
+ disabled: p,
12121
+ onClear: ee
12122
12122
  })
12123
12123
  ]
12124
12124
  }),
12125
- u && /* @__PURE__ */ G(ut, {
12126
- id: x,
12127
- error: d,
12128
- children: u
12125
+ d && /* @__PURE__ */ G(ut, {
12126
+ id: S,
12127
+ error: f,
12128
+ children: d
12129
12129
  })
12130
12130
  ]
12131
12131
  });
@@ -1,4 +1,4 @@
1
- import { r as e } from "./i18n-provider-GV4Ukoe2.js";
1
+ import { r as e } from "./i18n-provider-WReTVxE3.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 } from "react";
4
4
  //#region ../../node_modules/date-fns/locale/fr/_lib/formatDistance.js
@@ -1,5 +1,5 @@
1
- import { r as e } from "./i18n-provider-GV4Ukoe2.js";
2
- import { t } from "./translate-material-C0aOnHpZ.js";
1
+ import { r as e } from "./i18n-provider-WReTVxE3.js";
2
+ import { t } from "./translate-material-DZ_i8xJx.js";
3
3
  import { useCallback as n } from "react";
4
4
  //#region lib/i18n/use-material-translation.ts
5
5
  function r() {
@@ -847,7 +847,8 @@ Its props are `ServerTableProps<T>`; `filter` is a `ServerTableFilter`,
847
847
  | `rows`, `totalCount`, `pageInfo` | the connection's page | — | `pageInfo: { endCursor?, hasNextPage }`; `rows` stable per answer |
848
848
  | `pageSize` | `number` | — | the footer's range ("21–40 of 45") |
849
849
  | `getRowId` | `(row) => string` | — | the selection's key |
850
- | `filter` | `ServerTableFilter` | — | `{ model, locked?, fieldProps?, variant?, sheetTrigger?, quick?, density?, shortcuts?, previewCount?, counts?, liveDelayMs?, label?, searchLabel?, searchPlaceholder? }` |
850
+ | `filter` | `ServerTableFilter` | — | `{ model, locked?, fieldProps?, variant?, sheetTrigger?, quick?, density?, shortcuts?, previewCount?, counts?, liveDelayMs?, label?, searchLabel?, searchPlaceholder?, searchApply?, searchMinLength?, codec? }` |
851
+ | `filter.codec` | `{ keepKnownValues?, encoding? }` | — | how the page reads and writes the URL: pass the loader's `keepKnownValues` / `encoding` so chips and rows agree |
851
852
  | `title` | `ReactNode` | — | the band's title (a string is an `<h2>`) |
852
853
  | `actions` | `ReactNode` | — | the page's actions, at the band's end |
853
854
  | `sorting` | `createSorting(…)` | — | headers sorted from the URL |
@@ -1163,10 +1164,41 @@ Its props are `FilterQueryProps`, its `variant` a `FilterQueryVariant`
1163
1164
  overload per kind, so `<Filter variant="bar" />` does not compile).
1164
1165
  `query` / `defaultQuery` + `onQueryChange` carry the user's query, never a
1165
1166
  locked condition; `density` (a `FilterDensity`: `'comfortable'` or
1166
- `'compact'`), `label`, `searchLabel`, `searchPlaceholder` and `liveDelayMs`
1167
- (200 ms) tune it. A locked chip is a focusable group named by its text ("Year is 2026-2027"), with "Locked: <reason>" as its description. The other variants
1167
+ `'compact'`), `label`, `searchLabel`, `searchPlaceholder`, `liveDelayMs`
1168
+ (200 ms), `searchApply` and `searchMinLength` tune it. A locked chip is a focusable group named by its text ("Year is 2026-2027"), with "Locked: <reason>" as its description. The other variants
1168
1169
  and `FilterProps` are unchanged.
1169
1170
 
1171
+ #### The search: apply on Enter, a minimum length
1172
+
1173
+ By default the search is live: the text reaches `onQueryChange` (and a
1174
+ `ServerTable`'s URL) `liveDelayMs` after the last keystroke. A list whose
1175
+ every request is costly or audited can hold it back:
1176
+
1177
+ ```tsx
1178
+ <ServerTable
1179
+ filter={{ model, searchApply: 'enter', searchMinLength: 3 }}
1180
+ {...props}
1181
+ />
1182
+ ```
1183
+
1184
+ - `searchApply: 'live' | 'enter'` (default `'live'`). With `'enter'`, typing
1185
+ changes nothing until Enter is pressed. Clearing the field (the ✕, Escape,
1186
+ or emptying it by hand then Enter) applies at once. The URL is written only
1187
+ when the search is applied, so a half-typed query never reaches the router
1188
+ or the loader.
1189
+ - `searchMinLength` (default `0`, in both modes): below it nothing is applied,
1190
+ and a short hint (`material.filter.bar.search-min`, "Type at least 3
1191
+ characters to search") is shown under the field and announced politely. An
1192
+ empty field is always allowed, because it clears. The length counts the
1193
+ trimmed text.
1194
+ - Both go on `Filter` (`variant="bar"` and `"facets"`) and on
1195
+ `ServerTable`'s `filter`. On a phone the search sits beside "Filters (N)"
1196
+ and follows them the same way.
1197
+ - A `text` field (an IPP number, a city) inherits `searchApply`, with no
1198
+ option of its own: its editor (the chip's popover, the facets panel) holds
1199
+ the text until Enter, which applies at once. The phone sheet and a staged
1200
+ panel keep their own Apply. `searchMinLength` concerns the search field only.
1201
+
1170
1202
  #### The model, the query and the URL
1171
1203
 
1172
1204
  Declare the fields once, in a `.ts` module with no JSX, so the route's loader
@@ -609,6 +609,7 @@ import { SearchField } from '@nxgt/material/components';
609
609
  | Prop | Type | Default | Effect |
610
610
  | --- | --- | --- | --- |
611
611
  | `onValueChange` | `(value: string) => void` | — | the text, debounced when `debounceMs` is set; the latest `onValueChange` is called when the delay ends, so an inline arrow is safe |
612
+ | `onClear` | `() => void` | — | the clear button or Escape emptied the field, after `onValueChange('')`; an input emptied by typing does not call it |
612
613
  | `debounceMs` | `number` | `0` | delay before `onValueChange`; `0` calls it on every key |
613
614
  | `loading` | `boolean` | `false` | spinner in place of the clear button |
614
615
  | `shortcut` | `string` | — | a hint for the key that focuses the field, e.g. `"/"`: a `Kbd` at the end while the field is empty, not loading and not disabled (`aria-hidden`) and `aria-keyshortcuts` on the input. It binds no key; your page listens and focuses the field |
@@ -81,6 +81,9 @@ phone's menu sheet pad clear of `env(safe-area-inset-*)`, as classes; see the
81
81
  | `menuOpen` / `onMenuOpenChange` | `boolean` / `(open: boolean) => void` | — | control the phone's menu sheet; it still closes by itself when a link in it is followed or the location changes (see the [app shell guide](../guides/app-shell.md#activitylayout)) |
82
82
  | `titleAs` | `'h1'` … `'h6'` \| `'div'` | `'h1'` | `ActivityContent`: the title's heading level |
83
83
  | `inset` | `boolean` | `false` | `ActivityContent`: pads the content 1rem on each side. Off, it lines up with the app bar and the cards |
84
+ | `width` | `'full' \| 'form' \| 'reading'` | `'full'` | `ActivityContent`: caps the main column at 48rem (`'form'`) or 72ch (`'reading'`), the side panel right beside it |
85
+ | `aside`, `asideLabel` / `asideLabelledBy` | `ReactNode`, `string` | — | `ActivityContent`: a side panel, a named `complementary` landmark, beside the content from 1280px (CSS only), stacked below; sticky under the app bar |
86
+ | `asideSide` / `asideWidth` / `asideFrom` / `asideSticky` / `asideStack` | `'start' \| 'end'` / `'sm' \| 'md' \| 'lg' \| string` / `'lg' \| 'xl' \| '2xl'` / `boolean` / `'before' \| 'after'` | `'end'` / `'md'` / `'xl'` / `true` / `'after'` | `ActivityContent`: the panel's side, width (16, 20, 24rem), breakpoint, stickiness and stacking order (see the [app shell guide](../guides/app-shell.md#a-side-panel-and-a-readable-width)) |
84
87
  | `align` | `'start' \| 'center'` | `'start'` | `ActivityLayout`, `AppSidebar`: the collapsed rail's entries sit right under the brand, or `'center'` for centred in the height below it |
85
88
  | `backdrop` | `ReactNode \| false` | — | `ActivityLayout`: an exception to the theme's background (drawn by default; Lavande's is the built-in gradient and blobs); `false` draws a plain page. A node is a decorative background behind the frame: a `Background` preset from `@nxgt/material/backgrounds`. Rendered in an `inert`, `aria-hidden` layer as wide as the content column and one viewport high, fixed in the viewport while the content scrolls; the chrome (app bar, breadcrumb, tabs strip) is lightly translucent and frosted over it (80%, 87% for the sidebar, breadcrumb and tabs strip, 92% and no blur under `prefers-reduced-transparency` or without `backdrop-filter`), and the lists, tables and cards stay opaque; `--nxgt-backdrop-chrome` sets the chrome's fill and `--nxgt-backdrop-surface` the lists'. See [Use a background preset behind the shell](../guides/app-shell.md#use-a-background-preset-behind-the-shell) |
86
89
  | `routeTransition` | `boolean \| Omit<ViewTransitionProps, 'children' \| 'ref'>` | `true` | `ActivityLayout`: React's `<ViewTransition>` around the content region, so a navigation cross-fades it. `false` renders none (your app has its own boundary); an object passes `default` / `update` classes, `name`, callbacks through. See [Route transitions](../guides/app-shell.md#route-transitions) |
@@ -799,6 +799,15 @@ export function BoardShell({ items }: { items: MenuItem[] }) {
799
799
  | `hideHeader` | `boolean` | `false` | No header card |
800
800
  | `titleAs` | `'h1'` … `'h6'` \| `'div'` | `'h1'` | The title's element: the screen's heading, `'h2'` under a heading of yours, `'div'` for none |
801
801
  | `inset` | `boolean` | `false` | Pads the content 1rem on each side. Off, it lines up with the app bar and the cards |
802
+ | `width` | `'full'` \| `'form'` \| `'reading'` | `'full'` | Caps the main column: `'form'` 48rem, `'reading'` 72ch. The header card keeps the full width |
803
+ | `aside` | `ReactNode` | — | A side panel: beside the content from `asideFrom`, stacked below it |
804
+ | `asideLabel` / `asideLabelledBy` | `string` | — | The panel's accessible name (`aria-label`), or the id of a heading inside it (`aria-labelledby`). One of them is needed |
805
+ | `asideSide` | `'start'` \| `'end'` | `'end'` | Which side of the content the panel sits on, wide |
806
+ | `asideWidth` | `'sm'` \| `'md'` \| `'lg'` \| a CSS length | `'md'` | 16, 20 or 24rem; `'md'` reads the `--nxgt-aside-width` token (20rem) |
807
+ | `asideFrom` | `'lg'` \| `'xl'` \| `'2xl'` | `'xl'` | The viewport width (1024, 1280 or 1536px) from which the panel is beside the content |
808
+ | `asideSticky` | `boolean` | `true` | Keeps the panel under the app bar while the page scrolls; it scrolls inside itself when taller than the window |
809
+ | `asideStack` | `'before'` \| `'after'` | `'after'` | Where the panel goes below `asideFrom`, in the DOM and on screen |
810
+ | `asideClassName` | `string` | — | Classes for the panel |
802
811
 
803
812
  ```tsx
804
813
  import { ActivityContent, Button } from '@nxgt/material/components';
@@ -819,6 +828,49 @@ export function InvoicesPage() {
819
828
  The header card wraps: on a narrow screen the actions go under the title
820
829
  instead of squeezing it, and a long title wraps rather than scrolling.
821
830
 
831
+ ### A side panel and a readable width
832
+
833
+ A record's alerts and key facts, a dashboard's counts, a form's help: pass them
834
+ as `aside`. From `asideFrom` (`'xl'`, a 1280px window) the panel sits beside the
835
+ main column and sticks under the app bar; below it, the panel stacks after the
836
+ content (`asideStack="before"` puts it first). The switch is CSS only: the
837
+ server's HTML and a phone's first paint are already right, and no JavaScript
838
+ decides the layout.
839
+
840
+ ```tsx
841
+ <ActivityContent
842
+ title="New visit"
843
+ width="form"
844
+ aside={<DuplicateHints />}
845
+ asideLabel="Possible duplicates"
846
+ >
847
+ <VisitForm />
848
+ </ActivityContent>
849
+ ```
850
+
851
+ - **Landmark.** The panel is an `<aside>`, a `complementary` landmark: name it
852
+ with `asideLabel`, or with `asideLabelledBy` (the id of its heading). Its
853
+ content is the panel's own; give it one `h2` when it has a heading.
854
+ - **Sticky, in every scroll mode.** With `scroll="document"` the panel sticks
855
+ under the app bar (the bar's gutter, its `--nxgt-header-height` and 0.5rem);
856
+ with `scroll="container"` it sticks to the top of the content region. It is as
857
+ tall as the window at most and scrolls inside itself, and becomes focusable
858
+ (`tabindex="0"`) only while it does, so a keyboard reaches what overflows. A
859
+ `scroll="document"` page needs no `overflow` on any ancestor of the screen
860
+ (see [the troubleshooting entry](../troubleshooting.md#the-side-panel-does-not-stick)).
861
+ - **A capped column sits beside its panel.** `width="form"` or `"reading"` caps
862
+ the main column and the pair stays start-aligned: at 1920px the panel is 1rem
863
+ from the fields, not at the window's far edge. The header card above keeps
864
+ the full width. `width` also works without a panel.
865
+ - **The breakpoint is the window's.** `asideFrom` follows the viewport, not the
866
+ content column, which the sidebar and the gutters narrow a little: pick `'lg'`
867
+ for a panel on a smaller window, `'2xl'` to keep it stacked on all but the
868
+ widest.
869
+ - **A size container.** With a panel, the main column is an `@container`, so a
870
+ `ResponsiveGrid` inside it follows the column's width.
871
+ - **Width token.** `--nxgt-aside-width` changes `asideWidth="md"` (20rem) app-wide;
872
+ any CSS length goes in `asideWidth` for one screen.
873
+
822
874
  ## Breadcrumbs
823
875
 
824
876
  `AppBreadcrumb` (rendered by `ActivityLayout`) starts with a home icon linking
@@ -275,7 +275,7 @@ children, `Spinner`'s and `ScrollToTop`'s `aria-label`, `LocationMarker`'s
275
275
 
276
276
  `Filter variant="bar"` words everything through its own keys,
277
277
  overridable like the rest: `material.filter.bar.*` (`label` "Filters" for its
278
- `search` landmark, `search`, `active` "Active filters" for the chip list,
278
+ `search` landmark, `search`, `search-min` "Type at least {min} character(s) to search" (the hint under the search while it is shorter than `searchMinLength`; a plural), `active` "Active filters" for the chip list,
279
279
  `locked` "Locked" and `locked-reason` "Locked: {reason}" (a locked
280
280
  chip's description), and a chip's words: `chip` "{field} {operator}
281
281
  {value}", `chip-plain`, `remove` "Remove {field}: {value}", `quick-active`;
@@ -144,6 +144,12 @@ export default function Students({ loaderData }: Route.ComponentProps) {
144
144
  never leaves you on a page that no longer exists. `serializeFilterQuery`
145
145
  copies `into`, it does not change it, and it replaces the search, every `f=`,
146
146
  every aliased param and the `reset` ones.
147
+ - **The search on Enter.** Every applied edit is one URL write, hence one
148
+ loader call. `searchApply: 'enter'` (on `Filter`, or `ServerTable`'s
149
+ `filter`) writes the search only when Enter is pressed, and
150
+ `searchMinLength` keeps a too-short text out of the URL; clearing the field
151
+ writes at once. Typing in between writes nothing, so a loader whose every
152
+ read is audited is called once per search.
147
153
  - **`resultCount` and `loading`** drive the bar's one live region: it waits
148
154
  for `loading` to end, then tells the count once.
149
155
  - **A readable URL.** `` `?${written}` `` prints `f=level:in:CE1,CE2`. Passing
@@ -151,6 +157,12 @@ export default function Students({ loaderData }: Route.ComponentProps) {
151
157
  re-encodes them (`f=level%3Ain%3ACE1%2CCE2`), which parses back the same. To
152
158
  compare a URL you wrote with the one the router hands back, use
153
159
  `paramsKey(a) === paramsKey(b)`.
160
+ - **The same options on both sides.** If the loader parses with
161
+ `keepKnownValues: true` (or writes `encoding: 'standard'`), give
162
+ `ServerTable` the same: `filter={{ model, codec: { keepKnownValues: true,
163
+ encoding: 'standard' } }}`. Without it the page drops a condition such as
164
+ `f=level:in:a,zzz` whole and shows no chip, while the loader keeps `a` and
165
+ filters the rows.
154
166
  - **Standard encoding.** If your list URLs are already written the
155
167
  `URLSearchParams` way (`status=a%2Cb`), pass `encoding: 'standard'` to
156
168
  `serializeFilterQuery` (and to `tableFilters` / `withoutFilters`): the params
@@ -625,6 +625,7 @@ centre line from `md` (48rem) up:
625
625
  | Token | Default | Reads |
626
626
  | --- | --- | --- |
627
627
  | `--nxgt-header-height` | `4rem` | the app bar (all widths) and the rail's header (`md` and up) |
628
+ | `--nxgt-aside-width` | `20rem` | an `ActivityContent` side panel with `asideWidth="md"` (the default) |
628
629
 
629
630
  ```css
630
631
  :root {
@@ -1338,6 +1338,30 @@ top (`align="start"`).
1338
1338
  <ActivityLayout items={items} align="center">…</ActivityLayout>
1339
1339
  ```
1340
1340
 
1341
+ ### The side panel does not stick
1342
+
1343
+ **When:** an `ActivityContent` `aside` scrolls away with the page instead of
1344
+ staying under the app bar, or it is not beside the content at 1280px.
1345
+ **Why:** `position: sticky` sticks inside its nearest scrolling ancestor, and
1346
+ any ancestor with an `overflow` other than `visible` (`overflow-hidden`,
1347
+ `overflow-auto`, `overflow-clip`; a `PaneLayout`'s root has `overflow-hidden`)
1348
+ becomes that scroller, which does not scroll, so the panel never moves. A
1349
+ wrapper of yours around the screen, or an `ActivityLayout` with
1350
+ `scroll="container"` where you meant `"document"`, does the same. Below
1351
+ `asideFrom` (1280px by default) the panel is stacked and not sticky on
1352
+ purpose, and the breakpoint is the window's width, not the column's.
1353
+ **Fix:** take the `overflow` off every ancestor between `ActivityLayout` and
1354
+ `ActivityContent`, or move it onto an element inside the screen; use
1355
+ `scroll="document"` (the default). Find the culprit in the console:
1356
+
1357
+ ```js
1358
+ for (let el = document.querySelector('[data-slot="activity-content-aside"]').parentElement; el; el = el.parentElement)
1359
+ if (getComputedStyle(el).overflowY !== 'visible') console.log(el);
1360
+ ```
1361
+
1362
+ With `scroll="container"` the region itself is the scroller, and the panel
1363
+ sticks to its top: that is expected.
1364
+
1341
1365
  ### axe reports `target-size` on a control under a form's sticky actions
1342
1366
 
1343
1367
  **When:** since the form's actions stick to the bottom (see above), axe's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/material",
3
- "version": "3.15.0",
3
+ "version": "3.17.0",
4
4
  "license": "MIT",
5
5
  "bugs": {
6
6
  "email": "stevegires@gmail.com"
@@ -357,7 +357,7 @@
357
357
  "docs:previews": "rm -rf node_modules/.cache/nxgt-preview-free/missing && NXGT_PREVIEW_FREE=1 vitest run --project previews && bun .storybook/preview-free-report.ts"
358
358
  },
359
359
  "dependencies": {
360
- "@nxgt/material-core": "^0.31.0",
360
+ "@nxgt/material-core": "^0.32.0",
361
361
  "@base-ui/react": "^1.6.0",
362
362
  "@dnd-kit/core": "^6.3.1",
363
363
  "@dnd-kit/sortable": "^10.0.0",