@stackone/malachite 2.75.0 → 2.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/COMPONENTS.md CHANGED
@@ -34,7 +34,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
34
34
  ## Feedback & status
35
35
 
36
36
  - **`ChangeReview`** — Reviewing changes a machine made. `ChangeReview.Item` attaches to one changed thing: it names what changed with an `assistant` Tag, shows the value it displaced struck through, and offers approve and deny as two equally reachable icon buttons — a review affordance that made keeping easier than rejecting would not be one. Given `children`, it wraps the field the change is annotating: the tag/label/actions become a header band above it and the before/after line moves below, so "Was …" reads next to the value it describes instead of stacked with the header; without children it renders as the standalone card it always has. `ChangeReview.Summary` counts what is still undecided across the whole form, which is what a per-item control cannot do and what a caller gates a save on; at zero it either says so or collapses to nothing. `ChangeReview.Removed` is for something the assistant took out: a dashed, tinted card listing what would be lost, because a removal that simply vanished would leave nothing to reject. `ChangeReview.Jump` is a chip an assistant turn carries to point at a field it touched. _Key props:_ `Item`: `label`, `before`, `after`, `kind` (`changed` | `added` | `removed`), `origin`, `children`, `onApprove`, `onDeny`, `disabled`, `className`. `Summary`: `count`, `origin`, `onApproveAll`, `onDenyAll`, `disabled`, `settledMessage`, `className`. `Removed`: `title`, `details` (`{label, value}[]`), `onRestore`, `onDiscard`, `restoreLabel`, `discardLabel`, `origin`, `disabled`, `className`. `Jump`: `label`, `onClick`, `disabled`, `className`. `Item` also takes `onPreviewRevert(previewing)`, fired on hover and on focus.
37
- - **`Alert`** — Inline alert/callout. Four severities (info, success, warning, error) plus `assistant` — a violet, sparkle-marked ground that says a machine wrote the message rather than that anything is wrong, so provenance never has to borrow a severity colour. `action` puts a control at the end — the link or button that resolves what the alert reports — and `icon` replaces the status icon; an svg that paints with `currentColor` (a CustomIcon) is drawn in the colour and size of the built-in one. _Key props:_ `type`, `message`, `lead` (a bold sentence the message runs on from; plain text), `layout` (`inline` | `banner` — a 48px page-wide band with a 16px icon, for `WizardLayout`'s `banner` slot; an expandable alert stays inline), `align` (`start` | `center`, the banner icon and text gathered mid-band), `action`, `icon`, `hasMargin`, `live` (makes the message a live region — `role="alert"` for error/warning, announced as it mounts; `status` otherwise, announced when its `message` changes, so keep it mounted; off by default), `renderLink` (routes root-relative links in `message` through the app’s router, as `MarkdownBlock` does), `children` (expandable body), `isExpanded`, `onToggle`, `className`.
37
+ - **`Alert`** — Inline alert/callout. Four severities (info, success, warning, error) plus `assistant` — a violet, sparkle-marked ground that says a machine wrote the message rather than that anything is wrong, so provenance never has to borrow a severity colour. `action` puts a control at the end — the link or button that resolves what the alert reports — and `icon` replaces the status icon; an svg that paints with `currentColor` (a CustomIcon) is drawn in the colour and size of the built-in one. _Key props:_ `type`, `message`, `lead` (a bold sentence the message runs on from; plain text), `address` (`{ text, emphasis? }`: an address the message runs on into, whole and in mono; `emphasis`, an optional substring to bold wherever it occurs, often the registrable domain) and `addressSuffix` (markdown after the address, joined without a space when it opens with any punctuation character), `layout` (`inline` | `banner` — a 48px page-wide band with a 16px icon, for `WizardLayout`'s `banner` slot; an expandable alert stays inline), `align` (`start` | `center`, the banner icon and text gathered mid-band), `action`, `icon`, `hasMargin`, `live` (makes the message a live region — `role="alert"` for error/warning, announced as it mounts; `status` otherwise, announced when its `message` changes, so keep it mounted; off by default), `renderLink` (routes root-relative links in `message` through the app’s router, as `MarkdownBlock` does), `children` (expandable body), `isExpanded`, `onToggle`, `className`.
38
38
  - **`IconIndicator`** — A non-interactive icon that carries a meaning, such as a capability shown on a page that cannot switch it on. Same square as an icon-only `Button` at each `size`, so it lines up where a sibling view shows the button. Renders `role="img"`, named by `aria-label`; with a `tooltip` it takes focus so the tooltip is reachable by keyboard. Reach for it instead of a hand-sized `<span>` around an icon. _Key props:_ `icon`, `aria-label`, `tooltip`, `size`.
39
39
  - **`IconBadge`** — A small filled tile carrying a 12px glyph, for a dialog or panel header such as `SidePanel`’s `icon`. Decorative and always `aria-hidden`: the title beside it carries the meaning, so reach for `IconIndicator` when the icon itself has to say something. `variant` picks a semantic fill (`default` neutral, `accent` the interaction colour, `warning`, `destructive`, `success`) rather than taking a colour, and the glyph is drawn in the card background. `ConfirmationDialog` draws its badge with it. _Key props:_ `icon`, `variant` (`default` | `accent` | `warning` | `destructive` | `success`), `className`.
40
40
  - **`StatusBadge`** — Large status indicator (e.g. success checkmark) for terminal/confirmation screens. _Key props:_ `type`.
@@ -1,16 +1,16 @@
1
- import { jsxs as s, jsx as e, Fragment as y } from "react/jsx-runtime";
2
- import { useState as W } from "react";
3
- import { Button as H } from "./Button.js";
4
- import M from "./CustomIcons/CaretDownIcon.js";
5
- import T from "./CustomIcons/CaretUpIcon.js";
6
- import Y from "./CustomIcons/CheckCircleFilled.js";
7
- import $ from "./CustomIcons/ErrorCircleFilled.js";
8
- import D from "./CustomIcons/InfoCircleFilled.js";
9
- import L from "./CustomIcons/SparkleIcon.js";
10
- import U from "./CustomIcons/WarningCircleFilled.js";
11
- import q from "./Typography/MarkdownBlock.js";
12
- import { getTextColor as j, getFontSize as G } from "./Typography/textStyles.js";
13
- const p = (r) => {
1
+ import { jsxs as i, jsx as e, Fragment as u } from "react/jsx-runtime";
2
+ import M, { useState as P } from "react";
3
+ import { Button as U } from "./Button.js";
4
+ import Y from "./CustomIcons/CaretDownIcon.js";
5
+ import $ from "./CustomIcons/CaretUpIcon.js";
6
+ import D from "./CustomIcons/CheckCircleFilled.js";
7
+ import L from "./CustomIcons/ErrorCircleFilled.js";
8
+ import q from "./CustomIcons/InfoCircleFilled.js";
9
+ import G from "./CustomIcons/SparkleIcon.js";
10
+ import J from "./CustomIcons/WarningCircleFilled.js";
11
+ import E from "./Typography/MarkdownBlock.js";
12
+ import { getTextColor as z, getFontSize as K } from "./Typography/textStyles.js";
13
+ const g = (r) => {
14
14
  switch (r) {
15
15
  case "info":
16
16
  return "primary";
@@ -27,147 +27,186 @@ const p = (r) => {
27
27
  default:
28
28
  return "primary";
29
29
  }
30
- }, a = {
30
+ }, m = {
31
31
  width: "13px",
32
32
  height: "13px",
33
33
  flexShrink: 0
34
- }, o = {
34
+ }, h = {
35
35
  info: "var(--malachite-alert-info-foreground)",
36
36
  success: "var(--malachite-alert-success-foreground)",
37
37
  error: "var(--malachite-alert-error-foreground)",
38
38
  warning: "var(--malachite-alert-warning-foreground)",
39
39
  assistant: "var(--malachite-alert-assistant-foreground)"
40
- }, _ = {
41
- info: /* @__PURE__ */ e(D, { style: { ...a, color: o.info } }),
42
- success: /* @__PURE__ */ e(Y, { style: { ...a, color: o.success } }),
43
- error: /* @__PURE__ */ e($, { style: { ...a, color: o.error } }),
44
- warning: /* @__PURE__ */ e(U, { style: { ...a, color: o.warning } }),
40
+ }, F = {
41
+ info: /* @__PURE__ */ e(q, { style: { ...m, color: h.info } }),
42
+ success: /* @__PURE__ */ e(D, { style: { ...m, color: h.success } }),
43
+ error: /* @__PURE__ */ e(L, { style: { ...m, color: h.error } }),
44
+ warning: /* @__PURE__ */ e(J, { style: { ...m, color: h.warning } }),
45
45
  // The same sparkle the control that produced the message carries, so the two read as
46
46
  // one thread rather than two unrelated affordances.
47
- assistant: /* @__PURE__ */ e(L, { style: { ...a, color: o.assistant } })
48
- }, J = { ...a, width: "16px", height: "16px" }, S = (r, t, l = !1) => !t && !l ? _[r] : /* @__PURE__ */ e(
47
+ assistant: /* @__PURE__ */ e(G, { style: { ...m, color: h.assistant } })
48
+ }, Q = { ...m, width: "16px", height: "16px" }, S = (r, l, t = !1) => !l && !t ? F[r] : /* @__PURE__ */ e(
49
49
  "span",
50
50
  {
51
51
  className: "alert-status-icon inline-flex shrink-0 [&_svg]:size-full!",
52
- style: { ...l ? J : a, color: o[r] },
53
- children: t || _[r]
52
+ style: { ...t ? Q : m, color: h[r] },
53
+ children: l || F[r]
54
54
  }
55
- ), v = ({ text: r, type: t, lead: l, renderLink: c }) => l ? /* @__PURE__ */ s("div", { className: "alert-lead", children: [
56
- /* @__PURE__ */ e(
57
- "strong",
58
- {
59
- style: {
60
- color: j(p(t)),
61
- fontSize: G("small"),
62
- fontWeight: 600
63
- },
64
- children: l
65
- }
66
- ),
67
- " ",
68
- /* @__PURE__ */ e(v, { text: r, type: t, renderLink: c })
69
- ] }) : /* @__PURE__ */ e(
70
- q,
55
+ ), V = ({ text: r, emphasis: l }) => {
56
+ if (!l)
57
+ return [{ text: r, bold: !1, offset: 0 }];
58
+ const t = [], a = (n, s, o) => {
59
+ n && t.push({ text: n, bold: s, offset: o });
60
+ }, c = r.split(l);
61
+ return c.reduce((n, s, o) => (a(s, !1, n), o < c.length - 1 && a(l, !0, n + s.length), n + s.length + l.length), 0), t;
62
+ }, X = ({ address: r, color: l }) => /* @__PURE__ */ e(
63
+ "code",
71
64
  {
72
- text: r,
73
- color: p(t),
74
- size: "small",
75
- omitMargin: !0,
76
- renderLink: c
65
+ className: "alert-address",
66
+ style: {
67
+ fontFamily: "var(--malachite-font-mono, monospace)",
68
+ fontSize: "0.9em",
69
+ color: l,
70
+ overflowWrap: "anywhere"
71
+ },
72
+ children: V(r).map(
73
+ (t) => t.bold ? /* @__PURE__ */ e("strong", { style: { fontWeight: 600 }, children: t.text }, t.offset) : /* @__PURE__ */ e(M.Fragment, { children: t.text }, t.offset)
74
+ )
77
75
  }
78
- ), ie = ({
76
+ ), Z = new RegExp("^\\p{P}", "u"), j = ({ text: r, type: l, lead: t, address: a, addressSuffix: c, renderLink: n }) => {
77
+ const s = z(g(l)), o = /* @__PURE__ */ e(
78
+ E,
79
+ {
80
+ text: r,
81
+ color: g(l),
82
+ size: "small",
83
+ omitMargin: !0,
84
+ renderLink: n
85
+ }
86
+ );
87
+ return !t && !a ? o : /* @__PURE__ */ i("div", { className: "alert-lead", children: [
88
+ t ? /* @__PURE__ */ i(u, { children: [
89
+ /* @__PURE__ */ e("strong", { style: { color: s, fontSize: K("small"), fontWeight: 600 }, children: t }),
90
+ " "
91
+ ] }) : null,
92
+ o,
93
+ a ? /* @__PURE__ */ i(u, { children: [
94
+ " ",
95
+ /* @__PURE__ */ e(X, { address: a, color: s })
96
+ ] }) : null,
97
+ a && c ? /* @__PURE__ */ i(u, { children: [
98
+ Z.test(c) ? "" : " ",
99
+ /* @__PURE__ */ e(
100
+ E,
101
+ {
102
+ text: c,
103
+ color: g(l),
104
+ size: "small",
105
+ omitMargin: !0,
106
+ renderLink: n
107
+ }
108
+ )
109
+ ] }) : null
110
+ ] });
111
+ }, he = ({
79
112
  type: r = "info",
80
- message: t,
81
- hasMargin: l = !0,
82
- className: c,
83
- children: g,
84
- isExpanded: x,
85
- onToggle: h,
86
- action: m,
87
- icon: w,
88
- live: E = !1,
89
- renderLink: N,
90
- layout: k = "inline",
113
+ message: l,
114
+ hasMargin: t = !0,
115
+ className: a,
116
+ children: c,
117
+ isExpanded: n,
118
+ onToggle: s,
119
+ action: o,
120
+ icon: N,
121
+ live: O = !1,
122
+ renderLink: w,
123
+ layout: W = "inline",
91
124
  lead: C,
92
- align: B = "start"
125
+ address: b,
126
+ addressSuffix: y,
127
+ align: k = "start"
93
128
  }) => {
94
- const n = !!g, f = k === "banner" && !n, u = f && B === "center", b = E ? r === "error" || r === "warning" ? "alert" : "status" : void 0, [F, z] = W(!1), i = x !== void 0 ? x : F, O = () => {
95
- const d = !i;
96
- x === void 0 && z(d), h == null || h(d);
129
+ const d = !!c, p = W === "banner" && !d, v = p && k === "center", _ = O ? r === "error" || r === "warning" ? "alert" : "status" : void 0, [A, B] = P(!1), f = n !== void 0 ? n : A, T = () => {
130
+ const x = !f;
131
+ n === void 0 && B(x), s == null || s(x);
97
132
  }, I = [
98
133
  "alert-base",
99
134
  `alert-${r}`,
100
135
  "flex",
101
136
  "w-full",
102
137
  // Ensure full width
103
- f ? "alert-banner" : n && i ? "flex-col" : "gap-2 items-center min-h-[2rem]",
104
- l ? "" : "alert-no-margin",
105
- u ? "text-center" : "text-left",
106
- f ? "" : n ? "rounded-xl !p-0" : "!px-2.5 !py-1.5",
138
+ p ? "alert-banner" : d && f ? "flex-col" : "gap-2 items-center min-h-[2rem]",
139
+ t ? "" : "alert-no-margin",
140
+ v ? "text-center" : "text-left",
141
+ p ? "" : d ? "rounded-xl !p-0" : "!px-2.5 !py-1.5",
107
142
  // Slightly more vertical padding for centering
108
- c
109
- ].filter(Boolean).join(" "), A = [
143
+ a
144
+ ].filter(Boolean).join(" "), R = [
110
145
  "flex items-center justify-between w-full",
111
- n ? "gap-2 px-2.5 py-1" : "gap-2",
112
- n && i ? "rounded-t-xl" : n ? "rounded-xl" : ""
113
- ].filter(Boolean).join(" "), R = ["w-full", "overflow-hidden"].filter(Boolean).join(" ");
114
- if (!n) {
115
- const d = /* @__PURE__ */ s(y, { children: [
116
- S(r, w, f),
117
- /* @__PURE__ */ e("div", { className: u ? "flex items-center" : "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: b, children: /* @__PURE__ */ e(
118
- v,
146
+ d ? "gap-2 px-2.5 py-1" : "gap-2",
147
+ d && f ? "rounded-t-xl" : d ? "rounded-xl" : ""
148
+ ].filter(Boolean).join(" "), H = ["w-full", "overflow-hidden"].filter(Boolean).join(" ");
149
+ if (!d) {
150
+ const x = /* @__PURE__ */ i(u, { children: [
151
+ S(r, N, p),
152
+ /* @__PURE__ */ e("div", { className: v ? "flex items-center" : "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: _, children: /* @__PURE__ */ e(
153
+ j,
119
154
  {
120
- text: t,
155
+ text: l,
121
156
  type: r,
122
157
  lead: C,
123
- renderLink: N
158
+ address: b,
159
+ addressSuffix: y,
160
+ renderLink: w
124
161
  }
125
162
  ) }) })
126
163
  ] });
127
- return /* @__PURE__ */ s("div", { className: I, children: [
128
- u ? (
164
+ return /* @__PURE__ */ i("div", { className: I, children: [
165
+ v ? (
129
166
  // Its own group, so an `action` stays at the end while this sits mid-band.
130
- /* @__PURE__ */ e("div", { className: "alert-centred flex-1 flex items-center justify-center gap-[10px]", children: d })
131
- ) : d,
132
- m && /* @__PURE__ */ e("div", { className: "alert-action shrink-0 flex items-center", children: m })
167
+ /* @__PURE__ */ e("div", { className: "alert-centred flex-1 flex items-center justify-center gap-[10px]", children: x })
168
+ ) : x,
169
+ o && /* @__PURE__ */ e("div", { className: "alert-action shrink-0 flex items-center", children: o })
133
170
  ] });
134
171
  }
135
- return /* @__PURE__ */ s("div", { className: `${I} alert-expandable`, children: [
136
- /* @__PURE__ */ s("div", { className: A, children: [
137
- /* @__PURE__ */ s("div", { className: "flex-1 flex gap-2 items-center", children: [
138
- S(r, w),
139
- /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: b, children: /* @__PURE__ */ e(
140
- v,
172
+ return /* @__PURE__ */ i("div", { className: `${I} alert-expandable`, children: [
173
+ /* @__PURE__ */ i("div", { className: R, children: [
174
+ /* @__PURE__ */ i("div", { className: "flex-1 flex gap-2 items-center", children: [
175
+ S(r, N),
176
+ /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: _, children: /* @__PURE__ */ e(
177
+ j,
141
178
  {
142
- text: t,
179
+ text: l,
143
180
  lead: C,
181
+ address: b,
182
+ addressSuffix: y,
144
183
  type: r,
145
- renderLink: N
184
+ renderLink: w
146
185
  }
147
186
  ) }) })
148
187
  ] }),
149
- /* @__PURE__ */ s("div", { className: "flex items-center gap-2", children: [
150
- m && /* @__PURE__ */ e("div", { className: "alert-action flex items-center", children: m }),
188
+ /* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
189
+ o && /* @__PURE__ */ e("div", { className: "alert-action flex items-center", children: o }),
151
190
  /* @__PURE__ */ e(
152
- H,
191
+ U,
153
192
  {
154
193
  variant: "no-style",
155
194
  size: "xsmall",
156
- onClick: O,
157
- "aria-label": i ? "Collapse" : "Expand",
195
+ onClick: T,
196
+ "aria-label": f ? "Collapse" : "Expand",
158
197
  style: {
159
- color: j(p(r))
198
+ color: z(g(r))
160
199
  },
161
- children: i ? /* @__PURE__ */ e(T, { style: { minWidth: "13px", minHeight: "13px" } }) : /* @__PURE__ */ e(M, { style: { minWidth: "13px", minHeight: "13px" } })
200
+ children: f ? /* @__PURE__ */ e($, { style: { minWidth: "13px", minHeight: "13px" } }) : /* @__PURE__ */ e(Y, { style: { minWidth: "13px", minHeight: "13px" } })
162
201
  }
163
202
  )
164
203
  ] })
165
204
  ] }),
166
- i && /* @__PURE__ */ e(y, { children: /* @__PURE__ */ e("div", { className: R, children: /* @__PURE__ */ e("div", { className: "bg-white rounded-[var(--malachite-radius-10,10px)] shadow-[0px_1px_0px_0px_rgba(0,0,0,0.15)] border border-[#e8e8e8] border-solid mx-2 mb-2 max-h-[553px] overflow-y-auto", children: g }) }) })
205
+ f && /* @__PURE__ */ e(u, { children: /* @__PURE__ */ e("div", { className: H, children: /* @__PURE__ */ e("div", { className: "bg-white rounded-[var(--malachite-radius-10,10px)] shadow-[0px_1px_0px_0px_rgba(0,0,0,0.15)] border border-[#e8e8e8] border-solid mx-2 mb-2 max-h-[553px] overflow-y-auto", children: c }) }) })
167
206
  ] });
168
207
  };
169
208
  export {
170
- ie as Alert,
171
- ie as default
209
+ he as Alert,
210
+ he as default
172
211
  };
173
212
  //# sourceMappingURL=Alert.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Alert.js","sources":["../../src/components/Alert.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Button, ButtonVariant } from './Button';\nimport CaretDownIcon from './CustomIcons/CaretDownIcon';\nimport CaretUpIcon from './CustomIcons/CaretUpIcon';\nimport CheckCircleFilled from './CustomIcons/CheckCircleFilled';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport InfoCircleFilled from './CustomIcons/InfoCircleFilled';\nimport SparkleIcon from './CustomIcons/SparkleIcon';\nimport WarningCircleFilled from './CustomIcons/WarningCircleFilled';\nimport type { RenderLink } from './PageLayout/types';\nimport MarkdownBlock from './Typography/MarkdownBlock';\nimport type { TextColor } from './Typography/Text';\nimport { getFontSize, getTextColor } from './Typography/textStyles';\n\nexport type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';\n\nexport type AlertLayout = 'inline' | 'banner';\n\ninterface AlertButtonConfig {\n label: string;\n onClick: () => void;\n variant?: ButtonVariant;\n icon?: React.ReactNode;\n}\n\ninterface AlertProps {\n type?: AlertType;\n message: string;\n hasMargin?: boolean;\n className?: string;\n children?: React.ReactNode;\n isExpanded?: boolean;\n onToggle?: (expanded: boolean) => void;\n /** A control at the end of the alert — a link or button that resolves what it reports. */\n action?: React.ReactNode;\n /** Replaces the type's status icon: an svg painting with `currentColor`, such as a CustomIcon,\n * is drawn in the type's colour at the same size. */\n icon?: React.ReactNode;\n /** Makes its message a live region: `role=\"alert\"` for error and warning, `status` otherwise.\n * Screen readers reliably announce an `alert` as it mounts; a `status` is read when its\n * `message` changes, so keep a live info or success alert mounted. Off by default. */\n live?: boolean;\n /** Routes root-relative links in `message` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n /** `banner`: a 48px page-wide band. Applies only without `children`. */\n layout?: AlertLayout;\n /** `center` gathers a banner's icon and text in the middle of the band, for a wide page. */\n align?: 'start' | 'center';\n /** A bold sentence the message runs on from. Plain text, not markdown. */\n lead?: string;\n}\n\n// Distinct from the imported `getTextColor`, which maps a TextColor to a CSS variable.\n// This maps an AlertType to a TextColor token; both are used in this file.\nconst getAlertTextColor = (alertType: AlertType): TextColor => {\n switch (alertType) {\n case 'info':\n return 'primary';\n case 'success':\n return 'success';\n case 'error':\n return 'error';\n case 'warning':\n return 'warning';\n // The violet is on `.alert-assistant` itself; inheriting it keeps one definition\n // rather than a TextColor token that only this alert would ever name.\n case 'assistant':\n return 'inherit';\n default:\n return 'primary';\n }\n};\n\nconst ICON_STYLE = {\n width: '13px',\n height: '13px',\n flexShrink: 0,\n};\n\nconst ICON_COLOR: Record<AlertType, string> = {\n info: 'var(--malachite-alert-info-foreground)',\n success: 'var(--malachite-alert-success-foreground)',\n error: 'var(--malachite-alert-error-foreground)',\n warning: 'var(--malachite-alert-warning-foreground)',\n assistant: 'var(--malachite-alert-assistant-foreground)',\n};\n\nconst AlertIcon = {\n info: <InfoCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.info }} />,\n success: <CheckCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.success }} />,\n error: <ErrorCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.error }} />,\n warning: <WarningCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.warning }} />,\n // The same sparkle the control that produced the message carries, so the two read as\n // one thread rather than two unrelated affordances.\n assistant: <SparkleIcon style={{ ...ICON_STYLE, color: ICON_COLOR.assistant }} />,\n};\n\nconst BANNER_ICON_STYLE = { ...ICON_STYLE, width: '16px', height: '16px' };\n\nconst statusIcon = (type: AlertType, icon: React.ReactNode, banner = false) => {\n if (!icon && !banner) return AlertIcon[type];\n const style = banner ? BANNER_ICON_STYLE : ICON_STYLE;\n return (\n <span\n className=\"alert-status-icon inline-flex shrink-0 [&_svg]:size-full!\"\n style={{ ...style, color: ICON_COLOR[type] }}\n >\n {icon || AlertIcon[type]}\n </span>\n );\n};\n\nconst SimpleTextRenderer: React.FC<{\n text: string;\n type: AlertType;\n lead?: string;\n renderLink?: RenderLink;\n}> = ({ text, type, lead, renderLink }) => {\n if (lead) {\n return (\n <div className=\"alert-lead\">\n <strong\n style={{\n color: getTextColor(getAlertTextColor(type)),\n fontSize: getFontSize('small'),\n fontWeight: 600,\n }}\n >\n {lead}\n </strong>{' '}\n <SimpleTextRenderer text={text} type={type} renderLink={renderLink} />\n </div>\n );\n }\n return (\n <MarkdownBlock\n text={text}\n color={getAlertTextColor(type)}\n size=\"small\"\n omitMargin\n renderLink={renderLink}\n />\n );\n};\n\nconst Alert: React.FC<AlertProps> = ({\n type = 'info',\n message,\n hasMargin = true,\n className,\n children,\n isExpanded,\n onToggle,\n action,\n icon,\n live = false,\n renderLink,\n layout = 'inline',\n lead,\n align = 'start',\n}) => {\n const isExpandable = !!children;\n const banner = layout === 'banner' && !isExpandable;\n const centred = banner && align === 'center';\n const urgent = type === 'error' || type === 'warning';\n const liveRole = live ? (urgent ? 'alert' : 'status') : undefined;\n const [internalExpanded, setInternalExpanded] = useState(false);\n\n // Use controlled state if isExpanded is provided, otherwise use internal state\n const expanded = isExpanded !== undefined ? isExpanded : internalExpanded;\n\n const handleToggle = () => {\n const newExpanded = !expanded;\n if (isExpanded === undefined) {\n // Uncontrolled mode\n setInternalExpanded(newExpanded);\n }\n // Call onToggle if provided (for both controlled and uncontrolled)\n onToggle?.(newExpanded);\n };\n\n const alertClasses = [\n 'alert-base',\n `alert-${type}`,\n 'flex',\n 'w-full', // Ensure full width\n banner\n ? 'alert-banner'\n : isExpandable && expanded\n ? 'flex-col'\n : 'gap-2 items-center min-h-[2rem]',\n !hasMargin ? 'alert-no-margin' : '',\n centred ? 'text-center' : 'text-left',\n banner ? '' : isExpandable ? 'rounded-xl !p-0' : '!px-2.5 !py-1.5', // Slightly more vertical padding for centering\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const headerClasses = [\n 'flex items-center justify-between w-full',\n isExpandable ? 'gap-2 px-2.5 py-1' : 'gap-2',\n isExpandable && expanded ? 'rounded-t-xl' : isExpandable ? 'rounded-xl' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const expandableContentClasses = ['w-full', 'overflow-hidden'].filter(Boolean).join(' ');\n\n // Non-expandable alert (original behavior)\n if (!isExpandable) {\n const content = (\n <>\n {statusIcon(type, icon, banner)}\n <div className={centred ? 'flex items-center' : 'flex-1 flex items-center'}>\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer\n text={message}\n type={type}\n lead={lead}\n renderLink={renderLink}\n />\n </div>\n </div>\n </>\n );\n return (\n <div className={alertClasses}>\n {centred ? (\n // Its own group, so an `action` stays at the end while this sits mid-band.\n <div className=\"alert-centred flex-1 flex items-center justify-center gap-[10px]\">\n {content}\n </div>\n ) : (\n content\n )}\n {action && <div className=\"alert-action shrink-0 flex items-center\">{action}</div>}\n </div>\n );\n }\n\n // Expandable alert\n return (\n <div className={`${alertClasses} alert-expandable`}>\n {/* Header section with title and expand/collapse button */}\n <div className={headerClasses}>\n <div className=\"flex-1 flex gap-2 items-center\">\n {statusIcon(type, icon)}\n <div className=\"flex-1 flex items-center\">\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer\n text={message}\n lead={lead}\n type={type}\n renderLink={renderLink}\n />\n </div>\n </div>\n </div>\n\n {/* Right side buttons container */}\n <div className=\"flex items-center gap-2\">\n {action && <div className=\"alert-action flex items-center\">{action}</div>}\n {/* Expand/collapse button */}\n <Button\n variant=\"no-style\"\n size=\"xsmall\"\n onClick={handleToggle}\n aria-label={expanded ? 'Collapse' : 'Expand'}\n style={{\n color: getTextColor(getAlertTextColor(type)),\n }}\n >\n {expanded ? (\n <CaretUpIcon style={{ minWidth: '13px', minHeight: '13px' }} />\n ) : (\n <CaretDownIcon style={{ minWidth: '13px', minHeight: '13px' }} />\n )}\n </Button>\n </div>\n </div>\n\n {/* Expandable content */}\n {expanded && (\n <>\n <div className={expandableContentClasses}>\n <div className=\"bg-white rounded-[var(--malachite-radius-10,10px)] shadow-[0px_1px_0px_0px_rgba(0,0,0,0.15)] border border-[#e8e8e8] border-solid mx-2 mb-2 max-h-[553px] overflow-y-auto\">\n {children}\n </div>\n </div>\n </>\n )}\n </div>\n );\n};\n\nexport default Alert;\nexport { Alert };\nexport type { AlertButtonConfig };\n"],"names":["getAlertTextColor","alertType","ICON_STYLE","ICON_COLOR","AlertIcon","jsx","InfoCircleFilled","CheckCircleFilled","ErrorCircleFilled","WarningCircleFilled","SparkleIcon","BANNER_ICON_STYLE","statusIcon","type","icon","banner","SimpleTextRenderer","text","lead","renderLink","jsxs","getTextColor","getFontSize","MarkdownBlock","Alert","message","hasMargin","className","children","isExpanded","onToggle","action","live","layout","align","isExpandable","centred","liveRole","internalExpanded","setInternalExpanded","useState","expanded","handleToggle","newExpanded","alertClasses","headerClasses","expandableContentClasses","content","Fragment","Button","CaretUpIcon","CaretDownIcon"],"mappings":"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"}
1
+ {"version":3,"file":"Alert.js","sources":["../../src/components/Alert.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { Button, ButtonVariant } from './Button';\nimport CaretDownIcon from './CustomIcons/CaretDownIcon';\nimport CaretUpIcon from './CustomIcons/CaretUpIcon';\nimport CheckCircleFilled from './CustomIcons/CheckCircleFilled';\nimport ErrorCircleFilled from './CustomIcons/ErrorCircleFilled';\nimport InfoCircleFilled from './CustomIcons/InfoCircleFilled';\nimport SparkleIcon from './CustomIcons/SparkleIcon';\nimport WarningCircleFilled from './CustomIcons/WarningCircleFilled';\nimport type { RenderLink } from './PageLayout/types';\nimport MarkdownBlock from './Typography/MarkdownBlock';\nimport type { TextColor } from './Typography/Text';\nimport { getFontSize, getTextColor } from './Typography/textStyles';\n\nexport type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';\n\nexport type AlertLayout = 'inline' | 'banner';\n\nexport interface AlertAddress {\n /** The full address, shown whole in mono; it wraps rather than truncates. */\n text: string;\n /** The part to set in bold, such as the registrable domain; every occurrence is bolded. */\n emphasis?: string;\n}\n\ninterface AlertButtonConfig {\n label: string;\n onClick: () => void;\n variant?: ButtonVariant;\n icon?: React.ReactNode;\n}\n\ninterface AlertProps {\n type?: AlertType;\n message: string;\n hasMargin?: boolean;\n className?: string;\n children?: React.ReactNode;\n isExpanded?: boolean;\n onToggle?: (expanded: boolean) => void;\n /** A control at the end of the alert — a link or button that resolves what it reports. */\n action?: React.ReactNode;\n /** Replaces the type's status icon: an svg painting with `currentColor`, such as a CustomIcon,\n * is drawn in the type's colour at the same size. */\n icon?: React.ReactNode;\n /** Makes its message a live region: `role=\"alert\"` for error and warning, `status` otherwise.\n * Screen readers reliably announce an `alert` as it mounts; a `status` is read when its\n * `message` changes, so keep a live info or success alert mounted. Off by default. */\n live?: boolean;\n /** Routes root-relative links in `message` through the app's router; see `MarkdownBlock`. */\n renderLink?: RenderLink;\n /** `banner`: a 48px page-wide band. Applies only without `children`. */\n layout?: AlertLayout;\n /** `center` gathers a banner's icon and text in the middle of the band, for a wide page. */\n align?: 'start' | 'center';\n /** A bold sentence the message runs on from. Plain text, not markdown. */\n lead?: string;\n /** An address the message runs on into, in mono; `emphasis`, an optional substring such as the registrable domain, is bold wherever it occurs. */\n address?: AlertAddress;\n /** Markdown that runs on after the address; it joins without a space when it opens with any punctuation. */\n addressSuffix?: string;\n}\n\n// Distinct from the imported `getTextColor`, which maps a TextColor to a CSS variable.\n// This maps an AlertType to a TextColor token; both are used in this file.\nconst getAlertTextColor = (alertType: AlertType): TextColor => {\n switch (alertType) {\n case 'info':\n return 'primary';\n case 'success':\n return 'success';\n case 'error':\n return 'error';\n case 'warning':\n return 'warning';\n // The violet is on `.alert-assistant` itself; inheriting it keeps one definition\n // rather than a TextColor token that only this alert would ever name.\n case 'assistant':\n return 'inherit';\n default:\n return 'primary';\n }\n};\n\nconst ICON_STYLE = {\n width: '13px',\n height: '13px',\n flexShrink: 0,\n};\n\nconst ICON_COLOR: Record<AlertType, string> = {\n info: 'var(--malachite-alert-info-foreground)',\n success: 'var(--malachite-alert-success-foreground)',\n error: 'var(--malachite-alert-error-foreground)',\n warning: 'var(--malachite-alert-warning-foreground)',\n assistant: 'var(--malachite-alert-assistant-foreground)',\n};\n\nconst AlertIcon = {\n info: <InfoCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.info }} />,\n success: <CheckCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.success }} />,\n error: <ErrorCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.error }} />,\n warning: <WarningCircleFilled style={{ ...ICON_STYLE, color: ICON_COLOR.warning }} />,\n // The same sparkle the control that produced the message carries, so the two read as\n // one thread rather than two unrelated affordances.\n assistant: <SparkleIcon style={{ ...ICON_STYLE, color: ICON_COLOR.assistant }} />,\n};\n\nconst BANNER_ICON_STYLE = { ...ICON_STYLE, width: '16px', height: '16px' };\n\nconst statusIcon = (type: AlertType, icon: React.ReactNode, banner = false) => {\n if (!icon && !banner) return AlertIcon[type];\n const style = banner ? BANNER_ICON_STYLE : ICON_STYLE;\n return (\n <span\n className=\"alert-status-icon inline-flex shrink-0 [&_svg]:size-full!\"\n style={{ ...style, color: ICON_COLOR[type] }}\n >\n {icon || AlertIcon[type]}\n </span>\n );\n};\n\ninterface AddressSegment {\n text: string;\n bold: boolean;\n offset: number;\n}\n\n// The text cut at every occurrence of the emphasis, each cut remembering where it started.\nconst addressSegments = ({ text, emphasis }: AlertAddress): AddressSegment[] => {\n if (!emphasis) {\n return [{ text, bold: false, offset: 0 }];\n }\n const segments: AddressSegment[] = [];\n const push = (part: string, bold: boolean, offset: number) => {\n if (part) segments.push({ text: part, bold, offset });\n };\n const cuts = text.split(emphasis);\n cuts.reduce((offset, cut, index) => {\n push(cut, false, offset);\n if (index < cuts.length - 1) push(emphasis, true, offset + cut.length);\n return offset + cut.length + emphasis.length;\n }, 0);\n return segments;\n};\n\nconst AddressText: React.FC<{ address: AlertAddress; color: string }> = ({ address, color }) => (\n <code\n className=\"alert-address\"\n style={{\n fontFamily: 'var(--malachite-font-mono, monospace)',\n fontSize: '0.9em',\n color,\n overflowWrap: 'anywhere',\n }}\n >\n {addressSegments(address).map((segment) =>\n segment.bold ? (\n <strong key={segment.offset} style={{ fontWeight: 600 }}>\n {segment.text}\n </strong>\n ) : (\n <React.Fragment key={segment.offset}>{segment.text}</React.Fragment>\n ),\n )}\n </code>\n);\n\nconst OPENS_WITH_PUNCTUATION = /^\\p{P}/u;\n\nconst SimpleTextRenderer: React.FC<{\n text: string;\n type: AlertType;\n lead?: string;\n address?: AlertAddress;\n addressSuffix?: string;\n renderLink?: RenderLink;\n}> = ({ text, type, lead, address, addressSuffix, renderLink }) => {\n const color = getTextColor(getAlertTextColor(type));\n const message = (\n <MarkdownBlock\n text={text}\n color={getAlertTextColor(type)}\n size=\"small\"\n omitMargin\n renderLink={renderLink}\n />\n );\n if (!lead && !address) {\n return message;\n }\n return (\n <div className=\"alert-lead\">\n {lead ? (\n <>\n <strong style={{ color, fontSize: getFontSize('small'), fontWeight: 600 }}>\n {lead}\n </strong>{' '}\n </>\n ) : null}\n {message}\n {address ? (\n <>\n {' '}\n <AddressText address={address} color={color} />\n </>\n ) : null}\n {address && addressSuffix ? (\n <>\n {OPENS_WITH_PUNCTUATION.test(addressSuffix) ? '' : ' '}\n <MarkdownBlock\n text={addressSuffix}\n color={getAlertTextColor(type)}\n size=\"small\"\n omitMargin\n renderLink={renderLink}\n />\n </>\n ) : null}\n </div>\n );\n};\n\nconst Alert: React.FC<AlertProps> = ({\n type = 'info',\n message,\n hasMargin = true,\n className,\n children,\n isExpanded,\n onToggle,\n action,\n icon,\n live = false,\n renderLink,\n layout = 'inline',\n lead,\n address,\n addressSuffix,\n align = 'start',\n}) => {\n const isExpandable = !!children;\n const banner = layout === 'banner' && !isExpandable;\n const centred = banner && align === 'center';\n const urgent = type === 'error' || type === 'warning';\n const liveRole = live ? (urgent ? 'alert' : 'status') : undefined;\n const [internalExpanded, setInternalExpanded] = useState(false);\n\n // Use controlled state if isExpanded is provided, otherwise use internal state\n const expanded = isExpanded !== undefined ? isExpanded : internalExpanded;\n\n const handleToggle = () => {\n const newExpanded = !expanded;\n if (isExpanded === undefined) {\n // Uncontrolled mode\n setInternalExpanded(newExpanded);\n }\n // Call onToggle if provided (for both controlled and uncontrolled)\n onToggle?.(newExpanded);\n };\n\n const alertClasses = [\n 'alert-base',\n `alert-${type}`,\n 'flex',\n 'w-full', // Ensure full width\n banner\n ? 'alert-banner'\n : isExpandable && expanded\n ? 'flex-col'\n : 'gap-2 items-center min-h-[2rem]',\n !hasMargin ? 'alert-no-margin' : '',\n centred ? 'text-center' : 'text-left',\n banner ? '' : isExpandable ? 'rounded-xl !p-0' : '!px-2.5 !py-1.5', // Slightly more vertical padding for centering\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const headerClasses = [\n 'flex items-center justify-between w-full',\n isExpandable ? 'gap-2 px-2.5 py-1' : 'gap-2',\n isExpandable && expanded ? 'rounded-t-xl' : isExpandable ? 'rounded-xl' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const expandableContentClasses = ['w-full', 'overflow-hidden'].filter(Boolean).join(' ');\n\n // Non-expandable alert (original behavior)\n if (!isExpandable) {\n const content = (\n <>\n {statusIcon(type, icon, banner)}\n <div className={centred ? 'flex items-center' : 'flex-1 flex items-center'}>\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer\n text={message}\n type={type}\n lead={lead}\n address={address}\n addressSuffix={addressSuffix}\n renderLink={renderLink}\n />\n </div>\n </div>\n </>\n );\n return (\n <div className={alertClasses}>\n {centred ? (\n // Its own group, so an `action` stays at the end while this sits mid-band.\n <div className=\"alert-centred flex-1 flex items-center justify-center gap-[10px]\">\n {content}\n </div>\n ) : (\n content\n )}\n {action && <div className=\"alert-action shrink-0 flex items-center\">{action}</div>}\n </div>\n );\n }\n\n // Expandable alert\n return (\n <div className={`${alertClasses} alert-expandable`}>\n {/* Header section with title and expand/collapse button */}\n <div className={headerClasses}>\n <div className=\"flex-1 flex gap-2 items-center\">\n {statusIcon(type, icon)}\n <div className=\"flex-1 flex items-center\">\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer\n text={message}\n lead={lead}\n address={address}\n addressSuffix={addressSuffix}\n type={type}\n renderLink={renderLink}\n />\n </div>\n </div>\n </div>\n\n {/* Right side buttons container */}\n <div className=\"flex items-center gap-2\">\n {action && <div className=\"alert-action flex items-center\">{action}</div>}\n {/* Expand/collapse button */}\n <Button\n variant=\"no-style\"\n size=\"xsmall\"\n onClick={handleToggle}\n aria-label={expanded ? 'Collapse' : 'Expand'}\n style={{\n color: getTextColor(getAlertTextColor(type)),\n }}\n >\n {expanded ? (\n <CaretUpIcon style={{ minWidth: '13px', minHeight: '13px' }} />\n ) : (\n <CaretDownIcon style={{ minWidth: '13px', minHeight: '13px' }} />\n )}\n </Button>\n </div>\n </div>\n\n {/* Expandable content */}\n {expanded && (\n <>\n <div className={expandableContentClasses}>\n <div className=\"bg-white rounded-[var(--malachite-radius-10,10px)] shadow-[0px_1px_0px_0px_rgba(0,0,0,0.15)] border border-[#e8e8e8] border-solid mx-2 mb-2 max-h-[553px] overflow-y-auto\">\n {children}\n </div>\n </div>\n </>\n )}\n </div>\n );\n};\n\nexport default Alert;\nexport { Alert };\nexport type { AlertButtonConfig };\n"],"names":["getAlertTextColor","alertType","ICON_STYLE","ICON_COLOR","AlertIcon","jsx","InfoCircleFilled","CheckCircleFilled","ErrorCircleFilled","WarningCircleFilled","SparkleIcon","BANNER_ICON_STYLE","statusIcon","type","icon","banner","addressSegments","text","emphasis","segments","push","part","bold","offset","cuts","cut","index","AddressText","address","color","segment","React","OPENS_WITH_PUNCTUATION","SimpleTextRenderer","lead","addressSuffix","renderLink","getTextColor","message","MarkdownBlock","jsxs","Fragment","getFontSize","Alert","hasMargin","className","children","isExpanded","onToggle","action","live","layout","align","isExpandable","centred","liveRole","internalExpanded","setInternalExpanded","useState","expanded","handleToggle","newExpanded","alertClasses","headerClasses","expandableContentClasses","content","Button","CaretUpIcon","CaretDownIcon"],"mappings":";;;;;;;;;;;;AAiEA,MAAMA,IAAoB,CAACC,MAAoC;AAC3D,UAAQA,GAAA;AAAA,IACJ,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA,IACX,KAAK;AACD,aAAO;AAAA;AAAA;AAAA,IAGX,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO;AAAA,EAAA;AAEnB,GAEMC,IAAa;AAAA,EACf,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,YAAY;AAChB,GAEMC,IAAwC;AAAA,EAC1C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,WAAW;AACf,GAEMC,IAAY;AAAA,EACd,MAAM,gBAAAC,EAACC,GAAA,EAAiB,OAAO,EAAE,GAAGJ,GAAY,OAAOC,EAAW,KAAA,GAAQ;AAAA,EAC1E,SAAS,gBAAAE,EAACE,GAAA,EAAkB,OAAO,EAAE,GAAGL,GAAY,OAAOC,EAAW,QAAA,GAAW;AAAA,EACjF,OAAO,gBAAAE,EAACG,GAAA,EAAkB,OAAO,EAAE,GAAGN,GAAY,OAAOC,EAAW,MAAA,GAAS;AAAA,EAC7E,SAAS,gBAAAE,EAACI,GAAA,EAAoB,OAAO,EAAE,GAAGP,GAAY,OAAOC,EAAW,QAAA,GAAW;AAAA;AAAA;AAAA,EAGnF,WAAW,gBAAAE,EAACK,GAAA,EAAY,OAAO,EAAE,GAAGR,GAAY,OAAOC,EAAW,YAAU,CAAG;AACnF,GAEMQ,IAAoB,EAAE,GAAGT,GAAY,OAAO,QAAQ,QAAQ,OAAA,GAE5DU,IAAa,CAACC,GAAiBC,GAAuBC,IAAS,OAC7D,CAACD,KAAQ,CAACC,IAAeX,EAAUS,CAAI,IAGvC,gBAAAR;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,WAAU;AAAA,IACV,OAAO,EAAE,GAJHU,IAASJ,IAAoBT,GAIhB,OAAOC,EAAWU,CAAI,EAAA;AAAA,IAExC,UAAAC,KAAQV,EAAUS,CAAI;AAAA,EAAA;AAAA,GAY7BG,IAAkB,CAAC,EAAE,MAAAC,GAAM,UAAAC,QAA+C;AAC5E,MAAI,CAACA;AACD,WAAO,CAAC,EAAE,MAAAD,GAAM,MAAM,IAAO,QAAQ,GAAG;AAE5C,QAAME,IAA6B,CAAA,GAC7BC,IAAO,CAACC,GAAcC,GAAeC,MAAmB;AAC1D,IAAIF,OAAe,KAAK,EAAE,MAAMA,GAAM,MAAAC,GAAM,QAAAC,GAAQ;AAAA,EACxD,GACMC,IAAOP,EAAK,MAAMC,CAAQ;AAChC,SAAAM,EAAK,OAAO,CAACD,GAAQE,GAAKC,OACtBN,EAAKK,GAAK,IAAOF,CAAM,GACnBG,IAAQF,EAAK,SAAS,OAAQN,GAAU,IAAMK,IAASE,EAAI,MAAM,GAC9DF,IAASE,EAAI,SAASP,EAAS,SACvC,CAAC,GACGC;AACX,GAEMQ,IAAkE,CAAC,EAAE,SAAAC,GAAS,OAAAC,QAChF,gBAAAxB;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,WAAU;AAAA,IACV,OAAO;AAAA,MACH,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,OAAAwB;AAAA,MACA,cAAc;AAAA,IAAA;AAAA,IAGjB,UAAAb,EAAgBY,CAAO,EAAE;AAAA,MAAI,CAACE,MAC3BA,EAAQ,yBACH,UAAA,EAA4B,OAAO,EAAE,YAAY,IAAA,GAC7C,YAAQ,KAAA,GADAA,EAAQ,MAErB,IAEA,gBAAAzB,EAAC0B,EAAM,UAAN,EAAqC,UAAAD,EAAQ,KAAA,GAAzBA,EAAQ,MAAsB;AAAA,IAAA;AAAA,EAE3D;AACJ,GAGEE,IAAyB,WAAA,WAAA,GAAA,GAEzBC,IAOD,CAAC,EAAE,MAAAhB,GAAM,MAAAJ,GAAM,MAAAqB,GAAM,SAAAN,GAAS,eAAAO,GAAe,YAAAC,QAAiB;AAC/D,QAAMP,IAAQQ,EAAarC,EAAkBa,CAAI,CAAC,GAC5CyB,IACF,gBAAAjC;AAAA,IAACkC;AAAA,IAAA;AAAA,MACG,MAAAtB;AAAA,MACA,OAAOjB,EAAkBa,CAAI;AAAA,MAC7B,MAAK;AAAA,MACL,YAAU;AAAA,MACV,YAAAuB;AAAA,IAAA;AAAA,EAAA;AAGR,SAAI,CAACF,KAAQ,CAACN,IACHU,IAGP,gBAAAE,EAAC,OAAA,EAAI,WAAU,cACV,UAAA;AAAA,IAAAN,IACG,gBAAAM,EAAAC,GAAA,EACI,UAAA;AAAA,MAAA,gBAAApC,EAAC,UAAA,EAAO,OAAO,EAAE,OAAAwB,GAAO,UAAUa,EAAY,OAAO,GAAG,YAAY,IAAA,GAC/D,UAAAR,EAAA,CACL;AAAA,MAAU;AAAA,IAAA,EAAA,CACd,IACA;AAAA,IACHI;AAAA,IACAV,IACG,gBAAAY,EAAAC,GAAA,EACK,UAAA;AAAA,MAAA;AAAA,MACD,gBAAApC,EAACsB,GAAA,EAAY,SAAAC,GAAkB,OAAAC,EAAA,CAAc;AAAA,IAAA,EAAA,CACjD,IACA;AAAA,IACHD,KAAWO,IACR,gBAAAK,EAAAC,GAAA,EACK,UAAA;AAAA,MAAAT,EAAuB,KAAKG,CAAa,IAAI,KAAK;AAAA,MACnD,gBAAA9B;AAAA,QAACkC;AAAA,QAAA;AAAA,UACG,MAAMJ;AAAA,UACN,OAAOnC,EAAkBa,CAAI;AAAA,UAC7B,MAAK;AAAA,UACL,YAAU;AAAA,UACV,YAAAuB;AAAA,QAAA;AAAA,MAAA;AAAA,IACJ,EAAA,CACJ,IACA;AAAA,EAAA,GACR;AAER,GAEMO,KAA8B,CAAC;AAAA,EACjC,MAAA9B,IAAO;AAAA,EACP,SAAAyB;AAAA,EACA,WAAAM,IAAY;AAAA,EACZ,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAnC;AAAA,EACA,MAAAoC,IAAO;AAAA,EACP,YAAAd;AAAA,EACA,QAAAe,IAAS;AAAA,EACT,MAAAjB;AAAA,EACA,SAAAN;AAAA,EACA,eAAAO;AAAA,EACA,OAAAiB,IAAQ;AACZ,MAAM;AACF,QAAMC,IAAe,CAAC,CAACP,GACjB/B,IAASoC,MAAW,YAAY,CAACE,GACjCC,IAAUvC,KAAUqC,MAAU,UAE9BG,IAAWL,IADFrC,MAAS,WAAWA,MAAS,YACV,UAAU,WAAY,QAClD,CAAC2C,GAAkBC,CAAmB,IAAIC,EAAS,EAAK,GAGxDC,IAAWZ,MAAe,SAAYA,IAAaS,GAEnDI,IAAe,MAAM;AACvB,UAAMC,IAAc,CAACF;AACrB,IAAIZ,MAAe,UAEfU,EAAoBI,CAAW,GAGnCb,KAAA,QAAAA,EAAWa;AAAA,EACf,GAEMC,IAAe;AAAA,IACjB;AAAA,IACA,SAASjD,CAAI;AAAA,IACb;AAAA,IACA;AAAA;AAAA,IACAE,IACM,iBACAsC,KAAgBM,IACd,aACA;AAAA,IACPf,IAAgC,KAApB;AAAA,IACbU,IAAU,gBAAgB;AAAA,IAC1BvC,IAAS,KAAKsC,IAAe,oBAAoB;AAAA;AAAA,IACjDR;AAAA,EAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG,GAEPkB,IAAgB;AAAA,IAClB;AAAA,IACAV,IAAe,sBAAsB;AAAA,IACrCA,KAAgBM,IAAW,iBAAiBN,IAAe,eAAe;AAAA,EAAA,EAEzE,OAAO,OAAO,EACd,KAAK,GAAG,GAEPW,IAA2B,CAAC,UAAU,iBAAiB,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAGvF,MAAI,CAACX,GAAc;AACf,UAAMY,IACF,gBAAAzB,EAAAC,GAAA,EACK,UAAA;AAAA,MAAA7B,EAAWC,GAAMC,GAAMC,CAAM;AAAA,MAC9B,gBAAAV,EAAC,OAAA,EAAI,WAAWiD,IAAU,sBAAsB,4BAC5C,UAAA,gBAAAjD,EAAC,OAAA,EAAI,WAAU,gBAAe,MAAMkD,GAChC,UAAA,gBAAAlD;AAAA,QAAC4B;AAAA,QAAA;AAAA,UACG,MAAMK;AAAA,UACN,MAAAzB;AAAA,UACA,MAAAqB;AAAA,UACA,SAAAN;AAAA,UACA,eAAAO;AAAA,UACA,YAAAC;AAAA,QAAA;AAAA,MAAA,GAER,EAAA,CACJ;AAAA,IAAA,GACJ;AAEJ,WACI,gBAAAI,EAAC,OAAA,EAAI,WAAWsB,GACX,UAAA;AAAA,MAAAR;AAAA;AAAA,QAEG,gBAAAjD,EAAC,OAAA,EAAI,WAAU,oEACV,UAAA4D,EAAA,CACL;AAAA,UAEAA;AAAA,MAEHhB,KAAU,gBAAA5C,EAAC,OAAA,EAAI,WAAU,2CAA2C,UAAA4C,EAAA,CAAO;AAAA,IAAA,GAChF;AAAA,EAER;AAGA,SACI,gBAAAT,EAAC,OAAA,EAAI,WAAW,GAAGsB,CAAY,qBAE3B,UAAA;AAAA,IAAA,gBAAAtB,EAAC,OAAA,EAAI,WAAWuB,GACZ,UAAA;AAAA,MAAA,gBAAAvB,EAAC,OAAA,EAAI,WAAU,kCACV,UAAA;AAAA,QAAA5B,EAAWC,GAAMC,CAAI;AAAA,QACtB,gBAAAT,EAAC,SAAI,WAAU,4BACX,4BAAC,OAAA,EAAI,WAAU,gBAAe,MAAMkD,GAChC,UAAA,gBAAAlD;AAAA,UAAC4B;AAAA,UAAA;AAAA,YACG,MAAMK;AAAA,YACN,MAAAJ;AAAA,YACA,SAAAN;AAAA,YACA,eAAAO;AAAA,YACA,MAAAtB;AAAA,YACA,YAAAuB;AAAA,UAAA;AAAA,QAAA,GAER,EAAA,CACJ;AAAA,MAAA,GACJ;AAAA,MAGA,gBAAAI,EAAC,OAAA,EAAI,WAAU,2BACV,UAAA;AAAA,QAAAS,KAAU,gBAAA5C,EAAC,OAAA,EAAI,WAAU,kCAAkC,UAAA4C,GAAO;AAAA,QAEnE,gBAAA5C;AAAA,UAAC6D;AAAA,UAAA;AAAA,YACG,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAASN;AAAA,YACT,cAAYD,IAAW,aAAa;AAAA,YACpC,OAAO;AAAA,cACH,OAAOtB,EAAarC,EAAkBa,CAAI,CAAC;AAAA,YAAA;AAAA,YAG9C,cACG,gBAAAR,EAAC8D,GAAA,EAAY,OAAO,EAAE,UAAU,QAAQ,WAAW,OAAA,GAAU,IAE7D,gBAAA9D,EAAC+D,KAAc,OAAO,EAAE,UAAU,QAAQ,WAAW,SAAO,CAAG;AAAA,UAAA;AAAA,QAAA;AAAA,MAEvE,EAAA,CACJ;AAAA,IAAA,GACJ;AAAA,IAGCT,KACG,gBAAAtD,EAAAoC,GAAA,EACI,UAAA,gBAAApC,EAAC,OAAA,EAAI,WAAW2D,GACZ,UAAA,gBAAA3D,EAAC,OAAA,EAAI,WAAU,6KACV,UAAAyC,EAAA,CACL,EAAA,CACJ,EAAA,CACJ;AAAA,EAAA,GAER;AAER;"}
@@ -1,169 +1,184 @@
1
- import { jsx as r, jsxs as l, Fragment as j } from "react/jsx-runtime";
2
- import { useId as B, useState as h, useRef as n, useEffect as P, useCallback as V } from "react";
3
- import { createPortal as le } from "react-dom";
4
- import { ShadowRootWrapper as te } from "../ShadowRootWrapper.js";
5
- import ie from "./CalloutStrip.js";
6
- import ne from "./CustomIcons/DismissIcon.js";
7
- import { getDeepActiveElement as oe } from "./activeElement.js";
8
- import { GLASS_SURFACE_STYLE as se } from "./glassSurface.js";
9
- import { MODAL_TRAY_BACKGROUND as ce, MODAL_TRAY_CAPTION_COLOR as de } from "./modalTray.js";
10
- import { useOverlayBehaviour as me, OVERLAY_ICON_BUTTON_CLASSES as ue } from "./overlayBehaviour.js";
11
- import { OVERLAY_ELEVATED_ATTR as pe, overlayIdentity as F } from "./portalOverlay.js";
12
- const U = {
1
+ import { jsx as e, jsxs as l, Fragment as V } from "react/jsx-runtime";
2
+ import { useId as F, useState as b, useRef as n, useEffect as U, useCallback as W } from "react";
3
+ import { createPortal as ce } from "react-dom";
4
+ import { ShadowRootWrapper as de } from "../ShadowRootWrapper.js";
5
+ import me from "./CalloutStrip.js";
6
+ import ue from "./CustomIcons/DismissIcon.js";
7
+ import { getDeepActiveElement as pe } from "./activeElement.js";
8
+ import { GLASS_SURFACE_STYLE as fe } from "./glassSurface.js";
9
+ import { MODAL_TRAY_BACKGROUND as xe, MODAL_TRAY_CAPTION_COLOR as he } from "./modalTray.js";
10
+ import { useOverlayBehaviour as ve, OVERLAY_ICON_BUTTON_CLASSES as be } from "./overlayBehaviour.js";
11
+ import { OVERLAY_ELEVATED_ATTR as ge, overlayIdentity as z } from "./portalOverlay.js";
12
+ const G = {
13
13
  small: "420px",
14
14
  medium: "612px",
15
15
  large: "760px"
16
- }, v = 200, xe = "flex-[0_1_auto] h-[min(600px,calc(100dvh-160px))]", Ie = ({
16
+ }, g = 200, q = "flex-[0_1_auto] h-[min(600px,calc(100dvh-160px))]", Oe = ({
17
17
  open: c,
18
18
  onClose: d,
19
- title: u,
20
- subtitle: p,
21
- icon: b,
22
- headerExtra: g,
23
- titleAdornment: N,
24
- tray: e,
25
- headerDivider: w = !1,
26
- footer: R,
27
- size: _ = "medium",
28
- showCloseButton: W = !0,
29
- closeOnOverlayClick: z = !0,
30
- bodyPadding: A = !0,
31
- bodyHeight: G = "auto",
32
- callouts: x,
33
- renderLink: q,
34
- role: H = "dialog",
35
- "aria-label": K,
36
- "aria-labelledby": T,
37
- "aria-describedby": X,
19
+ title: p,
20
+ subtitle: f,
21
+ icon: N,
22
+ headerExtra: w,
23
+ titleAdornment: y,
24
+ tray: K,
25
+ headerDivider: R = !1,
26
+ footer: _,
27
+ size: A = "medium",
28
+ surface: X = "card",
29
+ showCloseButton: Z = !0,
30
+ closeOnOverlayClick: H = !0,
31
+ bodyPadding: T = !0,
32
+ bodyHeight: I = "auto",
33
+ callouts: J,
34
+ renderLink: Q,
35
+ role: ee = "dialog",
36
+ "aria-label": ae,
37
+ "aria-labelledby": $,
38
+ "aria-describedby": re,
38
39
  busy: o = !1,
39
- children: I
40
+ children: x
40
41
  }) => {
41
- const k = B(), S = B(), m = (x == null ? void 0 : x.filter((a) => a.message.trim())) ?? [], [f, $] = h(!1), [Z, O] = h(!1), [J, E] = h(!1), C = n(null), s = n(null), t = n(null), L = n(o), D = n(d);
42
- P(() => {
43
- L.current = o, D.current = d;
42
+ var P;
43
+ const k = F(), S = F(), m = X === "none", a = m ? void 0 : K, u = ((P = m ? void 0 : J) == null ? void 0 : P.filter((r) => r.message.trim())) ?? [], [h, O] = b(!1), [le, C] = b(!1), [te, E] = b(!1), L = n(null), s = n(null), t = n(null), D = n(o), M = n(d);
44
+ U(() => {
45
+ D.current = o, M.current = d;
44
46
  }, [o, d]);
45
- const M = V(() => {
46
- L.current || D.current();
47
- }, []), y = n(null), {
48
- ref: Y,
49
- isTopmost: Q,
50
- zIndex: ee,
51
- elevated: re
52
- } = me({
47
+ const B = W(() => {
48
+ D.current || M.current();
49
+ }, []), Y = n(null), {
50
+ ref: j,
51
+ isTopmost: ie,
52
+ zIndex: ne,
53
+ elevated: oe
54
+ } = ve({
53
55
  open: c,
54
56
  onClose: d,
55
- hostRef: y
56
- }), ae = V(
57
- (a) => {
58
- C.current = a, Y(a);
57
+ hostRef: Y
58
+ }), se = W(
59
+ (r) => {
60
+ L.current = r, j(r);
59
61
  },
60
- [Y]
62
+ [j]
61
63
  );
62
- return P(() => {
63
- var a;
64
+ if (U(() => {
65
+ var r;
64
66
  if (c)
65
- O(!0), E(!1), t.current && (clearTimeout(t.current), t.current = null), s.current = requestAnimationFrame(() => {
66
- s.current = null, $(!0);
67
+ C(!0), E(!1), t.current && (clearTimeout(t.current), t.current = null), s.current = requestAnimationFrame(() => {
68
+ s.current = null, O(!0);
67
69
  });
68
70
  else {
69
- const i = oe();
70
- i && ((a = C.current) != null && a.contains(i)) && i.blur(), E(!0), $(!1), t.current = setTimeout(() => {
71
- t.current = null, O(!1);
72
- }, v);
71
+ const i = pe();
72
+ i && ((r = L.current) != null && r.contains(i)) && i.blur(), E(!0), O(!1), t.current = setTimeout(() => {
73
+ t.current = null, C(!1);
74
+ }, g);
73
75
  }
74
76
  return () => {
75
77
  s.current !== null && (cancelAnimationFrame(s.current), s.current = null), t.current && (clearTimeout(t.current), t.current = null);
76
78
  };
77
- }, [c]), Z ? le(
79
+ }, [c]), !le)
80
+ return null;
81
+ let v = "relative flex max-h-full w-full 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-glow,var(--malachite-shadow-lg))]";
82
+ return m ? v = "relative flex max-h-full w-full flex-col outline-none" : a && (v = "relative flex max-h-full w-full flex-col gap-[4px] rounded-[20px] p-[4px] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]"), ce(
78
83
  // Host carries the stacking context — ShadowRootWrapper's `isolation` would otherwise
79
84
  // flatten our z-index. Not promoted to the top layer, so host dialogs can cover us.
80
- /* @__PURE__ */ r(
81
- te,
85
+ /* @__PURE__ */ e(
86
+ de,
82
87
  {
83
- hostRef: y,
84
- hostStyle: { position: "relative", zIndex: ee },
85
- hostProps: re ? { ...F("modal"), [pe]: "" } : F("modal"),
88
+ hostRef: Y,
89
+ hostStyle: { position: "relative", zIndex: ne },
90
+ hostProps: oe ? { ...z("modal"), [ge]: "" } : z("modal"),
86
91
  children: /* @__PURE__ */ l(
87
92
  "div",
88
93
  {
89
94
  className: `fixed inset-0 z-[1000] flex items-center justify-center p-[16px] ${c ? "" : "pointer-events-none"}`,
90
95
  children: [
91
- /* @__PURE__ */ r(
96
+ /* @__PURE__ */ e(
92
97
  "div",
93
98
  {
94
99
  "aria-hidden": "true",
95
- onClick: z ? M : void 0,
96
- className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${f ? "opacity-100" : "opacity-0"}`
100
+ onClick: H ? B : void 0,
101
+ className: `absolute inset-0 bg-[var(--malachite-overlay-scrim)] transition-opacity duration-200 ease-in-out ${h ? "opacity-100" : "opacity-0"}`
97
102
  }
98
103
  ),
99
104
  /* @__PURE__ */ l(
100
105
  "div",
101
106
  {
102
- ref: ae,
103
- role: H,
104
- "aria-hidden": J ? "true" : void 0,
105
- "aria-modal": Q ? "true" : void 0,
107
+ ref: se,
108
+ role: ee,
109
+ "aria-hidden": te ? "true" : void 0,
110
+ "aria-modal": ie ? "true" : void 0,
106
111
  "aria-describedby": [
107
- ...m.map((a, i) => `${S}-${i}`),
108
- X,
109
- e != null && e.caption ? k : null
112
+ ...u.map((r, i) => `${S}-${i}`),
113
+ re,
114
+ a != null && a.caption ? k : null
110
115
  ].filter(Boolean).join(" ") || void 0,
111
116
  "aria-busy": o || void 0,
112
117
  tabIndex: -1,
113
- "aria-label": T ? void 0 : K ?? (typeof u == "string" ? u : void 0),
114
- "aria-labelledby": T,
115
- className: e ? "relative flex max-h-full w-full flex-col gap-[4px] rounded-[20px] p-[4px] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]" : "relative flex max-h-full w-full 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-glow,var(--malachite-shadow-lg))]",
118
+ "aria-label": $ ? void 0 : ae ?? (typeof p == "string" ? p : void 0),
119
+ "aria-labelledby": $,
120
+ className: v,
116
121
  style: {
117
- maxWidth: e ? `calc(${U[_]} + 8px)` : U[_],
118
- ...e ? {
119
- backgroundColor: ce[e.tone ?? "neutral"]
122
+ maxWidth: a ? `calc(${G[A]} + 8px)` : G[A],
123
+ ...a ? {
124
+ backgroundColor: xe[a.tone ?? "neutral"]
120
125
  } : {},
121
126
  // Inline: Tailwind scale/translate utilities silently break inside
122
127
  // shadow roots (see CLAUDE.md Shadow DOM caveats).
123
- transform: f ? "scale(1)" : "scale(0.96)",
124
- opacity: f ? 1 : 0,
125
- transition: `transform ${v}ms ease-out, opacity ${v}ms ease-out`
128
+ transform: h ? "scale(1)" : "scale(0.96)",
129
+ opacity: h ? 1 : 0,
130
+ transition: `transform ${g}ms ease-out, opacity ${g}ms ease-out`
126
131
  },
127
132
  children: [
128
- /* @__PURE__ */ l(
133
+ m ? (
134
+ // Still a scroll body: the page behind is locked, so content taller
135
+ // than the viewport has nowhere else to scroll.
136
+ /* @__PURE__ */ e(
137
+ "div",
138
+ {
139
+ className: `min-h-0 ${I === "tall" ? q : "flex-1"} overflow-y-auto`,
140
+ children: x
141
+ }
142
+ )
143
+ ) : /* @__PURE__ */ l(
129
144
  "div",
130
145
  {
131
- className: e ? "flex min-h-0 flex-col overflow-hidden rounded-[16px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] [box-shadow:var(--malachite-shadow-glow-lg,var(--malachite-shadow-xl))]" : "contents",
146
+ className: a ? "flex min-h-0 flex-col overflow-hidden rounded-[16px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] [box-shadow:var(--malachite-shadow-glow-lg,var(--malachite-shadow-xl))]" : "contents",
132
147
  children: [
133
148
  /* @__PURE__ */ l(
134
149
  "div",
135
150
  {
136
- className: `flex gap-[20px] p-[20px] ${p ? "items-start" : "items-center"} ${w ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : ""}`,
151
+ className: `flex gap-[20px] p-[20px] ${f ? "items-start" : "items-center"} ${R ? "border-0 border-b border-solid border-[var(--malachite-card-border)]" : ""}`,
137
152
  children: [
138
153
  /* @__PURE__ */ l("div", { className: "flex h-[18px] min-w-0 flex-1 items-center gap-[12px]", children: [
139
154
  /* @__PURE__ */ l("div", { className: "flex min-w-0 items-center gap-[8px]", children: [
140
- b ? /* @__PURE__ */ r("span", { className: "flex shrink-0 items-center", children: b }) : null,
155
+ N ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: N }) : null,
141
156
  /* @__PURE__ */ l("div", { className: "flex min-w-0 flex-col gap-[4px]", children: [
142
- /* @__PURE__ */ r("span", { className: "truncate text-[14px] font-medium leading-[1.25] tracking-[-0.14px] text-[var(--malachite-text-primary)]", children: u }),
143
- p ? /* @__PURE__ */ r("span", { className: "text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]", children: p }) : null
157
+ /* @__PURE__ */ e("span", { className: "truncate text-[14px] font-medium leading-[1.25] tracking-[-0.14px] text-[var(--malachite-text-primary)]", children: p }),
158
+ f ? /* @__PURE__ */ e("span", { className: "text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]", children: f }) : null
144
159
  ] })
145
160
  ] }),
146
- N ? /* @__PURE__ */ l(j, { children: [
147
- /* @__PURE__ */ r(
161
+ y ? /* @__PURE__ */ l(V, { children: [
162
+ /* @__PURE__ */ e(
148
163
  "span",
149
164
  {
150
165
  "aria-hidden": "true",
151
166
  className: "h-[12px] w-px shrink-0 bg-[var(--malachite-card-border)]"
152
167
  }
153
168
  ),
154
- /* @__PURE__ */ r("span", { className: "flex min-w-0 items-center overflow-hidden", children: N })
169
+ /* @__PURE__ */ e("span", { className: "flex min-w-0 items-center overflow-hidden", children: y })
155
170
  ] }) : null
156
171
  ] }),
157
- g ? /* @__PURE__ */ r("span", { className: "flex shrink-0 items-center", children: g }) : null,
158
- W ? /* @__PURE__ */ r(
172
+ w ? /* @__PURE__ */ e("span", { className: "flex shrink-0 items-center", children: w }) : null,
173
+ Z ? /* @__PURE__ */ e(
159
174
  "button",
160
175
  {
161
176
  type: "button",
162
177
  "aria-label": "Close",
163
- onClick: M,
178
+ onClick: B,
164
179
  disabled: o,
165
- className: ue,
166
- children: /* @__PURE__ */ r(ne, { size: 10 })
180
+ className: be,
181
+ children: /* @__PURE__ */ e(ue, { size: 10 })
167
182
  }
168
183
  ) : null
169
184
  ]
@@ -172,51 +187,51 @@ const U = {
172
187
  /* @__PURE__ */ l(
173
188
  "div",
174
189
  {
175
- className: `min-h-0 ${G === "tall" ? xe : "flex-1"} overflow-y-auto ${A && m.length === 0 ? "px-[20px]" : ""}`,
190
+ className: `min-h-0 ${I === "tall" ? q : "flex-1"} overflow-y-auto ${T && u.length === 0 ? "px-[20px]" : ""}`,
176
191
  children: [
177
- m.map((a, i) => /* @__PURE__ */ r(
178
- ie,
192
+ u.map((r, i) => /* @__PURE__ */ e(
193
+ me,
179
194
  {
180
195
  id: `${S}-${i}`,
181
- type: a.type,
182
- message: a.message,
183
- renderLink: q
196
+ type: r.type,
197
+ message: r.message,
198
+ renderLink: Q
184
199
  },
185
200
  i
186
201
  )),
187
- A ? /* @__PURE__ */ r(
202
+ T ? /* @__PURE__ */ e(
188
203
  "div",
189
204
  {
190
- className: m.length > 0 ? "px-[20px] pt-[18px] pb-[20px]" : `pb-[20px] ${w ? "pt-[18px]" : ""}`,
191
- children: I
205
+ className: u.length > 0 ? "px-[20px] pt-[18px] pb-[20px]" : `pb-[20px] ${R ? "pt-[18px]" : ""}`,
206
+ children: x
192
207
  }
193
- ) : I
208
+ ) : x
194
209
  ]
195
210
  }
196
211
  ),
197
- R ? /* @__PURE__ */ r(
212
+ _ ? /* @__PURE__ */ e(
198
213
  "div",
199
214
  {
200
215
  className: "flex min-h-[56px] shrink-0 items-center border-0 border-t border-solid border-[var(--malachite-card-border)] px-[12px]",
201
- style: se,
202
- children: R
216
+ style: fe,
217
+ children: _
203
218
  }
204
219
  ) : null
205
220
  ]
206
221
  }
207
222
  ),
208
- e != null && e.caption ? /* @__PURE__ */ r(
223
+ a != null && a.caption ? /* @__PURE__ */ e(
209
224
  "div",
210
225
  {
211
226
  id: k,
212
227
  className: "flex h-[48px] shrink-0 items-center justify-center px-[16px] text-[13px] tracking-[0.13px]",
213
- style: { color: de[e.tone ?? "neutral"] },
228
+ style: { color: he[a.tone ?? "neutral"] },
214
229
  children: /* @__PURE__ */ l("span", { children: [
215
- e.caption.label ? /* @__PURE__ */ l(j, { children: [
216
- /* @__PURE__ */ r("span", { className: "font-medium", children: e.caption.label }),
230
+ a.caption.label ? /* @__PURE__ */ l(V, { children: [
231
+ /* @__PURE__ */ e("span", { className: "font-medium", children: a.caption.label }),
217
232
  " "
218
233
  ] }) : null,
219
- e.caption.message
234
+ a.caption.message
220
235
  ] })
221
236
  }
222
237
  ) : null
@@ -229,10 +244,10 @@ const U = {
229
244
  }
230
245
  ),
231
246
  document.body
232
- ) : null;
247
+ );
233
248
  };
234
249
  export {
235
- Ie as Modal,
236
- Ie as default
250
+ Oe as Modal,
251
+ Oe as default
237
252
  };
238
253
  //# sourceMappingURL=Modal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","sources":["../../src/components/Modal.tsx"],"sourcesContent":["import type React from 'react';\nimport { useCallback, 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 DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport { getDeepActiveElement } from './activeElement';\nimport { GLASS_SURFACE_STYLE } from './glassSurface';\nimport { MODAL_TRAY_BACKGROUND, MODAL_TRAY_CAPTION_COLOR, type ModalTrayTone } from './modalTray';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\n\n/** Widths keyed to the size union — a raw `width` prop would let a consumer off the scale. */\nconst SIZE_MAX_WIDTH: Record<ModalSize, string> = {\n small: '420px',\n medium: '612px',\n large: '760px',\n};\n\nconst TRANSITION_MS = 200;\n\n// A basis of its own: a `flex-1` body's zero basis would override the height in Chrome.\nconst TALL_BODY = 'flex-[0_1_auto] h-[min(600px,calc(100dvh-160px))]';\n\nexport interface ModalProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n /** Secondary line beneath the title. */\n subtitle?: React.ReactNode;\n /** Leading header slot, typically an icon or logo. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n titleAdornment?: React.ReactNode;\n tray?: { tone?: ModalTrayTone; caption?: { label?: string; message: string } };\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Pinned action row below the scrolling body. */\n footer?: React.ReactNode;\n size?: ModalSize;\n /** Default: true. */\n showCloseButton?: boolean;\n /** Default: true. Turn off for a dialog whose choice must be made deliberately. */\n closeOnOverlayClick?: boolean;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `tall`: 600px, or the viewport less 160px, for content that sizes to its box. */\n bodyHeight?: 'auto' | 'tall';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of the dialog's 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 /**\n * `alertdialog` for a dialog interrupting the user over a consequential choice — it\n * tells assistive tech to announce the body, not just the name.\n */\n role?: 'dialog' | 'alertdialog';\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 /** ID of the element describing what the dialog is asking. */\n 'aria-describedby'?: string;\n /**\n * Work is in flight: suppresses the pointer dismissal routes and announces the busy\n * state. Never ESC — that is the only guaranteed keyboard exit from a focus trap, so it\n * always reaches `onClose` and whether to abort is left to the caller.\n */\n busy?: boolean;\n children: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n title,\n subtitle,\n icon,\n headerExtra,\n titleAdornment,\n tray,\n headerDivider = false,\n footer,\n size = 'medium',\n showCloseButton = true,\n closeOnOverlayClick = true,\n bodyPadding = true,\n bodyHeight = 'auto',\n callouts,\n renderLink,\n role = 'dialog',\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n busy = false,\n children,\n}) => {\n const captionId = useId();\n const calloutId = useId();\n const shownCallouts = callouts?.filter((callout) => callout.message.trim()) ?? [];\n const [isVisible, setIsVisible] = useState(false);\n // Starts false even when `open` does: portals are unsupported on the server, so the\n // dialog must reach `document.body` from the client effect below and nowhere else.\n const [isMounted, setIsMounted] = useState(false);\n // Distinct from `!isVisible`, which is also false on the frame the dialog opens.\n const [isExiting, setIsExiting] = useState(false);\n const panelRef = useRef<HTMLElement | null>(null);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const busyRef = useRef(busy);\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n busyRef.current = busy;\n onCloseRef.current = onClose;\n }, [busy, onClose]);\n\n // Pointer routes only. Removing ESC too would leave a focus-trapped keyboard user no\n // exit while a request hangs (WCAG 2.1.2), so ESC always reaches onClose.\n const dismissByPointer = useCallback(() => {\n if (!busyRef.current) {\n onCloseRef.current();\n }\n }, []);\n const hostRef = useRef<HTMLDivElement | null>(null);\n // No prop of its own: it stays in the base band unless a SidePanel elevated the stack,\n // and follows it up when one has.\n const {\n ref: takePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n hostRef,\n });\n const handlePanelRef = useCallback(\n (node: HTMLElement | null) => {\n panelRef.current = node;\n takePanelRef(node);\n },\n [takePanelRef],\n );\n\n // Mounted outlives `open` by one transition, so the dialog can animate out.\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n setIsExiting(false);\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 // A browser refuses `aria-hidden` on a subtree still holding focus, so the\n // attribute waits for this point — after useOverlayBehaviour's cleanup has\n // returned focus to the trigger — and blurs what is left if the trigger has gone.\n const active = getDeepActiveElement();\n if (active && panelRef.current?.contains(active)) {\n active.blur();\n }\n setIsExiting(true);\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 return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would otherwise\n // flatten our z-index. Not promoted to the top layer, so host dialogs can cover us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('modal'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('modal')\n }\n >\n {/* The exit transition outlives `open`, so a closed-but-mounted dialog has to stop\n taking clicks and leave the a11y tree — a faded opacity does neither. */}\n <div\n className={`fixed inset-0 z-[1000] flex items-center justify-center p-[16px] ${\n open ? '' : 'pointer-events-none'\n }`}\n >\n <div\n aria-hidden=\"true\"\n onClick={closeOnOverlayClick ? dismissByPointer : undefined}\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={role}\n aria-hidden={isExiting ? 'true' : undefined}\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...shownCallouts.map((_, index) => `${calloutId}-${index}`),\n ariaDescribedBy,\n tray?.caption ? captionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n aria-busy={busy || undefined}\n tabIndex={-1}\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className={\n tray\n ? 'relative flex max-h-full w-full flex-col gap-[4px] rounded-[20px] p-[4px] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]'\n : 'relative flex max-h-full w-full 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-glow,var(--malachite-shadow-lg))]'\n }\n style={{\n maxWidth: tray\n ? `calc(${SIZE_MAX_WIDTH[size]} + 8px)`\n : SIZE_MAX_WIDTH[size],\n ...(tray\n ? {\n backgroundColor: MODAL_TRAY_BACKGROUND[tray.tone ?? 'neutral'],\n }\n : {}),\n // Inline: Tailwind scale/translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'scale(1)' : 'scale(0.96)',\n opacity: isVisible ? 1 : 0,\n transition: `transform ${TRANSITION_MS}ms ease-out, opacity ${TRANSITION_MS}ms ease-out`,\n }}\n >\n <div\n className={\n tray\n ? 'flex min-h-0 flex-col overflow-hidden rounded-[16px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] [box-shadow:var(--malachite-shadow-glow-lg,var(--malachite-shadow-xl))]'\n : 'contents'\n }\n >\n <div\n className={`flex gap-[20px] p-[20px] ${\n subtitle ? 'items-start' : 'items-center'\n } ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex h-[18px] min-w-0 flex-1 items-center gap-[12px]\">\n <div className=\"flex min-w-0 items-center gap-[8px]\">\n {icon ? (\n <span className=\"flex shrink-0 items-center\">{icon}</span>\n ) : null}\n <div className=\"flex min-w-0 flex-col gap-[4px]\">\n <span className=\"truncate text-[14px] font-medium leading-[1.25] tracking-[-0.14px] text-[var(--malachite-text-primary)]\">\n {title}\n </span>\n {subtitle ? (\n <span className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\">\n {subtitle}\n </span>\n ) : null}\n </div>\n </div>\n {titleAdornment ? (\n <>\n <span\n aria-hidden=\"true\"\n className=\"h-[12px] w-px shrink-0 bg-[var(--malachite-card-border)]\"\n />\n <span className=\"flex min-w-0 items-center overflow-hidden\">\n {titleAdornment}\n </span>\n </>\n ) : null}\n </div>\n {headerExtra ? (\n <span className=\"flex shrink-0 items-center\">{headerExtra}</span>\n ) : null}\n {showCloseButton ? (\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={dismissByPointer}\n disabled={busy}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n ) : null}\n </div>\n <div\n className={`min-h-0 ${bodyHeight === 'tall' ? TALL_BODY : 'flex-1'} overflow-y-auto ${\n bodyPadding && shownCallouts.length === 0 ? 'px-[20px]' : ''\n }`}\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 {bodyPadding ? (\n <div\n className={\n shownCallouts.length > 0\n ? 'px-[20px] pt-[18px] pb-[20px]'\n : `pb-[20px] ${headerDivider ? 'pt-[18px]' : ''}`\n }\n >\n {children}\n </div>\n ) : (\n children\n )}\n </div>\n {footer ? (\n <div\n className=\"flex min-h-[56px] shrink-0 items-center border-0 border-t border-solid border-[var(--malachite-card-border)] px-[12px]\"\n style={GLASS_SURFACE_STYLE}\n >\n {footer}\n </div>\n ) : null}\n </div>\n {tray?.caption ? (\n <div\n id={captionId}\n className=\"flex h-[48px] shrink-0 items-center justify-center px-[16px] text-[13px] tracking-[0.13px]\"\n style={{ color: MODAL_TRAY_CAPTION_COLOR[tray.tone ?? 'neutral'] }}\n >\n <span>\n {tray.caption.label ? (\n <>\n <span className=\"font-medium\">\n {tray.caption.label}\n </span>{' '}\n </>\n ) : null}\n {tray.caption.message}\n </span>\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default Modal;\nexport { Modal };\n"],"names":["SIZE_MAX_WIDTH","TRANSITION_MS","TALL_BODY","Modal","open","onClose","title","subtitle","icon","headerExtra","titleAdornment","tray","headerDivider","footer","size","showCloseButton","closeOnOverlayClick","bodyPadding","bodyHeight","callouts","renderLink","role","ariaLabel","ariaLabelledBy","ariaDescribedBy","busy","children","captionId","useId","calloutId","shownCallouts","callout","isVisible","setIsVisible","useState","isMounted","setIsMounted","isExiting","setIsExiting","panelRef","useRef","frameRef","unmountTimerRef","busyRef","onCloseRef","useEffect","dismissByPointer","useCallback","hostRef","takePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","handlePanelRef","node","active","getDeepActiveElement","_a","createPortal","jsx","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","MODAL_TRAY_BACKGROUND","Fragment","OVERLAY_ICON_BUTTON_CLASSES","DismissIcon","CalloutStrip","GLASS_SURFACE_STYLE","MODAL_TRAY_CAPTION_COLOR"],"mappings":"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"}
1
+ {"version":3,"file":"Modal.js","sources":["../../src/components/Modal.tsx"],"sourcesContent":["import type React from 'react';\nimport { useCallback, 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 DismissIcon from './CustomIcons/DismissIcon';\nimport type { RenderLink } from './PageLayout/types';\nimport { getDeepActiveElement } from './activeElement';\nimport { GLASS_SURFACE_STYLE } from './glassSurface';\nimport { MODAL_TRAY_BACKGROUND, MODAL_TRAY_CAPTION_COLOR, type ModalTrayTone } from './modalTray';\nimport { OVERLAY_ICON_BUTTON_CLASSES, useOverlayBehaviour } from './overlayBehaviour';\nimport { OVERLAY_ELEVATED_ATTR, overlayIdentity } from './portalOverlay';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\nexport type ModalSurface = 'card' | 'none';\n\n/** Widths keyed to the size union — a raw `width` prop would let a consumer off the scale. */\nconst SIZE_MAX_WIDTH: Record<ModalSize, string> = {\n small: '420px',\n medium: '612px',\n large: '760px',\n};\n\nconst TRANSITION_MS = 200;\n\n// A basis of its own: a `flex-1` body's zero basis would override the height in Chrome.\nconst TALL_BODY = 'flex-[0_1_auto] h-[min(600px,calc(100dvh-160px))]';\n\nexport interface ModalProps {\n open: boolean;\n /** Dismiss handler — close button, ESC, or overlay click. */\n onClose: () => void;\n title: React.ReactNode;\n /** Secondary line beneath the title. */\n subtitle?: React.ReactNode;\n /** Leading header slot, typically an icon or logo. */\n icon?: React.ReactNode;\n /** Content pinned right in the header, before the close button. */\n headerExtra?: React.ReactNode;\n titleAdornment?: React.ReactNode;\n tray?: { tone?: ModalTrayTone; caption?: { label?: string; message: string } };\n /** Divider under the header. Default: false. */\n headerDivider?: boolean;\n /** Pinned action row below the scrolling body. */\n footer?: React.ReactNode;\n size?: ModalSize;\n /**\n * `none` draws no card: no header, close button, footer, callouts or tray, only the\n * overlay and a scroll body around content that brings its own chrome, such as the Hub.\n * `title` then only names the dialog for assistive tech. Default: `card`.\n */\n surface?: ModalSurface;\n /** Default: true. */\n showCloseButton?: boolean;\n /** Default: true. Turn off for a dialog whose choice must be made deliberately. */\n closeOnOverlayClick?: boolean;\n /** Whether the body gets default padding. Default: true. */\n bodyPadding?: boolean;\n /** `tall`: 600px, or the viewport less 160px, for content that sizes to its box. */\n bodyHeight?: 'auto' | 'tall';\n /** Full-width Alert bands at the top of the body, above `children`, in order. Unaffected by\n * `bodyPadding`, and announced ahead of the dialog's 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 /**\n * `alertdialog` for a dialog interrupting the user over a consequential choice — it\n * tells assistive tech to announce the body, not just the name.\n */\n role?: 'dialog' | 'alertdialog';\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 /** ID of the element describing what the dialog is asking. */\n 'aria-describedby'?: string;\n /**\n * Work is in flight: suppresses the pointer dismissal routes and announces the busy\n * state. Never ESC — that is the only guaranteed keyboard exit from a focus trap, so it\n * always reaches `onClose` and whether to abort is left to the caller.\n */\n busy?: boolean;\n children: React.ReactNode;\n}\n\nconst Modal: React.FC<ModalProps> = ({\n open,\n onClose,\n title,\n subtitle,\n icon,\n headerExtra,\n titleAdornment,\n tray: trayProp,\n headerDivider = false,\n footer,\n size = 'medium',\n surface = 'card',\n showCloseButton = true,\n closeOnOverlayClick = true,\n bodyPadding = true,\n bodyHeight = 'auto',\n callouts,\n renderLink,\n role = 'dialog',\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n busy = false,\n children,\n}) => {\n const captionId = useId();\n const calloutId = useId();\n const isBare = surface === 'none';\n // A bare dialog has no card to ring or caption, so the tray is not drawn either.\n const tray = isBare ? undefined : trayProp;\n const shownCallouts =\n (isBare ? undefined : callouts)?.filter((callout) => callout.message.trim()) ?? [];\n const [isVisible, setIsVisible] = useState(false);\n // Starts false even when `open` does: portals are unsupported on the server, so the\n // dialog must reach `document.body` from the client effect below and nowhere else.\n const [isMounted, setIsMounted] = useState(false);\n // Distinct from `!isVisible`, which is also false on the frame the dialog opens.\n const [isExiting, setIsExiting] = useState(false);\n const panelRef = useRef<HTMLElement | null>(null);\n const frameRef = useRef<number | null>(null);\n const unmountTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const busyRef = useRef(busy);\n const onCloseRef = useRef(onClose);\n useEffect(() => {\n busyRef.current = busy;\n onCloseRef.current = onClose;\n }, [busy, onClose]);\n\n // Pointer routes only. Removing ESC too would leave a focus-trapped keyboard user no\n // exit while a request hangs (WCAG 2.1.2), so ESC always reaches onClose.\n const dismissByPointer = useCallback(() => {\n if (!busyRef.current) {\n onCloseRef.current();\n }\n }, []);\n const hostRef = useRef<HTMLDivElement | null>(null);\n // No prop of its own: it stays in the base band unless a SidePanel elevated the stack,\n // and follows it up when one has.\n const {\n ref: takePanelRef,\n isTopmost,\n zIndex,\n elevated,\n } = useOverlayBehaviour({\n open,\n onClose,\n hostRef,\n });\n const handlePanelRef = useCallback(\n (node: HTMLElement | null) => {\n panelRef.current = node;\n takePanelRef(node);\n },\n [takePanelRef],\n );\n\n // Mounted outlives `open` by one transition, so the dialog can animate out.\n useEffect(() => {\n if (open) {\n setIsMounted(true);\n setIsExiting(false);\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 // A browser refuses `aria-hidden` on a subtree still holding focus, so the\n // attribute waits for this point — after useOverlayBehaviour's cleanup has\n // returned focus to the trigger — and blurs what is left if the trigger has gone.\n const active = getDeepActiveElement();\n if (active && panelRef.current?.contains(active)) {\n active.blur();\n }\n setIsExiting(true);\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 let panelClassName =\n 'relative flex max-h-full w-full 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-glow,var(--malachite-shadow-lg))]';\n if (isBare) {\n panelClassName = 'relative flex max-h-full w-full flex-col outline-none';\n } else if (tray) {\n panelClassName =\n 'relative flex max-h-full w-full flex-col gap-[4px] rounded-[20px] p-[4px] text-[var(--malachite-card-foreground)] outline-none [box-shadow:var(--malachite-shadow-glow,var(--malachite-shadow-lg))]';\n }\n\n return createPortal(\n // Host carries the stacking context — ShadowRootWrapper's `isolation` would otherwise\n // flatten our z-index. Not promoted to the top layer, so host dialogs can cover us.\n <ShadowRootWrapper\n hostRef={hostRef}\n hostStyle={{ position: 'relative', zIndex }}\n hostProps={\n elevated\n ? { ...overlayIdentity('modal'), [OVERLAY_ELEVATED_ATTR]: '' }\n : overlayIdentity('modal')\n }\n >\n {/* The exit transition outlives `open`, so a closed-but-mounted dialog has to stop\n taking clicks and leave the a11y tree — a faded opacity does neither. */}\n <div\n className={`fixed inset-0 z-[1000] flex items-center justify-center p-[16px] ${\n open ? '' : 'pointer-events-none'\n }`}\n >\n <div\n aria-hidden=\"true\"\n onClick={closeOnOverlayClick ? dismissByPointer : undefined}\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={role}\n aria-hidden={isExiting ? 'true' : undefined}\n aria-modal={isTopmost ? 'true' : undefined}\n aria-describedby={\n [\n ...shownCallouts.map((_, index) => `${calloutId}-${index}`),\n ariaDescribedBy,\n tray?.caption ? captionId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n }\n aria-busy={busy || undefined}\n tabIndex={-1}\n aria-label={\n ariaLabelledBy\n ? undefined\n : (ariaLabel ?? (typeof title === 'string' ? title : undefined))\n }\n aria-labelledby={ariaLabelledBy}\n className={panelClassName}\n style={{\n maxWidth: tray\n ? `calc(${SIZE_MAX_WIDTH[size]} + 8px)`\n : SIZE_MAX_WIDTH[size],\n ...(tray\n ? {\n backgroundColor: MODAL_TRAY_BACKGROUND[tray.tone ?? 'neutral'],\n }\n : {}),\n // Inline: Tailwind scale/translate utilities silently break inside\n // shadow roots (see CLAUDE.md Shadow DOM caveats).\n transform: isVisible ? 'scale(1)' : 'scale(0.96)',\n opacity: isVisible ? 1 : 0,\n transition: `transform ${TRANSITION_MS}ms ease-out, opacity ${TRANSITION_MS}ms ease-out`,\n }}\n >\n {isBare ? (\n // Still a scroll body: the page behind is locked, so content taller\n // than the viewport has nowhere else to scroll.\n <div\n className={`min-h-0 ${bodyHeight === 'tall' ? TALL_BODY : 'flex-1'} overflow-y-auto`}\n >\n {children}\n </div>\n ) : (\n <div\n className={\n tray\n ? 'flex min-h-0 flex-col overflow-hidden rounded-[16px] border border-solid border-[var(--malachite-card-border)] bg-[var(--malachite-card-background)] [box-shadow:var(--malachite-shadow-glow-lg,var(--malachite-shadow-xl))]'\n : 'contents'\n }\n >\n <div\n className={`flex gap-[20px] p-[20px] ${\n subtitle ? 'items-start' : 'items-center'\n } ${\n headerDivider\n ? 'border-0 border-b border-solid border-[var(--malachite-card-border)]'\n : ''\n }`}\n >\n <div className=\"flex h-[18px] min-w-0 flex-1 items-center gap-[12px]\">\n <div className=\"flex min-w-0 items-center gap-[8px]\">\n {icon ? (\n <span className=\"flex shrink-0 items-center\">\n {icon}\n </span>\n ) : null}\n <div className=\"flex min-w-0 flex-col gap-[4px]\">\n <span className=\"truncate text-[14px] font-medium leading-[1.25] tracking-[-0.14px] text-[var(--malachite-text-primary)]\">\n {title}\n </span>\n {subtitle ? (\n <span className=\"text-[13px] leading-[1.6] text-[var(--malachite-text-secondary)]\">\n {subtitle}\n </span>\n ) : null}\n </div>\n </div>\n {titleAdornment ? (\n <>\n <span\n aria-hidden=\"true\"\n className=\"h-[12px] w-px shrink-0 bg-[var(--malachite-card-border)]\"\n />\n <span className=\"flex min-w-0 items-center overflow-hidden\">\n {titleAdornment}\n </span>\n </>\n ) : null}\n </div>\n {headerExtra ? (\n <span className=\"flex shrink-0 items-center\">\n {headerExtra}\n </span>\n ) : null}\n {showCloseButton ? (\n <button\n type=\"button\"\n aria-label=\"Close\"\n onClick={dismissByPointer}\n disabled={busy}\n className={OVERLAY_ICON_BUTTON_CLASSES}\n >\n <DismissIcon size={10} />\n </button>\n ) : null}\n </div>\n <div\n className={`min-h-0 ${bodyHeight === 'tall' ? TALL_BODY : 'flex-1'} overflow-y-auto ${\n bodyPadding && shownCallouts.length === 0 ? 'px-[20px]' : ''\n }`}\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 {bodyPadding ? (\n <div\n className={\n shownCallouts.length > 0\n ? 'px-[20px] pt-[18px] pb-[20px]'\n : `pb-[20px] ${headerDivider ? 'pt-[18px]' : ''}`\n }\n >\n {children}\n </div>\n ) : (\n children\n )}\n </div>\n {footer ? (\n <div\n className=\"flex min-h-[56px] shrink-0 items-center border-0 border-t border-solid border-[var(--malachite-card-border)] px-[12px]\"\n style={GLASS_SURFACE_STYLE}\n >\n {footer}\n </div>\n ) : null}\n </div>\n )}\n {tray?.caption ? (\n <div\n id={captionId}\n className=\"flex h-[48px] shrink-0 items-center justify-center px-[16px] text-[13px] tracking-[0.13px]\"\n style={{ color: MODAL_TRAY_CAPTION_COLOR[tray.tone ?? 'neutral'] }}\n >\n <span>\n {tray.caption.label ? (\n <>\n <span className=\"font-medium\">\n {tray.caption.label}\n </span>{' '}\n </>\n ) : null}\n {tray.caption.message}\n </span>\n </div>\n ) : null}\n </div>\n </div>\n </ShadowRootWrapper>,\n document.body,\n );\n};\n\nexport default Modal;\nexport { Modal };\n"],"names":["SIZE_MAX_WIDTH","TRANSITION_MS","TALL_BODY","Modal","open","onClose","title","subtitle","icon","headerExtra","titleAdornment","trayProp","headerDivider","footer","size","surface","showCloseButton","closeOnOverlayClick","bodyPadding","bodyHeight","callouts","renderLink","role","ariaLabel","ariaLabelledBy","ariaDescribedBy","busy","children","captionId","useId","calloutId","isBare","tray","shownCallouts","_a","callout","isVisible","setIsVisible","useState","isMounted","setIsMounted","isExiting","setIsExiting","panelRef","useRef","frameRef","unmountTimerRef","busyRef","onCloseRef","useEffect","dismissByPointer","useCallback","hostRef","takePanelRef","isTopmost","zIndex","elevated","useOverlayBehaviour","handlePanelRef","node","active","getDeepActiveElement","panelClassName","createPortal","jsx","ShadowRootWrapper","overlayIdentity","OVERLAY_ELEVATED_ATTR","jsxs","_","index","MODAL_TRAY_BACKGROUND","Fragment","OVERLAY_ICON_BUTTON_CLASSES","DismissIcon","CalloutStrip","GLASS_SURFACE_STYLE","MODAL_TRAY_CAPTION_COLOR"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -185,6 +185,13 @@ export declare const AdvancedLogsIcon: React.FC<IconProps_4>;
185
185
 
186
186
  export declare const Alert: default_2.FC<AlertProps>;
187
187
 
188
+ declare interface AlertAddress {
189
+ /** The full address, shown whole in mono; it wraps rather than truncates. */
190
+ text: string;
191
+ /** The part to set in bold, such as the registrable domain; every occurrence is bolded. */
192
+ emphasis?: string;
193
+ }
194
+
188
195
  export declare type AlertLayout = 'inline' | 'banner';
189
196
 
190
197
  declare interface AlertProps {
@@ -212,6 +219,10 @@ declare interface AlertProps {
212
219
  align?: 'start' | 'center';
213
220
  /** A bold sentence the message runs on from. Plain text, not markdown. */
214
221
  lead?: string;
222
+ /** An address the message runs on into, in mono; `emphasis`, an optional substring such as the registrable domain, is bold wherever it occurs. */
223
+ address?: AlertAddress;
224
+ /** Markdown that runs on after the address; it joins without a space when it opens with any punctuation. */
225
+ addressSuffix?: string;
215
226
  }
216
227
 
217
228
  export declare type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';
@@ -3607,6 +3618,12 @@ export declare interface ModalProps {
3607
3618
  /** Pinned action row below the scrolling body. */
3608
3619
  footer?: default_2.ReactNode;
3609
3620
  size?: ModalSize;
3621
+ /**
3622
+ * `none` draws no card: no header, close button, footer, callouts or tray, only the
3623
+ * overlay and a scroll body around content that brings its own chrome, such as the Hub.
3624
+ * `title` then only names the dialog for assistive tech. Default: `card`.
3625
+ */
3626
+ surface?: ModalSurface;
3610
3627
  /** Default: true. */
3611
3628
  showCloseButton?: boolean;
3612
3629
  /** Default: true. Turn off for a dialog whose choice must be made deliberately. */
@@ -3645,6 +3662,8 @@ export declare interface ModalProps {
3645
3662
 
3646
3663
  export declare type ModalSize = 'small' | 'medium' | 'large';
3647
3664
 
3665
+ export declare type ModalSurface = 'card' | 'none';
3666
+
3648
3667
  export declare type ModalTrayTone = 'neutral' | 'warning' | 'error' | 'success';
3649
3668
 
3650
3669
  export declare const MoreHorizontalIcon: React.FC<IconProps_77>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/malachite",
3
- "version": "2.75.0",
3
+ "version": "2.76.0",
4
4
  "description": "StackOne's themeable React component library — Shadow DOM isolated, scoped Tailwind, theme-token driven.",
5
5
  "license": "MIT",
6
6
  "author": "StackOne",