@stackone/malachite 2.23.0 → 2.23.1
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/dist/components/CardStrip.js +157 -157
- package/dist/components/CardStrip.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/package.json +1 -1
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import $, { useRef as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { CONTENT_INSET as
|
|
7
|
-
import { CARD_FLARE_PX as m, STRIP_RULE_PX as
|
|
8
|
-
import { CardStripSlotContext as
|
|
9
|
-
import { FOCUS_RING as
|
|
10
|
-
import { useAdoptedStyleSheet as
|
|
11
|
-
const
|
|
1
|
+
import { jsxs as M, jsx as u } from "react/jsx-runtime";
|
|
2
|
+
import $, { useRef as H, useState as mt, useCallback as L, useLayoutEffect as X } from "react";
|
|
3
|
+
import Xt from "./CustomIcons/ArrowLeftIcon.js";
|
|
4
|
+
import Wt from "./CustomIcons/ForwardArrowIcon.js";
|
|
5
|
+
import Mt from "./CustomIcons/PlusIcon.js";
|
|
6
|
+
import { CONTENT_INSET as Rt } from "./PageLayout/constants.js";
|
|
7
|
+
import { CARD_FLARE_PX as m, STRIP_RULE_PX as Yt, CARD_FLARE_TIP_PX as et, CARD_WIDTH_PX as Vt, FLARE_CLASS as zt } from "./SelectableCard.js";
|
|
8
|
+
import { CardStripSlotContext as gt, PINNED_SLOT as Kt, SCROLLED_SLOT as jt } from "./cardStripSlot.js";
|
|
9
|
+
import { FOCUS_RING as qt } from "./focusRing.js";
|
|
10
|
+
import { useAdoptedStyleSheet as Zt } from "./useAdoptedStyleSheet.js";
|
|
11
|
+
const Jt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"]), I = '[role="radio"]', Qt = "data-card-strip-scroller", te = "data-card-strip-trough", Y = "malachite-card-strip", R = "malachite-card-strip-scroller", wt = "malachite-card-strip-fade", x = "malachite-card-strip-add-tile", Ct = "[data-selectable-card-actions]", ee = 'a[href], area[href], button, input, select, textarea, iframe, [contenteditable="true"], [tabindex]', C = "data-card-strip-prev-tabindex", Q = 1, re = 0.8, ne = (t) => {
|
|
12
12
|
const [r, c] = Array.from(t.children), s = r && c ? c.getBoundingClientRect().left - r.getBoundingClientRect().left : (r == null ? void 0 : r.getBoundingClientRect().width) ?? 0, i = t.clientWidth - m * 2;
|
|
13
|
-
return s <= 0 ? i *
|
|
14
|
-
},
|
|
15
|
-
.${
|
|
16
|
-
clip-path: inset(-${
|
|
13
|
+
return s <= 0 ? i * re : Math.max(1, Math.floor(i / s)) * s;
|
|
14
|
+
}, oe = 80, ae = 20, _t = 11, T = 12, P = 52, ce = (P + ae) / 2, It = "var(--malachite-shadow-default)", se = "var(--malachite-card-strip-arrow-background, var(--malachite-card-background, #ffffff))", ie = "var(--malachite-card-strip-arrow-border, #e8e8e8)", rt = "var(--malachite-card-strip-background, #f1f1f1)", At = "var(--malachite-radius-xxl, 14px)", le = `${At} ${At} 0 0`, xt = "var(--malachite-radius-xxxl, 16px)", de = `${xt} ${xt} 0 0`, V = 4, St = oe + (m - V), ue = Vt, fe = "var(--malachite-card-strip-divider, #dddddd)", Et = "var(--malachite-card-strip-fade, transparent)", pe = "var(--malachite-selectable-card-hover-background, #e8e8e8)", he = "var(--malachite-card-strip-arrow-border, #e8e8e8)", Lt = "var(--malachite-selectable-card-hover-rule, #bbbbbb)", $t = "0px 1px 0px 0px rgba(0, 0, 0, 0.4)", be = "var(--malachite-card-background, #ffffff)", me = "var(--malachite-text-primary, #0a0a0a)", Re = "var(--malachite-card-strip-add-primary-background, var(--malachite-text-primary, #0a0a0a))", ge = "var(--malachite-card-strip-add-primary-foreground, var(--malachite-card-background, #ffffff))", _e = "0px 1px 0px 0px rgba(10, 10, 10, 0.7)", ot = Yt, Tt = 16, W = 9999, Ae = 4, xe = `
|
|
15
|
+
.${Y} {
|
|
16
|
+
clip-path: inset(-${W}px -${W}px 0);
|
|
17
17
|
}
|
|
18
|
-
.${
|
|
19
|
-
clip-path: inset(-${
|
|
18
|
+
.${Y}:has(:focus-visible) {
|
|
19
|
+
clip-path: inset(-${W}px -${W}px -${Ae}px);
|
|
20
20
|
}
|
|
21
21
|
.${R} {
|
|
22
22
|
display: flex;
|
|
@@ -26,8 +26,8 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
26
26
|
scroll-behavior: smooth;
|
|
27
27
|
scrollbar-width: none;
|
|
28
28
|
-ms-overflow-style: none;
|
|
29
|
-
padding-block: ${
|
|
30
|
-
margin-block: -${
|
|
29
|
+
padding-block: ${Tt}px;
|
|
30
|
+
margin-block: -${Tt}px;
|
|
31
31
|
/* overflow-x clips both axes, so the end cards would lose a flare; the negative margin trades
|
|
32
32
|
the padding back out and scroll-padding keeps the rest position at zero. */
|
|
33
33
|
padding-inline: ${m}px;
|
|
@@ -35,7 +35,7 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
35
35
|
scroll-padding-inline: ${m}px;
|
|
36
36
|
}
|
|
37
37
|
/* A card focused at a faded edge has to stay readable, so the fade lifts entirely. */
|
|
38
|
-
.${
|
|
38
|
+
.${Y}:has(:focus-visible) .${wt} {
|
|
39
39
|
display: none;
|
|
40
40
|
}
|
|
41
41
|
.${R}::-webkit-scrollbar {
|
|
@@ -43,40 +43,40 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
43
43
|
}
|
|
44
44
|
/* No bottom edge: the strip's rule is the baseline for the add tile as much as for a card. */
|
|
45
45
|
.${x} > * {
|
|
46
|
-
background: ${
|
|
47
|
-
border-radius: ${
|
|
46
|
+
background: ${rt};
|
|
47
|
+
border-radius: ${le};
|
|
48
48
|
}
|
|
49
49
|
.${x}:hover:not(:has(button:disabled)) > * {
|
|
50
|
-
background: ${
|
|
50
|
+
background: ${pe};
|
|
51
51
|
}
|
|
52
52
|
.${x} button:active:not(:disabled) {
|
|
53
53
|
opacity: 0.8;
|
|
54
54
|
}
|
|
55
55
|
.${x}:has(button:active) > * {
|
|
56
|
-
background: ${
|
|
56
|
+
background: ${rt};
|
|
57
57
|
}
|
|
58
58
|
.${x}[data-emphasis='secondary'] button {
|
|
59
|
-
border-color: ${
|
|
60
|
-
box-shadow: ${
|
|
59
|
+
border-color: ${he};
|
|
60
|
+
box-shadow: ${It};
|
|
61
61
|
}
|
|
62
62
|
.${x}[data-emphasis='secondary']:hover:not(:has(button:disabled)) button {
|
|
63
|
-
border-color: ${
|
|
64
|
-
box-shadow: ${
|
|
63
|
+
border-color: ${Lt};
|
|
64
|
+
box-shadow: ${$t};
|
|
65
65
|
}
|
|
66
66
|
.${x}[data-emphasis='secondary'] button:active:not(:disabled) {
|
|
67
|
-
border-color: ${
|
|
68
|
-
box-shadow: ${
|
|
67
|
+
border-color: ${Lt};
|
|
68
|
+
box-shadow: ${$t};
|
|
69
69
|
}
|
|
70
70
|
.${x}[data-emphasis='primary'] button {
|
|
71
71
|
border-color: transparent;
|
|
72
|
-
box-shadow: ${
|
|
72
|
+
box-shadow: ${_e};
|
|
73
73
|
}
|
|
74
74
|
.${R} > * {
|
|
75
75
|
flex: 0 0 auto;
|
|
76
76
|
min-width: 0;
|
|
77
77
|
}
|
|
78
78
|
.${R} > * + * {
|
|
79
|
-
border-left: 1px solid ${
|
|
79
|
+
border-left: 1px solid ${fe};
|
|
80
80
|
}
|
|
81
81
|
.${R}[data-snap='true'] {
|
|
82
82
|
scroll-snap-type: x proximity;
|
|
@@ -94,14 +94,14 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
94
94
|
.${R}[data-snap='true'] > * {
|
|
95
95
|
scroll-snap-align: none;
|
|
96
96
|
}
|
|
97
|
-
}`,
|
|
97
|
+
}`, Se = "malachite-card-strip-style", vt = () => typeof window > "u" || typeof window.matchMedia != "function" ? !0 : window.matchMedia("(prefers-reduced-motion: reduce)").matches, A = (t) => t.dataset.value ?? t.getAttribute("value"), tt = (t) => t.hasAttribute("disabled") || t.getAttribute("aria-disabled") === "true", Ee = (t) => {
|
|
98
98
|
const r = t.parentElement;
|
|
99
|
-
return !r || r.querySelectorAll(I).length !== 1 ? null : r.querySelector(
|
|
100
|
-
},
|
|
99
|
+
return !r || r.querySelectorAll(I).length !== 1 ? null : r.querySelector(Ct);
|
|
100
|
+
}, Le = (t, r) => {
|
|
101
101
|
const c = t.closest(I);
|
|
102
102
|
if (c)
|
|
103
103
|
return c;
|
|
104
|
-
if (t.closest(
|
|
104
|
+
if (t.closest(Ct))
|
|
105
105
|
return null;
|
|
106
106
|
let s = t;
|
|
107
107
|
for (; s && r.contains(s); ) {
|
|
@@ -111,63 +111,63 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
111
111
|
s = s.parentElement;
|
|
112
112
|
}
|
|
113
113
|
return null;
|
|
114
|
-
}, Le = (t) => {
|
|
115
|
-
const r = Se(t);
|
|
116
|
-
return r ? Array.from(r.querySelectorAll(Qt)) : [];
|
|
117
114
|
}, $e = (t) => {
|
|
118
|
-
|
|
115
|
+
const r = Ee(t);
|
|
116
|
+
return r ? Array.from(r.querySelectorAll(ee)) : [];
|
|
119
117
|
}, Te = (t) => {
|
|
120
|
-
|
|
118
|
+
t.hasAttribute(C) || t.setAttribute(C, t.getAttribute("tabindex") ?? ""), t.setAttribute("tabindex", "-1");
|
|
119
|
+
}, ve = (t) => {
|
|
120
|
+
if (!t.hasAttribute(C))
|
|
121
121
|
return;
|
|
122
|
-
const r = t.getAttribute(
|
|
123
|
-
t.removeAttribute(
|
|
124
|
-
},
|
|
122
|
+
const r = t.getAttribute(C);
|
|
123
|
+
t.removeAttribute(C), r ? t.setAttribute("tabindex", r) : t.removeAttribute("tabindex");
|
|
124
|
+
}, ye = {
|
|
125
125
|
profile: "var(--malachite-selectable-card-selected-border, #047b43)",
|
|
126
126
|
library: "var(--malachite-selectable-card-library-selected-border, #bbbbbb)",
|
|
127
127
|
editing: "var(--malachite-selectable-card-pending-foreground, #96580a)"
|
|
128
|
-
},
|
|
128
|
+
}, De = {
|
|
129
129
|
backgroundRepeat: "no-repeat",
|
|
130
130
|
backgroundPosition: "left bottom",
|
|
131
|
-
backgroundSize: `100% ${
|
|
132
|
-
},
|
|
133
|
-
const r = t.querySelector(`:scope > .${
|
|
131
|
+
backgroundSize: `100% ${ot}px`
|
|
132
|
+
}, yt = 0.5, Dt = m - et, Oe = (t) => {
|
|
133
|
+
const r = t.querySelector(`:scope > .${zt}`);
|
|
134
134
|
if (!r)
|
|
135
135
|
return null;
|
|
136
136
|
const { left: c, right: s } = r.getBoundingClientRect();
|
|
137
|
-
return { left: c +
|
|
138
|
-
},
|
|
137
|
+
return { left: c + Dt, right: s - Dt };
|
|
138
|
+
}, we = (t, r, c, s) => {
|
|
139
139
|
if (!t)
|
|
140
140
|
return;
|
|
141
|
-
const i =
|
|
141
|
+
const i = ye[s], S = t.getBoundingClientRect(), v = S.left, k = c && (r != null && r.contains(c)) ? r.getBoundingClientRect() : S, E = c == null ? void 0 : c.getBoundingClientRect(), g = c ? Oe(c) : null, K = (g == null ? void 0 : g.left) ?? (E ? E.left - et : 0), j = (g == null ? void 0 : g.right) ?? (E ? E.right + et : 0), y = E ? Math.max(K, k.left) + yt - v : 0, b = E ? Math.min(j, k.right) - yt - v : 0;
|
|
142
142
|
t.style.backgroundImage = b > y ? `linear-gradient(to right, ${i} 0 ${y}px, transparent ${y}px ${b}px, ${i} ${b}px 100%)` : `linear-gradient(to right, ${i} 0 100%)`;
|
|
143
143
|
}, Ce = {
|
|
144
|
-
marginInline: `calc(${
|
|
145
|
-
paddingInline:
|
|
146
|
-
},
|
|
147
|
-
background:
|
|
148
|
-
borderRadius:
|
|
149
|
-
paddingTop: `${
|
|
150
|
-
paddingInline: `${
|
|
151
|
-
marginBottom: `${
|
|
152
|
-
},
|
|
153
|
-
...
|
|
144
|
+
marginInline: `calc(${Rt} * -1)`,
|
|
145
|
+
paddingInline: Rt
|
|
146
|
+
}, z = {
|
|
147
|
+
background: rt,
|
|
148
|
+
borderRadius: de,
|
|
149
|
+
paddingTop: `${V}px`,
|
|
150
|
+
paddingInline: `${V}px`,
|
|
151
|
+
marginBottom: `${ot}px`
|
|
152
|
+
}, Ie = {
|
|
153
|
+
...z,
|
|
154
154
|
marginInline: `${T}px`
|
|
155
|
-
},
|
|
155
|
+
}, Pe = Object.fromEntries(
|
|
156
156
|
[T, P].flatMap(
|
|
157
157
|
(t) => [T, P].map((r) => [
|
|
158
158
|
`${t}:${r}`,
|
|
159
|
-
{ ...
|
|
159
|
+
{ ...z, marginInline: `${t}px ${r}px` }
|
|
160
160
|
])
|
|
161
161
|
)
|
|
162
|
-
),
|
|
162
|
+
), ke = z, Ne = z, Ue = {
|
|
163
163
|
marginInlineStart: `${T}px`
|
|
164
|
-
},
|
|
164
|
+
}, Be = {
|
|
165
165
|
primary: {
|
|
166
|
-
backgroundColor:
|
|
167
|
-
color:
|
|
166
|
+
backgroundColor: Re,
|
|
167
|
+
color: ge
|
|
168
168
|
},
|
|
169
|
-
secondary: { backgroundColor:
|
|
170
|
-
},
|
|
169
|
+
secondary: { backgroundColor: be, color: me }
|
|
170
|
+
}, Pt = ({
|
|
171
171
|
label: t,
|
|
172
172
|
icon: r,
|
|
173
173
|
onClick: c,
|
|
@@ -180,26 +180,26 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
180
180
|
className: x,
|
|
181
181
|
"data-emphasis": i,
|
|
182
182
|
style: {
|
|
183
|
-
...
|
|
184
|
-
width: `${
|
|
185
|
-
height: `calc(100% - ${
|
|
183
|
+
...ke,
|
|
184
|
+
width: `${ue}px`,
|
|
185
|
+
height: `calc(100% - ${ot}px)`
|
|
186
186
|
},
|
|
187
|
-
children: /* @__PURE__ */ u("div", { className: "flex h-full items-center justify-center px-4", children: /* @__PURE__ */
|
|
187
|
+
children: /* @__PURE__ */ u("div", { className: "flex h-full items-center justify-center px-4", children: /* @__PURE__ */ M(
|
|
188
188
|
"button",
|
|
189
189
|
{
|
|
190
190
|
type: "button",
|
|
191
191
|
onClick: c,
|
|
192
192
|
disabled: s,
|
|
193
|
-
style:
|
|
194
|
-
className: `${
|
|
193
|
+
style: Be[i],
|
|
194
|
+
className: `${qt} inline-flex items-center justify-center gap-1.5 h-[var(--malachite-control-height-medium,32px)] w-[108px] px-2.5 rounded-xl border border-solid text-[length:var(--malachite-font-size-small,13px)] font-medium whitespace-nowrap ${s ? "opacity-50 cursor-not-allowed" : "cursor-pointer"} ${S}`,
|
|
195
195
|
children: [
|
|
196
|
-
/* @__PURE__ */ u("span", { className: "inline-flex h-[13px] w-[13px] shrink-0 items-center justify-center", children: r ?? /* @__PURE__ */ u(
|
|
196
|
+
/* @__PURE__ */ u("span", { className: "inline-flex h-[13px] w-[13px] shrink-0 items-center justify-center", children: r ?? /* @__PURE__ */ u(Mt, { size: 13 }) }),
|
|
197
197
|
t
|
|
198
198
|
]
|
|
199
199
|
}
|
|
200
200
|
) })
|
|
201
201
|
}
|
|
202
|
-
),
|
|
202
|
+
), nt = (t) => $.isValidElement(t) && t.type === Pt, Ge = (t) => $.isValidElement(t) && t.type === $.Fragment && $.Children.toArray(t.props.children).some(nt), Ot = ({ side: t, onClick: r }) => /* @__PURE__ */ u(
|
|
203
203
|
"button",
|
|
204
204
|
{
|
|
205
205
|
type: "button",
|
|
@@ -209,14 +209,14 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
209
209
|
onClick: r,
|
|
210
210
|
className: "absolute top-1/2 -translate-y-1/2 z-10 inline-flex items-center justify-center w-5 h-5 rounded-lg cursor-pointer text-[var(--malachite-text-secondary)]",
|
|
211
211
|
style: {
|
|
212
|
-
[t]: `-${
|
|
213
|
-
background:
|
|
214
|
-
border: `1px solid ${
|
|
215
|
-
boxShadow:
|
|
212
|
+
[t]: `-${ce}px`,
|
|
213
|
+
background: se,
|
|
214
|
+
border: `1px solid ${ie}`,
|
|
215
|
+
boxShadow: It
|
|
216
216
|
},
|
|
217
|
-
children: t === "left" ? /* @__PURE__ */ u(
|
|
217
|
+
children: t === "left" ? /* @__PURE__ */ u(Xt, { size: _t }) : /* @__PURE__ */ u(Wt, { size: _t })
|
|
218
218
|
}
|
|
219
|
-
),
|
|
219
|
+
), Fe = ({
|
|
220
220
|
value: t,
|
|
221
221
|
tone: r,
|
|
222
222
|
onChange: c,
|
|
@@ -227,95 +227,95 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
227
227
|
snap: k = !0,
|
|
228
228
|
bleed: E = !1,
|
|
229
229
|
scrollSelectedIntoView: g = !0,
|
|
230
|
-
"aria-label":
|
|
231
|
-
"aria-labelledby":
|
|
230
|
+
"aria-label": K,
|
|
231
|
+
"aria-labelledby": j,
|
|
232
232
|
className: y = "",
|
|
233
233
|
style: b
|
|
234
234
|
}) => {
|
|
235
|
-
const D =
|
|
236
|
-
|
|
237
|
-
const
|
|
235
|
+
const D = H(null), O = H(null), at = H(!1), [N, kt] = mt({ canScrollLeft: !1, canScrollRight: !1 });
|
|
236
|
+
Zt(D, xe, Se);
|
|
237
|
+
const q = $.Children.toArray(s), Z = q.filter((e) => !nt(e)), Nt = Z.some(Ge), U = Z.length > 0, ct = q.filter(nt).map(
|
|
238
238
|
(e) => e.props.emphasis === void 0 ? $.cloneElement(e, { emphasis: U ? "secondary" : "primary" }) : e
|
|
239
|
-
),
|
|
239
|
+
), st = q.length, _ = L(() => {
|
|
240
240
|
const e = D.current;
|
|
241
241
|
return e ? Array.from(e.querySelectorAll(I)) : [];
|
|
242
|
-
}, []),
|
|
242
|
+
}, []), J = L(
|
|
243
243
|
() => _().filter((e) => A(e) !== null),
|
|
244
244
|
[_]
|
|
245
|
-
),
|
|
246
|
-
|
|
247
|
-
}, []), [
|
|
248
|
-
|
|
245
|
+
), it = H(/* @__PURE__ */ new Set()), w = L((e, n) => {
|
|
246
|
+
it.current.has(e) || (it.current.add(e), console.warn(n));
|
|
247
|
+
}, []), [Ut, Bt] = mt("profile");
|
|
248
|
+
X(() => {
|
|
249
249
|
var n, a;
|
|
250
250
|
const e = (a = (n = _().find((d) => A(d) === t)) == null ? void 0 : n.parentElement) == null ? void 0 : a.getAttribute("data-variant");
|
|
251
|
-
(e === "profile" || e === "library" || e === "editing") &&
|
|
252
|
-
}, [_, t]),
|
|
253
|
-
const e = _(), n =
|
|
251
|
+
(e === "profile" || e === "library" || e === "editing") && Bt(e);
|
|
252
|
+
}, [_, t]), X(() => {
|
|
253
|
+
const e = _(), n = J(), d = n.find((o) => A(o) === t) ?? n.find((o) => !tt(o)) ?? null;
|
|
254
254
|
if (e.forEach((o) => {
|
|
255
255
|
const h = o === d, G = h ? 0 : -1;
|
|
256
256
|
o.tabIndex !== G && (o.tabIndex = G);
|
|
257
|
-
for (const
|
|
258
|
-
h ?
|
|
257
|
+
for (const F of $e(o))
|
|
258
|
+
h ? ve(F) : Te(F);
|
|
259
259
|
}), process.env.NODE_ENV === "production")
|
|
260
260
|
return;
|
|
261
|
-
n.length !== e.length &&
|
|
261
|
+
n.length !== e.length && w(
|
|
262
262
|
"missing-value",
|
|
263
263
|
'CardStrip: a child with role="radio" has no `data-value`. It cannot be selected or reached by arrow keys, so it is excluded from the radio set. Give every card a `data-value`.'
|
|
264
264
|
);
|
|
265
265
|
const l = /* @__PURE__ */ new Set();
|
|
266
266
|
for (const o of n) {
|
|
267
267
|
const h = A(o);
|
|
268
|
-
h !== null && (l.has(h) &&
|
|
268
|
+
h !== null && (l.has(h) && w(
|
|
269
269
|
`duplicate:${h}`,
|
|
270
270
|
`CardStrip: two cards share the data-value "${h}". Both will read as checked and only the first is selectable — data-value must be unique.`
|
|
271
271
|
), l.add(h));
|
|
272
272
|
}
|
|
273
273
|
const p = t !== "";
|
|
274
|
-
e.length > 0 && p && !l.has(t) &&
|
|
274
|
+
e.length > 0 && p && !l.has(t) && w(
|
|
275
275
|
`unmatched:${t}`,
|
|
276
276
|
`CardStrip: value "${t}" matches no card's data-value, so the group reports no selection.`
|
|
277
277
|
);
|
|
278
278
|
const f = e.filter(
|
|
279
279
|
(o) => o.getAttribute("aria-checked") === "true"
|
|
280
280
|
).length;
|
|
281
|
-
e.length > 0 && p && f !== 1 &&
|
|
281
|
+
e.length > 0 && p && f !== 1 && w(
|
|
282
282
|
`checked:${f}`,
|
|
283
283
|
`CardStrip: ${f} cards are aria-checked, but a radiogroup has exactly one. Drive each card's checked state from the strip's \`value\`.`
|
|
284
|
-
),
|
|
284
|
+
), Nt && w(
|
|
285
285
|
"wrapped-add-tile",
|
|
286
286
|
"CardStrip: a CardStrip.AddTile inside a fragment is treated as a card and scrolls with them. The add tile must be a direct child of CardStrip."
|
|
287
287
|
);
|
|
288
|
-
}),
|
|
288
|
+
}), X(() => {
|
|
289
289
|
if (!g)
|
|
290
290
|
return;
|
|
291
|
-
const e = O.current, n = _().find((
|
|
291
|
+
const e = O.current, n = _().find((F) => A(F) === t);
|
|
292
292
|
if (!e || !n || typeof e.scrollTo != "function")
|
|
293
293
|
return;
|
|
294
|
-
const d = (n.closest('[role="radio"]') ?? n).getBoundingClientRect(), l = e.getBoundingClientRect(), p = e.scrollLeft + (d.left - l.left), f = p + d.width, o = e.scrollLeft + m, h = e.scrollLeft + e.clientWidth - m;
|
|
295
|
-
p >= o && f <= h
|
|
294
|
+
const d = (n.closest('[role="radio"]') ?? n).getBoundingClientRect(), l = e.getBoundingClientRect(), p = e.scrollLeft + (d.left - l.left), f = p + d.width, o = e.scrollLeft + m, h = e.scrollLeft + e.clientWidth - m, G = at.current;
|
|
295
|
+
at.current = !0, !(p >= o && f <= h) && e.scrollTo({
|
|
296
296
|
left: f > h ? f - e.clientWidth + m : p - m,
|
|
297
|
-
behavior: "instant"
|
|
297
|
+
behavior: G && !vt() ? "smooth" : "instant"
|
|
298
298
|
});
|
|
299
|
-
}, [_, g, t,
|
|
300
|
-
const
|
|
299
|
+
}, [_, g, t, st]);
|
|
300
|
+
const lt = r ?? Ut, dt = (b == null ? void 0 : b.background) !== void 0 || (b == null ? void 0 : b.backgroundImage) !== void 0, B = L(() => {
|
|
301
301
|
var f;
|
|
302
302
|
const e = O.current;
|
|
303
|
-
if (
|
|
303
|
+
if (dt || we(
|
|
304
304
|
D.current,
|
|
305
305
|
e,
|
|
306
306
|
(f = _().find((o) => A(o) === t)) == null ? void 0 : f.parentElement,
|
|
307
|
-
|
|
307
|
+
lt
|
|
308
308
|
), !e)
|
|
309
309
|
return;
|
|
310
|
-
const { scrollWidth: n, clientWidth: a, scrollLeft: d } = e, l = n > a +
|
|
311
|
-
canScrollLeft: l && d >
|
|
312
|
-
canScrollRight: l && d + a < n -
|
|
310
|
+
const { scrollWidth: n, clientWidth: a, scrollLeft: d } = e, l = n > a + Q, p = {
|
|
311
|
+
canScrollLeft: l && d > Q,
|
|
312
|
+
canScrollRight: l && d + a < n - Q
|
|
313
313
|
};
|
|
314
|
-
|
|
314
|
+
kt(
|
|
315
315
|
(o) => o.canScrollLeft === p.canScrollLeft && o.canScrollRight === p.canScrollRight ? o : p
|
|
316
316
|
);
|
|
317
|
-
}, [
|
|
318
|
-
|
|
317
|
+
}, [dt, _, lt, t]);
|
|
318
|
+
X(() => {
|
|
319
319
|
B();
|
|
320
320
|
const e = O.current;
|
|
321
321
|
if (!e)
|
|
@@ -326,21 +326,21 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
326
326
|
return a == null || a.observe(e), () => {
|
|
327
327
|
e.removeEventListener("scroll", n), a == null || a.disconnect();
|
|
328
328
|
};
|
|
329
|
-
}, [B,
|
|
330
|
-
const
|
|
329
|
+
}, [B, st]);
|
|
330
|
+
const ut = L((e) => {
|
|
331
331
|
const n = O.current;
|
|
332
332
|
!n || typeof n.scrollBy != "function" || n.scrollBy({
|
|
333
|
-
left: e *
|
|
334
|
-
behavior:
|
|
333
|
+
left: e * ne(n),
|
|
334
|
+
behavior: vt() ? "auto" : "smooth"
|
|
335
335
|
});
|
|
336
|
-
}, []),
|
|
336
|
+
}, []), Gt = L(
|
|
337
337
|
(e) => {
|
|
338
|
-
if (!
|
|
338
|
+
if (!Jt.has(e.key))
|
|
339
339
|
return;
|
|
340
340
|
const n = e.target;
|
|
341
341
|
if (!(n instanceof Element) || !n.closest(I))
|
|
342
342
|
return;
|
|
343
|
-
const a =
|
|
343
|
+
const a = J().filter((o) => !tt(o));
|
|
344
344
|
if (a.length === 0)
|
|
345
345
|
return;
|
|
346
346
|
e.preventDefault();
|
|
@@ -357,8 +357,8 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
357
357
|
const p = a[l], f = A(p);
|
|
358
358
|
f !== null && f !== t && c(f), p.focus();
|
|
359
359
|
},
|
|
360
|
-
[
|
|
361
|
-
),
|
|
360
|
+
[J, c, t]
|
|
361
|
+
), Ft = L(
|
|
362
362
|
(e) => {
|
|
363
363
|
const n = e.target;
|
|
364
364
|
if (!(n instanceof Element))
|
|
@@ -366,65 +366,65 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
366
366
|
const a = D.current;
|
|
367
367
|
if (!a)
|
|
368
368
|
return;
|
|
369
|
-
const d =
|
|
370
|
-
if (!d ||
|
|
369
|
+
const d = Le(n, a);
|
|
370
|
+
if (!d || tt(d))
|
|
371
371
|
return;
|
|
372
372
|
const l = A(d);
|
|
373
373
|
l !== null && l !== t && c(l);
|
|
374
374
|
},
|
|
375
375
|
[c, t]
|
|
376
|
-
),
|
|
377
|
-
return /* @__PURE__ */
|
|
376
|
+
), ft = S && N.canScrollLeft, pt = S && N.canScrollRight, ht = v && N.canScrollLeft, bt = v && N.canScrollRight, Ht = S ? Pe[`${ft ? P : T}:${pt ? P : T}`] : Ie;
|
|
377
|
+
return /* @__PURE__ */ M(
|
|
378
378
|
"div",
|
|
379
379
|
{
|
|
380
380
|
ref: D,
|
|
381
|
-
onKeyDown:
|
|
382
|
-
onClick:
|
|
383
|
-
className: `${
|
|
381
|
+
onKeyDown: Gt,
|
|
382
|
+
onClick: Ft,
|
|
383
|
+
className: `${Y} flex items-stretch ${y}`,
|
|
384
384
|
style: {
|
|
385
|
-
...
|
|
385
|
+
...De,
|
|
386
386
|
...E ? Ce : null,
|
|
387
387
|
...b
|
|
388
388
|
},
|
|
389
389
|
children: [
|
|
390
|
-
/* @__PURE__ */
|
|
390
|
+
/* @__PURE__ */ M(
|
|
391
391
|
"div",
|
|
392
392
|
{
|
|
393
393
|
role: "radiogroup",
|
|
394
|
-
"aria-label":
|
|
395
|
-
"aria-labelledby":
|
|
394
|
+
"aria-label": K,
|
|
395
|
+
"aria-labelledby": j,
|
|
396
396
|
className: U ? "flex items-stretch min-w-0" : "flex items-stretch",
|
|
397
397
|
children: [
|
|
398
|
-
i ? /* @__PURE__ */ u(
|
|
399
|
-
U ? /* @__PURE__ */
|
|
398
|
+
i ? /* @__PURE__ */ u(gt.Provider, { value: Kt, children: /* @__PURE__ */ u("div", { className: "shrink-0", style: Ne, children: i }) }) : null,
|
|
399
|
+
U ? /* @__PURE__ */ M(
|
|
400
400
|
"div",
|
|
401
401
|
{
|
|
402
|
-
[
|
|
402
|
+
[te]: "",
|
|
403
403
|
className: "relative min-w-0 shrink basis-auto",
|
|
404
|
-
style:
|
|
404
|
+
style: Ht,
|
|
405
405
|
children: [
|
|
406
406
|
/* @__PURE__ */ u(
|
|
407
407
|
"div",
|
|
408
408
|
{
|
|
409
409
|
ref: O,
|
|
410
410
|
tabIndex: -1,
|
|
411
|
-
[
|
|
411
|
+
[Qt]: "",
|
|
412
412
|
"data-snap": k ? "true" : "false",
|
|
413
413
|
className: R,
|
|
414
|
-
children: /* @__PURE__ */ u(
|
|
414
|
+
children: /* @__PURE__ */ u(gt.Provider, { value: jt, children: Z })
|
|
415
415
|
}
|
|
416
416
|
),
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
417
|
+
ft ? /* @__PURE__ */ u(Ot, { side: "left", onClick: () => ut(-1) }) : null,
|
|
418
|
+
pt ? /* @__PURE__ */ u(Ot, { side: "right", onClick: () => ut(1) }) : null,
|
|
419
|
+
ht || bt ? /* @__PURE__ */ u(
|
|
420
420
|
"div",
|
|
421
421
|
{
|
|
422
422
|
"aria-hidden": !0,
|
|
423
423
|
"data-card-strip-fade": "",
|
|
424
|
-
className: `${
|
|
424
|
+
className: `${wt} absolute pointer-events-none`,
|
|
425
425
|
style: {
|
|
426
|
-
inset: `-${
|
|
427
|
-
background: `linear-gradient(to right, ${
|
|
426
|
+
inset: `-${V}px -${m}px 0`,
|
|
427
|
+
background: `linear-gradient(to right, ${ht ? Et : "transparent"} 0, transparent ${St}px, transparent calc(100% - ${St}px), ${bt ? Et : "transparent"} 100%)`
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
430
|
) : null
|
|
@@ -434,21 +434,21 @@ const qt = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight", "ArrowUp", "Arrow
|
|
|
434
434
|
]
|
|
435
435
|
}
|
|
436
436
|
),
|
|
437
|
-
|
|
437
|
+
ct.length > 0 ? /* @__PURE__ */ u(
|
|
438
438
|
"div",
|
|
439
439
|
{
|
|
440
440
|
className: "shrink-0",
|
|
441
|
-
style: !U && i ?
|
|
442
|
-
children:
|
|
441
|
+
style: !U && i ? Ue : void 0,
|
|
442
|
+
children: ct
|
|
443
443
|
}
|
|
444
444
|
) : null
|
|
445
445
|
]
|
|
446
446
|
}
|
|
447
447
|
);
|
|
448
448
|
};
|
|
449
|
-
|
|
449
|
+
Fe.AddTile = Pt;
|
|
450
450
|
export {
|
|
451
|
-
|
|
452
|
-
|
|
451
|
+
Fe as CardStrip,
|
|
452
|
+
Fe as default
|
|
453
453
|
};
|
|
454
454
|
//# sourceMappingURL=CardStrip.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CardStrip.js","sources":["../../src/components/CardStrip.tsx"],"sourcesContent":["import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport ForwardArrowIcon from './CustomIcons/ForwardArrowIcon';\nimport PlusIcon from './CustomIcons/PlusIcon';\nimport { CONTENT_INSET } from './PageLayout/constants';\nimport {\n CARD_FLARE_PX,\n CARD_FLARE_TIP_PX,\n CARD_WIDTH_PX,\n FLARE_CLASS,\n STRIP_RULE_PX,\n} from './SelectableCard';\nimport { CardStripSlotContext, PINNED_SLOT, SCROLLED_SLOT } from './cardStripSlot';\nimport { FOCUS_RING } from './focusRing';\nimport { useAdoptedStyleSheet } from './useAdoptedStyleSheet';\n\nexport type CardStripAddTileEmphasis = 'primary' | 'secondary';\n\nexport interface CardStripAddTileProps {\n /** Visible label, e.g. \"Add Profile\". Also names the button for assistive tech. */\n label: string;\n /** Defaults to a plus. */\n icon?: React.ReactNode;\n onClick: () => void;\n disabled?: boolean;\n /** Leave unset: CardStrip picks `primary` while the strip is empty and `secondary` once cards exist. */\n emphasis?: CardStripAddTileEmphasis;\n className?: string;\n}\n\n/** Palette for the strip's rule. Pass the tone of whatever card is selected. */\nexport type CardStripTone = 'profile' | 'library' | 'editing';\n\nexport interface CardStripProps {\n /** The selected card's value, matched against each radio child's `data-value`. */\n value: string;\n /** Overrides the palette the strip reads off the selected card. See `CardStripTone`. */\n tone?: CardStripTone;\n onChange: (value: string) => void;\n /** Cards. Any element with `role=\"radio\"` and a `data-value` joins the group; an\n * add tile must be a direct child or it scrolls with the cards. */\n children: React.ReactNode;\n /** Pinned, non-scrolling slot before the cards (the Library card in the profile picker). */\n leading?: React.ReactNode;\n /** Circular scroll affordances, shown only on an edge that can actually scroll. */\n arrows?: boolean;\n /** Fade the cards out at any edge they scroll past. */\n fadeEdges?: boolean;\n /** Snap cards to the leading edge as the strip scrolls. */\n snap?: boolean;\n /** Run the bottom rule the full width of the page card while the cards stay on the gutter.\n * Only has an effect inside a layout that publishes its inset (`PageLayout`). */\n bleed?: boolean;\n /** Whether a selection change scrolls the selected card into view. Set `false` when the\n * value comes from a URL, or a deep-linked strip below the fold jumps the page on load. */\n scrollSelectedIntoView?: boolean;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/** Arrow keys move AND select, per the WAI-ARIA radiogroup pattern. */\nconst NAV_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End']);\n\nconst RADIO_SELECTOR = '[role=\"radio\"]';\nconst SCROLLER_ATTR = 'data-card-strip-scroller';\nconst TROUGH_ATTR = 'data-card-strip-trough';\nconst ROOT_CLASS = 'malachite-card-strip';\nconst SCROLLER_CLASS = 'malachite-card-strip-scroller';\nconst FADE_CLASS = 'malachite-card-strip-fade';\nconst ADD_TILE_CLASS = 'malachite-card-strip-add-tile';\n\nconst ACTIONS_SELECTOR = '[data-selectable-card-actions]';\nconst FOCUSABLE_SELECTOR =\n 'a[href], area[href], button, input, select, textarea, iframe, [contenteditable=\"true\"], [tabindex]';\nconst PREV_TABINDEX_ATTR = 'data-card-strip-prev-tabindex';\n\nconst EDGE_EPSILON_PX = 1;\nconst SCROLL_STEP_RATIO = 0.8;\n\nconst scrollStepFor = (scroller: HTMLElement): number => {\n const [first, second] = Array.from(scroller.children);\n const pitch =\n first && second\n ? second.getBoundingClientRect().left - first.getBoundingClientRect().left\n : (first?.getBoundingClientRect().width ?? 0);\n // `clientWidth` counts the flare padding, which is not width a card can be read in.\n const visible = scroller.clientWidth - CARD_FLARE_PX * 2;\n\n if (pitch <= 0) {\n return visible * SCROLL_STEP_RATIO;\n }\n\n return Math.max(1, Math.floor(visible / pitch)) * pitch;\n};\nconst FADE_WIDTH_PX = 80;\n\nconst ARROW_SIZE_PX = 20;\nconst ARROW_GLYPH_PX = 11;\nconst GUTTER_REST_PX = 12;\nconst GUTTER_OPEN_PX = 52;\nconst ARROW_OFFSET_PX = (GUTTER_OPEN_PX + ARROW_SIZE_PX) / 2;\n\nconst LIP_SHADOW = 'var(--malachite-shadow-default)';\nconst ARROW_BACKGROUND =\n 'var(--malachite-card-strip-arrow-background, var(--malachite-card-background, #ffffff))';\nconst ARROW_BORDER = 'var(--malachite-card-strip-arrow-border, #e8e8e8)';\nconst TROUGH_BACKGROUND = 'var(--malachite-card-strip-background, #f1f1f1)';\nconst CARD_CORNER = 'var(--malachite-radius-xxl, 14px)';\nconst CARD_RADIUS = `${CARD_CORNER} ${CARD_CORNER} 0 0`;\nconst TROUGH_CORNER = 'var(--malachite-radius-xxxl, 16px)';\nconst TROUGH_RADIUS = `${TROUGH_CORNER} ${TROUGH_CORNER} 0 0`;\nconst TROUGH_SHOULDER_PX = 4;\nconst FADE_RAMP_PX = FADE_WIDTH_PX + (CARD_FLARE_PX - TROUGH_SHOULDER_PX);\nconst SLOT_WIDTH_PX = CARD_WIDTH_PX;\nconst DIVIDER_COLOR = 'var(--malachite-card-strip-divider, #dddddd)';\nconst FADE_COLOR = 'var(--malachite-card-strip-fade, transparent)';\nconst ADD_HOVER_BACKGROUND = 'var(--malachite-selectable-card-hover-background, #e8e8e8)';\nconst ADD_PILL_BORDER = 'var(--malachite-card-strip-arrow-border, #e8e8e8)';\nconst ADD_PILL_BORDER_ACTIVE = 'var(--malachite-selectable-card-hover-rule, #bbbbbb)';\nconst ADD_PILL_SHADOW_DEEP = '0px 1px 0px 0px rgba(0, 0, 0, 0.4)';\nconst ADD_PILL_BACKGROUND = 'var(--malachite-card-background, #ffffff)';\nconst ADD_PILL_FOREGROUND = 'var(--malachite-text-primary, #0a0a0a)';\nconst ADD_PILL_PRIMARY_BACKGROUND =\n 'var(--malachite-card-strip-add-primary-background, var(--malachite-text-primary, #0a0a0a))';\nconst ADD_PILL_PRIMARY_FOREGROUND =\n 'var(--malachite-card-strip-add-primary-foreground, var(--malachite-card-background, #ffffff))';\nconst ADD_PILL_PRIMARY_SHADOW = '0px 1px 0px 0px rgba(10, 10, 10, 0.7)';\n\nconst BOTTOM_RULE_WEIGHT_PX = STRIP_RULE_PX;\n\nconst OVERFLOW_INSET_PX = 16;\n\nconst CLIP_SLACK_PX = 9999;\nconst FOCUS_RING_REACH_PX = 4;\n\n/** A sheet, not inline styles: these rules have to reach children this component does not render. */\nconst SCROLLER_CSS = `\n.${ROOT_CLASS} {\n clip-path: inset(-${CLIP_SLACK_PX}px -${CLIP_SLACK_PX}px 0);\n}\n.${ROOT_CLASS}:has(:focus-visible) {\n clip-path: inset(-${CLIP_SLACK_PX}px -${CLIP_SLACK_PX}px -${FOCUS_RING_REACH_PX}px);\n}\n.${SCROLLER_CLASS} {\n display: flex;\n flex-wrap: nowrap;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scrollbar-width: none;\n -ms-overflow-style: none;\n padding-block: ${OVERFLOW_INSET_PX}px;\n margin-block: -${OVERFLOW_INSET_PX}px;\n /* overflow-x clips both axes, so the end cards would lose a flare; the negative margin trades\n the padding back out and scroll-padding keeps the rest position at zero. */\n padding-inline: ${CARD_FLARE_PX}px;\n margin-inline: -${CARD_FLARE_PX}px;\n scroll-padding-inline: ${CARD_FLARE_PX}px;\n}\n/* A card focused at a faded edge has to stay readable, so the fade lifts entirely. */\n.${ROOT_CLASS}:has(:focus-visible) .${FADE_CLASS} {\n display: none;\n}\n.${SCROLLER_CLASS}::-webkit-scrollbar {\n display: none;\n}\n/* No bottom edge: the strip's rule is the baseline for the add tile as much as for a card. */\n.${ADD_TILE_CLASS} > * {\n background: ${TROUGH_BACKGROUND};\n border-radius: ${CARD_RADIUS};\n}\n.${ADD_TILE_CLASS}:hover:not(:has(button:disabled)) > * {\n background: ${ADD_HOVER_BACKGROUND};\n}\n.${ADD_TILE_CLASS} button:active:not(:disabled) {\n opacity: 0.8;\n}\n.${ADD_TILE_CLASS}:has(button:active) > * {\n background: ${TROUGH_BACKGROUND};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary'] button {\n border-color: ${ADD_PILL_BORDER};\n box-shadow: ${LIP_SHADOW};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary']:hover:not(:has(button:disabled)) button {\n border-color: ${ADD_PILL_BORDER_ACTIVE};\n box-shadow: ${ADD_PILL_SHADOW_DEEP};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary'] button:active:not(:disabled) {\n border-color: ${ADD_PILL_BORDER_ACTIVE};\n box-shadow: ${ADD_PILL_SHADOW_DEEP};\n}\n.${ADD_TILE_CLASS}[data-emphasis='primary'] button {\n border-color: transparent;\n box-shadow: ${ADD_PILL_PRIMARY_SHADOW};\n}\n.${SCROLLER_CLASS} > * {\n flex: 0 0 auto;\n min-width: 0;\n}\n.${SCROLLER_CLASS} > * + * {\n border-left: 1px solid ${DIVIDER_COLOR};\n}\n.${SCROLLER_CLASS}[data-snap='true'] {\n scroll-snap-type: x proximity;\n}\n.${SCROLLER_CLASS}[data-snap='true'] > * {\n scroll-snap-align: start;\n}\n@media (prefers-reduced-motion: reduce) {\n .${SCROLLER_CLASS} {\n scroll-behavior: auto;\n }\n .${SCROLLER_CLASS}[data-snap='true'] {\n scroll-snap-type: none;\n }\n .${SCROLLER_CLASS}[data-snap='true'] > * {\n scroll-snap-align: none;\n }\n}`;\n\nconst STYLE_ID = 'malachite-card-strip-style';\n\n/** `window.matchMedia` is absent under SSR and in older test environments. */\nconst prefersReducedMotion = (): boolean => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return true;\n }\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n};\n\nconst radioValue = (radio: HTMLElement): string | null =>\n radio.dataset.value ?? radio.getAttribute('value');\n\nconst isRadioDisabled = (radio: HTMLElement): boolean =>\n radio.hasAttribute('disabled') || radio.getAttribute('aria-disabled') === 'true';\n\nconst actionsFor = (radio: HTMLElement): HTMLElement | null => {\n const card = radio.parentElement;\n if (!card || card.querySelectorAll(RADIO_SELECTOR).length !== 1) {\n return null;\n }\n return card.querySelector<HTMLElement>(ACTIONS_SELECTOR);\n};\n\n/** A card is wider than its radio, so `closest` misses clicks on the count row. */\nconst radioForClick = (target: Element, root: Element): HTMLElement | null => {\n const direct = target.closest<HTMLElement>(RADIO_SELECTOR);\n if (direct) {\n return direct;\n }\n if (target.closest(ACTIONS_SELECTOR)) {\n return null;\n }\n let node: Element | null = target;\n while (node && root.contains(node)) {\n const radios: NodeListOf<HTMLElement> = node.querySelectorAll(RADIO_SELECTOR);\n if (radios.length === 1 && radios[0].parentElement === node) {\n return radios[0];\n }\n node = node.parentElement;\n }\n return null;\n};\n\nconst actionControls = (radio: HTMLElement): HTMLElement[] => {\n const actions = actionsFor(radio);\n return actions ? Array.from(actions.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)) : [];\n};\n\nconst suppressTabStop = (element: HTMLElement): void => {\n if (!element.hasAttribute(PREV_TABINDEX_ATTR)) {\n element.setAttribute(PREV_TABINDEX_ATTR, element.getAttribute('tabindex') ?? '');\n }\n element.setAttribute('tabindex', '-1');\n};\n\nconst restoreTabStop = (element: HTMLElement): void => {\n if (!element.hasAttribute(PREV_TABINDEX_ATTR)) {\n return;\n }\n const previous = element.getAttribute(PREV_TABINDEX_ATTR);\n element.removeAttribute(PREV_TABINDEX_ATTR);\n if (previous) {\n element.setAttribute('tabindex', previous);\n } else {\n element.removeAttribute('tabindex');\n }\n};\n\nconst TONE_RULE: Record<CardStripTone, string> = {\n profile: 'var(--malachite-selectable-card-selected-border, #047b43)',\n library: 'var(--malachite-selectable-card-library-selected-border, #bbbbbb)',\n editing: 'var(--malachite-selectable-card-pending-foreground, #96580a)',\n};\nconst RULE_ROW_STYLE: React.CSSProperties = {\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'left bottom',\n backgroundSize: `100% ${BOTTOM_RULE_WEIGHT_PX}px`,\n};\n\n/** The rule runs under the flare's tip rather than butting against it, so antialiasing\n * cannot open the junction into a gap. */\nconst RULE_GAP_OVERLAP_PX = 0.5;\n\nconst FLARE_TIP_INSET_PX = CARD_FLARE_PX - CARD_FLARE_TIP_PX;\n\nconst flareTips = (card: HTMLElement): { left: number; right: number } | null => {\n const flare = card.querySelector(`:scope > .${FLARE_CLASS}`);\n if (!flare) {\n return null;\n }\n const { left, right } = flare.getBoundingClientRect();\n return { left: left + FLARE_TIP_INSET_PX, right: right - FLARE_TIP_INSET_PX };\n};\n\n/** The rule is cut where the selected card stands, never covered: the strip's clip lands on the\n * rule's own edge, so a cover takes the same partial alpha and the rule bleeds through it. */\nconst paintRule = (\n root: HTMLElement | null,\n scroller: HTMLElement | null,\n card: HTMLElement | null | undefined,\n tone: CardStripTone,\n): void => {\n if (!root) {\n return;\n }\n const colour = TONE_RULE[tone];\n const rootRect = root.getBoundingClientRect();\n const rootLeft = rootRect.left;\n const clip = card && scroller?.contains(card) ? scroller.getBoundingClientRect() : rootRect;\n const cardRect = card?.getBoundingClientRect();\n const tips = card ? flareTips(card) : null;\n const tipLeft = tips?.left ?? (cardRect ? cardRect.left - CARD_FLARE_TIP_PX : 0);\n const tipRight = tips?.right ?? (cardRect ? cardRect.right + CARD_FLARE_TIP_PX : 0);\n const from = cardRect ? Math.max(tipLeft, clip.left) + RULE_GAP_OVERLAP_PX - rootLeft : 0;\n const to = cardRect ? Math.min(tipRight, clip.right) - RULE_GAP_OVERLAP_PX - rootLeft : 0;\n\n root.style.backgroundImage =\n to > from\n ? `linear-gradient(to right, ${colour} 0 ${from}px, transparent ${from}px ${to}px, ${colour} ${to}px 100%)`\n : `linear-gradient(to right, ${colour} 0 100%)`;\n};\n\nconst BLEED_STYLE: React.CSSProperties = {\n marginInline: `calc(${CONTENT_INSET} * -1)`,\n paddingInline: CONTENT_INSET,\n};\n\n/** The rule's row is a margin, never padding: a background paints under its own padding, which\n * would hide the very line the troughs stand on. */\nconst TROUGH_SURFACE: React.CSSProperties = {\n background: TROUGH_BACKGROUND,\n borderRadius: TROUGH_RADIUS,\n paddingTop: `${TROUGH_SHOULDER_PX}px`,\n paddingInline: `${TROUGH_SHOULDER_PX}px`,\n marginBottom: `${BOTTOM_RULE_WEIGHT_PX}px`,\n};\nconst TROUGH_STYLE: React.CSSProperties = {\n ...TROUGH_SURFACE,\n marginInline: `${GUTTER_REST_PX}px`,\n};\nconst TROUGH_GUTTER_STYLES: Record<string, React.CSSProperties> = Object.fromEntries(\n [GUTTER_REST_PX, GUTTER_OPEN_PX].flatMap((start) =>\n [GUTTER_REST_PX, GUTTER_OPEN_PX].map((end) => [\n `${start}:${end}`,\n { ...TROUGH_SURFACE, marginInline: `${start}px ${end}px` },\n ]),\n ),\n);\nconst ADD_TILE_SHAPE_STYLE: React.CSSProperties = TROUGH_SURFACE;\n\nconst PINNED_SLOT_STYLE: React.CSSProperties = TROUGH_SURFACE;\n\nconst EMPTY_ADD_SLOT_STYLE: React.CSSProperties = {\n marginInlineStart: `${GUTTER_REST_PX}px`,\n};\n\nconst ADD_PILL_FILL: Record<CardStripAddTileEmphasis, React.CSSProperties> = {\n primary: {\n backgroundColor: ADD_PILL_PRIMARY_BACKGROUND,\n color: ADD_PILL_PRIMARY_FOREGROUND,\n },\n secondary: { backgroundColor: ADD_PILL_BACKGROUND, color: ADD_PILL_FOREGROUND },\n};\n\nconst AddTile: React.FC<CardStripAddTileProps> = ({\n label,\n icon,\n onClick,\n disabled = false,\n emphasis = 'secondary',\n className = '',\n}) => (\n <div\n className={ADD_TILE_CLASS}\n data-emphasis={emphasis}\n style={{\n ...ADD_TILE_SHAPE_STYLE,\n width: `${SLOT_WIDTH_PX}px`,\n height: `calc(100% - ${BOTTOM_RULE_WEIGHT_PX}px)`,\n }}\n >\n <div className=\"flex h-full items-center justify-center px-4\">\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n style={ADD_PILL_FILL[emphasis]}\n className={`${FOCUS_RING} inline-flex items-center justify-center gap-1.5 h-[var(--malachite-control-height-medium,32px)] w-[108px] px-2.5 rounded-xl border border-solid text-[length:var(--malachite-font-size-small,13px)] font-medium whitespace-nowrap ${\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'\n } ${className}`}\n >\n <span className=\"inline-flex h-[13px] w-[13px] shrink-0 items-center justify-center\">\n {icon ?? <PlusIcon size={13} />}\n </span>\n {label}\n </button>\n </div>\n </div>\n);\n\nconst isAddTile = (node: React.ReactNode): node is React.ReactElement<CardStripAddTileProps> =>\n React.isValidElement(node) && node.type === AddTile;\n\nconst hidesAddTile = (child: React.ReactNode): boolean =>\n React.isValidElement<{ children?: React.ReactNode }>(child) &&\n child.type === React.Fragment &&\n React.Children.toArray(child.props.children).some(isAddTile);\n\ninterface ArrowButtonProps {\n side: 'left' | 'right';\n onClick: () => void;\n}\n\nconst ArrowButton: React.FC<ArrowButtonProps> = ({ side, onClick }) => (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-hidden=\"true\"\n aria-label={side === 'left' ? 'Scroll left' : 'Scroll right'}\n onClick={onClick}\n className=\"absolute top-1/2 -translate-y-1/2 z-10 inline-flex items-center justify-center w-5 h-5 rounded-lg cursor-pointer text-[var(--malachite-text-secondary)]\"\n style={{\n [side]: `-${ARROW_OFFSET_PX}px`,\n background: ARROW_BACKGROUND,\n border: `1px solid ${ARROW_BORDER}`,\n boxShadow: LIP_SHADOW,\n }}\n >\n {side === 'left' ? (\n <ArrowLeftIcon size={ARROW_GLYPH_PX} />\n ) : (\n <ForwardArrowIcon size={ARROW_GLYPH_PX} />\n )}\n </button>\n);\n\n/** A horizontally scrolling radiogroup of cards — the \"pick one of these\" strip. */\nconst CardStrip: React.FC<CardStripProps> & { AddTile: React.FC<CardStripAddTileProps> } = ({\n value,\n tone,\n onChange,\n children,\n leading,\n arrows = true,\n fadeEdges = true,\n snap = true,\n bleed = false,\n scrollSelectedIntoView = true,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const rootRef = useRef<HTMLDivElement>(null);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const [edges, setEdges] = useState({ canScrollLeft: false, canScrollRight: false });\n\n useAdoptedStyleSheet(rootRef, SCROLLER_CSS, STYLE_ID);\n\n const childList = React.Children.toArray(children);\n const cards = childList.filter((child) => !isAddTile(child));\n const wrappedAddTile = cards.some(hidesAddTile);\n const hasCards = cards.length > 0;\n\n const addTiles = childList\n .filter(isAddTile)\n .map((tile) =>\n tile.props.emphasis === undefined\n ? React.cloneElement(tile, { emphasis: hasCards ? 'secondary' : 'primary' })\n : tile,\n );\n\n const childCount = childList.length;\n\n const getRadios = useCallback((): HTMLElement[] => {\n const root = rootRef.current;\n if (!root) {\n return [];\n }\n return Array.from(root.querySelectorAll<HTMLElement>(RADIO_SELECTOR));\n }, []);\n\n const getNavigableRadios = useCallback(\n (): HTMLElement[] => getRadios().filter((radio) => radioValue(radio) !== null),\n [getRadios],\n );\n\n const warned = useRef(new Set<string>());\n const warnOnce = useCallback((key: string, message: string): void => {\n if (warned.current.has(key)) {\n return;\n }\n warned.current.add(key);\n console.warn(message);\n }, []);\n\n const [derivedTone, setDerivedTone] = useState<CardStripTone>('profile');\n\n useLayoutEffect(() => {\n const selectedCard = getRadios()\n .find((radio) => radioValue(radio) === value)\n ?.parentElement?.getAttribute('data-variant');\n if (\n selectedCard === 'profile' ||\n selectedCard === 'library' ||\n selectedCard === 'editing'\n ) {\n setDerivedTone(selectedCard);\n }\n }, [getRadios, value]);\n\n useLayoutEffect(() => {\n const radios = getRadios();\n const navigable = getNavigableRadios();\n const selected = navigable.find((radio) => radioValue(radio) === value);\n const tabStop = selected ?? navigable.find((radio) => !isRadioDisabled(radio)) ?? null;\n\n radios.forEach((radio) => {\n const holdsTabStop = radio === tabStop;\n const nextTabIndex = holdsTabStop ? 0 : -1;\n if (radio.tabIndex !== nextTabIndex) {\n radio.tabIndex = nextTabIndex;\n }\n for (const control of actionControls(radio)) {\n if (holdsTabStop) {\n restoreTabStop(control);\n } else {\n suppressTabStop(control);\n }\n }\n });\n\n if (process.env.NODE_ENV === 'production') {\n return;\n }\n\n if (navigable.length !== radios.length) {\n warnOnce(\n 'missing-value',\n 'CardStrip: a child with role=\"radio\" has no `data-value`. It cannot be selected or reached by arrow keys, so it is excluded from the radio set. Give every card a `data-value`.',\n );\n }\n\n const values = new Set<string>();\n for (const radio of navigable) {\n const current = radioValue(radio);\n if (current === null) {\n continue;\n }\n if (values.has(current)) {\n warnOnce(\n `duplicate:${current}`,\n `CardStrip: two cards share the data-value \"${current}\". Both will read as checked and only the first is selectable — data-value must be unique.`,\n );\n }\n values.add(current);\n }\n\n const selectionSettled = value !== '';\n\n if (radios.length > 0 && selectionSettled && !values.has(value)) {\n warnOnce(\n `unmatched:${value}`,\n `CardStrip: value \"${value}\" matches no card's data-value, so the group reports no selection.`,\n );\n }\n\n const checked = radios.filter(\n (radio) => radio.getAttribute('aria-checked') === 'true',\n ).length;\n if (radios.length > 0 && selectionSettled && checked !== 1) {\n warnOnce(\n `checked:${checked}`,\n `CardStrip: ${checked} cards are aria-checked, but a radiogroup has exactly one. Drive each card's checked state from the strip's \\`value\\`.`,\n );\n }\n\n if (wrappedAddTile) {\n warnOnce(\n 'wrapped-add-tile',\n 'CardStrip: a CardStrip.AddTile inside a fragment is treated as a card and scrolls with them. The add tile must be a direct child of CardStrip.',\n );\n }\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: cards arriving is the signal\n useLayoutEffect(() => {\n if (!scrollSelectedIntoView) {\n return;\n }\n const scroller = scrollerRef.current;\n const selected = getRadios().find((radio) => radioValue(radio) === value);\n // jsdom implements neither, and a strip that cannot scroll has nothing to bring into view.\n if (!scroller || !selected || typeof scroller.scrollTo !== 'function') {\n return;\n }\n\n // Positioned rather than asked for: the track is scroll-snapped, and `scrollIntoView`\n // on a card several widths away lands back on the nearest snap point instead — so a\n // card appended past the end never came into view at all.\n // Measured against the scroller rather than an offset parent: the cards are flex\n // children whose `offsetParent` is not the scroller, so `offsetLeft` is not its frame.\n const card = (selected.closest('[role=\"radio\"]') ?? selected) as HTMLElement;\n const cardRect = card.getBoundingClientRect();\n const viewRect = scroller.getBoundingClientRect();\n const left = scroller.scrollLeft + (cardRect.left - viewRect.left);\n const right = left + cardRect.width;\n const visibleFrom = scroller.scrollLeft + CARD_FLARE_PX;\n const visibleTo = scroller.scrollLeft + scroller.clientWidth - CARD_FLARE_PX;\n\n if (left >= visibleFrom && right <= visibleTo) {\n return;\n }\n\n scroller.scrollTo({\n left:\n right > visibleTo\n ? right - scroller.clientWidth + CARD_FLARE_PX\n : left - CARD_FLARE_PX,\n behavior: 'instant',\n });\n }, [getRadios, scrollSelectedIntoView, value, childCount]);\n\n const ruleTone = tone ?? derivedTone;\n const callerPaintsBackground =\n style?.background !== undefined || style?.backgroundImage !== undefined;\n\n const measure = useCallback(() => {\n const scroller = scrollerRef.current;\n if (!callerPaintsBackground) {\n paintRule(\n rootRef.current,\n scroller,\n getRadios().find((radio) => radioValue(radio) === value)?.parentElement,\n ruleTone,\n );\n }\n if (!scroller) {\n return;\n }\n const { scrollWidth, clientWidth, scrollLeft } = scroller;\n const overflows = scrollWidth > clientWidth + EDGE_EPSILON_PX;\n const next = {\n canScrollLeft: overflows && scrollLeft > EDGE_EPSILON_PX,\n canScrollRight: overflows && scrollLeft + clientWidth < scrollWidth - EDGE_EPSILON_PX,\n };\n setEdges((previous) =>\n previous.canScrollLeft === next.canScrollLeft &&\n previous.canScrollRight === next.canScrollRight\n ? previous\n : next,\n );\n }, [callerPaintsBackground, getRadios, ruleTone, value]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: adding or removing a card changes the scroll width, so re-measure on the count\n useLayoutEffect(() => {\n measure();\n\n const scroller = scrollerRef.current;\n if (!scroller) {\n return;\n }\n\n const onScroll = (): void => measure();\n scroller.addEventListener('scroll', onScroll, { passive: true });\n\n const observer =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => measure()) : null;\n observer?.observe(scroller);\n\n return () => {\n scroller.removeEventListener('scroll', onScroll);\n observer?.disconnect();\n };\n }, [measure, childCount]);\n\n const scrollByStep = useCallback((direction: -1 | 1) => {\n const scroller = scrollerRef.current;\n if (!scroller || typeof scroller.scrollBy !== 'function') {\n return;\n }\n scroller.scrollBy({\n left: direction * scrollStepFor(scroller),\n behavior: prefersReducedMotion() ? 'auto' : 'smooth',\n });\n }, []);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (!NAV_KEYS.has(event.key)) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof Element) || !target.closest(RADIO_SELECTOR)) {\n return;\n }\n\n const enabled = getNavigableRadios().filter((radio) => !isRadioDisabled(radio));\n if (enabled.length === 0) {\n return;\n }\n\n event.preventDefault();\n\n const currentPosition = enabled.findIndex((radio) => radioValue(radio) === value);\n let nextPosition: number;\n if (event.key === 'Home') {\n nextPosition = 0;\n } else if (event.key === 'End') {\n nextPosition = enabled.length - 1;\n } else {\n const delta = event.key === 'ArrowLeft' || event.key === 'ArrowUp' ? -1 : 1;\n const from = currentPosition === -1 ? 0 : currentPosition;\n nextPosition = (from + delta + enabled.length) % enabled.length;\n }\n\n const next = enabled[nextPosition];\n const nextValue = radioValue(next);\n if (nextValue !== null && nextValue !== value) {\n onChange(nextValue);\n }\n next.focus();\n },\n [getNavigableRadios, onChange, value],\n );\n\n const handleClick = useCallback(\n (event: React.MouseEvent) => {\n const target = event.target;\n if (!(target instanceof Element)) {\n return;\n }\n const root = rootRef.current;\n if (!root) {\n return;\n }\n const radio = radioForClick(target, root);\n if (!radio || isRadioDisabled(radio)) {\n return;\n }\n const clicked = radioValue(radio);\n if (clicked !== null && clicked !== value) {\n onChange(clicked);\n }\n },\n [onChange, value],\n );\n\n const showLeftArrow = arrows && edges.canScrollLeft;\n const showRightArrow = arrows && edges.canScrollRight;\n\n const fadeLeft = fadeEdges && edges.canScrollLeft;\n const fadeRight = fadeEdges && edges.canScrollRight;\n const troughStyle = arrows\n ? TROUGH_GUTTER_STYLES[\n `${showLeftArrow ? GUTTER_OPEN_PX : GUTTER_REST_PX}:${\n showRightArrow ? GUTTER_OPEN_PX : GUTTER_REST_PX\n }`\n ]\n : TROUGH_STYLE;\n\n return (\n <div\n ref={rootRef}\n onKeyDown={handleKeyDown}\n onClick={handleClick}\n className={`${ROOT_CLASS} flex items-stretch ${className}`}\n style={{\n ...RULE_ROW_STYLE,\n ...(bleed ? BLEED_STYLE : null),\n ...style,\n }}\n >\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n className={hasCards ? 'flex items-stretch min-w-0' : 'flex items-stretch'}\n >\n {leading ? (\n <CardStripSlotContext.Provider value={PINNED_SLOT}>\n <div className=\"shrink-0\" style={PINNED_SLOT_STYLE}>\n {leading}\n </div>\n </CardStripSlotContext.Provider>\n ) : null}\n {hasCards ? (\n <div\n {...{ [TROUGH_ATTR]: '' }}\n className=\"relative min-w-0 shrink basis-auto\"\n style={troughStyle}\n >\n <div\n ref={scrollerRef}\n tabIndex={-1}\n {...{ [SCROLLER_ATTR]: '' }}\n data-snap={snap ? 'true' : 'false'}\n className={SCROLLER_CLASS}\n >\n <CardStripSlotContext.Provider value={SCROLLED_SLOT}>\n {cards}\n </CardStripSlotContext.Provider>\n </div>\n {showLeftArrow ? (\n <ArrowButton side=\"left\" onClick={() => scrollByStep(-1)} />\n ) : null}\n {showRightArrow ? (\n <ArrowButton side=\"right\" onClick={() => scrollByStep(1)} />\n ) : null}\n {fadeLeft || fadeRight ? (\n <div\n aria-hidden\n data-card-strip-fade=\"\"\n className={`${FADE_CLASS} absolute pointer-events-none`}\n style={{\n inset: `-${TROUGH_SHOULDER_PX}px -${CARD_FLARE_PX}px 0`,\n background: `linear-gradient(to right, ${fadeLeft ? FADE_COLOR : 'transparent'} 0, transparent ${FADE_RAMP_PX}px, transparent calc(100% - ${FADE_RAMP_PX}px), ${fadeRight ? FADE_COLOR : 'transparent'} 100%)`,\n }}\n />\n ) : null}\n </div>\n ) : null}\n </div>\n {addTiles.length > 0 ? (\n <div\n className=\"shrink-0\"\n style={!hasCards && leading ? EMPTY_ADD_SLOT_STYLE : undefined}\n >\n {addTiles}\n </div>\n ) : null}\n </div>\n );\n};\n\nCardStrip.AddTile = AddTile;\n\nexport default CardStrip;\nexport { CardStrip };\n"],"names":["NAV_KEYS","RADIO_SELECTOR","SCROLLER_ATTR","TROUGH_ATTR","ROOT_CLASS","SCROLLER_CLASS","FADE_CLASS","ADD_TILE_CLASS","ACTIONS_SELECTOR","FOCUSABLE_SELECTOR","PREV_TABINDEX_ATTR","EDGE_EPSILON_PX","SCROLL_STEP_RATIO","scrollStepFor","scroller","first","second","pitch","visible","CARD_FLARE_PX","FADE_WIDTH_PX","ARROW_SIZE_PX","ARROW_GLYPH_PX","GUTTER_REST_PX","GUTTER_OPEN_PX","ARROW_OFFSET_PX","LIP_SHADOW","ARROW_BACKGROUND","ARROW_BORDER","TROUGH_BACKGROUND","CARD_CORNER","CARD_RADIUS","TROUGH_CORNER","TROUGH_RADIUS","TROUGH_SHOULDER_PX","FADE_RAMP_PX","SLOT_WIDTH_PX","CARD_WIDTH_PX","DIVIDER_COLOR","FADE_COLOR","ADD_HOVER_BACKGROUND","ADD_PILL_BORDER","ADD_PILL_BORDER_ACTIVE","ADD_PILL_SHADOW_DEEP","ADD_PILL_BACKGROUND","ADD_PILL_FOREGROUND","ADD_PILL_PRIMARY_BACKGROUND","ADD_PILL_PRIMARY_FOREGROUND","ADD_PILL_PRIMARY_SHADOW","BOTTOM_RULE_WEIGHT_PX","STRIP_RULE_PX","OVERFLOW_INSET_PX","CLIP_SLACK_PX","FOCUS_RING_REACH_PX","SCROLLER_CSS","STYLE_ID","prefersReducedMotion","radioValue","radio","isRadioDisabled","actionsFor","card","radioForClick","target","root","direct","node","radios","actionControls","actions","suppressTabStop","element","restoreTabStop","previous","TONE_RULE","RULE_ROW_STYLE","RULE_GAP_OVERLAP_PX","FLARE_TIP_INSET_PX","CARD_FLARE_TIP_PX","flareTips","flare","FLARE_CLASS","left","right","paintRule","tone","colour","rootRect","rootLeft","clip","cardRect","tips","tipLeft","tipRight","from","to","BLEED_STYLE","CONTENT_INSET","TROUGH_SURFACE","TROUGH_STYLE","TROUGH_GUTTER_STYLES","start","end","ADD_TILE_SHAPE_STYLE","PINNED_SLOT_STYLE","EMPTY_ADD_SLOT_STYLE","ADD_PILL_FILL","AddTile","label","icon","onClick","disabled","emphasis","className","jsx","jsxs","FOCUS_RING","PlusIcon","isAddTile","React","hidesAddTile","child","ArrowButton","side","ArrowLeftIcon","ForwardArrowIcon","CardStrip","value","onChange","children","leading","arrows","fadeEdges","snap","bleed","scrollSelectedIntoView","ariaLabel","ariaLabelledBy","style","rootRef","useRef","scrollerRef","edges","setEdges","useState","useAdoptedStyleSheet","childList","cards","wrappedAddTile","hasCards","addTiles","tile","childCount","getRadios","useCallback","getNavigableRadios","warned","warnOnce","key","message","derivedTone","setDerivedTone","useLayoutEffect","selectedCard","_b","_a","navigable","tabStop","holdsTabStop","nextTabIndex","control","values","current","selectionSettled","checked","selected","viewRect","visibleFrom","visibleTo","ruleTone","callerPaintsBackground","measure","scrollWidth","clientWidth","scrollLeft","overflows","next","onScroll","observer","scrollByStep","direction","handleKeyDown","event","enabled","currentPosition","nextPosition","delta","nextValue","handleClick","clicked","showLeftArrow","showRightArrow","fadeLeft","fadeRight","troughStyle","CardStripSlotContext","PINNED_SLOT","SCROLLED_SLOT"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CardStrip.js","sources":["../../src/components/CardStrip.tsx"],"sourcesContent":["import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport ArrowLeftIcon from './CustomIcons/ArrowLeftIcon';\nimport ForwardArrowIcon from './CustomIcons/ForwardArrowIcon';\nimport PlusIcon from './CustomIcons/PlusIcon';\nimport { CONTENT_INSET } from './PageLayout/constants';\nimport {\n CARD_FLARE_PX,\n CARD_FLARE_TIP_PX,\n CARD_WIDTH_PX,\n FLARE_CLASS,\n STRIP_RULE_PX,\n} from './SelectableCard';\nimport { CardStripSlotContext, PINNED_SLOT, SCROLLED_SLOT } from './cardStripSlot';\nimport { FOCUS_RING } from './focusRing';\nimport { useAdoptedStyleSheet } from './useAdoptedStyleSheet';\n\nexport type CardStripAddTileEmphasis = 'primary' | 'secondary';\n\nexport interface CardStripAddTileProps {\n /** Visible label, e.g. \"Add Profile\". Also names the button for assistive tech. */\n label: string;\n /** Defaults to a plus. */\n icon?: React.ReactNode;\n onClick: () => void;\n disabled?: boolean;\n /** Leave unset: CardStrip picks `primary` while the strip is empty and `secondary` once cards exist. */\n emphasis?: CardStripAddTileEmphasis;\n className?: string;\n}\n\n/** Palette for the strip's rule. Pass the tone of whatever card is selected. */\nexport type CardStripTone = 'profile' | 'library' | 'editing';\n\nexport interface CardStripProps {\n /** The selected card's value, matched against each radio child's `data-value`. */\n value: string;\n /** Overrides the palette the strip reads off the selected card. See `CardStripTone`. */\n tone?: CardStripTone;\n onChange: (value: string) => void;\n /** Cards. Any element with `role=\"radio\"` and a `data-value` joins the group; an\n * add tile must be a direct child or it scrolls with the cards. */\n children: React.ReactNode;\n /** Pinned, non-scrolling slot before the cards (the Library card in the profile picker). */\n leading?: React.ReactNode;\n /** Circular scroll affordances, shown only on an edge that can actually scroll. */\n arrows?: boolean;\n /** Fade the cards out at any edge they scroll past. */\n fadeEdges?: boolean;\n /** Snap cards to the leading edge as the strip scrolls. */\n snap?: boolean;\n /** Run the bottom rule the full width of the page card while the cards stay on the gutter.\n * Only has an effect inside a layout that publishes its inset (`PageLayout`). */\n bleed?: boolean;\n /** Whether a selection change scrolls the selected card into view. The strip's opening\n * selection is placed instantly; later ones slide, unless motion is reduced. Set `false`\n * when the value comes from a URL, or a deep-linked strip below the fold jumps the page\n * on load. */\n scrollSelectedIntoView?: boolean;\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n className?: string;\n style?: React.CSSProperties;\n}\n\n/** Arrow keys move AND select, per the WAI-ARIA radiogroup pattern. */\nconst NAV_KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End']);\n\nconst RADIO_SELECTOR = '[role=\"radio\"]';\nconst SCROLLER_ATTR = 'data-card-strip-scroller';\nconst TROUGH_ATTR = 'data-card-strip-trough';\nconst ROOT_CLASS = 'malachite-card-strip';\nconst SCROLLER_CLASS = 'malachite-card-strip-scroller';\nconst FADE_CLASS = 'malachite-card-strip-fade';\nconst ADD_TILE_CLASS = 'malachite-card-strip-add-tile';\n\nconst ACTIONS_SELECTOR = '[data-selectable-card-actions]';\nconst FOCUSABLE_SELECTOR =\n 'a[href], area[href], button, input, select, textarea, iframe, [contenteditable=\"true\"], [tabindex]';\nconst PREV_TABINDEX_ATTR = 'data-card-strip-prev-tabindex';\n\nconst EDGE_EPSILON_PX = 1;\nconst SCROLL_STEP_RATIO = 0.8;\n\nconst scrollStepFor = (scroller: HTMLElement): number => {\n const [first, second] = Array.from(scroller.children);\n const pitch =\n first && second\n ? second.getBoundingClientRect().left - first.getBoundingClientRect().left\n : (first?.getBoundingClientRect().width ?? 0);\n // `clientWidth` counts the flare padding, which is not width a card can be read in.\n const visible = scroller.clientWidth - CARD_FLARE_PX * 2;\n\n if (pitch <= 0) {\n return visible * SCROLL_STEP_RATIO;\n }\n\n return Math.max(1, Math.floor(visible / pitch)) * pitch;\n};\nconst FADE_WIDTH_PX = 80;\n\nconst ARROW_SIZE_PX = 20;\nconst ARROW_GLYPH_PX = 11;\nconst GUTTER_REST_PX = 12;\nconst GUTTER_OPEN_PX = 52;\nconst ARROW_OFFSET_PX = (GUTTER_OPEN_PX + ARROW_SIZE_PX) / 2;\n\nconst LIP_SHADOW = 'var(--malachite-shadow-default)';\nconst ARROW_BACKGROUND =\n 'var(--malachite-card-strip-arrow-background, var(--malachite-card-background, #ffffff))';\nconst ARROW_BORDER = 'var(--malachite-card-strip-arrow-border, #e8e8e8)';\nconst TROUGH_BACKGROUND = 'var(--malachite-card-strip-background, #f1f1f1)';\nconst CARD_CORNER = 'var(--malachite-radius-xxl, 14px)';\nconst CARD_RADIUS = `${CARD_CORNER} ${CARD_CORNER} 0 0`;\nconst TROUGH_CORNER = 'var(--malachite-radius-xxxl, 16px)';\nconst TROUGH_RADIUS = `${TROUGH_CORNER} ${TROUGH_CORNER} 0 0`;\nconst TROUGH_SHOULDER_PX = 4;\nconst FADE_RAMP_PX = FADE_WIDTH_PX + (CARD_FLARE_PX - TROUGH_SHOULDER_PX);\nconst SLOT_WIDTH_PX = CARD_WIDTH_PX;\nconst DIVIDER_COLOR = 'var(--malachite-card-strip-divider, #dddddd)';\nconst FADE_COLOR = 'var(--malachite-card-strip-fade, transparent)';\nconst ADD_HOVER_BACKGROUND = 'var(--malachite-selectable-card-hover-background, #e8e8e8)';\nconst ADD_PILL_BORDER = 'var(--malachite-card-strip-arrow-border, #e8e8e8)';\nconst ADD_PILL_BORDER_ACTIVE = 'var(--malachite-selectable-card-hover-rule, #bbbbbb)';\nconst ADD_PILL_SHADOW_DEEP = '0px 1px 0px 0px rgba(0, 0, 0, 0.4)';\nconst ADD_PILL_BACKGROUND = 'var(--malachite-card-background, #ffffff)';\nconst ADD_PILL_FOREGROUND = 'var(--malachite-text-primary, #0a0a0a)';\nconst ADD_PILL_PRIMARY_BACKGROUND =\n 'var(--malachite-card-strip-add-primary-background, var(--malachite-text-primary, #0a0a0a))';\nconst ADD_PILL_PRIMARY_FOREGROUND =\n 'var(--malachite-card-strip-add-primary-foreground, var(--malachite-card-background, #ffffff))';\nconst ADD_PILL_PRIMARY_SHADOW = '0px 1px 0px 0px rgba(10, 10, 10, 0.7)';\n\nconst BOTTOM_RULE_WEIGHT_PX = STRIP_RULE_PX;\n\nconst OVERFLOW_INSET_PX = 16;\n\nconst CLIP_SLACK_PX = 9999;\nconst FOCUS_RING_REACH_PX = 4;\n\n/** A sheet, not inline styles: these rules have to reach children this component does not render. */\nconst SCROLLER_CSS = `\n.${ROOT_CLASS} {\n clip-path: inset(-${CLIP_SLACK_PX}px -${CLIP_SLACK_PX}px 0);\n}\n.${ROOT_CLASS}:has(:focus-visible) {\n clip-path: inset(-${CLIP_SLACK_PX}px -${CLIP_SLACK_PX}px -${FOCUS_RING_REACH_PX}px);\n}\n.${SCROLLER_CLASS} {\n display: flex;\n flex-wrap: nowrap;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scrollbar-width: none;\n -ms-overflow-style: none;\n padding-block: ${OVERFLOW_INSET_PX}px;\n margin-block: -${OVERFLOW_INSET_PX}px;\n /* overflow-x clips both axes, so the end cards would lose a flare; the negative margin trades\n the padding back out and scroll-padding keeps the rest position at zero. */\n padding-inline: ${CARD_FLARE_PX}px;\n margin-inline: -${CARD_FLARE_PX}px;\n scroll-padding-inline: ${CARD_FLARE_PX}px;\n}\n/* A card focused at a faded edge has to stay readable, so the fade lifts entirely. */\n.${ROOT_CLASS}:has(:focus-visible) .${FADE_CLASS} {\n display: none;\n}\n.${SCROLLER_CLASS}::-webkit-scrollbar {\n display: none;\n}\n/* No bottom edge: the strip's rule is the baseline for the add tile as much as for a card. */\n.${ADD_TILE_CLASS} > * {\n background: ${TROUGH_BACKGROUND};\n border-radius: ${CARD_RADIUS};\n}\n.${ADD_TILE_CLASS}:hover:not(:has(button:disabled)) > * {\n background: ${ADD_HOVER_BACKGROUND};\n}\n.${ADD_TILE_CLASS} button:active:not(:disabled) {\n opacity: 0.8;\n}\n.${ADD_TILE_CLASS}:has(button:active) > * {\n background: ${TROUGH_BACKGROUND};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary'] button {\n border-color: ${ADD_PILL_BORDER};\n box-shadow: ${LIP_SHADOW};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary']:hover:not(:has(button:disabled)) button {\n border-color: ${ADD_PILL_BORDER_ACTIVE};\n box-shadow: ${ADD_PILL_SHADOW_DEEP};\n}\n.${ADD_TILE_CLASS}[data-emphasis='secondary'] button:active:not(:disabled) {\n border-color: ${ADD_PILL_BORDER_ACTIVE};\n box-shadow: ${ADD_PILL_SHADOW_DEEP};\n}\n.${ADD_TILE_CLASS}[data-emphasis='primary'] button {\n border-color: transparent;\n box-shadow: ${ADD_PILL_PRIMARY_SHADOW};\n}\n.${SCROLLER_CLASS} > * {\n flex: 0 0 auto;\n min-width: 0;\n}\n.${SCROLLER_CLASS} > * + * {\n border-left: 1px solid ${DIVIDER_COLOR};\n}\n.${SCROLLER_CLASS}[data-snap='true'] {\n scroll-snap-type: x proximity;\n}\n.${SCROLLER_CLASS}[data-snap='true'] > * {\n scroll-snap-align: start;\n}\n@media (prefers-reduced-motion: reduce) {\n .${SCROLLER_CLASS} {\n scroll-behavior: auto;\n }\n .${SCROLLER_CLASS}[data-snap='true'] {\n scroll-snap-type: none;\n }\n .${SCROLLER_CLASS}[data-snap='true'] > * {\n scroll-snap-align: none;\n }\n}`;\n\nconst STYLE_ID = 'malachite-card-strip-style';\n\n/** `window.matchMedia` is absent under SSR and in older test environments. */\nconst prefersReducedMotion = (): boolean => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return true;\n }\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n};\n\nconst radioValue = (radio: HTMLElement): string | null =>\n radio.dataset.value ?? radio.getAttribute('value');\n\nconst isRadioDisabled = (radio: HTMLElement): boolean =>\n radio.hasAttribute('disabled') || radio.getAttribute('aria-disabled') === 'true';\n\nconst actionsFor = (radio: HTMLElement): HTMLElement | null => {\n const card = radio.parentElement;\n if (!card || card.querySelectorAll(RADIO_SELECTOR).length !== 1) {\n return null;\n }\n return card.querySelector<HTMLElement>(ACTIONS_SELECTOR);\n};\n\n/** A card is wider than its radio, so `closest` misses clicks on the count row. */\nconst radioForClick = (target: Element, root: Element): HTMLElement | null => {\n const direct = target.closest<HTMLElement>(RADIO_SELECTOR);\n if (direct) {\n return direct;\n }\n if (target.closest(ACTIONS_SELECTOR)) {\n return null;\n }\n let node: Element | null = target;\n while (node && root.contains(node)) {\n const radios: NodeListOf<HTMLElement> = node.querySelectorAll(RADIO_SELECTOR);\n if (radios.length === 1 && radios[0].parentElement === node) {\n return radios[0];\n }\n node = node.parentElement;\n }\n return null;\n};\n\nconst actionControls = (radio: HTMLElement): HTMLElement[] => {\n const actions = actionsFor(radio);\n return actions ? Array.from(actions.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)) : [];\n};\n\nconst suppressTabStop = (element: HTMLElement): void => {\n if (!element.hasAttribute(PREV_TABINDEX_ATTR)) {\n element.setAttribute(PREV_TABINDEX_ATTR, element.getAttribute('tabindex') ?? '');\n }\n element.setAttribute('tabindex', '-1');\n};\n\nconst restoreTabStop = (element: HTMLElement): void => {\n if (!element.hasAttribute(PREV_TABINDEX_ATTR)) {\n return;\n }\n const previous = element.getAttribute(PREV_TABINDEX_ATTR);\n element.removeAttribute(PREV_TABINDEX_ATTR);\n if (previous) {\n element.setAttribute('tabindex', previous);\n } else {\n element.removeAttribute('tabindex');\n }\n};\n\nconst TONE_RULE: Record<CardStripTone, string> = {\n profile: 'var(--malachite-selectable-card-selected-border, #047b43)',\n library: 'var(--malachite-selectable-card-library-selected-border, #bbbbbb)',\n editing: 'var(--malachite-selectable-card-pending-foreground, #96580a)',\n};\nconst RULE_ROW_STYLE: React.CSSProperties = {\n backgroundRepeat: 'no-repeat',\n backgroundPosition: 'left bottom',\n backgroundSize: `100% ${BOTTOM_RULE_WEIGHT_PX}px`,\n};\n\n/** The rule runs under the flare's tip rather than butting against it, so antialiasing\n * cannot open the junction into a gap. */\nconst RULE_GAP_OVERLAP_PX = 0.5;\n\nconst FLARE_TIP_INSET_PX = CARD_FLARE_PX - CARD_FLARE_TIP_PX;\n\nconst flareTips = (card: HTMLElement): { left: number; right: number } | null => {\n const flare = card.querySelector(`:scope > .${FLARE_CLASS}`);\n if (!flare) {\n return null;\n }\n const { left, right } = flare.getBoundingClientRect();\n return { left: left + FLARE_TIP_INSET_PX, right: right - FLARE_TIP_INSET_PX };\n};\n\n/** The rule is cut where the selected card stands, never covered: the strip's clip lands on the\n * rule's own edge, so a cover takes the same partial alpha and the rule bleeds through it. */\nconst paintRule = (\n root: HTMLElement | null,\n scroller: HTMLElement | null,\n card: HTMLElement | null | undefined,\n tone: CardStripTone,\n): void => {\n if (!root) {\n return;\n }\n const colour = TONE_RULE[tone];\n const rootRect = root.getBoundingClientRect();\n const rootLeft = rootRect.left;\n const clip = card && scroller?.contains(card) ? scroller.getBoundingClientRect() : rootRect;\n const cardRect = card?.getBoundingClientRect();\n const tips = card ? flareTips(card) : null;\n const tipLeft = tips?.left ?? (cardRect ? cardRect.left - CARD_FLARE_TIP_PX : 0);\n const tipRight = tips?.right ?? (cardRect ? cardRect.right + CARD_FLARE_TIP_PX : 0);\n const from = cardRect ? Math.max(tipLeft, clip.left) + RULE_GAP_OVERLAP_PX - rootLeft : 0;\n const to = cardRect ? Math.min(tipRight, clip.right) - RULE_GAP_OVERLAP_PX - rootLeft : 0;\n\n root.style.backgroundImage =\n to > from\n ? `linear-gradient(to right, ${colour} 0 ${from}px, transparent ${from}px ${to}px, ${colour} ${to}px 100%)`\n : `linear-gradient(to right, ${colour} 0 100%)`;\n};\n\nconst BLEED_STYLE: React.CSSProperties = {\n marginInline: `calc(${CONTENT_INSET} * -1)`,\n paddingInline: CONTENT_INSET,\n};\n\n/** The rule's row is a margin, never padding: a background paints under its own padding, which\n * would hide the very line the troughs stand on. */\nconst TROUGH_SURFACE: React.CSSProperties = {\n background: TROUGH_BACKGROUND,\n borderRadius: TROUGH_RADIUS,\n paddingTop: `${TROUGH_SHOULDER_PX}px`,\n paddingInline: `${TROUGH_SHOULDER_PX}px`,\n marginBottom: `${BOTTOM_RULE_WEIGHT_PX}px`,\n};\nconst TROUGH_STYLE: React.CSSProperties = {\n ...TROUGH_SURFACE,\n marginInline: `${GUTTER_REST_PX}px`,\n};\nconst TROUGH_GUTTER_STYLES: Record<string, React.CSSProperties> = Object.fromEntries(\n [GUTTER_REST_PX, GUTTER_OPEN_PX].flatMap((start) =>\n [GUTTER_REST_PX, GUTTER_OPEN_PX].map((end) => [\n `${start}:${end}`,\n { ...TROUGH_SURFACE, marginInline: `${start}px ${end}px` },\n ]),\n ),\n);\nconst ADD_TILE_SHAPE_STYLE: React.CSSProperties = TROUGH_SURFACE;\n\nconst PINNED_SLOT_STYLE: React.CSSProperties = TROUGH_SURFACE;\n\nconst EMPTY_ADD_SLOT_STYLE: React.CSSProperties = {\n marginInlineStart: `${GUTTER_REST_PX}px`,\n};\n\nconst ADD_PILL_FILL: Record<CardStripAddTileEmphasis, React.CSSProperties> = {\n primary: {\n backgroundColor: ADD_PILL_PRIMARY_BACKGROUND,\n color: ADD_PILL_PRIMARY_FOREGROUND,\n },\n secondary: { backgroundColor: ADD_PILL_BACKGROUND, color: ADD_PILL_FOREGROUND },\n};\n\nconst AddTile: React.FC<CardStripAddTileProps> = ({\n label,\n icon,\n onClick,\n disabled = false,\n emphasis = 'secondary',\n className = '',\n}) => (\n <div\n className={ADD_TILE_CLASS}\n data-emphasis={emphasis}\n style={{\n ...ADD_TILE_SHAPE_STYLE,\n width: `${SLOT_WIDTH_PX}px`,\n height: `calc(100% - ${BOTTOM_RULE_WEIGHT_PX}px)`,\n }}\n >\n <div className=\"flex h-full items-center justify-center px-4\">\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n style={ADD_PILL_FILL[emphasis]}\n className={`${FOCUS_RING} inline-flex items-center justify-center gap-1.5 h-[var(--malachite-control-height-medium,32px)] w-[108px] px-2.5 rounded-xl border border-solid text-[length:var(--malachite-font-size-small,13px)] font-medium whitespace-nowrap ${\n disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'\n } ${className}`}\n >\n <span className=\"inline-flex h-[13px] w-[13px] shrink-0 items-center justify-center\">\n {icon ?? <PlusIcon size={13} />}\n </span>\n {label}\n </button>\n </div>\n </div>\n);\n\nconst isAddTile = (node: React.ReactNode): node is React.ReactElement<CardStripAddTileProps> =>\n React.isValidElement(node) && node.type === AddTile;\n\nconst hidesAddTile = (child: React.ReactNode): boolean =>\n React.isValidElement<{ children?: React.ReactNode }>(child) &&\n child.type === React.Fragment &&\n React.Children.toArray(child.props.children).some(isAddTile);\n\ninterface ArrowButtonProps {\n side: 'left' | 'right';\n onClick: () => void;\n}\n\nconst ArrowButton: React.FC<ArrowButtonProps> = ({ side, onClick }) => (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-hidden=\"true\"\n aria-label={side === 'left' ? 'Scroll left' : 'Scroll right'}\n onClick={onClick}\n className=\"absolute top-1/2 -translate-y-1/2 z-10 inline-flex items-center justify-center w-5 h-5 rounded-lg cursor-pointer text-[var(--malachite-text-secondary)]\"\n style={{\n [side]: `-${ARROW_OFFSET_PX}px`,\n background: ARROW_BACKGROUND,\n border: `1px solid ${ARROW_BORDER}`,\n boxShadow: LIP_SHADOW,\n }}\n >\n {side === 'left' ? (\n <ArrowLeftIcon size={ARROW_GLYPH_PX} />\n ) : (\n <ForwardArrowIcon size={ARROW_GLYPH_PX} />\n )}\n </button>\n);\n\n/** A horizontally scrolling radiogroup of cards — the \"pick one of these\" strip. */\nconst CardStrip: React.FC<CardStripProps> & { AddTile: React.FC<CardStripAddTileProps> } = ({\n value,\n tone,\n onChange,\n children,\n leading,\n arrows = true,\n fadeEdges = true,\n snap = true,\n bleed = false,\n scrollSelectedIntoView = true,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className = '',\n style,\n}) => {\n const rootRef = useRef<HTMLDivElement>(null);\n const scrollerRef = useRef<HTMLDivElement>(null);\n const hasPositioned = useRef(false);\n const [edges, setEdges] = useState({ canScrollLeft: false, canScrollRight: false });\n\n useAdoptedStyleSheet(rootRef, SCROLLER_CSS, STYLE_ID);\n\n const childList = React.Children.toArray(children);\n const cards = childList.filter((child) => !isAddTile(child));\n const wrappedAddTile = cards.some(hidesAddTile);\n const hasCards = cards.length > 0;\n\n const addTiles = childList\n .filter(isAddTile)\n .map((tile) =>\n tile.props.emphasis === undefined\n ? React.cloneElement(tile, { emphasis: hasCards ? 'secondary' : 'primary' })\n : tile,\n );\n\n const childCount = childList.length;\n\n const getRadios = useCallback((): HTMLElement[] => {\n const root = rootRef.current;\n if (!root) {\n return [];\n }\n return Array.from(root.querySelectorAll<HTMLElement>(RADIO_SELECTOR));\n }, []);\n\n const getNavigableRadios = useCallback(\n (): HTMLElement[] => getRadios().filter((radio) => radioValue(radio) !== null),\n [getRadios],\n );\n\n const warned = useRef(new Set<string>());\n const warnOnce = useCallback((key: string, message: string): void => {\n if (warned.current.has(key)) {\n return;\n }\n warned.current.add(key);\n console.warn(message);\n }, []);\n\n const [derivedTone, setDerivedTone] = useState<CardStripTone>('profile');\n\n useLayoutEffect(() => {\n const selectedCard = getRadios()\n .find((radio) => radioValue(radio) === value)\n ?.parentElement?.getAttribute('data-variant');\n if (\n selectedCard === 'profile' ||\n selectedCard === 'library' ||\n selectedCard === 'editing'\n ) {\n setDerivedTone(selectedCard);\n }\n }, [getRadios, value]);\n\n useLayoutEffect(() => {\n const radios = getRadios();\n const navigable = getNavigableRadios();\n const selected = navigable.find((radio) => radioValue(radio) === value);\n const tabStop = selected ?? navigable.find((radio) => !isRadioDisabled(radio)) ?? null;\n\n radios.forEach((radio) => {\n const holdsTabStop = radio === tabStop;\n const nextTabIndex = holdsTabStop ? 0 : -1;\n if (radio.tabIndex !== nextTabIndex) {\n radio.tabIndex = nextTabIndex;\n }\n for (const control of actionControls(radio)) {\n if (holdsTabStop) {\n restoreTabStop(control);\n } else {\n suppressTabStop(control);\n }\n }\n });\n\n if (process.env.NODE_ENV === 'production') {\n return;\n }\n\n if (navigable.length !== radios.length) {\n warnOnce(\n 'missing-value',\n 'CardStrip: a child with role=\"radio\" has no `data-value`. It cannot be selected or reached by arrow keys, so it is excluded from the radio set. Give every card a `data-value`.',\n );\n }\n\n const values = new Set<string>();\n for (const radio of navigable) {\n const current = radioValue(radio);\n if (current === null) {\n continue;\n }\n if (values.has(current)) {\n warnOnce(\n `duplicate:${current}`,\n `CardStrip: two cards share the data-value \"${current}\". Both will read as checked and only the first is selectable — data-value must be unique.`,\n );\n }\n values.add(current);\n }\n\n const selectionSettled = value !== '';\n\n if (radios.length > 0 && selectionSettled && !values.has(value)) {\n warnOnce(\n `unmatched:${value}`,\n `CardStrip: value \"${value}\" matches no card's data-value, so the group reports no selection.`,\n );\n }\n\n const checked = radios.filter(\n (radio) => radio.getAttribute('aria-checked') === 'true',\n ).length;\n if (radios.length > 0 && selectionSettled && checked !== 1) {\n warnOnce(\n `checked:${checked}`,\n `CardStrip: ${checked} cards are aria-checked, but a radiogroup has exactly one. Drive each card's checked state from the strip's \\`value\\`.`,\n );\n }\n\n if (wrappedAddTile) {\n warnOnce(\n 'wrapped-add-tile',\n 'CardStrip: a CardStrip.AddTile inside a fragment is treated as a card and scrolls with them. The add tile must be a direct child of CardStrip.',\n );\n }\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: cards arriving is the signal\n useLayoutEffect(() => {\n if (!scrollSelectedIntoView) {\n return;\n }\n const scroller = scrollerRef.current;\n const selected = getRadios().find((radio) => radioValue(radio) === value);\n // jsdom implements neither, and a strip that cannot scroll has nothing to bring into view.\n if (!scroller || !selected || typeof scroller.scrollTo !== 'function') {\n return;\n }\n\n // Positioned rather than asked for: the track is scroll-snapped, and `scrollIntoView`\n // on a card several widths away lands back on the nearest snap point instead — so a\n // card appended past the end never came into view at all.\n // Measured against the scroller rather than an offset parent: the cards are flex\n // children whose `offsetParent` is not the scroller, so `offsetLeft` is not its frame.\n const card = (selected.closest('[role=\"radio\"]') ?? selected) as HTMLElement;\n const cardRect = card.getBoundingClientRect();\n const viewRect = scroller.getBoundingClientRect();\n const left = scroller.scrollLeft + (cardRect.left - viewRect.left);\n const right = left + cardRect.width;\n const visibleFrom = scroller.scrollLeft + CARD_FLARE_PX;\n const visibleTo = scroller.scrollLeft + scroller.clientWidth - CARD_FLARE_PX;\n\n // The first placement is where the strip opens — a deep link, not a move — so it is\n // instant. Every later one is the selection travelling, and travel is legible only if\n // you can see it happen.\n const wasPositioned = hasPositioned.current;\n hasPositioned.current = true;\n\n if (left >= visibleFrom && right <= visibleTo) {\n return;\n }\n\n scroller.scrollTo({\n left:\n right > visibleTo\n ? right - scroller.clientWidth + CARD_FLARE_PX\n : left - CARD_FLARE_PX,\n behavior: wasPositioned && !prefersReducedMotion() ? 'smooth' : 'instant',\n });\n }, [getRadios, scrollSelectedIntoView, value, childCount]);\n\n const ruleTone = tone ?? derivedTone;\n const callerPaintsBackground =\n style?.background !== undefined || style?.backgroundImage !== undefined;\n\n const measure = useCallback(() => {\n const scroller = scrollerRef.current;\n if (!callerPaintsBackground) {\n paintRule(\n rootRef.current,\n scroller,\n getRadios().find((radio) => radioValue(radio) === value)?.parentElement,\n ruleTone,\n );\n }\n if (!scroller) {\n return;\n }\n const { scrollWidth, clientWidth, scrollLeft } = scroller;\n const overflows = scrollWidth > clientWidth + EDGE_EPSILON_PX;\n const next = {\n canScrollLeft: overflows && scrollLeft > EDGE_EPSILON_PX,\n canScrollRight: overflows && scrollLeft + clientWidth < scrollWidth - EDGE_EPSILON_PX,\n };\n setEdges((previous) =>\n previous.canScrollLeft === next.canScrollLeft &&\n previous.canScrollRight === next.canScrollRight\n ? previous\n : next,\n );\n }, [callerPaintsBackground, getRadios, ruleTone, value]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: adding or removing a card changes the scroll width, so re-measure on the count\n useLayoutEffect(() => {\n measure();\n\n const scroller = scrollerRef.current;\n if (!scroller) {\n return;\n }\n\n const onScroll = (): void => measure();\n scroller.addEventListener('scroll', onScroll, { passive: true });\n\n const observer =\n typeof ResizeObserver !== 'undefined' ? new ResizeObserver(() => measure()) : null;\n observer?.observe(scroller);\n\n return () => {\n scroller.removeEventListener('scroll', onScroll);\n observer?.disconnect();\n };\n }, [measure, childCount]);\n\n const scrollByStep = useCallback((direction: -1 | 1) => {\n const scroller = scrollerRef.current;\n if (!scroller || typeof scroller.scrollBy !== 'function') {\n return;\n }\n scroller.scrollBy({\n left: direction * scrollStepFor(scroller),\n behavior: prefersReducedMotion() ? 'auto' : 'smooth',\n });\n }, []);\n\n const handleKeyDown = useCallback(\n (event: React.KeyboardEvent) => {\n if (!NAV_KEYS.has(event.key)) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof Element) || !target.closest(RADIO_SELECTOR)) {\n return;\n }\n\n const enabled = getNavigableRadios().filter((radio) => !isRadioDisabled(radio));\n if (enabled.length === 0) {\n return;\n }\n\n event.preventDefault();\n\n const currentPosition = enabled.findIndex((radio) => radioValue(radio) === value);\n let nextPosition: number;\n if (event.key === 'Home') {\n nextPosition = 0;\n } else if (event.key === 'End') {\n nextPosition = enabled.length - 1;\n } else {\n const delta = event.key === 'ArrowLeft' || event.key === 'ArrowUp' ? -1 : 1;\n const from = currentPosition === -1 ? 0 : currentPosition;\n nextPosition = (from + delta + enabled.length) % enabled.length;\n }\n\n const next = enabled[nextPosition];\n const nextValue = radioValue(next);\n if (nextValue !== null && nextValue !== value) {\n onChange(nextValue);\n }\n next.focus();\n },\n [getNavigableRadios, onChange, value],\n );\n\n const handleClick = useCallback(\n (event: React.MouseEvent) => {\n const target = event.target;\n if (!(target instanceof Element)) {\n return;\n }\n const root = rootRef.current;\n if (!root) {\n return;\n }\n const radio = radioForClick(target, root);\n if (!radio || isRadioDisabled(radio)) {\n return;\n }\n const clicked = radioValue(radio);\n if (clicked !== null && clicked !== value) {\n onChange(clicked);\n }\n },\n [onChange, value],\n );\n\n const showLeftArrow = arrows && edges.canScrollLeft;\n const showRightArrow = arrows && edges.canScrollRight;\n\n const fadeLeft = fadeEdges && edges.canScrollLeft;\n const fadeRight = fadeEdges && edges.canScrollRight;\n const troughStyle = arrows\n ? TROUGH_GUTTER_STYLES[\n `${showLeftArrow ? GUTTER_OPEN_PX : GUTTER_REST_PX}:${\n showRightArrow ? GUTTER_OPEN_PX : GUTTER_REST_PX\n }`\n ]\n : TROUGH_STYLE;\n\n return (\n <div\n ref={rootRef}\n onKeyDown={handleKeyDown}\n onClick={handleClick}\n className={`${ROOT_CLASS} flex items-stretch ${className}`}\n style={{\n ...RULE_ROW_STYLE,\n ...(bleed ? BLEED_STYLE : null),\n ...style,\n }}\n >\n <div\n role=\"radiogroup\"\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n className={hasCards ? 'flex items-stretch min-w-0' : 'flex items-stretch'}\n >\n {leading ? (\n <CardStripSlotContext.Provider value={PINNED_SLOT}>\n <div className=\"shrink-0\" style={PINNED_SLOT_STYLE}>\n {leading}\n </div>\n </CardStripSlotContext.Provider>\n ) : null}\n {hasCards ? (\n <div\n {...{ [TROUGH_ATTR]: '' }}\n className=\"relative min-w-0 shrink basis-auto\"\n style={troughStyle}\n >\n <div\n ref={scrollerRef}\n tabIndex={-1}\n {...{ [SCROLLER_ATTR]: '' }}\n data-snap={snap ? 'true' : 'false'}\n className={SCROLLER_CLASS}\n >\n <CardStripSlotContext.Provider value={SCROLLED_SLOT}>\n {cards}\n </CardStripSlotContext.Provider>\n </div>\n {showLeftArrow ? (\n <ArrowButton side=\"left\" onClick={() => scrollByStep(-1)} />\n ) : null}\n {showRightArrow ? (\n <ArrowButton side=\"right\" onClick={() => scrollByStep(1)} />\n ) : null}\n {fadeLeft || fadeRight ? (\n <div\n aria-hidden\n data-card-strip-fade=\"\"\n className={`${FADE_CLASS} absolute pointer-events-none`}\n style={{\n inset: `-${TROUGH_SHOULDER_PX}px -${CARD_FLARE_PX}px 0`,\n background: `linear-gradient(to right, ${fadeLeft ? FADE_COLOR : 'transparent'} 0, transparent ${FADE_RAMP_PX}px, transparent calc(100% - ${FADE_RAMP_PX}px), ${fadeRight ? FADE_COLOR : 'transparent'} 100%)`,\n }}\n />\n ) : null}\n </div>\n ) : null}\n </div>\n {addTiles.length > 0 ? (\n <div\n className=\"shrink-0\"\n style={!hasCards && leading ? EMPTY_ADD_SLOT_STYLE : undefined}\n >\n {addTiles}\n </div>\n ) : null}\n </div>\n );\n};\n\nCardStrip.AddTile = AddTile;\n\nexport default CardStrip;\nexport { CardStrip };\n"],"names":["NAV_KEYS","RADIO_SELECTOR","SCROLLER_ATTR","TROUGH_ATTR","ROOT_CLASS","SCROLLER_CLASS","FADE_CLASS","ADD_TILE_CLASS","ACTIONS_SELECTOR","FOCUSABLE_SELECTOR","PREV_TABINDEX_ATTR","EDGE_EPSILON_PX","SCROLL_STEP_RATIO","scrollStepFor","scroller","first","second","pitch","visible","CARD_FLARE_PX","FADE_WIDTH_PX","ARROW_SIZE_PX","ARROW_GLYPH_PX","GUTTER_REST_PX","GUTTER_OPEN_PX","ARROW_OFFSET_PX","LIP_SHADOW","ARROW_BACKGROUND","ARROW_BORDER","TROUGH_BACKGROUND","CARD_CORNER","CARD_RADIUS","TROUGH_CORNER","TROUGH_RADIUS","TROUGH_SHOULDER_PX","FADE_RAMP_PX","SLOT_WIDTH_PX","CARD_WIDTH_PX","DIVIDER_COLOR","FADE_COLOR","ADD_HOVER_BACKGROUND","ADD_PILL_BORDER","ADD_PILL_BORDER_ACTIVE","ADD_PILL_SHADOW_DEEP","ADD_PILL_BACKGROUND","ADD_PILL_FOREGROUND","ADD_PILL_PRIMARY_BACKGROUND","ADD_PILL_PRIMARY_FOREGROUND","ADD_PILL_PRIMARY_SHADOW","BOTTOM_RULE_WEIGHT_PX","STRIP_RULE_PX","OVERFLOW_INSET_PX","CLIP_SLACK_PX","FOCUS_RING_REACH_PX","SCROLLER_CSS","STYLE_ID","prefersReducedMotion","radioValue","radio","isRadioDisabled","actionsFor","card","radioForClick","target","root","direct","node","radios","actionControls","actions","suppressTabStop","element","restoreTabStop","previous","TONE_RULE","RULE_ROW_STYLE","RULE_GAP_OVERLAP_PX","FLARE_TIP_INSET_PX","CARD_FLARE_TIP_PX","flareTips","flare","FLARE_CLASS","left","right","paintRule","tone","colour","rootRect","rootLeft","clip","cardRect","tips","tipLeft","tipRight","from","to","BLEED_STYLE","CONTENT_INSET","TROUGH_SURFACE","TROUGH_STYLE","TROUGH_GUTTER_STYLES","start","end","ADD_TILE_SHAPE_STYLE","PINNED_SLOT_STYLE","EMPTY_ADD_SLOT_STYLE","ADD_PILL_FILL","AddTile","label","icon","onClick","disabled","emphasis","className","jsx","jsxs","FOCUS_RING","PlusIcon","isAddTile","React","hidesAddTile","child","ArrowButton","side","ArrowLeftIcon","ForwardArrowIcon","CardStrip","value","onChange","children","leading","arrows","fadeEdges","snap","bleed","scrollSelectedIntoView","ariaLabel","ariaLabelledBy","style","rootRef","useRef","scrollerRef","hasPositioned","edges","setEdges","useState","useAdoptedStyleSheet","childList","cards","wrappedAddTile","hasCards","addTiles","tile","childCount","getRadios","useCallback","getNavigableRadios","warned","warnOnce","key","message","derivedTone","setDerivedTone","useLayoutEffect","selectedCard","_b","_a","navigable","tabStop","holdsTabStop","nextTabIndex","control","values","current","selectionSettled","checked","selected","viewRect","visibleFrom","visibleTo","wasPositioned","ruleTone","callerPaintsBackground","measure","scrollWidth","clientWidth","scrollLeft","overflows","next","onScroll","observer","scrollByStep","direction","handleKeyDown","event","enabled","currentPosition","nextPosition","delta","nextValue","handleClick","clicked","showLeftArrow","showRightArrow","fadeLeft","fadeRight","troughStyle","CardStripSlotContext","PINNED_SLOT","SCROLLED_SLOT"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -420,8 +420,10 @@ export declare interface CardStripProps {
|
|
|
420
420
|
/** Run the bottom rule the full width of the page card while the cards stay on the gutter.
|
|
421
421
|
* Only has an effect inside a layout that publishes its inset (`PageLayout`). */
|
|
422
422
|
bleed?: boolean;
|
|
423
|
-
/** Whether a selection change scrolls the selected card into view.
|
|
424
|
-
*
|
|
423
|
+
/** Whether a selection change scrolls the selected card into view. The strip's opening
|
|
424
|
+
* selection is placed instantly; later ones slide, unless motion is reduced. Set `false`
|
|
425
|
+
* when the value comes from a URL, or a deep-linked strip below the fold jumps the page
|
|
426
|
+
* on load. */
|
|
425
427
|
scrollSelectedIntoView?: boolean;
|
|
426
428
|
'aria-label'?: string;
|
|
427
429
|
'aria-labelledby'?: string;
|
package/package.json
CHANGED