@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,76 +1,94 @@
1
1
  /* empty css */
2
- import { useCallback as e, useEffect as t, useRef as n, useState as r } from "react";
3
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
2
+ import { useCallback as e, useEffect as t, useId as n, useRef as r, useState as i } from "react";
3
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
4
4
  //#region src/components/Drawer/Drawer.tsx
5
- var o = {
5
+ var s = {
6
6
  narrow: "400px",
7
7
  medium: "520px",
8
8
  wide: "900px"
9
9
  };
10
- function s({ isOpen: s, onClose: c, title: l, subtitle: u, width: d = "medium", children: f, footer: p, className: m = "", ariaLabelledBy: h, ariaDescribedBy: g, closeLabel: _ = "Close" }) {
11
- let v = n(null), y = n(null), b = n(null), [x, S] = r(!1), C = n(!1);
10
+ function c({ isOpen: c, onClose: l, title: u, subtitle: d, width: f = "medium", children: p, footer: m, className: h = "", ariaLabelledBy: g, ariaDescribedBy: _, closeLabel: v = "Close", preventDismiss: y = !1, onDismissAttempt: b }) {
11
+ let x = r(null), S = n(), [C, w] = i(!1), T = r(y);
12
+ T.current = y;
13
+ let E = r(b);
14
+ E.current = b;
15
+ let D = r(l);
16
+ D.current = l;
17
+ let O = e(() => {
18
+ D.current();
19
+ }, []), k = e(() => T.current ? (w(!0), E.current?.(), !0) : !1, []), A = e((e) => {
20
+ e.animationName === "drawer-shake" && w(!1);
21
+ }, []), j = r(null), M = r(null), [N, P] = i(!1), F = r(!1);
12
22
  t(() => {
13
- s && !C.current ? (C.current = !0, requestAnimationFrame(() => {
23
+ c && !F.current ? (F.current = !0, requestAnimationFrame(() => {
14
24
  requestAnimationFrame(() => {
15
- S(!0);
25
+ P(!0);
16
26
  });
17
- })) : S(!!s);
18
- }, [s]);
19
- let w = s && x, T = d in o ? o[d] : d, E = h || "drawer-title", D = g || (u ? "drawer-subtitle" : void 0);
27
+ })) : P(!!c);
28
+ }, [c]);
29
+ let I = c && N, L = f in s ? s[f] : f, R = g ?? `${S}-title`, z = _ ?? (d ? `${S}-subtitle` : void 0);
20
30
  t(() => {
21
- if (!s) return;
22
- y.current = document.activeElement;
23
- let e = v.current;
31
+ if (!I) return;
32
+ j.current = document.activeElement;
33
+ let e = x.current;
24
34
  if (!e) return;
25
- requestAnimationFrame(() => {
26
- b.current?.focus();
27
- });
35
+ M.current?.focus();
28
36
  let t = e.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])"), n = t[0], r = t[t.length - 1], i = (e) => {
29
37
  if (e.key === "Escape") {
30
- c();
38
+ if (k()) return;
39
+ O();
31
40
  return;
32
41
  }
33
42
  e.key === "Tab" && (e.shiftKey ? document.activeElement === n && (e.preventDefault(), r?.focus()) : document.activeElement === r && (e.preventDefault(), n?.focus()));
34
43
  };
35
44
  return e.addEventListener("keydown", i), () => {
36
- e.removeEventListener("keydown", i), y.current && y.current.focus();
45
+ e.removeEventListener("keydown", i), j.current && j.current.focus();
37
46
  };
38
- }, [s, c]);
39
- let O = e((e) => {
40
- e.target === e.currentTarget && c();
41
- }, [c]);
42
- return /* @__PURE__ */ i("div", {
43
- className: `drawer__backdrop ${w ? "drawer__backdrop--open" : ""}`,
44
- onClick: O,
47
+ }, [
48
+ I,
49
+ O,
50
+ k
51
+ ]);
52
+ let B = e((e) => {
53
+ if (e.target === e.currentTarget) {
54
+ if (k()) return;
55
+ O();
56
+ }
57
+ }, [O, k]);
58
+ return /* @__PURE__ */ a("div", {
59
+ className: `drawer__backdrop ${I ? "drawer__backdrop--open" : ""}`,
60
+ onClick: B,
45
61
  role: "presentation",
46
- "aria-hidden": !s,
47
- children: /* @__PURE__ */ a("aside", {
48
- ref: v,
49
- className: `drawer ${w ? "drawer--open" : ""} ${m}`,
62
+ "aria-hidden": !c,
63
+ inert: !c,
64
+ children: /* @__PURE__ */ o("aside", {
65
+ ref: x,
66
+ className: `drawer ${I ? "drawer--open" : ""} ${C ? "drawer--shaking" : ""} ${h}`,
50
67
  style: {
51
- width: T,
68
+ width: L,
52
69
  maxWidth: "100vw"
53
70
  },
54
71
  role: "dialog",
55
72
  "aria-modal": "true",
56
- "aria-labelledby": E,
57
- "aria-describedby": D,
73
+ "aria-labelledby": R,
74
+ "aria-describedby": z,
75
+ onAnimationEnd: A,
58
76
  children: [
59
- /* @__PURE__ */ a("header", {
77
+ /* @__PURE__ */ o("header", {
60
78
  className: "drawer__header",
61
- children: [/* @__PURE__ */ a("div", {
79
+ children: [/* @__PURE__ */ o("div", {
62
80
  className: "drawer__title-row",
63
- children: [/* @__PURE__ */ i("h2", {
64
- id: E,
81
+ children: [/* @__PURE__ */ a("h2", {
82
+ id: R,
65
83
  className: "drawer__title",
66
- children: l
67
- }), /* @__PURE__ */ i("button", {
68
- ref: b,
84
+ children: u
85
+ }), /* @__PURE__ */ a("button", {
86
+ ref: M,
69
87
  type: "button",
70
88
  className: "drawer__close-btn",
71
- onClick: c,
72
- "aria-label": _,
73
- children: /* @__PURE__ */ a("svg", {
89
+ onClick: O,
90
+ "aria-label": v,
91
+ children: /* @__PURE__ */ o("svg", {
74
92
  width: "20",
75
93
  height: "20",
76
94
  viewBox: "0 0 24 24",
@@ -79,29 +97,29 @@ function s({ isOpen: s, onClose: c, title: l, subtitle: u, width: d = "medium",
79
97
  strokeWidth: "2",
80
98
  strokeLinecap: "round",
81
99
  strokeLinejoin: "round",
82
- children: [/* @__PURE__ */ i("path", { d: "M18 6L6 18" }), /* @__PURE__ */ i("path", { d: "M6 6l12 12" })]
100
+ children: [/* @__PURE__ */ a("path", { d: "M18 6L6 18" }), /* @__PURE__ */ a("path", { d: "M6 6l12 12" })]
83
101
  })
84
102
  })]
85
- }), u && /* @__PURE__ */ i("p", {
86
- id: D,
103
+ }), d && /* @__PURE__ */ a("p", {
104
+ id: z,
87
105
  className: "drawer__subtitle",
88
- children: u
106
+ children: d
89
107
  })]
90
108
  }),
91
- /* @__PURE__ */ i("div", {
109
+ /* @__PURE__ */ a("div", {
92
110
  className: "drawer__content",
93
- children: f
111
+ children: p
94
112
  }),
95
- p && /* @__PURE__ */ i("footer", {
113
+ m && /* @__PURE__ */ a("footer", {
96
114
  className: "drawer__footer",
97
- children: p
115
+ children: m
98
116
  })
99
117
  ]
100
118
  })
101
119
  });
102
120
  }
103
121
  //#endregion
104
- export { s as Drawer };
122
+ export { c as Drawer };
105
123
 
106
124
  //# sourceMappingURL=Drawer2.js.map
107
125
  import "../../assets/components/Drawer/Drawer.css";
@@ -1 +1 @@
1
- {"version":3,"file":"Drawer2.js","names":[],"sources":["../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["/**\n * Drawer Component\n *\n * A reusable right-side drawer panel with backdrop, animations, and accessibility features.\n * Consolidates common patterns from all drawer implementations.\n */\n\nimport { useEffect, useRef, useCallback, useState } from \"react\";\nimport \"./Drawer.css\";\n\nexport interface DrawerProps {\n /** Whether the drawer is open */\n isOpen: boolean;\n /** Callback when drawer should close */\n onClose: () => void;\n /** Drawer title */\n title: React.ReactNode;\n /** Optional subtitle */\n subtitle?: React.ReactNode;\n /** Drawer width preset or custom CSS width value */\n width?: \"narrow\" | \"medium\" | \"wide\" | (string & Record<never, never>);\n /** Drawer content */\n children: React.ReactNode;\n /** Optional footer content */\n footer?: React.ReactNode;\n /** Additional CSS class for drawer panel */\n className?: string;\n /** ARIA labelledby ID (defaults to internal title ID) */\n ariaLabelledBy?: string;\n /** ARIA describedby ID (defaults to internal subtitle ID if subtitle exists) */\n ariaDescribedBy?: string;\n /** Accessible label for the close button. Default: \"Close\" */\n closeLabel?: string;\n}\n\nconst WIDTH_PRESETS = {\n narrow: \"400px\",\n medium: \"520px\",\n wide: \"900px\",\n};\n\nexport function Drawer({\n isOpen,\n onClose,\n title,\n subtitle,\n width = \"medium\",\n children,\n footer,\n className = \"\",\n ariaLabelledBy,\n ariaDescribedBy,\n closeLabel = \"Close\",\n}: DrawerProps) {\n const drawerRef = useRef<HTMLDivElement>(null);\n const previousActiveElementRef = useRef<HTMLElement | null>(null);\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n // Track if this is the first render to enable animation on initial open\n // Without this, when the component mounts with isOpen=true, there's no\n // transition because CSS transitions only apply to state changes, not initial renders.\n const [shouldAnimate, setShouldAnimate] = useState(false);\n const hasInitialized = useRef(false);\n\n useEffect(() => {\n if (isOpen && !hasInitialized.current) {\n // First time opening - delay adding open class to trigger animation\n hasInitialized.current = true;\n // Use double rAF to ensure the closed state is painted first\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setShouldAnimate(true);\n });\n });\n } else if (isOpen) {\n setShouldAnimate(true);\n } else {\n setShouldAnimate(false);\n }\n }, [isOpen]);\n\n // Compute the actual open state for CSS classes\n const isVisuallyOpen = isOpen && shouldAnimate;\n\n // Compute width value\n const widthValue =\n width in WIDTH_PRESETS ? WIDTH_PRESETS[width as keyof typeof WIDTH_PRESETS] : width;\n\n // Internal IDs for ARIA\n const titleId = ariaLabelledBy || \"drawer-title\";\n const subtitleId = ariaDescribedBy || (subtitle ? \"drawer-subtitle\" : undefined);\n\n // Focus management and trap\n useEffect(() => {\n if (!isOpen) return;\n\n // Store previously focused element\n previousActiveElementRef.current = document.activeElement as HTMLElement;\n\n const drawer = drawerRef.current;\n if (!drawer) return;\n\n // Focus close button when drawer opens\n requestAnimationFrame(() => {\n closeButtonRef.current?.focus();\n });\n\n // Setup focus trap\n const focusableElements = drawer.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n );\n\n const firstFocusable = focusableElements[0];\n const lastFocusable = focusableElements[focusableElements.length - 1];\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Escape to close\n if (e.key === \"Escape\") {\n onClose();\n return;\n }\n\n // Tab key focus trap\n if (e.key === \"Tab\") {\n if (e.shiftKey) {\n // Shift + Tab\n if (document.activeElement === firstFocusable) {\n e.preventDefault();\n lastFocusable?.focus();\n }\n } else {\n // Tab\n if (document.activeElement === lastFocusable) {\n e.preventDefault();\n firstFocusable?.focus();\n }\n }\n }\n };\n\n drawer.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n drawer.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus when drawer closes\n if (previousActiveElementRef.current) {\n previousActiveElementRef.current.focus();\n }\n };\n }, [isOpen, onClose]);\n\n // Handle backdrop click\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n },\n [onClose],\n );\n\n return (\n <div\n className={`drawer__backdrop ${isVisuallyOpen ? \"drawer__backdrop--open\" : \"\"}`}\n onClick={handleBackdropClick}\n role=\"presentation\"\n aria-hidden={!isOpen}\n >\n <aside\n ref={drawerRef}\n className={`drawer ${isVisuallyOpen ? \"drawer--open\" : \"\"} ${className}`}\n style={{ width: widthValue, maxWidth: \"100vw\" }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={subtitleId}\n >\n {/* Header */}\n <header className=\"drawer__header\">\n <div className=\"drawer__title-row\">\n <h2 id={titleId} className=\"drawer__title\">\n {title}\n </h2>\n <button\n ref={closeButtonRef}\n type=\"button\"\n className=\"drawer__close-btn\"\n onClick={onClose}\n aria-label={closeLabel}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 6L6 18\" />\n <path d=\"M6 6l12 12\" />\n </svg>\n </button>\n </div>\n {subtitle && (\n <p id={subtitleId} className=\"drawer__subtitle\">\n {subtitle}\n </p>\n )}\n </header>\n\n {/* Content */}\n <div className=\"drawer__content\">{children}</div>\n\n {/* Footer */}\n {footer && <footer className=\"drawer__footer\">{footer}</footer>}\n </aside>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Drawer2.js","names":[],"sources":["../../../src/components/Drawer/Drawer.tsx"],"sourcesContent":["/**\n * Drawer Component\n *\n * A reusable right-side drawer panel with backdrop, animations, and accessibility features.\n * Consolidates common patterns from all drawer implementations.\n */\n\nimport { useEffect, useRef, useCallback, useId, useState } from \"react\";\nimport \"./Drawer.css\";\n\nexport interface DrawerProps {\n /** Whether the drawer is open */\n isOpen: boolean;\n /** Callback when drawer should close */\n onClose: () => void;\n /** Drawer title */\n title: React.ReactNode;\n /** Optional subtitle */\n subtitle?: React.ReactNode;\n /** Drawer width preset or custom CSS width value */\n width?: \"narrow\" | \"medium\" | \"wide\" | (string & Record<never, never>);\n /** Drawer content */\n children: React.ReactNode;\n /** Optional footer content */\n footer?: React.ReactNode;\n /** Additional CSS class for drawer panel */\n className?: string;\n /** ARIA labelledby ID (defaults to internal title ID) */\n ariaLabelledBy?: string;\n /** ARIA describedby ID (defaults to internal subtitle ID if subtitle exists) */\n ariaDescribedBy?: string;\n /** Accessible label for the close button. Default: \"Close\" */\n closeLabel?: string;\n /**\n * Refuse dismissal by Escape or a backdrop click, shaking the panel instead.\n * The close button and any footer control still call `onClose` directly, so\n * route those through the same guard when they also need confirming.\n */\n preventDismiss?: boolean;\n /**\n * Called when `preventDismiss` blocked a dismissal, so the consumer can offer\n * an explicit way out (a discard confirmation, for instance).\n */\n onDismissAttempt?: () => void;\n}\n\nconst WIDTH_PRESETS = {\n narrow: \"400px\",\n medium: \"520px\",\n wide: \"900px\",\n};\n\nexport function Drawer({\n isOpen,\n onClose,\n title,\n subtitle,\n width = \"medium\",\n children,\n footer,\n className = \"\",\n ariaLabelledBy,\n ariaDescribedBy,\n closeLabel = \"Close\",\n preventDismiss = false,\n onDismissAttempt,\n}: DrawerProps) {\n const drawerRef = useRef<HTMLDivElement>(null);\n const generatedId = useId();\n\n const [isShaking, setIsShaking] = useState(false);\n\n // Read the guard through refs so `blockDismiss` keeps a stable identity. The\n // focus-management effect depends on it, and if the identity changed the\n // moment the consumer marks the drawer dirty, that effect would re-run on the\n // first keystroke and steal focus from the field being typed into.\n const preventDismissRef = useRef(preventDismiss);\n preventDismissRef.current = preventDismiss;\n const onDismissAttemptRef = useRef(onDismissAttempt);\n onDismissAttemptRef.current = onDismissAttempt;\n const onCloseRef = useRef(onClose);\n onCloseRef.current = onClose;\n\n const requestClose = useCallback(() => {\n onCloseRef.current();\n }, []);\n\n /** Blocks a dismissal when the guard is on. Returns whether it blocked. */\n const blockDismiss = useCallback(() => {\n if (!preventDismissRef.current) return false;\n setIsShaking(true);\n onDismissAttemptRef.current?.();\n return true;\n }, []);\n\n // Guarded on the animation name so an unrelated animation on the panel does\n // not clear the flag early.\n const handleAnimationEnd = useCallback((e: React.AnimationEvent) => {\n if (e.animationName === \"drawer-shake\") setIsShaking(false);\n }, []);\n const previousActiveElementRef = useRef<HTMLElement | null>(null);\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n // Track if this is the first render to enable animation on initial open\n // Without this, when the component mounts with isOpen=true, there's no\n // transition because CSS transitions only apply to state changes, not initial renders.\n const [shouldAnimate, setShouldAnimate] = useState(false);\n const hasInitialized = useRef(false);\n\n useEffect(() => {\n if (isOpen && !hasInitialized.current) {\n // First time opening - delay adding open class to trigger animation\n hasInitialized.current = true;\n // Use double rAF to ensure the closed state is painted first\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n setShouldAnimate(true);\n });\n });\n } else if (isOpen) {\n setShouldAnimate(true);\n } else {\n setShouldAnimate(false);\n }\n }, [isOpen]);\n\n // Compute the actual open state for CSS classes\n const isVisuallyOpen = isOpen && shouldAnimate;\n\n // Compute width value\n const widthValue =\n width in WIDTH_PRESETS ? WIDTH_PRESETS[width as keyof typeof WIDTH_PRESETS] : width;\n\n // Internal IDs for ARIA\n const titleId = ariaLabelledBy ?? `${generatedId}-title`;\n const subtitleId =\n ariaDescribedBy ?? (subtitle ? `${generatedId}-subtitle` : undefined);\n\n // Focus management and trap\n useEffect(() => {\n // Wait until the open classes have committed so focus never enters a\n // backdrop that is still hidden and non-interactive.\n if (!isVisuallyOpen) return;\n\n // Store previously focused element\n previousActiveElementRef.current = document.activeElement as HTMLElement;\n\n const drawer = drawerRef.current;\n if (!drawer) return;\n\n // Focus close button when drawer opens\n closeButtonRef.current?.focus();\n\n // Setup focus trap\n const focusableElements = drawer.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n );\n\n const firstFocusable = focusableElements[0];\n const lastFocusable = focusableElements[focusableElements.length - 1];\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Escape to close, unless the guard blocks it\n if (e.key === \"Escape\") {\n if (blockDismiss()) return;\n requestClose();\n return;\n }\n\n // Tab key focus trap\n if (e.key === \"Tab\") {\n if (e.shiftKey) {\n // Shift + Tab\n if (document.activeElement === firstFocusable) {\n e.preventDefault();\n lastFocusable?.focus();\n }\n } else {\n // Tab\n if (document.activeElement === lastFocusable) {\n e.preventDefault();\n firstFocusable?.focus();\n }\n }\n }\n };\n\n drawer.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n drawer.removeEventListener(\"keydown\", handleKeyDown);\n // Restore focus when drawer closes\n if (previousActiveElementRef.current) {\n previousActiveElementRef.current.focus();\n }\n };\n }, [isVisuallyOpen, requestClose, blockDismiss]);\n\n // Handle backdrop click\n const handleBackdropClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n if (blockDismiss()) return;\n requestClose();\n }\n },\n [requestClose, blockDismiss],\n );\n\n return (\n <div\n className={`drawer__backdrop ${isVisuallyOpen ? \"drawer__backdrop--open\" : \"\"}`}\n onClick={handleBackdropClick}\n role=\"presentation\"\n aria-hidden={!isOpen}\n // `aria-hidden` takes the closed drawer out of the accessibility tree but\n // leaves its focusable children in the tab sequence, so a keyboard user\n // tabs into an invisible form. `inert` removes both.\n inert={!isOpen}\n >\n <aside\n ref={drawerRef}\n className={`drawer ${isVisuallyOpen ? \"drawer--open\" : \"\"} ${\n isShaking ? \"drawer--shaking\" : \"\"\n } ${className}`}\n style={{ width: widthValue, maxWidth: \"100vw\" }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={subtitleId}\n onAnimationEnd={handleAnimationEnd}\n >\n {/* Header */}\n <header className=\"drawer__header\">\n <div className=\"drawer__title-row\">\n <h2 id={titleId} className=\"drawer__title\">\n {title}\n </h2>\n <button\n ref={closeButtonRef}\n type=\"button\"\n className=\"drawer__close-btn\"\n onClick={requestClose}\n aria-label={closeLabel}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M18 6L6 18\" />\n <path d=\"M6 6l12 12\" />\n </svg>\n </button>\n </div>\n {subtitle && (\n <p id={subtitleId} className=\"drawer__subtitle\">\n {subtitle}\n </p>\n )}\n </header>\n\n {/* Content */}\n <div className=\"drawer__content\">{children}</div>\n\n {/* Footer */}\n {footer && <footer className=\"drawer__footer\">{footer}</footer>}\n </aside>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { ReactNode } from 'react';
2
- export type IllustrationType = "chat" | "models" | "creations" | "text" | "benchmark" | "logs" | "statistics" | "error" | "schedule" | "generic";
3
2
  export interface EmptyStateAction {
4
3
  label: string;
5
4
  onClick: () => void;
@@ -10,8 +9,16 @@ export interface EmptyStateSecondaryAction {
10
9
  onClick?: () => void;
11
10
  }
12
11
  export interface EmptyStateProps {
13
- /** Type of illustration to display */
14
- illustration: IllustrationType;
12
+ /**
13
+ * The drawing shown above the text.
14
+ *
15
+ * This used to be one of ten names: chat, models, creations, benchmark,
16
+ * logs, statistics, schedule and so on, each resolving to an SVG shipped
17
+ * inside this package. Those names are one product's information
18
+ * architecture, and no other consumer has a "creations" screen to draw for.
19
+ * A consumer passes its own artwork and keeps its own vocabulary.
20
+ */
21
+ illustration?: ReactNode;
15
22
  /** Main heading */
16
23
  title: string;
17
24
  /** Descriptive text */
@@ -1,79 +1,62 @@
1
1
  import { Button as e } from "../Button/Button2.js";
2
- import { BenchmarkIllustration as t, ChatIllustration as n, CreationsIllustration as r, ErrorIllustration as i, GenericIllustration as a, LogsIllustration as o, ModelsIllustration as s, ScheduleIllustration as c, StatisticsIllustration as l, TextIllustration as u } from "./illustrations.js";
3
2
  /* empty css */
4
- import { memo as d, useCallback as f, useMemo as p } from "react";
5
- import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
3
+ import { memo as t, useCallback as n, useMemo as r } from "react";
4
+ import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
6
5
  //#region src/components/EmptyState/EmptyState.tsx
7
- var _ = {
8
- chat: n,
9
- models: s,
10
- creations: r,
11
- text: u,
12
- benchmark: t,
13
- logs: o,
14
- statistics: l,
15
- error: i,
16
- schedule: c,
17
- generic: a
18
- };
19
- function v({ illustration: t, title: n, description: r, primaryAction: i, secondaryAction: a, children: o, className: s = "", showIllustration: c = !0 }) {
20
- let l = i?.onClick, u = a?.onClick, d = f(() => {
21
- l?.();
22
- }, [l]), v = f(() => {
23
- u?.();
24
- }, [u]), y = p(() => _[t], [t]), b = p(() => [
25
- "empty-state",
26
- `empty-state--${t}`,
27
- s
28
- ].filter(Boolean).join(" "), [t, s]);
29
- return /* @__PURE__ */ g("div", {
30
- className: b,
6
+ function s({ illustration: t, title: s, description: c, primaryAction: l, secondaryAction: u, children: d, className: f = "", showIllustration: p = !0 }) {
7
+ let m = l?.onClick, h = u?.onClick, g = n(() => {
8
+ m?.();
9
+ }, [m]), _ = n(() => {
10
+ h?.();
11
+ }, [h]), v = r(() => ["empty-state", f].filter(Boolean).join(" "), [f]);
12
+ return /* @__PURE__ */ o("div", {
13
+ className: v,
31
14
  role: "status",
32
15
  "aria-live": "polite",
33
16
  children: [
34
- c && /* @__PURE__ */ h("div", {
17
+ p && t && /* @__PURE__ */ a("div", {
35
18
  className: "empty-state__illustration",
36
- children: /* @__PURE__ */ h(y, { className: "empty-state__icon" })
19
+ children: t
37
20
  }),
38
- /* @__PURE__ */ g("div", {
21
+ /* @__PURE__ */ o("div", {
39
22
  className: "empty-state__content",
40
23
  children: [
41
- /* @__PURE__ */ h("h3", {
24
+ /* @__PURE__ */ a("h3", {
42
25
  className: "empty-state__title",
43
- children: n
26
+ children: s
44
27
  }),
45
- /* @__PURE__ */ h("p", {
28
+ /* @__PURE__ */ a("p", {
46
29
  className: "empty-state__description",
47
- children: r
30
+ children: c
48
31
  }),
49
- o
32
+ d
50
33
  ]
51
34
  }),
52
- (i || a) && /* @__PURE__ */ g("div", {
35
+ (l || u) && /* @__PURE__ */ o("div", {
53
36
  className: "empty-state__actions",
54
- children: [i && /* @__PURE__ */ h(e, {
37
+ children: [l && /* @__PURE__ */ a(e, {
55
38
  variant: "primary",
56
- onClick: d,
39
+ onClick: g,
57
40
  className: "empty-state__action-btn empty-state__action-btn--primary",
58
- children: i.label
59
- }), a && /* @__PURE__ */ h(m, { children: a.href ? /* @__PURE__ */ h("a", {
60
- href: a.href,
41
+ children: l.label
42
+ }), u && /* @__PURE__ */ a(i, { children: u.href ? /* @__PURE__ */ a("a", {
43
+ href: u.href,
61
44
  className: "empty-state__action-link",
62
- onClick: v,
63
- children: a.label
64
- }) : /* @__PURE__ */ h(e, {
45
+ onClick: _,
46
+ children: u.label
47
+ }) : /* @__PURE__ */ a(e, {
65
48
  variant: "ghost",
66
- onClick: v,
49
+ onClick: _,
67
50
  className: "empty-state__action-btn empty-state__action-btn--secondary",
68
- children: a.label
51
+ children: u.label
69
52
  }) })]
70
53
  })
71
54
  ]
72
55
  });
73
56
  }
74
- var y = d(v);
57
+ var c = t(s);
75
58
  //#endregion
76
- export { y as EmptyState };
59
+ export { c as EmptyState };
77
60
 
78
61
  //# sourceMappingURL=EmptyState2.js.map
79
62
  import "../../assets/components/EmptyState/EmptyState.css";
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState2.js","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["/**\n * EmptyState Component\n *\n * Unified empty state component with consistent layout and styling.\n * Provides configurable illustration, title, description, and call-to-action buttons.\n *\n * Features:\n * - Multiple illustration types for different contexts\n * - Primary and secondary action buttons, plus a `children` slot for an\n * onboarding state that needs more than two (issue #3903)\n * - Accessible (ARIA attributes, semantic HTML)\n * - Dark/light theme support via design tokens\n * - Fade-in animation with reduced motion support\n * - Responsive design\n * - Memoized for optimal performance\n */\n\nimport { memo, useCallback, useMemo, type ReactNode } from \"react\";\nimport { Button } from \"../Button\";\nimport {\n ChatIllustration,\n ModelsIllustration,\n CreationsIllustration,\n TextIllustration,\n BenchmarkIllustration,\n LogsIllustration,\n StatisticsIllustration,\n ErrorIllustration,\n ScheduleIllustration,\n GenericIllustration,\n} from \"./illustrations\";\nimport \"./EmptyState.css\";\n\nexport type IllustrationType =\n | \"chat\"\n | \"models\"\n | \"creations\"\n | \"text\"\n | \"benchmark\"\n | \"logs\"\n | \"statistics\"\n | \"error\"\n | \"schedule\"\n | \"generic\";\n\nexport interface EmptyStateAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface EmptyStateSecondaryAction {\n label: string;\n href?: string;\n onClick?: () => void;\n}\n\nexport interface EmptyStateProps {\n /** Type of illustration to display */\n illustration: IllustrationType;\n /** Main heading */\n title: string;\n /** Descriptive text */\n description: string;\n /** Primary action button */\n primaryAction?: EmptyStateAction;\n /** Secondary action (link or button) */\n secondaryAction?: EmptyStateSecondaryAction;\n /**\n * Extra content rendered under the description, inside the same text column.\n *\n * The two action props cover the common one-or-two-button case. An\n * onboarding state that has to offer more than that (e.g. the Data Hub's\n * three ingest paths, issue #3903) renders them here instead of growing a\n * page-local copy of this component.\n */\n children?: ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Whether to show illustration (default: true) */\n showIllustration?: boolean;\n}\n\n/**\n * Static map of illustration types to components.\n * Defined outside component to avoid recreation on each render.\n */\nconst illustrationMap: Record<\n IllustrationType,\n React.ComponentType<{ className?: string }>\n> = {\n chat: ChatIllustration,\n models: ModelsIllustration,\n creations: CreationsIllustration,\n text: TextIllustration,\n benchmark: BenchmarkIllustration,\n logs: LogsIllustration,\n statistics: StatisticsIllustration,\n error: ErrorIllustration,\n schedule: ScheduleIllustration,\n generic: GenericIllustration,\n};\n\n/**\n * EmptyState Component\n *\n * Displays an empty state with illustration, text, and optional actions.\n * Memoized to prevent unnecessary re-renders.\n */\nfunction EmptyStateComponent({\n illustration,\n title,\n description,\n primaryAction,\n secondaryAction,\n children,\n className = \"\",\n showIllustration = true,\n}: EmptyStateProps) {\n // Use stable callback references by extracting onClick functions\n const primaryOnClick = primaryAction?.onClick;\n const secondaryOnClick = secondaryAction?.onClick;\n\n const handlePrimaryAction = useCallback(() => {\n primaryOnClick?.();\n }, [primaryOnClick]);\n\n const handleSecondaryAction = useCallback(() => {\n secondaryOnClick?.();\n }, [secondaryOnClick]);\n\n // Memoize illustration component lookup\n const Illustration = useMemo(() => illustrationMap[illustration], [illustration]);\n\n // Memoize class name computation\n const containerClass = useMemo(\n () =>\n [\"empty-state\", `empty-state--${illustration}`, className]\n .filter(Boolean)\n .join(\" \"),\n [illustration, className],\n );\n\n return (\n <div className={containerClass} role=\"status\" aria-live=\"polite\">\n {showIllustration && (\n <div className=\"empty-state__illustration\">\n <Illustration className=\"empty-state__icon\" />\n </div>\n )}\n\n <div className=\"empty-state__content\">\n <h3 className=\"empty-state__title\">{title}</h3>\n <p className=\"empty-state__description\">{description}</p>\n {children}\n </div>\n\n {(primaryAction || secondaryAction) && (\n <div className=\"empty-state__actions\">\n {primaryAction && (\n <Button\n variant=\"primary\"\n onClick={handlePrimaryAction}\n className=\"empty-state__action-btn empty-state__action-btn--primary\"\n >\n {primaryAction.label}\n </Button>\n )}\n\n {secondaryAction && (\n <>\n {secondaryAction.href ? (\n <a\n href={secondaryAction.href}\n className=\"empty-state__action-link\"\n onClick={handleSecondaryAction}\n >\n {secondaryAction.label}\n </a>\n ) : (\n <Button\n variant=\"ghost\"\n onClick={handleSecondaryAction}\n className=\"empty-state__action-btn empty-state__action-btn--secondary\"\n >\n {secondaryAction.label}\n </Button>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport const EmptyState = memo(EmptyStateComponent);\n"],"mappings":";;;;;;AAsFA,IAAM,IAGF;CACF,MAAM;CACN,QAAQ;CACR,WAAW;CACX,MAAM;CACN,WAAW;CACX,MAAM;CACN,YAAY;CACZ,OAAO;CACP,UAAU;CACV,SAAS;AACX;AAQA,SAAS,EAAoB,EAC3B,iBACA,UACA,gBACA,kBACA,oBACA,aACA,eAAY,IACZ,sBAAmB,MACD;CAElB,IAAM,IAAiB,GAAe,SAChC,IAAmB,GAAiB,SAEpC,IAAsB,QAAkB;EAC5C,IAAiB;CACnB,GAAG,CAAC,CAAc,CAAC,GAEb,IAAwB,QAAkB;EAC9C,IAAmB;CACrB,GAAG,CAAC,CAAgB,CAAC,GAGf,IAAe,QAAc,EAAgB,IAAe,CAAC,CAAY,CAAC,GAG1E,IAAiB,QAEnB;EAAC;EAAe,gBAAgB;EAAgB;CAAS,CAAC,CACvD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GACb,CAAC,GAAc,CAAS,CAC1B;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW;EAAgB,MAAK;EAAS,aAAU;EAAxD,UAAA;GACG,KACC,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD,EAAc,WAAU,oBAAqB,CAAA;GAC1C,CAAA;GAGP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;MAAsB,UAAA;KAAU,CAAA;KAC9C,kBAAC,KAAD;MAAG,WAAU;MAA4B,UAAA;KAAe,CAAA;KACvD;IACE;;IAEH,KAAiB,MACjB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAc;IACT,CAAA,GAGT,KACC,kBAAA,GAAA,EAAA,UACG,EAAgB,OACf,kBAAC,KAAD;KACE,MAAM,EAAgB;KACtB,WAAU;KACV,SAAS;KAER,UAAA,EAAgB;IAChB,CAAA,IAEH,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAgB;IACX,CAAA,EAEV,CAAA,CAED;;EAEJ;;AAET;AAEA,IAAa,IAAa,EAAK,CAAmB"}
1
+ {"version":3,"file":"EmptyState2.js","names":[],"sources":["../../../src/components/EmptyState/EmptyState.tsx"],"sourcesContent":["/**\n * EmptyState Component\n *\n * Unified empty state component with consistent layout and styling.\n * Provides configurable illustration, title, description, and call-to-action buttons.\n *\n * Features:\n * - Multiple illustration types for different contexts\n * - Primary and secondary action buttons, plus a `children` slot for an\n * onboarding state that needs more than two (issue #3903)\n * - Accessible (ARIA attributes, semantic HTML)\n * - Dark/light theme support via design tokens\n * - Fade-in animation with reduced motion support\n * - Responsive design\n * - Memoized for optimal performance\n */\n\nimport { memo, useCallback, useMemo, type ReactNode } from \"react\";\nimport { Button } from \"../Button\";\nimport \"./EmptyState.css\";\n\nexport interface EmptyStateAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface EmptyStateSecondaryAction {\n label: string;\n href?: string;\n onClick?: () => void;\n}\n\nexport interface EmptyStateProps {\n /**\n * The drawing shown above the text.\n *\n * This used to be one of ten names: chat, models, creations, benchmark,\n * logs, statistics, schedule and so on, each resolving to an SVG shipped\n * inside this package. Those names are one product's information\n * architecture, and no other consumer has a \"creations\" screen to draw for.\n * A consumer passes its own artwork and keeps its own vocabulary.\n */\n illustration?: ReactNode;\n /** Main heading */\n title: string;\n /** Descriptive text */\n description: string;\n /** Primary action button */\n primaryAction?: EmptyStateAction;\n /** Secondary action (link or button) */\n secondaryAction?: EmptyStateSecondaryAction;\n /**\n * Extra content rendered under the description, inside the same text column.\n *\n * The two action props cover the common one-or-two-button case. An\n * onboarding state that has to offer more than that (e.g. the Data Hub's\n * three ingest paths, issue #3903) renders them here instead of growing a\n * page-local copy of this component.\n */\n children?: ReactNode;\n /** Additional CSS classes */\n className?: string;\n /** Whether to show illustration (default: true) */\n showIllustration?: boolean;\n}\n\n/**\n * EmptyState Component\n *\n * Displays an empty state with illustration, text, and optional actions.\n * Memoized to prevent unnecessary re-renders.\n */\nfunction EmptyStateComponent({\n illustration,\n title,\n description,\n primaryAction,\n secondaryAction,\n children,\n className = \"\",\n showIllustration = true,\n}: EmptyStateProps) {\n // Use stable callback references by extracting onClick functions\n const primaryOnClick = primaryAction?.onClick;\n const secondaryOnClick = secondaryAction?.onClick;\n\n const handlePrimaryAction = useCallback(() => {\n primaryOnClick?.();\n }, [primaryOnClick]);\n\n const handleSecondaryAction = useCallback(() => {\n secondaryOnClick?.();\n }, [secondaryOnClick]);\n\n // Memoize class name computation\n const containerClass = useMemo(\n () => [\"empty-state\", className].filter(Boolean).join(\" \"),\n [className],\n );\n\n return (\n <div className={containerClass} role=\"status\" aria-live=\"polite\">\n {showIllustration && illustration && (\n <div className=\"empty-state__illustration\">{illustration}</div>\n )}\n\n <div className=\"empty-state__content\">\n <h3 className=\"empty-state__title\">{title}</h3>\n <p className=\"empty-state__description\">{description}</p>\n {children}\n </div>\n\n {(primaryAction || secondaryAction) && (\n <div className=\"empty-state__actions\">\n {primaryAction && (\n <Button\n variant=\"primary\"\n onClick={handlePrimaryAction}\n className=\"empty-state__action-btn empty-state__action-btn--primary\"\n >\n {primaryAction.label}\n </Button>\n )}\n\n {secondaryAction && (\n <>\n {secondaryAction.href ? (\n <a\n href={secondaryAction.href}\n className=\"empty-state__action-link\"\n onClick={handleSecondaryAction}\n >\n {secondaryAction.label}\n </a>\n ) : (\n <Button\n variant=\"ghost\"\n onClick={handleSecondaryAction}\n className=\"empty-state__action-btn empty-state__action-btn--secondary\"\n >\n {secondaryAction.label}\n </Button>\n )}\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport const EmptyState = memo(EmptyStateComponent);\n"],"mappings":";;;;;AAwEA,SAAS,EAAoB,EAC3B,iBACA,UACA,gBACA,kBACA,oBACA,aACA,eAAY,IACZ,sBAAmB,MACD;CAElB,IAAM,IAAiB,GAAe,SAChC,IAAmB,GAAiB,SAEpC,IAAsB,QAAkB;EAC5C,IAAiB;CACnB,GAAG,CAAC,CAAc,CAAC,GAEb,IAAwB,QAAkB;EAC9C,IAAmB;CACrB,GAAG,CAAC,CAAgB,CAAC,GAGf,IAAiB,QACf,CAAC,eAAe,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GACzD,CAAC,CAAS,CACZ;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW;EAAgB,MAAK;EAAS,aAAU;EAAxD,UAAA;GACG,KAAoB,KACnB,kBAAC,OAAD;IAAK,WAAU;IAA6B,UAAA;GAAkB,CAAA;GAGhE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,MAAD;MAAI,WAAU;MAAsB,UAAA;KAAU,CAAA;KAC9C,kBAAC,KAAD;MAAG,WAAU;MAA4B,UAAA;KAAe,CAAA;KACvD;IACE;;IAEH,KAAiB,MACjB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAc;IACT,CAAA,GAGT,KACC,kBAAA,GAAA,EAAA,UACG,EAAgB,OACf,kBAAC,KAAD;KACE,MAAM,EAAgB;KACtB,WAAU;KACV,SAAS;KAER,UAAA,EAAgB;IAChB,CAAA,IAEH,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAgB;IACX,CAAA,EAEV,CAAA,CAED;;EAEJ;;AAET;AAEA,IAAa,IAAa,EAAK,CAAmB"}
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * EmptyState Component - Barrel Export
3
+ *
4
+ * The ten illustrations that used to ship here were one product's information
5
+ * architecture: chat, models, creations, benchmark, logs, statistics,
6
+ * schedule. No other consumer has a "creations" screen to draw for. A consumer
7
+ * passes its own artwork through `illustration` and keeps its own vocabulary.
3
8
  */
4
9
  export { EmptyState } from './EmptyState';
5
- export type { EmptyStateProps, EmptyStateAction, EmptyStateSecondaryAction, IllustrationType, } from './EmptyState';
10
+ export type { EmptyStateProps, EmptyStateAction, EmptyStateSecondaryAction, } from './EmptyState';
@@ -1,11 +1,24 @@
1
- export type ErrorType = "network" | "configuration" | "model" | "permission" | "generic";
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * How the error reads, not what it is about.
4
+ *
5
+ * This prop used to be a union of five names: network, configuration, model,
6
+ * permission, generic. Two of those, and "model" in particular, are one
7
+ * product's categories rather than anything a shared component can reason
8
+ * about, and all five resolved to three colours anyway: network and permission
9
+ * were the same amber, model and generic the same red. A consumer decides
10
+ * which of its own error categories reads as which tone.
11
+ */
12
+ export type ErrorTone = "danger" | "warning" | "accent";
2
13
  export interface ErrorAction {
3
14
  label: string;
4
15
  onClick: () => void;
5
16
  }
6
17
  export interface ErrorStateProps {
7
- /** Error type determines icon and default styling */
8
- type?: ErrorType;
18
+ /** How the error reads. Defaults to `danger`. */
19
+ tone?: ErrorTone;
20
+ /** Replaces the default alert icon. */
21
+ icon?: ReactNode;
9
22
  /** Error title - main heading */
10
23
  title: string;
11
24
  /** Detailed error message */
@@ -22,4 +35,4 @@ export interface ErrorStateProps {
22
35
  /**
23
36
  * ErrorState Component
24
37
  */
25
- export declare function ErrorState({ type, title, message, primaryAction, secondaryAction, className, showIcon, }: ErrorStateProps): import("react").JSX.Element;
38
+ export declare function ErrorState({ tone, icon, title, message, primaryAction, secondaryAction, className, showIcon, }: ErrorStateProps): import("react").JSX.Element;
@@ -4,56 +4,53 @@ import { AlertCircleIcon as t } from "../../icons/AlertCircleIcon.js";
4
4
  import { useCallback as n } from "react";
5
5
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
6
  //#region src/components/ErrorState/ErrorState.tsx
7
- function a(e) {
8
- return /* @__PURE__ */ r(t, { size: 48 });
9
- }
10
- function o({ type: t = "generic", title: o, message: s, primaryAction: c, secondaryAction: l, className: u = "", showIcon: d = !0 }) {
11
- let f = n(() => {
12
- c?.onClick();
13
- }, [c]), p = n(() => {
7
+ function a({ tone: a = "danger", icon: o, title: s, message: c, primaryAction: l, secondaryAction: u, className: d = "", showIcon: f = !0 }) {
8
+ let p = n(() => {
14
9
  l?.onClick();
15
- }, [l]), m = [
10
+ }, [l]), m = n(() => {
11
+ u?.onClick();
12
+ }, [u]), h = [
16
13
  "error-state",
17
- `error-state--${t}`,
18
- u
14
+ `error-state--${a}`,
15
+ d
19
16
  ].filter(Boolean).join(" ");
20
17
  return /* @__PURE__ */ i("div", {
21
- className: m,
18
+ className: h,
22
19
  role: "alert",
23
20
  "aria-live": "polite",
24
21
  children: [
25
- d && /* @__PURE__ */ r("div", {
22
+ f && /* @__PURE__ */ r("div", {
26
23
  className: "error-state__icon",
27
24
  "aria-hidden": "true",
28
- children: a(t)
25
+ children: o ?? /* @__PURE__ */ r(t, { size: 48 })
29
26
  }),
30
27
  /* @__PURE__ */ r("h2", {
31
28
  className: "error-state__title",
32
- children: o
29
+ children: s
33
30
  }),
34
31
  /* @__PURE__ */ r("p", {
35
32
  className: "error-state__message",
36
- children: s
33
+ children: c
37
34
  }),
38
- (c || l) && /* @__PURE__ */ i("div", {
35
+ (l || u) && /* @__PURE__ */ i("div", {
39
36
  className: "error-state__actions",
40
- children: [c && /* @__PURE__ */ r(e, {
37
+ children: [l && /* @__PURE__ */ r(e, {
41
38
  variant: "primary",
42
- onClick: f,
39
+ onClick: p,
43
40
  className: "error-state__action-btn error-state__action-btn--primary",
44
- children: c.label
45
- }), l && /* @__PURE__ */ r(e, {
41
+ children: l.label
42
+ }), u && /* @__PURE__ */ r(e, {
46
43
  variant: "secondary",
47
- onClick: p,
44
+ onClick: m,
48
45
  className: "error-state__action-btn error-state__action-btn--secondary",
49
- children: l.label
46
+ children: u.label
50
47
  })]
51
48
  })
52
49
  ]
53
50
  });
54
51
  }
55
52
  //#endregion
56
- export { o as ErrorState };
53
+ export { a as ErrorState };
57
54
 
58
55
  //# sourceMappingURL=ErrorState2.js.map
59
56
  import "../../assets/components/ErrorState/ErrorState.css";
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorState2.js","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["/**\n * ErrorState Component\n *\n * Unified error state component with recovery actions.\n * Provides consistent error presentation across all pages with actionable buttons.\n *\n * Features:\n * - Error type variants (network, configuration, model, permission, generic)\n * - Primary and secondary action buttons\n * - Accessible (ARIA attributes, focus management)\n * - Dark/light theme support\n */\n\nimport { useCallback } from \"react\";\nimport { AlertCircleIcon } from \"../../icons/AlertCircleIcon\";\nimport { Button } from \"../Button\";\nimport \"./ErrorState.css\";\n\nexport type ErrorType =\n \"network\" | \"configuration\" | \"model\" | \"permission\" | \"generic\";\n\nexport interface ErrorAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface ErrorStateProps {\n /** Error type determines icon and default styling */\n type?: ErrorType;\n /** Error title - main heading */\n title: string;\n /** Detailed error message */\n message: string;\n /** Primary action button (e.g., Retry, Go to Settings) */\n primaryAction?: ErrorAction;\n /** Secondary action button (e.g., View Logs, Report Issue) */\n secondaryAction?: ErrorAction;\n /** Additional CSS classes */\n className?: string;\n /** Whether to show error icon */\n showIcon?: boolean;\n}\n\n/**\n * Get icon for error type\n */\nfunction getErrorIcon(_type: ErrorType): React.ReactNode {\n // All error types use the same AlertCircleIcon for now\n // Can be extended with different icons per type in the future\n return <AlertCircleIcon size={48} />;\n}\n\n/**\n * ErrorState Component\n */\nexport function ErrorState({\n type = \"generic\",\n title,\n message,\n primaryAction,\n secondaryAction,\n className = \"\",\n showIcon = true,\n}: ErrorStateProps) {\n const handlePrimaryAction = useCallback(() => {\n primaryAction?.onClick();\n }, [primaryAction]);\n\n const handleSecondaryAction = useCallback(() => {\n secondaryAction?.onClick();\n }, [secondaryAction]);\n\n const containerClass = [\"error-state\", `error-state--${type}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div className={containerClass} role=\"alert\" aria-live=\"polite\">\n {showIcon && (\n <div className=\"error-state__icon\" aria-hidden=\"true\">\n {getErrorIcon(type)}\n </div>\n )}\n\n <h2 className=\"error-state__title\">{title}</h2>\n\n <p className=\"error-state__message\">{message}</p>\n\n {(primaryAction || secondaryAction) && (\n <div className=\"error-state__actions\">\n {primaryAction && (\n <Button\n variant=\"primary\"\n onClick={handlePrimaryAction}\n className=\"error-state__action-btn error-state__action-btn--primary\"\n >\n {primaryAction.label}\n </Button>\n )}\n\n {secondaryAction && (\n <Button\n variant=\"secondary\"\n onClick={handleSecondaryAction}\n className=\"error-state__action-btn error-state__action-btn--secondary\"\n >\n {secondaryAction.label}\n </Button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AA8CA,SAAS,EAAa,GAAmC;CAGvD,OAAO,kBAAC,GAAD,EAAiB,MAAM,GAAK,CAAA;AACrC;AAKA,SAAgB,EAAW,EACzB,UAAO,WACP,UACA,YACA,kBACA,oBACA,eAAY,IACZ,cAAW,MACO;CAClB,IAAM,IAAsB,QAAkB;EAC5C,GAAe,QAAQ;CACzB,GAAG,CAAC,CAAa,CAAC,GAEZ,IAAwB,QAAkB;EAC9C,GAAiB,QAAQ;CAC3B,GAAG,CAAC,CAAe,CAAC,GAEd,IAAiB;EAAC;EAAe,gBAAgB;EAAQ;CAAS,CAAC,CACtE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EAAK,WAAW;EAAgB,MAAK;EAAQ,aAAU;EAAvD,UAAA;GACG,KACC,kBAAC,OAAD;IAAK,WAAU;IAAoB,eAAY;IAC5C,UAAA,EAAa,CAAI;GACf,CAAA;GAGP,kBAAC,MAAD;IAAI,WAAU;IAAsB,UAAA;GAAU,CAAA;GAE9C,kBAAC,KAAD;IAAG,WAAU;IAAwB,UAAA;GAAW,CAAA;IAE9C,KAAiB,MACjB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAc;IACT,CAAA,GAGT,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAgB;IACX,CAAA,CAEP;;EAEJ;;AAET"}
1
+ {"version":3,"file":"ErrorState2.js","names":[],"sources":["../../../src/components/ErrorState/ErrorState.tsx"],"sourcesContent":["/**\n * ErrorState Component\n *\n * Unified error state component with recovery actions.\n * Provides consistent error presentation across all pages with actionable buttons.\n *\n * Features:\n * - Three visual tones\n * - Primary and secondary action buttons\n * - Accessible (ARIA attributes, focus management)\n * - Dark/light theme support\n */\n\nimport type { ReactNode } from \"react\";\nimport { useCallback } from \"react\";\nimport { AlertCircleIcon } from \"../../icons/AlertCircleIcon\";\nimport { Button } from \"../Button\";\nimport \"./ErrorState.css\";\n\n/**\n * How the error reads, not what it is about.\n *\n * This prop used to be a union of five names: network, configuration, model,\n * permission, generic. Two of those, and \"model\" in particular, are one\n * product's categories rather than anything a shared component can reason\n * about, and all five resolved to three colours anyway: network and permission\n * were the same amber, model and generic the same red. A consumer decides\n * which of its own error categories reads as which tone.\n */\nexport type ErrorTone = \"danger\" | \"warning\" | \"accent\";\n\nexport interface ErrorAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface ErrorStateProps {\n /** How the error reads. Defaults to `danger`. */\n tone?: ErrorTone;\n /** Replaces the default alert icon. */\n icon?: ReactNode;\n /** Error title - main heading */\n title: string;\n /** Detailed error message */\n message: string;\n /** Primary action button (e.g., Retry, Go to Settings) */\n primaryAction?: ErrorAction;\n /** Secondary action button (e.g., View Logs, Report Issue) */\n secondaryAction?: ErrorAction;\n /** Additional CSS classes */\n className?: string;\n /** Whether to show error icon */\n showIcon?: boolean;\n}\n\n/**\n * ErrorState Component\n */\nexport function ErrorState({\n tone = \"danger\",\n icon,\n title,\n message,\n primaryAction,\n secondaryAction,\n className = \"\",\n showIcon = true,\n}: ErrorStateProps) {\n const handlePrimaryAction = useCallback(() => {\n primaryAction?.onClick();\n }, [primaryAction]);\n\n const handleSecondaryAction = useCallback(() => {\n secondaryAction?.onClick();\n }, [secondaryAction]);\n\n const containerClass = [\"error-state\", `error-state--${tone}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div className={containerClass} role=\"alert\" aria-live=\"polite\">\n {showIcon && (\n <div className=\"error-state__icon\" aria-hidden=\"true\">\n {icon ?? <AlertCircleIcon size={48} />}\n </div>\n )}\n\n <h2 className=\"error-state__title\">{title}</h2>\n\n <p className=\"error-state__message\">{message}</p>\n\n {(primaryAction || secondaryAction) && (\n <div className=\"error-state__actions\">\n {primaryAction && (\n <Button\n variant=\"primary\"\n onClick={handlePrimaryAction}\n className=\"error-state__action-btn error-state__action-btn--primary\"\n >\n {primaryAction.label}\n </Button>\n )}\n\n {secondaryAction && (\n <Button\n variant=\"secondary\"\n onClick={handleSecondaryAction}\n className=\"error-state__action-btn error-state__action-btn--secondary\"\n >\n {secondaryAction.label}\n </Button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AA0DA,SAAgB,EAAW,EACzB,UAAO,UACP,SACA,UACA,YACA,kBACA,oBACA,eAAY,IACZ,cAAW,MACO;CAClB,IAAM,IAAsB,QAAkB;EAC5C,GAAe,QAAQ;CACzB,GAAG,CAAC,CAAa,CAAC,GAEZ,IAAwB,QAAkB;EAC9C,GAAiB,QAAQ;CAC3B,GAAG,CAAC,CAAe,CAAC,GAEd,IAAiB;EAAC;EAAe,gBAAgB;EAAQ;CAAS,CAAC,CACtE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EAAK,WAAW;EAAgB,MAAK;EAAQ,aAAU;EAAvD,UAAA;GACG,KACC,kBAAC,OAAD;IAAK,WAAU;IAAoB,eAAY;IAC5C,UAAA,KAAQ,kBAAC,GAAD,EAAiB,MAAM,GAAK,CAAA;GAClC,CAAA;GAGP,kBAAC,MAAD;IAAI,WAAU;IAAsB,UAAA;GAAU,CAAA;GAE9C,kBAAC,KAAD;IAAG,WAAU;IAAwB,UAAA;GAAW,CAAA;IAE9C,KAAiB,MACjB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAc;IACT,CAAA,GAGT,KACC,kBAAC,GAAD;KACE,SAAQ;KACR,SAAS;KACT,WAAU;KAET,UAAA,EAAgB;IACX,CAAA,CAEP;;EAEJ;;AAET"}
@@ -2,4 +2,4 @@
2
2
  * ErrorState Component Export
3
3
  */
4
4
  export { ErrorState } from './ErrorState';
5
- export type { ErrorStateProps, ErrorType, ErrorAction } from './ErrorState';
5
+ export type { ErrorStateProps, ErrorTone, ErrorAction } from './ErrorState';
@@ -8,6 +8,19 @@ export interface PageHeaderProps {
8
8
  actions?: ReactNode;
9
9
  /** Error message to display below the header */
10
10
  error?: string | null;
11
+ /**
12
+ * Secondary line under the message, for the raw detail a server returned.
13
+ * Kept separate so the message stays readable when the detail is long.
14
+ */
15
+ errorDetail?: string | null;
16
+ /**
17
+ * Callback for the Retry button, rendered before the dismiss control when
18
+ * set. Dismissal is a pure dismissal and must not retry, which is why these
19
+ * are two props rather than one.
20
+ */
21
+ onRetry?: () => void;
22
+ /** Label for the Retry button. Default: "Retry" */
23
+ retryLabel?: string;
11
24
  /** Callback when error is dismissed */
12
25
  onErrorDismiss?: () => void;
13
26
  /** Additional CSS class names */
@@ -15,4 +28,4 @@ export interface PageHeaderProps {
15
28
  /** Accessible label for the error-dismiss button. Default: "Dismiss error" */
16
29
  dismissErrorLabel?: string;
17
30
  }
18
- export declare function PageHeader({ title, description, actions, error, onErrorDismiss, className, dismissErrorLabel, }: PageHeaderProps): import("react").JSX.Element;
31
+ export declare function PageHeader({ title, description, actions, error, onErrorDismiss, className, errorDetail, onRetry, retryLabel, dismissErrorLabel, }: PageHeaderProps): import("react").JSX.Element;