@nizivo/react 0.1.0 → 0.2.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/THIRD_PARTY_NOTICES +12 -5
- package/dist/_engines/react-aria/dialog.client.js +16 -24
- package/dist/_engines/react-aria/drawer.client.js +8 -0
- package/dist/_engines/react-aria/file-upload.client.js +50 -0
- package/dist/_engines/react-aria/menu.client.js +17 -13
- package/dist/_engines/react-aria/open-state.client.js +53 -0
- package/dist/_engines/react-aria/outside-press.client.js +61 -0
- package/dist/_engines/react-aria/overlay.client.js +6 -1
- package/dist/_engines/react-aria/popover.client.js +148 -0
- package/dist/_engines/react-aria/popup.client.js +31 -5
- package/dist/_engines/react-aria/select.client.js +22 -12
- package/dist/_engines/react-aria/toast.client.js +38 -0
- package/dist/_engines/react-aria/tooltip.client.js +11 -11
- package/dist/_internal/data-status.d.ts +3 -0
- package/dist/_internal/data-status.js +13 -0
- package/dist/_internal/glyphs.js +54 -1
- package/dist/_internal/modal.client.js +54 -0
- package/dist/_internal/nested-focus.js +33 -0
- package/dist/alert/alert-dismiss.client.d.ts +1 -1
- package/dist/alert/alert-dismiss.client.js +3 -1
- package/dist/app-shell/app-shell.d.ts +24 -0
- package/dist/app-shell/app-shell.js +56 -0
- package/dist/app-shell/index.d.ts +2 -0
- package/dist/app-shell/index.js +1 -0
- package/dist/avatar/avatar.d.ts +96 -0
- package/dist/avatar/avatar.js +94 -0
- package/dist/avatar/index.d.ts +2 -0
- package/dist/avatar/index.js +1 -0
- package/dist/banner/banner-dismiss.client.d.ts +32 -0
- package/dist/banner/banner-dismiss.client.js +38 -0
- package/dist/banner/banner.d.ts +34 -0
- package/dist/banner/banner.js +47 -0
- package/dist/banner/index.d.ts +3 -0
- package/dist/banner/index.js +3 -0
- package/dist/breadcrumb/breadcrumb.d.ts +46 -0
- package/dist/breadcrumb/breadcrumb.js +46 -0
- package/dist/breadcrumb/breadcrumb.parts.d.ts +6 -0
- package/dist/breadcrumb/breadcrumb.parts.js +9 -0
- package/dist/breadcrumb/index.d.ts +3 -0
- package/dist/breadcrumb/index.js +3 -0
- package/dist/button/button.d.ts +3 -2
- package/dist/card/card.d.ts +9 -2
- package/dist/chip-group/chip-group.client.d.ts +88 -0
- package/dist/chip-group/chip-group.client.js +157 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +1 -0
- package/dist/choice-card/choice-card.client.d.ts +66 -0
- package/dist/choice-card/choice-card.client.js +138 -0
- package/dist/choice-card/index.d.ts +2 -0
- package/dist/choice-card/index.js +1 -0
- package/dist/config/config.client.d.ts +16 -1
- package/dist/config/config.client.js +18 -3
- package/dist/config/index.d.ts +2 -2
- package/dist/contracts/index.d.ts +1 -1
- package/dist/css/app-shell.css +2 -0
- package/dist/css/avatar.css +2 -0
- package/dist/css/banner.css +2 -0
- package/dist/css/base.css +1 -1
- package/dist/css/breadcrumb.css +2 -0
- package/dist/css/card.css +1 -1
- package/dist/css/chip-group.css +2 -0
- package/dist/css/choice-card.css +2 -0
- package/dist/css/delta.css +1 -1
- package/dist/css/drawer.css +2 -0
- package/dist/css/file-upload.css +2 -0
- package/dist/css/form.css +2 -0
- package/dist/css/heading.css +1 -1
- package/dist/css/kpi-tile.css +2 -0
- package/dist/css/metric.css +2 -0
- package/dist/css/mobile-tab-bar.css +2 -0
- package/dist/css/mobile-top-bar.css +2 -0
- package/dist/css/motion.css +2 -0
- package/dist/css/nav-item.css +2 -0
- package/dist/css/number-value.css +2 -0
- package/dist/css/page-header.css +2 -0
- package/dist/css/pagination.css +2 -0
- package/dist/css/password-input.css +2 -0
- package/dist/css/popover.css +2 -0
- package/dist/css/ranked-list.css +2 -0
- package/dist/css/search-field.css +2 -0
- package/dist/css/sidebar.css +2 -0
- package/dist/css/split.css +2 -0
- package/dist/css/sticky-bar.css +2 -0
- package/dist/css/table-selection.css +2 -0
- package/dist/css/table.css +2 -0
- package/dist/css/text.css +1 -1
- package/dist/css/toast.css +2 -0
- package/dist/css/top-bar.css +2 -0
- package/dist/css/trend-card.css +2 -0
- package/dist/dialog/dialog.client.d.ts +1 -1
- package/dist/dialog/dialog.client.js +15 -37
- package/dist/drawer/drawer.client.d.ts +25 -0
- package/dist/drawer/drawer.client.js +154 -0
- package/dist/drawer/drawer.contract.d.ts +98 -0
- package/dist/drawer/drawer.parts.d.ts +6 -0
- package/dist/drawer/drawer.parts.js +16 -0
- package/dist/drawer/index.d.ts +5 -0
- package/dist/drawer/index.js +3 -0
- package/dist/field/field-scope.client.js +9 -2
- package/dist/file-upload/file-upload.client.d.ts +9 -0
- package/dist/file-upload/file-upload.client.js +406 -0
- package/dist/file-upload/file-upload.contract.d.ts +112 -0
- package/dist/file-upload/index.d.ts +3 -0
- package/dist/file-upload/index.js +1 -0
- package/dist/file-upload/seam.d.ts +1 -0
- package/dist/form/form.client.d.ts +38 -0
- package/dist/form/form.client.js +127 -0
- package/dist/form/form.d.ts +36 -0
- package/dist/form/form.js +29 -0
- package/dist/form/index.d.ts +4 -0
- package/dist/form/index.js +4 -0
- package/dist/form/submit-button.client.d.ts +20 -0
- package/dist/form/submit-button.client.js +19 -0
- package/dist/heading/heading.d.ts +4 -1
- package/dist/i18n/format-label.d.ts +24 -0
- package/dist/i18n/format-label.js +19 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/icon-button/icon-button.client.js +1 -1
- package/dist/icon-button/icon-button.js +1 -1
- package/dist/index.d.ts +84 -5
- package/dist/index.js +49 -4
- package/dist/kpi-tile/index.d.ts +2 -0
- package/dist/kpi-tile/index.js +1 -0
- package/dist/kpi-tile/kpi-tile.d.ts +30 -0
- package/dist/kpi-tile/kpi-tile.js +48 -0
- package/dist/locales/en-US.d.ts +77 -0
- package/dist/locales/en-US.js +83 -0
- package/dist/menu/menu.contract.d.ts +1 -1
- package/dist/metric/index.d.ts +2 -0
- package/dist/metric/index.js +1 -0
- package/dist/metric/metric.d.ts +72 -0
- package/dist/metric/metric.js +116 -0
- package/dist/mobile-tab-bar/index.d.ts +4 -0
- package/dist/mobile-tab-bar/index.js +4 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-inset.client.js +38 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.d.ts +26 -0
- package/dist/mobile-tab-bar/mobile-tab-bar-more.client.js +60 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.d.ts +39 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.js +54 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.d.ts +6 -0
- package/dist/mobile-tab-bar/mobile-tab-bar.parts.js +9 -0
- package/dist/mobile-top-bar/index.d.ts +2 -0
- package/dist/mobile-top-bar/index.js +1 -0
- package/dist/mobile-top-bar/mobile-top-bar.d.ts +17 -0
- package/dist/mobile-top-bar/mobile-top-bar.js +31 -0
- package/dist/motion/count-up.client.d.ts +39 -0
- package/dist/motion/count-up.client.js +109 -0
- package/dist/motion/index.d.ts +2 -0
- package/dist/motion/index.js +1 -0
- package/dist/nav-item/index.d.ts +2 -0
- package/dist/nav-item/index.js +1 -0
- package/dist/nav-item/nav-item.d.ts +35 -0
- package/dist/nav-item/nav-item.js +50 -0
- package/dist/number-value/index.d.ts +2 -0
- package/dist/number-value/index.js +1 -0
- package/dist/number-value/number-value.d.ts +25 -0
- package/dist/number-value/number-value.js +26 -0
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +1 -0
- package/dist/page-header/page-header.d.ts +19 -0
- package/dist/page-header/page-header.js +39 -0
- package/dist/pagination/index.d.ts +2 -0
- package/dist/pagination/index.js +1 -0
- package/dist/pagination/pagination.d.ts +74 -0
- package/dist/pagination/pagination.js +136 -0
- package/dist/password-input/index.d.ts +2 -0
- package/dist/password-input/index.js +1 -0
- package/dist/password-input/password-input.client.d.ts +52 -0
- package/dist/password-input/password-input.client.js +106 -0
- package/dist/popover/index.d.ts +5 -0
- package/dist/popover/index.js +3 -0
- package/dist/popover/popover.client.d.ts +20 -0
- package/dist/popover/popover.client.js +113 -0
- package/dist/popover/popover.contract.d.ts +88 -0
- package/dist/popover/popover.parts.d.ts +6 -0
- package/dist/popover/popover.parts.js +13 -0
- package/dist/ranked-list/index.d.ts +3 -0
- package/dist/ranked-list/index.js +3 -0
- package/dist/ranked-list/ranked-list.d.ts +85 -0
- package/dist/ranked-list/ranked-list.js +153 -0
- package/dist/ranked-list/ranked-list.parts.d.ts +6 -0
- package/dist/ranked-list/ranked-list.parts.js +10 -0
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +1 -0
- package/dist/search-field/search-field.client.d.ts +55 -0
- package/dist/search-field/search-field.client.js +136 -0
- package/dist/select/select.contract.d.ts +1 -1
- package/dist/sidebar/index.d.ts +4 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar-item.client.d.ts +10 -0
- package/dist/sidebar/sidebar-item.client.js +55 -0
- package/dist/sidebar/sidebar.d.ts +45 -0
- package/dist/sidebar/sidebar.js +62 -0
- package/dist/sidebar/sidebar.parts.d.ts +6 -0
- package/dist/sidebar/sidebar.parts.js +11 -0
- package/dist/split/index.d.ts +3 -0
- package/dist/split/index.js +3 -0
- package/dist/split/split.d.ts +28 -0
- package/dist/split/split.js +33 -0
- package/dist/split/split.parts.d.ts +6 -0
- package/dist/split/split.parts.js +10 -0
- package/dist/sticky-bar/index.d.ts +2 -0
- package/dist/sticky-bar/index.js +1 -0
- package/dist/sticky-bar/sticky-bar.d.ts +16 -0
- package/dist/sticky-bar/sticky-bar.js +26 -0
- package/dist/styles.css +66 -7
- package/dist/table/index.d.ts +3 -0
- package/dist/table/index.js +3 -0
- package/dist/table/table.d.ts +101 -0
- package/dist/table/table.js +121 -0
- package/dist/table/table.parts.d.ts +6 -0
- package/dist/table/table.parts.js +18 -0
- package/dist/table-selection/index.d.ts +3 -0
- package/dist/table-selection/index.js +3 -0
- package/dist/table-selection/table-selection.client.d.ts +14 -0
- package/dist/table-selection/table-selection.client.js +84 -0
- package/dist/table-selection/table-selection.d.ts +34 -0
- package/dist/table-selection/table-selection.js +50 -0
- package/dist/text/text.d.ts +13 -2
- package/dist/toast/index.d.ts +4 -0
- package/dist/toast/index.js +3 -0
- package/dist/toast/seam.d.ts +2 -0
- package/dist/toast/store.d.ts +19 -0
- package/dist/toast/store.js +136 -0
- package/dist/toast/toast.contract.d.ts +56 -0
- package/dist/toast/toaster.client.d.ts +10 -0
- package/dist/toast/toaster.client.js +305 -0
- package/dist/tooltip/tooltip.contract.d.ts +1 -1
- package/dist/top-bar/index.d.ts +2 -0
- package/dist/top-bar/index.js +1 -0
- package/dist/top-bar/top-bar.d.ts +17 -0
- package/dist/top-bar/top-bar.js +35 -0
- package/dist/trend-card/index.d.ts +2 -0
- package/dist/trend-card/index.js +1 -0
- package/dist/trend-card/trend-card.d.ts +34 -0
- package/dist/trend-card/trend-card.js +74 -0
- package/package.json +167 -4
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { RenderProp } from "../contracts/render.js";
|
|
2
|
+
import { ComponentPropsWithRef, ReactElement } from "react";
|
|
3
|
+
//#region src/table/table.d.ts
|
|
4
|
+
type Empty = Record<string, never>;
|
|
5
|
+
export type TableSort = "ascending" | "descending";
|
|
6
|
+
export interface TableContainerProps extends ComponentPropsWithRef<"div"> {
|
|
7
|
+
/**
|
|
8
|
+
* Names the container as a scrollable region and puts it in the Tab order, so a keyboard can
|
|
9
|
+
* scroll a table wider than the screen (Safari and Firefox do not focus a scroller on their own).
|
|
10
|
+
* Give it when the table can scroll sideways and its rows hold no link or control.
|
|
11
|
+
*/
|
|
12
|
+
label?: string;
|
|
13
|
+
render?: RenderProp<Empty>;
|
|
14
|
+
}
|
|
15
|
+
export interface TableRootProps extends ComponentPropsWithRef<"table"> {
|
|
16
|
+
render?: RenderProp<Empty>;
|
|
17
|
+
}
|
|
18
|
+
export interface TableCaptionProps extends ComponentPropsWithRef<"caption"> {
|
|
19
|
+
/**
|
|
20
|
+
* Keeps the caption as the table's accessible name but hides it from sight, for a table whose
|
|
21
|
+
* card already shows a heading. @default false
|
|
22
|
+
*/
|
|
23
|
+
visuallyHidden?: boolean;
|
|
24
|
+
render?: RenderProp<Empty>;
|
|
25
|
+
}
|
|
26
|
+
export interface TableSectionProps extends ComponentPropsWithRef<"tbody"> {
|
|
27
|
+
render?: RenderProp<Empty>;
|
|
28
|
+
}
|
|
29
|
+
export interface TableRowState {
|
|
30
|
+
selected: boolean;
|
|
31
|
+
interactive: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface TableRowProps extends ComponentPropsWithRef<"tr"> {
|
|
34
|
+
/** `data-selected` (never `aria-selected` inside a table, §16.2). @default false */
|
|
35
|
+
selected?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The whole row is the hit area of its `Table.RowLink` (a stretched link) and shows Figma's hover.
|
|
38
|
+
* Other controls in the row stay above the link. @default false
|
|
39
|
+
*/
|
|
40
|
+
interactive?: boolean;
|
|
41
|
+
render?: RenderProp<TableRowState>;
|
|
42
|
+
}
|
|
43
|
+
export interface TableHeadState {
|
|
44
|
+
sort: TableSort | undefined;
|
|
45
|
+
numeric: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface TableHeadProps extends ComponentPropsWithRef<"th"> {
|
|
48
|
+
/** The column's current sort: `aria-sort` and `data-sort` on the `<th>`. */
|
|
49
|
+
sort?: TableSort;
|
|
50
|
+
/** A column of numbers: end-aligned, tabular figures. @default false */
|
|
51
|
+
numeric?: boolean;
|
|
52
|
+
/** `row` for a row header in the body. @default 'col' */
|
|
53
|
+
scope?: "col" | "row" | "colgroup" | "rowgroup";
|
|
54
|
+
render?: RenderProp<TableHeadState>;
|
|
55
|
+
}
|
|
56
|
+
export interface TableCellState {
|
|
57
|
+
numeric: boolean;
|
|
58
|
+
}
|
|
59
|
+
export interface TableCellProps extends ComponentPropsWithRef<"td"> {
|
|
60
|
+
/** A number: end-aligned, tabular figures. @default false */
|
|
61
|
+
numeric?: boolean;
|
|
62
|
+
render?: RenderProp<TableCellState>;
|
|
63
|
+
}
|
|
64
|
+
export interface TableSortButtonProps extends ComponentPropsWithRef<"button"> {
|
|
65
|
+
/**
|
|
66
|
+
* The same page sorted by this column, for example `href="?sort=-total"`: the part renders an
|
|
67
|
+
* `<a>`, and the URL holds the state. With neither `href` nor `render` it is a
|
|
68
|
+
* `<button type="button">` for your own handler.
|
|
69
|
+
*/
|
|
70
|
+
href?: string;
|
|
71
|
+
/** The router's link, for example `render={<Link href="?sort=-total" />}`. */
|
|
72
|
+
render?: RenderProp<Empty>;
|
|
73
|
+
}
|
|
74
|
+
export interface TableRowLinkProps extends ComponentPropsWithRef<"a"> {
|
|
75
|
+
/** The router's link, for example `render={<Link href="/orders/1042" />}`. It must render an `<a>`. */
|
|
76
|
+
render?: RenderProp<Empty>;
|
|
77
|
+
}
|
|
78
|
+
/** The table's box: the border, the radius and the horizontal scroll of a wide table. */
|
|
79
|
+
export declare function TableContainer({ label, render, className, ...rest }: TableContainerProps): ReactElement;
|
|
80
|
+
export declare function TableRoot({ render, className, ...rest }: TableRootProps): ReactElement;
|
|
81
|
+
/** The table's name. Give every table one: a caption, or `aria-labelledby` to a visible heading. */
|
|
82
|
+
export declare function TableCaption({ visuallyHidden, render, className, ...rest }: TableCaptionProps): ReactElement;
|
|
83
|
+
export declare function TableHeader({ render, className, ...rest }: TableSectionProps): ReactElement;
|
|
84
|
+
export declare function TableBody({ render, className, ...rest }: TableSectionProps): ReactElement;
|
|
85
|
+
export declare function TableFooter({ render, className, ...rest }: TableSectionProps): ReactElement;
|
|
86
|
+
export declare function TableRow({ selected, interactive, render, className, ...rest }: TableRowProps): ReactElement;
|
|
87
|
+
export declare function TableHead({ sort, numeric, scope, render, className, ...rest }: TableHeadProps): ReactElement;
|
|
88
|
+
export declare function TableCell({ numeric, render, className, ...rest }: TableCellProps): ReactElement;
|
|
89
|
+
/**
|
|
90
|
+
* The column's label as a control. Its arrow follows the `sort` of the `Table.Head` it sits in
|
|
91
|
+
* (up for ascending, down for descending, both ways when unsorted) through CSS, so it needs no
|
|
92
|
+
* client code; the `<th>`'s `aria-sort` tells assistive technology the current order.
|
|
93
|
+
*/
|
|
94
|
+
export declare function TableSortButton({ href, render, className, children, ...rest }: TableSortButtonProps): ReactElement;
|
|
95
|
+
/**
|
|
96
|
+
* A row's link, usually its first cell's text (Figma Order Row: the order number). In a row with
|
|
97
|
+
* `interactive`, it stretches over the whole row.
|
|
98
|
+
*/
|
|
99
|
+
export declare function TableRowLink({ render, className, ...rest }: TableRowLinkProps): ReactElement;
|
|
100
|
+
//#endregion
|
|
101
|
+
export {};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { cx } from "../_internal/cx.js";
|
|
2
|
+
import { renderElement } from "../contracts/render.js";
|
|
3
|
+
import { ChevronGlyph, ChevronsUpDownGlyph } from "../_internal/glyphs.js";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
//#region src/table/table.tsx
|
|
6
|
+
/** The table's box: the border, the radius and the horizontal scroll of a wide table. */
|
|
7
|
+
function TableContainer({ label, render, className, ...rest }) {
|
|
8
|
+
return renderElement("div", render, {}, {
|
|
9
|
+
"data-slot": "table-container",
|
|
10
|
+
...label === void 0 ? {} : {
|
|
11
|
+
role: "region",
|
|
12
|
+
"aria-label": label,
|
|
13
|
+
tabIndex: 0
|
|
14
|
+
},
|
|
15
|
+
...rest,
|
|
16
|
+
className: cx("nz-table-container", className)
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function TableRoot({ render, className, ...rest }) {
|
|
20
|
+
return renderElement("table", render, {}, {
|
|
21
|
+
"data-slot": "table",
|
|
22
|
+
...rest,
|
|
23
|
+
className: cx("nz-table", className)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
/** The table's name. Give every table one: a caption, or `aria-labelledby` to a visible heading. */
|
|
27
|
+
function TableCaption({ visuallyHidden = false, render, className, ...rest }) {
|
|
28
|
+
return renderElement("caption", render, {}, {
|
|
29
|
+
"data-slot": "table-caption",
|
|
30
|
+
...rest,
|
|
31
|
+
className: cx("nz-table-caption", visuallyHidden && "nz-visually-hidden", className)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function TableHeader({ render, className, ...rest }) {
|
|
35
|
+
return renderElement("thead", render, {}, {
|
|
36
|
+
"data-slot": "table-header",
|
|
37
|
+
...rest,
|
|
38
|
+
className: cx("nz-table-header", className)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function TableBody({ render, className, ...rest }) {
|
|
42
|
+
return renderElement("tbody", render, {}, {
|
|
43
|
+
"data-slot": "table-body",
|
|
44
|
+
...rest,
|
|
45
|
+
className: cx("nz-table-body", className)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function TableFooter({ render, className, ...rest }) {
|
|
49
|
+
return renderElement("tfoot", render, {}, {
|
|
50
|
+
"data-slot": "table-footer",
|
|
51
|
+
...rest,
|
|
52
|
+
className: cx("nz-table-footer", className)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function TableRow({ selected = false, interactive = false, render, className, ...rest }) {
|
|
56
|
+
return renderElement("tr", render, {
|
|
57
|
+
selected,
|
|
58
|
+
interactive
|
|
59
|
+
}, {
|
|
60
|
+
"data-slot": "table-row",
|
|
61
|
+
"data-selected": selected ? "" : void 0,
|
|
62
|
+
"data-interactive": interactive ? "" : void 0,
|
|
63
|
+
...rest,
|
|
64
|
+
className: cx("nz-table-row", className)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function TableHead({ sort, numeric = false, scope = "col", render, className, ...rest }) {
|
|
68
|
+
return renderElement("th", render, {
|
|
69
|
+
sort,
|
|
70
|
+
numeric
|
|
71
|
+
}, {
|
|
72
|
+
"data-slot": "table-head",
|
|
73
|
+
"data-sort": sort,
|
|
74
|
+
"data-numeric": numeric ? "" : void 0,
|
|
75
|
+
"aria-sort": sort,
|
|
76
|
+
scope,
|
|
77
|
+
...rest,
|
|
78
|
+
className: cx("nz-table-head", className)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function TableCell({ numeric = false, render, className, ...rest }) {
|
|
82
|
+
return renderElement("td", render, { numeric }, {
|
|
83
|
+
"data-slot": "table-cell",
|
|
84
|
+
"data-numeric": numeric ? "" : void 0,
|
|
85
|
+
...rest,
|
|
86
|
+
className: cx("nz-table-cell", className)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The column's label as a control. Its arrow follows the `sort` of the `Table.Head` it sits in
|
|
91
|
+
* (up for ascending, down for descending, both ways when unsorted) through CSS, so it needs no
|
|
92
|
+
* client code; the `<th>`'s `aria-sort` tells assistive technology the current order.
|
|
93
|
+
*/
|
|
94
|
+
function TableSortButton({ href, render, className, children, ...rest }) {
|
|
95
|
+
return renderElement(href === void 0 ? "button" : "a", render, {}, {
|
|
96
|
+
"data-slot": "table-sort-button",
|
|
97
|
+
href,
|
|
98
|
+
type: href !== void 0 || render !== void 0 ? void 0 : "button",
|
|
99
|
+
...rest,
|
|
100
|
+
className: cx("nz-table-sort-button", "nz-hit-target", className),
|
|
101
|
+
children: /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsxs("span", {
|
|
102
|
+
className: "nz-table-sort-icon",
|
|
103
|
+
"data-slot": "table-sort-icon",
|
|
104
|
+
"aria-hidden": "true",
|
|
105
|
+
children: [/* @__PURE__ */ jsx(ChevronsUpDownGlyph, {}), /* @__PURE__ */ jsx(ChevronGlyph, {})]
|
|
106
|
+
})] })
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* A row's link, usually its first cell's text (Figma Order Row: the order number). In a row with
|
|
111
|
+
* `interactive`, it stretches over the whole row.
|
|
112
|
+
*/
|
|
113
|
+
function TableRowLink({ render, className, ...rest }) {
|
|
114
|
+
return renderElement("a", render, {}, {
|
|
115
|
+
"data-slot": "table-row-link",
|
|
116
|
+
...rest,
|
|
117
|
+
className: cx("nz-table-row-link", className)
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
export { TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRoot, TableRow, TableRowLink, TableSortButton };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRoot, TableRow, TableRowLink, TableSortButton } from "./table.js";
|
|
2
|
+
declare namespace table_parts_d_exports {
|
|
3
|
+
export { TableBody as Body, TableCaption as Caption, TableCell as Cell, TableContainer as Container, TableFooter as Footer, TableHead as Head, TableHeader as Header, TableRoot as Root, TableRow as Row, TableRowLink as RowLink, TableSortButton as SortButton };
|
|
4
|
+
}
|
|
5
|
+
//#endregion
|
|
6
|
+
export { TableBody as Body, TableCaption as Caption, TableCell as Cell, TableContainer as Container, TableFooter as Footer, TableHead as Head, TableHeader as Header, TableRoot as Root, TableRow as Row, TableRowLink as RowLink, TableSortButton as SortButton, table_parts_d_exports };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRoot, TableRow, TableRowLink, TableSortButton } from "./table.js";
|
|
3
|
+
//#region src/table/table.parts.ts
|
|
4
|
+
var table_parts_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
Body: () => TableBody,
|
|
6
|
+
Caption: () => TableCaption,
|
|
7
|
+
Cell: () => TableCell,
|
|
8
|
+
Container: () => TableContainer,
|
|
9
|
+
Footer: () => TableFooter,
|
|
10
|
+
Head: () => TableHead,
|
|
11
|
+
Header: () => TableHeader,
|
|
12
|
+
Root: () => TableRoot,
|
|
13
|
+
Row: () => TableRow,
|
|
14
|
+
RowLink: () => TableRowLink,
|
|
15
|
+
SortButton: () => TableSortButton
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { TableBody as Body, TableCaption as Caption, TableCell as Cell, TableContainer as Container, TableFooter as Footer, TableHead as Head, TableHeader as Header, TableRoot as Root, TableRow as Row, TableRowLink as RowLink, TableSortButton as SortButton, table_parts_exports };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { TableSelection, TableSelectionProps } from "./table-selection.client.js";
|
|
2
|
+
import { TableSelectAll, TableSelectAllProps, TableSelectRow, TableSelectRowProps, TableSelectionLabels } from "./table-selection.js";
|
|
3
|
+
export { TableSelectAll, type TableSelectAllProps, TableSelectRow, type TableSelectRowProps, TableSelection, type TableSelectionLabels, type TableSelectionProps };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RenderProp } from "../contracts/render.js";
|
|
2
|
+
import { ComponentPropsWithRef, ReactElement } from "react";
|
|
3
|
+
//#region src/table-selection/table-selection.client.d.ts
|
|
4
|
+
export interface TableSelectionProps extends Omit<ComponentPropsWithRef<"div">, "ref"> {
|
|
5
|
+
/**
|
|
6
|
+
* The selected rows' values, after every change (and once on mount when a row is already
|
|
7
|
+
* checked, for example by the browser's form restoration). For a client owner; a Server Component
|
|
8
|
+
* reads the selection from the form.
|
|
9
|
+
*/
|
|
10
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
11
|
+
render?: RenderProp<Record<string, never>>;
|
|
12
|
+
}
|
|
13
|
+
export declare function TableSelection({ onSelectionChange, render, className, ...rest }: TableSelectionProps): ReactElement;
|
|
14
|
+
//#endregion
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cx } from "../_internal/cx.js";
|
|
3
|
+
import { renderElement } from "../contracts/render.js";
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
//#region src/table-selection/table-selection.client.tsx
|
|
6
|
+
const ROW = "[data-slot=\"table-select-row-input\"]";
|
|
7
|
+
const ALL = "[data-slot=\"table-select-all-input\"]";
|
|
8
|
+
function TableSelection({ onSelectionChange, render, className, ...rest }) {
|
|
9
|
+
const root = useRef(null);
|
|
10
|
+
const report = useRef(onSelectionChange);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
report.current = onSelectionChange;
|
|
13
|
+
});
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const element = root.current;
|
|
16
|
+
if (element === null) return void 0;
|
|
17
|
+
const rows = () => [...element.querySelectorAll(ROW)];
|
|
18
|
+
let last = "";
|
|
19
|
+
let anchor;
|
|
20
|
+
let shift = false;
|
|
21
|
+
/** The select-all boxes follow the rows; the owner hears of a changed selection. */
|
|
22
|
+
const sync = () => {
|
|
23
|
+
const all = rows().filter((input) => !input.disabled);
|
|
24
|
+
const checked = all.filter((input) => input.checked);
|
|
25
|
+
for (const box of element.querySelectorAll(ALL)) {
|
|
26
|
+
box.checked = all.length > 0 && checked.length === all.length;
|
|
27
|
+
box.indeterminate = checked.length > 0 && checked.length < all.length;
|
|
28
|
+
}
|
|
29
|
+
const ids = rows().filter((input) => input.checked).map((input) => input.value);
|
|
30
|
+
const key = ids.join("\0");
|
|
31
|
+
if (key !== last) {
|
|
32
|
+
last = key;
|
|
33
|
+
report.current?.(ids);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const onClick = (event) => {
|
|
37
|
+
shift = event.shiftKey;
|
|
38
|
+
};
|
|
39
|
+
const onChange = (event) => {
|
|
40
|
+
const target = event.target;
|
|
41
|
+
if (!(target instanceof HTMLInputElement)) return;
|
|
42
|
+
if (target.matches(ALL)) {
|
|
43
|
+
for (const input of rows()) if (!input.disabled) input.checked = target.checked;
|
|
44
|
+
anchor = void 0;
|
|
45
|
+
} else if (target.matches(ROW)) {
|
|
46
|
+
const list = rows();
|
|
47
|
+
if (shift && anchor !== void 0 && anchor !== target && list.includes(anchor)) {
|
|
48
|
+
const [a, b] = [list.indexOf(anchor), list.indexOf(target)];
|
|
49
|
+
for (const input of list.slice(Math.min(a, b), Math.max(a, b) + 1)) if (!input.disabled) input.checked = target.checked;
|
|
50
|
+
}
|
|
51
|
+
anchor = target;
|
|
52
|
+
} else return;
|
|
53
|
+
shift = false;
|
|
54
|
+
sync();
|
|
55
|
+
};
|
|
56
|
+
const onKeyDown = (event) => {
|
|
57
|
+
if (event.key !== "Escape" || event.defaultPrevented) return;
|
|
58
|
+
const checked = rows().filter((input) => input.checked && !input.disabled);
|
|
59
|
+
if (checked.length === 0) return;
|
|
60
|
+
for (const input of checked) input.checked = false;
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
event.stopPropagation();
|
|
63
|
+
anchor = void 0;
|
|
64
|
+
sync();
|
|
65
|
+
};
|
|
66
|
+
element.addEventListener("click", onClick, true);
|
|
67
|
+
element.addEventListener("change", onChange);
|
|
68
|
+
element.addEventListener("keydown", onKeyDown);
|
|
69
|
+
sync();
|
|
70
|
+
return () => {
|
|
71
|
+
element.removeEventListener("click", onClick, true);
|
|
72
|
+
element.removeEventListener("change", onChange);
|
|
73
|
+
element.removeEventListener("keydown", onKeyDown);
|
|
74
|
+
};
|
|
75
|
+
}, []);
|
|
76
|
+
return renderElement("div", render, {}, {
|
|
77
|
+
"data-slot": "table-selection",
|
|
78
|
+
ref: root,
|
|
79
|
+
...rest,
|
|
80
|
+
className: cx("nz-table-selection", className)
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { TableSelection };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, ReactElement } from "react";
|
|
2
|
+
//#region src/table-selection/table-selection.d.ts
|
|
3
|
+
/** Row selection's own strings (§16.4): serialisable, English defaults. */
|
|
4
|
+
export interface TableSelectionLabels {
|
|
5
|
+
/** The select-all checkbox's name. @default 'Select all rows' */
|
|
6
|
+
selectAll: string;
|
|
7
|
+
}
|
|
8
|
+
type CheckboxInputProps = Omit<ComponentPropsWithRef<"input">, "type" | "children" | "checked" | "defaultChecked">;
|
|
9
|
+
export interface TableSelectAllProps extends CheckboxInputProps {
|
|
10
|
+
/** An `aria-label` wins over `labels.selectAll`. */
|
|
11
|
+
labels?: Partial<TableSelectionLabels>;
|
|
12
|
+
}
|
|
13
|
+
export interface TableSelectRowProps extends CheckboxInputProps {
|
|
14
|
+
/** The row's id: what a form receives under `name` when the row is selected. */
|
|
15
|
+
value: string;
|
|
16
|
+
/** The checkbox's name, unique per row, for example "Select order 1042". */
|
|
17
|
+
"aria-label": string;
|
|
18
|
+
/** @default 'ids' */
|
|
19
|
+
name?: string;
|
|
20
|
+
/** Selected when the page loads. @default false */
|
|
21
|
+
defaultChecked?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The header's checkbox: checks or clears every row of its `TableSelection`, and shows the mixed
|
|
25
|
+
* state when some are selected. It submits nothing. Without `TableSelection` it does nothing.
|
|
26
|
+
*/
|
|
27
|
+
export declare function TableSelectAll({ labels, className, ...rest }: TableSelectAllProps): ReactElement;
|
|
28
|
+
/**
|
|
29
|
+
* A row's checkbox: a native input that submits `value` under `name` with its form (pass `form` to
|
|
30
|
+
* reach a form outside the table). The row shows `bg/brand-subtle` while it is checked, through CSS.
|
|
31
|
+
*/
|
|
32
|
+
export declare function TableSelectRow({ name, className, ...rest }: TableSelectRowProps): ReactElement;
|
|
33
|
+
//#endregion
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { cx } from "../_internal/cx.js";
|
|
2
|
+
import { CheckGlyph, MinusGlyph } from "../_internal/glyphs.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/table-selection/table-selection.tsx
|
|
5
|
+
/**
|
|
6
|
+
* The header's checkbox: checks or clears every row of its `TableSelection`, and shows the mixed
|
|
7
|
+
* state when some are selected. It submits nothing. Without `TableSelection` it does nothing.
|
|
8
|
+
*/
|
|
9
|
+
function TableSelectAll({ labels, className, ...rest }) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
11
|
+
"data-slot": "table-select-all",
|
|
12
|
+
className: cx("nz-table-select-all nz-checkbox nz-hit-target", className),
|
|
13
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
14
|
+
"aria-label": labels?.selectAll ?? "Select all rows",
|
|
15
|
+
...rest,
|
|
16
|
+
type: "checkbox",
|
|
17
|
+
className: "nz-table-select-all-input nz-checkbox-input",
|
|
18
|
+
"data-slot": "table-select-all-input"
|
|
19
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
20
|
+
className: "nz-table-select-all-indicator nz-checkbox-indicator",
|
|
21
|
+
"data-slot": "table-select-all-indicator",
|
|
22
|
+
"aria-hidden": "true",
|
|
23
|
+
children: [/* @__PURE__ */ jsx(CheckGlyph, {}), /* @__PURE__ */ jsx(MinusGlyph, {})]
|
|
24
|
+
})]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A row's checkbox: a native input that submits `value` under `name` with its form (pass `form` to
|
|
29
|
+
* reach a form outside the table). The row shows `bg/brand-subtle` while it is checked, through CSS.
|
|
30
|
+
*/
|
|
31
|
+
function TableSelectRow({ name = "ids", className, ...rest }) {
|
|
32
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
33
|
+
"data-slot": "table-select-row",
|
|
34
|
+
className: cx("nz-table-select-row nz-checkbox nz-hit-target", className),
|
|
35
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
36
|
+
name,
|
|
37
|
+
...rest,
|
|
38
|
+
type: "checkbox",
|
|
39
|
+
className: "nz-table-select-row-input nz-checkbox-input",
|
|
40
|
+
"data-slot": "table-select-row-input"
|
|
41
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
42
|
+
className: "nz-table-select-row-indicator nz-checkbox-indicator",
|
|
43
|
+
"data-slot": "table-select-row-indicator",
|
|
44
|
+
"aria-hidden": "true",
|
|
45
|
+
children: [/* @__PURE__ */ jsx(CheckGlyph, {}), /* @__PURE__ */ jsx(MinusGlyph, {})]
|
|
46
|
+
})]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { TableSelectAll, TableSelectRow };
|
package/dist/text/text.d.ts
CHANGED
|
@@ -3,7 +3,15 @@ import { ComponentPropsWithRef, ReactElement } from "react";
|
|
|
3
3
|
//#region src/text/text.d.ts
|
|
4
4
|
/** The Figma text styles as lowercase names (`Nizivo/Label/M` → `label-m`), plus the 12 px proposals. */
|
|
5
5
|
export type TextVariant = "display-l" | "display-m" | "heading-h1" | "heading-h2" | "heading-h3" | "heading-h4" | "body-l" | "body-m" | "body-m-strong" | "body-s" | "label-l" | "label-m" | "label-m-strong" | "label-s" | "numeric-display" | "numeric-kpi" | "numeric-l" | "numeric-m" | "mono-m" | "mono-m-strong";
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* The `text/*` colour tokens. `accent` paints `--nz-text-brand`, since Figma has no accent text for page
|
|
8
|
+
* surfaces (M38; `--nz-text-inverse-accent` is for `bg/inverse`).
|
|
9
|
+
*
|
|
10
|
+
* Deprecated: `'accent'`, which looks exactly like `'brand'`; use `'brand'`. It keeps working; its
|
|
11
|
+
* removal is deferred to 1.0, or to when Figma adds an accent text for page surfaces (M42).
|
|
12
|
+
* TypeScript cannot deprecate one member of a union type, so this note is the marker. Card's and
|
|
13
|
+
* KpiTile's `tone="accent"`, a surface, are not deprecated.
|
|
14
|
+
*/
|
|
7
15
|
export type TextTone = "primary" | "secondary" | "tertiary" | "disabled" | "inverse" | "on-brand" | "on-accent" | "on-critical" | "brand" | "accent" | "success" | "warning" | "critical" | "info";
|
|
8
16
|
export interface TextState {
|
|
9
17
|
variant: TextVariant;
|
|
@@ -12,7 +20,10 @@ export interface TextState {
|
|
|
12
20
|
export interface TextProps extends ComponentPropsWithRef<"p"> {
|
|
13
21
|
/** The text style. 12 px exists only as `body-s` and `label-s` (§15.1). @default 'body-m' */
|
|
14
22
|
variant?: TextVariant;
|
|
15
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* A `text/*` colour. Absent, the colour is inherited from the surface. Deprecated value:
|
|
25
|
+
* `'accent'`, which paints `--nz-text-brand`; use `'brand'` (M42; removal deferred to 1.0).
|
|
26
|
+
*/
|
|
16
27
|
tone?: TextTone;
|
|
17
28
|
/** Another element or component, for example `render={<span />}` or `render={<label htmlFor="sku" />}`. */
|
|
18
29
|
render?: RenderProp<TextState>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Politeness, ToastAction, ToastOptions, ToastTone, ToasterLabels, ToasterProps } from "./toast.contract.js";
|
|
2
|
+
import { Toaster } from "./toaster.client.js";
|
|
3
|
+
import { announce, toast } from "./store.js";
|
|
4
|
+
export { type Politeness, type ToastAction, type ToastOptions, type ToastTone, Toaster, type ToasterLabels, type ToasterProps, announce, toast };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "./seam.js";
|
|
2
|
+
import { Politeness, ToastOptions } from "./toast.contract.js";
|
|
3
|
+
//#region src/toast/store.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Shows a toast and returns its id. A toast with an action, or a critical one, stays until it is
|
|
6
|
+
* dismissed; any other leaves after `timeout` (5 s). Every toast is spoken once through the Toaster's
|
|
7
|
+
* announcer: polite, or assertive when critical. Render one `<Toaster />` in the app's root layout.
|
|
8
|
+
*/
|
|
9
|
+
export declare const toast: ((message: string, options?: ToastOptions) => string) & {
|
|
10
|
+
/** Removes the toast with this id, or every toast. */
|
|
11
|
+
dismiss: (id?: string) => void;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Speaks `message` through the Toaster's announcer, a live region that is on the page before any
|
|
15
|
+
* message and stays reachable above a modal. For status a sighted user sees some other way: "Saved",
|
|
16
|
+
* "3 results". Needs a mounted `<Toaster />`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function announce(message: string, politeness?: Politeness): void;
|
|
19
|
+
//#endregion
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
//#region src/toast/store.ts
|
|
2
|
+
const TIMEOUT = 5e3;
|
|
3
|
+
let entries = [];
|
|
4
|
+
let snapshot = [];
|
|
5
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
6
|
+
/** Why the clock is stopped: the region (`region`: hover, focus within), the page (`hidden`). */
|
|
7
|
+
const pauses = /* @__PURE__ */ new Set();
|
|
8
|
+
/** Ids a Toaster shows; a waiting toast's clock does not run. */
|
|
9
|
+
let shown = /* @__PURE__ */ new Set();
|
|
10
|
+
let hosts = 0;
|
|
11
|
+
let next = 0;
|
|
12
|
+
let speaker;
|
|
13
|
+
function emit() {
|
|
14
|
+
snapshot = entries.map((entry) => entry.record);
|
|
15
|
+
for (const listener of listeners) listener();
|
|
16
|
+
}
|
|
17
|
+
function stop(entry) {
|
|
18
|
+
if (entry.handle === void 0) return;
|
|
19
|
+
clearTimeout(entry.handle);
|
|
20
|
+
entry.handle = void 0;
|
|
21
|
+
if (entry.remaining !== null) entry.remaining -= Date.now() - entry.started;
|
|
22
|
+
}
|
|
23
|
+
/** Runs each clock that may run: a shown toast that leaves on its own, a Toaster mounted, no pause. */
|
|
24
|
+
function sync() {
|
|
25
|
+
const running = hosts > 0 && pauses.size === 0;
|
|
26
|
+
for (const entry of entries) if (!running || !shown.has(entry.record.id) || entry.remaining === null) stop(entry);
|
|
27
|
+
else if (entry.handle === void 0) {
|
|
28
|
+
const { id } = entry.record;
|
|
29
|
+
entry.started = Date.now();
|
|
30
|
+
entry.handle = setTimeout(() => dismiss(id), Math.max(0, entry.remaining));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The text a toast speaks: its message, then its description. */
|
|
34
|
+
function spoken(record) {
|
|
35
|
+
if (record.description === void 0) return record.message;
|
|
36
|
+
const separator = /[.!?…:]$/.test(record.message) ? " " : ". ";
|
|
37
|
+
return record.message + separator + record.description;
|
|
38
|
+
}
|
|
39
|
+
function add(message, options = {}) {
|
|
40
|
+
const tone = options.tone ?? "neutral";
|
|
41
|
+
const timeout = options.action !== void 0 || tone === "critical" ? null : options.timeout ?? TIMEOUT;
|
|
42
|
+
const id = options.id ?? `nz-toast-${next += 1}`;
|
|
43
|
+
const record = {
|
|
44
|
+
id,
|
|
45
|
+
message,
|
|
46
|
+
tone,
|
|
47
|
+
description: options.description,
|
|
48
|
+
action: options.action,
|
|
49
|
+
timeout
|
|
50
|
+
};
|
|
51
|
+
const entry = {
|
|
52
|
+
record,
|
|
53
|
+
onClose: options.onClose,
|
|
54
|
+
remaining: timeout,
|
|
55
|
+
started: 0,
|
|
56
|
+
handle: void 0
|
|
57
|
+
};
|
|
58
|
+
const at = entries.findIndex((existing) => existing.record.id === id);
|
|
59
|
+
if (at === -1) entries = [...entries, entry];
|
|
60
|
+
else {
|
|
61
|
+
const previous = entries[at];
|
|
62
|
+
if (previous !== void 0) stop(previous);
|
|
63
|
+
entries = entries.with(at, entry);
|
|
64
|
+
}
|
|
65
|
+
emit();
|
|
66
|
+
sync();
|
|
67
|
+
announce(spoken(record), tone === "critical" ? "assertive" : "polite");
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
/** Removes one toast, or every toast with no id. */
|
|
71
|
+
function dismiss(id) {
|
|
72
|
+
const leaving = entries.filter((entry) => id === void 0 || entry.record.id === id);
|
|
73
|
+
if (leaving.length === 0) return;
|
|
74
|
+
for (const entry of leaving) stop(entry);
|
|
75
|
+
entries = entries.filter((entry) => !leaving.includes(entry));
|
|
76
|
+
emit();
|
|
77
|
+
for (const entry of leaving) entry.onClose?.();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Shows a toast and returns its id. A toast with an action, or a critical one, stays until it is
|
|
81
|
+
* dismissed; any other leaves after `timeout` (5 s). Every toast is spoken once through the Toaster's
|
|
82
|
+
* announcer: polite, or assertive when critical. Render one `<Toaster />` in the app's root layout.
|
|
83
|
+
*/
|
|
84
|
+
const toast = Object.assign(add, { dismiss });
|
|
85
|
+
/**
|
|
86
|
+
* Speaks `message` through the Toaster's announcer, a live region that is on the page before any
|
|
87
|
+
* message and stays reachable above a modal. For status a sighted user sees some other way: "Saved",
|
|
88
|
+
* "3 results". Needs a mounted `<Toaster />`.
|
|
89
|
+
*/
|
|
90
|
+
function announce(message, politeness = "polite") {
|
|
91
|
+
if (speaker !== void 0) speaker(message, politeness);
|
|
92
|
+
else if (process.env.NODE_ENV !== "production") console.warn(`Nizivo: announce("${message}") ran with no <Toaster /> mounted, so nothing spoke it.`);
|
|
93
|
+
}
|
|
94
|
+
function subscribe(listener) {
|
|
95
|
+
listeners.add(listener);
|
|
96
|
+
return () => listeners.delete(listener);
|
|
97
|
+
}
|
|
98
|
+
function getSnapshot() {
|
|
99
|
+
return snapshot;
|
|
100
|
+
}
|
|
101
|
+
const EMPTY = [];
|
|
102
|
+
/** The server renders no toast: the queue is the browser's. */
|
|
103
|
+
function getServerSnapshot() {
|
|
104
|
+
return EMPTY;
|
|
105
|
+
}
|
|
106
|
+
/** A Toaster mounted; clocks run while one is. Returns its unmount. */
|
|
107
|
+
function attach() {
|
|
108
|
+
hosts += 1;
|
|
109
|
+
sync();
|
|
110
|
+
return () => {
|
|
111
|
+
hosts -= 1;
|
|
112
|
+
sync();
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** The ids the Toaster shows: the newest `limit`. */
|
|
116
|
+
function show(ids) {
|
|
117
|
+
shown = new Set(ids);
|
|
118
|
+
sync();
|
|
119
|
+
}
|
|
120
|
+
function pause(reason) {
|
|
121
|
+
pauses.add(reason);
|
|
122
|
+
sync();
|
|
123
|
+
}
|
|
124
|
+
function resume(reason) {
|
|
125
|
+
pauses.delete(reason);
|
|
126
|
+
sync();
|
|
127
|
+
}
|
|
128
|
+
/** The announcer registers here while mounted. Returns its unregister. */
|
|
129
|
+
function speakThrough(speak) {
|
|
130
|
+
speaker = speak;
|
|
131
|
+
return () => {
|
|
132
|
+
if (speaker === speak) speaker = void 0;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { announce, attach, getServerSnapshot, getSnapshot, pause, resume, show, speakThrough, subscribe, toast };
|