@nxgt/material-vue 0.29.1 → 0.30.1
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 +45 -0
- package/dist/{HoverCardTrigger-Ci1iT9-I.js → HoverCardTrigger-BTAHE6wK.js} +10 -1
- package/dist/{camera-BFnqY3CN.js → camera-l87FB3uW.js} +1 -1
- package/dist/components/ui/primitives/label/label.css +14 -21
- package/dist/{components-kGJbzQYZ.js → components-DSl6EpOS.js} +6824 -6806
- package/dist/components.js +2 -2
- package/dist/{form-scope-DHnmoR2r.js → form-scope-BTUGjQdY.js} +1 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-toolbar.d.ts +14 -9
- package/dist/lib/components/ui/dates/calendar/calendar-weekday.d.ts +4 -0
- 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/main.js +2 -2
- package/dist/map.js +1 -1
- package/dist/material-vue.css +1 -1
- package/dist/{pdf-outline-sidebar-Bll123U-.js → pdf-outline-sidebar-DQ6BCQhR.js} +1 -1
- package/dist/{pdf-page-DEi2b6dz.js → pdf-page-cuvGDdM2.js} +1 -1
- package/dist/{pdf-page-list-eQ0uLV6i.js → pdf-page-list-B94WdjV4.js} +2 -2
- package/dist/{pdf-reader-CWQbdM31.js → pdf-reader-CEkr3KzC.js} +6 -6
- package/dist/{pdf-sidebar-Dv2PY_bB.js → pdf-sidebar-DJf--6rP.js} +2 -2
- package/dist/{pdf-thumbnail-sidebar-3RBdIUuk.js → pdf-thumbnail-sidebar-JLWNyl-p.js} +2 -2
- package/dist/{pdf-toolbar-Z5YML7a-.js → pdf-toolbar-B_MDicKL.js} +1 -1
- package/dist/{stx-player-DVTFb2Oe.js → stx-player-DWy055hI.js} +1 -1
- package/docs/components/data-table-filter-and-lists.md +15 -6
- package/docs/components/date-and-time.md +6 -1
- package/docs/components/feedback-and-status.md +17 -2
- package/docs/components/primitives.md +7 -6
- 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 +76 -38
- package/docs/troubleshooting.md +97 -6
- package/lib/components/ui/primitives/label/label.css +14 -21
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
2
|
import { t } from "./utils-CykWQ0iJ.js";
|
|
3
|
-
import { Ef as n } from "./components-
|
|
3
|
+
import { Ef as n } from "./components-DSl6EpOS.js";
|
|
4
4
|
import { t as r } from "./use-material-translation-Do6ztdtV.js";
|
|
5
5
|
import { Fragment as i, computed as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, defineComponent as u, normalizeClass as d, normalizeStyle as f, openBlock as p, ref as m, renderList as h, toDisplayString as g, unref as _, withCtx as v } from "vue";
|
|
6
6
|
//#region lib/components/ui/media/pdf-viewer/partials/pdf-outline-row.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./utils-CykWQ0iJ.js";
|
|
2
|
-
import { kp as t } from "./components-
|
|
2
|
+
import { kp as t } from "./components-DSl6EpOS.js";
|
|
3
3
|
import { computed as n, createBlock as r, createCommentVNode as i, createElementBlock as a, createElementVNode as o, defineComponent as s, nextTick as c, normalizeClass as l, normalizeStyle as u, onBeforeUnmount as d, openBlock as f, ref as p, shallowRef as m, unref as h, watch as g } from "vue";
|
|
4
4
|
import { DEFAULT_PAGE_SIZE as _, escapeHtml as v, findTextMatches as y, highlightItemHtml as b, placeholderSize as x, rotatedSize as S } from "@nxgt/material-core/pdf-viewer";
|
|
5
5
|
//#region lib/components/ui/media/pdf-viewer/pdf-note-icons.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
|
-
import { Ef as t } from "./components-
|
|
3
|
-
import { t as n } from "./pdf-page-
|
|
2
|
+
import { Ef as t } from "./components-DSl6EpOS.js";
|
|
3
|
+
import { t as n } from "./pdf-page-cuvGDdM2.js";
|
|
4
4
|
import { Fragment as r, createBlock as i, createElementBlock as a, createElementVNode as o, defineComponent as s, openBlock as c, renderList as l, withCtx as u } from "vue";
|
|
5
5
|
//#region lib/components/ui/media/pdf-viewer/partials/pdf-page-list.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var d = { class: "flex flex-col items-center gap-4 px-4 py-4" }, f = /*@__PURE__*/ s({
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as e } from "./utils-CykWQ0iJ.js";
|
|
2
|
-
import { On as t } from "./components-
|
|
2
|
+
import { On as t } from "./components-DSl6EpOS.js";
|
|
3
3
|
import { t as n } from "./use-material-translation-Do6ztdtV.js";
|
|
4
4
|
import { t as r } from "./Button-CNbJT5qV.js";
|
|
5
|
-
import { o as i } from "./HoverCardTrigger-
|
|
6
|
-
import { n as a } from "./pdf-page-
|
|
7
|
-
import { t as o } from "./pdf-page-list-
|
|
8
|
-
import { t as s } from "./pdf-sidebar-
|
|
9
|
-
import { t as c } from "./pdf-toolbar-
|
|
5
|
+
import { o as i } from "./HoverCardTrigger-BTAHE6wK.js";
|
|
6
|
+
import { n as a } from "./pdf-page-cuvGDdM2.js";
|
|
7
|
+
import { t as o } from "./pdf-page-list-B94WdjV4.js";
|
|
8
|
+
import { t as s } from "./pdf-sidebar-DJf--6rP.js";
|
|
9
|
+
import { t as c } from "./pdf-toolbar-B_MDicKL.js";
|
|
10
10
|
import { computed as l, createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, nextTick as _, normalizeClass as v, onBeforeUnmount as y, onMounted as b, openBlock as x, reactive as S, ref as C, shallowRef as w, toDisplayString as T, toRef as E, unref as D, useId as O, watch as k, withCtx as A } from "vue";
|
|
11
11
|
import { AlertCircle as j, FileX2 as M, KeyRound as N, Loader2 as P } from "@lucide/vue";
|
|
12
12
|
import { pdfSourceKey as F, toPdfjsParams as I } from "@nxgt/material-core/pdf-source";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
2
|
import { t } from "./utils-CykWQ0iJ.js";
|
|
3
3
|
import { t as n } from "./use-material-translation-Do6ztdtV.js";
|
|
4
|
-
import { t as r } from "./pdf-outline-sidebar-
|
|
5
|
-
import { t as i } from "./pdf-thumbnail-sidebar-
|
|
4
|
+
import { t as r } from "./pdf-outline-sidebar-DQ6BCQhR.js";
|
|
5
|
+
import { t as i } from "./pdf-thumbnail-sidebar-JLWNyl-p.js";
|
|
6
6
|
import { createElementBlock as a, createElementVNode as o, createVNode as s, defineComponent as c, normalizeClass as l, openBlock as u, toDisplayString as d, unref as f, useId as p, useTemplateRef as m } from "vue";
|
|
7
7
|
//#region lib/components/ui/media/pdf-viewer/partials/pdf-sidebar.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var h = ["aria-label"], g = ["aria-label"], _ = [
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
2
|
import { t } from "./utils-CykWQ0iJ.js";
|
|
3
|
-
import { Ef as n } from "./components-
|
|
3
|
+
import { Ef as n } from "./components-DSl6EpOS.js";
|
|
4
4
|
import { t as r } from "./use-material-translation-Do6ztdtV.js";
|
|
5
|
-
import { t as i } from "./pdf-page-
|
|
5
|
+
import { t as i } from "./pdf-page-cuvGDdM2.js";
|
|
6
6
|
import { Fragment as a, createCommentVNode as o, createElementBlock as s, createElementVNode as c, createVNode as l, defineComponent as u, normalizeClass as d, openBlock as f, renderList as p, toDisplayString as m, unref as h, withCtx as g } from "vue";
|
|
7
7
|
//#region lib/components/ui/media/pdf-viewer/partials/pdf-thumbnail-sidebar.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var _ = ["aria-label"], v = {
|
|
@@ -4,7 +4,7 @@ import { t as n } from "./use-material-translation-Do6ztdtV.js";
|
|
|
4
4
|
import { d as r } from "./Button-CNbJT5qV.js";
|
|
5
5
|
import { t as i } from "./icon-button-DXXjxBgr.js";
|
|
6
6
|
import { a, i as o, n as s, o as c, r as l, t as u } from "./DropdownMenuTrigger-BsuyNVzV.js";
|
|
7
|
-
import { o as d } from "./HoverCardTrigger-
|
|
7
|
+
import { o as d } from "./HoverCardTrigger-BTAHE6wK.js";
|
|
8
8
|
import { Fragment as f, computed as p, createBlock as m, createCommentVNode as h, createElementBlock as g, createElementVNode as _, createTextVNode as v, createVNode as y, defineComponent as b, nextTick as x, normalizeClass as S, openBlock as C, ref as w, renderList as T, toDisplayString as E, unref as D, useTemplateRef as O, watch as k, withCtx as A } from "vue";
|
|
9
9
|
import { ChevronDown as j, ChevronLeft as M, ChevronRight as N, ChevronUp as P, Download as F, Maximize2 as I, Minimize2 as L, Moon as R, Printer as z, RotateCw as B, Search as V, Sidebar as H, ZoomIn as U, ZoomOut as W } from "@lucide/vue";
|
|
10
10
|
//#region lib/components/ui/media/pdf-viewer/partials/pdf-toolbar-search.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as e } from "./utils-CykWQ0iJ.js";
|
|
2
|
-
import { $t as t, Jt as n, Mp as r, Qt as i, Yt as a, Zt as o, en as s, qt as c } from "./components-
|
|
2
|
+
import { $t as t, Jt as n, Mp as r, Qt as i, Yt as a, Zt as o, en as s, qt as c } from "./components-DSl6EpOS.js";
|
|
3
3
|
import { t as l } from "./use-material-translation-Do6ztdtV.js";
|
|
4
4
|
import { createBlock as u, createCommentVNode as d, createElementBlock as f, createElementVNode as p, createTextVNode as m, createVNode as h, defineComponent as g, normalizeClass as _, openBlock as v, toDisplayString as y, unref as b, withCtx as x } from "vue";
|
|
5
5
|
//#region lib/components/ui/media/stx-player/partials/stx-player-frame.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -175,23 +175,32 @@ keys, and an edge fades on each side where columns are hidden
|
|
|
175
175
|
server; once focused, it stays a tab stop until focus leaves, even if it
|
|
176
176
|
stops overflowing. The empty state is centred in the part of the table you
|
|
177
177
|
can see (the box's measured width, `--table-visible-width`), not across its
|
|
178
|
-
whole scroll width
|
|
178
|
+
whole scroll width: a wide `#empty` slot stays inside the box on a 375px
|
|
179
|
+
phone. The table needs no width from its parent: inside a
|
|
179
180
|
content-sized one (`w-fit`, `inline-flex`, an `auto` grid track, a popover)
|
|
180
181
|
it is as wide as its columns.
|
|
181
182
|
|
|
182
183
|
The `select` column's checkboxes keep their 16px box, with a 24px target
|
|
183
|
-
around it (WCAG 2.5.8)
|
|
184
|
-
the
|
|
185
|
-
|
|
184
|
+
around it (WCAG 2.5.8), and a 12px margin after it: axe's `target-size`
|
|
185
|
+
measures the box itself, so a 24px circle around it stays clear of the next
|
|
186
|
+
column's control — "Select all" beside a `DataTableColumnHeader` sort button
|
|
187
|
+
included.
|
|
188
|
+
|
|
189
|
+
The toolbar renders only when it has content: the `actions` prop or the
|
|
190
|
+
`#actions` slot that render nothing (`null`, `false`, `''`, whitespace, a
|
|
191
|
+
`v-if` left out, an empty fragment or array) leave no empty `<fieldset>`
|
|
192
|
+
behind. A component of yours that renders nothing still counts as content:
|
|
193
|
+
put the `v-if` on it instead.
|
|
186
194
|
|
|
187
195
|
Selection actions do not move the rows. With `actions` or the `#actions`
|
|
188
196
|
slot and the `select` column (`predefinedColumns().select`, id `select`),
|
|
189
|
-
the toolbar's height is reserved — an empty, hidden placeholder
|
|
197
|
+
the toolbar's height (68px) is reserved — an empty, hidden placeholder
|
|
190
198
|
(`[data-slot="header-placeholder"]`) while they render nothing, the same
|
|
191
199
|
minimum height once they do — so the "Delete selected" that appears on the
|
|
192
200
|
first selection does not push the tapped row down. The reserved height is
|
|
193
201
|
one row of default-size buttons (`h-9`); taller or wrapping actions still
|
|
194
|
-
grow the toolbar.
|
|
202
|
+
grow the toolbar. Without the `select` column, or without actions, no band
|
|
203
|
+
is kept above the table.
|
|
195
204
|
|
|
196
205
|
```vue
|
|
197
206
|
<template>
|
|
@@ -83,7 +83,12 @@ await page.getByRole('gridcell', { name: 'Thursday, October 1, 2026', exact: tru
|
|
|
83
83
|
first day (Monday in French). Each header is labelled by its full weekday
|
|
84
84
|
("lundi"), as in `@nxgt/material`; reka hides the row from assistive tech
|
|
85
85
|
(`<thead aria-hidden>`), since every day's name already carries its weekday.
|
|
86
|
-
It reads at 4.5:1 or more on
|
|
86
|
+
It reads at 4.5:1 or more on its tinted header (`th`, `bg-primary/15`), on the
|
|
87
|
+
page and in a popover, in the light and the dark theme.
|
|
88
|
+
|
|
89
|
+
**Contrast.** The days of the neighbouring months are muted but not faded:
|
|
90
|
+
they can be picked, so they read at 4.5:1 or more, on a tinted week too
|
|
91
|
+
(`Date & time/Calendar` → Contrast measures them all).
|
|
87
92
|
|
|
88
93
|
No form wrapper — use `DateFormField`.
|
|
89
94
|
**Storybook:** `Date & time/Calendar` · **React:** `Calendar`, `CalendarDayButton`
|
|
@@ -96,8 +96,17 @@ const open = ref(true);
|
|
|
96
96
|
| `dismissible` | `boolean` | `false` | shows a close button that emits `dismiss`; the banner does not hide itself |
|
|
97
97
|
|
|
98
98
|
Where React shows the close button when `onDismiss` is passed, Vue asks for
|
|
99
|
-
`dismissible` and `@dismiss`.
|
|
100
|
-
|
|
99
|
+
`dismissible` and `@dismiss`. It stays mounted until you stop rendering it.
|
|
100
|
+
|
|
101
|
+
**Announced:** every tone, `error` included, is a polite live region:
|
|
102
|
+
`role="status"` `aria-live="polite"` `aria-atomic="true"`. A change of its
|
|
103
|
+
text is read out, and a modal layer keeps it reachable when it makes the page
|
|
104
|
+
`inert`; a `Banner` mounted later inside a part of the page made inert stays
|
|
105
|
+
inert until the layer closes. Behind the layer, a screen reader's browse mode
|
|
106
|
+
still reaches its action and dismiss button. For an urgent banner, pass
|
|
107
|
+
`role="alert"` (and `aria-live="assertive"`): the
|
|
108
|
+
attributes you pass (`id`, `data-*`, `aria-*`, `role`) fall through to its
|
|
109
|
+
root and win over these.
|
|
101
110
|
|
|
102
111
|
**Emits:** `dismiss` — no payload.
|
|
103
112
|
**Storybook:** `Feedback & status/Banner` · **React:** `Banner`
|
|
@@ -643,6 +652,12 @@ touch screen a tap no longer fans out a stack of two or more toasts either: pass
|
|
|
643
652
|
only collapses the stack); this `Toast` does when focus is inside it, with or
|
|
644
653
|
without an action. The close button is reached with Tab.
|
|
645
654
|
|
|
655
|
+
**The action's colours.** The toast is the inverse of the page (dark in the
|
|
656
|
+
light theme, light in the dark one), so its `{ label }` action takes the other
|
|
657
|
+
theme's primary tone, on an opaque mix of primary toward the toast, and reads
|
|
658
|
+
at 4.5:1 or more in both themes (WCAG 1.4.3). A function action's own buttons
|
|
659
|
+
keep the page's tones: give them colours measured on the toast.
|
|
660
|
+
|
|
646
661
|
**Focus after an action.** A click on a toast's action first gives the focus
|
|
647
662
|
back to the control that had it before the focus entered the toast, then runs
|
|
648
663
|
your `onClick`, then closes the toast; a function action's `dismiss` does the
|
|
@@ -248,19 +248,20 @@ import { Input, Label } from '@nxgt/material-vue/components';
|
|
|
248
248
|
|
|
249
249
|
| Prop | Type | Default | Effect |
|
|
250
250
|
| --- | --- | --- | --- |
|
|
251
|
-
| `with-asterisk` | `boolean` | — | draws a red `*`
|
|
251
|
+
| `with-asterisk` | `boolean` | — | draws a red `*` after the label, an `aria-hidden` SVG, so it is in neither the label's text nor its accessible name (`getByLabel('Email', { exact: true })` and `getByLabelText` match "Email"): mark the field itself `required` (or `aria-required`), which every field of this library does for you |
|
|
252
252
|
| `for` | `string` | — | the control it labels; clicking the label focuses it |
|
|
253
253
|
|
|
254
254
|
Fields on the [Form fields](form-fields.md) page render it for you through
|
|
255
255
|
their `label` prop.
|
|
256
256
|
|
|
257
|
-
To restyle the mark, target `[data-slot="label-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
To restyle the mark, target `[data-slot="label-required-mark"]`: `color` sets
|
|
258
|
+
its colour (default `var(--color-error)`), `width` and `height` its size. It
|
|
259
|
+
stays visible in forced-colors mode and in print, and it loads no image, so a
|
|
260
|
+
Content-Security-Policy whose `img-src` refuses `data:` draws it too.
|
|
260
261
|
|
|
261
262
|
```css
|
|
262
|
-
[data-slot="label-
|
|
263
|
-
|
|
263
|
+
[data-slot="label-required-mark"] {
|
|
264
|
+
color: #b45309;
|
|
264
265
|
width: 0.75em;
|
|
265
266
|
height: 0.75em;
|
|
266
267
|
}
|
package/docs/guides/app-shell.md
CHANGED
|
@@ -251,7 +251,8 @@ button ("Open menu") that opens the same entries in a sheet. Breadcrumbs are
|
|
|
251
251
|
hidden there. The sheet is a dialog named "Navigation"
|
|
252
252
|
(`material.app-shell.navigation`) with a visible "Close" button. Following an
|
|
253
253
|
entry closes it — so does any route change, Back included — and focus goes to
|
|
254
|
-
the page's `<main
|
|
254
|
+
the page's `<main>`, unless the new screen already focused an element inside it
|
|
255
|
+
(an error page's `h1`), which keeps it; closed with Escape, the close button or the overlay,
|
|
255
256
|
focus returns to the menu button. Its entries show their labels, so they have
|
|
256
257
|
no tooltip: none opens over the first entry as focus moves in.
|
|
257
258
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
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` slot and `empty` prop still replace it), `PdfReader`, `CommandEmpty`,
|
|
15
|
+
the gallery, the kanban board, chat and the partials. Ships in
|
|
16
|
+
`@nxgt/material-vue` 1.0, with the rest of the 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-vue` 1.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 the Vue library no longer needs react. One data API,
|
|
35
|
+
`definePdfDocument`, everywhere; the HTML `Print*` blocks stay for
|
|
36
|
+
`window.print()`. Output is tagged for accessibility (PDF/UA), archival
|
|
37
|
+
(PDF/A-3) and electronic invoicing (Factur-X, EN 16931). It also brings the
|
|
38
|
+
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
|
- **Print blocks that paginate on paper** — the HTML `Print*` blocks repeat
|
|
14
64
|
their table header on every printed page, keep rows and totals whole, print
|
|
15
65
|
their colours, and a `PrintPage` sets size and margins for `window.print()`.
|
|
@@ -19,6 +69,11 @@ Nothing in progress right now; see Next.
|
|
|
19
69
|
|
|
20
70
|
## Later
|
|
21
71
|
|
|
72
|
+
- **Next major: an error `Banner` interrupts** — `tone="error"` becomes
|
|
73
|
+
`role="alert"` `aria-live="assertive"`, so a screen reader reads it out at
|
|
74
|
+
once. Every tone is `role="status"` `aria-live="polite"` today; pass
|
|
75
|
+
`role="alert"` for an urgent banner until then. Breaking for a test that
|
|
76
|
+
finds an error `Banner` with `getByRole('status')`.
|
|
22
77
|
- **Next major: `ListTile`'s `data-slot` becomes `list-tile`** — it is
|
|
23
78
|
`item-detail` today, so the name matches the component like every other
|
|
24
79
|
slot. Breaking for a selector or a test that looks for `item-detail`.
|
|
@@ -38,23 +93,6 @@ Nothing in progress right now; see Next.
|
|
|
38
93
|
- **Ready-made documents** — invoice, quote, receipt, report, certificate and
|
|
39
94
|
label-sheet templates that take your data and return a document, their labels
|
|
40
95
|
translated.
|
|
41
|
-
- **Your brand on the page** — a print theme whose defaults follow the screen
|
|
42
|
-
theme, and your own font files registered in one call — the library bundles
|
|
43
|
-
no fonts.
|
|
44
|
-
- **QR codes, barcodes and charts in a PDF** — pass the value or the chart
|
|
45
|
-
options and get vector output, no data URL to prepare.
|
|
46
|
-
- **Rich text and Markdown in a PDF** — the rich-text editor's content and
|
|
47
|
-
Markdown rendered as PDF headings, paragraphs, lists, tables and links.
|
|
48
|
-
- **A live preview inside `PdfReader`** — `PdfReader` renders a document
|
|
49
|
-
itself and refreshes it a moment after its data stops changing. Today
|
|
50
|
-
`usePdf` plus `<PdfReader :file="blob">` covers a manual preview.
|
|
51
|
-
- **Test helpers for generated PDFs** — read a generated PDF's text, page count
|
|
52
|
-
and metadata in a unit test, without a browser.
|
|
53
|
-
- **Archive-ready PDFs** — PDF/A output through one option, for invoices and
|
|
54
|
-
records that must be kept.
|
|
55
|
-
- **Electronic invoices (Factur-X)** — an invoice PDF that carries its
|
|
56
|
-
machine-readable data, built on archive-ready PDFs and the invoice template,
|
|
57
|
-
for e-invoicing mandates such as France's.
|
|
58
96
|
|
|
59
97
|
## Not planned
|
|
60
98
|
|
|
@@ -85,13 +123,14 @@ Nothing in progress right now; see Next.
|
|
|
85
123
|
- **An app shell that builds its own menu** — `items` stays a prop and labels
|
|
86
124
|
stay already-translated, because each app filters its menu by its own
|
|
87
125
|
permissions and translates in its own namespace.
|
|
88
|
-
- **Right-to-left and complex-script PDFs** —
|
|
89
|
-
|
|
90
|
-
documents with the HTML `Print*` blocks and
|
|
91
|
-
`window.print()`, or Playwright or Gotenberg on a
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
and
|
|
126
|
+
- **Right-to-left and complex-script PDFs** — pdfkit does not lay out
|
|
127
|
+
right-to-left text or shape Arabic and Hebrew reliably, so the new engine
|
|
128
|
+
does not promise it. Render such documents with the HTML `Print*` blocks and
|
|
129
|
+
print them with a browser: `window.print()`, or Playwright or Gotenberg on a
|
|
130
|
+
server.
|
|
131
|
+
- **Two PDF engines** — pdfkit replaces `@react-pdf/renderer`; there is no
|
|
132
|
+
Vue-native renderer, no pdfmake and no second engine beside it. One engine
|
|
133
|
+
and one document model serve both libraries, and react is no longer needed.
|
|
95
134
|
|
|
96
135
|
## Shipped
|
|
97
136
|
|
|
@@ -217,24 +256,23 @@ Nothing in progress right now; see Next.
|
|
|
217
256
|
keyboard and in fullscreen. 0.22.0.
|
|
218
257
|
([PdfReader](components/media-and-files.md#pdfreader))
|
|
219
258
|
- **Amounts and dates in your locale** — `formatAmount` and `formatDate` take a
|
|
220
|
-
locale and time zone, use each currency's own decimals (`{ fractionDigits: 2
|
|
221
|
-
keeps two) and keep a date-only value on its day; they are on
|
|
259
|
+
locale and time zone, use each currency's own decimals (`{ fractionDigits: 2
|
|
260
|
+
}` keeps two) and keep a date-only value on its day; they are on
|
|
222
261
|
`@nxgt/material-vue/lib` as in `@nxgt/material`; `useFormatters()` binds them
|
|
223
262
|
to the `I18nProvider` language and `createFormatters()` to a locale you pass,
|
|
224
263
|
so a document rendered on a server reads like the screen. 0.22.0.
|
|
225
264
|
([printing](guides/printing.md#formatamount-and-formatdate))
|
|
226
|
-
- **More built-in labels follow the language** — calendar navigation,
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
then the pagination buttons, breadcrumb names, `CommandDialog`'s
|
|
232
|
-
carousel's role description, the filter's empty state and chips,
|
|
265
|
+
- **More built-in labels follow the language** — calendar navigation, the data
|
|
266
|
+
table's selection checkboxes, filter presets and `Min`/`Max`, the spinner,
|
|
267
|
+
scroll-to-top, upload `Retry`/`Remove`, the map's `You are here`, zoom and `My
|
|
268
|
+
position` buttons, close buttons (including `DialogFooter`'s), and the
|
|
269
|
+
editor's slash menu (searchable in either language), font names and table
|
|
270
|
+
alignment; then the pagination buttons, breadcrumb names, `CommandDialog`'s
|
|
271
|
+
title, the carousel's role description, the filter's empty state and chips,
|
|
233
272
|
`MessageCard`'s "Unread", the upload field's replace button and errors, the
|
|
234
273
|
attribute options' "Add option", the editor's placeholder and emoji buttons,
|
|
235
274
|
`CircularProgress`, `StxPlayer`, `PaneLayoutPane`'s sheet title,
|
|
236
|
-
`JsonViewer`'s "Empty JSON" and `TimePicker`'s AM/PM.
|
|
237
|
-
0.22.0.
|
|
275
|
+
`JsonViewer`'s "Empty JSON" and `TimePicker`'s AM/PM. 0.22.0.
|
|
238
276
|
([i18n](guides/i18n.md#the-material-namespace))
|
|
239
277
|
- **PdfReader fixes** — downloads finish in every browser and take the file name
|
|
240
278
|
you give instead of `document.pdf`, a wrong password says so, Escape inside a
|
package/docs/troubleshooting.md
CHANGED
|
@@ -23,6 +23,7 @@ words in your error.
|
|
|
23
23
|
- [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)
|
|
24
24
|
- [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)
|
|
25
25
|
- [Dialogs, toasts or buttons no longer animate](#dialogs-toasts-or-buttons-no-longer-animate)
|
|
26
|
+
- [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)
|
|
26
27
|
- [A Button's label overflows a card on a phone](#a-buttons-label-overflows-a-card-on-a-phone)
|
|
27
28
|
- [`JsBarcode is not a function`](#jsbarcode-is-not-a-function)
|
|
28
29
|
- [A `LinkButton` selected as a `button` stops matching](#a-linkbutton-selected-as-a-button-stops-matching)
|
|
@@ -55,6 +56,8 @@ words in your error.
|
|
|
55
56
|
- [A toast never goes away after a tap](#a-toast-never-goes-away-after-a-tap)
|
|
56
57
|
- [A toast's action cannot be clicked while a dialog is open](#a-toasts-action-cannot-be-clicked-while-a-dialog-is-open)
|
|
57
58
|
- [`toasts.success(message, { action })` shows no action button](#toastssuccessmessage--action--shows-no-action-button)
|
|
59
|
+
- [An accessibility audit reports low contrast on a toast's action](#an-accessibility-audit-reports-low-contrast-on-a-toasts-action)
|
|
60
|
+
- [A `Banner` is not announced while a dialog is open](#a-banner-is-not-announced-while-a-dialog-is-open)
|
|
58
61
|
- [The focus leaves a dialog that a toast's action opened](#the-focus-leaves-a-dialog-that-a-toasts-action-opened)
|
|
59
62
|
- [A `ConfirmationDialog` reopened at once stays closed](#a-confirmationdialog-reopened-at-once-stays-closed)
|
|
60
63
|
- [The first Escape after closing a nested dialog does nothing](#the-first-escape-after-closing-a-nested-dialog-does-nothing)
|
|
@@ -62,6 +65,7 @@ words in your error.
|
|
|
62
65
|
**Navigation**
|
|
63
66
|
|
|
64
67
|
- [A `ListTile` link reloads the whole page](#a-listtile-link-reloads-the-whole-page)
|
|
68
|
+
- [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)
|
|
65
69
|
- [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)
|
|
66
70
|
- [`Tabs` look different after upgrading](#tabs-look-different-after-upgrading)
|
|
67
71
|
- [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)
|
|
@@ -129,6 +133,7 @@ words in your error.
|
|
|
129
133
|
- [Zod messages ignore the language, or your `material.zod.*` strings](#zod-messages-ignore-the-language-or-your-materialzod-strings)
|
|
130
134
|
- [A test asserting the old Zod string length text fails](#a-test-asserting-the-old-zod-string-length-text-fails)
|
|
131
135
|
- [A calendar's weekday row is in English on a French page](#a-calendars-weekday-row-is-in-english-on-a-french-page)
|
|
136
|
+
- [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)
|
|
132
137
|
|
|
133
138
|
**Runtime**
|
|
134
139
|
|
|
@@ -166,6 +171,7 @@ words in your error.
|
|
|
166
171
|
- [A `DataTable` shows its header row on a phone](#a-datatable-shows-its-header-row-on-a-phone)
|
|
167
172
|
- [A test's `getByRole('region')` finds more than one region](#a-tests-getbyroleregion-finds-more-than-one-region)
|
|
168
173
|
- [A `DataTable` toolbar is gone](#a-datatable-toolbar-is-gone)
|
|
174
|
+
- [axe reports `target-size` on a `DataTable`'s "Select all"](#axe-reports-target-size-on-a-datatables-select-all)
|
|
169
175
|
|
|
170
176
|
**PDF reader**
|
|
171
177
|
|
|
@@ -852,10 +858,9 @@ await expect(page.getByRole('combobox', { name: 'Delivery date' })).toHaveAttrib
|
|
|
852
858
|
```
|
|
853
859
|
|
|
854
860
|
Custom CSS that targeted the old `<span class="text-error">` should target
|
|
855
|
-
`[data-slot="label-
|
|
856
|
-
[Label](components/primitives.md#label). The mark is
|
|
857
|
-
|
|
858
|
-
forced-colors mode.
|
|
861
|
+
`[data-slot="label-required-mark"]` instead; the recipe is in
|
|
862
|
+
[Label](components/primitives.md#label). The mark is an `aria-hidden` SVG with
|
|
863
|
+
no text, and it stays visible in forced-colors mode.
|
|
859
864
|
|
|
860
865
|
### An accessibility audit reports low contrast on a badge, a button, a toast or a menu entry
|
|
861
866
|
|
|
@@ -934,8 +939,8 @@ is open and leaves it focusable; a control the tab order reaches inside an
|
|
|
934
939
|
reports it predates the inert background.
|
|
935
940
|
**Fix:** upgrade: the page behind a modal layer of this library is `inert`
|
|
936
941
|
as well — out of the tab order and of the accessibility tree — and the rule
|
|
937
|
-
passes. Live regions (the `Toaster`) stay reachable. Do not
|
|
938
|
-
`[aria-hidden]` or `[data-aria-hidden]` from the audit: it hides real
|
|
942
|
+
passes. Live regions (the `Toaster`, every `Banner`) stay reachable. Do not
|
|
943
|
+
exclude `[aria-hidden]` or `[data-aria-hidden]` from the audit: it hides real
|
|
939
944
|
failures. A layer of yours built on reka directly (not on these
|
|
940
945
|
components) still marks the page `aria-hidden` only; make the rest of the
|
|
941
946
|
page inert with core's `inertOthers`, which keeps live regions and counts
|
|
@@ -1164,6 +1169,42 @@ toasts.success({ title: 'Staff member restored', action: { label: 'Send an invit
|
|
|
1164
1169
|
`data` takes no `icon` (a preset draws its own) and no `cancel` (the X button
|
|
1165
1170
|
beside the action stands for it).
|
|
1166
1171
|
|
|
1172
|
+
### An accessibility audit reports low contrast on a toast's action
|
|
1173
|
+
|
|
1174
|
+
**When:** axe (or Lighthouse) reports `color-contrast` on a toast's action
|
|
1175
|
+
button (`[data-slot="toast-action"]`), the `{ label }` one: an
|
|
1176
|
+
"Undo", a "Send an invitation", or the "Close" a preset shows in its place.
|
|
1177
|
+
**Why:** the action is a `tonal` `Button`, whose tones are made for the page,
|
|
1178
|
+
and the toast is the inverse of the page (`bg-foreground`: dark in the light
|
|
1179
|
+
theme, light in the dark one). Its `primary` label on a 15 % primary tint over
|
|
1180
|
+
the toast read 2.5:1 in the light theme and 1.5:1 in the dark one.
|
|
1181
|
+
**Fix:** upgrade: the action takes the other theme's tone (the lightened
|
|
1182
|
+
primary on the dark toast, `primary` on the light one) on an opaque mix of
|
|
1183
|
+
primary toward the toast's surface, 9.4:1 and 5.5:1 at rest, and more hovered,
|
|
1184
|
+
focused or pressed. Drop an exclusion of `[data-slot="toast-action"]` from
|
|
1185
|
+
your contrast scan. A function action (`(dismiss) => h(Button, …)`) renders
|
|
1186
|
+
your own buttons, which keep the page's tones: give them colours measured on
|
|
1187
|
+
the toast, or use the `{ label, onClick }` form.
|
|
1188
|
+
|
|
1189
|
+
### A `Banner` is not announced while a dialog is open
|
|
1190
|
+
|
|
1191
|
+
**When:** a `Banner` (an update notice, a session notice) changes or shows
|
|
1192
|
+
while a `Dialog`, `Sheet` or another modal layer is open, and a screen reader
|
|
1193
|
+
says nothing.
|
|
1194
|
+
**Why:** a modal layer makes the page behind it `inert` and keeps only live
|
|
1195
|
+
regions (`[aria-live]`) reachable; a `Banner` was a `role="status"` without
|
|
1196
|
+
`aria-live`, so it went inert with the page.
|
|
1197
|
+
**Fix:** upgrade: every `Banner`, `error` included, is a polite live region
|
|
1198
|
+
(`role="status"` `aria-live="polite"` `aria-atomic="true"`), so the layer
|
|
1199
|
+
keeps it reachable. The attributes you pass (`id`, `data-*`, `aria-*`,
|
|
1200
|
+
`role`) fall through to its root and win: pass `role="alert"` for an urgent
|
|
1201
|
+
banner. Drop a `<div aria-live="polite">` wrapper kept for this. The page is
|
|
1202
|
+
made inert when the layer opens: a `Banner` mounted later inside a part of
|
|
1203
|
+
the page made inert stays inert until the layer closes, so render it before
|
|
1204
|
+
(and change its text), or keep it in a live container that is already there.
|
|
1205
|
+
A kept `Banner` stays interactive behind the layer: a screen reader's browse
|
|
1206
|
+
mode reaches its action and dismiss button (Tab stays in the layer).
|
|
1207
|
+
|
|
1167
1208
|
### The focus leaves a dialog that a toast's action opened
|
|
1168
1209
|
|
|
1169
1210
|
**When:** a toast's action opens a `Dialog` (or an `AlertDialog`, a `Sheet`,
|
|
@@ -1280,6 +1321,31 @@ export const AppLink = defineComponent({
|
|
|
1280
1321
|
<ListTile title="Notifications" href="/settings/notifications" :link-component="AppLink" />
|
|
1281
1322
|
```
|
|
1282
1323
|
|
|
1324
|
+
### After a link in the phone menu, the focus goes to `<main>`, not to the page's heading
|
|
1325
|
+
|
|
1326
|
+
**When:** on a phone, a link followed in the menu sheet of `ActivityLayout` or
|
|
1327
|
+
`AppHeader` (or a navigation while it is open) opens a screen that moves the
|
|
1328
|
+
focus to its own element as it mounts (an error page's `h1`, a step's title),
|
|
1329
|
+
and the focus ends on `<main>` instead.
|
|
1330
|
+
**Why:** as the sheet closed after a navigation, it always focused `<main>`,
|
|
1331
|
+
over what the new screen had focused.
|
|
1332
|
+
**Fix:** update `@nxgt/material-vue`. The sheet now leaves the focus where the screen put it
|
|
1333
|
+
inside `<main>`, and focuses `<main>` only when the focus is elsewhere (on the
|
|
1334
|
+
body, or still in the closing sheet). Code that gave the focus back
|
|
1335
|
+
to the screen's element after the sheet closed can go.
|
|
1336
|
+
|
|
1337
|
+
### A Content-Security-Policy reports a `data:` image on every form with a required field
|
|
1338
|
+
|
|
1339
|
+
**When:** a page with a required field (`Label` with the asterisk, or a field
|
|
1340
|
+
of this library with `required`) reports a CSP violation for a
|
|
1341
|
+
`data:image/svg+xml` image under a policy whose `img-src` refuses `data:`
|
|
1342
|
+
(`img-src 'self'`), and the red asterisk is missing.
|
|
1343
|
+
**Why:** the mark was a CSS mask whose image was a `data:` URI.
|
|
1344
|
+
**Fix:** update `@nxgt/material-vue`. The mark is now an `aria-hidden` SVG in the label's
|
|
1345
|
+
markup, which loads no image. An override of `--label-required-mark` (or a copy
|
|
1346
|
+
of the mark served by your app) can go; restyle the mark with
|
|
1347
|
+
`[data-slot="label-required-mark"]` (see [Label](components/primitives.md#label)).
|
|
1348
|
+
|
|
1283
1349
|
### The phone menu needs two Escapes to close, or a tooltip shows over it
|
|
1284
1350
|
|
|
1285
1351
|
**When:** on a phone, the menu sheet of `ActivityLayout` or `AppHeader` opens
|
|
@@ -2304,6 +2370,25 @@ z.config({ customError: zodLocaleError({ language: () => requestLanguage() }) })
|
|
|
2304
2370
|
|
|
2305
2371
|
See [helpers](guides/helpers.md#zodlocaleerror-limits).
|
|
2306
2372
|
|
|
2373
|
+
### An accessibility audit reports low contrast on a calendar's weekday row or its days
|
|
2374
|
+
|
|
2375
|
+
**When:** axe (or Lighthouse) reports `color-contrast` on the weekday row
|
|
2376
|
+
(`[data-slot="calendar-head-cell"]`, or the head cells of `DateRangeField`'s
|
|
2377
|
+
calendar) of a `Calendar`, `DateField`, `DateRangeField` or `EventCalendar`'s
|
|
2378
|
+
date picker, in the light theme, on the page or in its popover.
|
|
2379
|
+
**Why:** the base stylesheet tints every table header (`th`,
|
|
2380
|
+
`bg-primary/15`) and every other row (`bg-primary/5`), and a calendar is a
|
|
2381
|
+
table. Before this fix, the weekday row drew `--muted-foreground` on that
|
|
2382
|
+
header tint: 4.4:1.
|
|
2383
|
+
**Fix:** update. The weekday row is muted toward the foreground: 5.6:1 in
|
|
2384
|
+
the light theme, 6.2:1 in the dark one on the popover. The neighbouring
|
|
2385
|
+
months' days keep `--muted-foreground`, unfaded: 5.1:1 light and 5.6:1 dark
|
|
2386
|
+
at least, on a tinted week too. Drop an exclusion your accessibility test kept
|
|
2387
|
+
for the weekday row. If the audit still fails, your stylesheet overrides
|
|
2388
|
+
`--muted-foreground`, `--primary` or the table rules, or a `class` of your
|
|
2389
|
+
own sets the head cell back to `text-muted-foreground`; check it at 4.5:1 on
|
|
2390
|
+
`bg-primary/15` over `--popover`.
|
|
2391
|
+
|
|
2307
2392
|
### A calendar's weekday row is in English on a French page
|
|
2308
2393
|
|
|
2309
2394
|
**When:** under `<I18nProvider>` set to French, a `DateField`,
|
|
@@ -3106,6 +3191,12 @@ page.getByRole('region', { name: 'Invoices' });
|
|
|
3106
3191
|
**Why:** the toolbar is rendered only when it has content (yours, or `show-view-options`): an empty `<fieldset>` is a nameless group to a screen reader.
|
|
3107
3192
|
**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.
|
|
3108
3193
|
|
|
3194
|
+
### axe reports `target-size` on a `DataTable`'s "Select all"
|
|
3195
|
+
|
|
3196
|
+
**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.
|
|
3197
|
+
**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.
|
|
3198
|
+
**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.
|
|
3199
|
+
|
|
3109
3200
|
---
|
|
3110
3201
|
|
|
3111
3202
|
---
|
|
@@ -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
|
}
|