@nxgt/material 2.7.1 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +201 -0
- package/README.md +9 -6
- package/dist/{_Uint8Array-JRUmWcRr.js → _Uint8Array-azThpjEP.js} +1 -1
- package/dist/{_overRest-DvC5rm5s.js → _overRest-DMn4Dt71.js} +1 -1
- package/dist/{abnfDiagram-O67JEVCF-Cl4ukf6a.js → abnfDiagram-O67JEVCF-D-rmT4BY.js} +4 -4
- package/dist/{architectureDiagram-NJMV4G6O-WmFlBQF5.js → architectureDiagram-NJMV4G6O-DOc_c_T9.js} +7 -7
- package/dist/{async-slice-OftEOtMA.js → async-slice-DhZDjEtw.js} +2 -2
- package/dist/{blockDiagram-BEXU5L5S-BM-gkWAO.js → blockDiagram-BEXU5L5S-BOsyK4E_.js} +11 -11
- package/dist/{c4Diagram-YGBWAQC7-D9xSt2QO.js → c4Diagram-YGBWAQC7-El4SkIzX.js} +8 -8
- package/dist/{channel-Dg92Hoym.js → channel-CnLB6790.js} +1 -1
- package/dist/{chunk-3FUC2YCW-Cf18L00V.js → chunk-3FUC2YCW-BCsKm3ZT.js} +8 -8
- package/dist/{chunk-5DYCD2WN-Cja1INgd.js → chunk-5DYCD2WN-Cd1zazNp.js} +3 -3
- package/dist/{chunk-6AEJRKK7-3YWRP4aV.js → chunk-6AEJRKK7-BLBlw8ui.js} +2 -2
- package/dist/{chunk-742MDFTN-Cs1qGiTK.js → chunk-742MDFTN-CsUjFyzK.js} +2 -2
- package/dist/{chunk-7INBJB4K-BY5n77ka.js → chunk-7INBJB4K-k-I67NSP.js} +6 -6
- package/dist/{chunk-7M6MHVWA-C3x6E3yT.js → chunk-7M6MHVWA-C3qpW8zM.js} +9 -9
- package/dist/{chunk-7PRAP22T-_Av9vcXz.js → chunk-7PRAP22T-0C6_H8Li.js} +1 -1
- package/dist/{chunk-GNY47TPC-D1E6DHDV.js → chunk-GNY47TPC-CzPNLW5k.js} +11 -11
- package/dist/{chunk-GTNCS2PH-BZ9WMD1v.js → chunk-GTNCS2PH-AJi9PVT7.js} +3 -3
- package/dist/{chunk-GWA4HPMP-Co-A6dtV.js → chunk-GWA4HPMP-B8jXI0Tl.js} +3 -3
- package/dist/{chunk-MBY4JIJT-C3RQP_Nk.js → chunk-MBY4JIJT-BFIqOe-8.js} +4 -4
- package/dist/{chunk-NETBCI7D-DJUuN4EY.js → chunk-NETBCI7D-tNinefdn.js} +1 -1
- package/dist/{chunk-O7XYJQB3-A66QSOPA.js → chunk-O7XYJQB3-BChweQ_V.js} +1 -1
- package/dist/{chunk-UA2S7LBM-BNeHeMx9.js → chunk-UA2S7LBM-ChuksCDg.js} +6 -6
- package/dist/{chunk-WEXAMYUT-CucJfehv.js → chunk-WEXAMYUT-CbFOhEve.js} +2 -2
- package/dist/{chunk-XXDRQBXY-FgXU14Bh.js → chunk-XXDRQBXY-dKXxu_aj.js} +1 -1
- package/dist/{chunk-Z7XXMR3K-DMTBxZxM.js → chunk-Z7XXMR3K-C9P-XjM2.js} +8 -8
- package/dist/{chunk-ZIGJFQKS-C3xUAXJq.js → chunk-ZIGJFQKS-9VXArDKF.js} +3 -3
- package/dist/{classDiagram-v2-NBCMYWYE-BDaxYvDy.js → classDiagram-v2-NBCMYWYE-D00ZobEC.js} +14 -14
- package/dist/clsx-CbxlCXZ3.js +16 -0
- package/dist/components/base-content.css +139 -0
- package/dist/components/base.css +150 -0
- package/dist/components/components.css +2 -0
- package/dist/components/reduced-motion.css +56 -0
- package/dist/components/theme-tokens.css +116 -0
- package/dist/components/ui/actions/button-group/button-group.css +1 -1
- package/dist/components/ui/feedback/toast/toast.css +21 -0
- package/dist/components/ui/primitives/label/label.css +33 -0
- package/dist/{components-DrStgM4J.js → components-km60bAdr.js} +34658 -34218
- package/dist/components.js +6 -6
- package/dist/{cose-bilkent-JH36ORCC-DRUT3qBb.js → cose-bilkent-JH36ORCC-P94vkHv_.js} +2 -2
- package/dist/{cynefinDiagram-VND7K2PF-B9HrdQW8.js → cynefinDiagram-VND7K2PF-EIpXbLXm.js} +4 -4
- package/dist/{dagre-6A5THRUB-DZF0nICj.js → dagre-6A5THRUB-D_F3_LlW.js} +20 -20
- package/dist/{diagram-22UHCM2B-CVZYpeev.js → diagram-22UHCM2B-CsxOExpW.js} +15 -15
- package/dist/{diagram-3UASUU5V-D7MmBJbM.js → diagram-3UASUU5V-Dl7AETV1.js} +7 -7
- package/dist/{diagram-ATOU4E4O-CNY-8kl0.js → diagram-ATOU4E4O-isL7nwg2.js} +3 -3
- package/dist/{diagram-CDSNMT55-C8Mk1smi.js → diagram-CDSNMT55-Bnhlo5at.js} +5 -5
- package/dist/{diagram-MLGK6HIB-CpfeILwW.js → diagram-MLGK6HIB-DvBcyz8v.js} +4 -4
- package/dist/{diagram-MPIPVDR6-Do7bUnTd.js → diagram-MPIPVDR6-iTevwmNE.js} +4 -4
- package/dist/{dist-C3YK_ean.js → dist-B6_-RPZ3.js} +1 -1
- package/dist/{dist-CRbPtqwD.js → dist-BvUQHUs_.js} +4 -4
- package/dist/dnd.js +1 -1
- package/dist/{ebnfDiagram-ZINNZB2B-1GewX9Zq.js → ebnfDiagram-ZINNZB2B-RVuQIpm0.js} +4 -4
- package/dist/{elk-276RUBZZ-DI4eicFj.js → elk-276RUBZZ-BK-NMLiI.js} +26 -26
- package/dist/{erDiagram-OPXOYQCR-CUbpVns3.js → erDiagram-OPXOYQCR-DC1GgS4l.js} +14 -14
- package/dist/field-blur--x_n3oMy.js +3637 -0
- package/dist/flowDiagram-KWPJA3E3-BUSlDNQP.js +17 -0
- package/dist/{ganttDiagram-FUAMR5RP-D3vmspam.js → ganttDiagram-FUAMR5RP-DOp1p_x0.js} +6 -6
- package/dist/{gitGraphDiagram-X574FWY7-80yOq8dE.js → gitGraphDiagram-X574FWY7-DerJL1Q-.js} +3 -3
- package/dist/{graphlib-DLJn7qS3.js → graphlib-DLjE3QPd.js} +6 -6
- package/dist/hooks.js +3 -3
- package/dist/{i18n-provider-DBFRz5uH.js → i18n-provider-CQL7fqLy.js} +1 -1
- package/dist/i18n.js +6 -6
- package/dist/icon-button-G9zdQ3Ix.js +2753 -0
- package/dist/{infoDiagram-VRGFBTTK-Cboh-B9n.js → infoDiagram-VRGFBTTK-CtVsLyCQ.js} +3 -3
- package/dist/{isArrayLikeObject-CO5xeuaJ.js → isArrayLikeObject-CO-5KAzG.js} +3 -3
- package/dist/{isEmpty-DOC38Ces.js → isEmpty-Bl1drJE7.js} +3 -3
- package/dist/{ishikawaDiagram-OU5B5YK6-DwTd1YxL.js → ishikawaDiagram-OU5B5YK6-D1n8vp8C.js} +4 -4
- package/dist/{journeyDiagram-ZHPQQLJL-Dxvl3oeN.js → journeyDiagram-ZHPQQLJL-DuQ9Th0y.js} +4 -4
- package/dist/{kanban-definition-PNTS6WVX-S8plI4wn.js → kanban-definition-PNTS6WVX-D1-Owjil.js} +10 -10
- package/dist/lib/components/ui/actions/button/busy-click-capture.d.ts +11 -0
- package/dist/lib/components/ui/actions/button/button-tones.d.ts +36 -0
- package/dist/lib/components/ui/actions/button/button.d.ts +19 -0
- package/dist/lib/components/ui/actions/button/button.wrap.d.ts +8 -0
- package/dist/lib/components/ui/actions/button/label-text.d.ts +10 -0
- package/dist/lib/components/ui/actions/button/use-click-lock.d.ts +18 -0
- package/dist/lib/components/ui/actions/copy-button/copy-button.d.ts +5 -1
- package/dist/lib/components/ui/actions/icon-button/icon-button.compound-variants.d.ts +114 -0
- package/dist/lib/components/ui/collections/data-table/hooks.d.ts +13 -13
- package/dist/lib/components/ui/collections/data-table/partials/data-table-empty-row.d.ts +5 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-scroll-region.d.ts +16 -0
- package/dist/lib/components/ui/collections/data-table/partials/data-table-toolbar.d.ts +24 -0
- package/dist/lib/components/ui/collections/data-table/select-checkbox.d.ts +10 -0
- package/dist/lib/components/ui/collections/data-table/types.d.ts +9 -0
- package/dist/lib/components/ui/collections/data-table/use-data-table.d.ts +12 -1
- package/dist/lib/components/ui/collections/data-table/use-scroll-edges.d.ts +22 -0
- package/dist/lib/components/ui/dates/calendar/calendar-day.d.ts +8 -0
- package/dist/lib/components/ui/dates/calendar/calendar.d.ts +3 -3
- package/dist/lib/components/ui/dates/calendar/calendar.utils.d.ts +8 -0
- package/dist/lib/components/ui/dates/calendar/use-calendar-labels.d.ts +22 -0
- package/dist/lib/components/ui/display/description/description.d.ts +2 -1
- package/dist/lib/components/ui/display/list-tile/list-tile.d.ts +9 -1
- package/dist/lib/components/ui/display/list-tile/partials/list-tile-body.d.ts +11 -0
- package/dist/lib/components/ui/display/list-tile/partials/list-tile-classes.d.ts +10 -0
- package/dist/lib/components/ui/feedback/alert-dialog/alert-dialog.d.ts +1 -1
- package/dist/lib/components/ui/feedback/toast/partials/toast-actions.d.ts +3 -0
- package/dist/lib/components/ui/feedback/toast/toast.d.ts +27 -3
- package/dist/lib/components/ui/feedback/toast/toaster.d.ts +19 -0
- package/dist/lib/components/ui/feedback/toast/toasts.d.ts +3 -0
- package/dist/lib/components/ui/forms/field-blur.d.ts +7 -2
- package/dist/lib/components/ui/forms/use-field-blur.d.ts +8 -1
- package/dist/lib/components/ui/layout/app-shell/activity-content.d.ts +10 -1
- package/dist/lib/components/ui/layout/app-shell/activity-layout.d.ts +26 -2
- package/dist/lib/components/ui/layout/app-shell/app-header.d.ts +8 -2
- package/dist/lib/components/ui/layout/app-shell/app-sidebar.d.ts +8 -2
- package/dist/lib/components/ui/layout/app-shell/types.d.ts +3 -0
- package/dist/lib/components/ui/layout/app-shell/use-content-scroll.d.ts +10 -0
- package/dist/lib/components/ui/layout/app-shell/use-navigation-sheet.d.ts +19 -0
- package/dist/lib/components/ui/layout/sidebar/index.d.ts +5 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-content.d.ts +2 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-context.d.ts +7 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-footer.d.ts +2 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-header.d.ts +2 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-menu-item-tooltip.d.ts +7 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-menu-item.d.ts +31 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar-menu-label.d.ts +4 -0
- package/dist/lib/components/ui/layout/sidebar/sidebar.d.ts +1 -12
- package/dist/lib/components/ui/overlays/context-menu/context-menu-items.d.ts +10 -0
- package/dist/lib/components/ui/overlays/context-menu/context-menu-sub.d.ts +8 -0
- package/dist/lib/components/ui/overlays/context-menu/context-menu.d.ts +4 -14
- package/dist/lib/components/ui/overlays/dialog/dialog-outside.d.ts +6 -0
- package/dist/lib/components/ui/overlays/dialog/dialog-scroll-content.d.ts +1 -1
- package/dist/lib/components/ui/overlays/dialog/dialog.d.ts +1 -1
- package/dist/lib/components/ui/overlays/dialog/use-return-focus.d.ts +3 -2
- package/dist/lib/components/ui/overlays/drawer/drawer.d.ts +1 -1
- package/dist/lib/components/ui/overlays/dropdown-menu/dropdown-menu-items.d.ts +11 -0
- package/dist/lib/components/ui/overlays/dropdown-menu/dropdown-menu-sub.d.ts +8 -0
- package/dist/lib/components/ui/overlays/dropdown-menu/dropdown-menu.d.ts +6 -21
- package/dist/lib/components/ui/overlays/popover/popover.d.ts +1 -1
- package/dist/lib/components/ui/overlays/sheet/sheet.d.ts +1 -1
- package/dist/lib/components/ui/primitives/card/card.d.ts +10 -1
- package/dist/lib/components/ui/primitives/link/link-component.d.ts +14 -0
- package/dist/lib/components/ui/primitives/tabs/partials/tabs-content.d.ts +3 -0
- package/dist/lib/components/ui/primitives/tabs/partials/tabs-indicator.d.ts +13 -0
- package/dist/lib/components/ui/primitives/tabs/partials/tabs-list.d.ts +3 -0
- package/dist/lib/components/ui/primitives/tabs/partials/tabs-trigger.d.ts +6 -0
- package/dist/lib/components/ui/primitives/tabs/tabs-classes.d.ts +27 -0
- package/dist/lib/components/ui/primitives/tabs/tabs-variant.d.ts +5 -0
- package/dist/lib/components/ui/primitives/tabs/tabs.d.ts +11 -7
- package/dist/lib/components/ui/selection/select/select.d.ts +1 -1
- package/dist/lib/components/ui/selection/select-chip-field/select-chip-field.d.ts +1 -1
- package/dist/lib/components/ui/widgets/emoji/types.d.ts +1 -6
- package/dist/lib/i18n/resources/en/en.d.ts +23 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +28 -5
- package/dist/lib/i18n/resources/fr/fr.d.ts +23 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +28 -5
- package/dist/lib/i18n/resources/resources.d.ts +46 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib/lib/redux/status-slice.d.ts +1 -1
- package/dist/lib.js +39 -55
- package/dist/main.js +13 -13
- package/dist/map.js +35 -35
- package/dist/material.css +1 -1
- package/dist/{merge-CuDTNgpm.js → merge-CwwtONfp.js} +4 -4
- package/dist/{mermaid.core-O7mtb1-p.js → mermaid.core-Dfr4zfuP.js} +49 -49
- package/dist/{mindmap-definition-NLK3R4M7-CO0E97EZ.js → mindmap-definition-NLK3R4M7-_qKWGSrk.js} +13 -13
- package/dist/{pegDiagram-GJSIUBJH-CAO6aYvj.js → pegDiagram-GJSIUBJH-CWKobqLl.js} +4 -4
- package/dist/{pieDiagram-5QR66LMP-BXxVfv5K.js → pieDiagram-5QR66LMP-B6at48Bd.js} +5 -5
- package/dist/print.js +2 -2
- package/dist/{quadrantDiagram-O4NWA36T-BbidZDM8.js → quadrantDiagram-O4NWA36T-Cr9bA0xJ.js} +3 -3
- package/dist/{railroadDiagram-XR7U4H2S-DmKDXg8V.js → railroadDiagram-XR7U4H2S-fsZ7oqPG.js} +4 -4
- package/dist/{requirementDiagram-PLB6GJNP-wFvgSWJP.js → requirementDiagram-PLB6GJNP-BBs-lByV.js} +13 -13
- package/dist/rolldown-runtime-BFFgcFxR.js +30 -0
- package/dist/{sankeyDiagram-IPEJSGJF-Cka5t09q.js → sankeyDiagram-IPEJSGJF-BzX37jGY.js} +3 -3
- package/dist/{sequenceDiagram-PO4LG4MO-B2qb55A5.js → sequenceDiagram-PO4LG4MO-Bgx1kuGA.js} +5 -5
- package/dist/{sortable-provider-C5VYhY8u.js → sortable-provider-WZT5I34N.js} +24 -24
- package/dist/{src-C9kQSo6K.js → src-CsLQInsN.js} +1 -1
- package/dist/{stateDiagram-v2-GCMORJYK-EMa7q3ju.js → stateDiagram-v2-GCMORJYK-Chc9Z6Mr.js} +14 -14
- package/dist/{stored-language-B0o4cBh8.js → stored-language-BW32owje.js} +56 -10
- package/dist/styles.css +10 -368
- package/dist/{swimlanes-2SLR337P-BtZ7Di5u.js → swimlanes-2SLR337P-D0yLvfot.js} +12 -12
- package/dist/swimlanesDiagram-TC7HE7FX-BOd0Czfs.js +28 -0
- package/dist/{timeline-definition-EJHVYXUP-2Z6UABw8.js → timeline-definition-EJHVYXUP-nDNR-Dt-.js} +5 -5
- package/dist/{translate-material-BCwQrt2G.js → translate-material-ZEzF-LKH.js} +2 -2
- package/dist/{translator-CwpmpI24.js → translator-BfqVlNGW.js} +1 -1
- package/dist/{use-heading-spy-BtBJiU63.js → use-heading-spy-DvZVu15k.js} +37 -37
- package/dist/{use-material-translation-DG_7z3Q7.js → use-material-translation-B2GUtxUY.js} +2 -2
- package/dist/{usecaseDiagram-POWQR4AR-DT56cp_B.js → usecaseDiagram-POWQR4AR-Bwen99ay.js} +13 -13
- package/dist/{utils-UBn-46YY.js → utils-DC8bw9A_.js} +346 -360
- package/dist/{vennDiagram-UO4OBE2U-CO0yFCI8.js → vennDiagram-UO4OBE2U-BpgP__1T.js} +4 -4
- package/dist/{wardleyDiagram-VNRHLVJA-QkwghAYo.js → wardleyDiagram-VNRHLVJA-CYqKMb2f.js} +4 -4
- package/dist/{xychartDiagram-PMCCYNJV-B2aZlrno.js → xychartDiagram-PMCCYNJV-b-Quuxoi.js} +7 -7
- package/docs/components/buttons-and-actions.md +60 -10
- package/docs/components/data-display.md +24 -2
- package/docs/components/data-table-filter-and-lists.md +88 -10
- package/docs/components/date-and-time.md +24 -0
- package/docs/components/feedback-and-status.md +85 -8
- package/docs/components/form-fields.md +14 -5
- package/docs/components/media-and-files.md +7 -0
- package/docs/components/navigation-and-layout.md +21 -3
- package/docs/components/overlays-and-menus.md +21 -6
- package/docs/components/primitives.md +96 -7
- package/docs/components/rich-widgets.md +10 -0
- package/docs/components/selection-and-choice.md +13 -2
- package/docs/getting-started.md +4 -2
- package/docs/guides/app-shell.md +97 -4
- package/docs/guides/forms.md +54 -5
- package/docs/guides/helpers.md +2 -2
- package/docs/guides/i18n.md +24 -4
- package/docs/guides/ssr.md +1 -1
- package/docs/guides/theming.md +147 -5
- package/docs/previews/data-display-codegroup.webp +0 -0
- package/docs/previews/data-display-description.webp +0 -0
- package/docs/previews/feedback-status-toast.webp +0 -0
- package/docs/previews/primitives-tabs.webp +0 -0
- package/docs/previews/rich-widgets-emojipicker.webp +0 -0
- package/docs/roadmap.md +29 -1
- package/docs/troubleshooting.md +937 -11
- package/lib/components/base-content.css +139 -0
- package/lib/components/base.css +150 -0
- package/lib/components/components.css +2 -0
- package/lib/components/reduced-motion.css +56 -0
- package/lib/components/theme-tokens.css +116 -0
- package/lib/components/ui/actions/button-group/button-group.css +1 -1
- package/lib/components/ui/feedback/toast/toast.css +21 -0
- package/lib/components/ui/primitives/label/label.css +33 -0
- package/lib/styles.css +10 -368
- package/package.json +2 -2
- package/dist/field-blur-DWQtxiAe.js +0 -3483
- package/dist/flowDiagram-KWPJA3E3-DZxumFfu.js +0 -17
- package/dist/icon-button-BxySFfrr.js +0 -2718
- package/dist/lib/components/ui/widgets/emoji/emoji.groups.d.ts +0 -6
- package/dist/swimlanesDiagram-TC7HE7FX-CROh8GTF.js +0 -28
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as e } from "./src-
|
|
2
|
-
import { i as t } from "./chunk-ZIGJFQKS-
|
|
1
|
+
import { t as e } from "./src-CsLQInsN.js";
|
|
2
|
+
import { i as t } from "./chunk-ZIGJFQKS-9VXArDKF.js";
|
|
3
3
|
import { n } from "./chunk-Y2CYZVJY-BAad7w_K.js";
|
|
4
|
-
import { H as r, U as i, a, b as o, c as s, f as c, it as l, nt as u, q as d, rt as f, tt as p, v as m, w as h, y as g } from "./chunk-O7XYJQB3-
|
|
5
|
-
import { t as _ } from "./chunk-6AEJRKK7-
|
|
4
|
+
import { H as r, U as i, a, b as o, c as s, f as c, it as l, nt as u, q as d, rt as f, tt as p, v as m, w as h, y as g } from "./chunk-O7XYJQB3-BChweQ_V.js";
|
|
5
|
+
import { t as _ } from "./chunk-6AEJRKK7-BLBlw8ui.js";
|
|
6
6
|
import { t as v } from "./rough.esm-Cvc79rxE.js";
|
|
7
7
|
//#region ../../node_modules/khroma/dist/methods/transparentize.js
|
|
8
8
|
var y = (e, t) => f(e, "a", -t), b = 1e-10;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as e } from "./src-
|
|
2
|
-
import { i as t } from "./chunk-ZIGJFQKS-
|
|
1
|
+
import { n as e } from "./src-CsLQInsN.js";
|
|
2
|
+
import { i as t } from "./chunk-ZIGJFQKS-9VXArDKF.js";
|
|
3
3
|
import { n } from "./mermaid-parser.core-BXD_TD1T.js";
|
|
4
4
|
import { n as r } from "./chunk-Y2CYZVJY-BAad7w_K.js";
|
|
5
|
-
import { D as i, H as a, U as o, a as s, b as c, c as l, q as u, v as d, w as f, x as p, y as m } from "./chunk-O7XYJQB3-
|
|
6
|
-
import { t as h } from "./chunk-6AEJRKK7-
|
|
5
|
+
import { D as i, H as a, U as o, a as s, b as c, c as l, q as u, v as d, w as f, x as p, y as m } from "./chunk-O7XYJQB3-BChweQ_V.js";
|
|
6
|
+
import { t as h } from "./chunk-6AEJRKK7-BLBlw8ui.js";
|
|
7
7
|
import { t as g } from "./chunk-JWPE2WC7-BGVSGRTC.js";
|
|
8
8
|
//#region ../../node_modules/mermaid/dist/chunks/mermaid.core/wardleyDiagram-VNRHLVJA.mjs
|
|
9
9
|
var _ = /* @__PURE__ */ r((e, t) => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { at as e, rt as t, st as n } from "./components-
|
|
2
|
-
import { n as r } from "./src-
|
|
3
|
-
import { i } from "./chunk-ZIGJFQKS-
|
|
1
|
+
import { at as e, rt as t, st as n } from "./components-km60bAdr.js";
|
|
2
|
+
import { n as r } from "./src-CsLQInsN.js";
|
|
3
|
+
import { i } from "./chunk-ZIGJFQKS-9VXArDKF.js";
|
|
4
4
|
import { n as a } from "./chunk-Y2CYZVJY-BAad7w_K.js";
|
|
5
|
-
import { D as o, H as s, U as c, a as l, b as u, c as d, f, q as p, v as m, w as h, y as g, z as _ } from "./chunk-O7XYJQB3-
|
|
6
|
-
import { t as v } from "./chunk-6AEJRKK7-
|
|
7
|
-
import "./chunk-742MDFTN-
|
|
8
|
-
import { t as y } from "./chunk-MBY4JIJT-
|
|
5
|
+
import { D as o, H as s, U as c, a as l, b as u, c as d, f, q as p, v as m, w as h, y as g, z as _ } from "./chunk-O7XYJQB3-BChweQ_V.js";
|
|
6
|
+
import { t as v } from "./chunk-6AEJRKK7-BLBlw8ui.js";
|
|
7
|
+
import "./chunk-742MDFTN-CsUjFyzK.js";
|
|
8
|
+
import { t as y } from "./chunk-MBY4JIJT-BFIqOe-8.js";
|
|
9
9
|
//#region ../../node_modules/mermaid/dist/chunks/mermaid.core/xychartDiagram-PMCCYNJV.mjs
|
|
10
10
|
var b = (function() {
|
|
11
11
|
var e = /* @__PURE__ */ a(function(e, t, n, r) {
|
|
@@ -50,15 +50,63 @@ import { Mail } from 'lucide-react';
|
|
|
50
50
|
| `variant` | `'filled' \| 'tonal' \| 'outlined' \| 'ghost' \| 'link'` | `'filled'` | the style |
|
|
51
51
|
| `color` | `'primary' \| 'secondary' \| 'success' \| 'info' \| 'warning' \| 'error' \| 'default'` | `'primary'` | the colour; `default` is the foreground colour |
|
|
52
52
|
| `size` | `'xs' \| 'sm' \| 'default' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | — | height: 24, 32, 36 and 40 px; the `icon*` sizes are square, for a button holding only an icon (give it an `aria-label`). Unset, the button keeps its content's height, as before sizes existed |
|
|
53
|
-
| `loading` | `boolean` | — |
|
|
53
|
+
| `loading` | `boolean` | — | busy: a spinner, `aria-busy="true"` and `aria-disabled="true"`, and every click cancelled — a submit button submits neither on a click nor on Enter in a field. It stays focusable (no native `disabled`), so focus is not lost |
|
|
54
|
+
| `lockOnClick` | `boolean` | — | a click makes the button busy at once, until `loading` has turned true and back (or for one second when it never does): for a `loading` that turns true only after an `await` |
|
|
54
55
|
| `spinnerVariant` | `SpinnerProps['variant']` | `'2'` | which spinner `loading` shows |
|
|
56
|
+
| `wrap` | `boolean` | — | the label breaks onto as many lines as it needs, centred, instead of being cut with “…”: the button grows taller, never shorter than its `size`. Ignored by the `icon*` sizes |
|
|
55
57
|
| `tooltip` | `string` | — | wraps the button in a `Tooltip` |
|
|
56
58
|
| `asChild` | `boolean` | `false` | styles its only child instead of rendering a `<button>` |
|
|
57
59
|
| `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | not `submit` by default — pass it inside a form |
|
|
58
60
|
|
|
59
61
|
The classes are exported as `buttonVariants` for styling your own element.
|
|
60
62
|
|
|
61
|
-
**
|
|
63
|
+
**On a phone.** A button is never wider than its container, and keeps its
|
|
64
|
+
content's width in a column: a label too
|
|
65
|
+
long for it (a card on a phone) is cut with “…” on one line, and its
|
|
66
|
+
accessible name — and a `title` you give it — keep the whole text. Give a
|
|
67
|
+
label that must be read in full `wrap`, or a width of your own (`w-full`).
|
|
68
|
+
The text is put in a `<span data-slot="button-label">` (one per run of
|
|
69
|
+
text) that shrinks and ends in the ellipsis; it needs the text to be the button's own child; with `asChild`,
|
|
70
|
+
put the label in a `<span>` inside the child element.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<Button title="Continue to the payment details">Continue to the payment details</Button>;
|
|
74
|
+
<Button wrap>Continue to the payment details and confirm the order</Button>;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Submitting once.** Give a submit button `loading={formState.isSubmitting}`:
|
|
78
|
+
React Hook Form sets it as `handleSubmit` starts, so the button is busy from
|
|
79
|
+
the first click and a double click, or Enter pressed twice, submits once.
|
|
80
|
+
When `loading` comes from something that turns true later — a mutation's
|
|
81
|
+
`isPending` after an async resolver — the second click comes first: add
|
|
82
|
+
`lockOnClick`.
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
<form onSubmit={handleSubmit(onSubmit)}>
|
|
86
|
+
<EmailFormField control={control} name="email" label="Email" />
|
|
87
|
+
<Button type="submit" loading={formState.isSubmitting}>
|
|
88
|
+
Sign in
|
|
89
|
+
</Button>
|
|
90
|
+
</form>;
|
|
91
|
+
|
|
92
|
+
<Button type="submit" loading={mutation.isPending} lockOnClick>
|
|
93
|
+
Sign in
|
|
94
|
+
</Button>;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**What the guard covers.** Clicks on this button, Space and Enter on it,
|
|
98
|
+
and Enter in a field when it is the form's first submit button (the default
|
|
99
|
+
one, which the browser clicks). `form.requestSubmit()` and `form.submit()`
|
|
100
|
+
fire no click, so a submit your code starts — an OTP step that submits on its
|
|
101
|
+
last digit, a keyboard shortcut — must check `formState.isSubmitting` itself.
|
|
102
|
+
With `lockOnClick`, a `loading` that never turns true releases the lock after
|
|
103
|
+
one second.
|
|
104
|
+
|
|
105
|
+
A test finds a busy button by its state, not by `disabled`:
|
|
106
|
+
`expect(button).toHaveAttribute('aria-busy', 'true')` (`toBeDisabled()` is
|
|
107
|
+
false: it is still focusable).
|
|
108
|
+
|
|
109
|
+
**Storybook:** `Buttons & actions/Button` (`Submits Once`, `Lock On Click`), `Buttons & actions/Button/Phone` · **Vue:** `Button`
|
|
62
110
|
|
|
63
111
|
---
|
|
64
112
|
|
|
@@ -179,7 +227,7 @@ import {
|
|
|
179
227
|
| --- | --- | --- | --- |
|
|
180
228
|
| `menu` | `ReactNode` | — (required) | the `DropdownMenu*` items shown by the chevron |
|
|
181
229
|
| `menuLabel` | `string` | `"More actions"` (translated) | the chevron's `aria-label` |
|
|
182
|
-
| `variant`, `color`, `loading`, `disabled` | as `Button` | — |
|
|
230
|
+
| `variant`, `color`, `loading`, `disabled` | as `Button` | — | `variant`, `color` and `disabled` apply to both halves; `loading` makes the main half busy (spinner, clicks ignored, still focusable) and disables the chevron (native `disabled`) |
|
|
183
231
|
|
|
184
232
|
Other `Button` props (`onClick`, `type`…) go to the main half.
|
|
185
233
|
|
|
@@ -191,7 +239,7 @@ Other `Button` props (`onClick`, `type`…) go to the main half.
|
|
|
191
239
|
|
|
192
240
|

|
|
193
241
|
|
|
194
|
-
Shows its label
|
|
242
|
+
Shows its label from 768 px up and collapses to icon-only below, keeping the label for screen readers. The collapse is a CSS media query, not a JS effect, so the server HTML is the same everywhere and nothing flashes.
|
|
195
243
|
|
|
196
244
|
```tsx
|
|
197
245
|
import { ResponsiveButton } from '@nxgt/material/components';
|
|
@@ -203,9 +251,10 @@ import { Plus } from 'lucide-react';
|
|
|
203
251
|
| Prop | Type | Default | Effect |
|
|
204
252
|
| --- | --- | --- | --- |
|
|
205
253
|
| `icon` | `ReactNode` | — (required) | always shown |
|
|
206
|
-
| `expanded` | `boolean` |
|
|
254
|
+
| `expanded` | `boolean` | by width (`max-md` CSS) | `true` or `false` forces the label shown, or kept as screen-reader text only, at every width |
|
|
207
255
|
|
|
208
|
-
Every `Button` prop applies.
|
|
256
|
+
Every `Button` prop applies. The label is always in the DOM, so the accessible
|
|
257
|
+
name is the same at every width; collapsed, it is
|
|
209
258
|
`sr-only` text, so the icon-only button keeps its accessible name; no
|
|
210
259
|
`aria-label` is needed. `expanded` is layout, not disclosure: the button has
|
|
211
260
|
no `aria-expanded` of its own, so it is not announced as "collapsed". Wrapped
|
|
@@ -263,7 +312,7 @@ Needs a `react-router` router above it.
|
|
|
263
312
|
|
|
264
313
|

|
|
265
314
|
|
|
266
|
-
Copies a value to the clipboard and briefly shows a check mark. `CopyValue` displays the value next to the button.
|
|
315
|
+
Copies a value to the clipboard and briefly shows a check mark (or a cross when the clipboard refuses). `CopyValue` displays the value next to the button.
|
|
267
316
|
|
|
268
317
|
```tsx
|
|
269
318
|
import { CopyButton, CopyValue } from '@nxgt/material/components';
|
|
@@ -277,12 +326,13 @@ import { CopyButton, CopyValue } from '@nxgt/material/components';
|
|
|
277
326
|
| Prop | Type | Default | Effect |
|
|
278
327
|
| --- | --- | --- | --- |
|
|
279
328
|
| `value` | `string \| (() => string)` | — (required) | what is copied; a function is read at click time |
|
|
280
|
-
| `label`
|
|
329
|
+
| `label` | `string` | `"Copy"` (translated) | the button's accessible name; it never changes after a click |
|
|
330
|
+
| `copiedLabel` / `failedLabel` | `string` | `"Copied"` / `"Copy failed"` (translated) | announced in the status region (and shown in the tooltip) once the write succeeded or failed |
|
|
281
331
|
| `icon` | `ReactNode` | a copy icon | replaces the idle icon |
|
|
282
332
|
| `variant`, `color` | as `IconButton` | `'ghost'`, `'default'` | the button style |
|
|
283
333
|
| `display` (`CopyValue`) | `ReactNode` | `value` | what is shown, when it differs from what is copied |
|
|
284
334
|
|
|
285
|
-
The
|
|
335
|
+
The write is awaited: "Copied" appears only once the clipboard accepted the text, and a refusal (no permission, an insecure page, no Clipboard API) shows "Copy failed" instead. The outcome is announced through a visually hidden `role="status"` (polite) region rendered next to the button, not by renaming the button: `getByRole('button', { name: 'Copy' })` keeps matching, and a test reads the outcome with `within(button.parentElement!).getByRole('status')` (a bare `getByRole('status')` is ambiguous: every `CopyButton` renders a `status` region, and so do `Banner`, `DataTable` and the skeletons). The result stays for 1.5 s.
|
|
286
336
|
|
|
287
337
|
**Storybook:** `Buttons & actions/CopyButton` · **Vue:** `CopyButton`, `CopyValue`
|
|
288
338
|
|
|
@@ -446,6 +496,6 @@ import { I18nProvider } from '@nxgt/material/i18n';
|
|
|
446
496
|
| --- | --- | --- | --- |
|
|
447
497
|
| `languages` | `Language[]` | the provider's `supportedLanguages` | which languages the menu lists |
|
|
448
498
|
|
|
449
|
-
Disabled when no `I18nProvider` is mounted. See the [i18n guide](../guides/i18n.md).
|
|
499
|
+
Its menu is non-modal (see [DropdownMenu](overlays-and-menus.md#dropdownmenu)). Disabled when no `I18nProvider` is mounted. See the [i18n guide](../guides/i18n.md).
|
|
450
500
|
|
|
451
501
|
**Storybook:** `Buttons & actions/LanguageSwitcher` · **Vue:** `LanguageSwitcher`
|
|
@@ -308,7 +308,9 @@ import { Description } from '@nxgt/material/components';
|
|
|
308
308
|
```
|
|
309
309
|
|
|
310
310
|
`label` and `value` are its only props; the rest go to the `div`. A falsy
|
|
311
|
-
`value` renders nothing, so optional fields need no guard.
|
|
311
|
+
`value` renders nothing, so optional fields need no guard. The label is a small
|
|
312
|
+
muted caption above the value (not a title). `Description` takes one cell of
|
|
313
|
+
the grid it is in; pass `className="col-start-full"` for a full-width row.
|
|
312
314
|
|
|
313
315
|
**Storybook:** `Data display/Description` · **Vue:** `Description`
|
|
314
316
|
|
|
@@ -358,12 +360,32 @@ import { ListTile } from '@nxgt/material/components';
|
|
|
358
360
|
| Prop | Type | Default | Effect |
|
|
359
361
|
| --- | --- | --- | --- |
|
|
360
362
|
| `href` | `string` | — | renders an `<a>` |
|
|
363
|
+
| `linkComponent` | `AppShellLinkComponent` | plain `<a>` | the link element, as in the app shell: takes `href`, spreads every other prop, forwards `ref` |
|
|
361
364
|
| `onClick` | `MouseEventHandler` | — | renders a `<button>` |
|
|
362
365
|
| `selected` | `boolean` | `false` | highlighted row |
|
|
363
366
|
| `size` | `'sm' \| 'md'` | `'md'` | `sm` is the dense navigation row |
|
|
364
367
|
| `leading`, `trailing`, `subtitle` | `ReactNode` | — | slots |
|
|
365
368
|
| `disabled` | `boolean` | — | disables the link or button |
|
|
366
369
|
|
|
370
|
+
With a router, pass `linkComponent` so a click navigates on the client instead of reloading the page (React Router's `Link` takes `to`, so wrap it):
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
import { Link } from 'react-router';
|
|
374
|
+
import type { AppShellLinkComponent } from '@nxgt/material/components';
|
|
375
|
+
import { ListTile } from '@nxgt/material/components';
|
|
376
|
+
|
|
377
|
+
// Hoisted: one component, not a new one on every render.
|
|
378
|
+
const RouterLink: AppShellLinkComponent = ({ href, ...props }) => <Link to={href} {...props} />;
|
|
379
|
+
|
|
380
|
+
export function SettingsLink() {
|
|
381
|
+
return <ListTile title="Notifications" href="/settings/notifications" linkComponent={RouterLink} />;
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
See also [A `ListTile` link reloads the whole page](../troubleshooting.md#a-listtile-link-reloads-the-whole-page). A disabled tile never renders the link component: it is a plain `<a>` without `href`, with `aria-disabled="true"`.
|
|
386
|
+
|
|
387
|
+
The root carries `data-slot="item-detail"` (a tile that is a button or a plain row too).
|
|
388
|
+
|
|
367
389
|
**Storybook:** `Data display/ListTile` · **Vue:** `ListTile`
|
|
368
390
|
|
|
369
391
|
---
|
|
@@ -457,7 +479,7 @@ import { EventChip } from '@nxgt/material/components';
|
|
|
457
479
|
|
|
458
480
|

|
|
459
481
|
|
|
460
|
-
Highlighted code with line numbers and copy, a Monaco diff, a collapsible JSON tree, and tabbed samples (`Tabs
|
|
482
|
+
Highlighted code with line numbers and copy, a Monaco diff, a collapsible JSON tree, and tabbed samples (`Tabs`, underlined).
|
|
461
483
|
|
|
462
484
|
<img src="../previews/data-display-codegroup.webp" height="96" alt="CodeGroup">
|
|
463
485
|
<img src="../previews/data-display-jsonviewer.webp" height="96" alt="JsonViewer">
|
|
@@ -23,7 +23,7 @@ each other, so either can be used alone.
|
|
|
23
23
|
|
|
24
24
|

|
|
25
25
|
|
|
26
|
-
TanStack Table v9 with sorting, filtering, selection, expandable rows, pagination or load-more, column visibility, skeleton rows while loading and your own empty state — or one server page at a time, with controlled sorting and selection, cursor Previous / Next links and row links.
|
|
26
|
+
TanStack Table v9 with sorting, filtering, selection, expandable rows, pagination or load-more, column visibility, skeleton rows while loading and your own empty state — or one server page at a time, with controlled sorting and selection, cursor Previous / Next links and row links. On a phone it keeps its header row and scrolls sideways in a keyboard-reachable region; the page does not.
|
|
27
27
|
|
|
28
28
|
```tsx
|
|
29
29
|
import {
|
|
@@ -72,14 +72,16 @@ table enables, for typing your own column defs.
|
|
|
72
72
|
| `actions` | `(table) => ReactNode` | — | toolbar content with access to the table (selected rows…) |
|
|
73
73
|
| `onLoadMore` / `isLoadingMore` | `() => void` / `boolean` | — | adds a "load more" button under the rows |
|
|
74
74
|
| `options` | `{ showPage?: boolean; showSelected?: boolean }` | both `true` | parts of the footer |
|
|
75
|
-
| `showHeader` | `boolean` |
|
|
75
|
+
| `showHeader` | `boolean` | shown | header row (column names, sorting, "Select all") at every width; `false` hides it |
|
|
76
|
+
| `maxHeight` | `number \| string` | none | caps the table's height (`400`, `'60vh'`); the rows scroll inside it |
|
|
77
|
+
| `scrollLabel` | `string` | "Scrollable table" | the name of the scroll region the table becomes while it overflows |
|
|
76
78
|
| `loading` | `boolean` | `false` | skeleton rows, or the current rows dimmed; `aria-busy`; controls disabled |
|
|
77
79
|
| `loadingRows` | `number` | the page size | how many skeleton rows |
|
|
78
80
|
| `empty` | `ReactNode \| ({ filtered }) => ReactNode` | icon and "No data available" | content of the empty row, spanning every visible column |
|
|
79
81
|
| `manual` | `boolean` | `false` | `data` is one server page: no client filtering, sorting or paging; the footer is the server footer ([server-side data](#server-side-data)) |
|
|
80
|
-
| `sorting` / `onSortingChange` | `SortingState` / `(sorting) => void` | held inside | controlled sorting; the callback gets the new state, not an updater |
|
|
82
|
+
| `sorting` / `onSortingChange` | `SortingState` / `(sorting) => void` | held inside | controlled sorting; the callback gets the new state, not an updater, and is not called for an update that resolves to the current value |
|
|
81
83
|
| `getRowId` | `(row, index) => string` | the index | the row's id, the key of `rowSelection` |
|
|
82
|
-
| `rowSelection` / `onRowSelectionChange` | `RowSelectionState` / `(selection) => void` | held inside | controlled selection, by id; may hold rows of other pages |
|
|
84
|
+
| `rowSelection` / `onRowSelectionChange` | `RowSelectionState` / `(selection) => void` | held inside | controlled selection, by id; may hold rows of other pages; the callback is not called for an update that resolves to the current value |
|
|
83
85
|
| `pagination` | `{ totalCount?, offset?, previous?, next? }` | — | the server footer's range ("41–60 of 133") and Previous / Next: an href (a link) or a callback (a button) |
|
|
84
86
|
| `footer` | `false \| (table) => ReactNode` | the pagination | replaces the footer, or removes it |
|
|
85
87
|
| `getRowHref` | `(row) => string \| undefined` | — | the first data cell links to the row's page; a click elsewhere on the row follows it |
|
|
@@ -138,6 +140,69 @@ default, or your own content, told whether rows exist but none matches the
|
|
|
138
140
|
filters (`filtered`); content that renders nothing gets the default.
|
|
139
141
|
`DataTableEmpty` and `DataTableEmptyState` type the prop and its argument.
|
|
140
142
|
|
|
143
|
+
### Phones and narrow screens
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// The rows scroll inside 60% of the viewport; the page scrolls otherwise.
|
|
147
|
+
<DataTable
|
|
148
|
+
data={invoices}
|
|
149
|
+
columns={columns}
|
|
150
|
+
maxHeight="60vh"
|
|
151
|
+
scrollLabel="Invoices"
|
|
152
|
+
/>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The table is as tall as its rows, and the page scrolls: there is no height
|
|
156
|
+
cap unless you pass `maxHeight`, so a phone never gets a scroll inside the
|
|
157
|
+
page's. The header row shows at every width (`showHeader` `false` hides it).
|
|
158
|
+
With `maxHeight`, the rows scroll under the header row, which stays in view
|
|
159
|
+
on an opaque background.
|
|
160
|
+
|
|
161
|
+
When the columns are wider than the table, the table scrolls sideways in
|
|
162
|
+
one box (`[data-slot="table-wrapper"]`), and the page does not. While it
|
|
163
|
+
overflows, that box is a `region` named "Scrollable table"
|
|
164
|
+
(`material.table.labels.scroll-region`, or `scrollLabel`) with
|
|
165
|
+
`tabindex="0"`, so a keyboard user can reach it and scroll it with the arrow
|
|
166
|
+
keys, and an edge fades on each side where columns are hidden
|
|
167
|
+
(`data-scroll-start` / `data-scroll-end` on its parent,
|
|
168
|
+
`[data-slot="table-scroll"]`). It is not a region while it fits, nor on the
|
|
169
|
+
server; once focused, it stays a tab stop until focus leaves, even if it
|
|
170
|
+
stops overflowing. The empty state is centred in the part of the table you
|
|
171
|
+
can see (the box's measured width, `--table-visible-width`), not across its
|
|
172
|
+
whole scroll width. The table needs no width from its parent: inside a
|
|
173
|
+
content-sized one (`w-fit`, `inline-flex`, an `auto` grid track, a popover)
|
|
174
|
+
it is as wide as its columns.
|
|
175
|
+
|
|
176
|
+
The `select` column's checkboxes keep their 16px box, with a 24px target
|
|
177
|
+
around it (WCAG 2.5.8). The toolbar renders only when it has content:
|
|
178
|
+
`actions` that render nothing (`null`, `false`, whitespace, an empty
|
|
179
|
+
fragment) leave no empty `<fieldset>` behind.
|
|
180
|
+
|
|
181
|
+
Selection actions do not move the rows. With `actions` and the `select`
|
|
182
|
+
column (`predefinedColumns().select`, id `select`), the toolbar's height is
|
|
183
|
+
reserved — an empty, hidden placeholder
|
|
184
|
+
(`[data-slot="header-placeholder"]`) while `actions` render nothing, the
|
|
185
|
+
same minimum height once they do — so the "Delete selected" that appears on
|
|
186
|
+
the first selection does not push the tapped row down. The reserved height
|
|
187
|
+
is one row of default-size buttons (`h-9`); taller or wrapping actions still
|
|
188
|
+
grow the toolbar.
|
|
189
|
+
|
|
190
|
+
```tsx
|
|
191
|
+
<DataTable
|
|
192
|
+
data={people}
|
|
193
|
+
columns={[select, ...columns]}
|
|
194
|
+
actions={(table) =>
|
|
195
|
+
table.getSelectedRowModel().rows.length > 0 && (
|
|
196
|
+
<Button onClick={handleDelete(table.getSelectedRowModel().rows)}>
|
|
197
|
+
Delete selected
|
|
198
|
+
</Button>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
/>
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Rows stay rows on a phone; a card layout is not built in.
|
|
205
|
+
|
|
141
206
|
### Server-side data
|
|
142
207
|
|
|
143
208
|
When the server filters, sorts and pages, hand the table **one page** and
|
|
@@ -249,12 +314,22 @@ export default function Students() {
|
|
|
249
314
|
index of the page's first row) make the range: "41–60 of 133"
|
|
250
315
|
(`material.table.pagination.range`), "41–60" without a total, "133 rows"
|
|
251
316
|
without an offset. Cursor paging knows the offset from the trail's length
|
|
252
|
-
times the page size; leave it out if pages can be short.
|
|
317
|
+
times the page size; leave it out if pages can be short. The range is a
|
|
318
|
+
polite live region (`role="status"`, `aria-atomic="true"`, named "Rows
|
|
319
|
+
shown" by `material.table.pagination.range-label`) that is in the DOM from
|
|
320
|
+
the first render whenever `pagination` is given, so a screen reader
|
|
321
|
+
announces "41–60 of 133" when the page changes. With neither `offset` nor
|
|
322
|
+
`totalCount` the region is empty, and is kept in the DOM so a later change
|
|
323
|
+
is still announced. The table already has a visually hidden status for
|
|
324
|
+
"Loading data…" (and the page may have a toast region), so a test finds the
|
|
325
|
+
range with `getByRole('status', { name: 'Rows shown' })`, not a bare
|
|
326
|
+
`getByRole('status')`.
|
|
253
327
|
- **Sorting** is controlled: the headers show `sorting`, and
|
|
254
328
|
`onSortingChange` receives the new `SortingState` (not TanStack's updater)
|
|
255
|
-
for you to put in the URL
|
|
256
|
-
|
|
257
|
-
|
|
329
|
+
for you to put in the URL (neither it nor `onRowSelectionChange` is called
|
|
330
|
+
for an update that resolves to the current value). Filters work the same
|
|
331
|
+
way: render them in `actions` and keep their values in the URL; `manual`
|
|
332
|
+
turns client filtering off.
|
|
258
333
|
- **Selection** is keyed by `getRowId`, so it survives a page change: ids
|
|
259
334
|
of other pages stay in `rowSelection`, and the footer counts them all
|
|
260
335
|
("3 rows selected", `material.table.pagination.selected`). `actions(table)`
|
|
@@ -271,7 +346,10 @@ export default function Students() {
|
|
|
271
346
|
navigation (opening a sheet). Alone, it makes the row focusable and Enter
|
|
272
347
|
calls it; with `getRowHref`, the link stays the keyboard target, and
|
|
273
348
|
calling `event.preventDefault()` in it stops a mouse click from following
|
|
274
|
-
the link.
|
|
349
|
+
the link. The row itself is never a second control: with `getRowHref` it
|
|
350
|
+
has no role, no `tabindex` and no `aria-label`, and the one link is named
|
|
351
|
+
by the cell's text, so `getByRole('link', { name: 'Ada', exact: true })`
|
|
352
|
+
is unique. A focusable row has no role of its own: for anything a screen
|
|
275
353
|
reader user must reach, prefer `getRowHref` or a button in a cell.
|
|
276
354
|
- **Your own footer.** `footer={(table) => …}` replaces the footer —
|
|
277
355
|
`<DataTableServerFooter table={table} pagination={…} />` is the default
|
|
@@ -280,7 +358,7 @@ export default function Students() {
|
|
|
280
358
|
navigation is pending, and the current rows stay in place, dimmed.
|
|
281
359
|
|
|
282
360
|
The server footer's strings are `material.table.pagination.*`
|
|
283
|
-
(`previous`, `next`, `label`, `range`, `range-open`, `total`, `selected`),
|
|
361
|
+
(`previous`, `next`, `label`, `range`, `range-open`, `range-label`, `total`, `selected`),
|
|
284
362
|
in English and French.
|
|
285
363
|
|
|
286
364
|
For the TanStack API itself (column helpers, features, row models), see
|
|
@@ -46,6 +46,30 @@ month label opens the year view.
|
|
|
46
46
|
| `startMonth`, `endMonth` | `Date` | — | navigation bounds |
|
|
47
47
|
| `captionLayout` | `'label' \| 'dropdown' \| …` | `'label'` | caption as text or month / year dropdowns |
|
|
48
48
|
| `showOutsideDays` | `boolean` | `true` | days of the adjacent months |
|
|
49
|
+
| `locale` | `Locale` (react-day-picker) | `I18nProvider` language, else `en` | month and weekday names, the heading, and the language of the day names |
|
|
50
|
+
|
|
51
|
+
**Day names.** Every day is named by its full date in the calendar's language
|
|
52
|
+
(`locale`, else the active `I18nProvider` language, else English): "Thursday,
|
|
53
|
+
October 1, 2026", "jeudi 1 octobre 2026". The name is on the button and, for
|
|
54
|
+
Testing Library, on the `gridcell` around it; "Today" and "selected" are not in
|
|
55
|
+
it. The chosen day has `aria-selected="true"` on its cell and its button is
|
|
56
|
+
described by "Selected" (`material.calendar.selected`, translated); today has
|
|
57
|
+
`aria-current="date"` on both. The days of the neighbouring months
|
|
58
|
+
(`showOutsideDays`) are named by their own dates, so a number alone matches no
|
|
59
|
+
day. "Selected" comes from the `Root` of the default `Calendar`: replacing
|
|
60
|
+
`components.Root` drops it. Pass `labels={{ labelDayButton }}` to override the
|
|
61
|
+
name on both:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
await page.getByRole('gridcell', { name: 'Thursday, October 1, 2026', exact: true }).getByRole('button').click();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Weekday row.** It follows the same language: "Su", "Mo"… in English, "lu",
|
|
68
|
+
"ma"… under a French `I18nProvider`, with the week starting on the locale's
|
|
69
|
+
first day (Monday in French). Each header is labelled by its full weekday
|
|
70
|
+
("lundi"); react-day-picker hides the row from assistive tech
|
|
71
|
+
(`<thead aria-hidden>`), since every day's name already carries its weekday.
|
|
72
|
+
It reads at 4.5:1 or more on the popover in the light and the dark theme.
|
|
49
73
|
|
|
50
74
|
**Storybook:** `Date & time/Calendar` · **Vue:** `Calendar` (Reka parts)
|
|
51
75
|
|
|
@@ -45,6 +45,8 @@ import { CircleAlert } from 'lucide-react';
|
|
|
45
45
|
| `title` | `ReactNode` | — | bold first line |
|
|
46
46
|
| `description` | `ReactNode` | — | muted body text |
|
|
47
47
|
|
|
48
|
+
The root carries `data-slot="alert"`, the title `data-slot="alert-title"` and the description `data-slot="alert-description"`, for tests and selectors.
|
|
49
|
+
|
|
48
50
|
**Storybook:** `Feedback & status/Alert` · **Vue:** `Alert`
|
|
49
51
|
|
|
50
52
|
---
|
|
@@ -129,7 +131,9 @@ to `outlined`). Radix props (`open`, `defaultOpen`, `onOpenChange`) go on
|
|
|
129
131
|
On open, `AlertDialogContent` focuses `AlertDialogCancel`, the least
|
|
130
132
|
destructive action (its first control when there is no Cancel, the content
|
|
131
133
|
when there is none); an `onOpenAutoFocus` that calls `event.preventDefault()`
|
|
132
|
-
keeps focus
|
|
134
|
+
keeps focus off the Cancel, on the content: the page behind an alert dialog is
|
|
135
|
+
`inert` while it is open
|
|
136
|
+
([Overlays & menus](overlays-and-menus.md)).
|
|
133
137
|
It hands focus back on close as `DialogContent` does: to
|
|
134
138
|
the element that had it when it opened (the button of yours that opened a
|
|
135
139
|
controlled `AlertDialog`, too), unless focus already went elsewhere or your
|
|
@@ -219,6 +223,13 @@ const schema = z.object({ reason: z.string().min(3) });
|
|
|
219
223
|
| `iconProps` | `IconButtonProps` | — | the badge's `variant`, `color`, `className` |
|
|
220
224
|
| `confirmText` / `cancelText` | `ReactNode` | "Confirm" / "Cancel", translated (`material.confirm-dialog.confirm` / `.cancel`) | button text |
|
|
221
225
|
|
|
226
|
+
**Several steps, one dialog.** Confirm closes it; to show the next step, change
|
|
227
|
+
its `title` (and `description`) and set `open` back to `true`, at once (from
|
|
228
|
+
`onConfirm` or `onOpenChange`) or after an `await`. No `key` per step is needed:
|
|
229
|
+
the reopened overlay stays under the content, even while the previous one is
|
|
230
|
+
still fading out, so the dialog's buttons take the click. The same holds for
|
|
231
|
+
`ConfirmDialog`, `Dialog`, `AlertDialog` and `Sheet`.
|
|
232
|
+
|
|
222
233
|

|
|
223
234
|
|
|
224
235
|
`CustomAlertDialog` is the alert-dialog twin of [CustomDialog](#customdialog):
|
|
@@ -415,15 +426,81 @@ toasts.dismiss(id);
|
|
|
415
426
|
| --- | --- | --- | --- |
|
|
416
427
|
| `title` / `description` | `ReactNode` | preset title for `success`, `error`, `loading` | toast text |
|
|
417
428
|
| `icon` | `ReactNode` (`toast`) · icon name (`toasts.custom`) | preset icon | leading icon |
|
|
418
|
-
| `action` | `ToastAction`: `{ label, onClick? }` or `(dismiss) => ReactNode` | a translated “Close” for `success`, `info`, `error
|
|
419
|
-
| `
|
|
429
|
+
| `action` | `ToastAction`: `{ label, onClick? }` or `(dismiss) => ReactNode` | a translated “Close” for `success`, `info`, `error`; a preset keeps the caller's own | trailing button: `onClick`, then the toast closes; or what the function renders, given `dismiss`. Brings the X button and a persistent toast, see below |
|
|
430
|
+
| `dismissLabel` | `string` | the translated “Close” when an `action` is given | accessible name of the X icon button beside the action; `''` hides it |
|
|
431
|
+
| `role` | `'status' \| 'alert'` | none (`toasts.error`: `'alert'`) | live-region role. Toasts are already announced politely by the `Toaster`'s region; `alert` interrupts, and may be read twice by some screen readers |
|
|
432
|
+
| `options` | Sonner `ExternalToast` | `duration: 5000` for presets, `Infinity` for `loading` and for any toast with your own `action` (a preset's fallback "Close" still times out at 5000) unless a `duration` is passed | passed to Sonner (`id`, `duration`, `position`…) |
|
|
420
433
|
|
|
421
434
|
The toast id defaults to the title, so two toasts with the same title
|
|
422
|
-
replace each other; pass `options: { id }` to show both. `Toaster`
|
|
423
|
-
and takes its props (`position`, `expand`, `richColors`…)
|
|
424
|
-
|
|
435
|
+
replace each other; pass `options: { id }` to show both. `Toaster` wraps
|
|
436
|
+
Sonner's and takes its props (`position`, `expand`, `richColors`…), all
|
|
437
|
+
forwarded; mount the one from `@nxgt/material/components`, not Sonner's own,
|
|
438
|
+
or neither phone change below applies. `Toast` is the component each toast
|
|
439
|
+
renders, for use with `sonnerToast.custom`.
|
|
440
|
+
|
|
441
|
+
**Types:** `ToastAction`, `ToastProps`, `ToastMethodProps`, `ToasterProps`.
|
|
442
|
+
|
|
443
|
+
**On a phone** (under 600px wide, where Sonner lays toasts out across the
|
|
444
|
+
screen), a `Toaster` with no `position` shows its toasts at the top
|
|
445
|
+
(`top-center`): across the bottom they covered what a form keeps there, its
|
|
446
|
+
submit button first. A `position` you pass applies on every screen. The server
|
|
447
|
+
and the hydrating client render the desktop default (`bottom-right`), and a
|
|
448
|
+
phone moves the toasts to the top once hydrated. The phone offset is Sonner's
|
|
449
|
+
`mobileOffset` (16px by default); raise its `top` when a sticky header must
|
|
450
|
+
stay visible: `<Toaster mobileOffset={{ top: 72 }} />`.
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
<Toaster /> // bottom-right on a desktop, top-center on a phone
|
|
454
|
+
<Toaster position="bottom-center" /> // bottom-center everywhere
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**An action keeps the toast open.** `toast()` itself does it, so a preset and a
|
|
458
|
+
direct call behave alike: any toast with an `action` is persistent by default
|
|
459
|
+
(`options.duration: Infinity`, WCAG 2.2.1: a timed toast can vanish before a
|
|
460
|
+
keyboard or screen-reader user reaches its button) unless you pass
|
|
461
|
+
`options.duration`, and shows a small close (X) icon button beside the action,
|
|
462
|
+
named by `material.toast.buttons.close` ("Close" / "Fermer") unless you pass
|
|
463
|
+
your own `dismissLabel` (`''` hides it). The presets keep the `action` you pass
|
|
464
|
+
(`toasts.info({ description: 'A new version is available', action: { label:
|
|
465
|
+
'Reload', onClick } })`); without an `action`, the preset's text "Close" button
|
|
466
|
+
is unchanged, on a timed toast. Sonner pauses its timer while a mouse hovers a
|
|
467
|
+
toast, while a finger is down on it and while the page is hidden, but not on
|
|
468
|
+
keyboard focus, which is why the default is persistent. A tap does not hover:
|
|
469
|
+
the mouse a browser emulates after a tap (which never leaves until the next tap
|
|
470
|
+
elsewhere) is ignored, so a tapped toast still goes after its duration. On a
|
|
471
|
+
touch screen a tap no longer fans out a stack of two or more toasts either: pass
|
|
472
|
+
`expand` to keep the stack open. Sonner does not close a toast on Escape (it
|
|
473
|
+
only collapses the stack); this `Toast` does when focus is inside it, with or
|
|
474
|
+
without an action. The close button is reached with Tab. **Focus after a
|
|
475
|
+
dismiss:** the dismissed toast leaves the page with the focused control in it,
|
|
476
|
+
so focus falls back to `document.body`; move it yourself (`onClick`, or after
|
|
477
|
+
`toasts.dismiss()`) when the flow needs it elsewhere.
|
|
478
|
+
|
|
479
|
+
**Announced to screen readers:** `Toaster` renders a polite live region
|
|
480
|
+
(`<section aria-live="polite">`) that is in the page before the first toast,
|
|
481
|
+
so every toast inserted into it is read out. A toast therefore has no `role`
|
|
482
|
+
of its own: one on each toast would nest a second live region. `toasts.error`
|
|
483
|
+
is `role="alert"` (assertive), so a failure interrupts; pass `role` to
|
|
484
|
+
`toast()` or to a preset to choose another (a caller's wins). Mount `Toaster`
|
|
485
|
+
once, early, and not conditionally after the first toast. A `Toast` rendered
|
|
486
|
+
outside a `Toaster` is not in a live region: give it its own.
|
|
487
|
+
|
|
488
|
+
**In tests:** find a toast by its text within the region, and an error toast
|
|
489
|
+
by role. A `status` or `alert` takes no name from its content, so read the
|
|
490
|
+
message with `toHaveTextContent`.
|
|
491
|
+
|
|
492
|
+
```ts
|
|
493
|
+
const alert = await screen.findByRole('alert'); // toasts.error
|
|
494
|
+
expect(alert).toHaveTextContent('Save failed');
|
|
495
|
+
const saved = await screen.findByText('Item saved'); // toasts.success / info
|
|
496
|
+
expect(saved.closest('section[aria-live="polite"]')).not.toBeNull();
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Wait with `findBy*` or `waitFor`, never a fixed delay. A toast stays in the
|
|
500
|
+
DOM until it is dismissed or times out (a toast with an action never times
|
|
501
|
+
out), so queries in one test file can see the previous
|
|
502
|
+
test's toasts: call `toasts.dismiss()` first.
|
|
425
503
|
|
|
426
|
-
**Types:** `ToastAction`, `ToastProps`, `ToastMethodProps`.
|
|
427
504
|
**Storybook:** `Feedback & status/Toast` · **Vue:** `Toaster`, `toast`, `toasts`, `Toast` (`ToastAction` type)
|
|
428
505
|
|
|
429
506
|
---
|
|
@@ -475,7 +552,7 @@ import { HydrateLoading } from '@nxgt/material/components';
|
|
|
475
552
|
| --- | --- | --- | --- |
|
|
476
553
|
| `loadingIcon` | `ReactNode` | `<Spinner className="size-8" />` | replaces the spinner (`lodadingIcon`, the old misspelling, is a deprecated alias) |
|
|
477
554
|
| `children` | `ReactNode` | — | shown above the spinner |
|
|
478
|
-
| `className` | `string` | — | the root fills the viewport (`
|
|
555
|
+
| `className` | `string` | — | the root fills the viewport (`w-lvw h-lvh`); override to box it |
|
|
479
556
|
|
|
480
557
|
**Storybook:** `Feedback & status/HydrateLoading` · **Vue:** `HydrateLoading`
|
|
481
558
|
|
|
@@ -348,7 +348,7 @@ import { SearchField } from '@nxgt/material/components';
|
|
|
348
348
|
|
|
349
349
|
| Prop | Type | Default | Effect |
|
|
350
350
|
| --- | --- | --- | --- |
|
|
351
|
-
| `onValueChange` | `(value: string) => void` | — | the text, debounced when `debounceMs` is set |
|
|
351
|
+
| `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 |
|
|
352
352
|
| `debounceMs` | `number` | `0` | delay before `onValueChange`; `0` calls it on every key |
|
|
353
353
|
| `loading` | `boolean` | `false` | spinner in place of the clear button |
|
|
354
354
|
| `onChange` | native handler | — | still fires on every key, undebounced |
|
|
@@ -410,8 +410,8 @@ export function Code() {
|
|
|
410
410
|
| `length` | `number` | `6` | number of slots, split in two groups |
|
|
411
411
|
| `value` / `onChange` | `string` / `(value: string) => void` | — | from `input-otp` |
|
|
412
412
|
| `onComplete` | `(value: string) => void` | — | once every slot is filled |
|
|
413
|
-
| `error` | `boolean` | — | error colour on the slots |
|
|
414
|
-
| `id` | `string` | from `useId()` | the input's id, which the label points to; the generated one is the same on the server and the client |
|
|
413
|
+
| `error` | `boolean` | — | error colour on the slots (`data-invalid` on each); `aria-invalid` goes on the input only, the one element a screen reader reads |
|
|
414
|
+
| `id` | `string` | from `useId()` | the input's id, which the label points to; the generated one is the same on the server and the client, and differs per field — `OtpFormField` too (not the field `name`), so two code forms on one page each keep their name |
|
|
415
415
|
|
|
416
416
|
`InputOTP`, `InputOTPGroup`, `InputOTPSlot` and `InputOTPSeparator` are the
|
|
417
417
|
parts `OtpField` is built from (`input-otp`), for a layout of your own — no
|
|
@@ -444,10 +444,19 @@ export function Pin() {
|
|
|
444
444
|
`index` it shows; `InputOTPSeparator` is a `separator` with a dash, or your
|
|
445
445
|
children.
|
|
446
446
|
|
|
447
|
+
**On a phone.** The slots are 44 px squares that shrink with a narrow
|
|
448
|
+
field, kept square: six fit a 320 px-wide card, each above the 24 px
|
|
449
|
+
target of WCAG 2.5.8, and the gaps between them narrow under the `sm`
|
|
450
|
+
breakpoint. A slot you build yourself with `InputOTPSlot` does the same.
|
|
451
|
+
|
|
452
|
+
**In a test**, find the code by its input — `getByLabelText('Enter OTP')` —
|
|
453
|
+
and an error by `toHaveAttribute('aria-invalid', 'true')` on it; a slot
|
|
454
|
+
carries `data-invalid`, not `aria-invalid`.
|
|
455
|
+
|
|
447
456
|
**Emits:** `string` (the digits typed so far).
|
|
448
457
|
**Form wrapper:** `OtpFormField` — `control` and `name`, see
|
|
449
458
|
[forms](../guides/forms.md#the-pair) and [what each field emits](../guides/forms.md#what-each-field-emits).
|
|
450
|
-
**Storybook:** `Form fields/OtpField` · **Vue:** `OtpField`, `OtpFormField`, `InputOTP` (same parts)
|
|
459
|
+
**Storybook:** `Form fields/OtpField`, `Form fields/OtpField/Phone` · **Vue:** `OtpField`, `OtpFormField`, `InputOTP` (same parts)
|
|
451
460
|
|
|
452
461
|
---
|
|
453
462
|
|
|
@@ -693,7 +702,7 @@ switch, Email me when an order ships" and `getByRole('switch', { name:
|
|
|
693
702
|
wins. The `helperText` (the validation message, under `SwitchFormField`)
|
|
694
703
|
describes the switch too, and an `aria-describedby` you pass is kept beside
|
|
695
704
|
these. With `required`, the switch has `aria-required` and the label's asterisk
|
|
696
|
-
is
|
|
705
|
+
is drawn by CSS, so the name and the label text stay "Terms", not "Terms*".
|
|
697
706
|
Without an `id` one is generated, under `SwitchFormField` too (it used to be
|
|
698
707
|
the field's `name`, which two forms on one page shared). The row is tinted
|
|
699
708
|
while the switch is on, from `checked` or, uncontrolled, from `defaultChecked` and each toggle, and carries
|
|
@@ -689,6 +689,13 @@ Playback uses the browser's `<video>` / `<audio>`: a format the browser cannot
|
|
|
689
689
|
decode (H.264 MP4 in a Chromium build without proprietary codecs) shows the
|
|
690
690
|
player's error state with a Retry button. The preview is the audio story.
|
|
691
691
|
|
|
692
|
+
The speed and captions menus are radio groups: each entry is a
|
|
693
|
+
`menuitemradio` and the chosen one `aria-checked="true"` (captions: "Off" or
|
|
694
|
+
one track's `label`). `c` toggles the captions; turned on before a language
|
|
695
|
+
was chosen, they show the current track's first caption track, which the menu
|
|
696
|
+
then checks. In a test, pick one with
|
|
697
|
+
`getByRole('menuitemradio', { name: 'English' })`.
|
|
698
|
+
|
|
692
699
|
**Storybook:** `Media & files/StxPlayer` · **Vue:** `StxPlayer` (same parts)
|
|
693
700
|
|
|
694
701
|
---
|