@stackone/malachite 2.25.1 → 2.26.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 +2 -0
- package/dist/components/Surface.js +137 -86
- package/dist/components/Surface.js.map +1 -1
- package/dist/index.d.ts +64 -0
- package/dist/index.js +410 -406
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css.js +1 -1
- package/package.json +1 -1
package/COMPONENTS.md
CHANGED
|
@@ -9,6 +9,8 @@ The catalog of components exported from `@stackone/malachite`. **Reach for one o
|
|
|
9
9
|
- **`Chat`** — A chat column: `Chat.Thread` scrolls and pins itself to the newest message, `Chat.Composer` keeps its own height and owns the Enter/Shift+Enter convention, and `Chat.Message`, `Chat.ToolCall` and `Chat.Thinking` render one turn each. A user turn sits right and hugs its text; an assistant turn runs full width, and `variant="card"` frames it with its state, copy and rating controls, and a token/model line. `variant="bubble"` is a third treatment, not a repaint of either: tinted bubbles whose flattened corner points at whoever spoke, so authorship reads before the words do. `Chat.Context` lists what the conversation can see — a removable chip per source, and an add affordance only when a handler is given. `Chat.Thinking` and a loading turn draw bars in the shape of the answer rather than a spinner. The row under a composer is `ComposerChip`, `ContextMeter` and `ModelPicker` — PillButton tabs, so it reads as attached to the field; `ModelPicker` opens a portalled menu with a submenu per model. The transcript is a live `log` region, so a streamed reply is announced, and it shows a centred empty state until the first turn. _Key props:_ `Chat`: `children`, `className`. `Thread`: `aria-label`, `emptyTitle`, `emptyDescription`, `emptyIcon`. `Message`: `role`, `variant` (`plain` | `card`), `content`, `children`, `name`, `avatarSrc`, `status` (`streaming` | `completed` | `error`), `loading`, `onCopy`, `onFeedback`, `usage`. `ToolCall`: `name`, `status` (`running` | `completed` | `error`), `callId`, `input`, `output`, `defaultExpanded`. `Thinking`: `label`. `Composer`: `value`, `onChange`, `onSend`, `onStop`, `busy`, `disabled`, `placeholder`, `maxLength`, `rows`, `children`. `ComposerChip`: `label`, `icon`, `trailingIcon`, `onClick`, `disabled`. `ContextMeter`: `used`, `limit`, `cached`, `label`. `ModelPicker`: `models`, `value`, `optionValue`, `onChange`, `openUp`, `disabled`. `Context`: `label`, `items` (`{id, label, onRemove?}`), `onAdd`, `className`.
|
|
10
10
|
- **`Surface`** — Rounded, bordered card container with the standard elevation shadow. Use `overflow="clip"` to keep the rounded clipping while letting a `position: sticky` descendant still pin (`hidden` would trap it); `visible` disables clipping. _Key props:_ `children`, `padding`, `overflow`, `className`, `style`.
|
|
11
11
|
- **`SurfaceRow`** — A full-bleed row inside a Surface (used as `Surface.Row`). Owns hover highlight, colour transition and an optional bottom divider. Pass `onClick`/`href` to make the whole row clickable (renders as a real button/anchor, so keyboard nav works). For a selectable row use `role="radio"` + `selected` and put a presentational `<Radio>` inside as the indicator; `selected` then paints the same treatment `Table` gives `selectedRowKey`. Under `role="checkbox"` it only announces — a multi-select row carries its own checkbox, and a highlight marking one of many says nothing when most rows are checked. `selection` overrides that either way (`highlight` / `announce`). Use `trailing` for a control that must stay interactive — it renders outside the row button, which a nested control could not be. `tone="muted"` tints a row whose subject is inactive, which `disabled` does not: a muted row stays clickable. _Key props:_ `divider`, `disabled`, `tone` (`default` | `muted`), `onClick`, `href`, `selected`, `selection` (`highlight` | `announce`), `trailing`, `role`, `className`, `style`.
|
|
12
|
+
- **`SurfaceExpandableRow`** — A row that opens to reveal a body (used as `Surface.ExpandableRow`), for a line that carries its own controls. Not `Accordion`, which puts its header inside the toggle button, so a header holding a dropdown or a second button would be invalid: here the row surface takes the click and a cell opts out by wrapping its controls in `ExpandableRow.Controls`, while the arrow stays a real button so the keyboard reaches it. That opt-out is explicit rather than sniffing the event target for an interactive ancestor, because a control rendering into a shadow root retargets the event to its host. `sticky` pins the row while its body scrolls, offset by `stickyTopOffset` for whatever is already pinned above it; it only pins while open, since a closed row has nothing to scroll past. _Key props:_ `header`, `children`, `expanded`, `onToggle`, `sticky`, `stickyTopOffset`, `divider`, `tone`, `aria-label`, `className`, `style`.
|
|
13
|
+
- **`DisclosureArrow`** — The expand/collapse triangle disclosure UI shares (`Accordion`, `Surface.ExpandableRow`). Owns its colour states so they never drift between usages: `text-primary` when expanded, `text-placeholder` otherwise, and dark on hover inside a `group` ancestor — put `group` on the clickable header or row so that hover state activates. _Key props:_ `expanded`, `size`, `className`.
|
|
12
14
|
- **`Card`** — Generic content card.
|
|
13
15
|
- **`SelectableCard`** — A card that is one option in a radio group — eyebrow, optional status tag, title, description, a count label and a top-right action slot. Use inside a `CardStrip`. Selection is controlled by the consumer: pass `selected`, which drives both the visual treatment and `aria-checked`. A selected card meets the sheet below the way a browser tab meets its toolbar — its bottom corners flare outward onto the strip’s rule — so its outline is one SVG path rather than borders, which would split into two lines at the tangent. `variant` picks the palette: `profile` (green), `library` (neutral) or `editing` (amber, for a profile with unsaved changes). `actions` stands in the card’s top-right corner, on the eyebrow row, and renders outside the control so a menu or icon button inside it stays clickable and keeps its own tab stop. Nothing else marks that corner: the flared outline, the tint and the green eyebrow already say which card is selected, so a radio there would only repeat them. `isDefault` marks the card as the account default with a pin beside the title, named for assistive tech and tooltipped for everyone else — it belongs with the name it qualifies rather than among the actions, which read as things to press. For a row-shaped selectable use `Surface.Row` instead. _Key props:_ `value`, `title`, `titleIcon`, `isDefault`, `variant` (`profile` | `library` | `editing`), `eyebrow`, `status` (`label`, `type`), `description`, `countLabel`, `actions`, `selected`, `loading` (`loadingLabel`, `loadingHint`), `disabled`, `dimmed`, `onSelect`, `tabIndex`, `aria-label`, `className`, `style`.
|
|
14
16
|
- **`CardStrip`** — Horizontally scrolling radio group of cards, with edge arrows that appear only when the content overflows, an edge fade, scroll-snap and arrow-key navigation matching `SegmentedControl`. Owns interaction only: it finds its options by looking for `role="radio"` descendants carrying `data-value`, so any such child works (`SelectableCard` emits both). Pass a non-selectable terminal tile as `CardStrip.AddTile` — it sits inside the group but outside the radio set, and must be a direct child or it scrolls with the cards. Use `leading` to pin a card that should not scroll away; the strip tells the cards which slot they are in, so a pinned `SelectableCard` drops the left rule the scrolling ones draw. Set `bleed` when the strip sits in a `PageLayout`: the strip stretches past the horizontal padding of the layout so its bottom rule runs the full width of the page card, while the cards stay aligned to the gutter. With no cards at all the strip degenerates to its pinned slots alone — no trough, no scroller and no arrows — with the add tile standing beside `leading` and taking `primary` emphasis automatically, since adding the first card is the only thing on offer. _Key props:_ `value`, `tone` (`profile` | `library` | `editing` — read off the selected card unless set), `onChange`, `children`, `leading`, `arrows`, `fadeEdges`, `snap`, `bleed`, `scrollSelectedIntoView`, `aria-label`, `aria-labelledby`, `className`, `style`. `CardStrip.AddTile`: `label`, `icon`, `onClick`, `disabled`, `emphasis` (`primary` | `secondary` — left to the strip unless set: `primary` while there are no cards, `secondary` once there are), `className`.
|
|
@@ -1,154 +1,205 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { jsx as e, jsxs as R } from "react/jsx-runtime";
|
|
2
|
+
import A from "react";
|
|
3
|
+
import { DisclosureArrow as j } from "./DisclosureArrow.js";
|
|
4
|
+
import { FOCUS_RING_INSET as _ } from "./focusRing.js";
|
|
5
|
+
import { isRenderableNode as F } from "./renderableNode.js";
|
|
6
|
+
import { FOREGROUND_RESET as I, SELECTED_TEXT_CONTEXT as G, SELECTED_ROW_ACCENT as P, SELECTED_ROW_FOREGROUND as U, SELECTED_ROW_BACKGROUND as y } from "./selectedRow.js";
|
|
7
|
+
const W = {
|
|
6
8
|
default: "",
|
|
7
9
|
muted: "bg-[var(--malachite-card-dimmed-background)]",
|
|
8
10
|
success: "bg-[var(--malachite-tag-success-background)]",
|
|
9
11
|
error: "bg-[var(--malachite-tag-error-background)]"
|
|
10
|
-
},
|
|
12
|
+
}, B = {
|
|
11
13
|
success: "var(--malachite-tag-success-foreground)",
|
|
12
14
|
error: "var(--malachite-tag-error-foreground)"
|
|
13
|
-
},
|
|
15
|
+
}, X = "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)", C = ({
|
|
14
16
|
children: t,
|
|
15
|
-
divider:
|
|
17
|
+
divider: n = !1,
|
|
16
18
|
disabled: a = !1,
|
|
17
|
-
onClick:
|
|
19
|
+
onClick: r,
|
|
18
20
|
href: l,
|
|
19
21
|
selected: c,
|
|
20
22
|
selection: b,
|
|
21
23
|
trailing: u,
|
|
22
|
-
tone:
|
|
23
|
-
role:
|
|
24
|
-
"aria-label":
|
|
25
|
-
"aria-labelledby":
|
|
26
|
-
className:
|
|
27
|
-
style:
|
|
24
|
+
tone: p = "default",
|
|
25
|
+
role: o,
|
|
26
|
+
"aria-label": i,
|
|
27
|
+
"aria-labelledby": s,
|
|
28
|
+
className: d = "",
|
|
29
|
+
style: v
|
|
28
30
|
}) => {
|
|
29
|
-
const
|
|
31
|
+
const g = !!(r || l), k = a && g ? "" : "transition-colors hover:bg-[var(--malachite-buttonlist-hover-background)]", $ = p !== "default", S = [
|
|
30
32
|
"w-full text-left border-0",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
].filter(Boolean).join(" "),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
].filter(Boolean).join(" "),
|
|
33
|
+
W[p],
|
|
34
|
+
n ? "border-b border-solid border-[var(--malachite-card-border)]" : "",
|
|
35
|
+
k
|
|
36
|
+
].filter(Boolean).join(" "), h = [
|
|
37
|
+
g ? `appearance-none ${$ ? "" : "bg-transparent"} p-0 ${_}` : "",
|
|
38
|
+
g && !a ? "cursor-pointer" : ""
|
|
39
|
+
].filter(Boolean).join(" "), E = [S, h, d].filter(Boolean).join(" "), T = c && (b ? b === "highlight" : o !== "checkbox") ? {
|
|
38
40
|
backgroundImage: `linear-gradient(${y}, ${y})`,
|
|
39
|
-
color:
|
|
40
|
-
boxShadow: `inset 2px 0 0 ${
|
|
41
|
-
...
|
|
42
|
-
} : {},
|
|
43
|
-
color:
|
|
44
|
-
"--malachite-ctx-text-primary":
|
|
45
|
-
} : {}, ...T, ...
|
|
46
|
-
role:
|
|
47
|
-
"aria-checked":
|
|
48
|
-
"aria-current":
|
|
49
|
-
"aria-label":
|
|
50
|
-
"aria-labelledby":
|
|
51
|
-
"aria-disabled":
|
|
41
|
+
color: U,
|
|
42
|
+
boxShadow: `inset 2px 0 0 ${P}`,
|
|
43
|
+
...G
|
|
44
|
+
} : {}, N = B[p], x = { ...N ? {
|
|
45
|
+
color: N,
|
|
46
|
+
"--malachite-ctx-text-primary": N
|
|
47
|
+
} : {}, ...T, ...v }, m = o === "radio" || o === "checkbox" ? !!c : void 0, f = m === void 0 && c ? !0 : void 0, w = {
|
|
48
|
+
role: o,
|
|
49
|
+
"aria-checked": m,
|
|
50
|
+
"aria-current": f,
|
|
51
|
+
"aria-label": i,
|
|
52
|
+
"aria-labelledby": s,
|
|
53
|
+
"aria-disabled": o && a ? !0 : void 0
|
|
52
54
|
};
|
|
53
|
-
if (
|
|
54
|
-
const
|
|
55
|
+
if (F(u)) {
|
|
56
|
+
const D = l && !a ? /* @__PURE__ */ e(
|
|
55
57
|
"a",
|
|
56
58
|
{
|
|
57
59
|
href: l,
|
|
58
|
-
onClick:
|
|
59
|
-
className: `${
|
|
60
|
-
role:
|
|
61
|
-
"aria-checked":
|
|
62
|
-
"aria-current":
|
|
63
|
-
"aria-label":
|
|
64
|
-
"aria-labelledby":
|
|
60
|
+
onClick: r,
|
|
61
|
+
className: `${h} border-0 flex-1 min-w-0 text-left no-underline text-inherit`,
|
|
62
|
+
role: o,
|
|
63
|
+
"aria-checked": m,
|
|
64
|
+
"aria-current": f,
|
|
65
|
+
"aria-label": i,
|
|
66
|
+
"aria-labelledby": s,
|
|
65
67
|
children: t
|
|
66
68
|
}
|
|
67
|
-
) :
|
|
69
|
+
) : r ? /* @__PURE__ */ e(
|
|
68
70
|
"button",
|
|
69
71
|
{
|
|
70
72
|
type: "button",
|
|
71
|
-
onClick:
|
|
73
|
+
onClick: r,
|
|
72
74
|
disabled: a,
|
|
73
|
-
className: `${
|
|
74
|
-
role:
|
|
75
|
-
"aria-checked":
|
|
76
|
-
"aria-current":
|
|
77
|
-
"aria-label":
|
|
78
|
-
"aria-labelledby":
|
|
75
|
+
className: `${h} border-0 flex-1 min-w-0 text-left`,
|
|
76
|
+
role: o,
|
|
77
|
+
"aria-checked": m,
|
|
78
|
+
"aria-current": f,
|
|
79
|
+
"aria-label": i,
|
|
80
|
+
"aria-labelledby": s,
|
|
79
81
|
children: t
|
|
80
82
|
}
|
|
81
83
|
) : (
|
|
82
84
|
// The set goes here, not on the wrapper: `radio` and `checkbox` make their
|
|
83
85
|
// descendants presentational, which would bury a control in the trailing slot.
|
|
84
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ e("div", { className: "flex-1 min-w-0", ...w, children: t })
|
|
85
87
|
);
|
|
86
|
-
return /* @__PURE__ */
|
|
88
|
+
return /* @__PURE__ */ R(
|
|
87
89
|
"div",
|
|
88
90
|
{
|
|
89
|
-
className: [S, "flex items-center",
|
|
91
|
+
className: [S, "flex items-center", d].filter(Boolean).join(" "),
|
|
90
92
|
style: x,
|
|
91
93
|
children: [
|
|
92
|
-
|
|
93
|
-
/* @__PURE__ */
|
|
94
|
+
D,
|
|
95
|
+
/* @__PURE__ */ e("div", { className: "shrink-0 flex items-center", children: u })
|
|
94
96
|
]
|
|
95
97
|
}
|
|
96
98
|
);
|
|
97
99
|
}
|
|
98
|
-
return l && !a ? /* @__PURE__ */
|
|
100
|
+
return l && !a ? /* @__PURE__ */ e(
|
|
99
101
|
"a",
|
|
100
102
|
{
|
|
101
103
|
href: l,
|
|
102
|
-
onClick:
|
|
103
|
-
className: `${
|
|
104
|
+
onClick: r,
|
|
105
|
+
className: `${E} no-underline text-inherit`,
|
|
104
106
|
style: x,
|
|
105
|
-
role:
|
|
106
|
-
"aria-checked":
|
|
107
|
-
"aria-current":
|
|
108
|
-
"aria-label":
|
|
109
|
-
"aria-labelledby":
|
|
107
|
+
role: o,
|
|
108
|
+
"aria-checked": m,
|
|
109
|
+
"aria-current": f,
|
|
110
|
+
"aria-label": i,
|
|
111
|
+
"aria-labelledby": s,
|
|
110
112
|
children: t
|
|
111
113
|
}
|
|
112
|
-
) :
|
|
114
|
+
) : r ? /* @__PURE__ */ e(
|
|
113
115
|
"button",
|
|
114
116
|
{
|
|
115
117
|
type: "button",
|
|
116
|
-
onClick:
|
|
118
|
+
onClick: r,
|
|
117
119
|
disabled: a,
|
|
118
|
-
className:
|
|
120
|
+
className: E,
|
|
119
121
|
style: x,
|
|
120
|
-
role:
|
|
121
|
-
"aria-checked":
|
|
122
|
-
"aria-current":
|
|
123
|
-
"aria-label":
|
|
124
|
-
"aria-labelledby":
|
|
122
|
+
role: o,
|
|
123
|
+
"aria-checked": m,
|
|
124
|
+
"aria-current": f,
|
|
125
|
+
"aria-label": i,
|
|
126
|
+
"aria-labelledby": s,
|
|
125
127
|
children: t
|
|
126
128
|
}
|
|
127
|
-
) : /* @__PURE__ */
|
|
128
|
-
},
|
|
129
|
+
) : /* @__PURE__ */ e("div", { className: E, style: x, ...w, children: t });
|
|
130
|
+
}, z = ({ children: t, className: n = "", style: a }) => /* @__PURE__ */ e("div", { className: n, style: a, onClick: (r) => r.stopPropagation(), children: t }), aa = 39, H = Object.assign(
|
|
131
|
+
({
|
|
132
|
+
header: t,
|
|
133
|
+
children: n,
|
|
134
|
+
expanded: a,
|
|
135
|
+
onToggle: r,
|
|
136
|
+
sticky: l = !1,
|
|
137
|
+
stickyTopOffset: c = 0,
|
|
138
|
+
divider: b = !1,
|
|
139
|
+
tone: u = "default",
|
|
140
|
+
"aria-label": p,
|
|
141
|
+
className: o = "",
|
|
142
|
+
style: i
|
|
143
|
+
}) => {
|
|
144
|
+
const s = A.useId(), d = r ? () => r(!a) : void 0;
|
|
145
|
+
return /* @__PURE__ */ R(C, { divider: b, tone: u, className: o, style: i, children: [
|
|
146
|
+
/* @__PURE__ */ R(
|
|
147
|
+
"div",
|
|
148
|
+
{
|
|
149
|
+
className: `group flex items-center w-full ${d ? "cursor-pointer" : ""} ${l && a ? "sticky z-[1] bg-[var(--malachite-card-background)]" : ""}`,
|
|
150
|
+
style: l && a ? { top: c } : void 0,
|
|
151
|
+
onClick: d,
|
|
152
|
+
role: "presentation",
|
|
153
|
+
children: [
|
|
154
|
+
/* @__PURE__ */ e("span", { className: "shrink-0 flex items-center pl-[16px] pr-[12px]", children: d && /* @__PURE__ */ e(
|
|
155
|
+
"button",
|
|
156
|
+
{
|
|
157
|
+
type: "button",
|
|
158
|
+
className: `appearance-none bg-transparent border-0 p-0 flex items-center cursor-pointer ${_}`,
|
|
159
|
+
"aria-expanded": a,
|
|
160
|
+
"aria-controls": s,
|
|
161
|
+
"aria-label": p,
|
|
162
|
+
onClick: (v) => {
|
|
163
|
+
v.stopPropagation(), d();
|
|
164
|
+
},
|
|
165
|
+
children: /* @__PURE__ */ e(j, { expanded: a })
|
|
166
|
+
}
|
|
167
|
+
) }),
|
|
168
|
+
t
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
a && /* @__PURE__ */ e("div", { id: s, children: n })
|
|
173
|
+
] });
|
|
174
|
+
},
|
|
175
|
+
{ Controls: z }
|
|
176
|
+
), O = ({
|
|
129
177
|
children: t,
|
|
130
|
-
padding:
|
|
178
|
+
padding: n = !1,
|
|
131
179
|
overflow: a = "hidden",
|
|
132
|
-
role:
|
|
180
|
+
role: r,
|
|
133
181
|
"aria-label": l,
|
|
134
182
|
"aria-labelledby": c,
|
|
135
183
|
className: b = "",
|
|
136
184
|
style: u
|
|
137
|
-
}) => /* @__PURE__ */
|
|
185
|
+
}) => /* @__PURE__ */ e(
|
|
138
186
|
"div",
|
|
139
187
|
{
|
|
140
|
-
className: `w-full rounded-[var(--malachite-radius-xxl,14px)] ${a === "clip" ? "overflow-clip" : a === "visible" ? "overflow-visible" : "overflow-hidden"} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${
|
|
141
|
-
style: { boxShadow:
|
|
142
|
-
role:
|
|
188
|
+
className: `w-full rounded-[var(--malachite-radius-xxl,14px)] ${a === "clip" ? "overflow-clip" : a === "visible" ? "overflow-visible" : "overflow-hidden"} bg-[var(--malachite-card-background)] border border-solid border-[var(--malachite-card-border)] ${n ? "py-3 px-4" : ""} ${b}`,
|
|
189
|
+
style: { boxShadow: X, ...I, ...u },
|
|
190
|
+
role: r,
|
|
143
191
|
"aria-label": l,
|
|
144
192
|
"aria-labelledby": c,
|
|
145
193
|
children: t
|
|
146
194
|
}
|
|
147
195
|
);
|
|
148
|
-
|
|
196
|
+
O.Row = C;
|
|
197
|
+
O.ExpandableRow = H;
|
|
149
198
|
export {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
199
|
+
aa as EXPANDABLE_ROW_LEAD_PX,
|
|
200
|
+
O as Surface,
|
|
201
|
+
H as SurfaceExpandableRow,
|
|
202
|
+
C as SurfaceRow,
|
|
203
|
+
O as default
|
|
153
204
|
};
|
|
154
205
|
//# sourceMappingURL=Surface.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Surface.js","sources":["../../src/components/Surface.tsx"],"sourcesContent":["import React from 'react';\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\nexport interface SurfaceRowProps {\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 /**\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 /** 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 /** Content pinned right, outside the row button, so it may hold its own control. */\n trailing?: React.ReactNode;\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 /** 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 className?: string;\n style?: React.CSSProperties;\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\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<SurfaceRowProps> = ({\n children,\n divider = false,\n disabled = false,\n onClick,\n href,\n selected,\n selection,\n trailing,\n tone = 'default',\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const interactive = Boolean(onClick || href);\n const hover =\n disabled && interactive\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 (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\ninterface SurfaceComponent extends React.FC<SurfaceProps> {\n Row: React.FC<SurfaceRowProps>;\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;\n\nexport default Surface;\nexport { Surface, SurfaceRow };\n"],"names":["TONE_CLASSES","TONE_FOREGROUNDS","TRIPLE_SHADOW","SurfaceRow","children","divider","disabled","onClick","href","selected","selection","trailing","tone","role","ariaLabel","ariaLabelledBy","className","style","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","isRenderableNode","control","jsx","jsxs","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 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\nexport interface SurfaceRowProps {\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 /**\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 /** 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 /** Content pinned right, outside the row button, so it may hold its own control. */\n trailing?: React.ReactNode;\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 /** 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 className?: string;\n style?: React.CSSProperties;\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\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<SurfaceRowProps> = ({\n children,\n divider = false,\n disabled = false,\n onClick,\n href,\n selected,\n selection,\n trailing,\n tone = 'default',\n role,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const interactive = Boolean(onClick || href);\n const hover =\n disabled && interactive\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 (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<SurfaceRowProps>;\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","children","divider","disabled","onClick","href","selected","selection","trailing","tone","role","ariaLabel","ariaLabelledBy","className","style","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","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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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1157,6 +1157,22 @@ export declare const DisabledIcon: React.FC<IconProps_33>;
|
|
|
1157
1157
|
|
|
1158
1158
|
export declare const DisableIcon: React.FC<IconProps_32>;
|
|
1159
1159
|
|
|
1160
|
+
/**
|
|
1161
|
+
* The expand/collapse triangle used by disclosure UI (Accordion, expandable rows).
|
|
1162
|
+
* Owns its colour states so they never drift between usages: dark
|
|
1163
|
+
* (`text-primary`) when expanded, muted (`text-placeholder`) otherwise, and dark on
|
|
1164
|
+
* hover when placed inside a `group` ancestor. Put `group` on the clickable
|
|
1165
|
+
* header/row so the hover state activates.
|
|
1166
|
+
*/
|
|
1167
|
+
export declare const DisclosureArrow: default_2.FC<DisclosureArrowProps>;
|
|
1168
|
+
|
|
1169
|
+
export declare interface DisclosureArrowProps {
|
|
1170
|
+
/** Whether the disclosure is open (renders the down triangle vs. the right one). */
|
|
1171
|
+
expanded: boolean;
|
|
1172
|
+
size?: number;
|
|
1173
|
+
className?: string;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1160
1176
|
export declare const DismissIcon: React.FC<IconProps_34>;
|
|
1161
1177
|
|
|
1162
1178
|
export declare const Divider: default_2.FC<DividerProps>;
|
|
@@ -1320,6 +1336,26 @@ export declare const EnumIcon: React.FC<IconProps_40>;
|
|
|
1320
1336
|
|
|
1321
1337
|
export declare const ErrorCircleFilled: React.FC<IconProps_41>;
|
|
1322
1338
|
|
|
1339
|
+
/**
|
|
1340
|
+
* The space before the header: the arrow's own inset, its glyph and the gap after it.
|
|
1341
|
+
* Exported so a consumer aligning a column header above these rows offsets by the same
|
|
1342
|
+
* amount instead of guessing at it.
|
|
1343
|
+
*/
|
|
1344
|
+
export declare const EXPANDABLE_ROW_LEAD_PX = 39;
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* Stops a click inside it from toggling the row, for the cells that hold controls.
|
|
1348
|
+
*
|
|
1349
|
+
* Explicit rather than sniffing the event's target for an interactive ancestor: a control
|
|
1350
|
+
* rendering into a shadow root retargets the event to its host, so the sniff would miss
|
|
1351
|
+
* exactly the components most likely to sit in a row.
|
|
1352
|
+
*/
|
|
1353
|
+
declare const ExpandableRowControls: default_2.FC<{
|
|
1354
|
+
children?: default_2.ReactNode;
|
|
1355
|
+
className?: string;
|
|
1356
|
+
style?: default_2.CSSProperties;
|
|
1357
|
+
}>;
|
|
1358
|
+
|
|
1323
1359
|
export declare const ExpandIcon: React.FC<IconProps_42>;
|
|
1324
1360
|
|
|
1325
1361
|
export declare const EyeClosedIcon: React.FC<IconProps_43>;
|
|
@@ -3949,6 +3985,34 @@ export declare const Surface: SurfaceComponent;
|
|
|
3949
3985
|
|
|
3950
3986
|
declare interface SurfaceComponent extends default_2.FC<SurfaceProps> {
|
|
3951
3987
|
Row: default_2.FC<SurfaceRowProps>;
|
|
3988
|
+
ExpandableRow: typeof SurfaceExpandableRow;
|
|
3989
|
+
}
|
|
3990
|
+
|
|
3991
|
+
export declare const SurfaceExpandableRow: default_2.FC<SurfaceExpandableRowProps> & {
|
|
3992
|
+
Controls: typeof ExpandableRowControls;
|
|
3993
|
+
};
|
|
3994
|
+
|
|
3995
|
+
export declare interface SurfaceExpandableRowProps {
|
|
3996
|
+
/** The row itself, laid out across the line. May hold its own controls. */
|
|
3997
|
+
header: default_2.ReactNode;
|
|
3998
|
+
/** The body, rendered beneath the row while it is open. */
|
|
3999
|
+
children?: default_2.ReactNode;
|
|
4000
|
+
expanded: boolean;
|
|
4001
|
+
/** Omit for a row that cannot open. The arrow's space is still reserved, so a list of
|
|
4002
|
+
* rows stays in one column whether or not each one has a body. */
|
|
4003
|
+
onToggle?: (expanded: boolean) => void;
|
|
4004
|
+
/**
|
|
4005
|
+
* Pins the row while its body scrolls, so a long body never leaves the reader without
|
|
4006
|
+
* the line it belongs to. Offset by whatever is already pinned above it.
|
|
4007
|
+
*/
|
|
4008
|
+
sticky?: boolean;
|
|
4009
|
+
stickyTopOffset?: number;
|
|
4010
|
+
divider?: boolean;
|
|
4011
|
+
tone?: SurfaceRowProps['tone'];
|
|
4012
|
+
/** Names the disclosure control, which is otherwise only an arrow. */
|
|
4013
|
+
'aria-label'?: string;
|
|
4014
|
+
className?: string;
|
|
4015
|
+
style?: default_2.CSSProperties;
|
|
3952
4016
|
}
|
|
3953
4017
|
|
|
3954
4018
|
export declare interface SurfaceProps {
|