@lablup/ui-common 0.1.0-alpha.2 → 0.1.0-alpha.20

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/components/BaseCard/BaseCard.css +1 -1
  3. package/dist/assets/components/Button/Button.css +1 -1
  4. package/dist/assets/components/DataTable/DataTable.css +1 -1
  5. package/dist/assets/components/Drawer/Drawer.css +1 -1
  6. package/dist/assets/components/EmptyState/EmptyState.css +1 -1
  7. package/dist/assets/components/ErrorState/ErrorState.css +1 -1
  8. package/dist/assets/components/PageHeader/PageHeader.css +1 -1
  9. package/dist/assets/components/Select/Select.css +1 -0
  10. package/dist/assets/components/StatCard/StatCard.css +1 -1
  11. package/dist/assets/components/Tabs/Tabs.css +1 -1
  12. package/dist/assets/components/Tooltip/Tooltip.css +1 -1
  13. package/dist/components/DataTable/DataTable.d.ts +30 -6
  14. package/dist/components/DataTable/DataTable2.js +85 -92
  15. package/dist/components/DataTable/DataTable2.js.map +1 -1
  16. package/dist/components/Drawer/Drawer.d.ts +12 -1
  17. package/dist/components/Drawer/Drawer2.js +69 -51
  18. package/dist/components/Drawer/Drawer2.js.map +1 -1
  19. package/dist/components/EmptyState/EmptyState.d.ts +10 -3
  20. package/dist/components/EmptyState/EmptyState2.js +31 -48
  21. package/dist/components/EmptyState/EmptyState2.js.map +1 -1
  22. package/dist/components/EmptyState/index.d.ts +6 -1
  23. package/dist/components/ErrorState/ErrorState.d.ts +17 -4
  24. package/dist/components/ErrorState/ErrorState2.js +20 -23
  25. package/dist/components/ErrorState/ErrorState2.js.map +1 -1
  26. package/dist/components/ErrorState/index.d.ts +1 -1
  27. package/dist/components/PageHeader/PageHeader.d.ts +14 -1
  28. package/dist/components/PageHeader/PageHeader2.js +40 -24
  29. package/dist/components/PageHeader/PageHeader2.js.map +1 -1
  30. package/dist/components/Select/Select.d.ts +38 -0
  31. package/dist/components/Select/Select2.js +313 -0
  32. package/dist/components/Select/Select2.js.map +1 -0
  33. package/dist/components/Select/index.d.ts +2 -0
  34. package/dist/components/Select/index.js +2 -0
  35. package/dist/components/Skeleton/Skeleton.d.ts +11 -1
  36. package/dist/components/Skeleton/Skeleton2.js +8 -6
  37. package/dist/components/Skeleton/Skeleton2.js.map +1 -1
  38. package/dist/components/Skeleton/SkeletonCard.d.ts +3 -1
  39. package/dist/components/Skeleton/SkeletonCard2.js +13 -3
  40. package/dist/components/Skeleton/SkeletonCard2.js.map +1 -1
  41. package/dist/components/Skeleton/SkeletonChart2.js +5 -0
  42. package/dist/components/Skeleton/SkeletonChart2.js.map +1 -1
  43. package/dist/components/Skeleton/SkeletonRow.d.ts +3 -1
  44. package/dist/components/Skeleton/SkeletonRow2.js +9 -3
  45. package/dist/components/Skeleton/SkeletonRow2.js.map +1 -1
  46. package/dist/components/Skeleton/SkeletonText.d.ts +3 -1
  47. package/dist/components/Skeleton/SkeletonText2.js +7 -5
  48. package/dist/components/Skeleton/SkeletonText2.js.map +1 -1
  49. package/dist/components/StatCard/StatCard.d.ts +10 -1
  50. package/dist/components/StatCard/StatCard2.js +30 -30
  51. package/dist/components/StatCard/StatCard2.js.map +1 -1
  52. package/dist/components/Tabs/Tabs.d.ts +10 -23
  53. package/dist/components/Tabs/Tabs2.js +127 -146
  54. package/dist/components/Tabs/Tabs2.js.map +1 -1
  55. package/dist/components/Tabs/index.d.ts +2 -2
  56. package/dist/components/Tabs/index.js +2 -3
  57. package/dist/components/Tooltip/Tooltip.d.ts +15 -1
  58. package/dist/components/Tooltip/Tooltip2.js +77 -47
  59. package/dist/components/Tooltip/Tooltip2.js.map +1 -1
  60. package/dist/index.d.ts +1 -0
  61. package/dist/index.js +6 -6
  62. package/dist/styles/base.css +101 -10
  63. package/dist/styles/themes/orange-dark.css +3 -0
  64. package/dist/styles/themes/orange-light.css +6 -1
  65. package/package.json +1 -1
  66. package/dist/components/EmptyState/illustrations.d.ts +0 -51
  67. package/dist/components/EmptyState/illustrations.js +0 -571
  68. package/dist/components/EmptyState/illustrations.js.map +0 -1
  69. package/dist/components/Tabs/tabTags.d.ts +0 -9
  70. package/dist/components/Tabs/tabTags.js +0 -11
  71. package/dist/components/Tabs/tabTags.js.map +0 -1
@@ -1,43 +1,59 @@
1
+ import { Button as e } from "../Button/Button2.js";
1
2
  /* empty css */
2
- import { jsx as e, jsxs as t } from "react/jsx-runtime";
3
+ import { jsx as t, jsxs as n } from "react/jsx-runtime";
3
4
  //#region src/components/PageHeader/PageHeader.tsx
4
- function n({ title: n, description: r, actions: i, error: a, onErrorDismiss: o, className: s = "", dismissErrorLabel: c = "Dismiss error" }) {
5
- let l = ["page-header", s].filter(Boolean).join(" ");
6
- return /* @__PURE__ */ t("header", {
7
- className: l,
8
- children: [/* @__PURE__ */ t("div", {
5
+ function r({ title: r, description: i, actions: a, error: o, onErrorDismiss: s, className: c = "", errorDetail: l, onRetry: u, retryLabel: d = "Retry", dismissErrorLabel: f = "Dismiss error" }) {
6
+ let p = ["page-header", c].filter(Boolean).join(" ");
7
+ return /* @__PURE__ */ n("header", {
8
+ className: p,
9
+ children: [/* @__PURE__ */ n("div", {
9
10
  className: "page-header__content",
10
- children: [/* @__PURE__ */ t("div", {
11
+ children: [/* @__PURE__ */ n("div", {
11
12
  className: "page-header__text",
12
- children: [/* @__PURE__ */ e("h1", {
13
+ children: [/* @__PURE__ */ t("h1", {
13
14
  className: "page-header__title",
14
- children: n
15
- }), r && /* @__PURE__ */ e("p", {
16
- className: "page-header__description",
17
15
  children: r
16
+ }), i && /* @__PURE__ */ t("p", {
17
+ className: "page-header__description",
18
+ children: i
18
19
  })]
19
- }), i && /* @__PURE__ */ e("div", {
20
+ }), a && /* @__PURE__ */ t("div", {
20
21
  className: "page-header__actions",
21
- children: i
22
+ children: a
22
23
  })]
23
- }), a && /* @__PURE__ */ t("div", {
24
+ }), o && /* @__PURE__ */ n("div", {
24
25
  className: "page-header__error",
25
26
  role: "alert",
26
- children: [/* @__PURE__ */ e("span", {
27
- className: "page-header__error-text",
28
- children: a
29
- }), o && /* @__PURE__ */ e("button", {
30
- type: "button",
31
- className: "page-header__error-dismiss",
32
- onClick: o,
33
- "aria-label": c,
34
- children: "×"
27
+ children: [/* @__PURE__ */ n("div", {
28
+ className: "page-header__error-body",
29
+ children: [/* @__PURE__ */ t("span", {
30
+ className: "page-header__error-text",
31
+ children: o
32
+ }), l && /* @__PURE__ */ t("span", {
33
+ className: "page-header__error-detail",
34
+ children: l
35
+ })]
36
+ }), (u || s) && /* @__PURE__ */ n("div", {
37
+ className: "page-header__error-actions",
38
+ children: [u && /* @__PURE__ */ t(e, {
39
+ variant: "secondary",
40
+ size: "small",
41
+ className: "page-header__error-retry",
42
+ onClick: u,
43
+ children: d
44
+ }), s && /* @__PURE__ */ t("button", {
45
+ type: "button",
46
+ className: "page-header__error-dismiss",
47
+ onClick: s,
48
+ "aria-label": f,
49
+ children: "×"
50
+ })]
35
51
  })]
36
52
  })]
37
53
  });
38
54
  }
39
55
  //#endregion
40
- export { n as PageHeader };
56
+ export { r as PageHeader };
41
57
 
42
58
  //# sourceMappingURL=PageHeader2.js.map
43
59
  import "../../assets/components/PageHeader/PageHeader.css";
@@ -1 +1 @@
1
- {"version":3,"file":"PageHeader2.js","names":[],"sources":["../../../src/components/PageHeader/PageHeader.tsx"],"sourcesContent":["/**\n * PageHeader Component\n *\n * Standardized page header with title, description, and optional action buttons.\n * Provides consistent styling and layout across all pages.\n *\n * @example\n * // Basic usage\n * <PageHeader\n * title=\"Models\"\n * description=\"Manage and browse your local models\"\n * />\n *\n * @example\n * // With action buttons\n * <PageHeader\n * title=\"Settings\"\n * description=\"Configure application settings\"\n * actions={\n * <>\n * <Button variant=\"secondary\">Import</Button>\n * <Button variant=\"primary\">Save</Button>\n * </>\n * }\n * />\n *\n * @example\n * // With error display\n * <PageHeader\n * title=\"Engines\"\n * description=\"Manage runtime engines\"\n * error={error}\n * onErrorDismiss={() => clearError()}\n * />\n */\n\nimport type { ReactNode } from \"react\";\nimport \"./PageHeader.css\";\n\nexport interface PageHeaderProps {\n /** Page title - displayed as h1 */\n title: string;\n /** Page description - displayed below title */\n description?: string;\n /** Optional action buttons or elements on the right side */\n actions?: ReactNode;\n /** Error message to display below the header */\n error?: string | null;\n /** Callback when error is dismissed */\n onErrorDismiss?: () => void;\n /** Additional CSS class names */\n className?: string;\n /** Accessible label for the error-dismiss button. Default: \"Dismiss error\" */\n dismissErrorLabel?: string;\n}\n\nexport function PageHeader({\n title,\n description,\n actions,\n error,\n onErrorDismiss,\n className = \"\",\n dismissErrorLabel = \"Dismiss error\",\n}: PageHeaderProps) {\n const classes = [\"page-header\", className].filter(Boolean).join(\" \");\n\n return (\n <header className={classes}>\n <div className=\"page-header__content\">\n <div className=\"page-header__text\">\n <h1 className=\"page-header__title\">{title}</h1>\n {description && <p className=\"page-header__description\">{description}</p>}\n </div>\n {actions && <div className=\"page-header__actions\">{actions}</div>}\n </div>\n {error && (\n <div className=\"page-header__error\" role=\"alert\">\n <span className=\"page-header__error-text\">{error}</span>\n {onErrorDismiss && (\n <button\n type=\"button\"\n className=\"page-header__error-dismiss\"\n onClick={onErrorDismiss}\n aria-label={dismissErrorLabel}\n >\n ×\n </button>\n )}\n </div>\n )}\n </header>\n );\n}\n"],"mappings":";;;AAwDA,SAAgB,EAAW,EACzB,UACA,gBACA,YACA,UACA,mBACA,eAAY,IACZ,uBAAoB,mBACF;CAClB,IAAM,IAAU,CAAC,eAAe,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAEnE,OACE,kBAAC,UAAD;EAAQ,WAAW;EAAnB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KAAsB,UAAA;IAAU,CAAA,GAC7C,KAAe,kBAAC,KAAD;KAAG,WAAU;KAA4B,UAAA;IAAe,CAAA,CACrE;GACJ,CAAA,GAAA,KAAW,kBAAC,OAAD;IAAK,WAAU;IAAwB,UAAA;GAAa,CAAA,CAC7D;EACJ,CAAA,GAAA,KACC,kBAAC,OAAD;GAAK,WAAU;GAAqB,MAAK;GAAzC,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAA2B,UAAA;GAAY,CAAA,GACtD,KACC,kBAAC,UAAD;IACE,MAAK;IACL,WAAU;IACV,SAAS;IACT,cAAY;IACb,UAAA;GAEO,CAAA,CAEP;EAED,CAAA,CAAA;;AAEZ"}
1
+ {"version":3,"file":"PageHeader2.js","names":[],"sources":["../../../src/components/PageHeader/PageHeader.tsx"],"sourcesContent":["/**\n * PageHeader Component\n *\n * Standardized page header with title, description, and optional action buttons.\n * Provides consistent styling and layout across all pages.\n *\n * @example\n * // Basic usage\n * <PageHeader\n * title=\"Models\"\n * description=\"Manage and browse your local models\"\n * />\n *\n * @example\n * // With action buttons\n * <PageHeader\n * title=\"Settings\"\n * description=\"Configure application settings\"\n * actions={\n * <>\n * <Button variant=\"secondary\">Import</Button>\n * <Button variant=\"primary\">Save</Button>\n * </>\n * }\n * />\n *\n * @example\n * // With error display\n * <PageHeader\n * title=\"Engines\"\n * description=\"Manage runtime engines\"\n * error={error}\n * onErrorDismiss={() => clearError()}\n * />\n */\n\nimport type { ReactNode } from \"react\";\nimport { Button } from \"../Button\";\nimport \"./PageHeader.css\";\n\nexport interface PageHeaderProps {\n /** Page title - displayed as h1 */\n title: string;\n /** Page description - displayed below title */\n description?: string;\n /** Optional action buttons or elements on the right side */\n actions?: ReactNode;\n /** Error message to display below the header */\n error?: string | null;\n /**\n * Secondary line under the message, for the raw detail a server returned.\n * Kept separate so the message stays readable when the detail is long.\n */\n errorDetail?: string | null;\n /**\n * Callback for the Retry button, rendered before the dismiss control when\n * set. Dismissal is a pure dismissal and must not retry, which is why these\n * are two props rather than one.\n */\n onRetry?: () => void;\n /** Label for the Retry button. Default: \"Retry\" */\n retryLabel?: string;\n /** Callback when error is dismissed */\n onErrorDismiss?: () => void;\n /** Additional CSS class names */\n className?: string;\n /** Accessible label for the error-dismiss button. Default: \"Dismiss error\" */\n dismissErrorLabel?: string;\n}\n\nexport function PageHeader({\n title,\n description,\n actions,\n error,\n onErrorDismiss,\n className = \"\",\n errorDetail,\n onRetry,\n retryLabel = \"Retry\",\n dismissErrorLabel = \"Dismiss error\",\n}: PageHeaderProps) {\n const classes = [\"page-header\", className].filter(Boolean).join(\" \");\n\n return (\n <header className={classes}>\n <div className=\"page-header__content\">\n <div className=\"page-header__text\">\n <h1 className=\"page-header__title\">{title}</h1>\n {description && <p className=\"page-header__description\">{description}</p>}\n </div>\n {actions && <div className=\"page-header__actions\">{actions}</div>}\n </div>\n {error && (\n <div className=\"page-header__error\" role=\"alert\">\n <div className=\"page-header__error-body\">\n <span className=\"page-header__error-text\">{error}</span>\n {errorDetail && (\n <span className=\"page-header__error-detail\">{errorDetail}</span>\n )}\n </div>\n {(onRetry || onErrorDismiss) && (\n <div className=\"page-header__error-actions\">\n {onRetry && (\n <Button\n variant=\"secondary\"\n size=\"small\"\n className=\"page-header__error-retry\"\n onClick={onRetry}\n >\n {retryLabel}\n </Button>\n )}\n {onErrorDismiss && (\n <button\n type=\"button\"\n className=\"page-header__error-dismiss\"\n onClick={onErrorDismiss}\n aria-label={dismissErrorLabel}\n >\n ×\n </button>\n )}\n </div>\n )}\n </div>\n )}\n </header>\n );\n}\n"],"mappings":";;;;AAsEA,SAAgB,EAAW,EACzB,UACA,gBACA,YACA,UACA,mBACA,eAAY,IACZ,gBACA,YACA,gBAAa,SACb,uBAAoB,mBACF;CAClB,IAAM,IAAU,CAAC,eAAe,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAEnE,OACE,kBAAC,UAAD;EAAQ,WAAW;EAAnB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;KAAsB,UAAA;IAAU,CAAA,GAC7C,KAAe,kBAAC,KAAD;KAAG,WAAU;KAA4B,UAAA;IAAe,CAAA,CACrE;GACJ,CAAA,GAAA,KAAW,kBAAC,OAAD;IAAK,WAAU;IAAwB,UAAA;GAAa,CAAA,CAC7D;EACJ,CAAA,GAAA,KACC,kBAAC,OAAD;GAAK,WAAU;GAAqB,MAAK;GAAzC,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAA2B,UAAA;IAAY,CAAA,GACtD,KACC,kBAAC,QAAD;KAAM,WAAU;KAA6B,UAAA;IAAkB,CAAA,CAE9D;GACH,CAAA,IAAA,KAAW,MACX,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,MAAK;KACL,WAAU;KACV,SAAS;KAER,UAAA;IACK,CAAA,GAET,KACC,kBAAC,UAAD;KACE,MAAK;KACL,WAAU;KACV,SAAS;KACT,cAAY;KACb,UAAA;IAEO,CAAA,CAEP;GAEJ,CAAA,CAAA;EAED,CAAA,CAAA;;AAEZ"}
@@ -0,0 +1,38 @@
1
+ import { ReactNode } from 'react';
2
+ export interface SelectOption<T extends string = string> {
3
+ value: T;
4
+ label: string;
5
+ description?: string;
6
+ icon?: ReactNode;
7
+ /** Keep an unavailable choice visible while preventing its selection. */
8
+ disabled?: boolean;
9
+ }
10
+ export interface SelectProps<T extends string = string> {
11
+ value: T;
12
+ onChange: (value: T) => void;
13
+ onBlur?: () => void;
14
+ options: SelectOption<T>[];
15
+ /**
16
+ * Field label rendered above the trigger, the way `TextInput` renders its
17
+ * own. Names the trigger and the listbox through `aria-labelledby`, so a
18
+ * caller that supplies it does not also need `aria-label`.
19
+ */
20
+ label?: ReactNode;
21
+ placeholder?: string;
22
+ disabled?: boolean;
23
+ size?: "small" | "default" | "medium" | "large";
24
+ fullWidth?: boolean;
25
+ className?: string;
26
+ searchable?: boolean;
27
+ searchPlaceholder?: string;
28
+ "aria-label"?: string;
29
+ "aria-describedby"?: string;
30
+ invalid?: boolean;
31
+ /**
32
+ * Shown in place of the list when a search matches nothing. English default,
33
+ * because this package cannot resolve a consumer's locale key: a product that
34
+ * localises passes its own words.
35
+ */
36
+ noOptionsLabel?: string;
37
+ }
38
+ export declare function Select<T extends string = string>({ value, onChange, onBlur, options, label, placeholder, disabled, size, fullWidth, className, searchable, searchPlaceholder, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, invalid, noOptionsLabel, }: SelectProps<T>): import("react").JSX.Element;
@@ -0,0 +1,313 @@
1
+ /* empty css */
2
+ import { useCallback as e, useEffect as t, useId as n, useMemo as r, useRef as i, useState as a } from "react";
3
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
+ import { createPortal as c } from "react-dom";
5
+ //#region src/components/Select/Select.tsx
6
+ function l({ value: l, onChange: u, onBlur: d, options: f, label: p, placeholder: ee = "Select...", disabled: m = !1, size: h = "default", fullWidth: g = !1, className: _ = "", searchable: v = !1, searchPlaceholder: y, "aria-label": b, "aria-describedby": x, invalid: S = !1, noOptionsLabel: C = "No options" }) {
7
+ let [w, T] = a(!1), [E, D] = a(-1), [O, k] = a(""), [A, te] = a({
8
+ top: 0,
9
+ left: 0,
10
+ width: 0
11
+ }), j = i(null), M = i(null), N = i(null), P = i(null), F = i([]), I = n(), L = n(), R = n(), z = p != null && p !== !1, B = f.find((e) => e.value === l), V = r(() => {
12
+ let e = O.trim().toLowerCase();
13
+ return !v || e.length === 0 ? f : f.filter((t) => [
14
+ t.label,
15
+ t.value,
16
+ t.description ?? ""
17
+ ].some((t) => t.toLowerCase().includes(e)));
18
+ }, [
19
+ f,
20
+ O,
21
+ v
22
+ ]), H = e((e, t) => {
23
+ for (let n = e; n >= 0 && n < V.length; n += t) {
24
+ let e = V[n];
25
+ if (e && !e.disabled) return n;
26
+ }
27
+ return -1;
28
+ }, [V]), U = (e) => `${L}-option-${String(e)}`, W = E >= 0 ? U(E) : void 0, G = e(() => {
29
+ if (!M.current) return;
30
+ let e = M.current.getBoundingClientRect();
31
+ te({
32
+ top: e.bottom + 4,
33
+ left: e.left,
34
+ width: e.width
35
+ });
36
+ }, []), K = e(() => {
37
+ if (m) return;
38
+ G(), T(!0);
39
+ let e = V.findIndex((e) => e.value === l && !e.disabled);
40
+ D(e === -1 ? H(0, 1) : e);
41
+ }, [
42
+ m,
43
+ V,
44
+ l,
45
+ G,
46
+ H
47
+ ]), q = e(() => {
48
+ T(!1), D(-1), k(""), M.current?.focus();
49
+ }, []), J = e((e, t) => {
50
+ t && (t.stopPropagation(), t.preventDefault()), !e.disabled && (u(e.value), q());
51
+ }, [u, q]);
52
+ t(() => {
53
+ let e = (e) => {
54
+ if (!w) return;
55
+ let t = e.target, n = j.current && !j.current.contains(t), r = N.current && !N.current.contains(t);
56
+ n && r && q();
57
+ }, t = (e) => {
58
+ e.key === "Escape" && w && q();
59
+ };
60
+ return w && (document.addEventListener("mousedown", e), document.addEventListener("keydown", t)), () => {
61
+ document.removeEventListener("mousedown", e), document.removeEventListener("keydown", t);
62
+ };
63
+ }, [w, q]), t(() => {
64
+ if (!w) return;
65
+ let e = () => {
66
+ G();
67
+ };
68
+ return window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
69
+ window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
70
+ };
71
+ }, [w, G]), t(() => {
72
+ w && v && P.current?.focus();
73
+ }, [w, v]), t(() => {
74
+ if (!w || !v) return;
75
+ F.current = [];
76
+ let e = V.findIndex((e) => e.value === l && !e.disabled);
77
+ D(e >= 0 ? e : H(0, 1));
78
+ }, [
79
+ w,
80
+ O,
81
+ v,
82
+ l,
83
+ V,
84
+ H
85
+ ]);
86
+ let Y = e((e) => {
87
+ if (!m) switch (e.key) {
88
+ case "Enter":
89
+ case " ":
90
+ if (e.preventDefault(), w) {
91
+ let e = V[E];
92
+ e && J(e);
93
+ } else K();
94
+ break;
95
+ case "Escape":
96
+ e.preventDefault(), w && q();
97
+ break;
98
+ case "ArrowDown":
99
+ if (e.preventDefault(), !w) K();
100
+ else {
101
+ let e = H(E + 1, 1);
102
+ e >= 0 && D(e);
103
+ }
104
+ break;
105
+ case "ArrowUp":
106
+ if (e.preventDefault(), w) {
107
+ let e = H(E - 1, -1);
108
+ e >= 0 && D(e);
109
+ }
110
+ break;
111
+ case "Tab": w && q();
112
+ }
113
+ }, [
114
+ m,
115
+ w,
116
+ E,
117
+ V,
118
+ H,
119
+ K,
120
+ q,
121
+ J
122
+ ]), X = e((e) => {
123
+ switch (e.key) {
124
+ case "Enter": {
125
+ e.preventDefault();
126
+ let t = V[E];
127
+ t && J(t);
128
+ break;
129
+ }
130
+ case "Escape":
131
+ e.preventDefault(), e.stopPropagation(), q();
132
+ break;
133
+ case "ArrowDown":
134
+ e.preventDefault(), D((e) => {
135
+ let t = H(e + 1, 1);
136
+ return t >= 0 ? t : e;
137
+ });
138
+ break;
139
+ case "ArrowUp":
140
+ e.preventDefault(), D((e) => {
141
+ let t = H(e - 1, -1);
142
+ return t >= 0 ? t : e;
143
+ });
144
+ break;
145
+ case "Tab": q();
146
+ }
147
+ }, [
148
+ q,
149
+ E,
150
+ J,
151
+ V,
152
+ H
153
+ ]);
154
+ t(() => {
155
+ let e = F.current[E];
156
+ w && E >= 0 && e && e.scrollIntoView({
157
+ block: "nearest",
158
+ behavior: "smooth"
159
+ });
160
+ }, [w, E]);
161
+ let Z = h === "default" ? "" : `select--${h}`, ne = g ? "select--full-width" : "", re = z ? "select--labelled" : "", Q = z ? R : void 0, $ = y ?? b;
162
+ return /* @__PURE__ */ s("div", {
163
+ ref: j,
164
+ className: `select ${Z} ${ne} ${re} ${w ? "select--open" : ""} ${m ? "select--disabled" : ""} ${_}`,
165
+ children: [
166
+ z && /* @__PURE__ */ o("span", {
167
+ className: "select__label",
168
+ id: R,
169
+ children: p
170
+ }),
171
+ /* @__PURE__ */ s("button", {
172
+ ref: M,
173
+ type: "button",
174
+ className: "select__trigger",
175
+ onClick: () => {
176
+ w ? q() : K();
177
+ },
178
+ onKeyDown: Y,
179
+ onBlur: d,
180
+ disabled: m,
181
+ "aria-haspopup": "listbox",
182
+ "aria-expanded": w,
183
+ "aria-controls": w ? I : void 0,
184
+ "aria-activedescendant": w ? W : void 0,
185
+ "aria-label": b,
186
+ "aria-labelledby": Q,
187
+ "aria-describedby": x,
188
+ "aria-invalid": S || void 0,
189
+ children: [B ? /* @__PURE__ */ s("span", {
190
+ className: "select__value",
191
+ children: [B.icon && /* @__PURE__ */ o("span", {
192
+ className: "select__value-icon",
193
+ children: B.icon
194
+ }), /* @__PURE__ */ o("span", {
195
+ className: "select__value-label",
196
+ children: B.label
197
+ })]
198
+ }) : /* @__PURE__ */ o("span", {
199
+ className: "select__placeholder",
200
+ children: ee
201
+ }), /* @__PURE__ */ o("span", {
202
+ className: `select__chevron ${w ? "select__chevron--open" : ""}`,
203
+ children: /* @__PURE__ */ o("svg", {
204
+ width: "10",
205
+ height: "6",
206
+ viewBox: "0 0 10 6",
207
+ fill: "none",
208
+ xmlns: "http://www.w3.org/2000/svg",
209
+ children: /* @__PURE__ */ o("path", {
210
+ d: "M1 1L5 5L9 1",
211
+ stroke: "currentColor",
212
+ strokeWidth: "1.5",
213
+ strokeLinecap: "round",
214
+ strokeLinejoin: "round"
215
+ })
216
+ })
217
+ })]
218
+ }),
219
+ w && c(/* @__PURE__ */ s("div", {
220
+ ref: N,
221
+ className: "select__dropdown select__dropdown--portal",
222
+ style: {
223
+ position: "fixed",
224
+ top: `${String(A.top)}px`,
225
+ left: `${String(A.left)}px`,
226
+ width: `${String(A.width)}px`
227
+ },
228
+ children: [v && /* @__PURE__ */ o("div", {
229
+ className: "select__search",
230
+ children: /* @__PURE__ */ o("input", {
231
+ ref: P,
232
+ className: "select__search-input",
233
+ type: "search",
234
+ value: O,
235
+ onChange: (e) => k(e.currentTarget.value),
236
+ onKeyDown: X,
237
+ placeholder: y,
238
+ "aria-label": $,
239
+ "aria-labelledby": $ ? void 0 : Q,
240
+ "aria-controls": I,
241
+ "aria-activedescendant": W,
242
+ autoComplete: "off",
243
+ spellCheck: !1
244
+ })
245
+ }), /* @__PURE__ */ o("div", {
246
+ className: "select__options",
247
+ role: "listbox",
248
+ id: I,
249
+ "aria-label": b,
250
+ "aria-labelledby": Q,
251
+ children: V.length === 0 ? /* @__PURE__ */ o("div", {
252
+ className: "select__empty",
253
+ children: C
254
+ }) : V.map((e, t) => /* @__PURE__ */ s("div", {
255
+ id: U(t),
256
+ ref: (e) => {
257
+ F.current[t] = e;
258
+ },
259
+ className: `select__option ${e.value === l ? "select__option--selected" : ""} ${t === E ? "select__option--focused" : ""} ${e.disabled ? "select__option--disabled" : ""}`,
260
+ role: "option",
261
+ "aria-selected": e.value === l,
262
+ "aria-disabled": e.disabled || void 0,
263
+ "aria-label": e.description ? e.label + ". " + e.description : void 0,
264
+ onClick: (t) => {
265
+ J(e, t);
266
+ },
267
+ onMouseEnter: () => {
268
+ e.disabled || D(t);
269
+ },
270
+ children: [
271
+ e.icon && /* @__PURE__ */ o("span", {
272
+ className: "select__option-icon",
273
+ children: e.icon
274
+ }),
275
+ /* @__PURE__ */ s("div", {
276
+ className: "select__option-content",
277
+ children: [/* @__PURE__ */ o("span", {
278
+ className: "select__option-label",
279
+ children: e.label
280
+ }), e.description && /* @__PURE__ */ o("span", {
281
+ className: "select__option-description",
282
+ children: e.description
283
+ })]
284
+ }),
285
+ e.value === l && /* @__PURE__ */ o("span", {
286
+ className: "select__option-check",
287
+ children: /* @__PURE__ */ o("svg", {
288
+ width: "14",
289
+ height: "10",
290
+ viewBox: "0 0 14 10",
291
+ fill: "none",
292
+ xmlns: "http://www.w3.org/2000/svg",
293
+ children: /* @__PURE__ */ o("path", {
294
+ d: "M1 5L5 9L13 1",
295
+ stroke: "currentColor",
296
+ strokeWidth: "2",
297
+ strokeLinecap: "round",
298
+ strokeLinejoin: "round"
299
+ })
300
+ })
301
+ })
302
+ ]
303
+ }, e.value))
304
+ })]
305
+ }), document.body)
306
+ ]
307
+ });
308
+ }
309
+ //#endregion
310
+ export { l as Select };
311
+
312
+ //# sourceMappingURL=Select2.js.map
313
+ import "../../assets/components/Select/Select.css";
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select2.js","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["/**\n * Select Component\n *\n * Single-select listbox with an optional search filter, icons, descriptions and\n * a disabled-but-visible option state. The listbox is portalled, so a select\n * near the bottom of a scrolling panel is not clipped by it.\n *\n * Every string it renders arrives as a prop with an English default, so the\n * component resolves no locale key of its own.\n */\n\nimport { useState, useRef, useEffect, useCallback, useId, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport \"./Select.css\";\n\nexport interface SelectOption<T extends string = string> {\n value: T;\n label: string;\n description?: string;\n icon?: ReactNode;\n /** Keep an unavailable choice visible while preventing its selection. */\n disabled?: boolean;\n}\n\nexport interface SelectProps<T extends string = string> {\n value: T;\n onChange: (value: T) => void;\n onBlur?: () => void;\n options: SelectOption<T>[];\n /**\n * Field label rendered above the trigger, the way `TextInput` renders its\n * own. Names the trigger and the listbox through `aria-labelledby`, so a\n * caller that supplies it does not also need `aria-label`.\n */\n label?: ReactNode;\n placeholder?: string;\n disabled?: boolean;\n size?: \"small\" | \"default\" | \"medium\" | \"large\";\n fullWidth?: boolean;\n className?: string;\n searchable?: boolean;\n searchPlaceholder?: string;\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n invalid?: boolean;\n /**\n * Shown in place of the list when a search matches nothing. English default,\n * because this package cannot resolve a consumer's locale key: a product that\n * localises passes its own words.\n */\n noOptionsLabel?: string;\n}\n\nexport function Select<T extends string = string>({\n value,\n onChange,\n onBlur,\n options,\n label,\n placeholder = \"Select...\",\n disabled = false,\n size = \"default\",\n fullWidth = false,\n className = \"\",\n searchable = false,\n searchPlaceholder,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n invalid = false,\n noOptionsLabel = \"No options\",\n}: SelectProps<T>) {\n const [isOpen, setIsOpen] = useState(false);\n const [focusedIndex, setFocusedIndex] = useState(-1);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] = useState({\n top: 0,\n left: 0,\n width: 0,\n });\n\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const optionsRef = useRef<(HTMLDivElement | null)[]>([]);\n const listboxId = useId();\n const optionIdPrefix = useId();\n const labelId = useId();\n const hasLabel = label !== undefined && label !== null && label !== false;\n\n // Find selected option\n const selectedOption = options.find((opt) => opt.value === value);\n const visibleOptions = useMemo(() => {\n const normalizedQuery = searchQuery.trim().toLowerCase();\n if (!searchable || normalizedQuery.length === 0) return options;\n return options.filter((option) =>\n [option.label, option.value, option.description ?? \"\"].some((candidate) =>\n candidate.toLowerCase().includes(normalizedQuery),\n ),\n );\n }, [options, searchQuery, searchable]);\n\n const findEnabledIndex = useCallback(\n (start: number, step: 1 | -1): number => {\n for (\n let index = start;\n index >= 0 && index < visibleOptions.length;\n index += step\n ) {\n const option = visibleOptions[index];\n if (option && !option.disabled) return index;\n }\n return -1;\n },\n [visibleOptions],\n );\n\n // Generate unique option ID\n const getOptionId = (index: number) => `${optionIdPrefix}-option-${String(index)}`;\n\n // Get active descendant ID for screen readers\n const activeDescendantId = focusedIndex >= 0 ? getOptionId(focusedIndex) : undefined;\n\n // Calculate dropdown position\n const updateDropdownPosition = useCallback(() => {\n if (!triggerRef.current) return;\n\n const rect = triggerRef.current.getBoundingClientRect();\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width, // Use trigger width as minimum, but allow expansion\n });\n }, []);\n\n // Open dropdown\n const openDropdown = useCallback(() => {\n if (disabled) return;\n updateDropdownPosition();\n setIsOpen(true);\n const selectedIndex = visibleOptions.findIndex(\n (opt) => opt.value === value && !opt.disabled,\n );\n setFocusedIndex(selectedIndex !== -1 ? selectedIndex : findEnabledIndex(0, 1));\n }, [disabled, visibleOptions, value, updateDropdownPosition, findEnabledIndex]);\n\n // Close dropdown\n const closeDropdown = useCallback(() => {\n setIsOpen(false);\n setFocusedIndex(-1);\n setSearchQuery(\"\");\n triggerRef.current?.focus();\n }, []);\n\n // Handle option selection\n const selectOption = useCallback(\n (option: SelectOption<T>, e?: React.MouseEvent) => {\n if (e) {\n e.stopPropagation();\n e.preventDefault();\n }\n if (option.disabled) return;\n onChange(option.value);\n closeDropdown();\n },\n [onChange, closeDropdown],\n );\n\n // Handle click outside to close\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (!isOpen) return;\n const target = event.target as Node;\n // Check if click is outside both the container and the dropdown (which is portaled)\n const isOutsideContainer =\n containerRef.current && !containerRef.current.contains(target);\n const isOutsideDropdown =\n dropdownRef.current && !dropdownRef.current.contains(target);\n if (isOutsideContainer && isOutsideDropdown) {\n closeDropdown();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && isOpen) {\n closeDropdown();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen, closeDropdown]);\n\n // Handle window resize/scroll to update dropdown position\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePositionUpdate = () => {\n updateDropdownPosition();\n };\n\n window.addEventListener(\"resize\", handlePositionUpdate);\n window.addEventListener(\"scroll\", handlePositionUpdate, true);\n\n return () => {\n window.removeEventListener(\"resize\", handlePositionUpdate);\n window.removeEventListener(\"scroll\", handlePositionUpdate, true);\n };\n }, [isOpen, updateDropdownPosition]);\n\n useEffect(() => {\n if (isOpen && searchable) {\n searchInputRef.current?.focus();\n }\n }, [isOpen, searchable]);\n\n useEffect(() => {\n if (!isOpen || !searchable) return;\n optionsRef.current = [];\n const selectedIndex = visibleOptions.findIndex(\n (option) => option.value === value && !option.disabled,\n );\n setFocusedIndex(selectedIndex >= 0 ? selectedIndex : findEnabledIndex(0, 1));\n }, [isOpen, searchQuery, searchable, value, visibleOptions, findEnabledIndex]);\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) return;\n\n switch (e.key) {\n case \"Enter\":\n case \" \":\n e.preventDefault();\n if (isOpen) {\n const focusedOption = visibleOptions[focusedIndex];\n if (focusedOption) {\n selectOption(focusedOption);\n }\n } else {\n openDropdown();\n }\n break;\n\n case \"Escape\":\n e.preventDefault();\n if (isOpen) {\n closeDropdown();\n }\n break;\n\n case \"ArrowDown\":\n e.preventDefault();\n if (!isOpen) {\n openDropdown();\n } else {\n const nextIndex = findEnabledIndex(focusedIndex + 1, 1);\n if (nextIndex >= 0) setFocusedIndex(nextIndex);\n }\n break;\n\n case \"ArrowUp\":\n e.preventDefault();\n if (isOpen) {\n const previousIndex = findEnabledIndex(focusedIndex - 1, -1);\n if (previousIndex >= 0) setFocusedIndex(previousIndex);\n }\n break;\n\n case \"Tab\":\n if (isOpen) {\n closeDropdown();\n }\n break;\n }\n },\n [\n disabled,\n isOpen,\n focusedIndex,\n visibleOptions,\n findEnabledIndex,\n openDropdown,\n closeDropdown,\n selectOption,\n ],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case \"Enter\": {\n event.preventDefault();\n const focusedOption = visibleOptions[focusedIndex];\n if (focusedOption) selectOption(focusedOption);\n break;\n }\n case \"Escape\":\n event.preventDefault();\n event.stopPropagation();\n closeDropdown();\n break;\n case \"ArrowDown\":\n event.preventDefault();\n setFocusedIndex((current) => {\n const nextIndex = findEnabledIndex(current + 1, 1);\n return nextIndex >= 0 ? nextIndex : current;\n });\n break;\n case \"ArrowUp\":\n event.preventDefault();\n setFocusedIndex((current) => {\n const previousIndex = findEnabledIndex(current - 1, -1);\n return previousIndex >= 0 ? previousIndex : current;\n });\n break;\n case \"Tab\":\n closeDropdown();\n break;\n }\n },\n [closeDropdown, focusedIndex, selectOption, visibleOptions, findEnabledIndex],\n );\n\n // Scroll focused option into view\n useEffect(() => {\n const focusedElement = optionsRef.current[focusedIndex];\n if (isOpen && focusedIndex >= 0 && focusedElement) {\n focusedElement.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [isOpen, focusedIndex]);\n\n const sizeClass = size !== \"default\" ? `select--${size}` : \"\";\n const widthClass = fullWidth ? \"select--full-width\" : \"\";\n const labelledClass = hasLabel ? \"select--labelled\" : \"\";\n // aria-labelledby wins over aria-label in the accessible-name calculation,\n // so a caller may pass either; the rendered label is preferred when present.\n const labelledBy = hasLabel ? labelId : undefined;\n const searchFieldLabel = searchPlaceholder ?? ariaLabel;\n\n return (\n <div\n ref={containerRef}\n className={`select ${sizeClass} ${widthClass} ${labelledClass} ${isOpen ? \"select--open\" : \"\"} ${disabled ? \"select--disabled\" : \"\"} ${className}`}\n >\n {hasLabel && (\n <span className=\"select__label\" id={labelId}>\n {label}\n </span>\n )}\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"select__trigger\"\n onClick={() => {\n if (isOpen) {\n closeDropdown();\n } else {\n openDropdown();\n }\n }}\n onKeyDown={handleKeyDown}\n onBlur={onBlur}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={isOpen ? activeDescendantId : undefined}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={invalid || undefined}\n >\n {selectedOption ? (\n <span className=\"select__value\">\n {selectedOption.icon && (\n <span className=\"select__value-icon\">{selectedOption.icon}</span>\n )}\n <span className=\"select__value-label\">{selectedOption.label}</span>\n </span>\n ) : (\n <span className=\"select__placeholder\">{placeholder}</span>\n )}\n <span className={`select__chevron ${isOpen ? \"select__chevron--open\" : \"\"}`}>\n <svg\n width=\"10\"\n height=\"6\"\n viewBox=\"0 0 10 6\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 1L5 5L9 1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n\n {isOpen &&\n createPortal(\n <div\n ref={dropdownRef}\n className=\"select__dropdown select__dropdown--portal\"\n style={{\n position: \"fixed\",\n top: `${String(dropdownPosition.top)}px`,\n left: `${String(dropdownPosition.left)}px`,\n width: `${String(dropdownPosition.width)}px`,\n }}\n >\n {searchable && (\n <div className=\"select__search\">\n <input\n ref={searchInputRef}\n className=\"select__search-input\"\n type=\"search\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.currentTarget.value)}\n onKeyDown={handleSearchKeyDown}\n placeholder={searchPlaceholder}\n aria-label={searchFieldLabel}\n aria-labelledby={searchFieldLabel ? undefined : labelledBy}\n aria-controls={listboxId}\n aria-activedescendant={activeDescendantId}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n )}\n <div\n className=\"select__options\"\n role=\"listbox\"\n id={listboxId}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n >\n {visibleOptions.length === 0 ? (\n <div className=\"select__empty\">{noOptionsLabel}</div>\n ) : (\n visibleOptions.map((option, index) => (\n <div\n key={option.value}\n id={getOptionId(index)}\n ref={(el) => {\n optionsRef.current[index] = el;\n }}\n className={`select__option ${\n option.value === value ? \"select__option--selected\" : \"\"\n } ${index === focusedIndex ? \"select__option--focused\" : \"\"} ${option.disabled ? \"select__option--disabled\" : \"\"}`}\n role=\"option\"\n aria-selected={option.value === value}\n aria-disabled={option.disabled || undefined}\n aria-label={\n option.description\n ? option.label + \". \" + option.description\n : undefined\n }\n onClick={(e) => {\n selectOption(option, e);\n }}\n onMouseEnter={() => {\n if (!option.disabled) setFocusedIndex(index);\n }}\n >\n {option.icon && (\n <span className=\"select__option-icon\">{option.icon}</span>\n )}\n <div className=\"select__option-content\">\n <span className=\"select__option-label\">{option.label}</span>\n {option.description && (\n <span className=\"select__option-description\">\n {option.description}\n </span>\n )}\n </div>\n {option.value === value && (\n <span className=\"select__option-check\">\n <svg\n width=\"14\"\n height=\"10\"\n viewBox=\"0 0 14 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 5L5 9L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n )}\n </div>\n ))\n )}\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { Select } from './Select';
2
+ export type { SelectOption, SelectProps } from './Select';
@@ -0,0 +1,2 @@
1
+ import { Select as e } from "./Select2.js";
2
+ export { e as Select };
@@ -11,6 +11,16 @@ export interface SkeletonProps {
11
11
  testId?: string;
12
12
  /** Accessible label announced while the skeleton is visible. Default: "Loading" */
13
13
  loadingLabel?: string;
14
+ /**
15
+ * Render as decoration: `aria-hidden`, with no role, no `aria-busy` and no
16
+ * label.
17
+ *
18
+ * For a shape inside a composite that announces the wait itself. `role="status"`
19
+ * is an implicit polite live region, so a composite that fills its own region
20
+ * with named primitives mounts one live region per shape and announces the
21
+ * same wait once per shape.
22
+ */
23
+ decorative?: boolean;
14
24
  }
15
25
  /**
16
26
  * Skeleton provides a loading placeholder with shimmer animation.
@@ -21,5 +31,5 @@ export interface SkeletonProps {
21
31
  * - Multiple shape variants
22
32
  * - Accessible via aria-busy and aria-label
23
33
  */
24
- export declare function Skeleton({ width, height, variant, className, testId, loadingLabel, }: SkeletonProps): import("react").JSX.Element;
34
+ export declare function Skeleton({ width, height, variant, className, testId, loadingLabel, decorative, }: SkeletonProps): import("react").JSX.Element;
25
35
  export default Skeleton;
@@ -1,21 +1,23 @@
1
1
  /* empty css */
2
2
  import { jsx as e } from "react/jsx-runtime";
3
3
  //#region src/components/Skeleton/Skeleton.tsx
4
- function t({ width: t = "100%", height: n = "20px", variant: r = "rect", className: i = "", testId: a, loadingLabel: o = "Loading" }) {
5
- let s = [
4
+ function t({ width: t = "100%", height: n = "20px", variant: r = "rect", className: i = "", testId: a, loadingLabel: o = "Loading", decorative: s = !1 }) {
5
+ let c = [
6
6
  "skeleton",
7
7
  `skeleton--${r}`,
8
8
  i
9
9
  ].filter(Boolean).join(" ");
10
10
  return /* @__PURE__ */ e("div", {
11
- className: s,
11
+ className: c,
12
12
  style: {
13
13
  width: t,
14
14
  height: n
15
15
  },
16
- role: "status",
17
- "aria-busy": "true",
18
- "aria-label": o,
16
+ ...s ? { "aria-hidden": !0 } : {
17
+ role: "status",
18
+ "aria-busy": !0,
19
+ "aria-label": o
20
+ },
19
21
  "data-testid": a,
20
22
  children: /* @__PURE__ */ e("span", { className: "skeleton__shimmer" })
21
23
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Skeleton2.js","names":[],"sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["/**\n * Skeleton Component\n *\n * Base skeleton component for loading states.\n * Provides a shimmer animation effect that respects prefers-reduced-motion.\n *\n * @example\n * // Basic usage\n * <Skeleton width=\"100%\" height=\"20px\" />\n *\n * @example\n * // Circle skeleton\n * <Skeleton width=\"40px\" height=\"40px\" variant=\"circle\" />\n */\n\nimport \"./Skeleton.css\";\n\nexport interface SkeletonProps {\n /** Width of the skeleton (CSS value) */\n width?: string;\n /** Height of the skeleton (CSS value) */\n height?: string;\n /** Visual variant */\n variant?: \"rect\" | \"circle\" | \"text\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the skeleton is visible. Default: \"Loading\" */\n loadingLabel?: string;\n}\n\n/**\n * Skeleton provides a loading placeholder with shimmer animation.\n *\n * Features:\n * - Shimmer effect using CSS animation\n * - Reduced motion preference support\n * - Multiple shape variants\n * - Accessible via aria-busy and aria-label\n */\nexport function Skeleton({\n width = \"100%\",\n height = \"20px\",\n variant = \"rect\",\n className = \"\",\n testId,\n loadingLabel = \"Loading\",\n}: SkeletonProps) {\n const classNames = [\"skeleton\", `skeleton--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ width, height }}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel}\n data-testid={testId}\n >\n <span className=\"skeleton__shimmer\" />\n </div>\n );\n}\n\nexport default Skeleton;\n"],"mappings":";;;AAyCA,SAAgB,EAAS,EACvB,WAAQ,QACR,YAAS,QACT,aAAU,QACV,eAAY,IACZ,WACA,kBAAe,aACC;CAChB,IAAM,IAAa;EAAC;EAAY,aAAa;EAAW;CAAS,CAAC,CAC/D,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO;GAAE;GAAO;EAAO;EACvB,MAAK;EACL,aAAU;EACV,cAAY;EACZ,eAAa;EAEb,UAAA,kBAAC,QAAD,EAAM,WAAU,oBAAqB,CAAA;CAClC,CAAA;AAET"}
1
+ {"version":3,"file":"Skeleton2.js","names":[],"sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["/**\n * Skeleton Component\n *\n * Base skeleton component for loading states.\n * Provides a shimmer animation effect that respects prefers-reduced-motion.\n *\n * @example\n * // Basic usage\n * <Skeleton width=\"100%\" height=\"20px\" />\n *\n * @example\n * // Circle skeleton\n * <Skeleton width=\"40px\" height=\"40px\" variant=\"circle\" />\n */\n\nimport \"./Skeleton.css\";\n\nexport interface SkeletonProps {\n /** Width of the skeleton (CSS value) */\n width?: string;\n /** Height of the skeleton (CSS value) */\n height?: string;\n /** Visual variant */\n variant?: \"rect\" | \"circle\" | \"text\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the skeleton is visible. Default: \"Loading\" */\n loadingLabel?: string;\n /**\n * Render as decoration: `aria-hidden`, with no role, no `aria-busy` and no\n * label.\n *\n * For a shape inside a composite that announces the wait itself. `role=\"status\"`\n * is an implicit polite live region, so a composite that fills its own region\n * with named primitives mounts one live region per shape and announces the\n * same wait once per shape.\n */\n decorative?: boolean;\n}\n\n/**\n * Skeleton provides a loading placeholder with shimmer animation.\n *\n * Features:\n * - Shimmer effect using CSS animation\n * - Reduced motion preference support\n * - Multiple shape variants\n * - Accessible via aria-busy and aria-label\n */\nexport function Skeleton({\n width = \"100%\",\n height = \"20px\",\n variant = \"rect\",\n className = \"\",\n testId,\n loadingLabel = \"Loading\",\n decorative = false,\n}: SkeletonProps) {\n const classNames = [\"skeleton\", `skeleton--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n // A decorative shape is one of several inside a composite that already\n // announces the wait. It keeps its size and its shimmer and leaves the\n // accessibility tree, so a card built from seven of these is one live region\n // rather than seven.\n const announcement = decorative\n ? ({ \"aria-hidden\": true } as const)\n : ({\n role: \"status\",\n \"aria-busy\": true,\n \"aria-label\": loadingLabel,\n } as const);\n\n return (\n <div\n className={classNames}\n style={{ width, height }}\n {...announcement}\n data-testid={testId}\n >\n <span className=\"skeleton__shimmer\" />\n </div>\n );\n}\n\nexport default Skeleton;\n"],"mappings":";;;AAmDA,SAAgB,EAAS,EACvB,WAAQ,QACR,YAAS,QACT,aAAU,QACV,eAAY,IACZ,WACA,kBAAe,WACf,gBAAa,MACG;CAChB,IAAM,IAAa;EAAC;EAAY,aAAa;EAAW;CAAS,CAAC,CAC/D,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAcX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO;GAAE;GAAO;EAAO;EACvB,GAZiB,IAChB,EAAE,eAAe,GAAK,IACtB;GACC,MAAM;GACN,aAAa;GACb,cAAc;EAChB;EAOA,eAAa;EAEb,UAAA,kBAAC,QAAD,EAAM,WAAU,oBAAqB,CAAA;CAClC,CAAA;AAET"}
@@ -5,6 +5,8 @@ export interface SkeletonCardProps {
5
5
  className?: string;
6
6
  /** Test ID for testing */
7
7
  testId?: string;
8
+ /** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
9
+ loadingLabel?: string;
8
10
  }
9
11
  /**
10
12
  * SkeletonCard provides a loading placeholder for card components.
@@ -14,5 +16,5 @@ export interface SkeletonCardProps {
14
16
  * - compact: Smaller card with reduced padding
15
17
  * - stat: Statistics card layout
16
18
  */
17
- export declare function SkeletonCard({ variant, className, testId, }: SkeletonCardProps): import("react").JSX.Element;
19
+ export declare function SkeletonCard({ variant, className, testId, loadingLabel, }: SkeletonCardProps): import("react").JSX.Element;
18
20
  export default SkeletonCard;