@stackone/malachite 2.70.0 → 2.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/COMPONENTS.md +12 -11
  2. package/dist/components/Accordion.js +59 -53
  3. package/dist/components/Accordion.js.map +1 -1
  4. package/dist/components/Alert.js +100 -75
  5. package/dist/components/Alert.js.map +1 -1
  6. package/dist/components/Button.js +89 -82
  7. package/dist/components/Button.js.map +1 -1
  8. package/dist/components/Modal.js +75 -74
  9. package/dist/components/Modal.js.map +1 -1
  10. package/dist/components/PopoverParts.js +35 -35
  11. package/dist/components/PopoverParts.js.map +1 -1
  12. package/dist/components/Search.js +30 -29
  13. package/dist/components/Search.js.map +1 -1
  14. package/dist/components/SidePanel.js +124 -106
  15. package/dist/components/SidePanel.js.map +1 -1
  16. package/dist/components/StatusPill.js +61 -0
  17. package/dist/components/StatusPill.js.map +1 -0
  18. package/dist/components/Surface.js +138 -133
  19. package/dist/components/Surface.js.map +1 -1
  20. package/dist/components/Toolbar.js +40 -33
  21. package/dist/components/Toolbar.js.map +1 -1
  22. package/dist/components/Typography/EllipsisText.js +27 -25
  23. package/dist/components/Typography/EllipsisText.js.map +1 -1
  24. package/dist/components/Typography/MarkdownBlock.js +36 -28
  25. package/dist/components/Typography/MarkdownBlock.js.map +1 -1
  26. package/dist/components/Typography/Text.js +24 -22
  27. package/dist/components/Typography/Text.js.map +1 -1
  28. package/dist/components/WizardLayout.js +81 -67
  29. package/dist/components/WizardLayout.js.map +1 -1
  30. package/dist/index.d.ts +65 -2
  31. package/dist/index.js +356 -354
  32. package/dist/index.js.map +1 -1
  33. package/dist/tailwind.css.js +1 -1
  34. package/package.json +1 -1
@@ -1,148 +1,165 @@
1
- import { jsx as e, jsxs as a } from "react/jsx-runtime";
2
- import { useId as k, useState as _, useRef as u, useEffect as q } from "react";
3
- import { createPortal as U } from "react-dom";
4
- import { ShadowRootWrapper as G } from "../ShadowRootWrapper.js";
5
- import H from "./CalloutStrip.js";
6
- import J from "./CustomIcons/ArrowLeftIcon.js";
7
- import K from "./CustomIcons/DismissIcon.js";
8
- import z from "./Typography/EllipsisText.js";
9
- import { useOverlayBehaviour as Q, OVERLAY_ICON_BUTTON_CLASSES as E } from "./overlayBehaviour.js";
10
- import { OVERLAY_ELEVATED_ATTR as Z, overlayIdentity as O } from "./portalOverlay.js";
11
- const P = 200, ee = (t) => typeof t == "number" ? `${t}px` : t, me = ({
12
- open: t,
13
- onClose: c,
14
- title: o,
15
- subtitle: d,
16
- titleExtra: f,
1
+ import { jsx as e, jsxs as r } from "react/jsx-runtime";
2
+ import { useId as V, useState as B, useRef as u, useEffect as Z } from "react";
3
+ import { createPortal as ee } from "react-dom";
4
+ import { ShadowRootWrapper as re } from "../ShadowRootWrapper.js";
5
+ import le from "./CalloutStrip.js";
6
+ import ae from "./CustomIcons/ArrowLeftIcon.js";
7
+ import te from "./CustomIcons/DismissIcon.js";
8
+ import C from "./Typography/EllipsisText.js";
9
+ import { useOverlayBehaviour as ie, OVERLAY_ICON_BUTTON_CLASSES as L } from "./overlayBehaviour.js";
10
+ import { OVERLAY_ELEVATED_ATTR as ne, overlayIdentity as j } from "./portalOverlay.js";
11
+ const M = 200, se = (a) => typeof a == "number" ? `${a}px` : a, ve = ({
12
+ open: a,
13
+ onClose: d,
14
+ title: s,
15
+ subtitle: o,
16
+ subtitlePlacement: W = "inline",
17
+ titleExtra: x,
17
18
  description: m,
18
- headerDivider: V = !1,
19
- icon: x,
19
+ toolbar: f,
20
+ headerDivider: D = !1,
21
+ icon: h,
20
22
  headerExtra: b,
21
- footer: h,
22
- onBack: v,
23
- maxWidth: C = 1080,
24
- "aria-label": L,
23
+ footer: v,
24
+ onBack: N,
25
+ maxWidth: F = 1080,
26
+ "aria-label": X,
25
27
  "aria-labelledby": y,
26
- bodyPadding: N = !0,
27
- stacking: j = "default",
28
+ bodyPadding: g = !0,
29
+ stacking: Y = "default",
28
30
  callouts: p,
29
- renderLink: B,
30
- children: g
31
+ renderLink: q,
32
+ children: w
31
33
  }) => {
32
- const T = k(), I = k(), [w, S] = _(!1), [M, R] = _(!1), i = u(null), r = u(null), $ = u(null), {
33
- ref: W,
34
- isTopmost: D,
35
- zIndex: F,
36
- elevated: X
37
- } = Q({
38
- open: t,
39
- onClose: c,
40
- elevated: j === "above-app-overlays",
34
+ const T = V(), I = V(), [S, k] = B(!1), [U, R] = B(!1), i = u(null), l = u(null), $ = u(null), {
35
+ ref: G,
36
+ isTopmost: H,
37
+ zIndex: J,
38
+ elevated: K
39
+ } = ie({
40
+ open: a,
41
+ onClose: d,
42
+ elevated: Y === "above-app-overlays",
41
43
  hostRef: $
42
44
  });
43
- if (q(() => (t ? (R(!0), r.current && (clearTimeout(r.current), r.current = null), i.current = requestAnimationFrame(() => {
44
- i.current = null, S(!0);
45
- })) : (S(!1), r.current = setTimeout(() => {
46
- r.current = null, R(!1);
47
- }, P)), () => {
48
- i.current !== null && (cancelAnimationFrame(i.current), i.current = null), r.current && (clearTimeout(r.current), r.current = null);
49
- }), [t]), !M)
45
+ if (Z(() => (a ? (R(!0), l.current && (clearTimeout(l.current), l.current = null), i.current = requestAnimationFrame(() => {
46
+ i.current = null, k(!0);
47
+ })) : (k(!1), l.current = setTimeout(() => {
48
+ l.current = null, R(!1);
49
+ }, M)), () => {
50
+ i.current !== null && (cancelAnimationFrame(i.current), i.current = null), l.current && (clearTimeout(l.current), l.current = null);
51
+ }), [a]), !U)
50
52
  return null;
51
- const l = p == null ? void 0 : p.filter((n) => n.message.trim()), A = !!(l != null && l.length), Y = N ? /* @__PURE__ */ e("div", { className: A ? "p-[28px]" : "py-[28px]", children: g }) : g;
52
- return U(
53
+ const t = p == null ? void 0 : p.filter((n) => n.message.trim()), A = !!(t != null && t.length), Q = g ? /* @__PURE__ */ e("div", { className: A ? "p-[28px]" : "py-[28px]", children: w }) : w, E = W === "below" && !!o, _ = /* @__PURE__ */ e(
54
+ "span",
55
+ {
56
+ className: E ? "flex min-w-0 shrink" : "flex min-w-0 max-w-full shrink-0",
57
+ children: /* @__PURE__ */ e(
58
+ C,
59
+ {
60
+ tooltip: s,
61
+ tooltipWhenTruncated: !0,
62
+ tooltipPlacement: "bottom",
63
+ className: "min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold",
64
+ children: s
65
+ }
66
+ )
67
+ }
68
+ ), z = o ? /* @__PURE__ */ e(
69
+ C,
70
+ {
71
+ tooltip: o,
72
+ tooltipWhenTruncated: !0,
73
+ tooltipPlacement: "bottom",
74
+ color: "secondary",
75
+ className: "min-w-0 text-[13px]",
76
+ children: o
77
+ }
78
+ ) : null, O = x ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: x }) : null, P = b ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-baseline", children: b }) : null;
79
+ return ee(
53
80
  // Host carries the stacking context — ShadowRootWrapper's `isolation` would
54
81
  // otherwise flatten our z-index and let sticky page elements paint over us.
55
82
  /* @__PURE__ */ e(
56
- G,
83
+ re,
57
84
  {
58
85
  hostRef: $,
59
- hostStyle: { position: "relative", zIndex: F },
60
- hostProps: X ? { ...O("sidepanel"), [Z]: "" } : O("sidepanel"),
61
- children: /* @__PURE__ */ a("div", { className: "fixed inset-0 z-[1000]", children: [
86
+ hostStyle: { position: "relative", zIndex: J },
87
+ hostProps: K ? { ...j("sidepanel"), [ne]: "" } : j("sidepanel"),
88
+ children: /* @__PURE__ */ r("div", { className: "fixed inset-0 z-[1000]", children: [
62
89
  /* @__PURE__ */ e(
63
90
  "div",
64
91
  {
65
92
  "aria-hidden": "true",
66
- onClick: c,
67
- className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${w ? "opacity-100" : "opacity-0"}`
93
+ onClick: d,
94
+ className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${S ? "opacity-100" : "opacity-0"}`
68
95
  }
69
96
  ),
70
- /* @__PURE__ */ a(
97
+ /* @__PURE__ */ r(
71
98
  "div",
72
99
  {
73
- ref: W,
100
+ ref: G,
74
101
  role: "dialog",
75
- "aria-modal": D ? "true" : void 0,
102
+ "aria-modal": H ? "true" : void 0,
76
103
  "aria-describedby": [
77
- ...(l ?? []).map((n, s) => `${T}-${s}`),
104
+ ...(t ?? []).map((n, c) => `${T}-${c}`),
78
105
  m ? I : null
79
106
  ].filter(Boolean).join(" ") || void 0,
80
107
  tabIndex: -1,
81
- "aria-label": y ? void 0 : L ?? (typeof o == "string" ? o : void 0),
108
+ "aria-label": y ? void 0 : X ?? (typeof s == "string" ? s : void 0),
82
109
  "aria-labelledby": y,
83
110
  className: "absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]",
84
111
  style: {
85
- width: `min(calc(100% - 16px), ${ee(C)})`,
112
+ width: `min(calc(100% - 16px), ${se(F)})`,
86
113
  // Inline: Tailwind translate utilities silently break inside
87
114
  // shadow roots (see CLAUDE.md Shadow DOM caveats).
88
- transform: w ? "translateX(0)" : "translateX(calc(100% + 16px))",
89
- transition: `transform ${P}ms ease-in-out`
115
+ transform: S ? "translateX(0)" : "translateX(calc(100% + 16px))",
116
+ transition: `transform ${M}ms ease-in-out`
90
117
  },
91
118
  children: [
92
- /* @__PURE__ */ a(
119
+ /* @__PURE__ */ r(
93
120
  "div",
94
121
  {
95
- className: `flex flex-col gap-[20px] px-[20px] py-[18px] ${V ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : ""}`,
122
+ className: `flex flex-col gap-[20px] px-[20px] py-[18px] ${D ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : ""}`,
96
123
  children: [
97
- /* @__PURE__ */ a("div", { className: "flex items-center gap-[12px]", children: [
98
- v ? /* @__PURE__ */ e(
124
+ /* @__PURE__ */ r("div", { className: "flex items-center gap-[12px]", children: [
125
+ N ? /* @__PURE__ */ e(
99
126
  "button",
100
127
  {
101
128
  type: "button",
102
129
  "aria-label": "Back",
103
- onClick: v,
104
- className: E,
105
- children: /* @__PURE__ */ e(J, { size: 16 })
130
+ onClick: N,
131
+ className: L,
132
+ children: /* @__PURE__ */ e(ae, { size: 16 })
106
133
  }
107
134
  ) : null,
108
- x ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: x }) : null,
109
- /* @__PURE__ */ a("div", { className: "flex min-w-0 flex-1 items-baseline gap-[12px]", children: [
110
- /* @__PURE__ */ a("div", { className: "flex min-w-0 flex-1 items-baseline gap-[8px]", children: [
111
- /* @__PURE__ */ a("div", { className: "flex min-w-0 items-baseline gap-[8px]", children: [
112
- /* @__PURE__ */ e("span", { className: "flex min-w-0 max-w-full shrink-0", children: /* @__PURE__ */ e(
113
- z,
114
- {
115
- tooltip: o,
116
- tooltipWhenTruncated: !0,
117
- tooltipPlacement: "bottom",
118
- className: "min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold",
119
- children: o
120
- }
121
- ) }),
122
- d ? /* @__PURE__ */ e(
123
- z,
124
- {
125
- tooltip: d,
126
- tooltipWhenTruncated: !0,
127
- tooltipPlacement: "bottom",
128
- color: "secondary",
129
- className: "min-w-0 text-[13px]",
130
- children: d
131
- }
132
- ) : null
135
+ h ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: h }) : null,
136
+ E ? /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-center gap-[12px]", children: [
137
+ /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 flex-col gap-[2px]", children: [
138
+ /* @__PURE__ */ r("div", { className: "flex min-w-0 items-baseline gap-[8px]", children: [
139
+ _,
140
+ O
133
141
  ] }),
134
- f ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: f }) : null
142
+ z
135
143
  ] }),
136
- b ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-baseline", children: b }) : null
144
+ P
145
+ ] }) : /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-baseline gap-[12px]", children: [
146
+ /* @__PURE__ */ r("div", { className: "flex min-w-0 flex-1 items-baseline gap-[8px]", children: [
147
+ /* @__PURE__ */ r("div", { className: "flex min-w-0 items-baseline gap-[8px]", children: [
148
+ _,
149
+ z
150
+ ] }),
151
+ O
152
+ ] }),
153
+ P
137
154
  ] }),
138
155
  /* @__PURE__ */ e(
139
156
  "button",
140
157
  {
141
158
  type: "button",
142
159
  "aria-label": "Close",
143
- onClick: c,
144
- className: E,
145
- children: /* @__PURE__ */ e(K, { size: 10 })
160
+ onClick: d,
161
+ className: L,
162
+ children: /* @__PURE__ */ e(te, { size: 10 })
146
163
  }
147
164
  )
148
165
  ] }),
@@ -157,26 +174,27 @@ const P = 200, ee = (t) => typeof t == "number" ? `${t}px` : t, me = ({
157
174
  ]
158
175
  }
159
176
  ),
160
- /* @__PURE__ */ a(
177
+ f ? /* @__PURE__ */ e("div", { className: "shrink-0 px-[16px] pt-[16px] pb-[8px]", children: f }) : null,
178
+ /* @__PURE__ */ r(
161
179
  "div",
162
180
  {
163
- className: `min-h-0 flex-1 overflow-y-auto ${N && !A ? "px-[28px]" : ""}`,
181
+ className: `min-h-0 flex-1 overflow-y-auto ${g && !A ? "px-[28px]" : ""}`,
164
182
  children: [
165
- l == null ? void 0 : l.map((n, s) => /* @__PURE__ */ e(
166
- H,
183
+ t == null ? void 0 : t.map((n, c) => /* @__PURE__ */ e(
184
+ le,
167
185
  {
168
- id: `${T}-${s}`,
186
+ id: `${T}-${c}`,
169
187
  type: n.type,
170
188
  message: n.message,
171
- renderLink: B
189
+ renderLink: q
172
190
  },
173
- s
191
+ c
174
192
  )),
175
- Y
193
+ Q
176
194
  ]
177
195
  }
178
196
  ),
179
- h ? /* @__PURE__ */ e("div", { className: "border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]", children: h }) : null
197
+ v ? /* @__PURE__ */ e("div", { className: "border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]", children: v }) : null
180
198
  ]
181
199
  }
182
200
  )
@@ -187,7 +205,7 @@ const P = 200, ee = (t) => typeof t == "number" ? `${t}px` : t, me = ({
187
205
  );
188
206
  };
189
207
  export {
190
- me as SidePanel,
191
- me as default
208
+ ve as SidePanel,
209
+ ve as default
192
210
  };
193
211
  //# sourceMappingURL=SidePanel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SidePanel.js","sources":["../../src/components/SidePanel.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ShadowRootWrapper } from '../ShadowRootWrapper';\nimport type { AlertType } from './Alert';\nimport CalloutStrip from './CalloutStrip';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport EllipsisText from './Typography/EllipsisText';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport interface SidePanelProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n /** Secondary text, inline after the title. */\n subtitle?: React.ReactNode;\n /** Content at the end of the title row, after the subtitle (e.g. a status tag). */\n titleExtra?: React.ReactNode;\n /** Block paragraph below the title row, spanning the header width. Announced as the panel's description. */\n description?: React.ReactNode;\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Leading header slot, typically a logo or icon. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n footer?: React.ReactNode;\n /** Renders a back button before the header icon. */\n onBack?: () => void;\n /** Maximum panel width. Default: 1080. */\n maxWidth?: number | string;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `above-app-overlays` lifts the overlay stack clear of chrome pinned near max-int. */\n stacking?: 'default' | 'above-app-overlays';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of `description`. The message is markdown. */\n callouts?: { type?: AlertType; message: string }[];\n /** Routes root-relative links in `callouts` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n children: React.ReactNode;\n}\n\nconst TRANSITION_MS = 200;\n\nconst toCssSize = (value: number | string): string =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * A right-hand slide-in overlay panel (drawer) for inspecting or editing an entity\n * without leaving the page. Portals to `document.body`, locks background scroll and\n * traps keyboard focus while open (restoring both on close), dismisses on ESC\n * (topmost open overlay only), overlay click or the close button, and exposes header\n * (back/icon/title/subtitle/extra), scrollable body and optional footer slots.\n */\nconst SidePanel: React.FC<SidePanelProps> = ({\n open,\n onClose,\n title,\n subtitle,\n titleExtra,\n description,\n headerDivider = false,\n icon,\n headerExtra,\n footer,\n onBack,\n maxWidth = 1080,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n bodyPadding = true,\n stacking = 'default',\n callouts,\n renderLink,\n children,\n}) => {\n const calloutId = useId();\n const descriptionId = useId();\n const [isVisible, setIsVisible] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const {\n ref: handlePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n elevated: stacking === 'above-app-overlays',\n hostRef,\n });\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n setIsVisible(false);\n unmountTimerRef.current = setTimeout(() => {\n unmountTimerRef.current = null;\n setIsMounted(false);\n }, TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n };\n }, [open]);\n\n if (!isMounted) {\n return null;\n }\n\n const shownCallouts = callouts?.filter((callout) => callout.message.trim());\n const hasCallouts = !!shownCallouts?.length;\n const paddedBody = bodyPadding ? (\n <div className={hasCallouts ? 'p-[28px]' : 'py-[28px]'}>{children}</div>\n ) : (\n children\n );\n\n return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would\n // otherwise flatten our z-index and let sticky page elements paint over us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('sidepanel'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('sidepanel')\n }\n >\n <div className=\"fixed inset-0 z-[1000]\">\n <div\n aria-hidden=\"true\"\n onClick={onClose}\n className={`absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${\n isVisible ? 'opacity-100' : 'opacity-0'\n }`}\n />\n <div\n ref={handlePanelRef}\n role=\"dialog\"\n // Only the topmost overlay may claim it, or a screen reader can still\n // browse the one underneath.\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...(shownCallouts ?? []).map((_, index) => `${calloutId}-${index}`),\n description ? descriptionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n // Prefer aria-labelledby; only fall back to aria-label when it's absent.\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className=\"absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]\"\n style={{\n width: `min(calc(100% - 16px), ${toCssSize(maxWidth)})`,\n // Inline: Tailwind translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'translateX(0)' : 'translateX(calc(100% + 16px))',\n transition: `transform ${TRANSITION_MS}ms ease-in-out`,\n }}\n >\n <div\n className={`flex flex-col gap-[20px] px-[20px] py-[18px] ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex items-center gap-[12px]\">\n {onBack ? (\n <button\n type=\"button\"\n aria-label=\"Back\"\n onClick={onBack}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <ArrowLeftIcon size={16} />\n </button>\n ) : null}\n {icon ? (\n <span className=\"flex shrink-0 items-center\">{icon}</span>\n ) : null}\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[8px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n <span className=\"flex min-w-0 max-w-full shrink-0\">\n <EllipsisText\n tooltip={title}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n className=\"min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold\"\n >\n {title}\n </EllipsisText>\n </span>\n {subtitle ? (\n <EllipsisText\n tooltip={subtitle}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n color=\"secondary\"\n className=\"min-w-0 text-[13px]\"\n >\n {subtitle}\n </EllipsisText>\n ) : null}\n </div>\n {titleExtra ? (\n <span className=\"flex shrink-0 items-center\">\n {titleExtra}\n </span>\n ) : null}\n </div>\n {headerExtra ? (\n <span className=\"flex shrink-0 items-baseline\">\n {headerExtra}\n </span>\n ) : null}\n </div>\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={onClose}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n </div>\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n </div>\n {/* Callouts move the horizontal padding inward so their strips run full-bleed. */}\n <div\n className={`min-h-0 flex-1 overflow-y-auto ${bodyPadding && !hasCallouts ? 'px-[28px]' : ''}`}\n >\n {shownCallouts?.map((callout, index) => (\n <CalloutStrip\n key={index}\n id={`${calloutId}-${index}`}\n type={callout.type}\n message={callout.message}\n renderLink={renderLink}\n />\n ))}\n {paddedBody}\n </div>\n {footer ? (\n <div className=\"border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]\">\n {footer}\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default SidePanel;\nexport { SidePanel };\n"],"names":["TRANSITION_MS","toCssSize","value","SidePanel","open","onClose","title","subtitle","titleExtra","description","headerDivider","icon","headerExtra","footer","onBack","maxWidth","ariaLabel","ariaLabelledBy","bodyPadding","stacking","callouts","renderLink","children","calloutId","useId","descriptionId","isVisible","setIsVisible","useState","isMounted","setIsMounted","frameRef","useRef","unmountTimerRef","hostRef","handlePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","useEffect","shownCallouts","callout","hasCallouts","paddedBody","jsx","createPortal","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","OVERLAY_ICON_BUTTON_CLASSES","ArrowLeftIcon","EllipsisText","DismissIcon","CalloutStrip"],"mappings":"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"}
1
+ {"version":3,"file":"SidePanel.js","sources":["../../src/components/SidePanel.tsx"],"sourcesContent":["import React, { useEffect, useId, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { ShadowRootWrapper } from '../ShadowRootWrapper';\nimport type { AlertType } from './Alert';\nimport CalloutStrip from './CalloutStrip';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport EllipsisText from './Typography/EllipsisText';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport interface SidePanelProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n subtitle?: React.ReactNode;\n /** `below` stacks the subtitle under the title, so neither truncates the other. */\n subtitlePlacement?: 'inline' | 'below';\n /** Content at the end of the title row, after the subtitle (e.g. a status tag). */\n titleExtra?: React.ReactNode;\n /** Block paragraph below the title row, spanning the header width. Announced as the panel's description. */\n description?: React.ReactNode;\n /** Pinned between the header and the scrolling body. */\n toolbar?: React.ReactNode;\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Leading header slot, typically a logo or icon. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n footer?: React.ReactNode;\n /** Renders a back button before the header icon. */\n onBack?: () => void;\n /** Maximum panel width. Default: 1080. */\n maxWidth?: number | string;\n /** Accessible dialog name; required when `title` isn't a plain string. */\n 'aria-label'?: string;\n /** ID of a visible element naming the dialog (alternative to `aria-label`). */\n 'aria-labelledby'?: string;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `above-app-overlays` lifts the overlay stack clear of chrome pinned near max-int. */\n stacking?: 'default' | 'above-app-overlays';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of `description`. The message is markdown. */\n callouts?: { type?: AlertType; message: string }[];\n /** Routes root-relative links in `callouts` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n children: React.ReactNode;\n}\n\nconst TRANSITION_MS = 200;\n\nconst toCssSize = (value: number | string): string =>\n typeof value === 'number' ? `${value}px` : value;\n\n/**\n * A right-hand slide-in overlay panel (drawer) for inspecting or editing an entity\n * without leaving the page. Portals to `document.body`, locks background scroll and\n * traps keyboard focus while open (restoring both on close), dismisses on ESC\n * (topmost open overlay only), overlay click or the close button, and exposes header\n * (back/icon/title/subtitle/extra), scrollable body and optional footer slots.\n */\nconst SidePanel: React.FC<SidePanelProps> = ({\n open,\n onClose,\n title,\n subtitle,\n subtitlePlacement = 'inline',\n titleExtra,\n description,\n toolbar,\n headerDivider = false,\n icon,\n headerExtra,\n footer,\n onBack,\n maxWidth = 1080,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n bodyPadding = true,\n stacking = 'default',\n callouts,\n renderLink,\n children,\n}) => {\n const calloutId = useId();\n const descriptionId = useId();\n const [isVisible, setIsVisible] = useState(false);\n const [isMounted, setIsMounted] = useState(false);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hostRef = useRef<HTMLDivElement | null>(null);\n const {\n ref: handlePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n elevated: stacking === 'above-app-overlays',\n hostRef,\n });\n\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n frameRef.current = requestAnimationFrame(() => {\n frameRef.current = null;\n setIsVisible(true);\n });\n } else {\n setIsVisible(false);\n unmountTimerRef.current = setTimeout(() => {\n unmountTimerRef.current = null;\n setIsMounted(false);\n }, TRANSITION_MS);\n }\n return () => {\n if (frameRef.current !== null) {\n cancelAnimationFrame(frameRef.current);\n frameRef.current = null;\n }\n if (unmountTimerRef.current) {\n clearTimeout(unmountTimerRef.current);\n unmountTimerRef.current = null;\n }\n };\n }, [open]);\n\n if (!isMounted) {\n return null;\n }\n\n const shownCallouts = callouts?.filter((callout) => callout.message.trim());\n const hasCallouts = !!shownCallouts?.length;\n const paddedBody = bodyPadding ? (\n <div className={hasCallouts ? 'p-[28px]' : 'py-[28px]'}>{children}</div>\n ) : (\n children\n );\n\n const subtitleBelow = subtitlePlacement === 'below' && !!subtitle;\n const titleNode = (\n <span\n className={subtitleBelow ? 'flex min-w-0 shrink' : 'flex min-w-0 max-w-full shrink-0'}\n >\n <EllipsisText\n tooltip={title}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n className=\"min-w-0 text-[length:var(--malachite-font-size-15,15px)] font-semibold\"\n >\n {title}\n </EllipsisText>\n </span>\n );\n const subtitleNode = subtitle ? (\n <EllipsisText\n tooltip={subtitle}\n tooltipWhenTruncated\n tooltipPlacement=\"bottom\"\n color=\"secondary\"\n className=\"min-w-0 text-[13px]\"\n >\n {subtitle}\n </EllipsisText>\n ) : null;\n const titleExtraNode = titleExtra ? (\n <span className=\"flex shrink-0 items-center\">{titleExtra}</span>\n ) : null;\n const headerExtraNode = headerExtra ? (\n <span className=\"flex shrink-0 items-baseline\">{headerExtra}</span>\n ) : null;\n\n return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would\n // otherwise flatten our z-index and let sticky page elements paint over us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('sidepanel'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('sidepanel')\n }\n >\n <div className=\"fixed inset-0 z-[1000]\">\n <div\n aria-hidden=\"true\"\n onClick={onClose}\n className={`absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${\n isVisible ? 'opacity-100' : 'opacity-0'\n }`}\n />\n <div\n ref={handlePanelRef}\n role=\"dialog\"\n // Only the topmost overlay may claim it, or a screen reader can still\n // browse the one underneath.\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...(shownCallouts ?? []).map((_, index) => `${calloutId}-${index}`),\n description ? descriptionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n tabIndex={-1}\n // Prefer aria-labelledby; only fall back to aria-label when it's absent.\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className=\"absolute top-[8px] right-[8px] bottom-[8px] flex flex-col overflow-hidden rounded-[20px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-lg)]\"\n style={{\n width: `min(calc(100% - 16px), ${toCssSize(maxWidth)})`,\n // Inline: Tailwind translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'translateX(0)' : 'translateX(calc(100% + 16px))',\n transition: `transform ${TRANSITION_MS}ms ease-in-out`,\n }}\n >\n <div\n className={`flex flex-col gap-[20px] px-[20px] py-[18px] ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex items-center gap-[12px]\">\n {onBack ? (\n <button\n type=\"button\"\n aria-label=\"Back\"\n onClick={onBack}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <ArrowLeftIcon size={16} />\n </button>\n ) : null}\n {icon ? (\n <span className=\"flex shrink-0 items-center\">{icon}</span>\n ) : null}\n {subtitleBelow ? (\n <div className=\"flex min-w-0 flex-1 items-center gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 flex-col gap-[2px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n {titleNode}\n {titleExtraNode}\n </div>\n {subtitleNode}\n </div>\n {headerExtraNode}\n </div>\n ) : (\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[12px]\">\n <div className=\"flex min-w-0 flex-1 items-baseline gap-[8px]\">\n <div className=\"flex min-w-0 items-baseline gap-[8px]\">\n {titleNode}\n {subtitleNode}\n </div>\n {titleExtraNode}\n </div>\n {headerExtraNode}\n </div>\n )}\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={onClose}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n </div>\n {description ? (\n <div\n id={descriptionId}\n className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\"\n >\n {description}\n </div>\n ) : null}\n </div>\n {toolbar ? (\n <div className=\"shrink-0 px-[16px] pt-[16px] pb-[8px]\">{toolbar}</div>\n ) : null}\n {/* Callouts move the horizontal padding inward so their strips run full-bleed. */}\n <div\n className={`min-h-0 flex-1 overflow-y-auto ${bodyPadding && !hasCallouts ? 'px-[28px]' : ''}`}\n >\n {shownCallouts?.map((callout, index) => (\n <CalloutStrip\n key={index}\n id={`${calloutId}-${index}`}\n type={callout.type}\n message={callout.message}\n renderLink={renderLink}\n />\n ))}\n {paddedBody}\n </div>\n {footer ? (\n <div className=\"border-0 border-t border-solid border-[var(--malachite-card-border)] px-[24px] py-[16px]\">\n {footer}\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default SidePanel;\nexport { SidePanel };\n"],"names":["TRANSITION_MS","toCssSize","value","SidePanel","open","onClose","title","subtitle","subtitlePlacement","titleExtra","description","toolbar","headerDivider","icon","headerExtra","footer","onBack","maxWidth","ariaLabel","ariaLabelledBy","bodyPadding","stacking","callouts","renderLink","children","calloutId","useId","descriptionId","isVisible","setIsVisible","useState","isMounted","setIsMounted","frameRef","useRef","unmountTimerRef","hostRef","handlePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","useEffect","shownCallouts","callout","hasCallouts","paddedBody","jsx","subtitleBelow","titleNode","EllipsisText","subtitleNode","titleExtraNode","headerExtraNode","createPortal","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","OVERLAY_ICON_BUTTON_CLASSES","ArrowLeftIcon","DismissIcon","CalloutStrip"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { jsxs as o, jsx as r, Fragment as p } from "react/jsx-runtime";
2
+ import u from "./CustomIcons/CheckCircleFilled.js";
3
+ import x from "./CustomIcons/ErrorCircleFilled.js";
4
+ import g from "./CustomIcons/InfoCircleFilled.js";
5
+ import f from "./CustomIcons/WarningCircleFilled.js";
6
+ import h from "./Spinner.js";
7
+ const b = {
8
+ success: "bg-[var(--malachite-alert-success-background)] text-[var(--malachite-alert-success-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-success-foreground)_70%,var(--malachite-text-primary))]",
9
+ neutral: "bg-[var(--malachite-alert-info-background)] text-[var(--malachite-alert-info-foreground)]",
10
+ warning: "bg-[var(--malachite-alert-warning-background)] text-[var(--malachite-alert-warning-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-warning-foreground)_70%,var(--malachite-text-primary))]",
11
+ error: "bg-[var(--malachite-alert-error-background)] text-[var(--malachite-alert-error-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-error-foreground)_70%,var(--malachite-text-primary))]"
12
+ }, v = {
13
+ success: u,
14
+ neutral: g,
15
+ warning: f,
16
+ error: x
17
+ }, _ = "border border-solid border-[var(--malachite-card-border)] supports-[color:color-mix(in_srgb,red,red)]:border-[color-mix(in_srgb,currentColor_24%,transparent)]", F = ({
18
+ label: n,
19
+ detail: l,
20
+ tone: i = "neutral",
21
+ icon: s,
22
+ busy: e = !1,
23
+ live: a = !1,
24
+ "aria-label": c,
25
+ "aria-labelledby": t,
26
+ className: m = ""
27
+ }) => {
28
+ const d = v[i];
29
+ return /* @__PURE__ */ o(
30
+ "span",
31
+ {
32
+ role: a ? "status" : void 0,
33
+ "aria-label": a && !t ? c : void 0,
34
+ "aria-labelledby": a ? t : void 0,
35
+ "aria-busy": e || void 0,
36
+ className: `inline-flex items-center gap-[6px] h-[28px] max-w-full min-w-0 pl-[8px] pr-[10px] rounded-full overflow-hidden whitespace-nowrap text-[12px] font-medium ${_} ${b[i]} ${m}`,
37
+ children: [
38
+ /* @__PURE__ */ r(
39
+ "span",
40
+ {
41
+ "aria-hidden": "true",
42
+ className: `inline-flex shrink-0 items-center justify-center size-[16px] ${e ? "" : "[&_svg]:size-full!"}`,
43
+ children: e ? /* @__PURE__ */ r(h, { size: "xxxsmall" }) : s ?? /* @__PURE__ */ r(d, { size: 16 })
44
+ }
45
+ ),
46
+ /* @__PURE__ */ o("span", { className: "min-w-0 overflow-hidden text-ellipsis", children: [
47
+ n,
48
+ l ? /* @__PURE__ */ o(p, { children: [
49
+ " · ",
50
+ /* @__PURE__ */ r("span", { className: "font-mono", children: l })
51
+ ] }) : null
52
+ ] })
53
+ ]
54
+ }
55
+ );
56
+ };
57
+ export {
58
+ F as StatusPill,
59
+ F as default
60
+ };
61
+ //# sourceMappingURL=StatusPill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusPill.js","sources":["../../src/components/StatusPill.tsx"],"sourcesContent":["import React from 'react';\nimport CheckCircleFilled, { type IconProps } from './CustomIcons/CheckCircleFilled';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport InfoCircleFilled from './CustomIcons/InfoCircleFilled';\nimport WarningCircleFilled from './CustomIcons/WarningCircleFilled';\nimport Spinner from './Spinner';\n\nexport type StatusPillTone = 'success' | 'neutral' | 'warning' | 'error';\n\nexport interface StatusPillProps {\n label: string;\n /** Set in the mono face after a `·`. */\n detail?: string;\n tone?: StatusPillTone;\n icon?: React.ReactNode;\n busy?: boolean;\n /** Makes it a `status` live region. Off by default, as on `Alert`. */\n live?: boolean;\n /** Names the live region; only applies with `live`. */\n 'aria-label'?: string;\n /** Only applies with `live`. */\n 'aria-labelledby'?: string;\n className?: string;\n}\n\n// Text leans 30% toward the primary colour so every tone holds 4.5:1 on its tint.\nconst TONE_CLASSES: Record<StatusPillTone, string> = {\n success:\n 'bg-[var(--malachite-alert-success-background)] text-[var(--malachite-alert-success-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-success-foreground)_70%,var(--malachite-text-primary))]',\n neutral:\n 'bg-[var(--malachite-alert-info-background)] text-[var(--malachite-alert-info-foreground)]',\n warning:\n 'bg-[var(--malachite-alert-warning-background)] text-[var(--malachite-alert-warning-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-warning-foreground)_70%,var(--malachite-text-primary))]',\n error: 'bg-[var(--malachite-alert-error-background)] text-[var(--malachite-alert-error-foreground)] supports-[color:color-mix(in_srgb,red,red)]:text-[color-mix(in_srgb,var(--malachite-alert-error-foreground)_70%,var(--malachite-text-primary))]',\n};\n\nconst TONE_ICONS: Record<StatusPillTone, React.FC<IconProps>> = {\n success: CheckCircleFilled,\n neutral: InfoCircleFilled,\n warning: WarningCircleFilled,\n error: ErrorCircleFilled,\n};\n\nconst BORDER =\n 'border border-solid border-[var(--malachite-card-border)] supports-[color:color-mix(in_srgb,red,red)]:border-[color-mix(in_srgb,currentColor_24%,transparent)]';\n\nconst StatusPill: React.FC<StatusPillProps> = ({\n label,\n detail,\n tone = 'neutral',\n icon,\n busy = false,\n live = false,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n}) => {\n const ToneIcon = TONE_ICONS[tone];\n\n return (\n <span\n role={live ? 'status' : undefined}\n aria-label={live && !ariaLabelledBy ? ariaLabel : undefined}\n aria-labelledby={live ? ariaLabelledBy : undefined}\n aria-busy={busy || undefined}\n className={`inline-flex items-center gap-[6px] h-[28px] max-w-full min-w-0 pl-[8px] pr-[10px] rounded-full overflow-hidden whitespace-nowrap text-[12px] font-medium ${BORDER} ${TONE_CLASSES[tone]} ${className}`}\n >\n <span\n aria-hidden=\"true\"\n className={`inline-flex shrink-0 items-center justify-center size-[16px] ${busy ? '' : '[&_svg]:size-full!'}`}\n >\n {busy ? <Spinner size=\"xxxsmall\" /> : (icon ?? <ToneIcon size={16} />)}\n </span>\n <span className=\"min-w-0 overflow-hidden text-ellipsis\">\n {label}\n {detail ? (\n <>\n {' · '}\n <span className=\"font-mono\">{detail}</span>\n </>\n ) : null}\n </span>\n </span>\n );\n};\n\nexport default StatusPill;\nexport { StatusPill };\n"],"names":["TONE_CLASSES","TONE_ICONS","CheckCircleFilled","InfoCircleFilled","WarningCircleFilled","ErrorCircleFilled","BORDER","StatusPill","label","detail","tone","icon","busy","live","ariaLabel","ariaLabelledBy","className","ToneIcon","jsxs","jsx","Spinner","Fragment"],"mappings":";;;;;;AA0BA,MAAMA,IAA+C;AAAA,EACjD,SACI;AAAA,EACJ,SACI;AAAA,EACJ,SACI;AAAA,EACJ,OAAO;AACX,GAEMC,IAA0D;AAAA,EAC5D,SAASC;AAAA,EACT,SAASC;AAAA,EACT,SAASC;AAAA,EACT,OAAOC;AACX,GAEMC,IACF,kKAEEC,IAAwC,CAAC;AAAA,EAC3C,OAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,MAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,MAAAC,IAAO;AAAA,EACP,cAAcC;AAAA,EACd,mBAAmBC;AAAA,EACnB,WAAAC,IAAY;AAChB,MAAM;AACF,QAAMC,IAAWhB,EAAWS,CAAI;AAEhC,SACI,gBAAAQ;AAAA,IAAC;AAAA,IAAA;AAAA,MACG,MAAML,IAAO,WAAW;AAAA,MACxB,cAAYA,KAAQ,CAACE,IAAiBD,IAAY;AAAA,MAClD,mBAAiBD,IAAOE,IAAiB;AAAA,MACzC,aAAWH,KAAQ;AAAA,MACnB,WAAW,4JAA4JN,CAAM,IAAIN,EAAaU,CAAI,CAAC,IAAIM,CAAS;AAAA,MAEhN,UAAA;AAAA,QAAA,gBAAAG;AAAA,UAAC;AAAA,UAAA;AAAA,YACG,eAAY;AAAA,YACZ,WAAW,gEAAgEP,IAAO,KAAK,oBAAoB;AAAA,YAE1G,UAAAA,IAAO,gBAAAO,EAACC,GAAA,EAAQ,MAAK,YAAW,IAAMT,KAAQ,gBAAAQ,EAACF,GAAA,EAAS,MAAM,GAAA,CAAI;AAAA,UAAA;AAAA,QAAA;AAAA,QAEvE,gBAAAC,EAAC,QAAA,EAAK,WAAU,yCACX,UAAA;AAAA,UAAAV;AAAA,UACAC,IACG,gBAAAS,EAAAG,GAAA,EACK,UAAA;AAAA,YAAA;AAAA,YACD,gBAAAF,EAAC,QAAA,EAAK,WAAU,aAAa,UAAAV,EAAA,CAAO;AAAA,UAAA,EAAA,CACxC,IACA;AAAA,QAAA,EAAA,CACR;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGZ;"}