@nxgt/material 3.88.1 → 3.91.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 +50 -0
- package/README.md +8 -5
- package/dist/{alert-dialog-CEGs7LMN.js → alert-dialog-BFk4ye-3.js} +1 -1
- package/dist/{async-slice-CR0M95Jq.js → async-slice-gGyfyUw2.js} +1 -1
- package/dist/{button-DuTNpo28.js → button-C5OEq9bi.js} +1 -1
- package/dist/{calculator-DsGk_fCw.js → calculator-Dg_L6d3R.js} +16 -16
- package/dist/calculator-field.js +6 -6
- package/dist/{calculator-segment-DMFptsDf.js → calculator-segment-CvAaDqKf.js} +1 -1
- package/dist/calculator.js +1 -1
- package/dist/charts.js +3 -3
- package/dist/{chip-C-RAjar5.js → chip-DOxFA4BI.js} +2 -2
- package/dist/{code-editor-DApeIOZ3.js → code-editor-tiAjhXW-.js} +4 -4
- package/dist/code-editor.js +4 -4
- package/dist/{code-language-items-CGtYfc1l.js → code-language-items-CcdzQvLT.js} +2 -2
- package/dist/{components-DiEY0nrG.js → components-G0nEVa52.js} +19744 -19404
- package/dist/components.js +38 -37
- package/dist/{conversion-variant-DfQiOwYC.js → conversion-variant-4gCdFWV-.js} +3 -3
- package/dist/currency-field-CIqe7Wg4.js +289 -0
- package/dist/{dialog-Bul68q8u.js → dialog-d6Kdf5wc.js} +3 -3
- package/dist/dnd.js +1 -1
- package/dist/{dropdown-menu-xUUE5X6T.js → dropdown-menu-DO5kUvof.js} +1 -1
- package/dist/editor.js +139 -139
- package/dist/{empty-state-D7ofGDU_.js → empty-state-DQnICuun.js} +1 -1
- package/dist/{financial-variant-CYgRZzKT.js → financial-variant-D80C1hVD.js} +14 -14
- package/dist/{hooks-CpvvZCs7.js → hooks-C-yLDF39.js} +2 -2
- package/dist/hooks.js +2 -2
- package/dist/{hover-card-CZLFQwZv.js → hover-card-DU3TAME4.js} +1 -1
- package/dist/i18n.js +3 -3
- package/dist/{icon-badge-0Xo9q7Ey.js → icon-badge-BGczZ4Hc.js} +1 -1
- package/dist/{icon-button-DE1EcO2-.js → icon-button-D0xjBCst.js} +1 -1
- package/dist/input-group-CSlXMFxu.js +70 -0
- package/dist/lib/components/ui/actions/back-link/back-link.d.ts +10 -2
- package/dist/lib/components/ui/collections/data-grid/grid-cell-tone.d.ts +12 -0
- package/dist/lib/components/ui/collections/data-grid/partials/grid-cell-access.d.ts +4 -3
- package/dist/lib/components/ui/collections/data-grid/partials/grid-cell-flags.d.ts +12 -0
- package/dist/lib/components/ui/collections/data-grid/partials/grid-cell-value.d.ts +4 -1
- package/dist/lib/components/ui/collections/data-table/partials/data-table-cell-content.d.ts +11 -0
- package/dist/lib/components/ui/collections/data-table/table-meta.d.ts +50 -2
- package/dist/lib/components/ui/collections/filter/use-filter-field-config.d.ts +1 -0
- package/dist/lib/components/ui/collections/list-pane/list-pane-item.d.ts +3 -1
- package/dist/lib/components/ui/collections/list-pane/partials/list-pane-item-content.d.ts +2 -1
- package/dist/lib/components/ui/dates/age-field/age-field.d.ts +8 -0
- package/dist/lib/components/ui/dates/age-field/age-form-field.d.ts +8 -0
- package/dist/lib/components/ui/dates/age-field/age-reading.d.ts +11 -0
- package/dist/lib/components/ui/dates/age-field/age-value.d.ts +9 -0
- package/dist/lib/components/ui/dates/age-field/index.d.ts +4 -0
- package/dist/lib/components/ui/dates/age-field/types.d.ts +40 -0
- package/dist/lib/components/ui/dates/index.d.ts +1 -0
- package/dist/lib/components/ui/display/badge/badge.d.ts +4 -1
- package/dist/lib/components/ui/display/entity-header/entity-header.d.ts +8 -1
- package/dist/lib/components/ui/display/index.d.ts +2 -0
- package/dist/lib/components/ui/display/person-cell/index.d.ts +1 -0
- package/dist/lib/components/ui/display/person-cell/person-cell.d.ts +23 -0
- package/dist/lib/components/ui/display/tone-value/index.d.ts +2 -0
- package/dist/lib/components/ui/display/tone-value/tone-value.d.ts +23 -0
- package/dist/lib/components/ui/feedback/error-state/partials/error-state-actions.d.ts +6 -1
- package/dist/lib/components/ui/feedback/page-load-failed/page-load-failed.d.ts +8 -1
- package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
- package/dist/lib/components/ui/fields/number-field/number-control.d.ts +2 -2
- package/dist/lib/components/ui/fields/switch/partials/switch-row.d.ts +4 -2
- package/dist/lib/components/ui/fields/switch/switch.d.ts +7 -1
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside-parts.d.ts +68 -0
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside-toggle.d.ts +22 -0
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside.d.ts +5 -2
- package/dist/lib/components/ui/layout/app-shell/activity-content-aside.types.d.ts +13 -0
- package/dist/lib/components/ui/layout/app-shell/activity-content.d.ts +3 -2
- package/dist/lib/components/ui/layout/app-shell/app-shell.utils.d.ts +3 -1
- package/dist/lib/components/ui/layout/app-shell/app-sidebar-entries.d.ts +5 -2
- package/dist/lib/components/ui/layout/app-shell/app-sidebar-icon-item.d.ts +2 -1
- package/dist/lib/components/ui/layout/app-shell/app-sidebar.d.ts +3 -1
- package/dist/lib/components/ui/layout/app-shell/types.d.ts +14 -5
- package/dist/lib/components/ui/layout/sticky-action-bar/sticky-action-bar.d.ts +3 -1
- package/dist/lib/components/ui/layout/sticky-action-bar/use-bar-clearance.d.ts +10 -0
- package/dist/lib/components/ui/primitives/tabs/partials/tabs-list.d.ts +8 -2
- package/dist/lib/components/ui/primitives/tabs/tabs-nav.d.ts +5 -1
- package/dist/lib/components/ui/primitives/tabs/tabs-overflow-classes.d.ts +3 -0
- package/dist/lib/components/ui/selection/sortable-list/index.d.ts +1 -1
- package/dist/lib/components/ui/selection/sortable-list/sortable-list-context.d.ts +3 -1
- package/dist/lib/components/ui/selection/sortable-list/sortable-list.d.ts +6 -2
- package/dist/lib/components/ui/selection/sortable-list/types.d.ts +1 -0
- package/dist/lib/components/ui/selection/sortable-list/use-sortable-list-labels.d.ts +3 -0
- package/dist/lib/i18n/resources/en/en.d.ts +11 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +12 -1
- package/dist/lib/i18n/resources/fr/fr.d.ts +11 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +12 -1
- package/dist/lib/i18n/resources/resources.d.ts +22 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib.js +1 -1
- package/dist/main.js +54 -53
- package/dist/map.js +7 -7
- package/dist/material.css +1 -1
- package/dist/pdf-reader.js +1 -1
- package/dist/{percent-field-BFwxazf1.js → percent-field-DyJ2yOH4.js} +1 -1
- package/dist/{picker-surface-DkfTv_ft.js → picker-surface-CnlOKQ3D.js} +4 -4
- package/dist/{popover-BM6xApJd.js → popover-BevReSHi.js} +1 -1
- package/dist/{pos-types-CpTpT4vE.js → pos-types-BrZBX0Zg.js} +1 -1
- package/dist/{pos-variant-Bs5BUB1L.js → pos-variant-G12HCSfQ.js} +4 -4
- package/dist/print.js +1 -1
- package/dist/{programmer-variant-B1eI1fd0.js → programmer-variant-WWLwTGRF.js} +2 -2
- package/dist/{public-CzLMnSsS.js → public-C1a6wQ6o.js} +19 -19
- package/dist/{rich-code-block-CdVtxD75.js → rich-code-block-Dh9J-VZ8.js} +5 -5
- package/dist/{scientific-variant-rfvJKxB4.js → scientific-variant-BvutlF8a.js} +2 -2
- package/dist/{sortable-provider-BopzsciJ.js → sortable-provider-BrA5tfJX.js} +2 -2
- package/dist/{spinner-DcW21pN1.js → spinner-JnLLiLIO.js} +1 -1
- package/dist/{tabs-CdoBFtWx.js → tabs-dXCZGShv.js} +63 -61
- package/dist/theme-picker.js +2 -2
- package/dist/{theme-toggle-Ch3GkDDU.js → theme-toggle-BmcK6mXV.js} +1 -1
- package/dist/{toolbar-items-CZ1lJXZZ.js → toolbar-items-B-kMYsDT.js} +4 -4
- package/dist/{translate-material-BrYBBZ66.js → translate-material-BmpcP1p1.js} +1 -1
- package/dist/{translator-DoVsjUff.js → translator-CfoXTrZd.js} +24 -2
- package/dist/{use-chat-composer-C9DG7O1Z.js → use-chat-composer-DFD_eF-r.js} +4197 -4246
- package/dist/{use-heading-spy-kyOSe9rb.js → use-heading-spy-BcNK1qvq.js} +4 -4
- package/dist/{use-material-translation-BdrItuwY.js → use-material-translation-DoymV6IP.js} +1 -1
- package/dist/{use-return-focus-Cqzvj9R0.js → use-return-focus-CLEnhfka.js} +1 -1
- package/docs/components/README.md +2 -1
- package/docs/components/buttons-and-actions.md +10 -1
- package/docs/components/data-display.md +80 -4
- package/docs/components/data-table-filter-and-lists.md +56 -3
- package/docs/components/date-and-time.md +53 -1
- package/docs/components/feedback-and-status.md +20 -3
- package/docs/components/form-fields.md +11 -2
- package/docs/components/navigation-and-layout.md +7 -2
- package/docs/components/primitives.md +7 -0
- package/docs/components/selection-and-choice.md +4 -2
- package/docs/guides/app-shell.md +46 -11
- package/docs/guides/data-grid.md +12 -0
- package/docs/guides/forms.md +1 -0
- package/docs/guides/i18n.md +1 -1
- package/docs/previews/data-display-personcell.webp +0 -0
- package/docs/previews/data-display-tonevalue.webp +0 -0
- package/docs/previews/date-time-agefield.webp +0 -0
- package/docs/roadmap.md +23 -0
- package/docs/troubleshooting.md +4 -0
- package/package.json +2 -2
- package/dist/currency-field-cwC7cqUE.js +0 -286
package/docs/guides/app-shell.md
CHANGED
|
@@ -105,12 +105,13 @@ type MenuItem = {
|
|
|
105
105
|
- **`footer: true` pins an entry to the footer.** Being last in the list does
|
|
106
106
|
not: appending an entry never moves another one out of the footer.
|
|
107
107
|
- **`display: 'icon'` draws the entry as a round, icon-only button.** Meant
|
|
108
|
-
for the footer's "Settings": in the collapsed rail
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
for the footer's "Settings": in the collapsed rail and the expanded sidebar
|
|
109
|
+
it is an `IconButton` (the Button family's look, ghost, tonal when it is the
|
|
110
|
+
active entry) with the label as its tooltip and, visually hidden, its
|
|
111
|
+
accessible name, `aria-current="page"` when active, and a 44px target on a
|
|
112
|
+
coarse pointer. The phone's menu sheet always shows the icon and the label,
|
|
113
|
+
since a lone icon reads poorly there. The entries without it keep their icon
|
|
114
|
+
and label. An icon button draws no `badge`.
|
|
114
115
|
|
|
115
116
|
```tsx
|
|
116
117
|
{ label: t('menu.settings'), url: '/settings', icon: 'gear', footer: true, display: 'icon' }
|
|
@@ -400,14 +401,27 @@ value (what the props resolve to), and `navigationClasses()` the classes that
|
|
|
400
401
|
show each preset only at the sizes it is configured for. `DEFAULT_NAVIGATION` is
|
|
401
402
|
the default value (`modal-drawer`, `rail`, `rail`).
|
|
402
403
|
|
|
404
|
+
`childrenIn: 'sidebar'` keeps an entry's `children` in the expanded sidebar and
|
|
405
|
+
the top dropdown only: the phone's menu sheet lists the entry as a plain link to
|
|
406
|
+
its `url`, with its badge, for a parent page that already lists them. Unset
|
|
407
|
+
(the default), the sheet nests them like the expanded sidebar.
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
{
|
|
411
|
+
label: 'Services', url: '/services', icon: 'grid-2',
|
|
412
|
+
children: [{ label: 'Lab', url: '/lab', icon: 'flask' }],
|
|
413
|
+
childrenIn: 'sidebar', // the phone's sheet shows "Services" alone, as a link
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
403
417
|
`MenuItem` also accepts `children`, `group`, `bar` and `priority`. Each is read
|
|
404
418
|
by the presets that use it, and ignored by the others: `bar` and `priority`
|
|
405
419
|
choose the entries of the bottom bar **and** of the floating toolbar (the rest go
|
|
406
420
|
under « More »), `group` is read by the drawer, and `children` by the top
|
|
407
|
-
navigation, the two-level panel, the sidebar and the phone's menu sheet.
|
|
421
|
+
navigation, the two-level panel, the sidebar and the phone's menu sheet (which drops them for a `childrenIn: 'sidebar'` entry).
|
|
408
422
|
`footer` is read by the rail, the sidebar and the drawer (its footer), `display`
|
|
409
423
|
by the rail, the sidebar and the phone's menu sheet, and `badge` and `badgeLabel`
|
|
410
|
-
by every preset that draws entries, except on a `display: 'icon'` entry.
|
|
424
|
+
by every preset that draws entries, except on the icon button a `display: 'icon'` entry draws in the rail and the expanded sidebar (the phone's menu sheet draws its badge).
|
|
411
425
|
|
|
412
426
|
### The bottom bar (`navigation="bar"`)
|
|
413
427
|
|
|
@@ -577,7 +591,7 @@ menu button narrows it to 5rem, labels under the icons.
|
|
|
577
591
|
link's name.
|
|
578
592
|
- On a phone the bar is not drawn, whatever the object says
|
|
579
593
|
(`{ phone: 'top' }` keeps the menu sheet): the sheet lists the entries and
|
|
580
|
-
nests each entry's `children` under it, indented. The expanded sidebar nests
|
|
594
|
+
nests each entry's `children` under it, indented (unless `childrenIn: 'sidebar'`). The expanded sidebar nests
|
|
581
595
|
them the same way.
|
|
582
596
|
- An entry with `children` is only a trigger: its `url` is never a link, so put an "all" link as the first child. (The phone's menu sheet and the expanded sidebar do list the
|
|
583
597
|
parent's own `url` as a link, with its children nested under it.)
|
|
@@ -635,7 +649,7 @@ menu button narrows it to 5rem, labels under the icons.
|
|
|
635
649
|
level of `children` is listed.
|
|
636
650
|
- **On a phone** neither is drawn, whatever the object says
|
|
637
651
|
(`{ phone: 'two-level' }` keeps the menu sheet, as `'top'` does): the sheet lists
|
|
638
|
-
the entries and nests each one's `children
|
|
652
|
+
the entries and nests each one's `children` (unless `childrenIn: 'sidebar'`). A name alone leaves the phone its
|
|
639
653
|
default.
|
|
640
654
|
- At 768px the rail and the open panel take 19rem beside the content; fold the
|
|
641
655
|
panel or use `{ tablet: 'rail', desktop: 'two-level' }` when that is too much.
|
|
@@ -1051,7 +1065,8 @@ export const invoiceRoute: RouteObject = {
|
|
|
1051
1065
|
- **A record page uses `EntityHeader` without `title`.** Its band (icon or
|
|
1052
1066
|
avatar, status, metadata, actions) stays, and no second heading duplicates
|
|
1053
1067
|
the bar's `h1`: `<EntityHeader icon={<User />} metadata={[…]} actions={[…]} />`.
|
|
1054
|
-
The root is a plain `div`, not a landmark, so nothing is left unnamed.
|
|
1068
|
+
The root is a plain `div`, not a landmark, so nothing is left unnamed. On a page band
|
|
1069
|
+
(no card of its own) pass `surface="none"`.
|
|
1055
1070
|
- **It labels `<main>`.** While the bar has a title, the content region gets
|
|
1056
1071
|
`aria-labelledby` pointing at the `h1`'s `id` (from `useId`, so it is the same
|
|
1057
1072
|
on the server and the client); without one, there is no `aria-labelledby`.
|
|
@@ -1609,6 +1624,8 @@ export function BoardShell({ items }: { items: MenuItem[] }) {
|
|
|
1609
1624
|
| `asideFrom` | `'lg'` \| `'xl'` \| `'2xl'` | `'xl'` | The viewport width (1024, 1280 or 1536px) from which the panel is beside the content |
|
|
1610
1625
|
| `asideSticky` | `boolean` | `true` | Keeps the panel under the app bar while the page scrolls; it scrolls inside itself when taller than the window |
|
|
1611
1626
|
| `asideStack` | `'before'` \| `'after'` | `'after'` | Where the panel goes below `asideFrom`, in the DOM and on screen |
|
|
1627
|
+
| `asidePhone` | `'stack'` \| `'toggle'` | `'stack'` | Below `asideFrom`: `'stack'` puts the panel after (or before) the content; `'toggle'` puts it behind a two-button switch above the content (content and panel are swapped, the form stays mounted so nothing typed is lost). For a form with a live preview. A `'sheet'` mode is discussed on [#2604](https://github.com/softistx/nxgt-material/issues/2604). |
|
|
1628
|
+
| `asidePreviewLabel` / `asideMainLabel` | `string` | "Preview" / "Content" (`material.app-shell.aside-preview` / `aside-main`) | The switch's button texts; the group's label is `material.app-shell.aside-toggle` ("View") |
|
|
1612
1629
|
| `asideClassName` | `string` | — | Classes for the panel |
|
|
1613
1630
|
|
|
1614
1631
|
```tsx
|
|
@@ -1639,6 +1656,23 @@ content (`asideStack="before"` puts it first). The switch is CSS only: the
|
|
|
1639
1656
|
server's HTML and a phone's first paint are already right, and no JavaScript
|
|
1640
1657
|
decides the layout.
|
|
1641
1658
|
|
|
1659
|
+
`asidePhone="toggle"` is for a form with a live preview: below `asideFrom` a
|
|
1660
|
+
two-button switch ("Content" / "Preview"; French: "Contenu" / "Aperçu") sits above the content and shows one of
|
|
1661
|
+
the two (the other stays mounted, hidden). The save bar, when placed in the content, is out of view while the preview shows, back on the switch (a footer slot outside both panes is tracked in #2609). The first paint is
|
|
1662
|
+
still the content.
|
|
1663
|
+
|
|
1664
|
+
```tsx
|
|
1665
|
+
<ActivityContent
|
|
1666
|
+
title="Edit question"
|
|
1667
|
+
width="form"
|
|
1668
|
+
aside={<QuestionPreview />}
|
|
1669
|
+
asideLabel="Preview"
|
|
1670
|
+
asidePhone="toggle"
|
|
1671
|
+
>
|
|
1672
|
+
<QuestionForm />
|
|
1673
|
+
</ActivityContent>
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1642
1676
|
```tsx
|
|
1643
1677
|
<ActivityContent
|
|
1644
1678
|
title="New visit"
|
|
@@ -1750,6 +1784,7 @@ in the plugin) assembles them for any record: a patient, a student, a project.
|
|
|
1750
1784
|
```tsx
|
|
1751
1785
|
<ActivityContent hideHeader>
|
|
1752
1786
|
<EntityHeader title={record.name} stats={stats} metadata={facts} />
|
|
1787
|
+
{/* on a page band, no card of its own: surface="none" */}
|
|
1753
1788
|
<DescriptionList meta="Added on … · Modified on …">
|
|
1754
1789
|
{fields.map((f) => <Description key={f.label} label={f.label} value={f.value} />)}
|
|
1755
1790
|
</DescriptionList>
|
package/docs/guides/data-grid.md
CHANGED
|
@@ -59,6 +59,18 @@ Columns are DataTable's TanStack v9 column definitions. A column with no
|
|
|
59
59
|
| `headerWrap` | `true` lets the header's title wrap onto up to two lines, the rest cut; the header row keeps one height. Without it a title that does not fit is cut to one line. Either way, a title that is cut shows in full in a tooltip on hover and when the header has the focus (the header's accessible name is always the whole title) |
|
|
60
60
|
| `headerMenu` | Items for the header's menu (a `size-6` button, Alt+ArrowDown or Shift+F10), made of `DataGridMenuItem`s. The built-in column items come first, then a separator, then yours |
|
|
61
61
|
| `className` | Classes for the column's cells. In a [virtual grid](#long-grids-virtual) give the width as `w-*`, the fallback for a column with no width of its own |
|
|
62
|
+
| `cellClassName(value, row)` | Classes for a body cell computed from the value it shows now, so they follow an edit, a save and an undo; return `undefined` for none. Merged after `className`, header untouched, none over a value kept as an error ([cell classes](../components/data-table-filter-and-lists.md#cell-classes-from-the-value)) |
|
|
63
|
+
| `tone(value, row)`, `toneLabel(value, row)` | A tone for a body cell (or `undefined`) from the value it shows now, so it follows an edit, a pending save, a refused one put back and an undo. The cell gets `data-tone` and a `ToneValue` (shape, tone text colour, optional hidden words from `toneLabel`); while the cell is edited the editor's ring stays the focus indicator, and a value kept as an error is not toned. On a phone the list summary and the row panel's read-only values show it too ([cells toned by their value](../components/data-table-filter-and-lists.md#cells-toned-by-their-value)) |
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
helper.accessor('score', {
|
|
67
|
+
meta: {
|
|
68
|
+
editor: 'number',
|
|
69
|
+
tone: (v) => (typeof v === 'number' && v < 8 ? 'error' : undefined),
|
|
70
|
+
toneLabel: (v) => (typeof v === 'number' && v < 8 ? 'Low' : undefined),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
```
|
|
62
74
|
|
|
63
75
|
```tsx
|
|
64
76
|
import { createColumnHelper } from '@tanstack/react-table';
|
package/docs/guides/forms.md
CHANGED
|
@@ -522,6 +522,7 @@ or fails validation.
|
|
|
522
522
|
| `DateField` · `DateFormField` | `Date \| undefined` (not an ISO string). With `timeZone`, still the true instant (the field shows and edits that zone's wall clock); with `showTimePicker`, `undefined` until the date and the time are both complete | `undefined` |
|
|
523
523
|
| `DateRangeField` · `DateRangeFormField` | `DateRange \| undefined`: `{ from: Date \| undefined; to?: Date }` | `undefined` |
|
|
524
524
|
| `TimeField` · `TimeFormField` | `Date \| undefined` (with `timeZone`, the true instant). With `asString`: `'HH:mm'`. While empty it shows its `placeholder` | `undefined` / `''` |
|
|
525
|
+
| `AgeField` · `AgeFormField` | `{ value: number \| null, unit: 'day' \| 'week' \| 'month' \| 'year' }` | `{ value: null, unit: <first unit> }` |
|
|
525
526
|
| `DurationField` · `DurationFormField` | `number \| null`: total minutes (hours × 60 + minutes) | `null` |
|
|
526
527
|
| `HalfDayRangeField` · `HalfDayRangeFormField` | `HalfDayRange \| undefined`: `{ start: { date, half }, end: { date, half } }`, `half` `'morning' \| 'afternoon'`; `undefined` while a day is missing; an end before the start is the value, refused by the wrapper's rule (`material.half-day-range.order`) | `undefined` |
|
|
527
528
|
|
package/docs/guides/i18n.md
CHANGED
|
@@ -345,7 +345,7 @@ separator's name (`material['list-details'].back` / `inspector-back` /
|
|
|
345
345
|
`new-tab`; French "Menu", "Pied de page" and "s'ouvre dans un nouvel onglet");
|
|
346
346
|
`JsonViewer`'s "Empty JSON" (`material['json-viewer'].empty`);
|
|
347
347
|
`TimePicker`'s AM / PM (`material['time-picker'].am` / `pm`, "a.m." / "p.m." in
|
|
348
|
-
French); and the names of `DurationField`'s inputs, "Hours" and "Minutes"
|
|
348
|
+
French); `AgeField`'s unit names, plural-aware (`material['age-field']['unit-day']`, `unit-week`, `unit-month`, `unit-year`: "2 months", « 2 mois »), its unit picker's name (`unit`, "Age unit") and the age its polite status reads (`reading`); and the names of `DurationField`'s inputs, "Hours" and "Minutes"
|
|
349
349
|
(`material['duration-field']['hours-label']` / `minutes-label`) and the
|
|
350
350
|
names of its −/+ buttons, "Increase hours" / "Decrease hours" /
|
|
351
351
|
"Increase minutes" / "Decrease minutes"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/roadmap.md
CHANGED
|
@@ -6,6 +6,16 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
6
6
|
|
|
7
7
|
## Now
|
|
8
8
|
|
|
9
|
+
- **Fields Refined** — every text-like field (text, select, combobox, search,
|
|
10
|
+
phone, date and time boxes) gets a crisper, more legible look by default: a
|
|
11
|
+
border of at least 3:1 contrast, the card surface, a clear focus ring, and no
|
|
12
|
+
filled tint. `NumberField` is right-aligned with its steppers inside the box,
|
|
13
|
+
and gains a compact `score` variant with a caller-set tone and a locked state
|
|
14
|
+
with its reason. New `--success-text` and `--warning-text` tokens join
|
|
15
|
+
`--error-text` in every theme preset. One minor release, no API removed;
|
|
16
|
+
every `--nxgt-field-*` token override still applies
|
|
17
|
+
([#2644](https://github.com/softistx/nxgt-material/issues/2644)).
|
|
18
|
+
|
|
9
19
|
- **Calculator** — `@nxgt/material/calculator` is an exact-decimal calculator
|
|
10
20
|
(Standard, Scientific, point of sale, Financial, Conversion, Programmer;
|
|
11
21
|
every variant but Standard loads on demand)
|
|
@@ -379,6 +389,19 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
379
389
|
|
|
380
390
|
## Shipped
|
|
381
391
|
|
|
392
|
+
- **Cells driven by their value** — in `DataTable`, `ServerTable` and
|
|
393
|
+
`DataGrid`, `meta.cellClassName(value, row)` computes a class per cell from
|
|
394
|
+
its value; `meta.tone(value, row)` colours a cell as coloured text after a
|
|
395
|
+
shaped mark (`ToneValue`: ◆ error, ▲ warning, ● success, ■ any other tone),
|
|
396
|
+
so colour is never the only cue, with an optional screen-reader label
|
|
397
|
+
(`meta.toneLabel`) and the band helper `toneBands` from
|
|
398
|
+
`@nxgt/material-core/cell-tone`; in `DataGrid` both follow edits, pending
|
|
399
|
+
saves and undo, and the phone cards and panels show the tone too; and
|
|
400
|
+
`PersonCell` shows a decorative initials avatar (photo when given) beside a
|
|
401
|
+
truncated name
|
|
402
|
+
([#1117](https://github.com/softistx/nxgt-material/issues/1117),
|
|
403
|
+
[#1032](https://github.com/softistx/nxgt-material/issues/1032),
|
|
404
|
+
[#1112](https://github.com/softistx/nxgt-material/issues/1112)).
|
|
382
405
|
- **Cursor trail cap** — `ServerTable` and `PageFooter` keep cursor URLs short:
|
|
383
406
|
each trail entry is encoded once and the trail is capped by `maxTrail` (20 by
|
|
384
407
|
default, a prop on each) behind a counted cut mark, so the "21–40 of N" range
|
package/docs/troubleshooting.md
CHANGED
|
@@ -2115,6 +2115,10 @@ offset's `top` (80 by default, so toasts start below that bar):
|
|
|
2115
2115
|
<Toaster position="bottom-center" /> // bottom-center on every screen
|
|
2116
2116
|
```
|
|
2117
2117
|
|
|
2118
|
+
A mounted `StickyActionBar` is cleared automatically (`--nxgt-sticky-bar`). An
|
|
2119
|
+
explicit `offset` or `mobileOffset` drops that, so add
|
|
2120
|
+
`var(--nxgt-sticky-bar, 0px)` to its `bottom` yourself.
|
|
2121
|
+
|
|
2118
2122
|
### A toast never goes away after a tap
|
|
2119
2123
|
|
|
2120
2124
|
**When:** on a phone (or any touch screen), a toast that should time out stays
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nxgt/material",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.91.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"email": "stevegires@gmail.com"
|
|
@@ -390,7 +390,7 @@
|
|
|
390
390
|
"docs:previews": "rm -rf node_modules/.cache/nxgt-preview-free/missing && NXGT_PREVIEW_FREE=1 vitest run --project previews && bun .storybook/preview-free-report.ts"
|
|
391
391
|
},
|
|
392
392
|
"dependencies": {
|
|
393
|
-
"@nxgt/material-core": "^0.
|
|
393
|
+
"@nxgt/material-core": "^0.53.0",
|
|
394
394
|
"@base-ui/react": "^1.6.0",
|
|
395
395
|
"@dnd-kit/core": "^6.3.1",
|
|
396
396
|
"@dnd-kit/sortable": "^10.0.0",
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { t as e } from "./utils-BLfntITJ.js";
|
|
2
|
-
import { n as t } from "./spinner-DcW21pN1.js";
|
|
3
|
-
import { a as n, i as r, n as i } from "./field-blur-context-BLGgf_3z.js";
|
|
4
|
-
import { i as a } from "./translate-material-BrYBBZ66.js";
|
|
5
|
-
import { t as o } from "./use-material-translation-BdrItuwY.js";
|
|
6
|
-
import { t as s } from "./icon-button-DE1EcO2-.js";
|
|
7
|
-
import { t as c } from "./input-CC2joTjB.js";
|
|
8
|
-
import { t as l } from "./text-field-BAdY-kpO.js";
|
|
9
|
-
import { t as u } from "./number.utils-CSueQZcv.js";
|
|
10
|
-
import { useCallback as d, useEffect as f, useId as p, useMemo as m, useRef as h, useState as g } from "react";
|
|
11
|
-
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
12
|
-
import { Minus as y, Plus as b } from "lucide-react";
|
|
13
|
-
import { clampNumber as x, parseNumberInput as S, stepNumber as C } from "@nxgt/material-core/parse-number";
|
|
14
|
-
import { currencyFractionDigits as w } from "@nxgt/material-core/currency-digits";
|
|
15
|
-
//#region lib/components/ui/fields/number-field/number-stepper.tsx
|
|
16
|
-
function T({ hovered: e, focused: t, focusVisible: n }) {
|
|
17
|
-
return e || !t || n;
|
|
18
|
-
}
|
|
19
|
-
function E(e) {
|
|
20
|
-
try {
|
|
21
|
-
return e.matches(":focus-visible");
|
|
22
|
-
} catch {
|
|
23
|
-
return !0;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function D({ direction: e, label: n, disabled: r, onStep: i }) {
|
|
27
|
-
let a = h(null), o = h(!1), [c, l] = g(!1);
|
|
28
|
-
return /* @__PURE__ */ _(t, {
|
|
29
|
-
content: n,
|
|
30
|
-
open: c,
|
|
31
|
-
onOpenChange: (e) => {
|
|
32
|
-
let t = a.current;
|
|
33
|
-
l(e && T({
|
|
34
|
-
hovered: o.current,
|
|
35
|
-
focused: t != null && document.activeElement === t,
|
|
36
|
-
focusVisible: t != null && E(t)
|
|
37
|
-
}));
|
|
38
|
-
},
|
|
39
|
-
children: /* @__PURE__ */ _(s, {
|
|
40
|
-
ref: a,
|
|
41
|
-
variant: "outlined",
|
|
42
|
-
color: "default",
|
|
43
|
-
className: "size-9 shrink-0 rounded-field",
|
|
44
|
-
disabled: r,
|
|
45
|
-
"aria-label": n,
|
|
46
|
-
onPointerEnter: () => {
|
|
47
|
-
o.current = !0;
|
|
48
|
-
},
|
|
49
|
-
onPointerLeave: () => {
|
|
50
|
-
o.current = !1;
|
|
51
|
-
},
|
|
52
|
-
onClick: () => i(e),
|
|
53
|
-
children: _(e < 0 ? y : b, {})
|
|
54
|
-
})
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
function O(e) {
|
|
58
|
-
let { t } = o();
|
|
59
|
-
return e ? {
|
|
60
|
-
decreaseLabel: t("material.number-field.decrease-named", "Decrease {label}", { label: e }),
|
|
61
|
-
increaseLabel: t("material.number-field.increase-named", "Increase {label}", { label: e })
|
|
62
|
-
} : {
|
|
63
|
-
decreaseLabel: t("material.number-field.decrease", "Decrease"),
|
|
64
|
-
increaseLabel: t("material.number-field.increase", "Increase")
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
//#endregion
|
|
68
|
-
//#region lib/components/ui/fields/number-field/format-number-input.ts
|
|
69
|
-
function k(e, t = "en") {
|
|
70
|
-
let n = String(e === 0 ? 0 : e);
|
|
71
|
-
try {
|
|
72
|
-
let r = u(e === 0 ? 0 : e, {
|
|
73
|
-
language: t,
|
|
74
|
-
useGrouping: !1,
|
|
75
|
-
maximumFractionDigits: 20,
|
|
76
|
-
numberingSystem: "latn"
|
|
77
|
-
}), i = S(r);
|
|
78
|
-
return e !== 0 && i !== e ? n : r;
|
|
79
|
-
} catch {
|
|
80
|
-
return n;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
//#endregion
|
|
84
|
-
//#region lib/components/ui/fields/number-field/use-number-input.ts
|
|
85
|
-
function A({ value: e, defaultValue: t, onChange: n, min: r, max: i, step: a, language: o }) {
|
|
86
|
-
let s = (e) => k(e, o), c = e !== void 0, [l, u] = g(t), d = c ? e : l, [p, m] = g(() => d == null ? "" : s(d));
|
|
87
|
-
f(() => {
|
|
88
|
-
c && m((t) => e == null ? t.trim() === "" ? t : "" : S(t) === e ? t : k(e, o));
|
|
89
|
-
}, [
|
|
90
|
-
c,
|
|
91
|
-
e,
|
|
92
|
-
o
|
|
93
|
-
]);
|
|
94
|
-
let _ = h(o);
|
|
95
|
-
f(() => {
|
|
96
|
-
_.current !== o && (_.current = o, m((e) => d != null && S(e) === d ? k(d, o) : e));
|
|
97
|
-
}, [o, d]);
|
|
98
|
-
let v = (e) => {
|
|
99
|
-
c || u(e), n?.(e);
|
|
100
|
-
};
|
|
101
|
-
return {
|
|
102
|
-
draft: p,
|
|
103
|
-
amount: d,
|
|
104
|
-
type: (e) => {
|
|
105
|
-
if (m(e), e.trim() === "") v(null);
|
|
106
|
-
else {
|
|
107
|
-
let t = S(e);
|
|
108
|
-
t != null && v(t);
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
commit: (e) => {
|
|
112
|
-
let t = S(e), n = t == null ? null : x(t, r, i);
|
|
113
|
-
m(n == null ? "" : s(n)), v(n);
|
|
114
|
-
},
|
|
115
|
-
stepBy: (e) => {
|
|
116
|
-
let t = C(d, e, a, r, i);
|
|
117
|
-
m(s(t)), v(t);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
//#endregion
|
|
122
|
-
//#region lib/components/ui/fields/number-field/number-control.tsx
|
|
123
|
-
function j({ error: e, disabled: t, value: n, defaultValue: r = null, onChange: i, onBlur: a, min: s, max: l, step: u = 1, hideSteppers: d = !1, suffix: f, stepperName: p, ...m }) {
|
|
124
|
-
let { language: h } = o(), { draft: g, amount: y, type: b, commit: x, stepBy: S } = A({
|
|
125
|
-
value: n,
|
|
126
|
-
defaultValue: r,
|
|
127
|
-
onChange: i,
|
|
128
|
-
min: s,
|
|
129
|
-
max: l,
|
|
130
|
-
step: u,
|
|
131
|
-
language: h
|
|
132
|
-
}), { decreaseLabel: C, increaseLabel: w } = O(p), T = s != null && y != null && y <= s, E = l != null && y != null && y >= l;
|
|
133
|
-
return /* @__PURE__ */ v("div", {
|
|
134
|
-
className: "flex items-center gap-1",
|
|
135
|
-
children: [
|
|
136
|
-
!d && /* @__PURE__ */ _(D, {
|
|
137
|
-
direction: -1,
|
|
138
|
-
label: C,
|
|
139
|
-
disabled: t || T,
|
|
140
|
-
onStep: S
|
|
141
|
-
}),
|
|
142
|
-
/* @__PURE__ */ _(c, {
|
|
143
|
-
...m,
|
|
144
|
-
inputMode: "decimal",
|
|
145
|
-
autoComplete: "off",
|
|
146
|
-
disabled: t,
|
|
147
|
-
"aria-invalid": e || void 0,
|
|
148
|
-
value: g,
|
|
149
|
-
className: "text-center",
|
|
150
|
-
onChange: (e) => b(e.target.value),
|
|
151
|
-
onBlur: (e) => {
|
|
152
|
-
x(e.target.value), a?.(e);
|
|
153
|
-
}
|
|
154
|
-
}),
|
|
155
|
-
!d && /* @__PURE__ */ _(D, {
|
|
156
|
-
direction: 1,
|
|
157
|
-
label: w,
|
|
158
|
-
disabled: t || E,
|
|
159
|
-
onStep: S
|
|
160
|
-
}),
|
|
161
|
-
f != null && /* @__PURE__ */ _("span", {
|
|
162
|
-
className: "px-1 font-medium text-muted-foreground text-sm",
|
|
163
|
-
children: f
|
|
164
|
-
})
|
|
165
|
-
]
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
//#endregion
|
|
169
|
-
//#region lib/components/ui/fields/number-field/number-field.tsx
|
|
170
|
-
function M({ label: t, helperText: a, error: o, required: s, className: c, name: l, id: u, "aria-describedby": d, ...f }) {
|
|
171
|
-
let m = i(), h = p(), g = u ?? h, y = p();
|
|
172
|
-
return /* @__PURE__ */ v("div", {
|
|
173
|
-
ref: m,
|
|
174
|
-
"data-slot": "number-field",
|
|
175
|
-
"data-pw": l ?? "number-field",
|
|
176
|
-
className: e("grid w-full content-start gap-1.5", c),
|
|
177
|
-
children: [
|
|
178
|
-
t && /* @__PURE__ */ _(r, {
|
|
179
|
-
htmlFor: g,
|
|
180
|
-
withAsterisk: s,
|
|
181
|
-
children: t
|
|
182
|
-
}),
|
|
183
|
-
/* @__PURE__ */ _(j, {
|
|
184
|
-
...f,
|
|
185
|
-
id: g,
|
|
186
|
-
name: l,
|
|
187
|
-
stepperName: typeof t == "string" && t ? t : f["aria-label"] || void 0,
|
|
188
|
-
error: o,
|
|
189
|
-
required: s,
|
|
190
|
-
"aria-describedby": [a ? y : void 0, d].filter(Boolean).join(" ") || void 0
|
|
191
|
-
}),
|
|
192
|
-
a && /* @__PURE__ */ _(n, {
|
|
193
|
-
id: y,
|
|
194
|
-
error: o,
|
|
195
|
-
children: a
|
|
196
|
-
})
|
|
197
|
-
]
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
//#endregion
|
|
201
|
-
//#region lib/components/ui/fields/currency-field/parse-currency.ts
|
|
202
|
-
function N(e) {
|
|
203
|
-
let t = e.trim().replace(/[\s\u00a0]/g, "");
|
|
204
|
-
if (!t) return null;
|
|
205
|
-
let n = t.lastIndexOf(",") > t.lastIndexOf(".") ? t.replace(/\./g, "").replace(",", ".") : t.replace(/,/g, ""), r = Number(n);
|
|
206
|
-
return Number.isFinite(r) ? r : null;
|
|
207
|
-
}
|
|
208
|
-
//#endregion
|
|
209
|
-
//#region lib/components/ui/fields/currency-field/use-currency-amount.ts
|
|
210
|
-
function P(e, t, n) {
|
|
211
|
-
return u(e, {
|
|
212
|
-
language: n,
|
|
213
|
-
minimumFractionDigits: t,
|
|
214
|
-
maximumFractionDigits: t
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
function F({ value: e, defaultValue: t, onChange: n, currency: r, fractionDigits: i }) {
|
|
218
|
-
let o = m(() => w(r, i), [r, i]), s = a()?.language, c = e !== void 0, [l, u] = g(t), p = c ? e : l, _ = h(null), v = d((e) => {
|
|
219
|
-
let t = P(e, o, s);
|
|
220
|
-
return _.current = {
|
|
221
|
-
text: t,
|
|
222
|
-
value: e
|
|
223
|
-
}, t;
|
|
224
|
-
}, [o, s]), [y, b] = g(() => p == null ? "" : v(p));
|
|
225
|
-
f(() => {
|
|
226
|
-
c && b((t) => e == null ? "" : N(t) === e || _.current?.text === t && _.current.value === e ? t : v(e));
|
|
227
|
-
}, [
|
|
228
|
-
c,
|
|
229
|
-
e,
|
|
230
|
-
v
|
|
231
|
-
]);
|
|
232
|
-
let x = h(p);
|
|
233
|
-
x.current = p, f(() => {
|
|
234
|
-
let e = x.current;
|
|
235
|
-
b(e == null ? "" : v(e));
|
|
236
|
-
}, [v]);
|
|
237
|
-
let S = (e) => {
|
|
238
|
-
c || u(e), n?.(e);
|
|
239
|
-
};
|
|
240
|
-
return {
|
|
241
|
-
draft: y,
|
|
242
|
-
change: (e) => {
|
|
243
|
-
b(e);
|
|
244
|
-
let t = N(e);
|
|
245
|
-
e.trim() === "" ? S(null) : t != null && S(t);
|
|
246
|
-
},
|
|
247
|
-
commit: (e) => {
|
|
248
|
-
let t = e.trim(), n = _.current?.text === t ? _.current.value : N(e);
|
|
249
|
-
b(n == null ? t : v(n)), S(n);
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
//#endregion
|
|
254
|
-
//#region lib/components/ui/fields/currency-field/currency-field.tsx
|
|
255
|
-
function I({ value: t, defaultValue: n = null, onChange: r, currency: i = "EUR", fractionDigits: a, trailingAction: o, className: s, ...c }) {
|
|
256
|
-
let { draft: u, change: d, commit: f } = F({
|
|
257
|
-
value: t,
|
|
258
|
-
defaultValue: n,
|
|
259
|
-
onChange: r,
|
|
260
|
-
currency: i,
|
|
261
|
-
fractionDigits: a
|
|
262
|
-
});
|
|
263
|
-
return /* @__PURE__ */ _(l, {
|
|
264
|
-
...c,
|
|
265
|
-
className: e(o && "[&_input]:pr-28!", s),
|
|
266
|
-
inputMode: "decimal",
|
|
267
|
-
autoComplete: "off",
|
|
268
|
-
spellCheck: !1,
|
|
269
|
-
value: u,
|
|
270
|
-
trailing: o ? /* @__PURE__ */ v("span", {
|
|
271
|
-
"data-slot": "currency-trailing",
|
|
272
|
-
className: "flex h-8! w-auto! items-center gap-1 bg-transparent! pointer-coarse:h-11! ps-1 pe-1.5 text-xs font-medium text-muted-foreground",
|
|
273
|
-
children: [i, o]
|
|
274
|
-
}) : /* @__PURE__ */ _("span", {
|
|
275
|
-
"data-slot": "currency-code",
|
|
276
|
-
className: "flex h-8! w-auto! items-center justify-center bg-transparent! px-1 text-xs leading-none font-medium text-muted-foreground pointer-coarse:h-11!",
|
|
277
|
-
children: i
|
|
278
|
-
}),
|
|
279
|
-
onChange: (e) => d(e.target.value),
|
|
280
|
-
onBlur: (e) => {
|
|
281
|
-
f(e.target.value), c.onBlur?.(e);
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
//#endregion
|
|
286
|
-
export { x as a, j as i, N as n, S as o, M as r, C as s, I as t };
|