@stealthscale/component-feedback 0.2.2 → 0.2.3

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.
Files changed (37) hide show
  1. package/dist/cyclonedx/bom.json +1 -1
  2. package/dist/index.js +1 -1825
  3. package/dist/pages/alert/alert.js +223 -0
  4. package/dist/pages/alert/alert.props.js +3 -0
  5. package/dist/pages/empty-state/empty-state.js +96 -0
  6. package/dist/pages/empty-state/empty-state.props.js +3 -0
  7. package/dist/pages/loader/loader.js +359 -0
  8. package/dist/pages/loader/loader.props.js +3 -0
  9. package/dist/pages/meter/meter.js +785 -0
  10. package/dist/pages/meter/meter.props.js +3 -0
  11. package/dist/pages/pages.json +115 -0
  12. package/dist/pages/progress/progress.js +550 -0
  13. package/dist/pages/progress/progress.props.js +3 -0
  14. package/dist/pages/progress-circle/progress-circle.js +329 -0
  15. package/dist/pages/progress-circle/progress-circle.props.js +3 -0
  16. package/dist/pages/skeleton/skeleton.js +94 -0
  17. package/dist/pages/skeleton/skeleton.props.js +3 -0
  18. package/dist/pages/skeleton-text/skeleton-text.js +81 -0
  19. package/dist/pages/skeleton-text/skeleton-text.props.js +3 -0
  20. package/dist/pages/spinner/spinner.js +186 -0
  21. package/dist/pages/spinner/spinner.props.js +3 -0
  22. package/dist/pages/toast/toast.js +427 -0
  23. package/dist/pages/toast/toast.props.js +3 -0
  24. package/dist/shared-Xc-n0bn7.js +1826 -0
  25. package/dist/theme.js +1 -1
  26. package/locales/en/specimen/alert.json +37 -0
  27. package/locales/en/specimen/empty-state.json +10 -0
  28. package/locales/en/specimen/loader.json +30 -0
  29. package/locales/en/specimen/meter.json +81 -0
  30. package/locales/en/specimen/progress-circle.json +41 -0
  31. package/locales/en/specimen/progress.json +66 -0
  32. package/locales/en/specimen/skeleton-text.json +12 -0
  33. package/locales/en/specimen/skeleton.json +18 -0
  34. package/locales/en/specimen/spinner.json +33 -0
  35. package/locales/en/specimen/toast.json +79 -0
  36. package/package.json +7 -6
  37. /package/dist/{recipe-CX1gSsN7.js → recipes-CX1gSsN7.js} +0 -0
@@ -0,0 +1,186 @@
1
+ import { t as __exportAll } from "../../rolldown-runtime-D7D4PA-g.js";
2
+ import { l as recipe } from "../../recipes-CX1gSsN7.js";
3
+ import { P as Spinner } from "../../shared-Xc-n0bn7.js";
4
+ import { c } from "react/compiler-runtime";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Matrix, scenesOf, specimen, useWords } from "@stealthscale/specimen";
7
+ import { Button } from "@stealthscale/component-actions";
8
+ import { Text } from "@stealthscale/component-typography";
9
+ //#region src/spinner/examples/busy.example.tsx
10
+ var busy_example_exports = /* @__PURE__ */ __exportAll({
11
+ Busy: () => Busy,
12
+ source: () => source$2
13
+ });
14
+ function Busy(props) {
15
+ const $ = c(6);
16
+ const { t } = useWords("spinner");
17
+ let t0;
18
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
19
+ t0 = /* @__PURE__ */ jsx(Spinner, { size: "inherit" });
20
+ $[0] = t0;
21
+ } else t0 = $[0];
22
+ let t1;
23
+ if ($[1] !== t) {
24
+ t1 = t("saving");
25
+ $[1] = t;
26
+ $[2] = t1;
27
+ } else t1 = $[2];
28
+ let t2;
29
+ if ($[3] !== props || $[4] !== t1) {
30
+ t2 = /* @__PURE__ */ jsxs(Button, {
31
+ disabled: true,
32
+ ...props,
33
+ children: [t0, t1]
34
+ });
35
+ $[3] = props;
36
+ $[4] = t1;
37
+ $[5] = t2;
38
+ } else t2 = $[5];
39
+ return t2;
40
+ }
41
+ const source$2 = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { Spinner } from \"@stealthscale/component-feedback\";\n\nexport function Busy(props: Parameters<typeof Button>[0]): ReactElement {\n const { t } = useWords(\"spinner\");\n\n return (\n <Button disabled {...props}>\n <Spinner size=\"inherit\" />\n {t(\"saving\")}\n </Button>\n );\n}\n";
42
+ //#endregion
43
+ //#region src/spinner/examples/saving.example.tsx
44
+ var saving_example_exports = /* @__PURE__ */ __exportAll({
45
+ Saving: () => Saving,
46
+ source: () => source$1
47
+ });
48
+ function Saving(props) {
49
+ const $ = c(6);
50
+ const { t } = useWords("spinner");
51
+ let t0;
52
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
53
+ t0 = /* @__PURE__ */ jsx(Spinner, { size: "inherit" });
54
+ $[0] = t0;
55
+ } else t0 = $[0];
56
+ let t1;
57
+ if ($[1] !== t) {
58
+ t1 = t("saving");
59
+ $[1] = t;
60
+ $[2] = t1;
61
+ } else t1 = $[2];
62
+ let t2;
63
+ if ($[3] !== props || $[4] !== t1) {
64
+ t2 = /* @__PURE__ */ jsxs(Text, {
65
+ ...props,
66
+ children: [
67
+ t0,
68
+ " ",
69
+ t1
70
+ ]
71
+ });
72
+ $[3] = props;
73
+ $[4] = t1;
74
+ $[5] = t2;
75
+ } else t2 = $[5];
76
+ return t2;
77
+ }
78
+ const source$1 = "import { type ReactElement } from \"react\";\n\nimport { Text } from \"@stealthscale/component-typography\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { Spinner } from \"@stealthscale/component-feedback\";\n\nexport function Saving(props: Parameters<typeof Text>[0]): ReactElement {\n const { t } = useWords(\"spinner\");\n\n return (\n <Text {...props}>\n <Spinner size=\"inherit\" /> {t(\"saving\")}\n </Text>\n );\n}\n";
79
+ //#endregion
80
+ //#region src/spinner/examples/turning.example.tsx
81
+ var turning_example_exports = /* @__PURE__ */ __exportAll({
82
+ Turning: () => Turning,
83
+ source: () => source
84
+ });
85
+ function Turning(props) {
86
+ const $ = c(2);
87
+ let t0;
88
+ if ($[0] !== props) {
89
+ t0 = /* @__PURE__ */ jsx(Spinner, { ...props });
90
+ $[0] = props;
91
+ $[1] = t0;
92
+ } else t0 = $[1];
93
+ return t0;
94
+ }
95
+ const source = "import { type ReactElement } from \"react\";\n\nimport { Spinner } from \"@stealthscale/component-feedback\";\n\nexport function Turning(props: Parameters<typeof Spinner>[0]): ReactElement {\n return <Spinner {...props} />;\n}\n";
96
+ //#endregion
97
+ //#region src/spinner/spinner.specimen.tsx
98
+ /**
99
+ * Catalogue page for the spinner.
100
+ *
101
+ * @remarks
102
+ * `scenesOf` generates one scene per recipe axis. The inline and button scenes are hand-written,
103
+ * because they vary the text size and the button look, which are not spinner axes. Every scene
104
+ * renders a component from `examples/` and shows that file as its source. The words are keys
105
+ * under `spinner` in `locales/en/specimen/spinner.json`.
106
+ */
107
+ /**
108
+ * Body text sizes of the inline scene.
109
+ */
110
+ const TEXT_SIZES = [
111
+ "sm",
112
+ "md",
113
+ "lg"
114
+ ];
115
+ /**
116
+ * Button looks of the button scene, from filled to outlined.
117
+ */
118
+ const LOOKS = [
119
+ "solid",
120
+ "subtle",
121
+ "outline"
122
+ ];
123
+ /**
124
+ * Hand-written scene for a spinner at `inherit` next to text at three body sizes.
125
+ */
126
+ const inline = {
127
+ about: "spinner.inline.about",
128
+ draw: () => /* @__PURE__ */ jsx(Matrix, {
129
+ knob: "size",
130
+ of: TEXT_SIZES,
131
+ children: (size) => /* @__PURE__ */ jsx(Saving, { size })
132
+ }),
133
+ example: saving_example_exports,
134
+ props: { size: "sm" },
135
+ title: "spinner.inline.title"
136
+ };
137
+ /**
138
+ * Hand-written scene for a spinner at `inherit` in a disabled button in three looks.
139
+ */
140
+ const button = {
141
+ about: "spinner.button.about",
142
+ draw: () => /* @__PURE__ */ jsx(Matrix, {
143
+ knob: "variant",
144
+ of: LOOKS,
145
+ children: (variant) => /* @__PURE__ */ jsx(Busy, { variant })
146
+ }),
147
+ example: busy_example_exports,
148
+ props: { variant: "solid" },
149
+ title: "spinner.button.title"
150
+ };
151
+ var spinner_specimen_default = specimen({
152
+ about: "spinner.about",
153
+ id: "components/feedback/spinner",
154
+ imports: "import { Spinner } from \"@stealthscale/component-feedback\";",
155
+ scenes: [
156
+ ...scenesOf(recipe, {
157
+ axes: {
158
+ effect: {
159
+ across: "palette",
160
+ with: { size: "lg" }
161
+ },
162
+ palette: { with: { size: "lg" } },
163
+ stroke: { with: { size: "lg" } },
164
+ track: { with: {
165
+ palette: "primary",
166
+ size: "lg"
167
+ } }
168
+ },
169
+ draw: (props) => /* @__PURE__ */ jsx(Turning, { ...props }),
170
+ example: turning_example_exports,
171
+ namespace: "spinner",
172
+ order: [
173
+ "size",
174
+ "palette",
175
+ "stroke",
176
+ "track",
177
+ "effect"
178
+ ]
179
+ }),
180
+ inline,
181
+ button
182
+ ],
183
+ title: "spinner.title"
184
+ });
185
+ //#endregion
186
+ export { button, spinner_specimen_default as default, inline };
@@ -0,0 +1,3 @@
1
+ export const dropped = {"SpinnerProps": {"conditions": 284, "foreign": 1040}};
2
+ export const parts = {"SpinnerProps": [{"accepts": "\"glow\" | \"pulse\"", "fallback": "", "kind": "variant", "name": "effect", "refers": [], "required": false, "says": "The halo drawn around the ring, in the palette's solid at half opacity."}, {"accepts": "\"accent\" | \"current\" | \"error\" | \"info\" | \"neutral\" | \"primary\" | \"secondary\" | \"success\" | \"warning\"", "fallback": "", "kind": "variant", "name": "palette", "refers": [], "required": false, "says": "The palette the arc is drawn in, as its `solid` role."}, {"accepts": "\"2xl\" | \"3xl\" | \"4xl\" | \"inherit\" | \"lg\" | \"md\" | \"sm\" | \"xl\" | \"xs\"", "fallback": "", "kind": "variant", "name": "size", "refers": [], "required": false, "says": ""}, {"accepts": "\"control\" | \"hairline\" | \"heavy\" | \"indicator\"", "fallback": "", "kind": "variant", "name": "stroke", "refers": [], "required": false, "says": "Border width of the ring. `hairline`, `control` and `indicator` read the theme's stroke tokens, and `heavy` reads the 4px `lg` width."}, {"accepts": "boolean", "fallback": "", "kind": "variant", "name": "track", "refers": [], "required": false, "says": "Whether the two track sides draw the ring behind the arc, in the palette's `muted` role."}]};
3
+ export const shapes = {};
@@ -0,0 +1,427 @@
1
+ import { t as __exportAll } from "../../rolldown-runtime-D7D4PA-g.js";
2
+ import { P as Spinner, a as Region, c as Content, i as Root, l as CloseTrigger, o as Indicator, r as Title, s as Description, t as createToaster, u as ActionTrigger } from "../../shared-Xc-n0bn7.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { Sample, specimen, useWords } from "@stealthscale/specimen";
6
+ import { CircleAlertIcon, CircleCheckIcon, InfoIcon, TriangleAlertIcon, XIcon } from "lucide-react";
7
+ import { Stack } from "@stealthscale/component-layout";
8
+ import { Button } from "@stealthscale/component-actions";
9
+ //#region src/toast/examples/toaster.ts
10
+ /**
11
+ * Creates the one toaster the toast's examples raise into, as an application creates one in a
12
+ * module its pages import.
13
+ */
14
+ /**
15
+ * The toaster: at the bottom end of the window, five toasts at a time, overlapping until a
16
+ * pointer rests on them.
17
+ */
18
+ const toaster = createToaster({
19
+ max: 5,
20
+ overlap: true,
21
+ placement: "bottom-end"
22
+ });
23
+ //#endregion
24
+ //#region src/toast/examples/kinds.example.tsx
25
+ var kinds_example_exports = /* @__PURE__ */ __exportAll({
26
+ Kinds: () => Kinds,
27
+ source: () => source$5
28
+ });
29
+ const KINDS = [
30
+ "success",
31
+ "error",
32
+ "warning",
33
+ "info",
34
+ "loading"
35
+ ];
36
+ function Kinds() {
37
+ const $ = c(4);
38
+ const { t } = useWords("toast");
39
+ let t0;
40
+ if ($[0] !== t) {
41
+ t0 = KINDS.map((kind) => /* @__PURE__ */ jsx(Button, {
42
+ onClick: () => {
43
+ toaster.create({
44
+ description: t(`kinds.${kind}.description`),
45
+ title: t(`kinds.${kind}.title`),
46
+ type: kind
47
+ });
48
+ },
49
+ variant: "outline",
50
+ children: t(`kinds.${kind}.show`)
51
+ }, kind));
52
+ $[0] = t;
53
+ $[1] = t0;
54
+ } else t0 = $[1];
55
+ let t1;
56
+ if ($[2] !== t0) {
57
+ t1 = /* @__PURE__ */ jsx(Stack, {
58
+ direction: "row",
59
+ gap: "sm",
60
+ wrap: true,
61
+ children: t0
62
+ });
63
+ $[2] = t0;
64
+ $[3] = t1;
65
+ } else t1 = $[3];
66
+ return t1;
67
+ }
68
+ const source$5 = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { Stack } from \"@stealthscale/component-layout\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { toaster } from \"./toaster.ts\";\n\nconst KINDS = [\"success\", \"error\", \"warning\", \"info\", \"loading\"] as const;\n\nexport function Kinds(): ReactElement {\n const { t } = useWords(\"toast\");\n\n return (\n <Stack direction=\"row\" gap=\"sm\" wrap>\n {KINDS.map((kind) => (\n <Button\n key={kind}\n onClick={() => {\n toaster.create({\n description: t(`kinds.${kind}.description`),\n title: t(`kinds.${kind}.title`),\n type: kind,\n });\n }}\n variant=\"outline\"\n >\n {t(`kinds.${kind}.show`)}\n </Button>\n ))}\n </Stack>\n );\n}\n";
69
+ //#endregion
70
+ //#region src/toast/examples/promise.example.tsx
71
+ var promise_example_exports = /* @__PURE__ */ __exportAll({
72
+ Export: () => Export,
73
+ source: () => source$4
74
+ });
75
+ const OUTCOMES = ["succeeds", "fails"];
76
+ function Export() {
77
+ const $ = c(4);
78
+ const { t } = useWords("toast");
79
+ let t0;
80
+ if ($[0] !== t) {
81
+ t0 = OUTCOMES.map((outcome) => /* @__PURE__ */ jsx(Button, {
82
+ onClick: () => {
83
+ toaster.promise(new Promise((resolve, reject) => {
84
+ globalThis.setTimeout(outcome === "succeeds" ? resolve : reject, 2e3);
85
+ }), {
86
+ error: {
87
+ description: t("promise.failed"),
88
+ title: t("promise.error")
89
+ },
90
+ loading: {
91
+ description: t("promise.lines"),
92
+ title: t("promise.loading")
93
+ },
94
+ success: {
95
+ description: t("promise.file"),
96
+ title: t("promise.success")
97
+ }
98
+ });
99
+ },
100
+ variant: "outline",
101
+ children: t(`promise.${outcome}`)
102
+ }, outcome));
103
+ $[0] = t;
104
+ $[1] = t0;
105
+ } else t0 = $[1];
106
+ let t1;
107
+ if ($[2] !== t0) {
108
+ t1 = /* @__PURE__ */ jsx(Stack, {
109
+ direction: "row",
110
+ gap: "sm",
111
+ wrap: true,
112
+ children: t0
113
+ });
114
+ $[2] = t0;
115
+ $[3] = t1;
116
+ } else t1 = $[3];
117
+ return t1;
118
+ }
119
+ const source$4 = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { Stack } from \"@stealthscale/component-layout\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { toaster } from \"./toaster.ts\";\n\nconst OUTCOMES = [\"succeeds\", \"fails\"] as const;\n\nexport function Export(): ReactElement {\n const { t } = useWords(\"toast\");\n\n return (\n <Stack direction=\"row\" gap=\"sm\" wrap>\n {OUTCOMES.map((outcome) => (\n <Button\n key={outcome}\n onClick={() => {\n toaster.promise(\n new Promise<void>((resolve, reject) => {\n globalThis.setTimeout(outcome === \"succeeds\" ? resolve : reject, 2000);\n }),\n {\n error: { description: t(\"promise.failed\"), title: t(\"promise.error\") },\n loading: { description: t(\"promise.lines\"), title: t(\"promise.loading\") },\n success: { description: t(\"promise.file\"), title: t(\"promise.success\") },\n },\n );\n }}\n variant=\"outline\"\n >\n {t(`promise.${outcome}`)}\n </Button>\n ))}\n </Stack>\n );\n}\n";
120
+ //#endregion
121
+ //#region src/toast/examples/queue.example.tsx
122
+ var queue_example_exports = /* @__PURE__ */ __exportAll({
123
+ Queue: () => Queue,
124
+ source: () => source$3
125
+ });
126
+ const LINES = [
127
+ 1,
128
+ 2,
129
+ 3,
130
+ 4,
131
+ 5,
132
+ 6,
133
+ 7,
134
+ 8
135
+ ];
136
+ function Queue() {
137
+ const $ = c(8);
138
+ const { i18n, t } = useWords("toast");
139
+ let t0;
140
+ if ($[0] !== i18n || $[1] !== t) {
141
+ t0 = () => {
142
+ for (const line of LINES) toaster.create({
143
+ description: t("queue.description", { line: line.toLocaleString(i18n.language) }),
144
+ title: t("queue.heading"),
145
+ type: "error"
146
+ });
147
+ };
148
+ $[0] = i18n;
149
+ $[1] = t;
150
+ $[2] = t0;
151
+ } else t0 = $[2];
152
+ let t1;
153
+ if ($[3] !== t) {
154
+ t1 = t("queue.show");
155
+ $[3] = t;
156
+ $[4] = t1;
157
+ } else t1 = $[4];
158
+ let t2;
159
+ if ($[5] !== t0 || $[6] !== t1) {
160
+ t2 = /* @__PURE__ */ jsx(Button, {
161
+ onClick: t0,
162
+ variant: "outline",
163
+ children: t1
164
+ });
165
+ $[5] = t0;
166
+ $[6] = t1;
167
+ $[7] = t2;
168
+ } else t2 = $[7];
169
+ return t2;
170
+ }
171
+ const source$3 = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { toaster } from \"./toaster.ts\";\n\nconst LINES = [1, 2, 3, 4, 5, 6, 7, 8] as const;\n\nexport function Queue(): ReactElement {\n const { i18n, t } = useWords(\"toast\");\n\n return (\n <Button\n onClick={() => {\n for (const line of LINES) {\n toaster.create({\n description: t(\"queue.description\", { line: line.toLocaleString(i18n.language) }),\n title: t(\"queue.heading\"),\n type: \"error\",\n });\n }\n }}\n variant=\"outline\"\n >\n {t(\"queue.show\")}\n </Button>\n );\n}\n";
172
+ //#endregion
173
+ //#region src/toast/examples/region.example.tsx
174
+ var region_example_exports = /* @__PURE__ */ __exportAll({
175
+ Toasts: () => Toasts,
176
+ source: () => source$2
177
+ });
178
+ const MARKS = {
179
+ error: /* @__PURE__ */ jsx(CircleAlertIcon, {}),
180
+ info: /* @__PURE__ */ jsx(InfoIcon, {}),
181
+ loading: /* @__PURE__ */ jsx(Spinner, { size: "sm" }),
182
+ success: /* @__PURE__ */ jsx(CircleCheckIcon, {}),
183
+ warning: /* @__PURE__ */ jsx(TriangleAlertIcon, {})
184
+ };
185
+ function Toasts() {
186
+ const $ = c(12);
187
+ const { t } = useWords("toast");
188
+ let t0;
189
+ if ($[0] !== t) {
190
+ t0 = () => {
191
+ toaster.create({
192
+ description: t("region.description"),
193
+ title: t("region.heading")
194
+ });
195
+ };
196
+ $[0] = t;
197
+ $[1] = t0;
198
+ } else t0 = $[1];
199
+ let t1;
200
+ if ($[2] !== t) {
201
+ t1 = t("region.show");
202
+ $[2] = t;
203
+ $[3] = t1;
204
+ } else t1 = $[3];
205
+ let t2;
206
+ if ($[4] !== t0 || $[5] !== t1) {
207
+ t2 = /* @__PURE__ */ jsx(Button, {
208
+ onClick: t0,
209
+ variant: "outline",
210
+ children: t1
211
+ });
212
+ $[4] = t0;
213
+ $[5] = t1;
214
+ $[6] = t2;
215
+ } else t2 = $[6];
216
+ let t3;
217
+ if ($[7] !== t) {
218
+ t3 = /* @__PURE__ */ jsx(Region, {
219
+ toaster,
220
+ children: (toast) => /* @__PURE__ */ jsxs(Root, { children: [
221
+ /* @__PURE__ */ jsx(Indicator, { children: MARKS[toast.type ?? "info"] }),
222
+ /* @__PURE__ */ jsxs(Content, { children: [/* @__PURE__ */ jsx(Title, { children: toast.title }), /* @__PURE__ */ jsx(Description, { children: toast.description })] }),
223
+ toast.action === void 0 ? null : /* @__PURE__ */ jsx(ActionTrigger, { children: toast.action.label }),
224
+ /* @__PURE__ */ jsx(CloseTrigger, {
225
+ "aria-label": t("dismiss"),
226
+ children: /* @__PURE__ */ jsx(XIcon, {})
227
+ })
228
+ ] })
229
+ });
230
+ $[7] = t;
231
+ $[8] = t3;
232
+ } else t3 = $[8];
233
+ let t4;
234
+ if ($[9] !== t2 || $[10] !== t3) {
235
+ t4 = /* @__PURE__ */ jsxs(Fragment, { children: [t2, t3] });
236
+ $[9] = t2;
237
+ $[10] = t3;
238
+ $[11] = t4;
239
+ } else t4 = $[11];
240
+ return t4;
241
+ }
242
+ const source$2 = "import { type ReactElement } from \"react\";\n\nimport { CircleAlertIcon, CircleCheckIcon, InfoIcon, TriangleAlertIcon, XIcon } from \"lucide-react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { Spinner, Toast } from \"@stealthscale/component-feedback\";\n\nimport { toaster } from \"./toaster.ts\";\n\nconst MARKS: Readonly<Record<string, ReactElement>> = {\n error: <CircleAlertIcon />,\n info: <InfoIcon />,\n loading: <Spinner size=\"sm\" />,\n success: <CircleCheckIcon />,\n warning: <TriangleAlertIcon />,\n};\n\nexport function Toasts(): ReactElement {\n const { t } = useWords(\"toast\");\n\n return (\n <>\n <Button\n onClick={() => {\n toaster.create({ description: t(\"region.description\"), title: t(\"region.heading\") });\n }}\n variant=\"outline\"\n >\n {t(\"region.show\")}\n </Button>\n <Toast.Region toaster={toaster}>\n {(toast) => (\n <Toast.Root>\n <Toast.Indicator>{MARKS[toast.type ?? \"info\"]}</Toast.Indicator>\n <Toast.Content>\n <Toast.Title>{toast.title}</Toast.Title>\n <Toast.Description>{toast.description}</Toast.Description>\n </Toast.Content>\n {toast.action === undefined ? null : (\n <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>\n )}\n <Toast.CloseTrigger aria-label={t(\"dismiss\")}>\n <XIcon />\n </Toast.CloseTrigger>\n </Toast.Root>\n )}\n </Toast.Region>\n </>\n );\n}\n";
243
+ //#endregion
244
+ //#region src/toast/examples/sync.example.tsx
245
+ var sync_example_exports = /* @__PURE__ */ __exportAll({
246
+ Sync: () => Sync,
247
+ source: () => source$1
248
+ });
249
+ function Sync() {
250
+ const $ = c(7);
251
+ const { t } = useWords("toast");
252
+ let t0;
253
+ if ($[0] !== t) {
254
+ t0 = () => {
255
+ const id = toaster.create({
256
+ description: t("sync.started"),
257
+ title: t("sync.heading"),
258
+ type: "loading"
259
+ });
260
+ globalThis.setTimeout(() => {
261
+ toaster.update(id, {
262
+ description: t("sync.halfway"),
263
+ type: "loading"
264
+ });
265
+ }, 1500);
266
+ globalThis.setTimeout(() => {
267
+ toaster.update(id, {
268
+ description: t("sync.done"),
269
+ title: t("sync.matched"),
270
+ type: "success"
271
+ });
272
+ }, 3e3);
273
+ };
274
+ $[0] = t;
275
+ $[1] = t0;
276
+ } else t0 = $[1];
277
+ let t1;
278
+ if ($[2] !== t) {
279
+ t1 = t("sync.show");
280
+ $[2] = t;
281
+ $[3] = t1;
282
+ } else t1 = $[3];
283
+ let t2;
284
+ if ($[4] !== t0 || $[5] !== t1) {
285
+ t2 = /* @__PURE__ */ jsx(Button, {
286
+ onClick: t0,
287
+ variant: "outline",
288
+ children: t1
289
+ });
290
+ $[4] = t0;
291
+ $[5] = t1;
292
+ $[6] = t2;
293
+ } else t2 = $[6];
294
+ return t2;
295
+ }
296
+ const source$1 = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { toaster } from \"./toaster.ts\";\n\nexport function Sync(): ReactElement {\n const { t } = useWords(\"toast\");\n\n return (\n <Button\n onClick={() => {\n const id = toaster.create({\n description: t(\"sync.started\"),\n title: t(\"sync.heading\"),\n type: \"loading\",\n });\n\n globalThis.setTimeout(() => {\n toaster.update(id, { description: t(\"sync.halfway\"), type: \"loading\" });\n }, 1500);\n globalThis.setTimeout(() => {\n toaster.update(id, {\n description: t(\"sync.done\"),\n title: t(\"sync.matched\"),\n type: \"success\",\n });\n }, 3000);\n }}\n variant=\"outline\"\n >\n {t(\"sync.show\")}\n </Button>\n );\n}\n";
297
+ //#endregion
298
+ //#region src/toast/examples/undo.example.tsx
299
+ var undo_example_exports = /* @__PURE__ */ __exportAll({
300
+ Undo: () => Undo,
301
+ source: () => source
302
+ });
303
+ function Undo() {
304
+ const $ = c(7);
305
+ const { t } = useWords("toast");
306
+ let t0;
307
+ if ($[0] !== t) {
308
+ t0 = () => {
309
+ toaster.create({
310
+ action: {
311
+ label: t("undo.action"),
312
+ onClick: () => {
313
+ toaster.success({ title: t("undo.restored") });
314
+ }
315
+ },
316
+ description: t("undo.description"),
317
+ duration: 1e4,
318
+ title: t("undo.heading")
319
+ });
320
+ };
321
+ $[0] = t;
322
+ $[1] = t0;
323
+ } else t0 = $[1];
324
+ let t1;
325
+ if ($[2] !== t) {
326
+ t1 = t("undo.show");
327
+ $[2] = t;
328
+ $[3] = t1;
329
+ } else t1 = $[3];
330
+ let t2;
331
+ if ($[4] !== t0 || $[5] !== t1) {
332
+ t2 = /* @__PURE__ */ jsx(Button, {
333
+ onClick: t0,
334
+ variant: "outline",
335
+ children: t1
336
+ });
337
+ $[4] = t0;
338
+ $[5] = t1;
339
+ $[6] = t2;
340
+ } else t2 = $[6];
341
+ return t2;
342
+ }
343
+ const source = "import { type ReactElement } from \"react\";\n\nimport { Button } from \"@stealthscale/component-actions\";\nimport { useWords } from \"@stealthscale/specimen\";\n\nimport { toaster } from \"./toaster.ts\";\n\nexport function Undo(): ReactElement {\n const { t } = useWords(\"toast\");\n\n return (\n <Button\n onClick={() => {\n toaster.create({\n action: {\n label: t(\"undo.action\"),\n onClick: () => {\n toaster.success({ title: t(\"undo.restored\") });\n },\n },\n description: t(\"undo.description\"),\n duration: 10_000,\n title: t(\"undo.heading\"),\n });\n }}\n variant=\"outline\"\n >\n {t(\"undo.show\")}\n </Button>\n );\n}\n";
344
+ //#endregion
345
+ //#region src/toast/toast.specimen.tsx
346
+ /**
347
+ * Catalogue page for the toast.
348
+ *
349
+ * @remarks
350
+ * A toast renders in a region fixed to the window, not in its scene, so every scene is a trigger
351
+ * that raises toasts. The examples share one toaster, as an application does, and the first
352
+ * scene renders its region. The recipe has no axes, so every scene is hand-written. The specimen
353
+ * imports each example file directly, because the props reader finds the toast's parts through
354
+ * the imports of the example files a specimen imports. A single trigger renders in a `Sample`,
355
+ * which keeps it at its own width. The words are keys under `toast` in
356
+ * `locales/en/specimen/toast.json`.
357
+ */
358
+ /**
359
+ * Hand-written scene for the region an application renders once, with a trigger.
360
+ */
361
+ const regioned = {
362
+ about: "toast.region.about",
363
+ draw: () => /* @__PURE__ */ jsx(Sample, { children: /* @__PURE__ */ jsx(Toasts, {}) }),
364
+ example: region_example_exports,
365
+ title: "toast.region.title"
366
+ };
367
+ /**
368
+ * Hand-written scene for the five kinds a toaster raises.
369
+ */
370
+ const typed = {
371
+ about: "toast.kinds.about",
372
+ draw: Kinds,
373
+ example: kinds_example_exports,
374
+ title: "toast.kinds.title"
375
+ };
376
+ /**
377
+ * Hand-written scene for a toast with an action.
378
+ */
379
+ const undone = {
380
+ about: "toast.undo.about",
381
+ draw: () => /* @__PURE__ */ jsx(Sample, { children: /* @__PURE__ */ jsx(Undo, {}) }),
382
+ example: undo_example_exports,
383
+ title: "toast.undo.title"
384
+ };
385
+ /**
386
+ * Hand-written scene for a toast that follows a promise.
387
+ */
388
+ const promised = {
389
+ about: "toast.promise.about",
390
+ draw: Export,
391
+ example: promise_example_exports,
392
+ title: "toast.promise.title"
393
+ };
394
+ /**
395
+ * Hand-written scene for a toast updated in place.
396
+ */
397
+ const updated = {
398
+ about: "toast.sync.about",
399
+ draw: () => /* @__PURE__ */ jsx(Sample, { children: /* @__PURE__ */ jsx(Sync, {}) }),
400
+ example: sync_example_exports,
401
+ title: "toast.sync.title"
402
+ };
403
+ /**
404
+ * Hand-written scene for toasts queued past the toaster's `max`.
405
+ */
406
+ const queued = {
407
+ about: "toast.queue.about",
408
+ draw: () => /* @__PURE__ */ jsx(Sample, { children: /* @__PURE__ */ jsx(Queue, {}) }),
409
+ example: queue_example_exports,
410
+ title: "toast.queue.title"
411
+ };
412
+ var toast_specimen_default = specimen({
413
+ about: "toast.about",
414
+ id: "components/feedback/toast",
415
+ imports: "import { Toast } from \"@stealthscale/component-feedback\";",
416
+ scenes: [
417
+ regioned,
418
+ typed,
419
+ undone,
420
+ promised,
421
+ updated,
422
+ queued
423
+ ],
424
+ title: "toast.title"
425
+ });
426
+ //#endregion
427
+ export { toast_specimen_default as default, promised, queued, regioned, typed, undone, updated };
@@ -0,0 +1,3 @@
1
+ export const dropped = {"ActionTriggerProps": {"conditions": 284, "foreign": 1051}, "CloseTriggerProps": {"conditions": 284, "foreign": 1051}, "ContentProps": {"conditions": 284, "foreign": 1041}, "DescriptionProps": {"conditions": 284, "foreign": 1041}, "IndicatorProps": {"conditions": 284, "foreign": 1041}, "RegionProps": {"conditions": 284, "foreign": 1039}, "RootProps": {"conditions": 284, "foreign": 1041}, "TitleProps": {"conditions": 284, "foreign": 1041}, "SpinnerProps": {"conditions": 284, "foreign": 1040}};
2
+ export const parts = {"ActionTriggerProps": [], "CloseTriggerProps": [], "ContentProps": [], "DescriptionProps": [], "IndicatorProps": [], "RegionProps": [{"accepts": "(toast: ToastOptions) => ReactNode", "fallback": "", "kind": "option", "name": "children", "refers": ["kit.ToastOptions", "react.ReactElement", "react.ReactPortal", "toast.ActionOptions", "toast.ToastQueuePriority", "toast.Type"], "required": true, "says": "Renders one toast, which the region wraps in the toast's own machine."}, {"accepts": "\"ltr\" | \"rtl\"", "fallback": "", "kind": "option", "name": "dir", "refers": [], "required": false, "says": "The text direction, which mirrors the start and end placements."}, {"accepts": "string", "fallback": "", "kind": "option", "name": "label", "refers": [], "required": false, "says": "The landmark's name, before the placement and the hotkey. `Notifications` by default."}, {"accepts": "Toaster", "fallback": "", "kind": "option", "name": "toaster", "refers": ["kit.Toaster", "toast.Options", "toast.Placement", "toast.PromiseOptions", "toast.ToastStoreProps", "types.Required"], "required": true, "says": "The store the region renders the toasts of."}], "RootProps": [], "TitleProps": [], "SpinnerProps": [{"accepts": "\"glow\" | \"pulse\"", "fallback": "", "kind": "variant", "name": "effect", "refers": [], "required": false, "says": "The halo drawn around the ring, in the palette's solid at half opacity."}, {"accepts": "\"accent\" | \"current\" | \"error\" | \"info\" | \"neutral\" | \"primary\" | \"secondary\" | \"success\" | \"warning\"", "fallback": "", "kind": "variant", "name": "palette", "refers": [], "required": false, "says": "The palette the arc is drawn in, as its `solid` role."}, {"accepts": "\"2xl\" | \"3xl\" | \"4xl\" | \"inherit\" | \"lg\" | \"md\" | \"sm\" | \"xl\" | \"xs\"", "fallback": "", "kind": "variant", "name": "size", "refers": [], "required": false, "says": ""}, {"accepts": "\"control\" | \"hairline\" | \"heavy\" | \"indicator\"", "fallback": "", "kind": "variant", "name": "stroke", "refers": [], "required": false, "says": "Border width of the ring. `hairline`, `control` and `indicator` read the theme's stroke tokens, and `heavy` reads the 4px `lg` width."}, {"accepts": "boolean", "fallback": "", "kind": "variant", "name": "track", "refers": [], "required": false, "says": "Whether the two track sides draw the ring behind the arc, in the palette's `muted` role."}]};
3
+ export const shapes = {"react.ReactElement": [{"accepts": "string | JSXElementConstructor<any>", "name": "type", "says": ""}, {"accepts": "unknown", "name": "props", "says": ""}, {"accepts": "string | null", "name": "key", "says": ""}], "react.ReactPortal": [{"accepts": "ReactNode", "name": "children", "says": ""}, {"accepts": "string | JSXElementConstructor<any>", "name": "type", "says": ""}, {"accepts": "unknown", "name": "props", "says": ""}, {"accepts": "string | null", "name": "key", "says": ""}], "kit.ToastOptions": [{"accepts": "ReactNode", "name": "title", "says": "The title of the toast."}, {"accepts": "ReactNode", "name": "description", "says": "The description of the toast."}, {"accepts": "number", "name": "duration", "says": "The duration the toast will be visible"}, {"accepts": "number", "name": "removeDelay", "says": "The duration for the toast to kept alive before it is removed. Useful for exit transitions."}, {"accepts": "string", "name": "id", "says": "The unique id of the toast"}, {"accepts": "Type", "name": "type", "says": "The type of the toast"}, {"accepts": "ToastQueuePriority", "name": "priority", "says": "The priority of the toast (1 = highest, 8 = lowest)"}, {"accepts": "((details: StatusChangeDetails) => void)", "name": "onStatusChange", "says": "Function called when the toast is visible"}, {"accepts": "ActionOptions", "name": "action", "says": "The action of the toast"}, {"accepts": "boolean", "name": "closable", "says": "Whether the toast is closable"}, {"accepts": "Record<string, any>", "name": "meta", "says": "The metadata of the toast"}], "toast.Type": [{"accepts": "", "name": "\"error\"", "says": ""}, {"accepts": "", "name": "\"info\"", "says": ""}, {"accepts": "", "name": "\"loading\"", "says": ""}, {"accepts": "", "name": "\"success\"", "says": ""}, {"accepts": "", "name": "\"warning\"", "says": ""}, {"accepts": "", "name": "string & {}", "says": ""}], "toast.ToastQueuePriority": [{"accepts": "", "name": "1", "says": ""}, {"accepts": "", "name": "2", "says": ""}, {"accepts": "", "name": "3", "says": ""}, {"accepts": "", "name": "4", "says": ""}, {"accepts": "", "name": "5", "says": ""}, {"accepts": "", "name": "6", "says": ""}, {"accepts": "", "name": "7", "says": ""}, {"accepts": "", "name": "8", "says": ""}], "toast.ActionOptions": [{"accepts": "string", "name": "label", "says": "The label of the action"}, {"accepts": "VoidFunction", "name": "onClick", "says": "The function to call when the action is clicked"}], "kit.Toaster": [{"accepts": "Required<ToastStoreProps>", "name": "attrs", "says": "The attributes of the toast store"}, {"accepts": "(subscriber: (...args: any[]) => void) => VoidFunction", "name": "subscribe", "says": "Subscribe to the toast store"}, {"accepts": "(data: Options<any>) => string", "name": "create", "says": "Create a new toast with the given options"}, {"accepts": "(id: string, data: Partial<ToastProps<any>>) => string", "name": "update", "says": "Update an existing toast with new properties"}, {"accepts": "(id?: string) => void", "name": "remove", "says": "Remove a toast by its ID"}, {"accepts": "(id?: string) => void", "name": "dismiss", "says": "Dismiss a toast by its ID. If no ID is provided, dismisses all toasts"}, {"accepts": "(data: Options<any>) => void", "name": "error", "says": "Create an error toast with the given options"}, {"accepts": "(data: Options<any>) => void", "name": "success", "says": "Create a success toast with the given options"}, {"accepts": "(data: Options<any>) => void", "name": "info", "says": "Create an info toast with the given options"}, {"accepts": "(data: Options<any>) => void", "name": "warning", "says": "Create a warning toast with the given options"}, {"accepts": "(data: Options<any>) => void", "name": "loading", "says": "Create a loading toast with the given options"}, {"accepts": "() => Partial<ToastProps<any>>[]", "name": "getVisibleToasts", "says": "Get all currently visible toasts"}, {"accepts": "() => number", "name": "getCount", "says": "Get the total number of toasts"}, {"accepts": "<T>(promise: Promise<T> | (() => Promise<T>), options: PromiseOptions<T, any>, shared?: Omit<Options<any>, \"type\">) => { ...; }", "name": "promise", "says": "Create a toast that tracks a promise's state"}, {"accepts": "(id?: string) => void", "name": "pause", "says": "Pause a toast's auto-dismiss timer. If no ID is provided, pauses all toasts"}, {"accepts": "(id?: string) => void", "name": "resume", "says": "Resume a toast's auto-dismiss timer. If no ID is provided, resumes all toasts"}, {"accepts": "(id: string) => boolean", "name": "isVisible", "says": "Check if a toast with the given ID is currently visible"}, {"accepts": "(id: string) => boolean", "name": "isDismissed", "says": "Check if a toast with the given ID has been dismissed"}, {"accepts": "VoidFunction", "name": "expand", "says": "Expand all toasts to show their full content (overlap mode)"}, {"accepts": "VoidFunction", "name": "collapse", "says": "Collapse all toasts to their compact state (overlap mode)"}], "toast.ToastStoreProps": [{"accepts": "Placement", "name": "placement", "says": "The placement of the toast"}, {"accepts": "number", "name": "max", "says": "The maximum number of toasts. When the number of toasts exceeds this limit, the new toasts are queued."}, {"accepts": "boolean", "name": "overlap", "says": "Whether to overlap the toasts"}, {"accepts": "number", "name": "duration", "says": "The duration of the toast. By default, it is determined by the type of the toast."}, {"accepts": "number", "name": "gap", "says": "The gap between the toasts"}, {"accepts": "string | Record<\"bottom\" | \"left\" | \"right\" | \"top\", string>", "name": "offsets", "says": "The offset from the safe environment edge of the viewport"}, {"accepts": "string[]", "name": "hotkey", "says": "The hotkey that will move focus to the toast group"}, {"accepts": "number", "name": "removeDelay", "says": "The duration for the toast to kept alive before it is removed. Useful for exit transitions."}, {"accepts": "boolean", "name": "pauseOnPageIdle", "says": "Whether to pause toast when the user leaves the browser tab"}], "types.Required": [{"accepts": "Placement", "name": "placement", "says": "The placement of the toast"}, {"accepts": "number", "name": "max", "says": "The maximum number of toasts. When the number of toasts exceeds this limit, the new toasts are queued."}, {"accepts": "boolean", "name": "overlap", "says": "Whether to overlap the toasts"}, {"accepts": "number", "name": "duration", "says": "The duration of the toast. By default, it is determined by the type of the toast."}, {"accepts": "number", "name": "gap", "says": "The gap between the toasts"}, {"accepts": "string | Record<\"bottom\" | \"left\" | \"right\" | \"top\", string>", "name": "offsets", "says": "The offset from the safe environment edge of the viewport"}, {"accepts": "string[]", "name": "hotkey", "says": "The hotkey that will move focus to the toast group"}, {"accepts": "number", "name": "removeDelay", "says": "The duration for the toast to kept alive before it is removed. Useful for exit transitions."}, {"accepts": "boolean", "name": "pauseOnPageIdle", "says": "Whether to pause toast when the user leaves the browser tab"}], "toast.Placement": [{"accepts": "", "name": "\"bottom\"", "says": ""}, {"accepts": "", "name": "\"bottom-end\"", "says": ""}, {"accepts": "", "name": "\"bottom-start\"", "says": ""}, {"accepts": "", "name": "\"top\"", "says": ""}, {"accepts": "", "name": "\"top-end\"", "says": ""}, {"accepts": "", "name": "\"top-start\"", "says": ""}], "toast.Options": [{"accepts": "any", "name": "title", "says": "The title of the toast."}, {"accepts": "any", "name": "description", "says": "The description of the toast."}, {"accepts": "number", "name": "duration", "says": "The duration the toast will be visible"}, {"accepts": "number", "name": "removeDelay", "says": "The duration for the toast to kept alive before it is removed. Useful for exit transitions."}, {"accepts": "string", "name": "id", "says": "The unique id of the toast"}, {"accepts": "Type", "name": "type", "says": "The type of the toast"}, {"accepts": "ToastQueuePriority", "name": "priority", "says": "The priority of the toast (1 = highest, 8 = lowest)"}, {"accepts": "((details: StatusChangeDetails) => void)", "name": "onStatusChange", "says": "Function called when the toast is visible"}, {"accepts": "ActionOptions", "name": "action", "says": "The action of the toast"}, {"accepts": "boolean", "name": "closable", "says": "Whether the toast is closable"}, {"accepts": "Record<string, any>", "name": "meta", "says": "The metadata of the toast"}], "toast.PromiseOptions": [{"accepts": "Omit<Options<any>, \"type\">", "name": "loading", "says": ""}, {"accepts": "MaybeFunction<Omit<Options<any>, \"type\"> & { type?: \"success\" | \"warning\"; }, T>", "name": "success", "says": ""}, {"accepts": "MaybeFunction<Omit<Options<any>, \"type\">, unknown>", "name": "error", "says": ""}, {"accepts": "(() => void | Promise<void>)", "name": "finally", "says": ""}]};