@nxgt/material 3.39.0 → 3.42.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 +18 -0
- package/README.md +4 -4
- package/dist/{async-slice-BtUexP2l.js → async-slice-Dj0tAKRI.js} +2 -2
- package/dist/{button-CCAYSsgh.js → button-CTsT_LqL.js} +1 -1
- package/dist/charts.js +1733 -1364
- package/dist/{chip-Corr637n.js → chip-DP7EyhtT.js} +1 -1
- package/dist/{code-editor-B8_ny_jT.js → code-editor-BWn0AXBf.js} +4 -4
- package/dist/code-editor.js +4 -4
- package/dist/{code-language-items-1E5Qmfzb.js → code-language-items-CCRuLYpA.js} +2 -2
- package/dist/components/components.css +1 -0
- package/dist/components/ui/widgets/native-charts/native-charts-reference.css +102 -0
- package/dist/{components-CTKlqX8g.js → components-g8mWYJE8.js} +10896 -10827
- package/dist/components.js +17 -17
- package/dist/{dialog-DGlnqBbX.js → dialog-uQld1gKm.js} +1 -1
- package/dist/dnd.js +1 -1
- package/dist/{dropdown-menu-B-buMTGc.js → dropdown-menu-BA70o7HC.js} +1 -1
- package/dist/editor.js +529 -529
- package/dist/{empty-state-DKgPt475.js → empty-state-BzwyRX5J.js} +1 -1
- package/dist/hooks.js +2 -2
- package/dist/{i18n-provider-Bc7bdIRW.js → i18n-provider-DkeMr5bw.js} +1 -1
- package/dist/i18n.js +5 -5
- package/dist/{icon-badge-BzLsPW3c.js → icon-badge-D_z5BGbc.js} +1 -1
- package/dist/lib/charts/index.d.ts +3 -1
- package/dist/lib/components/ui/collections/server-table/bulk-action-targets.d.ts +18 -0
- package/dist/lib/components/ui/collections/server-table/bulk-action.d.ts +50 -3
- package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-buttons.d.ts +5 -3
- package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-focus.d.ts +31 -0
- package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-more.d.ts +24 -0
- package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-notice.d.ts +16 -0
- package/dist/lib/components/ui/collections/server-table/partials/server-table-bulk-texts.d.ts +9 -0
- package/dist/lib/components/ui/collections/server-table/server-table.d.ts +1 -1
- package/dist/lib/components/ui/fields/contacts/placeholders.d.ts +1 -1
- package/dist/lib/components/ui/selection/autocomplete/autocomplete-form-field.d.ts +5 -2
- package/dist/lib/components/ui/selection/autocomplete/autocomplete-text-rules.d.ts +20 -0
- package/dist/lib/components/ui/selection/autocomplete/autocomplete.d.ts +1 -1
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-chip-input.d.ts +13 -0
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-chips.d.ts +7 -1
- package/dist/lib/components/ui/selection/autocomplete/partials/autocomplete-text-input.d.ts +15 -0
- package/dist/lib/components/ui/selection/autocomplete/types.d.ts +15 -0
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete-handlers.d.ts +10 -3
- package/dist/lib/components/ui/selection/autocomplete/use-autocomplete.d.ts +6 -1
- package/dist/lib/components/ui/selection/combobox/combobox-input.d.ts +3 -1
- package/dist/lib/components/ui/widgets/native-charts/core/point-tones.d.ts +17 -0
- package/dist/lib/components/ui/widgets/native-charts/core/reference-text.d.ts +30 -0
- package/dist/lib/components/ui/widgets/native-charts/core/reference.d.ts +45 -0
- package/dist/lib/components/ui/widgets/native-charts/core/summary.d.ts +3 -0
- package/dist/lib/components/ui/widgets/native-charts/core/table.d.ts +7 -0
- package/dist/lib/components/ui/widgets/native-charts/core/types.d.ts +25 -0
- package/dist/lib/components/ui/widgets/native-charts/hooks/chart-model-types.d.ts +18 -1
- package/dist/lib/components/ui/widgets/native-charts/hooks/model-parts.d.ts +3 -0
- package/dist/lib/components/ui/widgets/native-charts/hooks/model-series.d.ts +3 -0
- package/dist/lib/components/ui/widgets/native-charts/hooks/model-tones.d.ts +19 -0
- package/dist/lib/components/ui/widgets/native-charts/hooks/use-chart-model.d.ts +3 -3
- package/dist/lib/components/ui/widgets/native-charts/index.d.ts +1 -1
- package/dist/lib/components/ui/widgets/native-charts/line-chart/line-chart-types.d.ts +26 -1
- package/dist/lib/components/ui/widgets/native-charts/line-chart/line-geometry.d.ts +4 -0
- package/dist/lib/components/ui/widgets/native-charts/line-chart/partials/reference-marks.d.ts +17 -0
- package/dist/lib/components/ui/widgets/native-charts/line-chart/partials/tone-points.d.ts +11 -0
- package/dist/lib/components/ui/widgets/native-charts/partials/chart-tooltip.d.ts +3 -0
- package/dist/lib/i18n/resources/en/en.d.ts +22 -0
- package/dist/lib/i18n/resources/en/material.json.d.ts +22 -0
- package/dist/lib/i18n/resources/fr/fr.d.ts +22 -0
- package/dist/lib/i18n/resources/fr/material.json.d.ts +22 -0
- package/dist/lib/i18n/resources/resources.d.ts +44 -0
- package/dist/lib/i18n/translator.d.ts +1 -1
- package/dist/lib.js +1 -1
- package/dist/main.js +23 -23
- package/dist/map.js +4 -4
- package/dist/material.css +1 -1
- package/dist/pdf-reader.js +1 -1
- package/dist/print.js +2 -2
- package/dist/{public-CNlIuQOj.js → public-ib0sK0Hr.js} +6 -6
- package/dist/{rich-code-block-Jo0OLy0J.js → rich-code-block-D_PTTZWQ.js} +4 -4
- package/dist/{sortable-provider-DgIo378H.js → sortable-provider-CrS51nKB.js} +1 -1
- package/dist/{spinner-BTR8rVN9.js → spinner-DLd_IHev.js} +1 -1
- package/dist/{stored-language-Bbwcy-Pv.js → stored-language-B5SMR-W2.js} +44 -0
- package/dist/theme-picker.js +2 -2
- package/dist/{theme-toggle-DMZ_3HiG.js → theme-toggle-wJYmnwgu.js} +1 -1
- package/dist/{toolbar-items-D3SPTgXE.js → toolbar-items-BLjrk8uU.js} +2 -2
- package/dist/{translate-material-CRF13PON.js → translate-material-BYRDtSEk.js} +2 -2
- package/dist/{translator-D7AVZCfQ.js → translator-C-_M57ZA.js} +1 -1
- package/dist/{use-chat-composer-D3kvp8Fw.js → use-chat-composer-D_hfO99B.js} +2647 -2474
- package/dist/{use-heading-spy-uyhOQV2O.js → use-heading-spy-wElRpO2G.js} +1 -1
- package/dist/{use-material-translation-kISeB-fY.js → use-material-translation-CFF73jk5.js} +2 -2
- package/docs/README.md +1 -1
- package/docs/components/data-table-filter-and-lists.md +59 -4
- package/docs/components/rich-widgets.md +6 -0
- package/docs/components/selection-and-choice.md +47 -1
- package/docs/guides/charts.md +78 -2
- package/docs/guides/i18n.md +1 -1
- package/docs/roadmap.md +7 -0
- package/lib/components/components.css +1 -0
- package/lib/components/ui/widgets/native-charts/native-charts-reference.css +102 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as e } from "./i18n-provider-
|
|
1
|
+
import { r as e } from "./i18n-provider-DkeMr5bw.js";
|
|
2
2
|
import { _ as t, g as n, h as r, n as i, v as a, y as o } from "./number.utils-BG_eEt5g.js";
|
|
3
3
|
import { useCallback as s, useEffect as c, useMemo as l, useRef as u } from "react";
|
|
4
4
|
//#region ../../node_modules/date-fns/locale/fr/_lib/formatDistance.js
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as e } from "./i18n-provider-
|
|
2
|
-
import { t } from "./translate-material-
|
|
1
|
+
import { r as e } from "./i18n-provider-DkeMr5bw.js";
|
|
2
|
+
import { t } from "./translate-material-BYRDtSEk.js";
|
|
3
3
|
import { useCallback as n } from "react";
|
|
4
4
|
//#region lib/i18n/use-material-translation.ts
|
|
5
5
|
function r() {
|
package/docs/README.md
CHANGED
|
@@ -9,7 +9,7 @@ detail: every option, the second example, and the traps.
|
|
|
9
9
|
| [Components](components/README.md) | You are looking for a component — one preview per category, then one page per category |
|
|
10
10
|
| [Forms](guides/forms.md) | You are building a form: the field / `*FormField` pair, React Hook Form + Zod, what each field emits, server errors, multi-step forms |
|
|
11
11
|
| [Themes for your app](guides/themes.md) | You define your own themes: `defineTheme` modules, the Vite plugin's `themes` option, the `nxgt-theme` command and its CI check, the tone warnings |
|
|
12
|
-
| [Charts](guides/charts.md) | You draw charts with `@nxgt/material/charts`: each chart, the shared props, zoom and phone scroll, the keyboard, accessibility, theming the `--chart-1..5` tokens, and moving off the Nivo charts, removed in 3.0 |
|
|
12
|
+
| [Charts](guides/charts.md) | You draw charts with `@nxgt/material/charts`: each chart, the shared props, reference bands, thresholds and point tones, zoom and phone scroll, the keyboard, accessibility, theming the `--chart-1..5` tokens, and moving off the Nivo charts, removed in 3.0 |
|
|
13
13
|
| [Cards and tiles](guides/cards-and-tiles.md) | You want a `DataTable` as a list of cards or tiles: `layout`, `renderCard`, `renderTile`, the card's one link, selection, the sort control, columns by the list's width |
|
|
14
14
|
| [DataGrid](guides/data-grid.md) | You are building an editable grid: columns and editors, save modes and conflicts, resizing, hiding and reordering columns, paste, fill and series, undo, totals, long lists, phones, custom editors, CSP |
|
|
15
15
|
| [Code editor](guides/code-editor.md) | You want `CodeEditor` or `CodeDiff` in a theme preset or your own (`defineCodeTheme`), several themes on one page, Monaco bundled instead of the CDN, or the new `@nxgt/material/code-editor` import (the reader look, the view props, the `ref` handle and the file tabs are in the component's own page) |
|
|
@@ -861,12 +861,12 @@ export default function Students() {
|
|
|
861
861
|
```
|
|
862
862
|
- **Bulk actions that count and run only their rows.** `bulkActions` also
|
|
863
863
|
takes a list of `ServerTableBulkAction<T>` (`{ id, label, icon?, appliesTo?,
|
|
864
|
-
onClick, variant?, color?, loading? }`). Each button reads "Label (n)", n
|
|
864
|
+
name?, max?, maxNotice?, onClick, variant?, color?, loading? }`). Each button reads "Label (n)", n
|
|
865
865
|
being the selected rows the action applies to, and is named "Label n rows"
|
|
866
866
|
(`material.server-table.bulk-action` and `bulk-action-name`, English and
|
|
867
867
|
French); `variant` (default `'tonal'`) and `color` (`'destructive'` for a
|
|
868
868
|
destructive one) style the button, `loading` makes it busy; the type is
|
|
869
|
-
exported as `ServerTableBulkAction`. It is not rendered when n is 0, so 5 rows selected with none
|
|
869
|
+
exported as `ServerTableBulkAction`, with `ServerTableBulkContext`. It is not rendered when n is 0, so 5 rows selected with none
|
|
870
870
|
archived show no "Restore". `onClick(ids, selection, rows)` receives only
|
|
871
871
|
those ids and rows. An action without `appliesTo` applies to the whole
|
|
872
872
|
selection: it shows the selection's size and gets every id. **Across
|
|
@@ -880,6 +880,61 @@ export default function Students() {
|
|
|
880
880
|
(an action without it still gets every selected id). A row's snapshot is
|
|
881
881
|
dropped when it is deselected, when the selection is cleared and when the
|
|
882
882
|
query changes.
|
|
883
|
+
|
|
884
|
+
**Name, maximum and focus (`name`, `max`, `maxNotice`, `onClick`'s fourth
|
|
885
|
+
argument).** All three are optional and additive:
|
|
886
|
+
- `name: (count) => string` is the button's accessible name and tooltip,
|
|
887
|
+
e.g. `(n) => `Archive ${n} people``, instead of the generic "Archive 2
|
|
888
|
+
rows". Start it with the visible `label`: the button reads "Archive (2)",
|
|
889
|
+
and a name that begins with it lets speech input ("click Archive") and
|
|
890
|
+
screen readers agree (WCAG 2.5.3, Label in Name). It applies to the
|
|
891
|
+
toolbar, the phone's bar and the More menu's items alike.
|
|
892
|
+
- `max: 100` is the most rows one call takes, counted on the rows the action
|
|
893
|
+
applies to. Above it the button is replaced by `maxNotice`: a short muted
|
|
894
|
+
text, by default "Select 100 rows or fewer to archive"
|
|
895
|
+
(`material.server-table.bulk-max-notice`, English and French), or your own
|
|
896
|
+
node or `(count, max) => node`. The notice is told politely once, when the
|
|
897
|
+
action goes past `max`; moving from 101 to 102 rows says nothing more.
|
|
898
|
+
Under `max` again, the button returns. On a phone an action in the bar
|
|
899
|
+
shows the notice inline; one in the More menu is a disabled item whose
|
|
900
|
+
notice is its description (`aria-describedby`), so it reads under its label.
|
|
901
|
+
- `onClick(ids, selection, rows, { trigger, focusTrigger })`: `trigger` is the
|
|
902
|
+
button the action started from (the "More" button for a More-menu item),
|
|
903
|
+
and `focusTrigger()` gives it the focus back, found again at call time, so
|
|
904
|
+
it works after a re-render. When the action is gone by then (its count fell
|
|
905
|
+
to 0, or past `max`) the focus goes to the next bulk action, else "More",
|
|
906
|
+
else the table's "Select all" (the table itself without one), never the
|
|
907
|
+
body. A handler that takes three parameters stays valid.
|
|
908
|
+
```tsx
|
|
909
|
+
const [confirm, setConfirm] = useState<{ ids: string[]; focus: () => void } | null>(null);
|
|
910
|
+
<ServerTable<Person>
|
|
911
|
+
{...props}
|
|
912
|
+
bulkActions={[
|
|
913
|
+
{
|
|
914
|
+
id: 'archive',
|
|
915
|
+
label: 'Archive',
|
|
916
|
+
appliesTo: (person) => !person.archived,
|
|
917
|
+
name: (n) => `Archive ${n} ${n === 1 ? 'person' : 'people'}`,
|
|
918
|
+
max: 100,
|
|
919
|
+
onClick: (ids, _selection, _rows, { focusTrigger }) =>
|
|
920
|
+
setConfirm({ ids, focus: focusTrigger }),
|
|
921
|
+
},
|
|
922
|
+
]}
|
|
923
|
+
/>
|
|
924
|
+
<Dialog open={confirm != null} onOpenChange={(open) => !open && setConfirm(null)}>
|
|
925
|
+
<DialogContent
|
|
926
|
+
// Without this, the focus goes back to what Radix remembers, which is
|
|
927
|
+
// gone when the action was in the More menu or has disappeared.
|
|
928
|
+
onCloseAutoFocus={(event) => {
|
|
929
|
+
event.preventDefault();
|
|
930
|
+
confirm?.focus();
|
|
931
|
+
}}
|
|
932
|
+
>
|
|
933
|
+
{/* … */}
|
|
934
|
+
</DialogContent>
|
|
935
|
+
</Dialog>
|
|
936
|
+
```
|
|
937
|
+
|
|
883
938
|
```tsx
|
|
884
939
|
<ServerTable<Item>
|
|
885
940
|
{...props}
|
|
@@ -932,7 +987,7 @@ Its props are `ServerTableProps<T>`; `filter` is a `ServerTableFilter`,
|
|
|
932
987
|
| `error` | `ServerTableError \| null` | — | the fetch failed: the failure and a Retry replace the rows |
|
|
933
988
|
| `onRetry` | `() => unknown` | — | the error's Retry; a returned promise keeps it loading |
|
|
934
989
|
| `onClearFilters` | `() => void` | focus the table | without `filter`, after "clear" |
|
|
935
|
-
| `bulkActions` | `(ids, selection: ServerTableSelection) => ReactNode \| ServerTableBulkAction<T>[]` | — | the selection's toolbar: your own buttons, or a list of actions
|
|
990
|
+
| `bulkActions` | `(ids, selection: ServerTableSelection) => ReactNode \| ServerTableBulkAction<T>[]` | — | the selection's toolbar: your own buttons, or a list of actions (`appliesTo`, `name`, `max`, `maxNotice`; `onClick` also gets a `ServerTableBulkContext`) that each count and run only the rows they apply to |
|
|
936
991
|
| `enableRowSelection`, `rowSelectionDisabledReason` | `boolean \| (row) => boolean`, `(row) => string \| undefined` | all rows, no reason | with `bulkActions`: which rows can be selected, and why one cannot ([DataTable](#datatable)) |
|
|
937
992
|
| `pageHref` | `(params) => string` | `` `?${params}` `` | Previous / Next hrefs |
|
|
938
993
|
| `pagingNames` | `{ after?, trail? }` | `after`, `trail` | the cursor's params |
|
|
@@ -965,7 +1020,7 @@ rows (the bulk bar is not drawn under it). With the declarative list form of
|
|
|
965
1020
|
line rather than scroll, and past the third action the rest go into a "More"
|
|
966
1021
|
menu (`material.server-table.bulk-more`), each item keeping its count. From
|
|
967
1022
|
768px the buttons read "Label (n)" as before. When the focused button
|
|
968
|
-
disappears the focus goes to the next one, else to "Select all". The function
|
|
1023
|
+
disappears the focus goes to the next one, else to "More", else to "Select all"; an action past `max` shows its notice there (an inline text, or a disabled More item). The function
|
|
969
1024
|
form (`bulkActions={(ids) => node}`) is drawn whole in the row, so keep it to
|
|
970
1025
|
one or two compact buttons; the footer's polite status still tells the selection once. The cards'
|
|
971
1026
|
own list bar row is gone in this layout; the names, the sort menu and the
|
|
@@ -278,6 +278,12 @@ import { LineChart } from '@nxgt/material/charts';
|
|
|
278
278
|
/>;
|
|
279
279
|
```
|
|
280
280
|
|
|
281
|
+
A line chart can be read against a reference: `bands` shade a range of the
|
|
282
|
+
value axis (a normal range), `thresholds` draw labelled lines and `pointTone`
|
|
283
|
+
rings the values that need a word, which the tooltip, the summary and the
|
|
284
|
+
"View data" table repeat
|
|
285
|
+
([guide](../guides/charts.md#reading-values-against-a-reference)).
|
|
286
|
+
|
|
281
287
|
Parts: `LineChart`, `AreaChart`, `BarChart`, `PieChart`, `DonutChart`, `Gauge`,
|
|
282
288
|
`RadialBarChart`, `FunnelChart`, `HeatmapChart`, `RadarChart`, `ScatterChart`,
|
|
283
289
|
`ComboChart`.
|
|
@@ -373,7 +373,7 @@ export function Framework() {
|
|
|
373
373
|
|
|
374
374
|

|
|
375
375
|
|
|
376
|
-
Single or multiple (chips) autocomplete with free-solo values, accent-insensitive matching and a debounced server search.
|
|
376
|
+
Single or multiple (chips) autocomplete with free-solo values, accent-insensitive matching and a debounced server search; a single value can be the input's own text (`display="text"`).
|
|
377
377
|
|
|
378
378
|
```tsx
|
|
379
379
|
import { Autocomplete } from '@nxgt/material/components';
|
|
@@ -409,6 +409,8 @@ disabled with the field; Backspace in the empty input removes the last one.
|
|
|
409
409
|
| Prop | Type | Default | Effect |
|
|
410
410
|
| --- | --- | --- | --- |
|
|
411
411
|
| `mode` | `'single' \| 'multiple'` | — | required; decides the `value` type |
|
|
412
|
+
| `display` | `'chip' \| 'text'` | `'chip'` | `mode="single"` only: how the value is drawn, a removable chip beside the input (and its placeholder), or the input's own text (type `AutocompleteDisplay`; see [One value as text](#one-value-as-text)). Ignored in `multiple` |
|
|
413
|
+
| `clearable` | `boolean` | `true` | shows the "Clear" button; with `display="text"`, whether emptying the text and leaving the field clears the value |
|
|
412
414
|
| `value` | `string` / `string[]` | — | required, per `mode` |
|
|
413
415
|
| `onValueChange` | `(value?: string \| null) => void` / `(value?: string[] \| null) => void` | — | per `mode` |
|
|
414
416
|
| `options` | `T[]` (`{ value, label, disabled? }` by default) | `[]` | the items (`disabled` on one: listed, announced as disabled, never picked); with `onSearch`, the list before a search and the selected options' labels |
|
|
@@ -435,6 +437,50 @@ An avatar in the rows and the chips:
|
|
|
435
437
|
`getOptionLeading={(person) => <Avatar src={person.photo} alt="" />}`; see
|
|
436
438
|
[the field look](../guides/field-look-2-x.md#autocomplete-and-the-chips-box).
|
|
437
439
|
|
|
440
|
+
### One value as text
|
|
441
|
+
|
|
442
|
+
By default a single value is drawn as a chip, like a multi-select with one
|
|
443
|
+
entry. For picking one entry out of a long directory (a person, a place, a
|
|
444
|
+
resource), `display="text"` makes the chosen option's label the input's own
|
|
445
|
+
text, as a `Select` shows it, and keeps the search:
|
|
446
|
+
|
|
447
|
+
```tsx
|
|
448
|
+
<Autocomplete
|
|
449
|
+
mode="single"
|
|
450
|
+
display="text"
|
|
451
|
+
label="Member"
|
|
452
|
+
placeholder="Search a member"
|
|
453
|
+
options={selected ? [selected] : []}
|
|
454
|
+
onSearch={searchMembers}
|
|
455
|
+
value={value}
|
|
456
|
+
onValueChange={(next) => setValue(next ?? '')}
|
|
457
|
+
/>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
- The label fills the input (on the server too); the placeholder shows only
|
|
461
|
+
while the field is empty. The text is selected on focus, so typing replaces
|
|
462
|
+
it and searches again (`onSearch` or the local `filter`); the list opened on
|
|
463
|
+
the label is the whole `options`, not filtered by it.
|
|
464
|
+
- Typing changes nothing until an option is picked. **Escape**, or leaving
|
|
465
|
+
the field (Tab, a click elsewhere), drops the typed text and brings the
|
|
466
|
+
label back; the value never moved. Escape on a closed list does the same
|
|
467
|
+
instead of clearing.
|
|
468
|
+
- The "Clear" button empties the text and the value. Emptying the text by
|
|
469
|
+
hand and leaving the field clears the value too, since the field is
|
|
470
|
+
`clearable`. With `clearable={false}` there is no button, and an emptied text
|
|
471
|
+
gets the label back on leave: the value can only be replaced by another pick.
|
|
472
|
+
- The option's `getOptionLeading` (or `renderSelectedLeading`) avatar shows
|
|
473
|
+
before the text while it is picked.
|
|
474
|
+
- `freeSolo` still adds through its "Add" button; text left in the input and
|
|
475
|
+
not added is dropped on leave, as any other typed text.
|
|
476
|
+
- Keep the selected option in `options` (as with `onSearch` and chips): a value
|
|
477
|
+
with no matching option has no label, so the input stays empty.
|
|
478
|
+
- The input is the combobox: `aria-expanded` follows the list,
|
|
479
|
+
`aria-activedescendant` names the highlighted option, the picked option is
|
|
480
|
+
`aria-selected`, and the field's live region announces the suggestions as
|
|
481
|
+
before. `AutocompleteFormField` takes `display` and `clearable` too. Leaving the
|
|
482
|
+
window (Alt-Tab) is not leaving the field: the typed text waits.
|
|
483
|
+
|
|
438
484
|
### Searching a server
|
|
439
485
|
|
|
440
486
|
`onSearch` takes the query and an `AbortSignal`; hand the signal to `fetch`
|
package/docs/guides/charts.md
CHANGED
|
@@ -63,7 +63,7 @@ export function SalesChart() {
|
|
|
63
63
|
plot of the right height; the plot is drawn once the browser has measured its
|
|
64
64
|
width, with its final geometry (the entry motion only runs after that).
|
|
65
65
|
Nothing mismatches on hydration.
|
|
66
|
-
- **Types:** `ChartRow`, `RowKey`, `ChartValue`, `ChartSeries`, `ChartAxis`, `ChartXAxis`,
|
|
66
|
+
- **Types:** `ChartRow`, `RowKey`, `ChartValue`, `ChartSeries`, `ChartAxis`, `ChartXAxis`, `ChartBand`, `ChartThreshold`,
|
|
67
67
|
`ChartPoint`, `ChartBaseProps`, `ChartColor`, `ChartShape`, `ChartSlice`,
|
|
68
68
|
`ScatterSeries`, `ScatterPoint`, `ComboSeries`, `ChartRange`,
|
|
69
69
|
`ChartZoomOptions`, `ChartScrollOptions`, `ChartRangeProps`, `HeatColumn`,
|
|
@@ -203,6 +203,80 @@ The funnel is one series, so it takes no `legend`, `hidden` or `grid`; the round
|
|
|
203
203
|
charts take no `grid`, and the heat map no `hidden`, `grid` or `patterns` (these
|
|
204
204
|
are left out of their props types).
|
|
205
205
|
|
|
206
|
+
## Reading values against a reference
|
|
207
|
+
|
|
208
|
+
`LineChart` (and `AreaChart`, which takes the same props) can draw the range a
|
|
209
|
+
value is read against, so it is not painted outside the chart where the
|
|
210
|
+
tooltip, the summary and the table would miss it.
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
'use client';
|
|
214
|
+
import { LineChart } from '@nxgt/material/charts';
|
|
215
|
+
import type { ChartBand, ChartPoint, ChartThreshold } from '@nxgt/material/charts';
|
|
216
|
+
|
|
217
|
+
// Module-level (or memoized): the arrays and the function key the summary and the table.
|
|
218
|
+
const bands: ChartBand[] = [
|
|
219
|
+
{ from: 40, to: 60, label: 'Normal range', tone: 'success' },
|
|
220
|
+
];
|
|
221
|
+
const thresholds: ChartThreshold[] = [
|
|
222
|
+
{ value: 70, label: 'Upper limit', tone: 'error' },
|
|
223
|
+
{ value: 30, label: 'Lower limit', tone: 'info', dash: false },
|
|
224
|
+
];
|
|
225
|
+
const toneOf = (point: ChartPoint) =>
|
|
226
|
+
point.value > 70 ? 'error' : point.value > 60 ? 'warning' : point.value < 40 ? 'info' : undefined;
|
|
227
|
+
|
|
228
|
+
<LineChart
|
|
229
|
+
title="Daily readings"
|
|
230
|
+
data={readings}
|
|
231
|
+
x="day"
|
|
232
|
+
series={[{ key: 'reading', label: 'Reading' }]}
|
|
233
|
+
points
|
|
234
|
+
bands={bands}
|
|
235
|
+
thresholds={thresholds}
|
|
236
|
+
pointTone={toneOf}
|
|
237
|
+
toneLabels={{ error: 'Critical', warning: 'High', info: 'Low' }}
|
|
238
|
+
/>;
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
| Prop | Effect |
|
|
242
|
+
| --- | --- |
|
|
243
|
+
| `bands` | `{ from, to, label, tone? }[]`: a wash across the plot behind the lines, with its `label` inside it at the left. `from` and `to` may come in either order. |
|
|
244
|
+
| `thresholds` | `{ value, label, tone?, dash? }[]`: a horizontal line behind the series with its `label` above it at the right end; dashed unless `dash: false`. |
|
|
245
|
+
| `pointTone` | `(point: ChartPoint, series: ChartSeries) => Tone \| undefined`: the tone of one value. It is given the point `onPointClick` gets, so `point.index` is the row of the full `data` even when the chart is zoomed. |
|
|
246
|
+
| `toneLabels` | `{ [tone]: word }`: the word of each tone, in your language and domain. Unset, the library's neutral word ("Error", translated by `material.charts.tone.*`); an app tone you declared falls back to its own name. |
|
|
247
|
+
|
|
248
|
+
**The value axis holds them.** Unless `yAxis.min` and `yAxis.max` pin it, the
|
|
249
|
+
axis grows to include every band end and threshold, so none is out of view.
|
|
250
|
+
With a pinned axis a band is clipped to the plot and a threshold outside it is
|
|
251
|
+
not drawn (it stays in the summary and the table). The scales are the chart's
|
|
252
|
+
own, so a `zoom` window, a phone `scroll` and a resize keep them right.
|
|
253
|
+
|
|
254
|
+
**The words are carried everywhere the picture is.**
|
|
255
|
+
|
|
256
|
+
- The **tooltip** and the **live status** add the tone's word to a toned
|
|
257
|
+
value: `Day 4: Reading 63 (High)`.
|
|
258
|
+
- The **summary** lists the ranges and lines (`Reference ranges: Normal range:
|
|
259
|
+
40 to 60. Thresholds: Upper limit: 70`), says how many values of each series
|
|
260
|
+
lie outside each band (`Reading: 5 of 12 points outside Normal range.`) and
|
|
261
|
+
counts the tones (`Reading: 2 High, 1 Critical, 2 Low, of 12 points.`). Over
|
|
262
|
+
a `zoom` window it counts the window's rows.
|
|
263
|
+
- **View data** gets a column after each toned series (`Reading tone`) and a
|
|
264
|
+
list of the ranges and lines under the table.
|
|
265
|
+
|
|
266
|
+
**Never colour alone.** A toned point is drawn as a ring in the tone's colour
|
|
267
|
+
round the value (the series' own shape inside the ring with `patterns`), so it
|
|
268
|
+
differs from an untoned dot by its form. A band is a decorative tint: the
|
|
269
|
+
label, the summary and the table carry its meaning. Labels use the tone's text
|
|
270
|
+
colour (4.5:1) on a card-coloured halo, lines and rings hold 3:1, and in
|
|
271
|
+
forced colours the band is outlined and the lines, labels and rings use system
|
|
272
|
+
colours. Nothing animates: reduced motion changes nothing here. Labels are
|
|
273
|
+
cut to 45% of the plot's width, and a label in a right-to-left script is set
|
|
274
|
+
right to left (the plot itself is never mirrored, see
|
|
275
|
+
[Right-to-left pages](#right-to-left-pages)).
|
|
276
|
+
|
|
277
|
+
A custom `tooltip` function receives the points as before; read the tone from
|
|
278
|
+
your own `pointTone` if it should show the word.
|
|
279
|
+
|
|
206
280
|
## Shared props
|
|
207
281
|
|
|
208
282
|
Every chart takes the shared props (`ChartBaseProps`):
|
|
@@ -398,7 +472,9 @@ keyboard behaviour.
|
|
|
398
472
|
contrast alone, so the heat map is exempt from the 3:1 non-text rule for that
|
|
399
473
|
step, and **View data** (the whole matrix as a table) is the accessible
|
|
400
474
|
fallback; the number in a cell keeps 4.5:1 against its own fill.
|
|
401
|
-
- **Never colour alone:** `patterns` adds shapes, dashes and fill patterns
|
|
475
|
+
- **Never colour alone:** `patterns` adds shapes, dashes and fill patterns; a
|
|
476
|
+
toned point is a ring and its word is in the tooltip, the summary and the
|
|
477
|
+
table ([Reading values against a reference](#reading-values-against-a-reference)).
|
|
402
478
|
- **Reduced motion:** with `prefers-reduced-motion`, the final geometry shows at
|
|
403
479
|
once with a short 120ms fade; there is no bounce, draw-in or morph, and the
|
|
404
480
|
crosshair jumps.
|
package/docs/guides/i18n.md
CHANGED
|
@@ -404,7 +404,7 @@ fichier.") when it cannot show it, `material.file-preview.download`
|
|
|
404
404
|
"Seuls les premiers {size} de ce fichier sont affichés.") under a text cut
|
|
405
405
|
by the size cap; the text or Markdown it shows scrolls in a region named by
|
|
406
406
|
`material.file-preview.content` ("Contents of {name}", "Contenu de {name}").
|
|
407
|
-
A `ServerTable` bulk action with a list entry reads `material.server-table.bulk-action` ("{label} ({count})", the same in French) and is named by `material.server-table.bulk-action-name` ("{label} {count, plural, one {# row} other {# rows}}"; "{label} : {count, plural, one {# ligne} other {# lignes}}").
|
|
407
|
+
A `ServerTable` bulk action with a list entry reads `material.server-table.bulk-action` ("{label} ({count})", the same in French) and is named by `material.server-table.bulk-action-name` ("{label} {count, plural, one {# row} other {# rows}}"; "{label} : {count, plural, one {# ligne} other {# lignes}}"). Past the action's `max` the notice that replaces its button reads `material.server-table.bulk-max-notice` ("Select {max, plural, one {# row} other {# rows}} or fewer to {label}"; "Sélectionnez {max, plural, one {# ligne} other {# lignes}} ou moins pour {label}"), unless the action gives its `maxNotice`; an action's `name` replaces `bulk-action-name`.
|
|
408
408
|
`ServerTable`'s own live region (without `filter`) says
|
|
409
409
|
`material.server-table.results` once a new query is answered ("{count,
|
|
410
410
|
plural, =0 {No results} one {# result} other {# results}}"; "{count, plural,
|
package/docs/roadmap.md
CHANGED
|
@@ -482,6 +482,13 @@ version they shipped in, and planned entries may name the major they target.
|
|
|
482
482
|
slider handles) and a phone scroll that opens on the latest point. The
|
|
483
483
|
light `--chart-4` is now a purple. Client-only, like `/editor`.
|
|
484
484
|
([Charts](guides/charts.md))
|
|
485
|
+
- **Reference bands, thresholds and point tones on the line chart** — `bands`
|
|
486
|
+
shade a range of the value axis, `thresholds` draw labelled lines, and
|
|
487
|
+
`pointTone` rings the values that need a word (`toneLabels` gives the words).
|
|
488
|
+
The words reach the tooltip, the live status, the summary (values outside a
|
|
489
|
+
band, tone counts) and a tone column of "View data"; the axis grows to hold
|
|
490
|
+
them and a zoom window keeps them right.
|
|
491
|
+
([Reading values against a reference](guides/charts.md#reading-values-against-a-reference))
|
|
485
492
|
|
|
486
493
|
- **The page's title in the app bar, a text breadcrumb root and the tenant in the menu** —
|
|
487
494
|
a route's `handle.title` (a node, or a function of the match like
|
|
@@ -150,6 +150,7 @@
|
|
|
150
150
|
@import "./ui/widgets/native-charts/native-charts-round.css";
|
|
151
151
|
@import "./ui/widgets/native-charts/native-charts-heat.css";
|
|
152
152
|
@import "./ui/widgets/native-charts/native-charts-points.css";
|
|
153
|
+
@import "./ui/widgets/native-charts/native-charts-reference.css";
|
|
153
154
|
@import "./ui/widgets/native-charts/native-charts-zoom.css";
|
|
154
155
|
/* The editor's documents: `.nxgt-prose`, shared with the viewer. */
|
|
155
156
|
@import "./editor-prose.css";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* A line chart's reference bands, threshold lines and toned points. Reached
|
|
2
|
+
* from components.css.
|
|
3
|
+
*
|
|
4
|
+
* A band is a wash across the plot, behind the lines: decorative, since its
|
|
5
|
+
* label (read aloud by the summary and listed under "View data") carries the
|
|
6
|
+
* meaning. A tone paints it with the tone itself at 12%; without one it is
|
|
7
|
+
* the foreground at 6%. Labels and threshold lines use the tone's text
|
|
8
|
+
* colour (4.5:1 on the card, both themes) or the foreground, and sit on a
|
|
9
|
+
* card-coloured halo so a line passing behind them does not cut the letters.
|
|
10
|
+
* A toned point is a ring round the value: a shape, never colour alone. */
|
|
11
|
+
.nxgt-chart-ref-band {
|
|
12
|
+
fill: var(--foreground);
|
|
13
|
+
opacity: 0.06;
|
|
14
|
+
}
|
|
15
|
+
.nxgt-chart-ref-band[data-tone] {
|
|
16
|
+
fill: var(--nxgt-tone);
|
|
17
|
+
opacity: 0.12;
|
|
18
|
+
}
|
|
19
|
+
.nxgt-chart-ref-line {
|
|
20
|
+
stroke: var(--nxgt-chart-axis);
|
|
21
|
+
stroke-width: 1.5;
|
|
22
|
+
stroke-dasharray: 6 4;
|
|
23
|
+
}
|
|
24
|
+
.nxgt-chart-ref-line[data-dash="false"] {
|
|
25
|
+
stroke-dasharray: none;
|
|
26
|
+
}
|
|
27
|
+
.nxgt-chart-ref-line[data-tone] {
|
|
28
|
+
stroke: var(--nxgt-tone-text);
|
|
29
|
+
}
|
|
30
|
+
.nxgt-chart-ref-label {
|
|
31
|
+
fill: var(--foreground);
|
|
32
|
+
font-size: 11px;
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
paint-order: stroke;
|
|
35
|
+
stroke: var(--card);
|
|
36
|
+
stroke-width: 3px;
|
|
37
|
+
stroke-linejoin: round;
|
|
38
|
+
pointer-events: none;
|
|
39
|
+
}
|
|
40
|
+
.nxgt-chart-ref-label[data-tone] {
|
|
41
|
+
fill: var(--nxgt-tone-text);
|
|
42
|
+
}
|
|
43
|
+
.nxgt-chart[data-phone] .nxgt-chart-ref-label {
|
|
44
|
+
font-size: 10px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nxgt-chart-tone-ring {
|
|
48
|
+
fill: var(--card);
|
|
49
|
+
stroke: var(--nxgt-tone-text);
|
|
50
|
+
stroke-width: 2;
|
|
51
|
+
}
|
|
52
|
+
.nxgt-chart-tone-dot {
|
|
53
|
+
fill: var(--nxgt-tone-text);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* The tone's word in the tooltip, with the ring the plot draws. */
|
|
57
|
+
.nxgt-chart-tip-tone {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
gap: 4px;
|
|
61
|
+
color: var(--nxgt-tone-text);
|
|
62
|
+
font-size: 12px;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Under "View data": the ranges and lines read as a list. */
|
|
67
|
+
.nxgt-chart-table-notes {
|
|
68
|
+
margin: 8px 0 0;
|
|
69
|
+
padding: 0;
|
|
70
|
+
list-style: none;
|
|
71
|
+
color: var(--muted-foreground);
|
|
72
|
+
font-size: 12px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (forced-colors: active) {
|
|
76
|
+
.nxgt-chart-ref-band {
|
|
77
|
+
fill: Canvas;
|
|
78
|
+
stroke: GrayText;
|
|
79
|
+
stroke-width: 1;
|
|
80
|
+
stroke-dasharray: 2 3;
|
|
81
|
+
opacity: 1;
|
|
82
|
+
}
|
|
83
|
+
.nxgt-chart-ref-line,
|
|
84
|
+
.nxgt-chart-ref-line[data-tone] {
|
|
85
|
+
stroke: CanvasText;
|
|
86
|
+
}
|
|
87
|
+
.nxgt-chart-ref-label,
|
|
88
|
+
.nxgt-chart-ref-label[data-tone] {
|
|
89
|
+
fill: CanvasText;
|
|
90
|
+
stroke: Canvas;
|
|
91
|
+
}
|
|
92
|
+
.nxgt-chart-tone-ring {
|
|
93
|
+
fill: Canvas;
|
|
94
|
+
stroke: Highlight;
|
|
95
|
+
}
|
|
96
|
+
.nxgt-chart-tone-dot {
|
|
97
|
+
fill: Highlight;
|
|
98
|
+
}
|
|
99
|
+
.nxgt-chart-tip-tone {
|
|
100
|
+
color: CanvasText;
|
|
101
|
+
}
|
|
102
|
+
}
|