@stackone/malachite 2.33.2 → 2.34.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.
@@ -1,77 +1,81 @@
1
- import { jsx as o, jsxs as k } from "react/jsx-runtime";
2
- import B from "react";
3
- import { paintOnChild as j } from "./asChild.js";
4
- import { DisclosureArrow as F } from "./DisclosureArrow.js";
5
- import { FOCUS_RING_INSET as _ } from "./focusRing.js";
6
- import { isRenderableNode as I } from "./renderableNode.js";
7
- import { FOREGROUND_RESET as G, SELECTED_TEXT_CONTEXT as P, SELECTED_ROW_ACCENT as U, SELECTED_ROW_FOREGROUND as W, SELECTED_ROW_BACKGROUND as w } from "./selectedRow.js";
8
- const X = {
1
+ import { jsx as o, jsxs as w } from "react/jsx-runtime";
2
+ import G from "react";
3
+ import { paintOnChild as P } from "./asChild.js";
4
+ import { DisclosureArrow as U } from "./DisclosureArrow.js";
5
+ import { FOCUS_RING_INSET as D } from "./focusRing.js";
6
+ import { resolveRel as $ } from "./linkRel.js";
7
+ import { safeHref as W } from "./safeHref.js";
8
+ import { isRenderableNode as X } from "./renderableNode.js";
9
+ import { FOREGROUND_RESET as H, SELECTED_TEXT_CONTEXT as z, SELECTED_ROW_ACCENT as K, SELECTED_ROW_FOREGROUND as q, SELECTED_ROW_BACKGROUND as T } from "./selectedRow.js";
10
+ const J = {
9
11
  default: "",
10
12
  muted: "bg-[var(--malachite-card-dimmed-background)]",
11
13
  success: "bg-[var(--malachite-tag-success-background)]",
12
14
  error: "bg-[var(--malachite-tag-error-background)]"
13
- }, z = {
15
+ }, M = {
14
16
  success: "var(--malachite-tag-success-foreground)",
15
17
  error: "var(--malachite-tag-error-foreground)"
16
- }, H = "0px 0px 4px 0px rgba(0,0,0,0.08), 0px 4px 4px 0px rgba(0,0,0,0.08), 0px 4px 10px 0px rgba(0,0,0,0.05)", O = (t) => {
18
+ }, Q = "0px 0px 4px 0px rgba(0,0,0,0.08), 0px 4px 4px 0px rgba(0,0,0,0.08), 0px 4px 10px 0px rgba(0,0,0,0.05)", L = (t) => {
17
19
  const {
18
20
  children: a,
19
21
  divider: r = !1,
20
22
  disabled: e = !1,
21
- selected: n,
22
- selection: u,
23
+ selected: s,
24
+ selection: b,
23
25
  tone: c = "default",
24
- className: m = "",
26
+ className: u = "",
25
27
  style: g
26
- } = t, d = t.asChild === !0, { onClick: i, href: s, trailing: b, role: l } = d ? {} : t, p = d ? void 0 : t["aria-label"], h = d ? void 0 : t["aria-labelledby"], C = !!(i || s), T = e && (C || d) ? "" : "transition-colors hover:bg-[var(--malachite-buttonlist-hover-background)]", D = c !== "default", R = [
28
+ } = t, d = t.asChild === !0, { onClick: l, href: E, target: i, rel: C, trailing: S, role: n } = d ? {} : t, f = W(E), p = d ? void 0 : t["aria-label"], h = d ? void 0 : t["aria-labelledby"], N = !!(l || f), B = e && (N || d) ? "" : "transition-colors hover:bg-[var(--malachite-buttonlist-hover-background)]", j = c !== "default", _ = [
27
29
  "w-full text-left border-0",
28
- X[c],
30
+ J[c],
29
31
  r ? "border-b border-solid border-[var(--malachite-card-border)]" : "",
30
- T
31
- ].filter(Boolean).join(" "), y = [
32
- C ? `appearance-none ${D ? "" : "bg-transparent"} p-0 ${_}` : "",
33
- C && !e ? "cursor-pointer" : ""
34
- ].filter(Boolean).join(" "), E = [R, y, m].filter(Boolean).join(" "), L = n && (u ? u === "highlight" : l !== "checkbox") ? {
35
- backgroundImage: `linear-gradient(${w}, ${w})`,
36
- color: W,
37
- boxShadow: `inset 2px 0 0 ${U}`,
38
- ...P
39
- } : {}, N = z[c], x = { ...N ? {
40
- color: N,
41
- "--malachite-ctx-text-primary": N
42
- } : {}, ...L, ...g }, f = l === "radio" || l === "checkbox" ? !!n : void 0, v = f === void 0 && n ? !0 : void 0, S = {
43
- role: l,
44
- "aria-checked": f,
32
+ B
33
+ ].filter(Boolean).join(" "), k = [
34
+ N ? `appearance-none ${j ? "" : "bg-transparent"} p-0 ${D}` : "",
35
+ N && !e ? "cursor-pointer" : ""
36
+ ].filter(Boolean).join(" "), y = [_, k, u].filter(Boolean).join(" "), F = s && (b ? b === "highlight" : n !== "checkbox") ? {
37
+ backgroundImage: `linear-gradient(${T}, ${T})`,
38
+ color: q,
39
+ boxShadow: `inset 2px 0 0 ${K}`,
40
+ ...z
41
+ } : {}, R = M[c], x = { ...R ? {
42
+ color: R,
43
+ "--malachite-ctx-text-primary": R
44
+ } : {}, ...F, ...g }, m = n === "radio" || n === "checkbox" ? !!s : void 0, v = m === void 0 && s ? !0 : void 0, O = {
45
+ role: n,
46
+ "aria-checked": m,
45
47
  "aria-current": v,
46
48
  "aria-label": p,
47
49
  "aria-labelledby": h,
48
- "aria-disabled": l && e ? !0 : void 0
50
+ "aria-disabled": n && e ? !0 : void 0
49
51
  };
50
52
  if (d)
51
- return j(a, E, x);
52
- if (I(b)) {
53
- const A = s && !e ? /* @__PURE__ */ o(
53
+ return P(a, y, x);
54
+ if (X(S)) {
55
+ const I = f && !e ? /* @__PURE__ */ o(
54
56
  "a",
55
57
  {
56
- href: s,
57
- onClick: i,
58
- className: `${y} border-0 flex-1 min-w-0 text-left no-underline text-inherit`,
59
- role: l,
60
- "aria-checked": f,
58
+ href: f,
59
+ target: i,
60
+ rel: $(C, i),
61
+ onClick: l,
62
+ className: `${k} border-0 flex-1 min-w-0 text-left no-underline text-inherit`,
63
+ role: n,
64
+ "aria-checked": m,
61
65
  "aria-current": v,
62
66
  "aria-label": p,
63
67
  "aria-labelledby": h,
64
68
  children: a
65
69
  }
66
- ) : i ? /* @__PURE__ */ o(
70
+ ) : l ? /* @__PURE__ */ o(
67
71
  "button",
68
72
  {
69
73
  type: "button",
70
- onClick: i,
74
+ onClick: l,
71
75
  disabled: e,
72
- className: `${y} border-0 flex-1 min-w-0 text-left`,
73
- role: l,
74
- "aria-checked": f,
76
+ className: `${k} border-0 flex-1 min-w-0 text-left`,
77
+ role: n,
78
+ "aria-checked": m,
75
79
  "aria-current": v,
76
80
  "aria-label": p,
77
81
  "aria-labelledby": h,
@@ -80,123 +84,125 @@ const X = {
80
84
  ) : (
81
85
  // The set goes here, not on the wrapper: `radio` and `checkbox` make their
82
86
  // descendants presentational, which would bury a control in the trailing slot.
83
- /* @__PURE__ */ o("div", { className: "flex-1 min-w-0", ...S, children: a })
87
+ /* @__PURE__ */ o("div", { className: "flex-1 min-w-0", ...O, children: a })
84
88
  );
85
- return /* @__PURE__ */ k(
89
+ return /* @__PURE__ */ w(
86
90
  "div",
87
91
  {
88
- className: [R, "flex items-center", m].filter(Boolean).join(" "),
92
+ className: [_, "flex items-center", u].filter(Boolean).join(" "),
89
93
  style: x,
90
94
  children: [
91
- A,
92
- /* @__PURE__ */ o("div", { className: "shrink-0 flex items-center", children: b })
95
+ I,
96
+ /* @__PURE__ */ o("div", { className: "shrink-0 flex items-center", children: S })
93
97
  ]
94
98
  }
95
99
  );
96
100
  }
97
- return s && !e ? /* @__PURE__ */ o(
101
+ return f && !e ? /* @__PURE__ */ o(
98
102
  "a",
99
103
  {
100
- href: s,
101
- onClick: i,
102
- className: `${E} no-underline text-inherit`,
104
+ href: f,
105
+ target: i,
106
+ rel: $(C, i),
107
+ onClick: l,
108
+ className: `${y} no-underline text-inherit`,
103
109
  style: x,
104
- role: l,
105
- "aria-checked": f,
110
+ role: n,
111
+ "aria-checked": m,
106
112
  "aria-current": v,
107
113
  "aria-label": p,
108
114
  "aria-labelledby": h,
109
115
  children: a
110
116
  }
111
- ) : i ? /* @__PURE__ */ o(
117
+ ) : l ? /* @__PURE__ */ o(
112
118
  "button",
113
119
  {
114
120
  type: "button",
115
- onClick: i,
121
+ onClick: l,
116
122
  disabled: e,
117
- className: E,
123
+ className: y,
118
124
  style: x,
119
- role: l,
120
- "aria-checked": f,
125
+ role: n,
126
+ "aria-checked": m,
121
127
  "aria-current": v,
122
128
  "aria-label": p,
123
129
  "aria-labelledby": h,
124
130
  children: a
125
131
  }
126
- ) : /* @__PURE__ */ o("div", { className: E, style: x, ...S, children: a });
127
- }, K = ({ children: t, className: a = "", style: r }) => /* @__PURE__ */ o("div", { className: a, style: r, onClick: (e) => e.stopPropagation(), children: t }), te = 39, q = Object.assign(
132
+ ) : /* @__PURE__ */ o("div", { className: y, style: x, ...O, children: a });
133
+ }, V = ({ children: t, className: a = "", style: r }) => /* @__PURE__ */ o("div", { className: a, style: r, onClick: (e) => e.stopPropagation(), children: t }), be = 39, Y = Object.assign(
128
134
  ({
129
135
  header: t,
130
136
  children: a,
131
137
  expanded: r,
132
138
  onToggle: e,
133
- sticky: n = !1,
134
- stickyTopOffset: u = 0,
139
+ sticky: s = !1,
140
+ stickyTopOffset: b = 0,
135
141
  divider: c = !1,
136
- tone: m = "default",
142
+ tone: u = "default",
137
143
  "aria-label": g,
138
144
  className: d = "",
139
- style: i
145
+ style: l
140
146
  }) => {
141
- const s = B.useId(), b = e ? () => e(!r) : void 0;
142
- return /* @__PURE__ */ k(O, { divider: c, tone: m, className: d, style: i, children: [
143
- /* @__PURE__ */ k(
147
+ const E = G.useId(), i = e ? () => e(!r) : void 0;
148
+ return /* @__PURE__ */ w(L, { divider: c, tone: u, className: d, style: l, children: [
149
+ /* @__PURE__ */ w(
144
150
  "div",
145
151
  {
146
- className: `group flex items-center w-full ${b ? "cursor-pointer" : ""} ${n && r ? "sticky z-[1] bg-[var(--malachite-card-background)]" : ""}`,
147
- style: n && r ? { top: u } : void 0,
148
- onClick: b,
152
+ className: `group flex items-center w-full ${i ? "cursor-pointer" : ""} ${s && r ? "sticky z-[1] bg-[var(--malachite-card-background)]" : ""}`,
153
+ style: s && r ? { top: b } : void 0,
154
+ onClick: i,
149
155
  role: "presentation",
150
156
  children: [
151
- /* @__PURE__ */ o("span", { className: "shrink-0 flex items-center pl-[16px] pr-[12px]", children: b && /* @__PURE__ */ o(
157
+ /* @__PURE__ */ o("span", { className: "shrink-0 flex items-center pl-[16px] pr-[12px]", children: i && /* @__PURE__ */ o(
152
158
  "button",
153
159
  {
154
160
  type: "button",
155
- className: `appearance-none bg-transparent border-0 p-0 flex items-center cursor-pointer ${_}`,
161
+ className: `appearance-none bg-transparent border-0 p-0 flex items-center cursor-pointer ${D}`,
156
162
  "aria-expanded": r,
157
- "aria-controls": s,
163
+ "aria-controls": E,
158
164
  "aria-label": g,
159
- onClick: (l) => {
160
- l.stopPropagation(), b();
165
+ onClick: (C) => {
166
+ C.stopPropagation(), i();
161
167
  },
162
- children: /* @__PURE__ */ o(F, { expanded: r })
168
+ children: /* @__PURE__ */ o(U, { expanded: r })
163
169
  }
164
170
  ) }),
165
171
  t
166
172
  ]
167
173
  }
168
174
  ),
169
- r && /* @__PURE__ */ o("div", { id: s, children: a })
175
+ r && /* @__PURE__ */ o("div", { id: E, children: a })
170
176
  ] });
171
177
  },
172
- { Controls: K }
173
- ), $ = ({
178
+ { Controls: V }
179
+ ), A = ({
174
180
  children: t,
175
181
  padding: a = !1,
176
182
  overflow: r = "hidden",
177
183
  role: e,
178
- "aria-label": n,
179
- "aria-labelledby": u,
184
+ "aria-label": s,
185
+ "aria-labelledby": b,
180
186
  className: c = "",
181
- style: m
187
+ style: u
182
188
  }) => /* @__PURE__ */ o(
183
189
  "div",
184
190
  {
185
191
  className: `w-full rounded-[var(--malachite-radius-xxl,14px)] ${r === "clip" ? "overflow-clip" : r === "visible" ? "overflow-visible" : "overflow-hidden"} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${a ? "py-3 px-4" : ""} ${c}`,
186
- style: { boxShadow: H, ...G, ...m },
192
+ style: { boxShadow: Q, ...H, ...u },
187
193
  role: e,
188
- "aria-label": n,
189
- "aria-labelledby": u,
194
+ "aria-label": s,
195
+ "aria-labelledby": b,
190
196
  children: t
191
197
  }
192
198
  );
193
- $.Row = O;
194
- $.ExpandableRow = q;
199
+ A.Row = L;
200
+ A.ExpandableRow = Y;
195
201
  export {
196
- te as EXPANDABLE_ROW_LEAD_PX,
197
- $ as Surface,
198
- q as SurfaceExpandableRow,
199
- O as SurfaceRow,
200
- $ as default
202
+ be as EXPANDABLE_ROW_LEAD_PX,
203
+ A as Surface,
204
+ Y as SurfaceExpandableRow,
205
+ L as SurfaceRow,
206
+ A as default
201
207
  };
202
208
  //# sourceMappingURL=Surface.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Surface.js","sources":["../../src/components/Surface.tsx"],"sourcesContent":["import React from 'react';\nimport { paintOnChild } from './asChild';\nimport DisclosureArrow from './DisclosureArrow';\nimport { FOCUS_RING_INSET } from './focusRing';\nimport { isRenderableNode } from './renderableNode';\nimport {\n FOREGROUND_RESET,\n SELECTED_ROW_ACCENT,\n SELECTED_ROW_BACKGROUND,\n SELECTED_ROW_FOREGROUND,\n SELECTED_TEXT_CONTEXT,\n} from './selectedRow';\n\nexport interface SurfaceProps {\n children?: React.ReactNode;\n padding?: boolean;\n /**\n * Content overflow. Defaults to `hidden` so children are clipped to the rounded\n * corners. Use `clip` to keep the rounded clipping WITHOUT creating a scroll\n * container — so a `position: sticky` descendant still pins (unlike `hidden`,\n * which traps it). `visible` disables clipping entirely.\n */\n overflow?: 'hidden' | 'visible' | 'clip';\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\ninterface SurfaceRowChromeProps {\n children?: React.ReactNode;\n /** Renders a bottom divider — omit on the last row in a Surface. */\n divider?: boolean;\n /** Removes the hover affordance / disables the control (e.g. while loading/busy). */\n disabled?: boolean;\n /** Announces the row as selected — `aria-checked` under a `radio`/`checkbox` role,\n * `aria-current` otherwise — and paints `Table`'s selected treatment unless `selection`\n * says not to. */\n selected?: boolean;\n /** How a `selected` row shows it. `highlight` paints the treatment; `announce` leaves the\n * visual to a control inside the row and only sets the ARIA state. Defaults to `announce`\n * under `role=\"checkbox\"` and `highlight` otherwise. */\n selection?: 'highlight' | 'announce';\n /**\n * Tints the whole row by what it reports. `muted` is a row whose subject is inactive —\n * not disabled: it stays interactive. `success` and `error` are for a row that carries\n * an outcome, where the result belongs to the whole line rather than to one cell in it.\n */\n tone?: 'default' | 'muted' | 'success' | 'error';\n className?: string;\n style?: React.CSSProperties;\n}\n\n/** Stays an interface under its original name: a consumer may `extends` it. */\nexport interface SurfaceRowProps extends SurfaceRowChromeProps {\n asChild?: false;\n /**\n * When provided, the whole row becomes clickable: it renders as a `<button>`\n * (or `<a>` when `href` is set), so the entire row is the click target with\n * native focus + Enter/Space — no manual tabIndex/key handlers. For a\n * selectable row, put a presentational `<Radio>`/`<Checkbox>` inside as the\n * visual indicator; do NOT nest an interactive control (invalid + double tab stop).\n */\n onClick?: (event: React.MouseEvent) => void;\n /** Renders the clickable row as an anchor instead of a button. */\n href?: string;\n /** Content pinned right, outside the row button, so it may hold its own control. */\n trailing?: React.ReactNode;\n /** ARIA role for a clickable row, e.g. `radio`/`checkbox` (wrap the list in a `radiogroup`). */\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * The outcome tones reuse the tag tokens rather than minting row ones, so a row saying \"this\n * passed\" and a tag saying it are the same green wherever the two sit together.\n */\nconst TONE_CLASSES: Record<NonNullable<SurfaceRowProps['tone']>, string> = {\n default: '',\n muted: 'bg-[var(--malachite-card-dimmed-background)]',\n success: 'bg-[var(--malachite-tag-success-background)]',\n error: 'bg-[var(--malachite-tag-error-background)]',\n};\n\n/**\n * The text an outcome tone carries with it, through the same context channel a selected row\n * uses, so `Typography` inside the row follows the tint instead of staying near-black on it.\n * `color` as well, for row content that is not Typography.\n *\n * Only the outcome tones. `muted` dims its subject rather than recolouring it, and its\n * foreground is the ordinary one.\n */\nconst TONE_FOREGROUNDS: Partial<Record<NonNullable<SurfaceRowProps['tone']>, string>> = {\n success: 'var(--malachite-tag-success-foreground)',\n error: 'var(--malachite-tag-error-foreground)',\n};\n\nexport interface SurfaceRowAsChildProps extends SurfaceRowChromeProps {\n asChild: true;\n children: React.ReactElement;\n}\n\nexport type AnySurfaceRowProps = SurfaceRowProps | SurfaceRowAsChildProps;\n\nconst TRIPLE_SHADOW =\n '0px 0px 4px 0px rgba(0,0,0,0.08), 0px 4px 4px 0px rgba(0,0,0,0.08), 0px 4px 10px 0px rgba(0,0,0,0.05)';\n\n/**\n * A single full-bleed row inside a <Surface>. Owns the row chrome — hover\n * highlight, colour transition and an optional bottom divider — so consumers\n * compose their own content inside without re-implementing design-system styling.\n * Pass `onClick`/`href` to make the entire row clickable (rendered as a real\n * button/anchor, so keyboard navigation works natively).\n */\nconst SurfaceRow: React.FC<AnySurfaceRowProps> = (props) => {\n const {\n children,\n divider = false,\n disabled = false,\n selected,\n selection,\n tone = 'default',\n className = '',\n style,\n } = props;\n const asChild = props.asChild === true;\n const { onClick, href, trailing, role } = asChild\n ? ({} as SurfaceRowProps)\n : (props as SurfaceRowProps);\n const ariaLabel = asChild ? undefined : (props as SurfaceRowProps)['aria-label'];\n const ariaLabelledBy = asChild ? undefined : (props as SurfaceRowProps)['aria-labelledby'];\n const interactive = Boolean(onClick || href);\n // `asChild` is interactive for the hover affordance only, not the focus/reset classes.\n const hover =\n disabled && (interactive || asChild)\n ? ''\n : 'transition-colors hover:bg-[var(--malachite-buttonlist-hover-background)]';\n\n // A class, not an inline colour, which would outrank the hover utility. It replaces the\n // button reset's `bg-transparent` rather than joining it: same specificity, so the winner\n // would be whichever Tailwind emitted last.\n const tinted = tone !== 'default';\n const toneClass = TONE_CLASSES[tone];\n\n const chromeClasses = [\n 'w-full text-left border-0',\n toneClass,\n divider ? 'border-b border-solid border-[var(--malachite-card-border)]' : '',\n hover,\n ]\n .filter(Boolean)\n .join(' ');\n\n const controlClasses = [\n interactive\n ? `appearance-none ${tinted ? '' : 'bg-transparent'} p-0 ${FOCUS_RING_INSET}`\n : '',\n interactive && !disabled ? 'cursor-pointer' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const classes = [chromeClasses, controlClasses, className].filter(Boolean).join(' ');\n\n const paints = selection ? selection === 'highlight' : role !== 'checkbox';\n\n // A gradient layer so the tint composites over hover, and an inset shadow because\n // `ring-*` silently doesn't paint in a shadow root.\n const selectedStyle: React.CSSProperties =\n selected && paints\n ? {\n backgroundImage: `linear-gradient(${SELECTED_ROW_BACKGROUND}, ${SELECTED_ROW_BACKGROUND})`,\n color: SELECTED_ROW_FOREGROUND,\n boxShadow: `inset 2px 0 0 ${SELECTED_ROW_ACCENT}`,\n ...SELECTED_TEXT_CONTEXT,\n }\n : {};\n\n const toneForeground = TONE_FOREGROUNDS[tone];\n const toneStyle: React.CSSProperties = toneForeground\n ? ({\n color: toneForeground,\n '--malachite-ctx-text-primary': toneForeground,\n } as React.CSSProperties)\n : {};\n\n // `selected` last of the two: a row can be both, and selection is the state the reader is\n // acting on, so it wins the colour.\n const rowStyle = { ...toneStyle, ...selectedStyle, ...style };\n\n const ariaChecked = role === 'radio' || role === 'checkbox' ? Boolean(selected) : undefined;\n // `aria-current`, not `aria-pressed`: a selected row is one of many choices, not a toggle\n // (same call as `Dropdown`'s options). A role that carries its own state uses that instead.\n const ariaCurrent = ariaChecked === undefined && selected ? true : undefined;\n\n // Everything a control would have carried, for the branches that render none: the row\n // element is then the only thing assistive tech sees. `aria-disabled` because there is no\n // control to be natively disabled — and it is inert without a role, like the name.\n const rowFallbackAria = {\n role,\n 'aria-checked': ariaChecked,\n 'aria-current': ariaCurrent,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-disabled': role && disabled ? true : undefined,\n };\n\n if (asChild) {\n return paintOnChild(children, classes, rowStyle);\n }\n\n if (isRenderableNode(trailing)) {\n const control =\n href && !disabled ? (\n <a\n href={href}\n onClick={onClick}\n className={`${controlClasses} border-0 flex-1 min-w-0 text-left no-underline text-inherit`}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </a>\n ) : onClick ? (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={`${controlClasses} border-0 flex-1 min-w-0 text-left`}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </button>\n ) : (\n // The set goes here, not on the wrapper: `radio` and `checkbox` make their\n // descendants presentational, which would bury a control in the trailing slot.\n <div className=\"flex-1 min-w-0\" {...rowFallbackAria}>\n {children}\n </div>\n );\n\n return (\n <div\n className={[chromeClasses, 'flex items-center', className]\n .filter(Boolean)\n .join(' ')}\n style={rowStyle}\n >\n {control}\n <div className=\"shrink-0 flex items-center\">{trailing}</div>\n </div>\n );\n }\n\n if (href && !disabled) {\n return (\n <a\n href={href}\n onClick={onClick}\n className={`${classes} no-underline text-inherit`}\n style={rowStyle}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </a>\n );\n }\n\n if (onClick) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={classes}\n style={rowStyle}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </button>\n );\n }\n\n return (\n <div className={classes} style={rowStyle} {...rowFallbackAria}>\n {children}\n </div>\n );\n};\n\nexport interface SurfaceExpandableRowProps {\n /** The row itself, laid out across the line. May hold its own controls. */\n header: React.ReactNode;\n /** The body, rendered beneath the row while it is open. */\n children?: React.ReactNode;\n expanded: boolean;\n /** Omit for a row that cannot open. The arrow's space is still reserved, so a list of\n * rows stays in one column whether or not each one has a body. */\n onToggle?: (expanded: boolean) => void;\n /**\n * Pins the row while its body scrolls, so a long body never leaves the reader without\n * the line it belongs to. Offset by whatever is already pinned above it.\n */\n sticky?: boolean;\n stickyTopOffset?: number;\n divider?: boolean;\n tone?: SurfaceRowProps['tone'];\n /** Names the disclosure control, which is otherwise only an arrow. */\n 'aria-label'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Stops a click inside it from toggling the row, for the cells that hold controls.\n *\n * Explicit rather than sniffing the event's target for an interactive ancestor: a control\n * rendering into a shadow root retargets the event to its host, so the sniff would miss\n * exactly the components most likely to sit in a row.\n */\nconst ExpandableRowControls: React.FC<{\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}> = ({ children, className = '', style }) => (\n <div className={className} style={style} onClick={(event) => event.stopPropagation()}>\n {children}\n </div>\n);\n\n/**\n * A row that opens to reveal a body, for a line that carries its own controls.\n *\n * Not `Accordion`: that puts its header inside the toggle button, so a header holding a\n * dropdown or a second button is invalid. Here the row surface takes the click and a cell\n * opts out with `ExpandableRow.Controls`, while the arrow stays a real button so the\n * keyboard reaches it.\n */\n/**\n * The space before the header: the arrow's own inset, its glyph and the gap after it.\n * Exported so a consumer aligning a column header above these rows offsets by the same\n * amount instead of guessing at it.\n */\nexport const EXPANDABLE_ROW_LEAD_PX = 39;\n\nconst SurfaceExpandableRow: React.FC<SurfaceExpandableRowProps> & {\n Controls: typeof ExpandableRowControls;\n} = Object.assign(\n ({\n header,\n children,\n expanded,\n onToggle,\n sticky = false,\n stickyTopOffset = 0,\n divider = false,\n tone = 'default',\n 'aria-label': ariaLabel,\n className = '',\n style,\n }: SurfaceExpandableRowProps) => {\n const bodyId = React.useId();\n const toggle = onToggle ? () => onToggle(!expanded) : undefined;\n\n return (\n <SurfaceRow divider={divider} tone={tone} className={className} style={style}>\n {/* `group` so the arrow takes its hover state from the whole row. */}\n <div\n className={`group flex items-center w-full ${toggle ? 'cursor-pointer' : ''} ${\n sticky && expanded\n ? 'sticky z-[1] bg-[var(--malachite-card-background)]'\n : ''\n }`}\n style={sticky && expanded ? { top: stickyTopOffset } : undefined}\n // Presentational: the arrow below is the keyboard control, and this only\n // widens the pointer target.\n onClick={toggle}\n role=\"presentation\"\n >\n {/* Reserved whether or not this row opens, so a list stays in one column.\n The inset and gap match Accordion's header. */}\n <span className=\"shrink-0 flex items-center pl-[16px] pr-[12px]\">\n {toggle && (\n <button\n type=\"button\"\n className={`appearance-none bg-transparent border-0 p-0 flex items-center cursor-pointer ${FOCUS_RING_INSET}`}\n aria-expanded={expanded}\n aria-controls={bodyId}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n toggle();\n }}\n >\n <DisclosureArrow expanded={expanded} />\n </button>\n )}\n </span>\n {header}\n </div>\n {expanded && <div id={bodyId}>{children}</div>}\n </SurfaceRow>\n );\n },\n { Controls: ExpandableRowControls },\n);\n\ninterface SurfaceComponent extends React.FC<SurfaceProps> {\n Row: React.FC<AnySurfaceRowProps>;\n ExpandableRow: typeof SurfaceExpandableRow;\n}\n\nconst Surface = (({\n children,\n padding = false,\n overflow = 'hidden',\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}: SurfaceProps) => {\n // Literal class names (not interpolated) so Tailwind's JIT emits them.\n const overflowClass =\n overflow === 'clip'\n ? 'overflow-clip'\n : overflow === 'visible'\n ? 'overflow-visible'\n : 'overflow-hidden';\n return (\n <div\n className={`w-full rounded-[var(--malachite-radius-xxl,14px)] ${overflowClass} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${padding ? 'py-3 px-4' : ''} ${className}`}\n style={{ boxShadow: TRIPLE_SHADOW, ...FOREGROUND_RESET, ...style }}\n role={role}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </div>\n );\n}) as SurfaceComponent;\n\nSurface.Row = SurfaceRow;\nSurface.ExpandableRow = SurfaceExpandableRow;\n\nexport default Surface;\nexport { Surface, SurfaceRow, SurfaceExpandableRow };\n"],"names":["TONE_CLASSES","TONE_FOREGROUNDS","TRIPLE_SHADOW","SurfaceRow","props","children","divider","disabled","selected","selection","tone","className","style","asChild","onClick","href","trailing","role","ariaLabel","ariaLabelledBy","interactive","hover","tinted","chromeClasses","controlClasses","FOCUS_RING_INSET","classes","selectedStyle","SELECTED_ROW_BACKGROUND","SELECTED_ROW_FOREGROUND","SELECTED_ROW_ACCENT","SELECTED_TEXT_CONTEXT","toneForeground","rowStyle","ariaChecked","ariaCurrent","rowFallbackAria","paintOnChild","isRenderableNode","control","jsx","jsxs","ExpandableRowControls","event","EXPANDABLE_ROW_LEAD_PX","SurfaceExpandableRow","header","expanded","onToggle","sticky","stickyTopOffset","bodyId","React","toggle","DisclosureArrow","Surface","padding","overflow","FOREGROUND_RESET"],"mappings":"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"}
1
+ {"version":3,"file":"Surface.js","sources":["../../src/components/Surface.tsx"],"sourcesContent":["import React from 'react';\nimport { paintOnChild } from './asChild';\nimport DisclosureArrow from './DisclosureArrow';\nimport { FOCUS_RING_INSET } from './focusRing';\nimport { resolveRel } from './linkRel';\nimport { safeHref } from './safeHref';\nimport { isRenderableNode } from './renderableNode';\nimport {\n FOREGROUND_RESET,\n SELECTED_ROW_ACCENT,\n SELECTED_ROW_BACKGROUND,\n SELECTED_ROW_FOREGROUND,\n SELECTED_TEXT_CONTEXT,\n} from './selectedRow';\n\nexport interface SurfaceProps {\n children?: React.ReactNode;\n padding?: boolean;\n /**\n * Content overflow. Defaults to `hidden` so children are clipped to the rounded\n * corners. Use `clip` to keep the rounded clipping WITHOUT creating a scroll\n * container — so a `position: sticky` descendant still pins (unlike `hidden`,\n * which traps it). `visible` disables clipping entirely.\n */\n overflow?: 'hidden' | 'visible' | 'clip';\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\ninterface SurfaceRowChromeProps {\n children?: React.ReactNode;\n /** Renders a bottom divider — omit on the last row in a Surface. */\n divider?: boolean;\n /** Removes the hover affordance / disables the control (e.g. while loading/busy). */\n disabled?: boolean;\n /** Announces the row as selected — `aria-checked` under a `radio`/`checkbox` role,\n * `aria-current` otherwise — and paints `Table`'s selected treatment unless `selection`\n * says not to. */\n selected?: boolean;\n /** How a `selected` row shows it. `highlight` paints the treatment; `announce` leaves the\n * visual to a control inside the row and only sets the ARIA state. Defaults to `announce`\n * under `role=\"checkbox\"` and `highlight` otherwise. */\n selection?: 'highlight' | 'announce';\n /**\n * Tints the whole row by what it reports. `muted` is a row whose subject is inactive —\n * not disabled: it stays interactive. `success` and `error` are for a row that carries\n * an outcome, where the result belongs to the whole line rather than to one cell in it.\n */\n tone?: 'default' | 'muted' | 'success' | 'error';\n className?: string;\n style?: React.CSSProperties;\n}\n\n/** Stays an interface under its original name: a consumer may `extends` it. */\nexport interface SurfaceRowProps extends SurfaceRowChromeProps {\n asChild?: false;\n /**\n * When provided, the whole row becomes clickable: it renders as a `<button>`\n * (or `<a>` when `href` is set), so the entire row is the click target with\n * native focus + Enter/Space — no manual tabIndex/key handlers. For a\n * selectable row, put a presentational `<Radio>`/`<Checkbox>` inside as the\n * visual indicator; do NOT nest an interactive control (invalid + double tab stop).\n */\n onClick?: (event: React.MouseEvent) => void;\n /** Renders the clickable row as an anchor instead of a button. */\n href?: string;\n target?: React.HTMLAttributeAnchorTarget;\n rel?: string;\n /** Content pinned right, outside the row button, so it may hold its own control. */\n trailing?: React.ReactNode;\n /** ARIA role for a clickable row, e.g. `radio`/`checkbox` (wrap the list in a `radiogroup`). */\n role?: React.AriaRole;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n}\n\n/**\n * The outcome tones reuse the tag tokens rather than minting row ones, so a row saying \"this\n * passed\" and a tag saying it are the same green wherever the two sit together.\n */\nconst TONE_CLASSES: Record<NonNullable<SurfaceRowProps['tone']>, string> = {\n default: '',\n muted: 'bg-[var(--malachite-card-dimmed-background)]',\n success: 'bg-[var(--malachite-tag-success-background)]',\n error: 'bg-[var(--malachite-tag-error-background)]',\n};\n\n/**\n * The text an outcome tone carries with it, through the same context channel a selected row\n * uses, so `Typography` inside the row follows the tint instead of staying near-black on it.\n * `color` as well, for row content that is not Typography.\n *\n * Only the outcome tones. `muted` dims its subject rather than recolouring it, and its\n * foreground is the ordinary one.\n */\nconst TONE_FOREGROUNDS: Partial<Record<NonNullable<SurfaceRowProps['tone']>, string>> = {\n success: 'var(--malachite-tag-success-foreground)',\n error: 'var(--malachite-tag-error-foreground)',\n};\n\nexport interface SurfaceRowAsChildProps extends SurfaceRowChromeProps {\n asChild: true;\n children: React.ReactElement;\n}\n\nexport type AnySurfaceRowProps = SurfaceRowProps | SurfaceRowAsChildProps;\n\nconst TRIPLE_SHADOW =\n '0px 0px 4px 0px rgba(0,0,0,0.08), 0px 4px 4px 0px rgba(0,0,0,0.08), 0px 4px 10px 0px rgba(0,0,0,0.05)';\n\n/**\n * A single full-bleed row inside a <Surface>. Owns the row chrome — hover\n * highlight, colour transition and an optional bottom divider — so consumers\n * compose their own content inside without re-implementing design-system styling.\n * Pass `onClick`/`href` to make the entire row clickable (rendered as a real\n * button/anchor, so keyboard navigation works natively).\n */\nconst SurfaceRow: React.FC<AnySurfaceRowProps> = (props) => {\n const {\n children,\n divider = false,\n disabled = false,\n selected,\n selection,\n tone = 'default',\n className = '',\n style,\n } = props;\n const asChild = props.asChild === true;\n const { onClick, href: rawHref, target, rel, trailing, role } = asChild\n ? ({} as SurfaceRowProps)\n : (props as SurfaceRowProps);\n // A rejected href (e.g. `javascript:`) leaves the row a button or a plain row, never an anchor.\n const href = safeHref(rawHref);\n const ariaLabel = asChild ? undefined : (props as SurfaceRowProps)['aria-label'];\n const ariaLabelledBy = asChild ? undefined : (props as SurfaceRowProps)['aria-labelledby'];\n const interactive = Boolean(onClick || href);\n // `asChild` is interactive for the hover affordance only, not the focus/reset classes.\n const hover =\n disabled && (interactive || asChild)\n ? ''\n : 'transition-colors hover:bg-[var(--malachite-buttonlist-hover-background)]';\n\n // A class, not an inline colour, which would outrank the hover utility. It replaces the\n // button reset's `bg-transparent` rather than joining it: same specificity, so the winner\n // would be whichever Tailwind emitted last.\n const tinted = tone !== 'default';\n const toneClass = TONE_CLASSES[tone];\n\n const chromeClasses = [\n 'w-full text-left border-0',\n toneClass,\n divider ? 'border-b border-solid border-[var(--malachite-card-border)]' : '',\n hover,\n ]\n .filter(Boolean)\n .join(' ');\n\n const controlClasses = [\n interactive\n ? `appearance-none ${tinted ? '' : 'bg-transparent'} p-0 ${FOCUS_RING_INSET}`\n : '',\n interactive && !disabled ? 'cursor-pointer' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n const classes = [chromeClasses, controlClasses, className].filter(Boolean).join(' ');\n\n const paints = selection ? selection === 'highlight' : role !== 'checkbox';\n\n // A gradient layer so the tint composites over hover, and an inset shadow because\n // `ring-*` silently doesn't paint in a shadow root.\n const selectedStyle: React.CSSProperties =\n selected && paints\n ? {\n backgroundImage: `linear-gradient(${SELECTED_ROW_BACKGROUND}, ${SELECTED_ROW_BACKGROUND})`,\n color: SELECTED_ROW_FOREGROUND,\n boxShadow: `inset 2px 0 0 ${SELECTED_ROW_ACCENT}`,\n ...SELECTED_TEXT_CONTEXT,\n }\n : {};\n\n const toneForeground = TONE_FOREGROUNDS[tone];\n const toneStyle: React.CSSProperties = toneForeground\n ? ({\n color: toneForeground,\n '--malachite-ctx-text-primary': toneForeground,\n } as React.CSSProperties)\n : {};\n\n // `selected` last of the two: a row can be both, and selection is the state the reader is\n // acting on, so it wins the colour.\n const rowStyle = { ...toneStyle, ...selectedStyle, ...style };\n\n const ariaChecked = role === 'radio' || role === 'checkbox' ? Boolean(selected) : undefined;\n // `aria-current`, not `aria-pressed`: a selected row is one of many choices, not a toggle\n // (same call as `Dropdown`'s options). A role that carries its own state uses that instead.\n const ariaCurrent = ariaChecked === undefined && selected ? true : undefined;\n\n // Everything a control would have carried, for the branches that render none: the row\n // element is then the only thing assistive tech sees. `aria-disabled` because there is no\n // control to be natively disabled — and it is inert without a role, like the name.\n const rowFallbackAria = {\n role,\n 'aria-checked': ariaChecked,\n 'aria-current': ariaCurrent,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-disabled': role && disabled ? true : undefined,\n };\n\n if (asChild) {\n return paintOnChild(children, classes, rowStyle);\n }\n\n if (isRenderableNode(trailing)) {\n const control =\n href && !disabled ? (\n <a\n href={href}\n target={target}\n rel={resolveRel(rel, target)}\n onClick={onClick}\n className={`${controlClasses} border-0 flex-1 min-w-0 text-left no-underline text-inherit`}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </a>\n ) : onClick ? (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={`${controlClasses} border-0 flex-1 min-w-0 text-left`}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </button>\n ) : (\n // The set goes here, not on the wrapper: `radio` and `checkbox` make their\n // descendants presentational, which would bury a control in the trailing slot.\n <div className=\"flex-1 min-w-0\" {...rowFallbackAria}>\n {children}\n </div>\n );\n\n return (\n <div\n className={[chromeClasses, 'flex items-center', className]\n .filter(Boolean)\n .join(' ')}\n style={rowStyle}\n >\n {control}\n <div className=\"shrink-0 flex items-center\">{trailing}</div>\n </div>\n );\n }\n\n if (href && !disabled) {\n return (\n <a\n href={href}\n target={target}\n rel={resolveRel(rel, target)}\n onClick={onClick}\n className={`${classes} no-underline text-inherit`}\n style={rowStyle}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </a>\n );\n }\n\n if (onClick) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className={classes}\n style={rowStyle}\n role={role}\n aria-checked={ariaChecked}\n aria-current={ariaCurrent}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </button>\n );\n }\n\n return (\n <div className={classes} style={rowStyle} {...rowFallbackAria}>\n {children}\n </div>\n );\n};\n\nexport interface SurfaceExpandableRowProps {\n /** The row itself, laid out across the line. May hold its own controls. */\n header: React.ReactNode;\n /** The body, rendered beneath the row while it is open. */\n children?: React.ReactNode;\n expanded: boolean;\n /** Omit for a row that cannot open. The arrow's space is still reserved, so a list of\n * rows stays in one column whether or not each one has a body. */\n onToggle?: (expanded: boolean) => void;\n /**\n * Pins the row while its body scrolls, so a long body never leaves the reader without\n * the line it belongs to. Offset by whatever is already pinned above it.\n */\n sticky?: boolean;\n stickyTopOffset?: number;\n divider?: boolean;\n tone?: SurfaceRowProps['tone'];\n /** Names the disclosure control, which is otherwise only an arrow. */\n 'aria-label'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/**\n * Stops a click inside it from toggling the row, for the cells that hold controls.\n *\n * Explicit rather than sniffing the event's target for an interactive ancestor: a control\n * rendering into a shadow root retargets the event to its host, so the sniff would miss\n * exactly the components most likely to sit in a row.\n */\nconst ExpandableRowControls: React.FC<{\n children?: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}> = ({ children, className = '', style }) => (\n <div className={className} style={style} onClick={(event) => event.stopPropagation()}>\n {children}\n </div>\n);\n\n/**\n * A row that opens to reveal a body, for a line that carries its own controls.\n *\n * Not `Accordion`: that puts its header inside the toggle button, so a header holding a\n * dropdown or a second button is invalid. Here the row surface takes the click and a cell\n * opts out with `ExpandableRow.Controls`, while the arrow stays a real button so the\n * keyboard reaches it.\n */\n/**\n * The space before the header: the arrow's own inset, its glyph and the gap after it.\n * Exported so a consumer aligning a column header above these rows offsets by the same\n * amount instead of guessing at it.\n */\nexport const EXPANDABLE_ROW_LEAD_PX = 39;\n\nconst SurfaceExpandableRow: React.FC<SurfaceExpandableRowProps> & {\n Controls: typeof ExpandableRowControls;\n} = Object.assign(\n ({\n header,\n children,\n expanded,\n onToggle,\n sticky = false,\n stickyTopOffset = 0,\n divider = false,\n tone = 'default',\n 'aria-label': ariaLabel,\n className = '',\n style,\n }: SurfaceExpandableRowProps) => {\n const bodyId = React.useId();\n const toggle = onToggle ? () => onToggle(!expanded) : undefined;\n\n return (\n <SurfaceRow divider={divider} tone={tone} className={className} style={style}>\n {/* `group` so the arrow takes its hover state from the whole row. */}\n <div\n className={`group flex items-center w-full ${toggle ? 'cursor-pointer' : ''} ${\n sticky && expanded\n ? 'sticky z-[1] bg-[var(--malachite-card-background)]'\n : ''\n }`}\n style={sticky && expanded ? { top: stickyTopOffset } : undefined}\n // Presentational: the arrow below is the keyboard control, and this only\n // widens the pointer target.\n onClick={toggle}\n role=\"presentation\"\n >\n {/* Reserved whether or not this row opens, so a list stays in one column.\n The inset and gap match Accordion's header. */}\n <span className=\"shrink-0 flex items-center pl-[16px] pr-[12px]\">\n {toggle && (\n <button\n type=\"button\"\n className={`appearance-none bg-transparent border-0 p-0 flex items-center cursor-pointer ${FOCUS_RING_INSET}`}\n aria-expanded={expanded}\n aria-controls={bodyId}\n aria-label={ariaLabel}\n onClick={(event) => {\n event.stopPropagation();\n toggle();\n }}\n >\n <DisclosureArrow expanded={expanded} />\n </button>\n )}\n </span>\n {header}\n </div>\n {expanded && <div id={bodyId}>{children}</div>}\n </SurfaceRow>\n );\n },\n { Controls: ExpandableRowControls },\n);\n\ninterface SurfaceComponent extends React.FC<SurfaceProps> {\n Row: React.FC<AnySurfaceRowProps>;\n ExpandableRow: typeof SurfaceExpandableRow;\n}\n\nconst Surface = (({\n children,\n padding = false,\n overflow = 'hidden',\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}: SurfaceProps) => {\n // Literal class names (not interpolated) so Tailwind's JIT emits them.\n const overflowClass =\n overflow === 'clip'\n ? 'overflow-clip'\n : overflow === 'visible'\n ? 'overflow-visible'\n : 'overflow-hidden';\n return (\n <div\n className={`w-full rounded-[var(--malachite-radius-xxl,14px)] ${overflowClass} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${padding ? 'py-3 px-4' : ''} ${className}`}\n style={{ boxShadow: TRIPLE_SHADOW, ...FOREGROUND_RESET, ...style }}\n role={role}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n >\n {children}\n </div>\n );\n}) as SurfaceComponent;\n\nSurface.Row = SurfaceRow;\nSurface.ExpandableRow = SurfaceExpandableRow;\n\nexport default Surface;\nexport { Surface, SurfaceRow, SurfaceExpandableRow };\n"],"names":["TONE_CLASSES","TONE_FOREGROUNDS","TRIPLE_SHADOW","SurfaceRow","props","children","divider","disabled","selected","selection","tone","className","style","asChild","onClick","rawHref","target","rel","trailing","role","href","safeHref","ariaLabel","ariaLabelledBy","interactive","hover","tinted","chromeClasses","controlClasses","FOCUS_RING_INSET","classes","selectedStyle","SELECTED_ROW_BACKGROUND","SELECTED_ROW_FOREGROUND","SELECTED_ROW_ACCENT","SELECTED_TEXT_CONTEXT","toneForeground","rowStyle","ariaChecked","ariaCurrent","rowFallbackAria","paintOnChild","isRenderableNode","control","jsx","resolveRel","jsxs","ExpandableRowControls","event","EXPANDABLE_ROW_LEAD_PX","SurfaceExpandableRow","header","expanded","onToggle","sticky","stickyTopOffset","bodyId","React","toggle","DisclosureArrow","Surface","padding","overflow","FOREGROUND_RESET"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ const s = (o, n) => {
2
+ if ((n == null ? void 0 : n.toLowerCase()) !== "_blank") return o;
3
+ const e = new Set(o == null ? void 0 : o.split(/\s+/).filter(Boolean));
4
+ return e.add("noopener"), e.add("noreferrer"), [...e].join(" ");
5
+ };
6
+ export {
7
+ s as resolveRel
8
+ };
9
+ //# sourceMappingURL=linkRel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linkRel.js","sources":["../../src/components/linkRel.ts"],"sourcesContent":["import type { HTMLAttributeAnchorTarget } from 'react';\n\n// Merged, never replaced: a caller's own `rel` must not drop `_blank`'s noopener/noreferrer.\nexport const resolveRel = (\n rel: string | undefined,\n target: HTMLAttributeAnchorTarget | undefined,\n): string | undefined => {\n // Browsers match the `_blank` keyword case-insensitively, so this must too.\n if (target?.toLowerCase() !== '_blank') return rel;\n\n const tokens = new Set(rel?.split(/\\s+/).filter(Boolean));\n tokens.add('noopener');\n tokens.add('noreferrer');\n return [...tokens].join(' ');\n};\n"],"names":["resolveRel","rel","target","tokens"],"mappings":"AAGO,MAAMA,IAAa,CACtBC,GACAC,MACqB;AAErB,OAAIA,KAAA,gBAAAA,EAAQ,mBAAkB,SAAU,QAAOD;AAE/C,QAAME,IAAS,IAAI,IAAIF,KAAA,gBAAAA,EAAK,MAAM,OAAO,OAAO,QAAQ;AACxD,SAAAE,EAAO,IAAI,UAAU,GACrBA,EAAO,IAAI,YAAY,GAChB,CAAC,GAAGA,CAAM,EAAE,KAAK,GAAG;AAC/B;"}
package/dist/index.d.ts CHANGED
@@ -143,6 +143,8 @@ declare interface AlertProps {
143
143
  children?: default_2.ReactNode;
144
144
  isExpanded?: boolean;
145
145
  onToggle?: (expanded: boolean) => void;
146
+ /** A control at the end of the alert — a link or button that resolves what it reports. */
147
+ action?: default_2.ReactNode;
146
148
  }
147
149
 
148
150
  export declare type AlertType = 'info' | 'success' | 'error' | 'warning' | 'assistant';
@@ -3392,7 +3394,11 @@ declare interface PillButtonProps {
3392
3394
  tone?: PillButtonTone;
3393
3395
  /** Sits after the label — a caret on a pill that opens a menu. */
3394
3396
  trailingIcon?: default_2.ReactNode;
3395
- onClick?: () => void;
3397
+ onClick?: (event: default_2.MouseEvent<HTMLElement>) => void;
3398
+ /** Renders the pill as a real anchor, so a link pill keeps cmd-click, copy-link and the status bar. */
3399
+ href?: string;
3400
+ target?: default_2.HTMLAttributeAnchorTarget;
3401
+ rel?: string;
3396
3402
  }
3397
3403
 
3398
3404
  /**
@@ -4210,6 +4216,8 @@ export declare interface SurfaceRowProps extends SurfaceRowChromeProps {
4210
4216
  onClick?: (event: default_2.MouseEvent) => void;
4211
4217
  /** Renders the clickable row as an anchor instead of a button. */
4212
4218
  href?: string;
4219
+ target?: default_2.HTMLAttributeAnchorTarget;
4220
+ rel?: string;
4213
4221
  /** Content pinned right, outside the row button, so it may hold its own control. */
4214
4222
  trailing?: default_2.ReactNode;
4215
4223
  /** ARIA role for a clickable row, e.g. `radio`/`checkbox` (wrap the list in a `radiogroup`). */