@nxgt/material 2.10.1 → 2.12.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 +52 -0
- package/dist/{blockDiagram-BEXU5L5S-CJLOORWK.js → blockDiagram-BEXU5L5S-CnFXw-7E.js} +1 -1
- package/dist/{chunk-3FUC2YCW-ClO5Q7A1.js → chunk-3FUC2YCW-3vMiTgTl.js} +1 -1
- package/dist/{chunk-7M6MHVWA-DsMPzivr.js → chunk-7M6MHVWA-NPaJJ6Gy.js} +1 -1
- package/dist/{chunk-GNY47TPC-CFItyjGy.js → chunk-GNY47TPC-DCFqYc_z.js} +4 -4
- package/dist/{chunk-NETBCI7D-Bll4gy0a.js → chunk-NETBCI7D-BB4rjLSQ.js} +1 -1
- package/dist/{chunk-Z7XXMR3K-CwcuZpJa.js → chunk-Z7XXMR3K-vmLFt9Cr.js} +1 -1
- package/dist/{classDiagram-v2-NBCMYWYE-BAvo2puZ.js → classDiagram-v2-NBCMYWYE-eUVWeh_6.js} +2 -2
- package/dist/components/ui/primitives/label/label.css +14 -21
- package/dist/{components-N_PpCQjB.js → components-BYxsGbyO.js} +23364 -23345
- package/dist/components.js +2 -2
- package/dist/{dagre-6A5THRUB-C70bzAEw.js → dagre-6A5THRUB-LmEtEC93.js} +3 -3
- package/dist/{diagram-22UHCM2B-BtBii6xG.js → diagram-22UHCM2B-BwARaM-x.js} +2 -2
- package/dist/{diagram-3UASUU5V-DMDUtIe2.js → diagram-3UASUU5V-BkeqK_e8.js} +1 -1
- package/dist/{elk-276RUBZZ-D2kPrlDF.js → elk-276RUBZZ-DL4pxCSP.js} +3 -3
- package/dist/{erDiagram-OPXOYQCR-CItUoDJi.js → erDiagram-OPXOYQCR-Ajlj2lcb.js} +2 -2
- package/dist/{field-blur-DbgP3nv0.js → field-blur-DgfIJceK.js} +909 -890
- package/dist/{flowDiagram-KWPJA3E3-BF73zGqG.js → flowDiagram-KWPJA3E3-BOEc9KSn.js} +3 -3
- package/dist/{ganttDiagram-FUAMR5RP-DWnIg8g9.js → ganttDiagram-FUAMR5RP-DdxLcLNx.js} +1 -1
- package/dist/{journeyDiagram-ZHPQQLJL-C1G4q1sS.js → journeyDiagram-ZHPQQLJL-BIzB9BVn.js} +1 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-empty-row.d.ts +3 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-toolbar.d.ts +10 -6
- package/dist/lib/components/ui/collections/data-table/select-checkbox.d.ts +5 -2
- package/dist/lib/components/ui/dates/calendar/calendar-classes.d.ts +45 -0
- package/dist/lib/components/ui/dates/calendar/calendar-weekday.d.ts +4 -0
- package/dist/lib/components/ui/feedback/banner/banner.d.ts +9 -4
- package/dist/lib/components/ui/feedback/toast/toast-classes.d.ts +13 -0
- package/dist/lib/components/ui/layout/app-shell/use-navigation-sheet.d.ts +3 -2
- package/dist/lib/components/ui/selection/select-chip-field/select-chip-field.d.ts +8 -3
- package/dist/main.js +2 -2
- package/dist/map.js +1 -1
- package/dist/material.css +1 -1
- package/dist/{mermaid.core-C74WUE6C.js → mermaid.core-6yWyNdZa.js} +21 -21
- package/dist/{mindmap-definition-NLK3R4M7-CFOfIsM7.js → mindmap-definition-NLK3R4M7-aHycauO9.js} +2 -2
- package/dist/{pieDiagram-5QR66LMP-B26Y_url.js → pieDiagram-5QR66LMP-DEiooyQu.js} +1 -1
- package/dist/{quadrantDiagram-O4NWA36T-vIoMpSWW.js → quadrantDiagram-O4NWA36T-CLlaqEdw.js} +1 -1
- package/dist/{requirementDiagram-PLB6GJNP-CL3H5GL7.js → requirementDiagram-PLB6GJNP-DD74Pa6_.js} +2 -2
- package/dist/{sankeyDiagram-IPEJSGJF-Wksiclao.js → sankeyDiagram-IPEJSGJF-DAR9G0yC.js} +1 -1
- package/dist/{stateDiagram-v2-GCMORJYK-oLPhH1yQ.js → stateDiagram-v2-GCMORJYK-pti7a_r-.js} +2 -2
- package/dist/{swimlanes-2SLR337P-C6I2boWI.js → swimlanes-2SLR337P-D10pSc8m.js} +3 -3
- package/dist/{swimlanesDiagram-TC7HE7FX-zAPI0RjB.js → swimlanesDiagram-TC7HE7FX-B8HgZod5.js} +3 -3
- package/dist/{timeline-definition-EJHVYXUP-Dpsxn1Fj.js → timeline-definition-EJHVYXUP-D8CWcNj3.js} +1 -1
- package/dist/{usecaseDiagram-POWQR4AR-DLZ1ULxe.js → usecaseDiagram-POWQR4AR-DIdH4Oia.js} +2 -2
- package/dist/{xychartDiagram-PMCCYNJV-HJtnH7o5.js → xychartDiagram-PMCCYNJV-aecZdRhd.js} +1 -1
- package/docs/components/data-table-filter-and-lists.md +16 -8
- package/docs/components/date-and-time.md +8 -1
- package/docs/components/feedback-and-status.md +17 -1
- package/docs/components/primitives.md +7 -6
- package/docs/components/selection-and-choice.md +2 -0
- package/docs/guides/app-shell.md +2 -1
- package/docs/previews/date-time-calendar.webp +0 -0
- package/docs/previews/date-time-datefield.webp +0 -0
- package/docs/previews/date-time-daterangefield.webp +0 -0
- package/docs/previews/feedback-status-toast.webp +0 -0
- package/docs/roadmap.md +90 -47
- package/docs/troubleshooting.md +129 -6
- package/lib/components/ui/primitives/label/label.css +14 -21
- package/package.json +2 -2
package/docs/roadmap.md
CHANGED
|
@@ -1,15 +1,65 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
3
|
What is being worked on, what is likely to follow, and what has been decided
|
|
4
|
-
against. This is a direction, not a commitment:
|
|
5
|
-
|
|
4
|
+
against. This is a direction, not a commitment: shipped entries carry the
|
|
5
|
+
version they shipped in, and planned entries may name the major they target.
|
|
6
6
|
|
|
7
7
|
## Now
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **Empty and error states that look designed** — `EmptyState` and a new
|
|
10
|
+
`ErrorState` in three sizes (`default`, `compact`, `inline`), with in-house
|
|
11
|
+
inline SVG illustrations or a slot for your own. `ErrorState` is a
|
|
12
|
+
`role="alert"` with a Retry action and collapsible technical details. Every
|
|
13
|
+
built-in empty or error state uses them — the `DataTable` default (your
|
|
14
|
+
`empty` prop still replaces it), `PdfReader`, `CommandEmpty`, the gallery, the
|
|
15
|
+
kanban board and chat. Ships in `@nxgt/material` 3.0, with the rest of the
|
|
16
|
+
redesign.
|
|
10
17
|
|
|
11
18
|
## Next
|
|
12
19
|
|
|
20
|
+
- **One media player, video and audio** — `MediaPlayer`, `MediaPlayerMini`,
|
|
21
|
+
`useMediaPlayer` and `AudioPlayer`, built on the native `<video>` / `<audio>`.
|
|
22
|
+
`StxPlayer` and `VideoPlayer` are removed in `@nxgt/material` 3.0, with a
|
|
23
|
+
migration guide. It plays streams — native HLS, plus `hls.js` with a quality
|
|
24
|
+
menu when you install it (an optional peer, loaded only when a stream needs
|
|
25
|
+
it) — shows chapters and a transcript that follows the playback, a waveform
|
|
26
|
+
for audio, thumbnails on hover (VTT sprites), resumes where the viewer left
|
|
27
|
+
off, and adds gestures, shuffle, a shortcut-help panel and a screen that stays
|
|
28
|
+
awake. It runs embedded at an aspect ratio, fullscreen, floating (a corner
|
|
29
|
+
mini player, and an audio bar that persists across pages) or in a modal
|
|
30
|
+
lightbox. Built for WCAG 2.2 AA and selected AAA criteria: controls at 7:1,
|
|
31
|
+
captions plus a transcript, a full keyboard, screen-reader announcements,
|
|
32
|
+
`aria-valuetext` on sliders, reduced motion and forced colors.
|
|
33
|
+
- **PDFs generated without React** — a framework-free engine on pdfkit replaces
|
|
34
|
+
`@react-pdf/renderer`, so a document renders the same in React, Vue, Node, Bun
|
|
35
|
+
and the browser. One data API, `definePdfDocument`, everywhere; the `Print*`
|
|
36
|
+
JSX components are removed in `@nxgt/material` 3.0. Output is tagged for
|
|
37
|
+
accessibility (PDF/UA), archival (PDF/A-3) and electronic invoicing (Factur-X,
|
|
38
|
+
EN 16931). It also brings the items below.
|
|
39
|
+
- **Your brand on the page** — a print theme whose defaults follow the screen
|
|
40
|
+
theme, and your own font files registered in one call (the library bundles
|
|
41
|
+
no fonts).
|
|
42
|
+
- **QR codes, barcodes and charts in a PDF** — pass the value or the chart
|
|
43
|
+
options and get vector output, no data URL to prepare.
|
|
44
|
+
- **Rich text and Markdown in a PDF** — the rich-text editor's content and
|
|
45
|
+
Markdown rendered as PDF headings, paragraphs, lists, tables and links.
|
|
46
|
+
- **A live preview inside `PdfReader`** — `PdfReader` takes a document and
|
|
47
|
+
renders it itself, refreshing a moment after its data stops changing.
|
|
48
|
+
- **Test helpers for generated PDFs** — read a generated PDF's text, page count
|
|
49
|
+
and metadata in a unit test, without a browser.
|
|
50
|
+
- **Archive-ready PDFs** — PDF/A-3 output through one option, for invoices and
|
|
51
|
+
records that must be kept.
|
|
52
|
+
- **Electronic invoices (Factur-X)** — an invoice PDF that carries its
|
|
53
|
+
machine-readable data (EN 16931), built on archive-ready PDFs and the
|
|
54
|
+
invoice template, for e-invoicing mandates such as France's.
|
|
55
|
+
- **A PDF reader that annotates and fills forms** — pdf.js used directly in
|
|
56
|
+
both libraries (React drops `react-pdf`), with one `PdfReader` whose `mode`
|
|
57
|
+
is `embedded`, `dialog` or `page` and whose toolbar adapts to the width of
|
|
58
|
+
its container. Viewers add their own annotations, held as JSON in
|
|
59
|
+
`value` / `onChange` and exportable into the PDF; fill AcroForms; read two
|
|
60
|
+
pages side by side; scroll continuously or page by page; hear the text read
|
|
61
|
+
aloud; or switch to a reflowed text mode. Annotation export loads `pdf-lib`
|
|
62
|
+
only when used.
|
|
13
63
|
- **Dark-mode previews** — each component preview also shown in the dark theme,
|
|
14
64
|
so you can check contrast without running it.
|
|
15
65
|
- **Previews that cannot go stale** — a CI check that fails when a story changes
|
|
@@ -18,6 +68,11 @@ Nothing in progress right now; see Next.
|
|
|
18
68
|
|
|
19
69
|
## Later
|
|
20
70
|
|
|
71
|
+
- **Next major: an error `Banner` interrupts** — `tone="error"` becomes
|
|
72
|
+
`role="alert"` `aria-live="assertive"`, so a screen reader reads it out at
|
|
73
|
+
once. Every tone is `role="status"` `aria-live="polite"` today; pass
|
|
74
|
+
`role="alert"` for an urgent banner until then. Breaking for a test that
|
|
75
|
+
finds an error `Banner` with `getByRole('status')`.
|
|
21
76
|
- **Next major: `ListTile`'s `data-slot` becomes `list-tile`** — it is
|
|
22
77
|
`item-detail` today, so the name matches the component like every other
|
|
23
78
|
slot. Breaking for a selector or a test that looks for `item-detail`.
|
|
@@ -44,23 +99,6 @@ Nothing in progress right now; see Next.
|
|
|
44
99
|
- **Ready-made documents** — invoice, quote, receipt, report, certificate and
|
|
45
100
|
label-sheet templates that take your data and return a document, their labels
|
|
46
101
|
translated.
|
|
47
|
-
- **Your brand on the page** — a print theme whose defaults follow the screen
|
|
48
|
-
theme, and your own font files registered in one call (the library bundles
|
|
49
|
-
no fonts).
|
|
50
|
-
- **QR codes, barcodes and charts in a PDF** — pass the value or the chart
|
|
51
|
-
options and get vector output, no data URL to prepare.
|
|
52
|
-
- **Rich text and Markdown in a PDF** — the rich-text editor's content and
|
|
53
|
-
Markdown rendered as PDF headings, paragraphs, lists, tables and links.
|
|
54
|
-
- **A live preview inside `PdfReader`** — `PdfReader` takes a document and
|
|
55
|
-
renders it itself, refreshing a moment after its data stops changing. Today
|
|
56
|
-
`usePdfFile` and a `PdfReader` given its `url` make the preview by hand.
|
|
57
|
-
- **Test helpers for generated PDFs** — read a generated PDF's text, page count
|
|
58
|
-
and metadata in a unit test, without a browser.
|
|
59
|
-
- **Archive-ready PDFs** — PDF/A output through one option, for invoices and
|
|
60
|
-
records that must be kept.
|
|
61
|
-
- **Electronic invoices (Factur-X)** — an invoice PDF that carries its
|
|
62
|
-
machine-readable data, built on archive-ready PDFs and the invoice template,
|
|
63
|
-
for e-invoicing mandates such as France's.
|
|
64
102
|
|
|
65
103
|
## Not planned
|
|
66
104
|
|
|
@@ -73,13 +111,17 @@ Nothing in progress right now; see Next.
|
|
|
73
111
|
could not upgrade. Browser-only and node-only dependencies are contained in
|
|
74
112
|
this package, behind their own entry and optional peers or behind
|
|
75
113
|
`clientOnly`.
|
|
76
|
-
- **Print components back on the main entry** —
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
114
|
+
- **Print components back on the main entry** — the PDF engine reaches
|
|
115
|
+
pdfkit, which needs Node-style dependencies a server bundle should not pull
|
|
116
|
+
in on every request. The PDF engine and `definePdfDocument` stay on
|
|
117
|
+
`@nxgt/material/print`, not the main entry, with their dependencies as
|
|
118
|
+
optional peers. The `Print*` JSX components go away in 3.0.
|
|
119
|
+
- **Right-to-left and complex-script PDFs** — pdfkit does not lay out
|
|
120
|
+
right-to-left text or shape Arabic and Hebrew reliably, so the new engine
|
|
121
|
+
does not promise it. Render such a document as HTML and print it to PDF with
|
|
122
|
+
a browser on a server, such as Playwright or Gotenberg.
|
|
123
|
+
- **Two PDF engines** — pdfkit replaces `@react-pdf/renderer`; they do not
|
|
124
|
+
coexist. One engine and one document model serve both libraries.
|
|
83
125
|
- **Importing `@nxgt/material/map` without a DOM** — leaflet reads `window` as
|
|
84
126
|
it is evaluated. An SSR app renders the map client-side, behind `clientOnly`.
|
|
85
127
|
- **An app shell that builds its own menu** — `items` stays a prop and labels
|
|
@@ -159,8 +201,8 @@ Nothing in progress right now; see Next.
|
|
|
159
201
|
- **PDFs from a Next.js route handler in one line of config** —
|
|
160
202
|
`withNxgtPrint(nextConfig)` from `@nxgt/material/next` adds what `/print`
|
|
161
203
|
needs to `next.config.ts` — the library in `serverExternalPackages`, and
|
|
162
|
-
pdfkit's fonts in the `output: 'standalone'` trace wherever your package
|
|
163
|
-
installed them — merged with your own config. 2.4.0.
|
|
204
|
+
pdfkit's fonts in the `output: 'standalone'` trace wherever your package
|
|
205
|
+
manager installed them — merged with your own config. 2.4.0.
|
|
164
206
|
([printing](guides/printing.md#nextjs-serverexternalpackages-and-output-standalone))
|
|
165
207
|
- **One copy of the framework-free code, shared with `@nxgt/material-vue`** —
|
|
166
208
|
the PDF document model and renderer, the print formatters, the PDF file
|
|
@@ -178,14 +220,15 @@ Nothing in progress right now; see Next.
|
|
|
178
220
|
2.2.0. ([forms](guides/forms.md#touched-on-blur))
|
|
179
221
|
- **Accessible names, ids and focus across the catalogue** — every field is
|
|
180
222
|
named by its label and says it is required on the element a screen reader
|
|
181
|
-
lands on (the input, the picker's `combobox`, the slider thumbs, the
|
|
182
|
-
|
|
183
|
-
and describe their error instead of carrying `aria-invalid`
|
|
184
|
-
not allow it; ids are generated rather than taken from a
|
|
185
|
-
an option's `value`, so two forms on one page no longer
|
|
186
|
-
buttons, crumbs, carousel arrows, codes and the camera have
|
|
187
|
-
dialog, sheet or drawer takes focus when it opens and gives it
|
|
188
|
-
closes. 2.2.0.
|
|
223
|
+
lands on (the input, the picker's `combobox`, the slider thumbs, the group),
|
|
224
|
+
with the asterisk drawn by CSS, so in no name or label text; groups are named
|
|
225
|
+
by their question and describe their error instead of carrying `aria-invalid`
|
|
226
|
+
where ARIA does not allow it; ids are generated rather than taken from a
|
|
227
|
+
field's `name` or an option's `value`, so two forms on one page no longer
|
|
228
|
+
collide; icon buttons, crumbs, carousel arrows, codes and the camera have
|
|
229
|
+
names; and a dialog, sheet or drawer takes focus when it opens and gives it
|
|
230
|
+
back when it closes. 2.2.0.
|
|
231
|
+
([upgrading](getting-started.md#220-ids-names-and-aria-invalid-moved))
|
|
189
232
|
- **PdfReader, turned pages and a steady zoom** — a page the PDF turns
|
|
190
233
|
(`/Rotate`) shows the right way up, the fit zoom settles once when the
|
|
191
234
|
document opens instead of moving while you read, `onPageChange` also reports
|
|
@@ -197,8 +240,8 @@ Nothing in progress right now; see Next.
|
|
|
197
240
|
documents written as plain data (`pdfDocument` and its builders,
|
|
198
241
|
`definePdfDocument` templates, `dataTable` from column definitions) alongside
|
|
199
242
|
the JSX components, and `@nxgt/material-vue/pdf` (0.22.0) renders the same
|
|
200
|
-
model, so a template renders the same pages in both libraries (experimental:
|
|
201
|
-
may still change in a minor release). 2.2.0.
|
|
243
|
+
model, so a template renders the same pages in both libraries (experimental:
|
|
244
|
+
the model may still change in a minor release). 2.2.0.
|
|
202
245
|
([printing](guides/printing.md#documents-as-data))
|
|
203
246
|
- **One call to a PDF file** — `downloadPdf` and `openPdf` in the browser (a
|
|
204
247
|
blocked tab falls back to a download), `usePdfFile` for a preview that keeps
|
|
@@ -231,10 +274,10 @@ Nothing in progress right now; see Next.
|
|
|
231
274
|
its zoom menu works from the keyboard and in fullscreen. 2.2.0.
|
|
232
275
|
([PdfReader](components/media-and-files.md#pdfreader))
|
|
233
276
|
- **Amounts and dates in your locale** — `formatAmount` and `formatDate` take a
|
|
234
|
-
locale and time zone, use each currency's own decimals (`{ fractionDigits: 2
|
|
235
|
-
keeps two) and keep a date-only value on its day; `useFormatters()` binds
|
|
236
|
-
to the `I18nProvider` language and `createFormatters()` to a locale you
|
|
237
|
-
so a document rendered on a server reads like the screen. 2.2.0.
|
|
277
|
+
locale and time zone, use each currency's own decimals (`{ fractionDigits: 2
|
|
278
|
+
}` keeps two) and keep a date-only value on its day; `useFormatters()` binds
|
|
279
|
+
them to the `I18nProvider` language and `createFormatters()` to a locale you
|
|
280
|
+
pass, so a document rendered on a server reads like the screen. 2.2.0.
|
|
238
281
|
([printing](guides/printing.md#formatamount-and-formatdate))
|
|
239
282
|
- **More built-in labels follow the language** — calendar navigation,
|
|
240
283
|
the data table's selection checkboxes, filter presets and
|
|
@@ -269,10 +312,10 @@ Nothing in progress right now; see Next.
|
|
|
269
312
|
server's guess while hydrating. 2.2.0.
|
|
270
313
|
- **Declaration files that always resolve** — a packed or linked build types
|
|
271
314
|
`react` like the npm one, instead of as `any`. 2.2.0.
|
|
272
|
-
- **Component documentation with previews** — every component has an entry
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
server errors. 2.2.0.
|
|
315
|
+
- **Component documentation with previews** — every component has an entry with
|
|
316
|
+
a picture of how it renders, an example that compiles and the options that
|
|
317
|
+
matter, under the same twelve categories in the README and `docs/`. A forms
|
|
318
|
+
guide covers React Hook Form, Zod, composite values and server errors. 2.2.0.
|
|
276
319
|
- **`@nxgt/material/map`** — the leaflet map, markers, location field and
|
|
277
320
|
`useGeolocation` as an entry of this package, with leaflet as optional peers.
|
|
278
321
|
2.1.0.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -24,6 +24,7 @@ words in your error.
|
|
|
24
24
|
- [An accessibility audit reports low contrast on a tonal or outlined button, a selected list tile or a hovered badge link](#an-accessibility-audit-reports-low-contrast-on-a-tonal-or-outlined-button-a-selected-list-tile-or-a-hovered-badge-link)
|
|
25
25
|
- [An accessibility audit reports low contrast on error text in the dark theme](#an-accessibility-audit-reports-low-contrast-on-error-text-in-the-dark-theme)
|
|
26
26
|
- [Dialogs, toasts or buttons no longer animate](#dialogs-toasts-or-buttons-no-longer-animate)
|
|
27
|
+
- [A Content-Security-Policy reports a `data:` image on every form with a required field](#a-content-security-policy-reports-a-data-image-on-every-form-with-a-required-field)
|
|
27
28
|
- [A Button's label overflows a card on a phone](#a-buttons-label-overflows-a-card-on-a-phone)
|
|
28
29
|
|
|
29
30
|
**Feedback**
|
|
@@ -33,6 +34,8 @@ words in your error.
|
|
|
33
34
|
- [A toast never goes away after a tap](#a-toast-never-goes-away-after-a-tap)
|
|
34
35
|
- [A toast's action cannot be clicked while a dialog is open](#a-toasts-action-cannot-be-clicked-while-a-dialog-is-open)
|
|
35
36
|
- [`toasts.success(message, { action })` shows no action button](#toastssuccessmessage--action--shows-no-action-button)
|
|
37
|
+
- [An accessibility audit reports low contrast on a toast's action](#an-accessibility-audit-reports-low-contrast-on-a-toasts-action)
|
|
38
|
+
- [A `Banner` is not announced while a dialog is open](#a-banner-is-not-announced-while-a-dialog-is-open)
|
|
36
39
|
- [The focus leaves a dialog that a toast's action opened](#the-focus-leaves-a-dialog-that-a-toasts-action-opened)
|
|
37
40
|
- [A `ConfirmationDialog` reopened with new content blocks clicks](#a-confirmationdialog-reopened-with-new-content-blocks-clicks)
|
|
38
41
|
- [The first Escape after closing a nested dialog does nothing](#the-first-escape-after-closing-a-nested-dialog-does-nothing)
|
|
@@ -40,6 +43,7 @@ words in your error.
|
|
|
40
43
|
**Navigation**
|
|
41
44
|
|
|
42
45
|
- [A `ListTile` link reloads the whole page](#a-listtile-link-reloads-the-whole-page)
|
|
46
|
+
- [After a link in the phone menu, the focus goes to `<main>`, not to the page's heading](#after-a-link-in-the-phone-menu-the-focus-goes-to-main-not-to-the-pages-heading)
|
|
43
47
|
- [The phone menu needs two Escapes to close, or a tooltip shows over it](#the-phone-menu-needs-two-escapes-to-close-or-a-tooltip-shows-over-it)
|
|
44
48
|
- [`Tabs` look different after upgrading](#tabs-look-different-after-upgrading)
|
|
45
49
|
- [A screen reader announces an icon-only tab as "tab", with no name](#a-screen-reader-announces-an-icon-only-tab-as-tab-with-no-name)
|
|
@@ -99,6 +103,7 @@ words in your error.
|
|
|
99
103
|
- [Zod messages ignore the language, or your `material.zod.*` strings](#zod-messages-ignore-the-language-or-your-materialzod-strings)
|
|
100
104
|
- [A test asserting the old Zod string length text fails](#a-test-asserting-the-old-zod-string-length-text-fails)
|
|
101
105
|
- [A calendar's weekday row is in English on a French page](#a-calendars-weekday-row-is-in-english-on-a-french-page)
|
|
106
|
+
- [An accessibility audit reports low contrast on a calendar's weekday row or its days](#an-accessibility-audit-reports-low-contrast-on-a-calendars-weekday-row-or-its-days)
|
|
102
107
|
|
|
103
108
|
**Runtime**
|
|
104
109
|
|
|
@@ -115,6 +120,7 @@ words in your error.
|
|
|
115
120
|
- [A `TimeFormField` shows its error on a desktop but not on a phone](#a-timeformfield-shows-its-error-on-a-desktop-but-not-on-a-phone)
|
|
116
121
|
- [`setError(…, { shouldFocus: true })` or a failed submit does not focus the field](#seterror--shouldfocus-true--or-a-failed-submit-does-not-focus-the-field)
|
|
117
122
|
- [A test that finds a chip by `aria-selected` or `getByRole('option')` no longer finds it](#a-test-that-finds-a-chip-by-aria-selected-or-getbyroleoption-no-longer-finds-it)
|
|
123
|
+
- [The `ref` of a `SelectChipField` focuses nothing](#the-ref-of-a-selectchipfield-focuses-nothing)
|
|
118
124
|
- [`touchedFields` stays empty after leaving a field, or `mode: 'onBlur'` never validates](#touchedfields-stays-empty-after-leaving-a-field-or-mode-onblur-never-validates)
|
|
119
125
|
- [`TypeError: values.map is not a function` (a `SliderFormField`)](#typeerror-valuesmap-is-not-a-function)
|
|
120
126
|
- [An end-to-end test no longer finds `aria-expanded` on a `ResponsiveButton`](#an-end-to-end-test-no-longer-finds-aria-expanded-on-a-responsivebutton)
|
|
@@ -164,6 +170,8 @@ words in your error.
|
|
|
164
170
|
- [A `DataTable` shows its header row on a phone](#a-datatable-shows-its-header-row-on-a-phone)
|
|
165
171
|
- [A test's `getByRole('region')` finds more than one region](#a-tests-getbyroleregion-finds-more-than-one-region)
|
|
166
172
|
- [A `DataTable` toolbar is gone](#a-datatable-toolbar-is-gone)
|
|
173
|
+
- [axe reports `target-size` on a `DataTable`'s "Select all"](#axe-reports-target-size-on-a-datatables-select-all)
|
|
174
|
+
- [A `DataTable`'s empty state is cut off at its right edge](#a-datatables-empty-state-is-cut-off-at-its-right-edge)
|
|
167
175
|
|
|
168
176
|
**PDF reader**
|
|
169
177
|
|
|
@@ -453,8 +461,8 @@ is open and leaves it focusable; a control the tab order reaches inside an
|
|
|
453
461
|
reports it predates the inert background.
|
|
454
462
|
**Fix:** upgrade: the page behind a modal layer of this library is `inert`
|
|
455
463
|
as well — out of the tab order and of the accessibility tree — and the rule
|
|
456
|
-
passes. Live regions (the `Toaster`) stay reachable. Do not
|
|
457
|
-
`[aria-hidden]` or `[data-aria-hidden]` from the audit: it hides real
|
|
464
|
+
passes. Live regions (the `Toaster`, every `Banner`) stay reachable. Do not
|
|
465
|
+
exclude `[aria-hidden]` or `[data-aria-hidden]` from the audit: it hides real
|
|
458
466
|
failures. A layer of yours built on Radix directly (not on these
|
|
459
467
|
components) still marks the page `aria-hidden` only; make the rest of the
|
|
460
468
|
page inert with core's `inertOthers`, which keeps live regions and counts
|
|
@@ -667,6 +675,42 @@ toasts.success({ title: 'Staff member restored', action: { label: 'Send an invit
|
|
|
667
675
|
`data` takes no `icon` (a preset draws its own) and no `cancel` (the X button
|
|
668
676
|
beside the action stands for it).
|
|
669
677
|
|
|
678
|
+
### An accessibility audit reports low contrast on a toast's action
|
|
679
|
+
|
|
680
|
+
**When:** axe (or Lighthouse) reports `color-contrast` on a toast's action
|
|
681
|
+
button (`[data-slot="toast-action"]`), the `{ label }` one: an
|
|
682
|
+
"Undo", a "Send an invitation", or the "Close" a preset shows in its place.
|
|
683
|
+
**Why:** the action is a `tonal` `Button`, whose tones are made for the page,
|
|
684
|
+
and the toast is the inverse of the page (`bg-foreground`: dark in the light
|
|
685
|
+
theme, light in the dark one). Its `primary` label on a 15 % primary tint over
|
|
686
|
+
the toast read 2.5:1 in the light theme and 1.5:1 in the dark one.
|
|
687
|
+
**Fix:** upgrade: the action takes the other theme's tone (the lightened
|
|
688
|
+
primary on the dark toast, `primary` on the light one) on an opaque mix of
|
|
689
|
+
primary toward the toast's surface, 9.4:1 and 5.5:1 at rest, and more hovered,
|
|
690
|
+
focused or pressed. Drop an exclusion of `[data-slot="toast-action"]` from
|
|
691
|
+
your contrast scan. A function action (`(dismiss) => <Button …>`) renders
|
|
692
|
+
your own buttons, which keep the page's tones: give them colours measured on
|
|
693
|
+
the toast, or use the `{ label, onClick }` form.
|
|
694
|
+
|
|
695
|
+
### A `Banner` is not announced while a dialog is open
|
|
696
|
+
|
|
697
|
+
**When:** a `Banner` (an update notice, a session notice) changes or shows
|
|
698
|
+
while a `Dialog`, `Sheet` or another modal layer is open, and a screen reader
|
|
699
|
+
says nothing; or an `aria-live` you set on it is dropped.
|
|
700
|
+
**Why:** a modal layer makes the page behind it `inert` and keeps only live
|
|
701
|
+
regions (`[aria-live]`) reachable; a `Banner` was a `role="status"` without
|
|
702
|
+
`aria-live`, so it went inert with the page, and it did not forward its props.
|
|
703
|
+
**Fix:** upgrade: every `Banner`, `error` included, is a polite live region
|
|
704
|
+
(`role="status"` `aria-live="polite"` `aria-atomic="true"`), so the layer
|
|
705
|
+
keeps it reachable, and the props you pass (`id`, `data-*`, `aria-*`, `role`)
|
|
706
|
+
go to its root and win: pass `role="alert"` for an urgent banner.
|
|
707
|
+
Drop a `<div aria-live="polite">` wrapper kept for this. The page is made
|
|
708
|
+
inert when the layer opens: a `Banner` mounted later inside a part of the page
|
|
709
|
+
made inert stays inert until the layer closes, so render it before (and change
|
|
710
|
+
its text), or keep it in a live container that is already there. A kept
|
|
711
|
+
`Banner` stays interactive behind the layer: a screen reader's browse mode
|
|
712
|
+
reaches its action and dismiss button (Tab stays in the layer).
|
|
713
|
+
|
|
670
714
|
### The focus leaves a dialog that a toast's action opened
|
|
671
715
|
|
|
672
716
|
**When:** a toast's action opens a `Dialog` (or an `AlertDialog`, a `Sheet`,
|
|
@@ -791,6 +835,33 @@ const RouterLink: AppShellLinkComponent = ({ href, ...props }) => (
|
|
|
791
835
|
<ListTile title="Notifications" href="/settings/notifications" linkComponent={RouterLink} />
|
|
792
836
|
```
|
|
793
837
|
|
|
838
|
+
### After a link in the phone menu, the focus goes to `<main>`, not to the page's heading
|
|
839
|
+
|
|
840
|
+
**When:** on a phone, a link followed in the menu sheet of `ActivityLayout` or
|
|
841
|
+
`AppHeader` (or a navigation while it is open) opens a screen that moves the
|
|
842
|
+
focus to its own element as it mounts (an error page's `h1`, a step's title),
|
|
843
|
+
and the focus ends on `<main>` instead.
|
|
844
|
+
**Why:** as the sheet closed after a navigation, it always focused `<main>`,
|
|
845
|
+
over what the new screen had focused.
|
|
846
|
+
**Fix:** update `@nxgt/material`. The sheet now leaves the focus where the screen put it
|
|
847
|
+
inside `<main>`, and focuses `<main>` only when the focus is elsewhere (on the
|
|
848
|
+
body, or still in the closing sheet). A controlled modal layer (the menu
|
|
849
|
+
sheet is one) releases the page from `inert` in the same commit that closes
|
|
850
|
+
it, so the focus your screen moves as it mounts is not refused. Code that gave the focus back
|
|
851
|
+
to the screen's element after the sheet closed can go.
|
|
852
|
+
|
|
853
|
+
### A Content-Security-Policy reports a `data:` image on every form with a required field
|
|
854
|
+
|
|
855
|
+
**When:** a page with a required field (`Label` with the asterisk, or a field
|
|
856
|
+
of this library with `required`) reports a CSP violation for a
|
|
857
|
+
`data:image/svg+xml` image under a policy whose `img-src` refuses `data:`
|
|
858
|
+
(`img-src 'self'`), and the red asterisk is missing.
|
|
859
|
+
**Why:** the mark was a CSS mask whose image was a `data:` URI.
|
|
860
|
+
**Fix:** update `@nxgt/material`. The mark is now an `aria-hidden` SVG in the label's
|
|
861
|
+
markup, which loads no image. An override of `--label-required-mark` (or a copy
|
|
862
|
+
of the mark served by your app) can go; restyle the mark with
|
|
863
|
+
`[data-slot="label-required-mark"]` (see [Label](components/primitives.md#label)).
|
|
864
|
+
|
|
794
865
|
### The phone menu needs two Escapes to close, or a tooltip shows over it
|
|
795
866
|
|
|
796
867
|
**When:** on a phone, the menu sheet of `ActivityLayout` or `AppHeader` opens
|
|
@@ -1688,6 +1759,31 @@ z.config({ customError: zodLocaleError({ storageKey: 'lang', translate }) });
|
|
|
1688
1759
|
z.config({ customError: zodLocaleError({ language: () => requestLanguage() }) });
|
|
1689
1760
|
```
|
|
1690
1761
|
|
|
1762
|
+
### An accessibility audit reports low contrast on a calendar's weekday row or its days
|
|
1763
|
+
|
|
1764
|
+
**When:** axe (or Lighthouse) reports `color-contrast` on the weekday row
|
|
1765
|
+
(`th.rdp-weekday`) of a `Calendar`, `DateField`, `DateRangeField` or
|
|
1766
|
+
`EventCalendar`'s date picker, in the light theme, on the page or in its
|
|
1767
|
+
popover; or on the days of the neighbouring months (`.rdp-outside`, such as
|
|
1768
|
+
31 August on September's grid), the middle days of a range, or the chosen
|
|
1769
|
+
day.
|
|
1770
|
+
**Why:** the base stylesheet tints every table header (`th`,
|
|
1771
|
+
`bg-primary/15`) and every other row (`bg-primary/5`), and a calendar is a
|
|
1772
|
+
table. Before this fix, the weekday row drew `--muted-foreground` on that
|
|
1773
|
+
header tint (4.4:1), a range's middle days drew it on their `bg-primary/15`,
|
|
1774
|
+
and every day's label was drawn at 70% opacity: 2.9:1 for a neighbouring
|
|
1775
|
+
month's day (they can be picked, so they need 4.5:1), 2.6:1 for a range's
|
|
1776
|
+
middle day and 4.4:1 for the chosen day's near-white label.
|
|
1777
|
+
**Fix:** update. The weekday row and a range's middle days are muted toward
|
|
1778
|
+
the foreground (5.6:1 light, 6.2:1 dark on the popover), the neighbouring
|
|
1779
|
+
months' days keep `--muted-foreground` without the fade (5.1:1 light, 5.6:1
|
|
1780
|
+
dark at least) and the other days are drawn at full strength. Drop an
|
|
1781
|
+
exclusion your accessibility test kept for `.rdp-weekday` or `.rdp-outside`.
|
|
1782
|
+
If the audit still fails, your stylesheet overrides `--muted-foreground`,
|
|
1783
|
+
`--primary` or the table rules, or a `classNames` of your own sets the
|
|
1784
|
+
weekday or outside colour back to `text-muted-foreground`; check it at 4.5:1
|
|
1785
|
+
on `bg-primary/15` over `--popover`.
|
|
1786
|
+
|
|
1691
1787
|
### A calendar's weekday row is in English on a French page
|
|
1692
1788
|
|
|
1693
1789
|
**When:** under `<I18nProvider>` set to French, a `DateField`,
|
|
@@ -2057,6 +2153,22 @@ const design = within(topics).getByRole('button', { name: 'Design' });
|
|
|
2057
2153
|
expect(design).toHaveAttribute('aria-pressed', 'true');
|
|
2058
2154
|
```
|
|
2059
2155
|
|
|
2156
|
+
### The `ref` of a `SelectChipField` focuses nothing
|
|
2157
|
+
|
|
2158
|
+
**When:** `ref.current?.focus()` on a `SelectChipField`, or React Hook Form's
|
|
2159
|
+
`setFocus(name)` on a `SelectChipFormField`, leaves focus where it was, or
|
|
2160
|
+
lands on the first chip when one is chosen. Before the release that lists
|
|
2161
|
+
this fix only.
|
|
2162
|
+
**Why:** the `ref` is the `role="group"` element, which a browser cannot
|
|
2163
|
+
focus; the chips are the focusable controls.
|
|
2164
|
+
**Fix:** upgrade: the `ref` now reaches the chosen chip, else the first, as a
|
|
2165
|
+
radio group does (type `Ref<HTMLButtonElement>`). Temporary, until
|
|
2166
|
+
material #502: on an older release, focus the chip yourself.
|
|
2167
|
+
|
|
2168
|
+
```tsx
|
|
2169
|
+
group.current?.querySelector<HTMLElement>('[aria-pressed="true"], button')?.focus();
|
|
2170
|
+
```
|
|
2171
|
+
|
|
2060
2172
|
### `touchedFields` stays empty after leaving a field, or `mode: 'onBlur'` never validates
|
|
2061
2173
|
|
|
2062
2174
|
**When:** a `*FormField` keeps `formState.touchedFields` (and
|
|
@@ -2238,10 +2350,9 @@ await expect(page.getByRole('combobox', { name: 'Delivery date' })).toHaveAttrib
|
|
|
2238
2350
|
```
|
|
2239
2351
|
|
|
2240
2352
|
Custom CSS that targeted the old `<span class="text-error">` should target
|
|
2241
|
-
`[data-slot="label-
|
|
2242
|
-
[Label](components/primitives.md#label). The mark is
|
|
2243
|
-
|
|
2244
|
-
forced-colors mode.
|
|
2353
|
+
`[data-slot="label-required-mark"]` instead; the recipe is in
|
|
2354
|
+
[Label](components/primitives.md#label). The mark is an `aria-hidden` SVG with
|
|
2355
|
+
no text, and it stays visible in forced-colors mode.
|
|
2245
2356
|
|
|
2246
2357
|
### An end-to-end test no longer finds `aria-expanded` on a `ResponsiveButton`
|
|
2247
2358
|
|
|
@@ -3172,6 +3283,18 @@ page.getByRole('region', { name: 'Invoices' });
|
|
|
3172
3283
|
**Why:** the toolbar is rendered only when it has content (yours, or `showViewOptions`): an empty `<fieldset>` is a nameless group to a screen reader.
|
|
3173
3284
|
**Fix:** look for what the toolbar holds (a filter by its label, the view options by "View"), not for the `fieldset` itself. A component of yours that renders nothing still counts as content: render it conditionally instead.
|
|
3174
3285
|
|
|
3286
|
+
### axe reports `target-size` on a `DataTable`'s "Select all"
|
|
3287
|
+
|
|
3288
|
+
**When:** axe (WCAG 2.5.8) flags the header row's "Select all" checkbox (`thead [data-slot="checkbox-field"]`) when the column after the `select` column is a sortable `DataTableColumnHeader`, mostly on a phone, where the columns are narrowest. The rows' checkboxes pass.
|
|
3289
|
+
**Why:** axe measures the 16px box itself, not its 24px `::before`, so it asks for a 24px circle around the box clear of every other control. The sort button reaches 12px back into its cell's padding (`-ml-3`), and the `select` cell had no padding after its checkbox: the circle met the button.
|
|
3290
|
+
**Fix:** upgrade: the `select` column's checkboxes now keep a 12px margin after them. Drop any axe `exclude` of `thead [data-slot="checkbox-field"]` you kept for it. A `select` column of your own (not `predefinedColumns().select`) needs the same: `me-3` on its checkboxes.
|
|
3291
|
+
|
|
3292
|
+
### A `DataTable`'s empty state is cut off at its right edge
|
|
3293
|
+
|
|
3294
|
+
**When:** a custom `empty` as wide as its cell (a paragraph, a `w-full` box) on a phone: its last 4px sit under the edge of the table's scroll box, and look cut off.
|
|
3295
|
+
**Why:** the empty state was sized to the box's visible width (`--table-visible-width`) but drawn inside the table container's 4px padding, so it stuck out by that padding.
|
|
3296
|
+
**Fix:** upgrade: the empty state now takes the padding off its width and sticks 4px in from the box's edge. Nothing to change in your `empty`.
|
|
3297
|
+
|
|
3175
3298
|
---
|
|
3176
3299
|
|
|
3177
3300
|
---
|
|
@@ -1,33 +1,26 @@
|
|
|
1
|
-
/* The required mark of `Label withAsterisk
|
|
2
|
-
* label's
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* `
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/* The required mark of `Label withAsterisk`: an `aria-hidden` inline SVG in
|
|
2
|
+
* the label's markup, not a "*" in its text. A typed "*" joined the label's
|
|
3
|
+
* name ("Email *") for `getByLabel(…, { exact })`, `getByLabelText` and
|
|
4
|
+
* screen readers, and so does generated text (`content: "*"`). The field's
|
|
5
|
+
* own `required` / `aria-required` is what is announced. Drawn by the markup,
|
|
6
|
+
* it loads no image: a Content-Security-Policy whose `img-src` refuses
|
|
7
|
+
* `data:` draws it too. Restyle it from your own CSS: `color` for the colour,
|
|
8
|
+
* `width` / `height` for the size. */
|
|
9
|
+
[data-slot="label-required-mark"] {
|
|
10
10
|
display: inline-block;
|
|
11
11
|
flex: none;
|
|
12
12
|
align-self: flex-start;
|
|
13
13
|
width: 0.5em;
|
|
14
14
|
height: 0.5em;
|
|
15
15
|
margin-block-start: 0.05em;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
mask-image: var(--label-required-mark);
|
|
19
|
-
mask-size: contain;
|
|
20
|
-
mask-repeat: no-repeat;
|
|
21
|
-
mask-position: center;
|
|
22
|
-
/* A browser's print stylesheet drops backgrounds; this one is the mark. */
|
|
23
|
-
print-color-adjust: exact;
|
|
24
|
-
-webkit-print-color-adjust: exact;
|
|
16
|
+
color: var(--color-error);
|
|
17
|
+
overflow: visible;
|
|
25
18
|
}
|
|
26
19
|
|
|
27
|
-
/* Forced colours
|
|
20
|
+
/* Forced colours keep an SVG's `currentColor` stroke as authored;
|
|
28
21
|
* CanvasText keeps the mark visible on any theme. */
|
|
29
22
|
@media (forced-colors: active) {
|
|
30
|
-
[data-slot="label-
|
|
31
|
-
|
|
23
|
+
[data-slot="label-required-mark"] {
|
|
24
|
+
color: CanvasText;
|
|
32
25
|
}
|
|
33
26
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/material",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"email": "stevegires@gmail.com"
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"docs:previews": "vitest run --project previews"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@nxgt/material-core": "^0.7.
|
|
117
|
+
"@nxgt/material-core": "^0.7.1",
|
|
118
118
|
"@base-ui/react": "^1.6.0",
|
|
119
119
|
"@dnd-kit/core": "^6.3.1",
|
|
120
120
|
"@dnd-kit/sortable": "^10.0.0",
|