@stackone/malachite 2.56.0 → 2.57.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
@@ -27,15 +27,16 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
27
27
  - **`ActionBar`** — A row of actions that collapses into a single `ActionMenu` once its container drops below `collapseBelow`. Measures the nearest genuinely-wider ancestor rather than itself, since the row shrinks to its own content. `dividerBefore` renders a vertical rule in the row and a divider in the collapsed menu, so both forms group the actions the same way. _Key props:_ `buttons` (`label`, `onClick`, `icon`, `variant`, `size`, `radius`, `tooltip`, `disabled`, `dividerBefore`), `collapseBelow`, `menuLabel`, `className`.
28
28
  - **`Popover`** — An anchored, non-modal panel for arbitrary content — a workspace switcher, an org flyout. The panel renders in its own shadow root, so malachite components inside it are styled, and joins the top layer like the other overlays. It prefers its `placement` and flips to the opposite side when there is no room, clamping along the other axis. Click-opened panels take focus and hand it back to the trigger on close; `openOn="hover"` also opens on focus and stays open while the pointer or focus is in the panel. A nested Popover counts as inside its parent for outside-press and hover dismissal, and Escape closes the topmost only. A click panel also closes when focus moves somewhere outside it and its trigger, and on close it hands focus back to the trigger only if focus would otherwise fall to the page. _Key props:_ `trigger`, `children`, `open`, `defaultOpen`, `onOpenChange`, `placement` (`bottom-start` | `bottom-end` | `top-start` | `top-center` | `right-start` | `right-end` | `left-start`), `openOn` (`click` | `hover`), `width` (`content` | `trigger`), `padding` (`none` | `small` | `medium`), `anchorRef` (position against another element, e.g. the section a trigger row sits in), `offset` (`small` 8px | `medium` 12px | `large` 14px), `elevation` (`default` | `raised`), `initialFocusRef` (what takes focus on open, in place of the first focusable), `role` (`dialog` | `menu` | `listbox`; `menu` brings no roving focus of its own), `aria-label` or `aria-labelledby` (one is required), `className`. The panel is capped to the viewport width, and only overlays opened from inside it (menus, dropdowns, modals) count as inside for outside-press dismissal. A side placement stays level with its anchor and scrolls within the room below, sliding up only when under 160px is left. Parts for the panel body: `Popover.Header` (`title`, `action`), `Popover.Action` (`icon`, `aria-label`, `onClick`, `href` (a link that opens in a new tab on Cmd/Ctrl-click or a middle click; a plain click runs `onClick` when one is given), `disabled`, `tooltip`), `Popover.List` (a scrolling list), `Popover.Section` (a bordered section) and `Popover.Empty` (an empty-state line).
29
29
  - **`Modal`** — Centred dialog over a scrim, with header slots (icon/title/subtitle/extra), a scrolling body and a pinned footer. Locks background scroll and dismisses on ESC, the close button, or a scrim click unless `closeOnOverlayClick` is off; `busy` suppresses the two pointer routes while a request is in flight and sets `aria-busy`, so a stray click cannot tear the dialog down mid-write — but never ESC, which is the only guaranteed keyboard exit from a focus trap and so always reaches `onClose`. ESC, the Tab focus trap and `aria-modal` all apply to the topmost overlay only, so these may be stacked — a dialog opened from a panel keeps Tab to itself and the panel stops claiming to be modal. The Tab trap follows focus into a malachite popup portaled out of the dialog’s own tree — a `MultiSelect` listbox or a `Popover` opened from the body — and traps Tab within that popup while it holds focus, so Tab walks and wraps that popup’s own stops rather than being yanked back to the dialog’s first control or escaping the dialog altogether. A `Dropdown` list or an `ActionMenu` is dismissed by Tab rather than trapping it: it closes and focus returns to its trigger, so Tab carries on from there. A consumer’s own portaled popup is not known to the trap and Tab will pull focus out of it. Set `role="alertdialog"` for a consequential choice, which asks assistive tech to announce the body and not just the name, and point `aria-describedby` at whichever element carries it. Width comes from the `size` union (`small` 420px | `medium` 612px | `large` 760px) rather than a raw pixel prop. `titleAdornment` sits immediately after the title behind a hairline divider, for naming the thing being acted on — distinct from `headerExtra`, which pins to the far right. `tray` paints a tinted plate around the card and hangs a `caption` beneath it; the plate is the dialog element itself, so that caption stays inside the `aria-modal` subtree rather than being stranded outside it by the visual nesting, and it is added to `aria-describedby` automatically because it says what the dialog is asking. It takes a tone (`neutral` | `warning` | `error` | `success`) rather than a colour, so no consumer can paint it off-palette — and the tone sets the plate and its caption colour together, so the two cannot disagree. The caption is a `{ label?, message }` pair rather than a node, because its row height, type scale and colour belong to the plate. `size` names the card, and the plate’s 4px ring is added on top. Like `SidePanel` it sits in a z-index band from 1000 — one step per stacked overlay, so what paints on top is what holds the keyboard — and stays out of the browser top layer, so a host app’s own dialogs can still cover it. For a confirmation use `ConfirmationDialog`, which is a preset over this. _Key props:_ `open`, `onClose`, `title`, `subtitle`, `icon`, `headerExtra`, `titleAdornment`, `tray`, `headerDivider`, `footer`, `size`, `showCloseButton`, `closeOnOverlayClick`, `bodyPadding`, `busy`, `role` (`dialog` | `alertdialog`), `aria-label`, `aria-labelledby`, `aria-describedby`.
30
- - **`SidePanel`** — Right-hand slide-in overlay panel (drawer) with header slots (back/icon/title/subtitle/extra), scrollable body and optional footer. Locks background scroll and dismisses on ESC, an overlay click or close. ESC and the Tab focus trap apply to the topmost overlay only, so a `Modal` may be stacked over it. The Tab trap follows focus into a malachite popup portaled out of the panel’s own tree — a `MultiSelect` listbox or a `Popover` opened from the body — and traps Tab within that popup while it holds focus, so Tab walks and wraps that popup’s own stops rather than being yanked back to the panel’s first control or escaping the panel altogether. A `Dropdown` list or an `ActionMenu` is dismissed by Tab rather than trapping it: it closes and focus returns to its trigger, so Tab carries on from there. A consumer’s own portaled popup is not known to the trap and Tab will pull focus out of it.
30
+ - **`SidePanel`** — Right-hand slide-in overlay panel (drawer) with header slots (back/icon/title/subtitle/extra), scrollable body and optional footer. Locks background scroll and dismisses on ESC, an overlay click or close. ESC and the Tab focus trap apply to the topmost overlay only, so a `Modal` may be stacked over it. The Tab trap follows focus into a malachite popup portaled out of the panel’s own tree — a `MultiSelect` listbox or a `Popover` opened from the body — and traps Tab within that popup while it holds focus, so Tab walks and wraps that popup’s own stops rather than being yanked back to the panel’s first control or escaping the panel altogether. A `Dropdown` list or an `ActionMenu` is dismissed by Tab rather than trapping it: it closes and focus returns to its trigger, so Tab carries on from there. A consumer’s own portaled popup is not known to the trap and Tab will pull focus out of it. `callouts` stacks full-bleed `Alert` bands at the top of the body, above `children` and unaffected by `bodyPadding` — the same band `ConfirmationDialog` gives its `callout` — and `renderLink` routes their root-relative markdown links through the app’s router.
31
31
  - **`useHasOpenOverlay`** — Hook reporting whether any modal-type overlay - `SidePanel` or `Modal` - is open anywhere in the app. For host chrome that has to get out of an overlay’s way, a floating support widget being the case it was added for: overlays render through a portal, so a host has no DOM signal of its own to read, and reading the library’s internal markers would couple it to something it does not own. Dropdowns and tooltips are deliberately not counted - they do not trap focus, and chrome does not need to move for them. _Key props:_ No arguments. Returns a boolean.
32
32
  - **`SidePanelNavFooter`** — Keyboard-hint footer for SidePanel: up/down keycaps to step between records and an esc-to-close hint, with an optional right-aligned actions slot.
33
33
 
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`, `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), `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`, `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
+ - **`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`.
39
40
  - **`StatusBadge`** — Large status indicator (e.g. success checkmark) for terminal/confirmation screens. _Key props:_ `type`.
40
41
  - **`StatBadge`** — Pill showing a numeric value with a label (e.g. "3 accounts selected"). _Key props:_ `count`, `label`.
41
42
  - **`Tag`** — Small status/label tag. Types: success, error, warning, default. _Key props:_ `value`, `type`, `paddingSize`, `textTransform`, `WidthSize`, `tooltip` (hover-only; wrap in `Tooltip focusableTrigger` for keyboard reach), `tooltipDescribesTag`, `onClick` (makes it a button, unless `onRemove` is set; keep `value`/`icon` non-interactive), `onRemove`.
@@ -103,7 +104,7 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
103
104
  ## Typography
104
105
 
105
106
  - **`ClampText`** — Clamps text to N lines; expands to full text on hover/focus with a height animation. Wrapping markdown? Pass `variant="flow"` to the `Typography.MarkdownBlock` inside it, or the clamp counts blocks instead of lines.
106
- - **`Typography`** — Text primitives — use these instead of raw colour tokens on `<span>`s. Includes `Typography.Text`, `Typography.SecondaryText`, `Typography.EllipsisText`, etc., with size/weight/color props. `Typography.Text` takes `font="sans" | "heading" | "body" | "mono"`, and `as` (`p`, `h1`–`h6`) for a heading or paragraph that keeps its look; `Typography.CodeText` takes `variant="inline"` for a chip mid-sentence; `Typography.MarkdownBlock` takes `variant="flow"` for use inside `ClampText`, `variant="inline"` for one line of inline syntax set inside another component (no autolinks, images as alt text), `links="inert"` to draw links without an anchor inside a button, and `normalizeSource` for machine-generated descriptions that omit blank lines between blocks. `Typography.EllipsisText` takes a `size` so a truncating label can match the text beside it, and shows its `tooltip` on every hover unless `tooltipWhenTruncated` is set, which limits it to text that is actually cut off — for a tooltip that repeats the label, where a tooltip carrying something the label does not say should keep the default.
107
+ - **`Typography`** — Text primitives — use these instead of raw colour tokens on `<span>`s. Includes `Typography.Text`, `Typography.SecondaryText`, `Typography.EllipsisText`, etc., with size/weight/color props. `Typography.Text` takes `font="sans" | "heading" | "body" | "mono"`, and `as` (`p`, `h1`–`h6`) for a heading or paragraph that keeps its look; `Typography.CodeText` takes `variant="inline"` for a chip mid-sentence; `Typography.MarkdownBlock` takes `variant="flow"` for use inside `ClampText`, `variant="inline"` for one line of inline syntax set inside another component (no autolinks, images as alt text), `links="inert"` to draw links without an anchor inside a button, `renderLink` to send root-relative links (`/path`, never `//host`) through the app’s router in the same tab while every other link still opens in a new one — without it every link opens in a new tab, and `normalizeSource` for machine-generated descriptions that omit blank lines between blocks. `Typography.EllipsisText` takes a `size` so a truncating label can match the text beside it, and shows its `tooltip` on every hover unless `tooltipWhenTruncated` is set, which limits it to text that is actually cut off — for a tooltip that repeats the label, where a tooltip carrying something the label does not say should keep the default.
107
108
 
108
109
  ## Data display
109
110
 
@@ -1,16 +1,16 @@
1
- import { jsxs as i, jsx as e, Fragment as j } from "react/jsx-runtime";
2
- import { useState as B } from "react";
3
- import { Button as E } from "./Button.js";
4
- import F from "./CustomIcons/CaretDownIcon.js";
5
- import S from "./CustomIcons/CaretUpIcon.js";
6
- import O from "./CustomIcons/CheckCircleFilled.js";
7
- import z from "./CustomIcons/ErrorCircleFilled.js";
8
- import A from "./CustomIcons/InfoCircleFilled.js";
9
- import R from "./CustomIcons/SparkleIcon.js";
10
- import W from "./CustomIcons/WarningCircleFilled.js";
11
- import H from "./Typography/MarkdownBlock.js";
12
- import { getTextColor as L } from "./Typography/textStyles.js";
13
- const g = (r) => {
1
+ import { jsxs as i, jsx as e, Fragment as B } from "react/jsx-runtime";
2
+ import { useState as E } from "react";
3
+ import { Button as F } from "./Button.js";
4
+ import S from "./CustomIcons/CaretDownIcon.js";
5
+ import O from "./CustomIcons/CaretUpIcon.js";
6
+ import z from "./CustomIcons/CheckCircleFilled.js";
7
+ import A from "./CustomIcons/ErrorCircleFilled.js";
8
+ import R from "./CustomIcons/InfoCircleFilled.js";
9
+ import W from "./CustomIcons/SparkleIcon.js";
10
+ import H from "./CustomIcons/WarningCircleFilled.js";
11
+ import M from "./Typography/MarkdownBlock.js";
12
+ import { getTextColor as $ } from "./Typography/textStyles.js";
13
+ const C = (r) => {
14
14
  switch (r) {
15
15
  case "info":
16
16
  return "primary";
@@ -37,27 +37,27 @@ const g = (r) => {
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
- }, M = {
40
+ }, D = {
41
41
  info: /* @__PURE__ */ e(
42
- A,
42
+ R,
43
43
  {
44
44
  style: { ...s, color: n.info }
45
45
  }
46
46
  ),
47
47
  success: /* @__PURE__ */ e(
48
- O,
48
+ z,
49
49
  {
50
50
  style: { ...s, color: n.success }
51
51
  }
52
52
  ),
53
53
  error: /* @__PURE__ */ e(
54
- z,
54
+ A,
55
55
  {
56
56
  style: { ...s, color: n.error }
57
57
  }
58
58
  ),
59
59
  warning: /* @__PURE__ */ e(
60
- W,
60
+ H,
61
61
  {
62
62
  style: { ...s, color: n.warning }
63
63
  }
@@ -65,75 +65,92 @@ const g = (r) => {
65
65
  // The same sparkle the control that produced the message carries, so the two read as
66
66
  // one thread rather than two unrelated affordances.
67
67
  assistant: /* @__PURE__ */ e(
68
- R,
68
+ W,
69
69
  {
70
70
  style: { ...s, color: n.assistant }
71
71
  }
72
72
  )
73
- }, p = (r, l) => l ? /* @__PURE__ */ e(
73
+ }, g = (r, l) => l ? /* @__PURE__ */ e(
74
74
  "span",
75
75
  {
76
76
  className: "alert-status-icon inline-flex shrink-0 [&_svg]:size-full!",
77
77
  style: { ...s, color: n[r] },
78
78
  children: l
79
79
  }
80
- ) : M[r], v = ({ text: r, type: l }) => /* @__PURE__ */ e(H, { text: r, color: g(l), size: "small", omitMargin: !0 }), Z = ({
80
+ ) : D[r], w = ({ text: r, type: l, renderLink: c }) => /* @__PURE__ */ e(
81
+ M,
82
+ {
83
+ text: r,
84
+ color: C(l),
85
+ size: "small",
86
+ omitMargin: !0,
87
+ renderLink: c
88
+ }
89
+ ), ee = ({
81
90
  type: r = "info",
82
91
  message: l,
83
- hasMargin: w = !0,
84
- className: C,
85
- children: m,
86
- isExpanded: c,
87
- onToggle: d,
92
+ hasMargin: c = !0,
93
+ className: N,
94
+ children: f,
95
+ isExpanded: d,
96
+ onToggle: m,
88
97
  action: o,
89
- icon: f,
90
- live: N = !1
98
+ icon: x,
99
+ live: b = !1,
100
+ renderLink: u
91
101
  }) => {
92
- const t = !!m, x = N ? r === "error" || r === "warning" ? "alert" : "status" : void 0, [b, I] = B(!1), a = c !== void 0 ? c : b, k = () => {
93
- const h = !a;
94
- c === void 0 && I(h), d == null || d(h);
95
- }, u = [
102
+ const t = !!f, h = b ? r === "error" || r === "warning" ? "alert" : "status" : void 0, [I, y] = E(!1), a = d !== void 0 ? d : I, k = () => {
103
+ const v = !a;
104
+ d === void 0 && y(v), m == null || m(v);
105
+ }, p = [
96
106
  "alert-base",
97
107
  `alert-${r}`,
98
108
  "flex",
99
109
  "w-full",
100
110
  // Ensure full width
101
111
  t && a ? "flex-col" : "gap-2 items-center min-h-[2rem]",
102
- w ? "" : "alert-no-margin",
112
+ c ? "" : "alert-no-margin",
103
113
  "text-left",
104
114
  t ? "rounded-xl !p-0" : "!px-2.5 !py-1.5",
105
115
  // Slightly more vertical padding for centering
106
- C
107
- ].filter(Boolean).join(" "), y = [
116
+ N
117
+ ].filter(Boolean).join(" "), _ = [
108
118
  "flex items-center justify-between w-full",
109
119
  t ? "gap-2 px-2.5 py-1" : "gap-2",
110
120
  t && a ? "rounded-t-xl" : t ? "rounded-xl" : ""
111
- ].filter(Boolean).join(" "), _ = ["w-full", "overflow-hidden"].filter(Boolean).join(" ");
112
- return t ? /* @__PURE__ */ i("div", { className: `${u} alert-expandable`, children: [
113
- /* @__PURE__ */ i("div", { className: y, children: [
121
+ ].filter(Boolean).join(" "), j = ["w-full", "overflow-hidden"].filter(Boolean).join(" ");
122
+ return t ? /* @__PURE__ */ i("div", { className: `${p} alert-expandable`, children: [
123
+ /* @__PURE__ */ i("div", { className: _, children: [
114
124
  /* @__PURE__ */ i("div", { className: "flex-1 flex gap-2 items-center", children: [
115
- p(r, f),
116
- /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: x, children: /* @__PURE__ */ e(v, { text: l, type: r }) }) })
125
+ g(r, x),
126
+ /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: h, children: /* @__PURE__ */ e(
127
+ w,
128
+ {
129
+ text: l,
130
+ type: r,
131
+ renderLink: u
132
+ }
133
+ ) }) })
117
134
  ] }),
118
135
  /* @__PURE__ */ i("div", { className: "flex items-center gap-2", children: [
119
136
  o && /* @__PURE__ */ e("div", { className: "alert-action flex items-center", children: o }),
120
137
  /* @__PURE__ */ e(
121
- E,
138
+ F,
122
139
  {
123
140
  variant: "no-style",
124
141
  size: "xsmall",
125
142
  onClick: k,
126
143
  "aria-label": a ? "Collapse" : "Expand",
127
144
  style: {
128
- color: L(g(r))
145
+ color: $(C(r))
129
146
  },
130
147
  children: a ? /* @__PURE__ */ e(
131
- S,
148
+ O,
132
149
  {
133
150
  style: { minWidth: "13px", minHeight: "13px" }
134
151
  }
135
152
  ) : /* @__PURE__ */ e(
136
- F,
153
+ S,
137
154
  {
138
155
  style: { minWidth: "13px", minHeight: "13px" }
139
156
  }
@@ -142,15 +159,15 @@ const g = (r) => {
142
159
  )
143
160
  ] })
144
161
  ] }),
145
- a && /* @__PURE__ */ e(j, { children: /* @__PURE__ */ e("div", { className: _, 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: m }) }) })
146
- ] }) : /* @__PURE__ */ i("div", { className: u, children: [
147
- p(r, f),
148
- /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: x, children: /* @__PURE__ */ e(v, { text: l, type: r }) }) }),
162
+ a && /* @__PURE__ */ e(B, { children: /* @__PURE__ */ e("div", { className: j, 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: f }) }) })
163
+ ] }) : /* @__PURE__ */ i("div", { className: p, children: [
164
+ g(r, x),
165
+ /* @__PURE__ */ e("div", { className: "flex-1 flex items-center", children: /* @__PURE__ */ e("div", { className: "[&>div]:mb-0", role: h, children: /* @__PURE__ */ e(w, { text: l, type: r, renderLink: u }) }) }),
149
166
  o && /* @__PURE__ */ e("div", { className: "alert-action shrink-0 flex items-center", children: o })
150
167
  ] });
151
168
  };
152
169
  export {
153
- Z as Alert,
154
- Z as default
170
+ ee as Alert,
171
+ ee as default
155
172
  };
156
173
  //# 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 MarkdownBlock from './Typography/MarkdownBlock';\nimport type { TextColor } from './Typography/Text';\nimport { getTextColor } from './Typography/textStyles';\n\nexport type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';\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}\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: (\n <InfoCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.info }}\n />\n ),\n success: (\n <CheckCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.success }}\n />\n ),\n error: (\n <ErrorCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.error }}\n />\n ),\n warning: (\n <WarningCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.warning }}\n />\n ),\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: (\n <SparkleIcon\n style={{ ...ICON_STYLE, color: ICON_COLOR.assistant }}\n />\n ),\n};\n\nconst statusIcon = (type: AlertType, icon: React.ReactNode) =>\n icon ? (\n <span\n className=\"alert-status-icon inline-flex shrink-0 [&_svg]:size-full!\"\n style={{ ...ICON_STYLE, color: ICON_COLOR[type] }}\n >\n {icon}\n </span>\n ) : (\n AlertIcon[type]\n );\n\nconst SimpleTextRenderer: React.FC<{ text: string; type: AlertType }> = ({ text, type }) => {\n return <MarkdownBlock text={text} color={getAlertTextColor(type)} size=\"small\" omitMargin />;\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}) => {\n const isExpandable = !!children;\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 isExpandable && expanded ? 'flex-col' : 'gap-2 items-center min-h-[2rem]',\n !hasMargin ? 'alert-no-margin' : '',\n 'text-left',\n 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 return (\n <div className={alertClasses}>\n {statusIcon(type, icon)}\n <div className=\"flex-1 flex items-center\">\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer text={message} type={type} />\n </div>\n </div>\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 text={message} type={type} />\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\n style={{ minWidth: '13px', minHeight: '13px' }}\n />\n ) : (\n <CaretDownIcon\n style={{ minWidth: '13px', minHeight: '13px' }}\n />\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","statusIcon","type","icon","SimpleTextRenderer","text","MarkdownBlock","Alert","message","hasMargin","className","children","isExpanded","onToggle","action","live","isExpandable","liveRole","internalExpanded","setInternalExpanded","useState","expanded","handleToggle","newExpanded","alertClasses","headerClasses","expandableContentClasses","jsxs","Button","getTextColor","CaretUpIcon","CaretDownIcon","Fragment"],"mappings":";;;;;;;;;;;;AA2CA,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,MACI,gBAAAC;AAAA,IAACC;AAAA,IAAA;AAAA,MACG,OAAO,EAAE,GAAGJ,GAAY,OAAOC,EAAW,KAAA;AAAA,IAAK;AAAA,EAAA;AAAA,EAGvD,SACI,gBAAAE;AAAA,IAACE;AAAA,IAAA;AAAA,MACG,OAAO,EAAE,GAAGL,GAAY,OAAOC,EAAW,QAAA;AAAA,IAAQ;AAAA,EAAA;AAAA,EAG1D,OACI,gBAAAE;AAAA,IAACG;AAAA,IAAA;AAAA,MACG,OAAO,EAAE,GAAGN,GAAY,OAAOC,EAAW,MAAA;AAAA,IAAM;AAAA,EAAA;AAAA,EAGxD,SACI,gBAAAE;AAAA,IAACI;AAAA,IAAA;AAAA,MACG,OAAO,EAAE,GAAGP,GAAY,OAAOC,EAAW,QAAA;AAAA,IAAQ;AAAA,EAAA;AAAA;AAAA;AAAA,EAK1D,WACI,gBAAAE;AAAA,IAACK;AAAA,IAAA;AAAA,MACG,OAAO,EAAE,GAAGR,GAAY,OAAOC,EAAW,UAAA;AAAA,IAAU;AAAA,EAAA;AAGhE,GAEMQ,IAAa,CAACC,GAAiBC,MACjCA,IACI,gBAAAR;AAAA,EAAC;AAAA,EAAA;AAAA,IACG,WAAU;AAAA,IACV,OAAO,EAAE,GAAGH,GAAY,OAAOC,EAAWS,CAAI,EAAA;AAAA,IAE7C,UAAAC;AAAA,EAAA;AACL,IAEAT,EAAUQ,CAAI,GAGhBE,IAAkE,CAAC,EAAE,MAAAC,GAAM,MAAAH,QACtE,gBAAAP,EAACW,GAAA,EAAc,MAAAD,GAAY,OAAOf,EAAkBY,CAAI,GAAG,MAAK,SAAQ,YAAU,GAAA,CAAC,GAGxFK,IAA8B,CAAC;AAAA,EACjC,MAAAL,IAAO;AAAA,EACP,SAAAM;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,WAAAC;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,EACA,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,MAAAX;AAAA,EACA,MAAAY,IAAO;AACX,MAAM;AACF,QAAMC,IAAe,CAAC,CAACL,GAEjBM,IAAWF,IADFb,MAAS,WAAWA,MAAS,YACV,UAAU,WAAY,QAClD,CAACgB,GAAkBC,CAAmB,IAAIC,EAAS,EAAK,GAGxDC,IAAWT,MAAe,SAAYA,IAAaM,GAEnDI,IAAe,MAAM;AACvB,UAAMC,IAAc,CAACF;AACrB,IAAIT,MAAe,UAEfO,EAAoBI,CAAW,GAGnCV,KAAA,QAAAA,EAAWU;AAAA,EACf,GAEMC,IAAe;AAAA,IACjB;AAAA,IACA,SAAStB,CAAI;AAAA,IACb;AAAA,IACA;AAAA;AAAA,IACAc,KAAgBK,IAAW,aAAa;AAAA,IACvCZ,IAAgC,KAApB;AAAA,IACb;AAAA,IACAO,IAAe,oBAAoB;AAAA;AAAA,IACnCN;AAAA,EAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG,GAEPe,IAAgB;AAAA,IAClB;AAAA,IACAT,IAAe,sBAAsB;AAAA,IACrCA,KAAgBK,IAAW,iBAAiBL,IAAe,eAAe;AAAA,EAAA,EAEzE,OAAO,OAAO,EACd,KAAK,GAAG,GAEPU,IAA2B,CAAC,UAAU,iBAAiB,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAGvF,SAAKV,IAgBD,gBAAAW,EAAC,OAAA,EAAI,WAAW,GAAGH,CAAY,qBAE3B,UAAA;AAAA,IAAA,gBAAAG,EAAC,OAAA,EAAI,WAAWF,GACZ,UAAA;AAAA,MAAA,gBAAAE,EAAC,OAAA,EAAI,WAAU,kCACV,UAAA;AAAA,QAAA1B,EAAWC,GAAMC,CAAI;AAAA,0BACrB,OAAA,EAAI,WAAU,4BACX,UAAA,gBAAAR,EAAC,SAAI,WAAU,gBAAe,MAAMsB,GAChC,4BAACb,GAAA,EAAmB,MAAMI,GAAS,MAAAN,GAAY,GACnD,EAAA,CACJ;AAAA,MAAA,GACJ;AAAA,MAGA,gBAAAyB,EAAC,OAAA,EAAI,WAAU,2BACV,UAAA;AAAA,QAAAb,KAAU,gBAAAnB,EAAC,OAAA,EAAI,WAAU,kCAAkC,UAAAmB,GAAO;AAAA,QAEnE,gBAAAnB;AAAA,UAACiC;AAAA,UAAA;AAAA,YACG,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAASN;AAAA,YACT,cAAYD,IAAW,aAAa;AAAA,YACpC,OAAO;AAAA,cACH,OAAOQ,EAAavC,EAAkBY,CAAI,CAAC;AAAA,YAAA;AAAA,YAG9C,UAAAmB,IACG,gBAAA1B;AAAA,cAACmC;AAAA,cAAA;AAAA,gBACG,OAAO,EAAE,UAAU,QAAQ,WAAW,OAAA;AAAA,cAAO;AAAA,YAAA,IAGjD,gBAAAnC;AAAA,cAACoC;AAAA,cAAA;AAAA,gBACG,OAAO,EAAE,UAAU,QAAQ,WAAW,OAAA;AAAA,cAAO;AAAA,YAAA;AAAA,UACjD;AAAA,QAAA;AAAA,MAER,EAAA,CACJ;AAAA,IAAA,GACJ;AAAA,IAGCV,KACG,gBAAA1B,EAAAqC,GAAA,EACI,UAAA,gBAAArC,EAAC,OAAA,EAAI,WAAW+B,GACZ,UAAA,gBAAA/B,EAAC,OAAA,EAAI,WAAU,6KACV,UAAAgB,EAAA,CACL,EAAA,CACJ,EAAA,CACJ;AAAA,EAAA,GAER,IA9DI,gBAAAgB,EAAC,OAAA,EAAI,WAAWH,GACX,UAAA;AAAA,IAAAvB,EAAWC,GAAMC,CAAI;AAAA,sBACrB,OAAA,EAAI,WAAU,4BACX,UAAA,gBAAAR,EAAC,SAAI,WAAU,gBAAe,MAAMsB,GAChC,4BAACb,GAAA,EAAmB,MAAMI,GAAS,MAAAN,EAAA,CAAY,GACnD,GACJ;AAAA,IACCY,KAAU,gBAAAnB,EAAC,OAAA,EAAI,WAAU,2CAA2C,UAAAmB,EAAA,CAAO;AAAA,EAAA,GAChF;AAwDZ;"}
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 { getTextColor } from './Typography/textStyles';\n\nexport type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';\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}\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: (\n <InfoCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.info }}\n />\n ),\n success: (\n <CheckCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.success }}\n />\n ),\n error: (\n <ErrorCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.error }}\n />\n ),\n warning: (\n <WarningCircleFilled\n style={{ ...ICON_STYLE, color: ICON_COLOR.warning }}\n />\n ),\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: (\n <SparkleIcon\n style={{ ...ICON_STYLE, color: ICON_COLOR.assistant }}\n />\n ),\n};\n\nconst statusIcon = (type: AlertType, icon: React.ReactNode) =>\n icon ? (\n <span\n className=\"alert-status-icon inline-flex shrink-0 [&_svg]:size-full!\"\n style={{ ...ICON_STYLE, color: ICON_COLOR[type] }}\n >\n {icon}\n </span>\n ) : (\n AlertIcon[type]\n );\n\nconst SimpleTextRenderer: React.FC<{\n text: string;\n type: AlertType;\n renderLink?: RenderLink;\n}> = ({ text, type, renderLink }) => {\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}) => {\n const isExpandable = !!children;\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 isExpandable && expanded ? 'flex-col' : 'gap-2 items-center min-h-[2rem]',\n !hasMargin ? 'alert-no-margin' : '',\n 'text-left',\n 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 return (\n <div className={alertClasses}>\n {statusIcon(type, icon)}\n <div className=\"flex-1 flex items-center\">\n <div className=\"[&>div]:mb-0\" role={liveRole}>\n <SimpleTextRenderer text={message} type={type} renderLink={renderLink} />\n </div>\n </div>\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 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\n style={{ minWidth: '13px', minHeight: '13px' }}\n />\n ) : (\n <CaretDownIcon\n style={{ minWidth: '13px', minHeight: '13px' }}\n />\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","statusIcon","type","icon","SimpleTextRenderer","text","renderLink","MarkdownBlock","Alert","message","hasMargin","className","children","isExpanded","onToggle","action","live","isExpandable","liveRole","internalExpanded","setInternalExpanded","useState","expanded","handleToggle","newExpanded","alertClasses","headerClasses","expandableContentClasses","jsxs","Button","getTextColor","CaretUpIcon","CaretDownIcon","Fragment"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Breadcrumbs.js","sources":["../../src/components/Breadcrumbs.tsx"],"sourcesContent":["import React from 'react';\nimport Button from './Button';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport CaretRightIcon from './CustomIcons/CaretRightIcon';\nimport type { BreadcrumbLink, PageAction, RenderBreadcrumbLink } from './PageLayout/types';\nimport Text, { type TextColor } from './Typography/Text';\nimport { hasBackButton } from './breadcrumbsNav';\nimport { FOCUS_RING } from './focusRing';\nimport { isSafeHref, safeHref } from './safeHref';\n\nexport interface BreadcrumbsProps {\n links: BreadcrumbLink[];\n actions?: PageAction[];\n renderLink?: RenderBreadcrumbLink;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst CRUMB_LINK_CLASSES = `no-underline rounded-xs cursor-pointer transition-colors duration-200 ease-in-out hover:text-[var(--malachite-accent-foreground,rgb(2,122,66))] ${FOCUS_RING}`;\n\nconst BACK_BUTTON_CLASSES = `flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--malachite-radius-10,10px)] no-underline bg-[var(--malachite-number-tag-background,rgba(0,0,0,0.08))] text-[var(--malachite-text-primary,rgb(10,10,10))] transition-colors duration-200 ease-in-out hover:bg-[var(--malachite-number-tag-emphasis-background,rgba(0,0,0,0.15))] ${FOCUS_RING}`;\n\ntype LinkProps = Parameters<RenderBreadcrumbLink>[0];\n\nconst renderCrumbLink = (props: LinkProps, renderLink?: RenderBreadcrumbLink): React.ReactNode => {\n // An unsafe url degrades to plain text rather than a link that could run a script.\n if (!isSafeHref(props.href)) {\n return props.children;\n }\n return renderLink ? renderLink(props) : <a {...props} />;\n};\n\nconst renderCrumbName = (name: React.ReactNode, color: TextColor): React.ReactNode =>\n typeof name === 'string' ? (\n <Text size=\"medium\" fontWeight=\"semi-bold\" color={color}>\n {name}\n </Text>\n ) : (\n name\n );\n\nconst renderAction = (\n {\n label,\n onClick,\n disabled,\n variant,\n icon,\n href,\n target,\n tooltip,\n tooltipPlacement,\n }: PageAction,\n index: number,\n) => {\n const safe = safeHref(href);\n return (\n <Button\n key={`${index}-${label}`}\n size=\"small\"\n variant={variant ?? 'outline'}\n disabled={disabled}\n icon={icon}\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n href={safe}\n target={safe ? (target ?? '_blank') : undefined}\n onClick={safe ? undefined : onClick}\n >\n {label}\n </Button>\n );\n};\n\nconst Breadcrumbs: React.FC<BreadcrumbsProps> = ({\n links,\n actions,\n renderLink,\n className = '',\n style,\n}) => {\n // PageLayout mounts this unconditionally, so returning markup would leave an empty\n // navigation landmark on every page without crumbs.\n if (links.length === 0 && !actions?.length) {\n return null;\n }\n\n const isTitle = links.length === 1 && Boolean(links[0].isRoot);\n const parentCrumb = hasBackButton(links) ? links[links.length - 2] : undefined;\n const parentName = parentCrumb?.name;\n const hasActions = Boolean(actions?.length);\n\n return (\n <div\n className={`flex items-center ${hasActions ? 'justify-between' : ''} ${className}`}\n style={style}\n >\n {isTitle ? (\n renderCrumbName(links[0].name, 'primary')\n ) : (\n <div className=\"flex items-center gap-4\">\n {parentCrumb?.url &&\n renderCrumbLink(\n {\n href: parentCrumb.url,\n 'aria-label':\n typeof parentName === 'string'\n ? `Back to ${parentName}`\n : 'Go back',\n className: BACK_BUTTON_CLASSES,\n children: <ArrowLeftIcon size={12} />,\n },\n renderLink,\n )}\n {links.length > 0 && (\n <nav aria-label=\"Breadcrumb\">\n <ol className=\"flex flex-wrap items-center gap-2 m-0 p-0 list-none\">\n {links.map((link, index) => {\n const isLast = index === links.length - 1;\n const color: TextColor = isLast ? 'primary' : 'muted';\n\n return (\n <li\n key={`${link.url ?? ''}-${index}`}\n className=\"flex items-center gap-2\"\n aria-current={isLast && !link.url ? 'page' : undefined}\n >\n {link.url\n ? renderCrumbLink(\n {\n href: link.url,\n 'aria-current': isLast\n ? 'page'\n : undefined,\n className: `${CRUMB_LINK_CLASSES} ${\n isLast\n ? 'text-[var(--malachite-text-primary,rgb(10,10,10))]'\n : 'text-[var(--malachite-text-muted,rgb(76,75,75))]'\n }`,\n children: renderCrumbName(\n link.name,\n 'inherit',\n ),\n },\n renderLink,\n )\n : renderCrumbName(link.name, color)}\n {!isLast && (\n <span\n aria-hidden=\"true\"\n className=\"flex items-center text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n <CaretRightIcon size={13} />\n </span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n )}\n </div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-2\">{actions?.map(renderAction)}</div>\n )}\n </div>\n );\n};\n\nexport { Breadcrumbs };\nexport default Breadcrumbs;\n"],"names":["CRUMB_LINK_CLASSES","FOCUS_RING","BACK_BUTTON_CLASSES","renderCrumbLink","props","renderLink","isSafeHref","jsx","renderCrumbName","name","color","Text","renderAction","label","onClick","disabled","variant","icon","href","target","tooltip","tooltipPlacement","index","safe","safeHref","Button","Breadcrumbs","links","actions","className","style","isTitle","parentCrumb","hasBackButton","parentName","hasActions","jsxs","ArrowLeftIcon","link","isLast","CaretRightIcon"],"mappings":"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"}
1
+ {"version":3,"file":"Breadcrumbs.js","sources":["../../src/components/Breadcrumbs.tsx"],"sourcesContent":["import React from 'react';\nimport Button from './Button';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport CaretRightIcon from './CustomIcons/CaretRightIcon';\nimport type { BreadcrumbLink, PageAction, RenderLink } from './PageLayout/types';\nimport Text, { type TextColor } from './Typography/Text';\nimport { hasBackButton } from './breadcrumbsNav';\nimport { FOCUS_RING } from './focusRing';\nimport { isSafeHref, safeHref } from './safeHref';\n\nexport interface BreadcrumbsProps {\n links: BreadcrumbLink[];\n actions?: PageAction[];\n renderLink?: RenderLink;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst CRUMB_LINK_CLASSES = `no-underline rounded-xs cursor-pointer transition-colors duration-200 ease-in-out hover:text-[var(--malachite-accent-foreground,rgb(2,122,66))] ${FOCUS_RING}`;\n\nconst BACK_BUTTON_CLASSES = `flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--malachite-radius-10,10px)] no-underline bg-[var(--malachite-number-tag-background,rgba(0,0,0,0.08))] text-[var(--malachite-text-primary,rgb(10,10,10))] transition-colors duration-200 ease-in-out hover:bg-[var(--malachite-number-tag-emphasis-background,rgba(0,0,0,0.15))] ${FOCUS_RING}`;\n\ntype LinkProps = Parameters<RenderLink>[0];\n\nconst renderCrumbLink = (props: LinkProps, renderLink?: RenderLink): React.ReactNode => {\n // An unsafe url degrades to plain text rather than a link that could run a script.\n if (!isSafeHref(props.href)) {\n return props.children;\n }\n return renderLink ? renderLink(props) : <a {...props} />;\n};\n\nconst renderCrumbName = (name: React.ReactNode, color: TextColor): React.ReactNode =>\n typeof name === 'string' ? (\n <Text size=\"medium\" fontWeight=\"semi-bold\" color={color}>\n {name}\n </Text>\n ) : (\n name\n );\n\nconst renderAction = (\n {\n label,\n onClick,\n disabled,\n variant,\n icon,\n href,\n target,\n tooltip,\n tooltipPlacement,\n }: PageAction,\n index: number,\n) => {\n const safe = safeHref(href);\n return (\n <Button\n key={`${index}-${label}`}\n size=\"small\"\n variant={variant ?? 'outline'}\n disabled={disabled}\n icon={icon}\n tooltip={tooltip}\n tooltipPlacement={tooltipPlacement}\n href={safe}\n target={safe ? (target ?? '_blank') : undefined}\n onClick={safe ? undefined : onClick}\n >\n {label}\n </Button>\n );\n};\n\nconst Breadcrumbs: React.FC<BreadcrumbsProps> = ({\n links,\n actions,\n renderLink,\n className = '',\n style,\n}) => {\n // PageLayout mounts this unconditionally, so returning markup would leave an empty\n // navigation landmark on every page without crumbs.\n if (links.length === 0 && !actions?.length) {\n return null;\n }\n\n const isTitle = links.length === 1 && Boolean(links[0].isRoot);\n const parentCrumb = hasBackButton(links) ? links[links.length - 2] : undefined;\n const parentName = parentCrumb?.name;\n const hasActions = Boolean(actions?.length);\n\n return (\n <div\n className={`flex items-center ${hasActions ? 'justify-between' : ''} ${className}`}\n style={style}\n >\n {isTitle ? (\n renderCrumbName(links[0].name, 'primary')\n ) : (\n <div className=\"flex items-center gap-4\">\n {parentCrumb?.url &&\n renderCrumbLink(\n {\n href: parentCrumb.url,\n 'aria-label':\n typeof parentName === 'string'\n ? `Back to ${parentName}`\n : 'Go back',\n className: BACK_BUTTON_CLASSES,\n children: <ArrowLeftIcon size={12} />,\n },\n renderLink,\n )}\n {links.length > 0 && (\n <nav aria-label=\"Breadcrumb\">\n <ol className=\"flex flex-wrap items-center gap-2 m-0 p-0 list-none\">\n {links.map((link, index) => {\n const isLast = index === links.length - 1;\n const color: TextColor = isLast ? 'primary' : 'muted';\n\n return (\n <li\n key={`${link.url ?? ''}-${index}`}\n className=\"flex items-center gap-2\"\n aria-current={isLast && !link.url ? 'page' : undefined}\n >\n {link.url\n ? renderCrumbLink(\n {\n href: link.url,\n 'aria-current': isLast\n ? 'page'\n : undefined,\n className: `${CRUMB_LINK_CLASSES} ${\n isLast\n ? 'text-[var(--malachite-text-primary,rgb(10,10,10))]'\n : 'text-[var(--malachite-text-muted,rgb(76,75,75))]'\n }`,\n children: renderCrumbName(\n link.name,\n 'inherit',\n ),\n },\n renderLink,\n )\n : renderCrumbName(link.name, color)}\n {!isLast && (\n <span\n aria-hidden=\"true\"\n className=\"flex items-center text-[var(--malachite-text-dimmed,rgb(161,161,161))]\"\n >\n <CaretRightIcon size={13} />\n </span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n )}\n </div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-2\">{actions?.map(renderAction)}</div>\n )}\n </div>\n );\n};\n\nexport { Breadcrumbs };\nexport default Breadcrumbs;\n"],"names":["CRUMB_LINK_CLASSES","FOCUS_RING","BACK_BUTTON_CLASSES","renderCrumbLink","props","renderLink","isSafeHref","jsx","renderCrumbName","name","color","Text","renderAction","label","onClick","disabled","variant","icon","href","target","tooltip","tooltipPlacement","index","safe","safeHref","Button","Breadcrumbs","links","actions","className","style","isTitle","parentCrumb","hasBackButton","parentName","hasActions","jsxs","ArrowLeftIcon","link","isLast","CaretRightIcon"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { jsx as r } from "react/jsx-runtime";
2
+ import { Alert as o } from "./Alert.js";
3
+ const t = ({ type: a, message: e, renderLink: d }) => /* @__PURE__ */ r("div", { className: "border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]", children: /* @__PURE__ */ r(o, { type: a, message: e, hasMargin: !1, renderLink: d }) });
4
+ export {
5
+ t as default
6
+ };
7
+ //# sourceMappingURL=CalloutStrip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalloutStrip.js","sources":["../../src/components/CalloutStrip.tsx"],"sourcesContent":["import type React from 'react';\nimport Alert, { type AlertType } from './Alert';\nimport type { RenderLink } from './PageLayout/types';\n\ninterface CalloutStripProps {\n type?: AlertType;\n message: string;\n renderLink?: RenderLink;\n}\n\n/** A full-bleed band holding one Alert at the top of an overlay's body. */\nconst CalloutStrip: React.FC<CalloutStripProps> = ({ type, message, renderLink }) => (\n <div className=\"border-0 border-b border-solid border-[var(--malachite-card-subtle-divider,var(--malachite-card-border))] p-[10px]\">\n <Alert type={type} message={message} hasMargin={false} renderLink={renderLink} />\n </div>\n);\n\nexport default CalloutStrip;\n"],"names":["CalloutStrip","type","message","renderLink","jsx","Alert"],"mappings":";;AAWA,MAAMA,IAA4C,CAAC,EAAE,MAAAC,GAAM,SAAAC,GAAS,YAAAC,EAAA,MAChE,gBAAAC,EAAC,OAAA,EAAI,WAAU,sHACX,4BAACC,GAAA,EAAM,MAAAJ,GAAY,SAAAC,GAAkB,WAAW,IAAO,YAAAC,GAAwB,EAAA,CACnF;"}