@nxgt/material 3.74.0 → 3.75.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 +48 -0
- package/README.md +7 -6
- package/dist/{background-D1gC4m2R.js → background-Q4Ek3rNy.js} +3 -1
- package/dist/backgrounds/css-react/celestial-day.css +85 -0
- package/dist/backgrounds/css-react/celestial.css +11 -11
- package/dist/backgrounds.js +1 -1
- package/dist/components/ui/collections/data-table/data-table-items-actions.css +37 -0
- package/dist/components/ui/collections/data-table/data-table-items-chevron.css +28 -0
- package/dist/components/ui/collections/data-table/data-table-items-tiles.css +7 -0
- package/dist/components/ui/collections/data-table/index.css +5 -1
- package/dist/components/ui/display/secret-card/secret-card.css +5 -1
- package/dist/components/ui/feedback/celebration/celebration.css +49 -0
- package/dist/components/ui/feedback/feedback.css +2 -0
- package/dist/{components-y18qSFzl.js → components-zJdfH4im.js} +17017 -16856
- package/dist/components.js +25 -25
- package/dist/editor.js +1 -1
- package/dist/lib/backgrounds/background/available.d.ts +4 -4
- package/dist/lib/backgrounds/background/background.d.ts +1 -1
- package/dist/lib/backgrounds/background/types.d.ts +1 -1
- package/dist/lib/components/ui/collections/data-table/layout-types.d.ts +13 -0
- package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-item-actions.d.ts +12 -0
- package/dist/lib/components/ui/collections/data-table/partials/layouts/data-table-item-title.d.ts +2 -1
- package/dist/lib/components/ui/collections/data-table/select-checkbox.d.ts +2 -1
- package/dist/lib/components/ui/collections/server-table/partials/server-table-band-classes.d.ts +3 -2
- package/dist/lib/components/ui/collections/server-table/server-table-classes.d.ts +8 -2
- package/dist/lib/components/ui/collections/server-table/types.d.ts +4 -0
- package/dist/lib/components/ui/display/change-history/partials/changes-collapse.d.ts +2 -1
- package/dist/lib/components/ui/display/secret-card/types.d.ts +6 -0
- package/dist/lib/components/ui/feedback/celebration/celebration.d.ts +24 -0
- package/dist/lib/components/ui/feedback/celebration/index.d.ts +1 -0
- package/dist/lib/components/ui/feedback/countdown-timer/countdown-ring.d.ts +1 -1
- package/dist/lib/components/ui/feedback/countdown-timer/countdown-timer.d.ts +2 -1
- package/dist/lib/components/ui/feedback/index.d.ts +1 -0
- package/dist/lib/components/ui/fields/number-field/number-stepper.d.ts +11 -0
- package/dist/lib/components/ui/fields/quantity-field/quantity-row.d.ts +8 -0
- package/dist/lib/components/ui/primitives/tabs/tabs-overflow-classes.d.ts +1 -1
- package/dist/lib/components/ui/selection/chip-group-field/chip-group-field.d.ts +2 -2
- package/dist/lib/components/ui/selection/chip-group-field/partials/chip-group-option.d.ts +5 -3
- package/dist/lib/components/ui/selection/choice-group/choice-group-root.d.ts +3 -1
- package/dist/lib/components/ui/widgets/chat/chat-thread-header-parts.d.ts +17 -0
- package/dist/lib/components/ui/widgets/chat/chat-thread-header.d.ts +9 -3
- package/dist/lib/components/ui/widgets/chat/proposal/chat-tool-activity.d.ts +3 -1
- package/dist/lib/illustrations-game/index.d.ts +6 -5
- package/dist/main.js +39 -39
- package/dist/material.css +1 -1
- package/dist/{use-chat-composer-Cn6yaeO0.js → use-chat-composer-BvWQogJe.js} +2030 -2021
- package/docs/components/data-display.md +2 -1
- package/docs/components/data-table-filter-and-lists.md +14 -3
- package/docs/components/feedback-and-status.md +30 -2
- package/docs/components/form-fields.md +13 -1
- package/docs/components/navigation-and-layout.md +1 -1
- package/docs/components/primitives.md +2 -2
- package/docs/components/rich-widgets.md +3 -2
- package/docs/components/selection-and-choice.md +3 -3
- package/docs/getting-started.md +1 -1
- package/docs/guides/app-shell.md +1 -1
- package/docs/guides/backgrounds.md +23 -11
- package/docs/guides/cards-and-tiles.md +42 -3
- package/docs/guides/icon-motifs.md +7 -7
- package/docs/guides/illustrations.md +6 -5
- package/docs/guides/theming.md +1 -1
- package/docs/previews/backgrounds-day-and-dawn-sky.webp +0 -0
- package/docs/previews/feedback-status-illustration-game.webp +0 -0
- package/docs/troubleshooting.md +40 -2
- package/lib/backgrounds/css-react/celestial-day.css +85 -0
- package/lib/backgrounds/css-react/celestial.css +11 -11
- package/lib/components/ui/collections/data-table/data-table-items-actions.css +37 -0
- package/lib/components/ui/collections/data-table/data-table-items-chevron.css +28 -0
- package/lib/components/ui/collections/data-table/data-table-items-tiles.css +7 -0
- package/lib/components/ui/collections/data-table/index.css +5 -1
- package/lib/components/ui/display/secret-card/secret-card.css +5 -1
- package/lib/components/ui/feedback/celebration/celebration.css +49 -0
- package/lib/components/ui/feedback/feedback.css +2 -0
- package/lib/theme-picker/theme-picker.css +1 -0
- package/lib/theme-picker/theme-tile-textures-day.css +43 -0
- package/lib/themes/teal.css +20 -18
- package/package.json +6 -2
|
@@ -231,6 +231,7 @@ import { Button, SecretCard } from '@nxgt/material/components';
|
|
|
231
231
|
| `revealed` + `onRevealedChange` | `boolean` + `(revealed) => void` | - | controlled |
|
|
232
232
|
| `defaultRevealed`, `onRevealedChange` | `boolean`, `(revealed) => void` | `false` | uncontrolled; never together with `revealed` |
|
|
233
233
|
| `autoHideMs` | `number` | - | hides again after this long shown; also calls `onRevealedChange(false)` |
|
|
234
|
+
| `size` | `'default' \| 'sm'` | `'default'` | `sm` is the compact card for a phone: the faces lose their 6rem minimum height, the padding and gap tighten (`data-size`) |
|
|
234
235
|
| `disabled` | `boolean` | `false` | the card cannot be revealed; a revealed card can always be hidden |
|
|
235
236
|
| `labels` | `Partial<{ reveal, revealed, hidden }>` | `material.secret-card.*` | the button's name ("Show secret") and the announcements |
|
|
236
237
|
|
|
@@ -1299,7 +1300,7 @@ yours, the component names no domain.
|
|
|
1299
1300
|
| `kinds` | `Record<string, ChangeHistoryKindOverride>` | built-ins | `label`, `verb`, `icon` (`null` removes it), `tone` per kind; `creation` (default true for `created`) makes an entry list values only |
|
|
1300
1301
|
| `variant` | `'rail' \| 'cards'` | `'rail'` | the look |
|
|
1301
1302
|
| `groupBy` | `'day' \| 'none'` | `'day'` | a heading per day (sticky on the rail), or one list in the order given |
|
|
1302
|
-
| `collapseAfter` | `number` | `3` | an entry with more changes collapses behind "N fields changed" (a creation: "N fields set") and a preview of the names, as a button with `aria-expanded
|
|
1303
|
+
| `collapseAfter` | `number` | `3` | an entry with more changes collapses behind "N fields changed" (a creation: "N fields set") and a preview of the first three names, as a button with `aria-expanded`. The preview wraps instead of clipping with an ellipsis, and a screen reader hears the names behind the "+N" |
|
|
1303
1304
|
| `filter` | `ReactNode` | — | a slot above the list, for a `Filter` bar |
|
|
1304
1305
|
| `loading` | `boolean` | `false` | skeleton entries |
|
|
1305
1306
|
| `hasMore` | `boolean` | — | shows the Load more button |
|
|
@@ -96,8 +96,8 @@ table enables, for typing your own column defs.
|
|
|
96
96
|
| `data` | `T[]` | — | rows; sorting, filtering and pagination run client-side |
|
|
97
97
|
| `layout` | `'table' \| 'cards' \| 'tiles' \| { phone, wide }` | `'table'` | `'cards'` lays the rows out as a list of cards, `'tiles'` as one column in a single surface ([Cards and tiles](../guides/cards-and-tiles.md)); both ignore `virtual`, `renderExpandedRow` and `showViewOptions` |
|
|
98
98
|
| `cardDensity` | `'comfortable' \| 'compact'` | `'comfortable'` | `compact` fits cards of at least `--nxgt-cards-min` (15rem), up to four a row, with a tighter padding; `layout="cards"` only ([Cards and tiles](../guides/cards-and-tiles.md#columns)) |
|
|
99
|
-
| `renderCard` | `(row, { Title, Row, selected, locked, reason }) => ReactNode` | — | a card's content, required with `layout="cards"`; `Title` is the card's one link and its name; `Row` (the compact record row) is also passed, laid out inside the card's own padding, with no height of its own |
|
|
100
|
-
| `renderTile` | `(row, { Title, Row, selected, locked, reason }) => ReactNode` | — | a tile's content, required with `layout="tiles"`; same `Title` as a card, or `Row`, the compact record row (title, subtitle, chips, trailing facts; see the cards and tiles guide) |
|
|
99
|
+
| `renderCard` | `(row, { Title, Actions, Row, selected, locked, reason }) => ReactNode` | — | a card's content, required with `layout="cards"`; `Title` is the card's one link and its name; `Actions` is the trailing action slot (outside the link, at least 44px); `Row` (the compact record row) is also passed, laid out inside the card's own padding, with no height of its own |
|
|
100
|
+
| `renderTile` | `(row, { Title, Actions, Row, selected, locked, reason }) => ReactNode` | — | a tile's content, required with `layout="tiles"`; same `Title` as a card, or `Row`, the compact record row (title, subtitle, chips, trailing facts; see the cards and tiles guide) |
|
|
101
101
|
| `renderExpandedRow` | `(row) => ReactNode` | — | makes rows expandable; pair with the `expand` column |
|
|
102
102
|
| `showViewOptions` | `boolean` | — | column visibility menu above the table |
|
|
103
103
|
| `actions` | `(table, controls) => ReactNode` | — | toolbar content with access to the table (selected rows…); disabled while `loading`. `controls.focusTable()` moves the focus to the table |
|
|
@@ -1042,6 +1042,7 @@ Its props are `ServerTableProps<T>`; `filter` is a `ServerTableFilter`,
|
|
|
1042
1042
|
| `loadMoreLabel` | `string` | "Load more" | with `footer="load-more"`: the button's label |
|
|
1043
1043
|
| `hideOnSinglePage` | `boolean` | `false` | hides the footer's range and Previous / Next when the result is one page (no previous, no next), in the table, cards and tiles layouts; the count is still announced by the live region but no longer shown, so put it in `description` or keep the footer. With `bulkActions` the footer stays for "N rows selected", without its pager |
|
|
1044
1044
|
| `bandActions` | `'stacked' \| 'inline'` | `'stacked'` | with `filter`, where `actions` sit below 768px: `'stacked'` gives them a row above the search; `'inline'` keeps them on the search's row (the search takes the room left), for a lone icon action such as a "+". An action wider than 3.5rem wraps under the search. From 768px both are the same. With a cards or tiles list on a phone, neither applies: [the two-row header](#the-phone-header-of-a-list-in-cards-or-tiles) puts the actions on its second row |
|
|
1045
|
+
| `surface` | `'card' \| 'none'` | `'card'` | the list's own surface: `'card'` a translucent background and 16px of padding (below 768px neither: the layout owns the page gutter and the tiles sit at it, so a `ServerTable` outside a layout that adds a gutter now sits flush with the screen edge below 768px and the caller wraps it in its own padding); `'none'` neither, for a `ServerTable` placed in a `Card`, a page section or any surface that already frames it, so the screen shows one surface, not a frame inside a frame (the tiles keep their own grouped border) |
|
|
1045
1046
|
| `filterRef` | `Ref<ServerTableFilterHandle>` | — | with `filter`: `filterRef.current.focus()` focuses the Filter's first control, the search, else the first quick filter, "Add filter" or "Filters (N)" the width shows |
|
|
1046
1047
|
| `sorting` | `createSorting(…)` | — | headers sorted from the URL; without it, no column is sortable (the server sorts, so pass `sorting` to let people sort), and the phone list bar shows only for selection |
|
|
1047
1048
|
| `filters` | `tableFilters(model)` | — | without `filter`: "nothing matches" and its clear |
|
|
@@ -1054,7 +1055,17 @@ Its props are `ServerTableProps<T>`; `filter` is a `ServerTableFilter`,
|
|
|
1054
1055
|
| `pageHref` | `(params) => string` | `` `?${params}` `` | Previous / Next hrefs |
|
|
1055
1056
|
| `pagingNames` | `{ after?, trail? }` | `after`, `trail` | the cursor's params |
|
|
1056
1057
|
| `resultsLabel` | `(count) => string` | "N results" | without `filter`: what the list's region says. The page past the last has its own words: `material.server-table.past-end`, `past-end-hint`, `first-page` and `past-end-status` |
|
|
1057
|
-
| `className` | `string` | — | on the list's surface |
|
|
1058
|
+
| `className` | `string` | — | on the list's surface (below 768px the list has no padding or background of its own) |
|
|
1059
|
+
|
|
1060
|
+
A `ServerTable` in a `Card` shows one surface with `surface="none"`:
|
|
1061
|
+
|
|
1062
|
+
```tsx
|
|
1063
|
+
<Card>
|
|
1064
|
+
<CardContent>
|
|
1065
|
+
<ServerTable {...props} surface="none" />
|
|
1066
|
+
</CardContent>
|
|
1067
|
+
</Card>
|
|
1068
|
+
```
|
|
1058
1069
|
|
|
1059
1070
|
```tsx
|
|
1060
1071
|
// A lone icon action stays on the search's row on a phone.
|
|
@@ -14,6 +14,7 @@ centre.
|
|
|
14
14
|
| <img src="../previews/feedback-status-stepupdialog.webp" width="96" alt=""> | [StepUpDialog](#stepupdialog) | "Confirm it's you": a dialog that asks for a one-time code, driven by props |
|
|
15
15
|
| <img src="../previews/feedback-status-unsaveddialog.webp" width="96" alt=""> | [UnsavedDialog](#unsaveddialog) | "Leave without saving?": a destructive confirm with Stay focused, used by the unsaved-changes guards |
|
|
16
16
|
| <img src="../previews/feedback-status-stalenotice.webp" width="96" alt=""> | [StaleNotice](#stalenotice) | "This record changed": a warning that another write came first, with one Reload action and no overwrite |
|
|
17
|
+
| | [Celebration](#celebration) | A one-shot confetti burst for a win or a reveal: plays once, never loops, theme colours, nothing under reduced motion |
|
|
17
18
|
| | [Moment](#moment) | A full-screen one-off announcement (a player is eliminated, a role revealed): illustration, title, description and action, dismissed by Escape, a tap, its action or a timer |
|
|
18
19
|
| <img src="../previews/feedback-status-emptystate.webp" width="96" alt=""> | [EmptyState](#emptystate) | Illustration, title, description and action, by kind (empty, search, not-found, unauthorized) |
|
|
19
20
|
| <img src="../previews/feedback-status-pageloadfailed.webp" width="96" alt=""> | [PageLoadFailed](#pageloadfailed) | An empty state for a page opened at a cursor that failed, with a link back to the start |
|
|
@@ -523,6 +524,30 @@ import { UnsavedDialog } from '@nxgt/material/components';
|
|
|
523
524
|
|
|
524
525
|
---
|
|
525
526
|
|
|
527
|
+
## Celebration
|
|
528
|
+
|
|
529
|
+
A one-shot confetti burst for a win or a reveal. It plays once when it mounts and again only when `trigger` changes. It never loops: the pieces fly out, fall and fade once, then are removed from the DOM. They are painted with theme tokens (`--primary`, `--secondary`, `--success`, `--info`, `--warning`), sit in a full-screen layer that ignores the pointer, and are `aria-hidden`. Under `prefers-reduced-motion` it renders nothing; it renders nothing on the server either.
|
|
530
|
+
|
|
531
|
+
```tsx
|
|
532
|
+
import { Celebration } from '@nxgt/material/components';
|
|
533
|
+
|
|
534
|
+
{winner && <Celebration trigger={round} onComplete={() => startNextRound()} />}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
| Prop | Type | Default | Effect |
|
|
538
|
+
| --- | --- | --- | --- |
|
|
539
|
+
| `trigger` | `unknown` | — | plays the burst again when its value changes |
|
|
540
|
+
| `pieces` | `number` | `48` | how many pieces fly out |
|
|
541
|
+
| `duration` | `number` (ms) | `2400` | length of one burst |
|
|
542
|
+
| `onComplete` | `() => void` | — | called once when a burst has ended |
|
|
543
|
+
| `className` | `string` | — | on the full-screen layer |
|
|
544
|
+
|
|
545
|
+
It is decorative: say what happened in text (a `Moment`, an alert). It pairs with `Moment` for a win screen.
|
|
546
|
+
|
|
547
|
+
**Storybook:** `Feedback & status/Celebration` · **Vue:** not yet (#2272)
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
526
551
|
## Moment
|
|
527
552
|
|
|
528
553
|
A transient full-screen announcement for a dramatic one-off event: a player is eliminated, a role is revealed. It is a modal dialog named by its `title` (and described by its `description`), so a screen reader announces it as it opens. Focus moves into it and goes back to the element that had it when it closes; the page behind is inert. Escape, a tap anywhere, the close button and the `action` dismiss it, and so does `duration`. It fades in and its picture pops in; under `prefers-reduced-motion` both stop. The surface is the tone's container with the foreground colour on it, so it holds AA in light and dark, and it fills a phone.
|
|
@@ -558,7 +583,7 @@ import { Illustration } from '@nxgt/material/illustrations';
|
|
|
558
583
|
|
|
559
584
|
A tap anywhere dismisses, so keep text a reader must act on out of a short `duration`. Without a `description` the dialog is described by the hint `material.moment.hint` ("Press Escape or tap to dismiss."), read by assistive technology only. The close button is named by `material.buttons.close`.
|
|
560
585
|
|
|
561
|
-
**Storybook:** `Feedback & status/Moment` · **Vue:** not yet (
|
|
586
|
+
**Storybook:** `Feedback & status/Moment` · **Vue:** not yet (#2248)
|
|
562
587
|
|
|
563
588
|
---
|
|
564
589
|
|
|
@@ -895,6 +920,9 @@ import { CountdownTimer } from '@nxgt/material/components';
|
|
|
895
920
|
// `criticalAt`); change (both tones) or hide the words:
|
|
896
921
|
<CountdownTimer duration={300} warningText="Hurry up" />;
|
|
897
922
|
<CountdownTimer duration={300} warningText={false} />;
|
|
923
|
+
|
|
924
|
+
// The focal point of a screen:
|
|
925
|
+
<CountdownTimer duration={300} size="lg" />;
|
|
898
926
|
```
|
|
899
927
|
|
|
900
928
|
| Prop | Type | Default | Effect |
|
|
@@ -905,7 +933,7 @@ import { CountdownTimer } from '@nxgt/material/components';
|
|
|
905
933
|
| `warningAt` / `criticalAt` | `number` | a quarter (≤ 60 s) / a tenth (≤ 10 s) | the seconds left when it turns amber / red |
|
|
906
934
|
| `label` | `string` | `'Time remaining'` | its name |
|
|
907
935
|
| `warningText` | `string \| false` | `'Little time left'` / `'Almost out of time'` | the words shown with a clock icon in the warning and critical tones, so low time is not told by colour alone; a string replaces both phrases; `false` hides them |
|
|
908
|
-
| `size` | `'sm' \| 'md'` | `'md'` | 28 or
|
|
936
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 28, 36 or 56 px high; `lg` is for a countdown that is the focal point of a screen (centred in a ring of seats, a full-screen exam) |
|
|
909
937
|
|
|
910
938
|
It ticks on the client only: the server renders the full time. The clock is a
|
|
911
939
|
`role="timer"`; a polite live region speaks only when a threshold is crossed
|
|
@@ -587,6 +587,13 @@ plain-text `label`, else from `aria-label`; with neither (a field named only
|
|
|
587
587
|
through `aria-labelledby` included), the buttons keep the bare "Increase" /
|
|
588
588
|
"Decrease".
|
|
589
589
|
|
|
590
|
+
**Stepper tooltips.** Each +/− button shows its name in a tooltip on hover and
|
|
591
|
+
on keyboard focus (`:focus-visible`). Focus that a script moves onto it, such
|
|
592
|
+
as a `Sheet` or `Dialog` putting its initial focus on the first tabbable
|
|
593
|
+
control, does not open the tooltip once the user has used the pointer (the browser does not treat that focus as `:focus-visible`), so it does not cover the field's label. The
|
|
594
|
+
buttons stay in the tab order and keep their accessible names. `QuantityField`
|
|
595
|
+
shares this (React only; the Vue steppers are unchanged, #2264).
|
|
596
|
+
|
|
590
597
|
**Decimal separator.** After blur (and after +/−) the value is shown with the
|
|
591
598
|
active language's separator, from `I18nProvider`: `1,5` in French, `1.5` in
|
|
592
599
|
English (no grouping, so it stays editable). Typing accepts both: `1,5` and
|
|
@@ -670,7 +677,7 @@ Without a form library, `QuantityField` takes `value` and `onChange` (or
|
|
|
670
677
|
`defaultValue`). The number is the one `NumberField` has: the language's
|
|
671
678
|
decimal separator, `min`, `max` and `step` (clamped on blur), and steppers
|
|
672
679
|
named after the field ("Increase Dose"). Both parts stay on one line on a
|
|
673
|
-
phone: the number shrinks, the unit
|
|
680
|
+
phone: the number shrinks, the unit is sized to its longest label (see Unit width below).
|
|
674
681
|
|
|
675
682
|
| Prop | Type | Default | What it does |
|
|
676
683
|
| --- | --- | --- | --- |
|
|
@@ -690,6 +697,11 @@ phone: the number shrinks, the unit keeps a fixed 7rem.
|
|
|
690
697
|
is a textbox named after the label, the unit a combobox (or, with
|
|
691
698
|
`allowCustomUnit`, a text input) named "Dose unit". The message describes
|
|
692
699
|
the group, the number and the unit, and both are `aria-invalid` on an error.
|
|
700
|
+
- **Unit width:** the unit part is sized to the longest label of `units`
|
|
701
|
+
(never under 7rem, never over 55% of the row, so the number keeps room at
|
|
702
|
+
360px). Beyond the cap the label is cut with an ellipsis and the full label
|
|
703
|
+
is the select's `title` (the `units` select only; a free unit typed past
|
|
704
|
+
the cap scrolls in its input). No inline style is used for it.
|
|
693
705
|
- **Translations:** `material.quantity-field.unit` and `.unit-named` (English
|
|
694
706
|
and French) name the unit part.
|
|
695
707
|
|
|
@@ -987,7 +987,7 @@ import { Background, Card } from '@nxgt/material/components';
|
|
|
987
987
|
It fills the viewport; pass a `className` such as `h-96 w-full` to use it as a band.
|
|
988
988
|
It is plain CSS from `styles.css`, with no inline `style`, and its colours lift
|
|
989
989
|
in dark. `ActivityLayout` and `ThreadLayout` sit on it. The superset with `grain`,
|
|
990
|
-
`seed`, `fill`, `motif` and the other presets (light, geometry and motif families) is `Background` from `/backgrounds`; see the [backgrounds guide](../guides/backgrounds.md). Light presets there: `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `grain`; geometry: `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`; motifs: `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport`, `moon`; sky: `eclipse`, `meteor-shower`, `ringed-planet`, `northern-lights`, or the `sky` prop to lay the moon or one of them over any preset.
|
|
990
|
+
`seed`, `fill`, `motif` and the other presets (light, geometry and motif families) is `Background` from `/backgrounds`; see the [backgrounds guide](../guides/backgrounds.md). Light presets there: `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `grain`; geometry: `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`; motifs: `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport`, `moon`; sky: `eclipse`, `meteor-shower`, `ringed-planet`, `northern-lights`, `day-sky`, `dawn-sky`, or the `sky` prop to lay the moon or one of them over any preset.
|
|
991
991
|
|
|
992
992
|
**Storybook:** `Navigation & layout/Background` · **Vue:** `Background`
|
|
993
993
|
|
|
@@ -739,8 +739,8 @@ reached with the arrow keys. The list scrolls sideways when the tabs do not
|
|
|
739
739
|
fit (its scrollbar hidden), which suits a phone or a narrow popover. While it
|
|
740
740
|
overflows, each side with hidden tabs fades and gets a small scroll button
|
|
741
741
|
("Scroll tabs left" / "Scroll tabs right", from `material.tabs.*`; out of the
|
|
742
|
-
tab order; on a touch screen 44px wide and as tall as the list, so it never covers content); the selected and the focused tab are
|
|
743
|
-
scrolled into view, instantly under reduced motion. A list that fits has
|
|
742
|
+
tab order; on a touch screen 44px wide and as tall as the list, so it never covers content). Under a button the list shows nothing (its edge mask is transparent there and fades in just beyond), so no label is ever cut by the button, even at 375px; the selected and the focused tab are
|
|
743
|
+
scrolled into view clear of the button, instantly under reduced motion. A list that fits has
|
|
744
744
|
neither, and neither is in the server markup. `segmented` does the same.
|
|
745
745
|
|
|
746
746
|
**`segmented`** is a neutral pill track: the active tab sits on a raised
|
|
@@ -135,7 +135,7 @@ import {
|
|
|
135
135
|
| `ChatActionProposal` `busy` / `disabled` | `boolean` | `false` | an answer is being sent (both disabled, Confirm spins) / a read-only viewer |
|
|
136
136
|
| `ChatActionProposal` `deadline` | `Date \| string \| number` | — | "Respond by …" in a `<time>`, in the active language; `expired` says "Expired on" |
|
|
137
137
|
| `ChatActionProposal` `failureCode` / `failureMessage` | `string` / `ReactNode` | — | a `failed` card's reason, in an `alert`, with the code |
|
|
138
|
-
| `ChatToolActivity` `name` / `state` / `detail` | `ReactNode` / `'running' \| 'ok' \| 'failed'` / `ReactNode` | — / `'running'` | one compact row for a tool step in a `ChatMessageList`: the name in mono, Running (spinner), Done or Failed |
|
|
138
|
+
| `ChatToolActivity` `name` / `nameText` / `state` / `detail` | `ReactNode` / `string` / `'running' \| 'ok' \| 'failed'` / `ReactNode` | — / — / `'running'` | one compact row for a tool step in a `ChatMessageList`: the name in mono, wrapped onto two lines at most with its full text in a `title` (`nameText` gives it when `name` is a node), then Running (spinner), Done or Failed |
|
|
139
139
|
| `ChatThread` / `ChatMessageList` `layout` | `'bubbles' \| 'flat'` | `'bubbles'` | a messenger's bubbles, or a team chat's rows (name and time over each run) |
|
|
140
140
|
| `ChatThread` / `ChatMessageList` `density` | `'comfortable' \| 'compact'` | `'comfortable'` | tighter bubbles, smaller avatars |
|
|
141
141
|
| `ChatMessageList` `viewportProps` | `ComponentProps` of the viewport | `{ tabIndex: 0 }` | attributes of the scrolling element; it is a tab stop so the keyboard can scroll the transcript (`tabIndex: -1` opts out) |
|
|
@@ -148,8 +148,9 @@ import {
|
|
|
148
148
|
| `ChatComposer` `onStop` | `() => void` | — | while `isLoading`, send becomes stop (an assistant answering) |
|
|
149
149
|
| `ChatComposer` `sendOnEnter` | `boolean` | `true` | Enter sends and Shift+Enter breaks the line; `false`: Ctrl/⌘+Enter sends. Never while an IME composes |
|
|
150
150
|
| `ChatComposer` `emojis` / `mentions` | `EmojiItem[]` / `MentionItem[]` | — | enables the emoji picker and the `@` list |
|
|
151
|
-
| `ChatThreadHeader` | `title`, `subtitle`, `avatarSrc`, `status`, `actions`, `onBack` | — | the title bar; inside a `ChatInbox` it carries the back button on a narrow screen |
|
|
151
|
+
| `ChatThreadHeader` | `title`, `subtitle`, `titleText`, `subtitleText`, `avatarSrc`, `status`, `actions`, `onBack` | — | the title bar; inside a `ChatInbox` it carries the back button on a narrow screen. The title is clamped to two lines and the subtitle truncated, each with its full text in a `title` attribute; `titleText` / `subtitleText` give that text when `title` / `subtitle` is a node |
|
|
152
152
|
| `ChatConversationItem` `title` / `titleText` | `ReactNode` / `string` | — | the clipped title carries its full text in a `title` attribute when it is a string; `titleText` gives it when `title` is a node |
|
|
153
|
+
| `ChatConversationItem` width | — | — | fills its container (`w-full`) and has no intrinsic width (`contain: inline-size`), so a long title never widens an auto-sized grid track and the timestamp stays whole; a shrink-to-fit parent (`w-fit`, `max-content`, an inline-flex wrapper, a popover sized to content) must give it a width |
|
|
153
154
|
| `ChatConversationItem` `status` / `isTyping` | `StatusTone` / `boolean` | — | presence dot; "Typing…" instead of the preview |
|
|
154
155
|
| `ChatInbox` `pane` / `defaultPane` | `'list' \| 'thread'` | `'list'` | which pane shows below the `@md` container width |
|
|
155
156
|
| `ChatWidget` `open` / `defaultOpen` / `onOpenChange` | `boolean` | `false` | the floating launcher's panel (full screen below `sm`); `unreadCount` on the launcher, `side`, `strategy` |
|
|
@@ -846,7 +846,7 @@ export function Topics() {
|
|
|
846
846
|
| `options` | `{ value; label; icon?; count?; description?; disabled?; disabledReason? }[]` | — | the chips, in one flow; `count`: see [option counts](#option-counts) |
|
|
847
847
|
| `groups` | `{ label: string; options }[]` | — | titled sections instead of `options` (it wins when both are given): see [slot picker](#slot-picker-columns-groups-and-reasons) |
|
|
848
848
|
| `columns` | `number \| { base?; sm?; md?; lg? }` | — | equal-width columns (1 to 12; one count per breakpoint, each holding to the next); Up and Down then move by row. Unset, the chips flow and wrap |
|
|
849
|
-
| `showDisabledReason` | `boolean` | `true` | prints a disabled option's `disabledReason`
|
|
849
|
+
| `showDisabledReason` | `boolean` | `true` | prints a disabled option's `disabledReason` below the whole group ("Label: reason"), so the chip row keeps its wrapping; `false` leaves it to the tooltip and the accessible description |
|
|
850
850
|
| `size` | `'default' \| 'sm' \| 'lg'` | `'default'` | the chip's size: 28px, 24px, or `lg`, a 44px box at every pointer (a coarse pointer already gets a 44px box at any size) |
|
|
851
851
|
| `name` | `string` | — | put on every chip (`ChipGroupFormField` passes its field `name`), so `document.getElementsByName(name)` finds the group's chips in order |
|
|
852
852
|
| `label`, `helperText`, `error`, `required`, `disabled`, `id` | | — | the question and its help or error text, the required mark, disabling every chip, the group's `id` |
|
|
@@ -894,7 +894,7 @@ export function Slots() {
|
|
|
894
894
|
}
|
|
895
895
|
```
|
|
896
896
|
|
|
897
|
-
- **Disabled reason.** The reason is a small muted line
|
|
897
|
+
- **Disabled reason.** The reason is a small muted line below the whole group, as "Label: reason" (not
|
|
898
898
|
only a tooltip), and the chip points to it with `aria-describedby`, so a
|
|
899
899
|
screen reader says "09:30, Taken". The chip stays `aria-disabled`, not
|
|
900
900
|
`disabled`: arrows still land on it and a press does nothing. The "up to N"
|
|
@@ -918,7 +918,7 @@ single mode), Home and End jump, and the arrows follow `dir="rtl"`; Space toggle
|
|
|
918
918
|
mode; Enter does nothing, so it never submits a surrounding form. One chip holds
|
|
919
919
|
the tab stop. A disabled option, or an unchosen one once `max` is reached, is
|
|
920
920
|
`aria-disabled`: it stays focusable and an arrow stop, a press does nothing,
|
|
921
|
-
and its `disabledReason` is printed
|
|
921
|
+
and its `disabledReason` is printed below the whole group, outside the chip row (unless
|
|
922
922
|
`showDisabledReason={false}`, then its tooltip) and is its accessible description
|
|
923
923
|
(as is `description`). The group's label shows the required mark when `required`; in
|
|
924
924
|
multiple mode, where a `group` cannot carry `aria-required`, the group is
|
package/docs/getting-started.md
CHANGED
|
@@ -144,7 +144,7 @@ and need nothing.
|
|
|
144
144
|
| `@nxgt/material/editor/viewer` | `RichTextViewer`: shows a saved document (HTML, JSON or Markdown) read-only. **Server-safe**: no editor instance, no `'use client'` ([RichTextViewer](components/rich-widgets.md#richtextviewer)) |
|
|
145
145
|
| `@nxgt/material/editor/collab` | `collaboration()`: several people editing one `DocumentEditor` through a Yjs document and provider your app supplies. Needs `yjs` and `y-protocols` ([Collaboration](components/rich-widgets.md#collaboration)) |
|
|
146
146
|
| `@nxgt/material/editor/pm` | The editor's own tiptap and ProseMirror classes (`Extension`, `Node`, `Plugin`, `PluginKey`, `TextSelection`, `ProseMirrorNode`, `Fragment`, `DecorationSet`, …) for a custom feature's extensions, so `instanceof` agrees with the editor. Shares the editor's code; **server-safe** ([A custom feature](components/rich-widgets.md#a-custom-feature)) |
|
|
147
|
-
| `@nxgt/material/backgrounds` | Background presets: `Background` (a superset of the `/components` one: `preset` (
|
|
147
|
+
| `@nxgt/material/backgrounds` | Background presets: `Background` (a superset of the `/components` one: `preset` (52 ids, `AVAILABLE_BACKGROUND_PRESETS`), `tone`, `intensity`, `animated`, `grain`, `seed`, `fill`, `sky`, `motif` (`shapes`, `density`, `size`, `rotate`, `shapeFill`, `opacitySpread`) and, for `preset="icons"`, `icons`, `iconStyle` and `iconMotif`), and the types and tables re-exported from `@nxgt/material-core/backgrounds`. **Its own entry**, with an opt-in stylesheet ([backgrounds](guides/backgrounds.md)) |
|
|
148
148
|
| `@nxgt/material/media-hls` | `hlsStreaming()`: the HLS adapter for `MediaPlayer`, `hls.js` loaded lazily ([streaming](guides/media-streaming.md)) |
|
|
149
149
|
| `@nxgt/material/vite` | Build-time helper for consumers: `pdfkitStandardFonts()` ([printing](guides/printing.md#bundling-print-into-an-ssr-server)) |
|
|
150
150
|
| `@nxgt/material/hooks` | `useTheme`, `useIsClient`, `useIsMobile`, `useLocalizedDate`, … ([helpers](guides/helpers.md#nxgtmaterialhooks)) |
|
package/docs/guides/app-shell.md
CHANGED
|
@@ -639,7 +639,7 @@ to know the theme on the server (a cookie, passed to `defaultTheme`).
|
|
|
639
639
|
## Use a background preset behind the shell
|
|
640
640
|
|
|
641
641
|
The shell draws the gradient with three blurred blobs behind its frame. To use
|
|
642
|
-
one of the
|
|
642
|
+
one of the 52 presets of `@nxgt/material/backgrounds` instead, pass it as
|
|
643
643
|
`backdrop` (behind the shell its shapes show only in empty space, see [Where the shapes go](#the-themes-background)):
|
|
644
644
|
|
|
645
645
|
```tsx
|
|
@@ -45,22 +45,22 @@ import '@nxgt/material/backgrounds.css';
|
|
|
45
45
|
|
|
46
46
|
| Prop | Values | Default |
|
|
47
47
|
| --- | --- | --- |
|
|
48
|
-
| `preset` | `gradient`, `grain`, `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`, `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport`, `moon`, `eclipse`, `meteor-shower`, `ringed-planet`, `northern-lights`, `icons` (`AVAILABLE_BACKGROUND_PRESETS`, the ids this library draws); any other id draws the gradient and warns outside production | `gradient` |
|
|
48
|
+
| `preset` | `gradient`, `grain`, `mesh`, `aurora`, `spotlight`, `bokeh`, `rays`, `halo`, `plasma`, `glass`, `ripples`, `blobs`, `paper`, `linen`, `concrete`, `marble`, `isometric`, `blueprint`, `dots`, `stripes`, `low-poly`, `topography`, `waves`, `hexagons`, `circuit`, `graph-paper`, `checker`, `diagonal-checker`, `chevrons`, `shapes`, `confetti-grid`, `constellation`, `halftone`, `truchet`, `floating`, `scatter-icons`, `school`, `night-sky`, `bubbles`, `leaves`, `science`, `music`, `travel`, `sport`, `moon`, `eclipse`, `meteor-shower`, `ringed-planet`, `northern-lights`, `day-sky`, `dawn-sky`, `icons` (`AVAILABLE_BACKGROUND_PRESETS`, the ids this library draws); any other id draws the gradient and warns outside production | `gradient` |
|
|
49
49
|
| `tone`, `intensity` | as above | `primary`, `default` |
|
|
50
50
|
| `animated` | `boolean`: drifts the layers, see Motion | `false` |
|
|
51
51
|
| `grain` | `boolean`: film noise over the preset; needs `grain.css` | `false` |
|
|
52
52
|
| `seed` | `number`: moves a seeded preset's geometry and the grain | `0` |
|
|
53
53
|
| `motif` | a `MotifOptions` object (`shapes`, `density`, `layout`, `size`, `rotate`, `shapeFill`, `opacitySpread`), see [Motif presets](#motif-presets) | all fields optional |
|
|
54
54
|
| `moon` | a `MoonOptions` object for `preset="moon"`, the celestial presets and a `sky`: `position` (`{ x, y }`, fractions of the container), `phase`, `halo`; see [Moon](#moon) | `{ position: { x: 0.8, y: 0.2 }, phase: 0.78, halo: 2.6 }` |
|
|
55
|
-
| `sky` | `'moon'`, `'eclipse'`, `'meteor-shower'`, `'ringed-planet'` or `'
|
|
55
|
+
| `sky` | `'moon'`, `'eclipse'`, `'meteor-shower'`, `'ringed-planet'`, `'northern-lights'`, `'day-sky'` or `'dawn-sky'`: a second scene drawn over any preset, before the grain; see [Celestial presets and the sky overlay](#celestial-presets-and-the-sky-overlay) | none |
|
|
56
56
|
| `icons` | for `preset="icons"`: a pack name (`school`, `health`, `finance`, `travel`, `nature`, `tech`) or up to 48 icon names and `{ name, family?, type? }` references; see [Icons](#icons) | the `school` pack |
|
|
57
57
|
| `iconStyle` | for `preset="icons"` (and `shapes` with `motif.icons`): one style (`{ family?, type? }` or a sprite name such as `'sharp-light'`), a list of at most 8, or a weighted list `[{ style, weight? }]`; one drawn per icon. A weighted list drops the styles whose sprite is not served | light 3, thin 3, sharp-regular 2, sharp-light 2, duotone-thin 1 |
|
|
58
58
|
| `iconMotif` | for `preset="icons"` (and `shapes` with `motif.icons`): `layout` (`even`: shapes and a few icons; `scatter`, `grid`, `constellation`, `drift`: icons only), `colors` (`one`, `palette`, `classic`), `sizeRange`, `rotation`, `duotone` (`opacity` or `tones`), `secondaryOpacity` (0.4 or, with `tones`, 0.85 unless set), `calm` (icons-only layouts), `quiet` (`start`, `end`, `center`: a band the icons fade out of) | `{ layout: 'even', colors: 'one', duotone: 'opacity' }` (`secondaryOpacity` unset: 0.4, or 0.85 with `tones`) |
|
|
59
59
|
| `fill` | `viewport` (the viewport's size) or `container` (its parent's size: the parent needs a definite height) | `viewport` |
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
`BACKGROUND_PRESETS` is the table of all
|
|
63
|
-
kind; `AVAILABLE_BACKGROUND_PRESETS` lists the ids this library draws (all
|
|
62
|
+
`BACKGROUND_PRESETS` is the table of all 52 presets with their family and
|
|
63
|
+
kind; `AVAILABLE_BACKGROUND_PRESETS` lists the ids this library draws (all 52;
|
|
64
64
|
`SHIPPED_BACKGROUND_PRESETS` is the common floor every library draws).
|
|
65
65
|
|
|
66
66
|
<img src="../previews/backgrounds-matrix.webp" width="640" alt="The presets, each in a card with its name">
|
|
@@ -287,8 +287,8 @@ follows `intensity` (`subtle` is a faint watermark, `vivid` the strongest; the s
|
|
|
287
287
|
|
|
288
288
|
## Celestial presets and the sky overlay
|
|
289
289
|
|
|
290
|
-
|
|
291
|
-
colours, a few stars and a clear middle for the content.
|
|
290
|
+
Six presets draw a sky of their own, each discreet like `moon`: thin outlines and soft halos in the tone's three
|
|
291
|
+
colours, a few stars (or, for the two daytime skies, clouds) and a clear middle for the content.
|
|
292
292
|
|
|
293
293
|
| Preset | Draws | `moon.phase` is | Default `moon.position` |
|
|
294
294
|
| --- | --- | --- | --- |
|
|
@@ -296,6 +296,8 @@ colours, a few stars and a clear middle for the content.
|
|
|
296
296
|
| `meteor-shower` | streaks falling down and to the left, among a few stars | the direction of the fall (0.2 steep, 0.9 shallow) | `0.7, 0.18` (the radiant) |
|
|
297
297
|
| `ringed-planet` | a planet with a ring that passes behind it, and a small moon | the ring's tilt | `0.78, 0.22` |
|
|
298
298
|
| `northern-lights` | three soft ribbons across the top | the ribbons' height | `0.5, 0.2` (only `y` applies) |
|
|
299
|
+
| `day-sky` | a thin-outlined sun with rays and a halo, and soft clouds in the top band; no stars | the cloud cover (0.2 clear, 0.9 overcast) | `0.8, 0.16` |
|
|
300
|
+
| `dawn-sky` | a low sun on the left over a horizon glow, and long thin clouds; no stars | the cloud cover | `0.22, 0.7` (`y` is where the glow hangs) |
|
|
299
301
|
|
|
300
302
|
```tsx
|
|
301
303
|
import '@nxgt/material/backgrounds/celestial.css'; // or backgrounds.css
|
|
@@ -308,7 +310,17 @@ They read `motif.size` (the body at 0.7, 1 or 1.4 times) and `motif.density` (5,
|
|
|
308
310
|
and `seed` places the stars. The body is halved (the planet scaled to two thirds) in a container under 640 px
|
|
309
311
|
wide so it stays whole in its corner. In light the scene is multiplied into the page, a faint watermark; in dark
|
|
310
312
|
it adds light and the body is silver. `intensity` fades it (`subtle` is the calmest, and the right pick for
|
|
311
|
-
`northern-lights`, whose ribbons are the strongest of the
|
|
313
|
+
`northern-lights`, whose ribbons are the strongest of the night skies).
|
|
314
|
+
|
|
315
|
+
`day-sky` and `dawn-sky` are the daytime pair, for an app that alternates night and day phases: the same
|
|
316
|
+
`preset` or `sky` option, so switching phase is a prop change (`preset={night ? 'night-sky' : 'day-sky'}`, or
|
|
317
|
+
`sky={night ? 'moon' : 'dawn-sky'}`). `moon.phase` is the cloud cover and `motif.density` adds clouds (2, 3 or 5,
|
|
318
|
+
plus up to two with the cover); `motif.size` scales the sun and the clouds. The clouds stay in the top band, out of
|
|
319
|
+
the clear middle, and every shape is drawn at half opacity or less, so body text over the backdrop keeps AA
|
|
320
|
+
contrast (checked in light and dark for every `intensity`). The tones follow the theme in light and dark, and
|
|
321
|
+
`animated` drifts the clouds sideways (18 s) unless the user asks for reduced motion.
|
|
322
|
+
|
|
323
|
+
<img src="../previews/backgrounds-day-and-dawn-sky.webp" width="640" alt="The day-sky and dawn-sky presets, each behind a card">
|
|
312
324
|
|
|
313
325
|
The builders live in `@nxgt/material-core/backgrounds/celestial`, a separate subpath, and `Background` loads it
|
|
314
326
|
on demand: the first paint (and the server's HTML) holds the layers, with the SVG filling in once the chunk has
|
|
@@ -316,7 +328,7 @@ loaded, so the scene never causes a hydration mismatch and an app that draws non
|
|
|
316
328
|
|
|
317
329
|
### The `sky` prop
|
|
318
330
|
|
|
319
|
-
`sky` draws the moon
|
|
331
|
+
`sky` draws the moon, a celestial preset or a daytime one over *any* preset, after its layers and before the grain, with its
|
|
320
332
|
own ids (`<id>-sky-…`), so the two never clash. It reads the base's `motif` but not its `moon` options (those stay with the
|
|
321
333
|
preset): the sky's body sits at its own default place, mirrored to the other side when the preset's moon or
|
|
322
334
|
celestial body would land within a fifth of the width, and its stars follow `seed + 1`.
|
|
@@ -327,8 +339,8 @@ celestial body would land within a fifth of the width, and its stars follow `see
|
|
|
327
339
|
|
|
328
340
|
A theme can name it too (`background: { preset: 'school', sky: 'meteor-shower' }`): a `sky` you pass wins over the
|
|
329
341
|
theme's. With `animated` the stars twinkle (8 s a leg), a meteor glides and fades (10 s) and a ribbon drifts
|
|
330
|
-
(14 s); nothing moves under `prefers-reduced-motion` or while the page is hidden. CSS: `backgrounds/celestial.css`
|
|
331
|
-
(it imports `scene.css`) styles all
|
|
342
|
+
(14 s) and a cloud slides (18 s); nothing moves under `prefers-reduced-motion` or while the page is hidden. CSS: `backgrounds/celestial.css`
|
|
343
|
+
(it imports `scene.css`) styles all six presets and the overlay; React only, `@nxgt/material-vue` does not draw
|
|
332
344
|
them. The theme picker draws a small tile for a theme with a celestial preset.
|
|
333
345
|
|
|
334
346
|
## Icons
|
|
@@ -700,7 +712,7 @@ else is opt-in, because CSS cannot be tree-shaken. `animated` on the
|
|
|
700
712
|
/* or just the one you use: */
|
|
701
713
|
@import "@nxgt/material/backgrounds/aurora.css"; /* a preset file, named after the preset (aurora.css, low-poly.css, hexagons.css, scatter-icons.css…) */
|
|
702
714
|
@import "@nxgt/material/backgrounds/grain.css"; /* the grain overlay, over any preset */
|
|
703
|
-
@import "@nxgt/material/backgrounds/celestial.css"; /* eclipse, meteor-shower, ringed-planet, northern-lights, and the `sky` overlay */
|
|
715
|
+
@import "@nxgt/material/backgrounds/celestial.css"; /* eclipse, meteor-shower, ringed-planet, northern-lights, day-sky, dawn-sky, and the `sky` overlay */
|
|
704
716
|
@import "@nxgt/material/backgrounds/halftone.css"; /* a motif preset (brings motifs.css) */
|
|
705
717
|
@import "@nxgt/material/backgrounds/floating.css"; /* brings motifs.css and drift.css */
|
|
706
718
|
```
|
|
@@ -123,12 +123,50 @@ A card is as tall as its content, and the cards of a grid row stretch to the tal
|
|
|
123
123
|
| the text only | neither |
|
|
124
124
|
|
|
125
125
|
The link's hit area covers the whole card, so a click anywhere on the card
|
|
126
|
-
follows it.
|
|
126
|
+
follows it. A linked or clickable `Title` also draws the same discreet,
|
|
127
|
+
decorative trailing chevron as `Row`, centred at the card's end (left out when
|
|
128
|
+
the card holds an `Actions` slot); `<Title chevron={false}>` removes it.
|
|
129
|
+
|
|
130
|
+
Never put a second link or a button inside the card's content:
|
|
127
131
|
only the title is interactive.
|
|
128
132
|
|
|
129
133
|
On a coarse pointer the title link also keeps a 44px box of its own, clear of
|
|
130
134
|
the row-select checkbox, however short the title.
|
|
131
135
|
|
|
136
|
+
### A trailing action beside the link
|
|
137
|
+
|
|
138
|
+
A card's primary action (a worklist's "Edit", "Approve") cannot live inside
|
|
139
|
+
the title link. Render it in `item.Actions`, after `Title`:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { Pencil } from 'lucide-react';
|
|
143
|
+
import { Button } from '@nxgt/material/components';
|
|
144
|
+
|
|
145
|
+
<DataTable
|
|
146
|
+
layout="cards"
|
|
147
|
+
getRowHref={(task) => `/tasks/${task.id}`}
|
|
148
|
+
renderCard={(task, { Title, Actions }) => (
|
|
149
|
+
<>
|
|
150
|
+
<Title as="h3">{task.name}</Title>
|
|
151
|
+
<p>{task.owner}</p>
|
|
152
|
+
<Actions>
|
|
153
|
+
<Button variant="ghost" size="icon" aria-label={`Edit ${task.name}`}
|
|
154
|
+
onClick={() => edit(task)}>
|
|
155
|
+
<Pencil aria-hidden />
|
|
156
|
+
</Button>
|
|
157
|
+
</Actions>
|
|
158
|
+
</>
|
|
159
|
+
)}
|
|
160
|
+
/>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`Actions` is a slot at the item's end (a tile centres it), outside the link,
|
|
164
|
+
at least 44px square, raised above the link's overlay: a click on the action
|
|
165
|
+
runs the action and does not follow the card. The item keeps room for it at its
|
|
166
|
+
end, room for one 44px control: a menu button for several actions, not a row
|
|
167
|
+
of buttons. `renderTile` takes it too, and so does a `ServerTable`. Render it once per
|
|
168
|
+
item. Put the action in `Actions`, not in `Row`'s `trailing` (decoration only).
|
|
169
|
+
|
|
132
170
|
`item` also carries `Row` (the compact record row above), `selected`,
|
|
133
171
|
`locked` and `reason` (a row `enableRowSelection` leaves out, and
|
|
134
172
|
`rowSelectionDisabledReason`'s answer).
|
|
@@ -237,7 +275,7 @@ own: do not put it in a shrink-to-fit parent (`w-fit`, `inline-flex`).
|
|
|
237
275
|
`cardDensity="compact"` instead fits as many cards of at least
|
|
238
276
|
`--nxgt-cards-min` (15rem) as the list holds, up to four, with a 0.5rem gap and a
|
|
239
277
|
tighter padding. By the list's own width (the table's box minus the 16px it
|
|
240
|
-
keeps on each side), four from about 62rem, three from about 46.5rem, two from
|
|
278
|
+
keeps on each side from 768px; on a phone it keeps 0, so the list is 32px wider than the thresholds below assume), four from about 62rem, three from about 46.5rem, two from
|
|
241
279
|
about 31rem, one below: a table 1280px wide shows four (so does a 1024px one), a 992px one
|
|
242
280
|
(a 1024px window with 16px page padding) three, a 328px one one. It suits a card that
|
|
243
281
|
holds a name and a fact or two. A compact card is about 15rem wide, so stack it
|
|
@@ -274,7 +312,7 @@ they are ignored and warn once in development. `tableRef` stays `null`: use
|
|
|
274
312
|
|
|
275
313
|
The list is a plain list, not a grid: Tab visits each card's checkbox (with a
|
|
276
314
|
`select` column) and then its link, in order, after the list bar's "Select all on
|
|
277
|
-
this page". Space toggles a checkbox, Enter follows a link. There is no arrow-key
|
|
315
|
+
this page". An `Actions` control comes after its link. Space toggles a checkbox, Enter follows a link. There is no arrow-key
|
|
278
316
|
navigation to learn.
|
|
279
317
|
|
|
280
318
|
## Custom links
|
|
@@ -352,6 +390,7 @@ then switches. Render the app on the client for a phone-only screen, or use
|
|
|
352
390
|
|
|
353
391
|
**My card has two links.** Only `Title` is a link. Content you render yourself
|
|
354
392
|
must not hold another `<a>` or button: it would sit under the card's hit area.
|
|
393
|
+
A button the card needs goes in `item.Actions`.
|
|
355
394
|
|
|
356
395
|
**The cards have one column on a wide screen.** (Tiles always do.) The columns follow the list's
|
|
357
396
|
width. Check that the list is not inside a shrink-to-fit parent.
|
|
@@ -97,8 +97,8 @@ no icon background never downloads it.
|
|
|
97
97
|
|
|
98
98
|
## A sky
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
`northern-lights`), and `sky` lays the moon or one of them over **any** preset:
|
|
100
|
+
Six presets draw a discreet sky (`eclipse`, `meteor-shower`, `ringed-planet`,
|
|
101
|
+
`northern-lights`, `day-sky`, `dawn-sky`), and `sky` lays the moon or one of them over **any** preset:
|
|
102
102
|
|
|
103
103
|
```tsx
|
|
104
104
|
import '@nxgt/material/backgrounds/celestial.css'; // or backgrounds.css
|
|
@@ -107,12 +107,12 @@ import '@nxgt/material/backgrounds/celestial.css'; // or backgrounds.css
|
|
|
107
107
|
<Background preset="icons" icons="travel" sky="northern-lights" grain />
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
<img src="../previews/backgrounds-celestial.webp" width="480" alt="
|
|
110
|
+
<img src="../previews/backgrounds-celestial.webp" width="480" alt="Four of the celestial presets: an eclipse, a meteor shower, a ringed planet and northern lights">
|
|
111
111
|
|
|
112
112
|
The `sky` keeps clear of the base's own moon or planet (it moves to the other
|
|
113
113
|
side), and sits before the grain. The sky over the school icons:
|
|
114
114
|
|
|
115
|
-
<img src="../previews/backgrounds-sky-overlay.webp" width="480" alt="
|
|
115
|
+
<img src="../previews/backgrounds-sky-overlay.webp" width="480" alt="Four of the skies laid over the school icons">
|
|
116
116
|
|
|
117
117
|
The presets and `sky` are pure SVG: they need no sprite. Details in
|
|
118
118
|
[backgrounds](backgrounds.md#celestial-presets-and-the-sky-overlay).
|
|
@@ -138,8 +138,8 @@ An `Illustration` draws a hero icon on a Material 3 Expressive plate, with two
|
|
|
138
138
|
to four satellites. There are twelve base scenes (`empty`, `no-results`,
|
|
139
139
|
`not-found`, `error`, `offline`, `success`, `welcome`, `forbidden`,
|
|
140
140
|
`maintenance`, `invitation`, `sign-in`, `empty-inbox`) and two domain sets of
|
|
141
|
-
ten, **health** and **education**, plus **game** (
|
|
142
|
-
import one does not carry it:
|
|
141
|
+
ten, **health** and **education**, plus **game** (sixteen scenes for games and
|
|
142
|
+
events), each its own subpath so an app that does not import one does not carry it:
|
|
143
143
|
|
|
144
144
|
<img src="../previews/feedback-status-illustration.webp" width="480" alt="The twelve base illustration scenes">
|
|
145
145
|
|
|
@@ -147,7 +147,7 @@ import one does not carry it:
|
|
|
147
147
|
|
|
148
148
|
<img src="../previews/feedback-status-illustration-education.webp" width="480" alt="The ten education scenes">
|
|
149
149
|
|
|
150
|
-
<img src="../previews/feedback-status-illustration-game.webp" width="480" alt="The
|
|
150
|
+
<img src="../previews/feedback-status-illustration-game.webp" width="480" alt="The game scenes">
|
|
151
151
|
|
|
152
152
|
- `IllustrationDefaults` is opt-in: without it (and without a `hero`) an
|
|
153
153
|
`EmptyState` or `ErrorState` draws the same built-in art as before. An
|
|
@@ -5,7 +5,7 @@ on a Material 3 Expressive plate, two to four satellite icons around it, a
|
|
|
5
5
|
dashed ring and a few sparkles. There are twelve scenes: `empty`, `no-results`,
|
|
6
6
|
`not-found`, `error`, `offline`, `success`, `welcome`, `forbidden`,
|
|
7
7
|
`maintenance`, `invitation`, `sign-in` and `empty-inbox`, and two domain sets of
|
|
8
|
-
ten more each, health and education, in their own entries ([health](#scene-sets-the-health-scenes) and [education](#scene-sets-the-education-scenes)), and
|
|
8
|
+
ten more each, health and education, in their own entries ([health](#scene-sets-the-health-scenes) and [education](#scene-sets-the-education-scenes)), and sixteen for games ([game](#scene-sets-the-game-scenes)). The icons are
|
|
9
9
|
[Font Awesome](https://fontawesome.com) sprites **your app serves** (see
|
|
10
10
|
[Icons](../getting-started.md#icons)): the package ships no icon artwork, so it
|
|
11
11
|
works with the sprites your licence covers. The [icon motifs guide](icon-motifs.md) shows them next to the icon backgrounds, the sky and the themes, and lists the suggested names that are Pro only, with Free neighbours.
|
|
@@ -148,16 +148,17 @@ icons: serve a Pro sprite, or set `edition="free"` on `IconSpritesProvider`, whi
|
|
|
148
148
|
|
|
149
149
|
## Scene sets: the game scenes
|
|
150
150
|
|
|
151
|
-
`@nxgt/material/illustrations/game` holds
|
|
152
|
-
community or an event app: `night-sky`, `
|
|
153
|
-
|
|
151
|
+
`@nxgt/material/illustrations/game` holds sixteen scenes for a game, a quiz, a
|
|
152
|
+
community or an event app: `night-sky`, `dawn`, `village` (night),
|
|
153
|
+
`day-village`, `graveyard`, seven character pictograms (`seer`, `healer`,
|
|
154
|
+
`archer`, `cupid`, `wolf`, `villager`, `witch`), `victory`, `empty-table`,
|
|
154
155
|
`waiting-players` and `connection-lost`. It works exactly like the other sets,
|
|
155
156
|
and they register side by side. Use them where a screen is empty, waiting,
|
|
156
157
|
failed, celebrating or opening: a lobby with no players, a round that waits, a
|
|
157
158
|
dropped connection, a winner, a night-phase hero. Keep them away from behind
|
|
158
159
|
data.
|
|
159
160
|
|
|
160
|
-
<img src="../previews/feedback-status-illustration-game.webp" width="480" alt="The
|
|
161
|
+
<img src="../previews/feedback-status-illustration-game.webp" width="480" alt="The game scenes">
|
|
161
162
|
|
|
162
163
|
```tsx
|
|
163
164
|
import { Illustration, IllustrationDefaults } from '@nxgt/material/illustrations';
|
package/docs/guides/theming.md
CHANGED
|
@@ -146,7 +146,7 @@ A backdrop's colours come from the theme; set none on it.
|
|
|
146
146
|
## The neutral palette
|
|
147
147
|
|
|
148
148
|
The default theme's page is plain: pure white in light and the one dark night
|
|
149
|
-
every theme shares (`oklch(0.15 0.026 273)`), whatever the colours.
|
|
149
|
+
every theme shares (`oklch(0.15 0.026 273)`), whatever the colours (the `teal` theme is the exception: it sets `neutrals: 'tinted'`). The default's other
|
|
150
150
|
neutrals (cards in dark, muted, borders, text) are softly tinted toward violet
|
|
151
151
|
(hue 290, low chroma), to sit with the primary indigo instead of fighting it.
|
|
152
152
|
A theme can tint its page too with `neutrals: 'tinted'` in `defineTheme`
|
|
Binary file
|
|
Binary file
|
package/docs/troubleshooting.md
CHANGED
|
@@ -386,6 +386,7 @@ words in your error.
|
|
|
386
386
|
- [`defineCodeTheme: "keyword" must be a hex colour`](#definecodetheme-keyword-must-be-a-hex-colour-rgb-or-rrggbb)
|
|
387
387
|
- [A `CodeEditor` shows its code in one colour after another Monaco editor mounts](#a-codeeditor-shows-its-code-in-one-colour-after-another-monaco-editor-mounts)
|
|
388
388
|
- [`primary={false}` has no effect on a `ContactsFormField` with `editing="dialog"`](#primaryfalse-has-no-effect-on-a-contactsformfield-with-editingdialog)
|
|
389
|
+
- [ChatConversationItem collapses to zero width (or its timestamp is clipped) inside a w-fit / max-content / inline-flex / popover parent](#chatconversationitem-collapses-to-zero-width-or-its-timestamp-is-clipped-inside-a-w-fit--max-content--inline-flex--popover-parent)
|
|
389
390
|
|
|
390
391
|
**PDF reader**
|
|
391
392
|
|
|
@@ -2325,6 +2326,17 @@ your own draws a second chevron since the tile adds one.
|
|
|
2325
2326
|
<ListTile title="Notifications" href="/settings/notifications" chevron={false} trailing={<MyArrow />} />
|
|
2326
2327
|
```
|
|
2327
2328
|
|
|
2329
|
+
### A linked DataTable card shows two chevrons
|
|
2330
|
+
|
|
2331
|
+
**When:** a `renderCard` or `renderTile` built on `item.Title`, with
|
|
2332
|
+
`getRowHref` or `onRowClick`, draws a chevron icon of its own.
|
|
2333
|
+
**Why:** a linked `Title` ends with a decorative chevron by default.
|
|
2334
|
+
**Fix:** drop your own, or keep it and pass `chevron={false}`:
|
|
2335
|
+
|
|
2336
|
+
```tsx
|
|
2337
|
+
<Title as="h3" chevron={false}>{row.name}</Title>
|
|
2338
|
+
```
|
|
2339
|
+
|
|
2328
2340
|
### A `ListTile` link reloads the whole page
|
|
2329
2341
|
|
|
2330
2342
|
**When:** a `ListTile` with an `href` is clicked inside a router app: the
|
|
@@ -7065,6 +7077,32 @@ in both modes.
|
|
|
7065
7077
|
**Fix:** use the default `editing="inline"` when the star must go, or drop the
|
|
7066
7078
|
`primary` flag from the value before saving.
|
|
7067
7079
|
|
|
7080
|
+
### `ChatConversationItem collapses to zero width (or its timestamp is clipped) inside a w-fit / max-content / inline-flex / popover parent`
|
|
7081
|
+
|
|
7082
|
+
**When:** a `ChatConversationItem` sits in a parent that sizes to its content
|
|
7083
|
+
(`w-fit`, `max-content`, an inline-flex wrapper, a popover sized to content),
|
|
7084
|
+
after upgrading `@nxgt/material` to the version that fixed the clipped timestamp.
|
|
7085
|
+
|
|
7086
|
+
**Why:** the item now has `contain: inline-size`, so it has no intrinsic width
|
|
7087
|
+
and a long title can no longer widen an auto-sized grid track and push the
|
|
7088
|
+
timestamp out of the list pane. It fills its container (`w-full`); a parent
|
|
7089
|
+
that takes its width from its content gives it zero.
|
|
7090
|
+
|
|
7091
|
+
**Fix:** give the item's parent a width, or, in a grid, use
|
|
7092
|
+
`grid-cols-[minmax(0,1fr)]` on the list that wraps it:
|
|
7093
|
+
|
|
7094
|
+
```tsx
|
|
7095
|
+
// A shrink-to-fit parent: give the item a width.
|
|
7096
|
+
<div className="w-72">
|
|
7097
|
+
<ChatConversationItem title="Support" timestamp="31 août" />
|
|
7098
|
+
</div>
|
|
7099
|
+
|
|
7100
|
+
// In a grid, let the track shrink below the title's width.
|
|
7101
|
+
<ul className="grid grid-cols-[minmax(0,1fr)]">
|
|
7102
|
+
<li><ChatConversationItem title="Support" timestamp="31 août" /></li>
|
|
7103
|
+
</ul>
|
|
7104
|
+
```
|
|
7105
|
+
|
|
7068
7106
|
## PDF reader
|
|
7069
7107
|
|
|
7070
7108
|
### PDF text is missing or in the wrong font in `PdfReader` (cMaps and standard fonts)
|
|
@@ -7653,13 +7691,13 @@ How the presets work is in the [Backgrounds guide](guides/backgrounds.md).
|
|
|
7653
7691
|
### `Background: preset "<id>" is not available in this library yet; drawing "gradient".`
|
|
7654
7692
|
|
|
7655
7693
|
**When:** in development (not when `NODE_ENV` is `production`), the first time a `Background` from `@nxgt/material/backgrounds` gets a `preset` that this library does not draw yet, or a typo from JavaScript. It is printed once per id.
|
|
7656
|
-
**Why:** `BACKGROUND_PRESETS` lists the
|
|
7694
|
+
**Why:** `BACKGROUND_PRESETS` lists the 52 presets; this library draws all of them, the ones in `AVAILABLE_BACKGROUND_PRESETS`. Any other id (a typo from JavaScript) draws the gradient.
|
|
7657
7695
|
**Fix:** use an available preset:
|
|
7658
7696
|
|
|
7659
7697
|
```ts
|
|
7660
7698
|
import { AVAILABLE_BACKGROUND_PRESETS } from '@nxgt/material/backgrounds';
|
|
7661
7699
|
|
|
7662
|
-
console.log(AVAILABLE_BACKGROUND_PRESETS); // the
|
|
7700
|
+
console.log(AVAILABLE_BACKGROUND_PRESETS); // the 52 ids it draws: 'gradient', 'grain', 'mesh', 'aurora', …, 'moon', 'eclipse', …, 'northern-lights', 'icons'
|
|
7663
7701
|
```
|
|
7664
7702
|
|
|
7665
7703
|
### A preset `Background` looks bare, with no error
|