@nxgt/material-vue 0.38.0 → 0.40.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 +64 -0
- package/README.md +1 -0
- package/dist/{Button-5UyKA-x_.js → Button-BAIJ8YvT.js} +1 -1
- package/dist/{DropdownMenuTrigger-BsuyNVzV.js → DropdownMenuTrigger-C7uYPf_9.js} +36 -36
- package/dist/{HoverCardTrigger-CmCDiTn8.js → HoverCardTrigger-CKtL8teP.js} +122 -120
- package/dist/{camera-BWzF8sOW.js → camera-2UuZVfGS.js} +4 -4
- package/dist/components/base-content.css +64 -4
- package/dist/components/theme-tokens.css +7 -2
- package/dist/{components-B_s5oxUp.js → components-CCrK1Sbt.js} +13631 -13383
- package/dist/components.js +8 -8
- package/dist/composables.js +3 -3
- package/dist/dnd.js +1 -1
- package/dist/{form-scope-UzoU38db.js → form-scope-BLjSnqUf.js} +1 -1
- package/dist/{i18n-provider-BEvjls8b.js → i18n-provider-BpNC9SxV.js} +1 -1
- package/dist/i18n.js +4 -4
- package/dist/{icon-button-DhqJE6Ej.js → icon-button-5bl9odKW.js} +1 -1
- package/dist/in-dialog-Blhwwbyb.js +31 -0
- package/dist/lib/components/ui/collections/data-table/data-table-density.d.ts +15 -0
- package/dist/lib/components/ui/collections/data-table/data-table.stories.columns.d.ts +49 -0
- package/dist/lib/components/ui/collections/data-table/data-table.stories.template.d.ts +1 -0
- package/dist/lib/components/ui/collections/data-table/index.d.ts +1 -1
- package/dist/lib/components/ui/collections/data-table/types.d.ts +7 -0
- package/dist/lib/components/ui/collections/facet-group/facet-group-classes.d.ts +18 -0
- package/dist/lib/components/ui/collections/facet-group/facet-group.vue.d.ts +47 -0
- package/dist/lib/components/ui/collections/facet-group/index.d.ts +2 -0
- package/dist/lib/components/ui/collections/index.d.ts +1 -0
- package/dist/lib/components/ui/fields/contacts/consts.d.ts +1 -1
- package/dist/lib/components/ui/layout/sidebar/sidebar-menu-item.vue.d.ts +4 -3
- package/dist/lib/components/ui/menu-item-loading.d.ts +26 -0
- package/dist/lib/components/ui/overlays/context-menu/ContextMenuItem.vue.d.ts +4 -2
- package/dist/lib/components/ui/overlays/dialog/in-dialog.d.ts +12 -0
- package/dist/lib/components/ui/overlays/dropdown-menu/DropdownMenuItem.vue.d.ts +9 -3
- package/dist/lib/components/ui/overlays/menubar/MenubarItem.vue.d.ts +4 -2
- package/dist/lib/composables/use-hidden-input-name.d.ts +12 -0
- package/dist/lib/i18n/resources/en/en.d.ts +7 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +8 -1
- package/dist/lib/i18n/resources/fr/fr.d.ts +7 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +8 -1
- package/dist/lib/i18n/resources/resources.d.ts +14 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib/nuxt/component-names.d.ts +1 -1
- package/dist/lib.js +3 -3
- package/dist/main.js +17 -17
- package/dist/map.js +4 -4
- package/dist/material-vue.css +1 -1
- package/dist/{number.utils-Bpo9tUaJ.js → number.utils-C1eB3GDr.js} +427 -427
- package/dist/{pdf-outline-sidebar-BsePJlTi.js → pdf-outline-sidebar-BUvWHjiE.js} +2 -2
- package/dist/{pdf-page-Ct313mNF.js → pdf-page-B57B0uES.js} +1 -1
- package/dist/{pdf-page-list-JrRo2BeU.js → pdf-page-list-BHU7pW0b.js} +2 -2
- package/dist/{pdf-reader-tABBZMbZ.js → pdf-reader-CwTYGXq8.js} +8 -8
- package/dist/{pdf-sidebar-Caw9rzU-.js → pdf-sidebar-CtMy8Kw_.js} +3 -3
- package/dist/{pdf-thumbnail-sidebar-ZybLeUG7.js → pdf-thumbnail-sidebar-DS0iT3qo.js} +3 -3
- package/dist/{pdf-toolbar-BM8Sz_JN.js → pdf-toolbar-DL_vCyXG.js} +5 -5
- package/dist/pdf.js +2 -2
- package/dist/{print-format.utils-CQFIVeUA.js → print-format.utils-k5W0GBRF.js} +3 -3
- package/dist/{sortable-provider-CKkWYijj.js → sortable-provider-cYkCa6tm.js} +2 -2
- package/dist/{stored-language-CvOHC8AD.js → stored-language-DEyPmUzl.js} +16 -2
- package/dist/{stx-player-CsVKbwFk.js → stx-player-C_lPkXc6.js} +13 -13
- package/dist/{translator-k1rKIgC7.js → translator-B62GlCBp.js} +1 -1
- package/dist/{use-heading-spy-D-ipoQwl.js → use-heading-spy-T94lNeNA.js} +21 -21
- package/dist/{use-material-translation-1FdRx9I7.js → use-material-translation-DxU51--g.js} +3 -3
- package/docs/components/data-table-filter-and-lists.md +45 -1
- package/docs/components/feedback-and-status.md +7 -6
- package/docs/components/form-fields.md +1 -1
- package/docs/components/navigation-and-layout.md +6 -5
- package/docs/components/overlays-and-menus.md +3 -0
- package/docs/guides/csp.md +10 -0
- package/docs/guides/forms.md +55 -4
- package/docs/guides/i18n.md +3 -2
- package/docs/guides/ssr.md +8 -0
- package/docs/guides/theming.md +29 -6
- package/docs/previews/buttons-actions-button.webp +0 -0
- package/docs/previews/data-display-avatar.webp +0 -0
- package/docs/previews/data-display-badge.webp +0 -0
- package/docs/previews/data-display-chip.webp +0 -0
- package/docs/previews/data-display-statusindicator.webp +0 -0
- package/docs/previews/data-display-timeline.webp +0 -0
- package/docs/previews/data-table-filter-lists-facetgroup.webp +0 -0
- package/docs/previews/feedback-status-alert.webp +0 -0
- package/docs/previews/feedback-status-banner.webp +0 -0
- package/docs/previews/feedback-status-circularprogress.webp +0 -0
- package/docs/previews/feedback-status-emptystate.webp +0 -0
- package/docs/previews/feedback-status-progress.webp +0 -0
- package/docs/previews/feedback-status-spinner.webp +0 -0
- package/docs/previews/feedback-status-toast.webp +0 -0
- package/docs/previews/form-fields-passwordfield.webp +0 -0
- package/docs/previews/form-fields-ratingfield.webp +0 -0
- package/docs/roadmap.md +5 -0
- package/docs/troubleshooting.md +32 -5
- package/lib/components/base-content.css +64 -4
- package/lib/components/theme-tokens.css +7 -2
- package/lib/nuxt/component-names.ts +1 -0
- package/package.json +2 -2
- package/dist/use-inert-others-CtGqZKR8.js +0 -22
package/docs/guides/forms.md
CHANGED
|
@@ -293,6 +293,55 @@ in `[data-slot="form-actions"]`) and put each group of fields in a
|
|
|
293
293
|
fields still take a row of their own. A rule separates each section from the
|
|
294
294
|
one before it (`:separated="false"` drops it).
|
|
295
295
|
|
|
296
|
+
### One scroll, sticky actions
|
|
297
|
+
|
|
298
|
+
The form grid has no height of its own and its fields no scroll box: a long
|
|
299
|
+
form grows with the page, and the page is the one scroll. The actions
|
|
300
|
+
(`[data-slot="form-actions"]`) are sticky at the bottom of whatever scrolls
|
|
301
|
+
the form, on a translucent, blurred background, so Cancel and Save stay in
|
|
302
|
+
reach while the fields scroll under them; a form shorter than the screen
|
|
303
|
+
shows them right under its fields.
|
|
304
|
+
|
|
305
|
+
- In a `DialogContent` or a `SheetContent`, which are capped to the screen
|
|
306
|
+
and scroll themselves, the actions stick to the dialog's or the sheet's
|
|
307
|
+
bottom. A `DrawerContent` does not scroll: a form that is its direct child
|
|
308
|
+
is the scroll box there.
|
|
309
|
+
- In an `AlertDialogContent` (the rich text editor's edit dialogs use one),
|
|
310
|
+
the actions stick to its bottom the same way, over its padding.
|
|
311
|
+
- `ConfirmationDialog` holds a form when you pass it `form-options` (a schema and its `defaultValues`) and the `#form` slot: it renders the
|
|
312
|
+
fields in a `.form-grid-layout` with no `form-actions`, so its footer
|
|
313
|
+
(Cancel, Confirm) is what sticks to the dialog's bottom. Any `Dialog` or
|
|
314
|
+
`AlertDialog` whose content holds a `.form-grid-layout` without
|
|
315
|
+
`form-actions` gets the same sticky footer.
|
|
316
|
+
- A focused control or link is scrolled into view clear of the actions and
|
|
317
|
+
a line of helper text below it (`scroll-margin-bottom` on the fields'
|
|
318
|
+
controls: 6rem, plus a dialog's bottom padding, 7.5rem above a
|
|
319
|
+
`ConfirmationDialog`'s stacked footer), so a field you tab to is never
|
|
320
|
+
hidden behind them (WCAG 2.4.11). It is set on the controls, so it holds
|
|
321
|
+
in a scroll box of your own too.
|
|
322
|
+
- Taller actions (a third button, labels that wrap) or helper text on
|
|
323
|
+
several lines need more room: raise `--form-actions-clearance` on the
|
|
324
|
+
form. A dialog whose bottom padding is not the default 1.5rem (`p-0` and
|
|
325
|
+
`p-4` are recognised) sets `--form-actions-fill` to it:
|
|
326
|
+
|
|
327
|
+
```css
|
|
328
|
+
.edit-school-form {
|
|
329
|
+
--form-actions-clearance: 9rem;
|
|
330
|
+
}
|
|
331
|
+
.edit-school-dialog {
|
|
332
|
+
--form-actions-fill: 2rem; /* its pb-8 */
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
```vue
|
|
337
|
+
<form class="form-grid-layout edit-school-form">
|
|
338
|
+
```
|
|
339
|
+
- To scroll a form in a box of your own, give it a height and the scroll
|
|
340
|
+
(`class="form-grid-layout max-h-[60vh] overflow-y-auto"`); to keep the
|
|
341
|
+
actions in place, give them `class="static"`. The
|
|
342
|
+
[troubleshooting entry](../troubleshooting.md#a-forms-fields-no-longer-scroll-in-their-own-box-after-upgrading)
|
|
343
|
+
has the details.
|
|
344
|
+
|
|
296
345
|
## Validation messages
|
|
297
346
|
|
|
298
347
|
`zodLocaleError()` from `@nxgt/material-vue/lib` is a Zod v4 error map that
|
|
@@ -902,10 +951,12 @@ const onSubmit = handleSubmit(() => {
|
|
|
902
951
|
|
|
903
952
|
- `meta.valid` keeps the button disabled until the schema passes; the form
|
|
904
953
|
runs a silent validation when it mounts, so it starts disabled.
|
|
905
|
-
- `ConfirmationDialog`
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
954
|
+
- `ConfirmationDialog` renders its default slot above Cancel / Confirm and
|
|
955
|
+
emits `confirm`, then closes. For a small form (a name to type before a
|
|
956
|
+
delete), pass `form-options` (a schema and its `defaultValues`) and render
|
|
957
|
+
the fields in its `#form` slot: Confirm stays disabled until the form is
|
|
958
|
+
valid, and `@confirm` receives the schema's output. Use the pattern above
|
|
959
|
+
for a larger form with its own submit.
|
|
909
960
|
- `ConfirmDialog` (controlled: `open` is required) awaits its `@confirm`
|
|
910
961
|
handler: while the promise is pending both buttons are disabled and the
|
|
911
962
|
confirm button reads "Processing..." (`material.confirm-dialog.processing`);
|
package/docs/guides/i18n.md
CHANGED
|
@@ -281,7 +281,8 @@ checkboxes, the filter's presets and `Min`/`Max` fields, the `variant="4"` spinn
|
|
|
281
281
|
`DialogFooter`. `CopyButton` reads `material.copy.copy`, `copied` and `failed` ("Copy", "Copied",
|
|
282
282
|
"Copy failed"). The other icon-only buttons are named from it too: the
|
|
283
283
|
`Sidebar` toggle (`material.sidebar.toggle`), the data table's row expander
|
|
284
|
-
(`material.table.labels.toggle-row`)
|
|
284
|
+
(`material.table.labels.toggle-row`) and its header, a hidden "Expand" / "Déplier"
|
|
285
|
+
(`material.table.labels.expand`), its loading status, "Loading data…" /
|
|
285
286
|
"Chargement des données…" (`material.table.loading`), its scroll region,
|
|
286
287
|
"Scrollable table" / "Tableau défilant"
|
|
287
288
|
(`material.table.labels.scroll-region`, or the `scroll-label` prop), a `Chip`'s remove button, which the
|
|
@@ -291,7 +292,7 @@ the `LocationPreview` trigger (`material.map.preview` / `preview-named`),
|
|
|
291
292
|
(`material['duration-field']['hours-label']` / `minutes-label`), and
|
|
292
293
|
the delete button of the deprecated `ContactItem` / `OpeningHoursItem`
|
|
293
294
|
(`material.contacts.buttons.remove`,
|
|
294
|
-
`material['opening-hours'].buttons.remove`). When the form of a
|
|
295
|
+
`material['opening-hours'].buttons.remove`). `FacetGroup`'s toggle is named "Level, 2 selected" / "Level, 2 sélectionnés" (`material.facet-group.name`, an ICU plural over `{title}` and `{count}`) and its Clear button "Clear Level" / "Effacer Level" (`material.facet-group.clear-label`, with the visible `material.facet-group.clear`). When the form of a
|
|
295
296
|
`ConfirmationDialog` with `form-options` cannot be loaded, it says so in the
|
|
296
297
|
form's place: "The form could not be loaded." / "Le formulaire n’a pas pu être
|
|
297
298
|
chargé." (`material.confirm-dialog.form-failed`). The keys and the French are the
|
package/docs/guides/ssr.md
CHANGED
|
@@ -179,6 +179,14 @@ function clientOnly<P extends object>(component: Component<P>): Component<P>;
|
|
|
179
179
|
`@nxgt/material-vue/composables` is a `Ref<boolean>` that is `false` on the
|
|
180
180
|
server and the first render, then `true`.
|
|
181
181
|
|
|
182
|
+
## Hidden form inputs
|
|
183
|
+
|
|
184
|
+
`Checkbox`, `Switch`, `RadioGroup` and `Select` create their hidden form input
|
|
185
|
+
after mount, never in the server HTML (Reka put an inline `style` on it, which a
|
|
186
|
+
strict CSP blocks). Before hydration a native form post therefore carries none
|
|
187
|
+
of these four controls' values; submit through the client, or wait for
|
|
188
|
+
hydration. See [csp.md](csp.md#the-hidden-form-inputs).
|
|
189
|
+
|
|
182
190
|
## Hydration
|
|
183
191
|
|
|
184
192
|
**Never name an SVG with `<svg><title>`.** Some SSR setups treat `<title>` as
|
package/docs/guides/theming.md
CHANGED
|
@@ -134,7 +134,7 @@ import { Button } from '@nxgt/material-vue/components';
|
|
|
134
134
|
|
|
135
135
|
**Contrast.** The shipped light palette keeps the text of every filled status
|
|
136
136
|
colour at 4.5:1 or more (WCAG 1.4.3): `--secondary` 5.7:1, `--success` 5.6:1,
|
|
137
|
-
`--info` 5.8:1 and `--warning` 5.
|
|
137
|
+
`--info` 5.8:1 and `--warning` 5.5:1 against their `-foreground`, and
|
|
138
138
|
`--secondary` as text (a `tonal`, `outlined` or `link` `Button`) 6.0:1 on
|
|
139
139
|
`--background`, 4.8:1 on its own 15 % `tonal` tint.
|
|
140
140
|
|
|
@@ -144,8 +144,8 @@ and 5.8:1 on `--card` (a `tonal` secondary `Button` 5.4:1 and 4.6:1). Under
|
|
|
144
144
|
near-white text those brights are too light, so every filled surface built on
|
|
145
145
|
them is tinted in the dark theme: a filled `secondary` `Button`, `IconButton`
|
|
146
146
|
or `Badge` at 70 % (5.2:1 on `--background`, 4.9:1 on `--card`), a filled
|
|
147
|
-
`success`, `info` or `warning` one at 60 % (7.3:1, 5.7:1 and
|
|
148
|
-
`--background`; 6.7:1, 5.3:1 and
|
|
147
|
+
`success`, `info` or `warning` one at 60 % (7.3:1, 5.7:1 and 6.0:1 on
|
|
148
|
+
`--background`; 6.7:1, 5.3:1 and 5.6:1 on `--card`; the `warning` `Button` 6.5:1). Their hover, focus and
|
|
149
149
|
pressed states are tinted further down, so they only gain contrast.
|
|
150
150
|
|
|
151
151
|
In the light theme the filled `primary`, `secondary`, `success`, `info`,
|
|
@@ -161,9 +161,9 @@ their text and icon in one tone per colour, read on `--background`, on
|
|
|
161
161
|
`--card` and on the variant's own tint (15 % at most, at rest or focused). In
|
|
162
162
|
the light theme `primary`, `secondary`, `info` and `success` use the token
|
|
163
163
|
itself (5.8, 4.8, 4.9 and 4.7:1 at their lowest) and `warning` and `error` the
|
|
164
|
-
token mixed with 15 % black (6.
|
|
164
|
+
token mixed with 15 % black (6.4 and 5.4:1). In the dark theme `primary` is
|
|
165
165
|
mixed with 60 % white (8.1:1 on `--card`: the token itself is a dark indigo,
|
|
166
|
-
2.2:1), `success` and `warning` with 15 % white (5.0 and
|
|
166
|
+
2.2:1), `success` and `warning` with 15 % white (5.0 and 6.3:1), `error` with
|
|
167
167
|
30 % white (5.9:1), and `secondary` and `info` use the token (4.6 and 5.3:1).
|
|
168
168
|
The tones are mixed from the tokens (`color-mix(in oklab, var(--color-error)
|
|
169
169
|
85%, black)`), so an override of a token moves its tone with it; a text colour
|
|
@@ -179,6 +179,29 @@ darker than the dark theme's: a filled `error` button's near-white text reaches
|
|
|
179
179
|
4.8:1 (it was 4.6:1). The dark `--error` keeps `0.577`: a lighter value drops
|
|
180
180
|
the filled surface's near-white text below 4.5:1 (`0.62` gives 3.85:1).
|
|
181
181
|
|
|
182
|
+
**`--warning` is amber**, a hue apart from `--error` (62 against 27 degrees in
|
|
183
|
+
the light theme, 70 in the dark one), so a warning `Alert`, `Banner`, `Badge`
|
|
184
|
+
or toast does not read as a failure. Light `oklch(0.52 0.13 62)` is 5.5:1
|
|
185
|
+
under its near-white `-foreground`; dark `oklch(0.7 0.15 70)` reads as text at
|
|
186
|
+
7.3:1 on `--background` and 6.5:1 on `--card` (6.6 and 5.8:1 on its 10 % tint). An app that overrides `--warning` keeps its own
|
|
187
|
+
value; one that keeps the shipped value sees its `bg-warning` and
|
|
188
|
+
`text-warning` surfaces change hue, and re-checks its custom pairs.
|
|
189
|
+
|
|
190
|
+
**A selected `DataTable` row** (`TableRow`, `data-state="selected"`) is a 15 %
|
|
191
|
+
primary tint with `foreground` text, a bar on the inline-start edge of its
|
|
192
|
+
first cell (`before:`, primary in the light theme, primary mixed with 60 %
|
|
193
|
+
white in the dark one: 5.9:1 in light and 8.2:1 or more in dark against the
|
|
194
|
+
row), and the checkbox, drawn in the same dark colour (8.2:1 or more). The
|
|
195
|
+
tint is too light to be told from its neighbour alone (1.2:1 in light, 1.06 to
|
|
196
|
+
1.11:1 in dark), which is what keeps the text at 4.5:1 or more on a page and on
|
|
197
|
+
a `Card`: 15.9:1 in light, and in dark 17.5:1 on a page, 17.1:1 in a `DataTable`
|
|
198
|
+
on a `Card` and 15.4:1 for a bare `TableRow` on a `Card`. Links and
|
|
199
|
+
`text-muted-foreground` texts (drawn as `foreground` at 70 %) are 7.0:1 in
|
|
200
|
+
light and 8.15:1 in dark for a bare row on a `Card`. A `text-error-text` text
|
|
201
|
+
keeps its colour. Do not
|
|
202
|
+
put `text-primary-foreground` in a cell for a selected row: it is near-white
|
|
203
|
+
on that tint.
|
|
204
|
+
|
|
182
205
|
**Error text has a token of its own**, `--error-text` (`text-error-text`), so
|
|
183
206
|
the fill can stay dark while the text is light enough to read. The light value
|
|
184
207
|
is `color-mix(in oklab, var(--error) 94%, black)` (5.7:1 on `--background`
|
|
@@ -212,7 +235,7 @@ the surfaces' text, the error text (`HelperText` and a field's message on
|
|
|
212
235
|
`--background` and `--card`), the `Alert`s and the `Timeline`, `Button` and
|
|
213
236
|
`IconButton` in every variant and colour, and a `Badge` link in every colour,
|
|
214
237
|
at rest, hovered, focused and pressed, the tracks and the tabs;
|
|
215
|
-
`Data display/ListTile` measures the selected tile. Run them against your own
|
|
238
|
+
`Data display/ListTile` measures the selected tile, `Data table, filter & lists/DataTable/On a card` the header, the cells, the links and the selected rows on a page and on a `Card` (also right-to-left), and `Feedback & status/Alert/Tones contrast` the warning, error and success alerts there. Run them against your own
|
|
216
239
|
tokens after an override.
|
|
217
240
|
|
|
218
241
|
**Tabs.** An `underline` tab's active label is `--primary` in the light
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/roadmap.md
CHANGED
|
@@ -90,9 +90,14 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
90
90
|
Vue only: `@nxgt/material`'s print blocks already produce a PDF.
|
|
91
91
|
- **`StepperIndicator`, as in `@nxgt/material`** — the step markers on their
|
|
92
92
|
own, for a stepper laid out your way.
|
|
93
|
+
- **Facets panel: `Filter variant="facets"`** — collapsible FacetGroups sharing the filter bar's state, a sheet on a phone
|
|
93
94
|
|
|
94
95
|
## Later
|
|
95
96
|
|
|
97
|
+
- **A CSP without `style-src-attr 'unsafe-inline'`** — the four form controls'
|
|
98
|
+
hidden inputs no longer need it; the checked `Checkbox` indicator,
|
|
99
|
+
`SelectValue`, the `RadioGroup` root, `Slider` and popper positioning still
|
|
100
|
+
do. Inventory: softistx/nxgt-material#596.
|
|
96
101
|
- **Next major: an error `Banner` interrupts** — `tone="error"` becomes
|
|
97
102
|
`role="alert"` `aria-live="assertive"`, so a screen reader reads it out at
|
|
98
103
|
once. Every tone is `role="status"` `aria-live="polite"` today; pass
|
package/docs/troubleshooting.md
CHANGED
|
@@ -27,6 +27,7 @@ words in your error.
|
|
|
27
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)
|
|
28
28
|
- [A Button's label overflows a card on a phone](#a-buttons-label-overflows-a-card-on-a-phone)
|
|
29
29
|
- [A dialog or sheet scrolls, or clips a child, after upgrading](#a-dialog-or-sheet-scrolls-or-clips-a-child-after-upgrading)
|
|
30
|
+
- [A form's fields no longer scroll in their own box after upgrading](#a-forms-fields-no-longer-scroll-in-their-own-box-after-upgrading)
|
|
30
31
|
- [`JsBarcode is not a function`](#jsbarcode-is-not-a-function)
|
|
31
32
|
- [A `LinkButton` selected as a `button` stops matching](#a-linkbutton-selected-as-a-button-stops-matching)
|
|
32
33
|
- [A `Toc`, `Pager`, `SeeAlso` or `ScrollProgress` inside `Doc` selected by `data-slot` stops matching](#a-toc-pager-seealso-or-scrollprogress-inside-doc-selected-by-data-slot-stops-matching)
|
|
@@ -1284,6 +1285,32 @@ with `class="max-h-none overflow-visible"`; to change the cap, pass your own
|
|
|
1284
1285
|
For a dialog that should grow taller than the screen and scroll inside the
|
|
1285
1286
|
overlay instead of capping, use `DialogScrollContent`.
|
|
1286
1287
|
|
|
1288
|
+
### A form's fields no longer scroll in their own box after upgrading
|
|
1289
|
+
|
|
1290
|
+
**When:** after upgrading, a `.form-grid-layout` form grows with the page
|
|
1291
|
+
instead of scrolling its fields in a box of its own, Cancel and Save stay at
|
|
1292
|
+
the bottom of the screen, or a form inside a box you gave a fixed height
|
|
1293
|
+
overflows it.
|
|
1294
|
+
**Why:** the form grid used to cap its height
|
|
1295
|
+
(`max-h-[calc(100lvh-184px)]`, more from `md`) and scroll
|
|
1296
|
+
`[data-slot="form-fields"]` inside it, so a page had two scrolls, one inside
|
|
1297
|
+
the other. It now has no cap and no scroll of its own: the page, or the
|
|
1298
|
+
`DialogContent` / `SheetContent` around it, is the one scroll, and
|
|
1299
|
+
`[data-slot="form-actions"]` is sticky at its bottom on a blurred background.
|
|
1300
|
+
A `Drawer`'s content does not scroll, so a form that is a direct child of
|
|
1301
|
+
`DrawerContent` is the scroll box there.
|
|
1302
|
+
**Fix:** to scroll a form inside a box again, give the box (or the form) a
|
|
1303
|
+
height and the scroll; the actions then stick to its bottom. To keep the
|
|
1304
|
+
actions where they are, make them static:
|
|
1305
|
+
|
|
1306
|
+
```vue
|
|
1307
|
+
<form class="form-grid-layout max-h-[60vh] overflow-y-auto">
|
|
1308
|
+
<div data-slot="form-actions" class="static">
|
|
1309
|
+
```
|
|
1310
|
+
|
|
1311
|
+
An app's own fixed bottom bar or floating action button now sits under the
|
|
1312
|
+
sticky actions (`z-index: 10`): give it a z-index above 10 (`class="z-20"`).
|
|
1313
|
+
|
|
1287
1314
|
## Feedback
|
|
1288
1315
|
|
|
1289
1316
|
### A toast with an action never goes away
|
|
@@ -1318,12 +1345,12 @@ no `position`; it still covers the bottom when the app mounts vue-sonner's own
|
|
|
1318
1345
|
`position`, which applies on every screen.
|
|
1319
1346
|
**Fix:** mount the `Toaster` from `@nxgt/material-vue/components`, and drop a
|
|
1320
1347
|
bottom `position` unless the bottom is what you want on phones too. When a
|
|
1321
|
-
sticky header
|
|
1322
|
-
`top
|
|
1348
|
+
sticky header is taller than the app shell's (72px with its margin), raise the
|
|
1349
|
+
phone offset's `top` (80 by default, so toasts start below that bar):
|
|
1323
1350
|
|
|
1324
1351
|
```vue
|
|
1325
1352
|
<Toaster /> <!-- top-center on a phone -->
|
|
1326
|
-
<Toaster :mobile-offset="{ top:
|
|
1353
|
+
<Toaster :mobile-offset="{ top: 96 }" />
|
|
1327
1354
|
<Toaster position="bottom-center" /> <!-- bottom-center on every screen -->
|
|
1328
1355
|
```
|
|
1329
1356
|
|
|
@@ -3306,8 +3333,8 @@ while a `Switch`, `SwitchField` or `SwitchFormField` with `required` and a
|
|
|
3306
3333
|
proceed".
|
|
3307
3334
|
**Why:** `required` used to draw only the label's asterisk. It now reaches the
|
|
3308
3335
|
switch, which is announced as required (`aria-required`), and its hidden input
|
|
3309
|
-
is `required`, so the browser's native validation blocks the
|
|
3310
|
-
required checkbox.
|
|
3336
|
+
is `required`, so once hydrated the browser's native validation blocks the
|
|
3337
|
+
submit, as for a required checkbox.
|
|
3311
3338
|
**Fix:** leave `required` on a switch that must be on (an agreement); drop it
|
|
3312
3339
|
from one that may stay off. A form that validates itself (vee-validate) can
|
|
3313
3340
|
turn native validation off with `novalidate`:
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
.form-grid-layout {
|
|
98
98
|
@apply relative flex flex-col gap-2 @container;
|
|
99
99
|
[data-slot="form-fields"] {
|
|
100
|
-
@apply grid @2xl:grid-cols-2 @4xl:grid-cols-3 @6xl:grid-cols-4 gap-2 bg-background/80 p-4 place-items-start
|
|
100
|
+
@apply grid @2xl:grid-cols-2 @4xl:grid-cols-3 @6xl:grid-cols-4 gap-2 bg-background/80 p-4 place-items-start;
|
|
101
101
|
|
|
102
102
|
[data-slot="separator"] {
|
|
103
103
|
@apply col-start-full;
|
|
@@ -125,13 +125,73 @@
|
|
|
125
125
|
@apply col-start-full;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
/* A focused control scrolls into view clear of the actions and a line
|
|
129
|
+
of helper text, in any scroll box (WCAG 2.4.11 Focus Not Obscured). */
|
|
130
|
+
[data-slot="form-fields"]
|
|
131
|
+
:is(
|
|
132
|
+
input,
|
|
133
|
+
textarea,
|
|
134
|
+
select,
|
|
135
|
+
button,
|
|
136
|
+
a[href],
|
|
137
|
+
summary,
|
|
138
|
+
[tabindex],
|
|
139
|
+
[contenteditable]
|
|
140
|
+
) {
|
|
141
|
+
scroll-margin-bottom: calc(
|
|
142
|
+
var(--form-actions-clearance, 6rem) +
|
|
143
|
+
var(--form-actions-fill, 0px)
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
/* Sticky at the bottom of whatever scrolls the form: in reach. */
|
|
128
147
|
[data-slot="form-actions"] {
|
|
129
|
-
@apply flex w-full justify-end gap-2
|
|
148
|
+
@apply sticky bottom-0 z-10 flex w-full justify-end gap-2 bg-background/90 p-4 backdrop-blur-sm max-sm:*:flex-1;
|
|
130
149
|
}
|
|
131
150
|
}
|
|
132
151
|
|
|
133
|
-
|
|
134
|
-
|
|
152
|
+
/* No height cap and no scroll of its own: the page (or the overlay) is
|
|
153
|
+
the one scroll. A Drawer's content does not scroll: the form does. */
|
|
154
|
+
[data-slot="drawer-content"] > .form-grid-layout {
|
|
155
|
+
@apply min-h-0 overflow-y-auto;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* In a dialog, the stuck actions sit above its bottom padding
|
|
159
|
+
(`--form-actions-fill`: p-6 by default; set it for another one). */
|
|
160
|
+
:is([data-slot="dialog-content"], [data-slot="alert-dialog-content"]) {
|
|
161
|
+
--form-actions-fill: 1.5rem;
|
|
162
|
+
&:is(.p-0, .py-0, .pb-0) {
|
|
163
|
+
--form-actions-fill: 0px;
|
|
164
|
+
}
|
|
165
|
+
&:is(.p-4, .py-4, .pb-4) {
|
|
166
|
+
--form-actions-fill: 1rem;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* ConfirmationDialog's form has no actions of its own: the dialog's
|
|
171
|
+
footer (two stacked buttons on a phone) sticks instead. */
|
|
172
|
+
:is([data-slot="dialog-content"], [data-slot="alert-dialog-content"]):has(
|
|
173
|
+
.form-grid-layout
|
|
174
|
+
):not(:has([data-slot="form-actions"])) {
|
|
175
|
+
--form-actions-clearance: 7.5rem;
|
|
176
|
+
> :is([data-slot="dialog-footer"], [data-slot="alert-dialog-footer"]) {
|
|
177
|
+
@apply sticky bottom-0 z-10 bg-background/90 backdrop-blur-sm;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* A sticky element stops at the scroll box's padding: in a dialog, an
|
|
182
|
+
`::after` as tall as that padding fills the strip below the stuck
|
|
183
|
+
actions, so no field shows there, and adds no overflow. */
|
|
184
|
+
:is([data-slot="dialog-content"], [data-slot="alert-dialog-content"])
|
|
185
|
+
.form-grid-layout
|
|
186
|
+
> [data-slot="form-actions"]::after,
|
|
187
|
+
:is([data-slot="dialog-content"], [data-slot="alert-dialog-content"]):has(
|
|
188
|
+
.form-grid-layout
|
|
189
|
+
):not(:has([data-slot="form-actions"]))
|
|
190
|
+
> :is(
|
|
191
|
+
[data-slot="dialog-footer"],
|
|
192
|
+
[data-slot="alert-dialog-footer"]
|
|
193
|
+
)::after {
|
|
194
|
+
@apply absolute inset-x-0 top-full h-(--form-actions-fill) bg-background content-[""];
|
|
135
195
|
}
|
|
136
196
|
|
|
137
197
|
/* No height cap on `DataTable` here (it nested a scroll in the page's):
|
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
--success-foreground: oklch(0.984 0.003 247.858);
|
|
39
39
|
--info: oklch(0.5 0.165 254.624);
|
|
40
40
|
--info-foreground: oklch(0.984 0.003 247.858);
|
|
41
|
-
--
|
|
41
|
+
/* Amber, a hue apart from --error (27): a warning must not read as a
|
|
42
|
+
failure. 5.7:1 as text on white, 5.0:1 on its 10% tint, 5.5:1 under near-white text. */
|
|
43
|
+
--warning: oklch(0.52 0.13 62);
|
|
42
44
|
--warning-foreground: oklch(0.984 0.003 247.858);
|
|
43
45
|
--destructive: var(--error);
|
|
44
46
|
--border: oklch(0.929 0.013 255.508);
|
|
@@ -94,7 +96,10 @@
|
|
|
94
96
|
--success-foreground: oklch(0.984 0.003 247.858);
|
|
95
97
|
--info: oklch(0.707 0.165 254.624);
|
|
96
98
|
--info-foreground: oklch(0.984 0.003 247.858);
|
|
97
|
-
|
|
99
|
+
/* Amber too, as text: 7.3:1 on --background and 6.5:1 on --card, 6.6:1 and
|
|
100
|
+
5.8:1 on its 10% tint; the badge's 60% fill under near-white text is
|
|
101
|
+
6.0:1 on a page and 5.6:1 on a Card. */
|
|
102
|
+
--warning: oklch(0.7 0.15 70);
|
|
98
103
|
--warning-foreground: oklch(0.984 0.003 247.858);
|
|
99
104
|
--destructive: oklch(0.704 0.191 22.216);
|
|
100
105
|
--border: oklch(1 0 0 / 10%);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/material-vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"email": "stevegires@gmail.com"
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
"docs:previews": "vitest run --project previews"
|
|
125
125
|
},
|
|
126
126
|
"dependencies": {
|
|
127
|
-
"@nxgt/material-core": "^0.11.
|
|
127
|
+
"@nxgt/material-core": "^0.11.1",
|
|
128
128
|
"@floating-ui/dom": "^1.8.0",
|
|
129
129
|
"@fortawesome/fontawesome-common-types": "7.3.1",
|
|
130
130
|
"@lucide/vue": "^1.45.0",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { nextTick as e, useTemplateRef as t, watch as n } from "vue";
|
|
2
|
-
import { unrefElement as r } from "@vueuse/core";
|
|
3
|
-
import { inertOthers as i } from "@nxgt/material-core/inert-others";
|
|
4
|
-
//#region lib/components/ui/overlays/dialog/use-inert-others.ts
|
|
5
|
-
function a(a, o) {
|
|
6
|
-
let s = typeof a == "string" ? t(a) : a;
|
|
7
|
-
n(o, (t, n, a) => {
|
|
8
|
-
if (!t || typeof document > "u") return;
|
|
9
|
-
let o, c = !1;
|
|
10
|
-
e(() => {
|
|
11
|
-
let e = r(s);
|
|
12
|
-
!c && e instanceof Element && (o = i(e));
|
|
13
|
-
}), a(() => {
|
|
14
|
-
c = !0, o?.();
|
|
15
|
-
});
|
|
16
|
-
}, {
|
|
17
|
-
immediate: !0,
|
|
18
|
-
flush: "post"
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
//#endregion
|
|
22
|
-
export { a as t };
|