@tetrascience-npm/tetrascience-react-ui 0.5.0-beta.60.1 → 0.5.0-beta.61.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.
Files changed (71) hide show
  1. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +2 -0
  2. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +1 -0
  3. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +140 -0
  4. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +1 -0
  5. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs +2 -0
  6. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs.map +1 -0
  7. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js +126 -0
  8. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js.map +1 -0
  9. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs +2 -0
  10. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs.map +1 -0
  11. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js +422 -0
  12. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js.map +1 -0
  13. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs +2 -0
  14. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs.map +1 -0
  15. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js +136 -0
  16. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js.map +1 -0
  17. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +2 -0
  18. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +1 -0
  19. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +389 -0
  20. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +1 -0
  21. package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs +2 -0
  22. package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs.map +1 -0
  23. package/dist/components/composed/PlateMapEditor/PlateZoomControl.js +54 -0
  24. package/dist/components/composed/PlateMapEditor/PlateZoomControl.js.map +1 -0
  25. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs +2 -0
  26. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs.map +1 -0
  27. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js +96 -0
  28. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js.map +1 -0
  29. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +2 -0
  30. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -0
  31. package/dist/components/composed/PlateMapEditor/WellLegend.js +58 -0
  32. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -0
  33. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +2 -0
  34. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +1 -0
  35. package/dist/components/composed/PlateMapEditor/WellManifestTable.js +421 -0
  36. package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +1 -0
  37. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs +2 -0
  38. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs.map +1 -0
  39. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js +177 -0
  40. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js.map +1 -0
  41. package/dist/components/composed/PlateMapEditor/autoFill.cjs +2 -0
  42. package/dist/components/composed/PlateMapEditor/autoFill.cjs.map +1 -0
  43. package/dist/components/composed/PlateMapEditor/autoFill.js +41 -0
  44. package/dist/components/composed/PlateMapEditor/autoFill.js.map +1 -0
  45. package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs +4 -0
  46. package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs.map +1 -0
  47. package/dist/components/composed/PlateMapEditor/csvPlateTriage.js +103 -0
  48. package/dist/components/composed/PlateMapEditor/csvPlateTriage.js.map +1 -0
  49. package/dist/components/composed/PlateMapEditor/helpers.cjs +2 -0
  50. package/dist/components/composed/PlateMapEditor/helpers.cjs.map +1 -0
  51. package/dist/components/composed/PlateMapEditor/helpers.js +11 -0
  52. package/dist/components/composed/PlateMapEditor/helpers.js.map +1 -0
  53. package/dist/components/composed/PlateMapEditor/wellGrid.cjs +2 -0
  54. package/dist/components/composed/PlateMapEditor/wellGrid.cjs.map +1 -0
  55. package/dist/components/composed/PlateMapEditor/wellGrid.js +56 -0
  56. package/dist/components/composed/PlateMapEditor/wellGrid.js.map +1 -0
  57. package/dist/components/ui/data-table/data-table.cjs +1 -1
  58. package/dist/components/ui/data-table/data-table.cjs.map +1 -1
  59. package/dist/components/ui/data-table/data-table.js +1 -0
  60. package/dist/components/ui/data-table/data-table.js.map +1 -1
  61. package/dist/components/ui/popover.cjs +2 -0
  62. package/dist/components/ui/popover.cjs.map +1 -0
  63. package/dist/components/ui/popover.js +45 -0
  64. package/dist/components/ui/popover.js.map +1 -0
  65. package/dist/index.cjs +1 -1
  66. package/dist/index.css +1 -1
  67. package/dist/index.d.ts +555 -0
  68. package/dist/index.js +637 -595
  69. package/dist/index.js.map +1 -1
  70. package/dist/index.tailwind.css +1 -1
  71. package/package.json +1 -1
@@ -0,0 +1,421 @@
1
+ import { jsxs as i, jsx as t } from "react/jsx-runtime";
2
+ import { Layers as _e, Check as ee, ChevronRight as ze, ChevronDown as Me, ArrowDownToLine as Te } from "lucide-react";
3
+ import * as h from "react";
4
+ import { ManifestFilterPopover as Ae } from "./ManifestFilterPopover.js";
5
+ import { Badge as ne } from "../../ui/badge.js";
6
+ import { Button as F } from "../../ui/button.js";
7
+ import { Checkbox as te } from "../../ui/checkbox.js";
8
+ import { useComboboxAnchor as Fe, Combobox as Pe, ComboboxChips as Re, ComboboxValue as Ie, ComboboxChip as De, ComboboxChipsInput as Ge, ComboboxContent as Le, ComboboxEmpty as Be, ComboboxList as Ve, ComboboxItem as We } from "../../ui/combobox.js";
9
+ import { applyFilterCondition as $e } from "../../ui/data-table/data-table.js";
10
+ import { Input as He } from "../../ui/input.js";
11
+ import { Select as B, SelectTrigger as V, SelectValue as W, SelectContent as $, SelectItem as P } from "../../ui/select.js";
12
+ import { Switch as je } from "../../ui/switch.js";
13
+ import { Table as Ze, TableHeader as Ue, TableRow as R, TableHead as H, TableBody as Ke, TableCell as M } from "../../ui/table.js";
14
+ import { TooltipProvider as Oe, Tooltip as Ye, TooltipTrigger as qe, TooltipContent as Je } from "../../ui/tooltip.js";
15
+ import { cn as I } from "../../../lib/utils.js";
16
+ function Qe({
17
+ ariaLabel: d,
18
+ value: o,
19
+ options: u,
20
+ placeholder: c,
21
+ onChange: p
22
+ }) {
23
+ const b = Fe(), g = h.useMemo(() => {
24
+ const m = /* @__PURE__ */ new Map();
25
+ return u.forEach((x) => m.set(x.value, x.label)), m;
26
+ }, [u]);
27
+ return /* @__PURE__ */ i(Pe, { multiple: !0, items: u.map((m) => m.value), value: o, onValueChange: p, children: [
28
+ /* @__PURE__ */ i(Re, { ref: b, className: I("min-h-7 w-full py-0.5", j), children: [
29
+ /* @__PURE__ */ t(Ie, { children: (m) => m.map((x) => /* @__PURE__ */ t(De, { children: g.get(x) ?? x }, x)) }),
30
+ /* @__PURE__ */ t(Ge, { "aria-label": d, placeholder: c ?? "Select…" })
31
+ ] }),
32
+ /* @__PURE__ */ i(Le, { anchor: b, children: [
33
+ /* @__PURE__ */ t(Be, { children: "No options." }),
34
+ /* @__PURE__ */ t(Ve, { children: (m) => /* @__PURE__ */ t(We, { value: m, children: g.get(m) ?? m }, m) })
35
+ ] })
36
+ ] });
37
+ }
38
+ const j = "border-transparent shadow-none hover:border-input/40", le = 25, Xe = 50, en = 100, nn = le, tn = [le, Xe, en];
39
+ function re(d) {
40
+ return d != null && d !== "";
41
+ }
42
+ const rn = {
43
+ number: "number",
44
+ integer: "number",
45
+ date: "date",
46
+ datetime: "datetime-local",
47
+ time: "time"
48
+ };
49
+ function ln(d) {
50
+ return rn[d] ?? "text";
51
+ }
52
+ function an(d, o) {
53
+ if (o !== "") {
54
+ if (d === "number") {
55
+ const u = parseFloat(o);
56
+ return Number.isFinite(u) ? u : o;
57
+ }
58
+ if (d === "integer") {
59
+ const u = parseInt(o, 10);
60
+ return Number.isFinite(u) ? u : o;
61
+ }
62
+ return o;
63
+ }
64
+ }
65
+ function sn(d, o) {
66
+ const u = /* @__PURE__ */ new Map();
67
+ for (const c of d) {
68
+ const p = c.row[o], b = p == null || p === "" ? "(blank)" : String(p), g = u.get(b);
69
+ g ? g.rows.push(c) : u.set(b, { key: b, rows: [c] });
70
+ }
71
+ return [...u.values()];
72
+ }
73
+ function on(d) {
74
+ return d.filter((o) => !!o.field).map((o) => ({ columnId: o.field, label: o.header }));
75
+ }
76
+ function Sn({
77
+ values: d,
78
+ columns: o,
79
+ fields: u,
80
+ selection: c,
81
+ onSelectionChange: p,
82
+ onChange: b,
83
+ emptyEntry: g,
84
+ isPopulated: m,
85
+ pageSize: x = nn,
86
+ pageSizeOptions: ae = tn,
87
+ enableFillDown: Z = !0,
88
+ rowProps: se,
89
+ filterable: D = !1,
90
+ filterColumns: U,
91
+ groupable: G = !1,
92
+ className: ie
93
+ }) {
94
+ const [T, oe] = h.useState(!1), [w, k] = h.useState(0), [C, de] = h.useState(x), [E, ce] = h.useState([]), [A, ue] = h.useState(""), [he, me] = h.useState(/* @__PURE__ */ new Set());
95
+ h.useEffect(() => {
96
+ k(0);
97
+ }, [T]);
98
+ const K = h.useMemo(() => {
99
+ const e = /* @__PURE__ */ new Map();
100
+ return (u ?? []).forEach((n) => e.set(n.key, n)), e;
101
+ }, [u]), fe = h.useMemo(
102
+ () => U ?? on(o),
103
+ [o, U]
104
+ ), v = h.useMemo(() => {
105
+ const e = [...d.entries()].map(([r, l]) => ({
106
+ id: r,
107
+ row: l
108
+ }));
109
+ let n = e;
110
+ if (!T && m && (n = e.filter((r) => m(r.row))), D && E.length > 0 && (n = n.filter((r) => {
111
+ const l = r.row;
112
+ return E.every((a) => {
113
+ const s = l[a.columnId], f = s == null ? "" : String(s);
114
+ return $e(f, a.operator, a.value);
115
+ });
116
+ })), c && c.size > 0) {
117
+ const r = new Set(n.map((l) => l.id));
118
+ c.forEach((l) => {
119
+ !r.has(l) && !d.has(l) && (n = [...n, { id: l, row: g(l) }]);
120
+ });
121
+ }
122
+ return n.sort((r, l) => r.id.localeCompare(l.id));
123
+ }, [d, T, m, c, g, D, E]);
124
+ h.useEffect(() => {
125
+ k(0);
126
+ }, [E]);
127
+ const L = h.useMemo(
128
+ () => v.slice(w * C, w * C + C),
129
+ [v, w, C]
130
+ ), S = (e, n) => {
131
+ const r = new Map(d), l = r.get(e) ?? g(e);
132
+ r.set(e, { ...l, ...n }), b(r);
133
+ }, pe = (e) => {
134
+ if (!p) return;
135
+ const n = new Set(c ?? []);
136
+ n.has(e) ? n.delete(e) : n.add(e), p(n);
137
+ }, O = (e) => {
138
+ if (!e.field) return null;
139
+ const n = !!c && c.size > 0, l = n ? v.filter(({ id: N }) => c.has(N)) : G && !!A ? v : L, a = l.findIndex(({ row: N }) => re(N[e.field]));
140
+ if (a < 0) return null;
141
+ const s = l[a], f = n ? l.filter(({ id: N }) => N !== s.id) : l.slice(a + 1);
142
+ return {
143
+ field: e.field,
144
+ source: s,
145
+ targets: f,
146
+ value: s.row[e.field]
147
+ };
148
+ }, ge = (e) => {
149
+ const n = O(e);
150
+ if (!n || n.targets.length === 0) return;
151
+ const r = new Map(d);
152
+ n.targets.forEach(({ id: l }) => {
153
+ const a = r.get(l) ?? g(l);
154
+ r.set(l, { ...a, [n.field]: n.value });
155
+ }), b(r);
156
+ }, be = (e, n, r, l, a) => /* @__PURE__ */ i(
157
+ B,
158
+ {
159
+ value: r ?? "",
160
+ onValueChange: (s) => S(l, { [n]: s }),
161
+ children: [
162
+ /* @__PURE__ */ t(V, { size: "sm", className: I("h-7 w-full", j), "aria-label": a, children: /* @__PURE__ */ t(W, { placeholder: e.placeholder ?? "Select…" }) }),
163
+ /* @__PURE__ */ t($, { children: (e.options ?? []).map((s) => /* @__PURE__ */ t(P, { value: s.value, children: /* @__PURE__ */ i("span", { className: "inline-flex items-center gap-2", children: [
164
+ s.swatch ? /* @__PURE__ */ t(
165
+ "span",
166
+ {
167
+ className: "inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",
168
+ style: { backgroundColor: s.swatch },
169
+ "aria-hidden": !0
170
+ }
171
+ ) : null,
172
+ s.label
173
+ ] }) }, s.value)) })
174
+ ]
175
+ }
176
+ ), xe = (e, n, r, l, a) => {
177
+ const s = !!r;
178
+ return e.boolStyle === "switch" ? /* @__PURE__ */ t(
179
+ je,
180
+ {
181
+ "aria-label": a,
182
+ checked: s,
183
+ onCheckedChange: (f) => S(l, { [n]: f })
184
+ }
185
+ ) : /* @__PURE__ */ t(
186
+ te,
187
+ {
188
+ "aria-label": a,
189
+ checked: s,
190
+ onCheckedChange: (f) => S(l, { [n]: f === !0 })
191
+ }
192
+ );
193
+ }, Ce = (e, n, r, l, a) => /* @__PURE__ */ t(
194
+ He,
195
+ {
196
+ type: ln(e.kind),
197
+ step: e.kind === "integer" ? 1 : void 0,
198
+ placeholder: e.placeholder,
199
+ "aria-label": a,
200
+ className: I("h-7", j),
201
+ value: r ?? "",
202
+ onChange: (s) => S(l, { [n]: an(e.kind, s.target.value) })
203
+ }
204
+ ), we = (e, n, r, l) => {
205
+ const a = n.field, s = l[a], f = `${e.label} for ${r}`;
206
+ if (e.kind === "select") return be(e, a, s, r, f);
207
+ if (e.kind === "multiselect") {
208
+ const N = Array.isArray(s) ? s : [];
209
+ return /* @__PURE__ */ t(
210
+ Qe,
211
+ {
212
+ ariaLabel: f,
213
+ value: N,
214
+ options: e.options ?? [],
215
+ placeholder: e.placeholder,
216
+ onChange: (X) => S(r, { [a]: X.length === 0 ? void 0 : X })
217
+ }
218
+ );
219
+ }
220
+ return e.kind === "boolean" ? xe(e, a, s, r, f) : Ce(e, a, s, r, f);
221
+ }, ve = (e, n) => {
222
+ if (e?.kind === "select") {
223
+ const r = (e.options ?? []).find((l) => l.value === n);
224
+ return r ? /* @__PURE__ */ i(ne, { variant: "secondary", children: [
225
+ r.swatch ? /* @__PURE__ */ t(
226
+ "span",
227
+ {
228
+ className: "size-2 rounded-sm border border-foreground/20",
229
+ style: { backgroundColor: r.swatch },
230
+ "aria-hidden": !0
231
+ }
232
+ ) : null,
233
+ r.label
234
+ ] }) : /* @__PURE__ */ t("span", { className: "text-muted-foreground", children: "—" });
235
+ }
236
+ if (e?.kind === "multiselect") {
237
+ const r = Array.isArray(n) ? n : [];
238
+ return r.length === 0 ? /* @__PURE__ */ t("span", { className: "text-muted-foreground", children: "—" }) : /* @__PURE__ */ t("div", { className: "flex flex-wrap gap-1", children: r.map((l) => {
239
+ const a = (e.options ?? []).find((s) => s.value === l);
240
+ return /* @__PURE__ */ i(ne, { variant: "secondary", children: [
241
+ a?.swatch ? /* @__PURE__ */ t(
242
+ "span",
243
+ {
244
+ className: "size-2 rounded-sm border border-foreground/20",
245
+ style: { backgroundColor: a.swatch },
246
+ "aria-hidden": !0
247
+ }
248
+ ) : null,
249
+ a?.label ?? l
250
+ ] }, l);
251
+ }) });
252
+ }
253
+ return e?.kind === "boolean" ? n ? /* @__PURE__ */ t(ee, { "aria-label": "Yes", className: "size-4 text-foreground" }) : /* @__PURE__ */ t("span", { className: "text-muted-foreground", children: "—" }) : re(n) ? String(n) : /* @__PURE__ */ t("span", { className: "text-muted-foreground", children: "—" });
254
+ }, Ne = (e, n, r) => {
255
+ if (e.render)
256
+ return e.render({
257
+ row: r,
258
+ wellId: n,
259
+ update: (s) => S(n, s)
260
+ });
261
+ if (!e.field) return null;
262
+ const l = K.get(e.field), a = r[e.field];
263
+ return l?.editableInTable && l.kind !== "custom" ? we(l, e, n, r) : ve(l, a);
264
+ }, Se = (e) => {
265
+ const n = e.field ? K.get(e.field) : void 0, r = e.icon ?? n?.icon, l = Z ? O(e) : null, a = !!l && l.targets.length > 0, s = c && c.size > 0 ? `Fill selected ${e.header} cells from the first selected value` : `Fill visible ${e.header} cells downward from the first value`;
266
+ return /* @__PURE__ */ i("span", { className: "flex min-w-0 items-center justify-between gap-2", children: [
267
+ /* @__PURE__ */ i("span", { className: "inline-flex min-w-0 items-center gap-1.5", children: [
268
+ r ? /* @__PURE__ */ t("span", { className: "inline-flex text-muted-foreground [&_svg]:size-3.5", children: r }) : null,
269
+ /* @__PURE__ */ t("span", { className: "truncate", children: e.header })
270
+ ] }),
271
+ Z && e.field ? /* @__PURE__ */ i(Ye, { children: [
272
+ /* @__PURE__ */ t(qe, { asChild: !0, children: /* @__PURE__ */ t(
273
+ F,
274
+ {
275
+ type: "button",
276
+ variant: "ghost",
277
+ size: "icon-xs",
278
+ className: "-mr-1 text-muted-foreground hover:text-foreground",
279
+ disabled: !a,
280
+ "aria-label": `Fill down ${e.header}`,
281
+ onClick: (f) => {
282
+ f.preventDefault(), f.stopPropagation(), ge(e);
283
+ },
284
+ children: /* @__PURE__ */ t(Te, {})
285
+ }
286
+ ) }),
287
+ /* @__PURE__ */ t(Je, { children: s })
288
+ ] }) : null
289
+ ] });
290
+ }, ye = h.useMemo(() => o.filter((e) => !!e.field), [o]), y = G && A ? A : "", _ = h.useMemo(
291
+ () => y ? sn(v, y) : null,
292
+ [y, v]
293
+ ), z = v.length, Y = Math.max(0, Math.ceil(z / C) - 1), ke = c?.size ?? 0, q = o.length + 1 + (p ? 1 : 0), J = (e, n) => {
294
+ const r = c?.has(e), l = se?.({ wellId: e, row: n, isSelected: !!r });
295
+ return /* @__PURE__ */ i(R, { ...l, children: [
296
+ p ? /* @__PURE__ */ t(M, { className: "w-10", children: /* @__PURE__ */ t(te, { checked: !!r, onCheckedChange: () => pe(e), "aria-label": `Select ${e}` }) }) : null,
297
+ /* @__PURE__ */ t(M, { className: "font-semibold", children: e }),
298
+ o.map((a) => /* @__PURE__ */ t(
299
+ M,
300
+ {
301
+ style: a.minWidth ? { minWidth: a.minWidth } : void 0,
302
+ children: Ne(a, e, n)
303
+ },
304
+ a.id ?? a.field ?? a.header
305
+ ))
306
+ ] }, e);
307
+ }, Q = (e) => {
308
+ me((n) => {
309
+ const r = new Set(n);
310
+ return r.has(e) ? r.delete(e) : r.add(e), r;
311
+ });
312
+ }, Ee = y ? o.find((n) => n.field === y)?.header ?? y : "";
313
+ return /* @__PURE__ */ i("div", { "data-slot": "well-manifest-table", className: I("flex flex-col gap-2", ie), children: [
314
+ /* @__PURE__ */ i("div", { className: "flex flex-wrap items-center gap-2", children: [
315
+ /* @__PURE__ */ t(F, { variant: "outline", size: "sm", onClick: () => oe((e) => !e), children: T ? "Hide empty wells" : "Show all wells" }),
316
+ D ? /* @__PURE__ */ t(Ae, { columns: fe, filters: E, onFiltersChange: ce }) : null,
317
+ G ? /* @__PURE__ */ i("div", { className: "inline-flex items-center gap-1.5", children: [
318
+ /* @__PURE__ */ t(_e, { "aria-hidden": !0, className: "size-3.5 text-muted-foreground" }),
319
+ /* @__PURE__ */ i(B, { value: A || "__none", onValueChange: (e) => ue(e === "__none" ? "" : e), children: [
320
+ /* @__PURE__ */ t(V, { size: "sm", className: "h-7 min-w-40", "aria-label": "Group by", children: /* @__PURE__ */ t(W, { placeholder: "Group by…" }) }),
321
+ /* @__PURE__ */ i($, { children: [
322
+ /* @__PURE__ */ t(P, { value: "__none", children: "No grouping" }),
323
+ ye.map((e) => /* @__PURE__ */ t(P, { value: e.field ?? "", children: e.header }, e.id ?? e.field))
324
+ ] })
325
+ ] })
326
+ ] }) : null,
327
+ /* @__PURE__ */ i("span", { className: "text-xs text-muted-foreground", children: [
328
+ z,
329
+ " rows · ",
330
+ ke,
331
+ " selected"
332
+ ] })
333
+ ] }),
334
+ /* @__PURE__ */ t(Oe, { children: /* @__PURE__ */ i(Ze, { "data-density": "default", children: [
335
+ /* @__PURE__ */ t(Ue, { children: /* @__PURE__ */ i(R, { children: [
336
+ p ? /* @__PURE__ */ t(H, { className: "w-10 text-center", children: /* @__PURE__ */ i("span", { className: "inline-flex items-center justify-center text-muted-foreground [&_svg]:size-3.5", children: [
337
+ /* @__PURE__ */ t(ee, { "aria-hidden": !0 }),
338
+ /* @__PURE__ */ t("span", { className: "sr-only", children: "Selected" })
339
+ ] }) }) : null,
340
+ /* @__PURE__ */ t(H, { style: { minWidth: 60 }, children: "Well" }),
341
+ o.map((e) => /* @__PURE__ */ t(
342
+ H,
343
+ {
344
+ style: e.minWidth ? { minWidth: e.minWidth } : void 0,
345
+ children: Se(e)
346
+ },
347
+ e.id ?? e.field ?? e.header
348
+ ))
349
+ ] }) }),
350
+ /* @__PURE__ */ i(Ke, { children: [
351
+ _ ? _.map((e) => {
352
+ const n = he.has(e.key);
353
+ return /* @__PURE__ */ i(h.Fragment, { children: [
354
+ /* @__PURE__ */ t(
355
+ R,
356
+ {
357
+ className: "cursor-pointer bg-muted/40",
358
+ onClick: () => Q(e.key),
359
+ onKeyDown: (r) => {
360
+ (r.key === "Enter" || r.key === " ") && (r.preventDefault(), Q(e.key));
361
+ },
362
+ role: "button",
363
+ tabIndex: 0,
364
+ "aria-expanded": !n,
365
+ children: /* @__PURE__ */ t(M, { colSpan: q, className: "py-1.5", children: /* @__PURE__ */ i("div", { className: "flex items-center gap-2 text-xs font-medium", children: [
366
+ n ? /* @__PURE__ */ t(ze, { "aria-hidden": !0, className: "size-3.5 text-muted-foreground" }) : /* @__PURE__ */ t(Me, { "aria-hidden": !0, className: "size-3.5 text-muted-foreground" }),
367
+ /* @__PURE__ */ i("span", { children: [
368
+ Ee,
369
+ ": ",
370
+ e.key
371
+ ] }),
372
+ /* @__PURE__ */ i("span", { className: "text-muted-foreground", children: [
373
+ "(",
374
+ e.rows.length,
375
+ " ",
376
+ e.rows.length === 1 ? "row" : "rows",
377
+ ")"
378
+ ] })
379
+ ] }) })
380
+ }
381
+ ),
382
+ n ? null : e.rows.map(({ id: r, row: l }) => J(r, l))
383
+ ] }, e.key);
384
+ }) : L.map(({ id: e, row: n }) => J(e, n)),
385
+ (_ ? _.length === 0 : L.length === 0) ? /* @__PURE__ */ t(R, { children: /* @__PURE__ */ t(M, { colSpan: q, className: "text-xs text-muted-foreground", children: "No rows. Paint wells on the plate." }) }) : null
386
+ ] })
387
+ ] }) }),
388
+ _ ? null : /* @__PURE__ */ i("div", { className: "flex items-center justify-end gap-3 text-xs text-muted-foreground", children: [
389
+ /* @__PURE__ */ t("span", { className: "text-muted-foreground", children: "Rows per page" }),
390
+ /* @__PURE__ */ i(
391
+ B,
392
+ {
393
+ value: String(C),
394
+ onValueChange: (e) => {
395
+ de(parseInt(e, 10)), k(0);
396
+ },
397
+ children: [
398
+ /* @__PURE__ */ t(V, { size: "sm", className: "h-7 w-18", "aria-label": "Rows per page", children: /* @__PURE__ */ t(W, {}) }),
399
+ /* @__PURE__ */ t($, { children: ae.map((e) => /* @__PURE__ */ t(P, { value: String(e), children: e }, e)) })
400
+ ]
401
+ }
402
+ ),
403
+ /* @__PURE__ */ t("span", { children: z === 0 ? "0 of 0" : `${w * C + 1}–${Math.min((w + 1) * C, z)} of ${z}` }),
404
+ /* @__PURE__ */ t(F, { variant: "outline", size: "sm", disabled: w === 0, onClick: () => k((e) => Math.max(0, e - 1)), children: "Prev" }),
405
+ /* @__PURE__ */ t(
406
+ F,
407
+ {
408
+ variant: "outline",
409
+ size: "sm",
410
+ disabled: w >= Y,
411
+ onClick: () => k((e) => Math.min(Y, e + 1)),
412
+ children: "Next"
413
+ }
414
+ )
415
+ ] })
416
+ ] });
417
+ }
418
+ export {
419
+ Sn as WellManifestTable
420
+ };
421
+ //# sourceMappingURL=WellManifestTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WellManifestTable.js","sources":["../../../../src/components/composed/PlateMapEditor/WellManifestTable.tsx"],"sourcesContent":["import { ArrowDownToLine, Check, ChevronDown, ChevronRight, Layers } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { ManifestFilterPopover } from \"./ManifestFilterPopover\";\n\nimport type { WellColumn, WellField, WellId, WellRecord, WellSelectOption } from \"./types\";\nimport type { FilterColumnConfig, FilterCondition } from \"@/components/ui/data-table/data-table\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { applyFilterCondition } from \"@/components/ui/data-table/data-table\";\nimport { Input } from \"@/components/ui/input\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"@/components/ui/table\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectCell({\n ariaLabel,\n value,\n options,\n placeholder,\n onChange,\n}: {\n ariaLabel: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className={cn(\"min-h-7 w-full py-0.5\", CELL_EDITOR_CLASS)}>\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput aria-label={ariaLabel} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n {labelByValue.get(item) ?? item}\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\n/**\n * Cell editors render borderless by default so the table reads flat. The\n * underlying primitives keep their `focus-visible` / `focus-within` rings, so\n * an outline only appears while the user is actively editing the cell.\n */\nconst CELL_EDITOR_CLASS = \"border-transparent shadow-none hover:border-input/40\";\n\nconst PAGE_SIZE_SMALL = 25;\nconst PAGE_SIZE_MEDIUM = 50;\nconst PAGE_SIZE_LARGE = 100;\nconst DEFAULT_PAGE_SIZE = PAGE_SIZE_SMALL;\nconst DEFAULT_PAGE_SIZE_OPTIONS: number[] = [PAGE_SIZE_SMALL, PAGE_SIZE_MEDIUM, PAGE_SIZE_LARGE];\n\nfunction hasFillValue(value: unknown): boolean {\n return value !== undefined && value !== null && value !== \"\";\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport interface WellManifestTableRowContext<T extends WellRecord = WellRecord> {\n wellId: WellId;\n row: T;\n isSelected: boolean;\n}\n\nexport interface WellManifestTableProps<T extends WellRecord = WellRecord> {\n values: Map<WellId, T>;\n columns: WellColumn<T>[];\n /**\n * Field schema. If a column has `field` matching a `select`-kind field, a\n * Select cell renders automatically with that field's options.\n */\n fields?: WellField<T>[];\n selection?: Set<WellId>;\n onSelectionChange?: (next: Set<WellId>) => void;\n onChange: (next: Map<WellId, T>) => void;\n /** Builds an empty record for a freshly-created row. */\n emptyEntry: (id: WellId) => T;\n /** Filter that controls which empty rows surface. Defaults to `false`. */\n isPopulated?: (row: T) => boolean;\n pageSize?: number;\n pageSizeOptions?: number[];\n /** Adds a column header action that copies the first non-empty value downward. */\n enableFillDown?: boolean;\n /**\n * Extra props spread onto each `<tr>` — typically used to attach a DnD\n * library's `setNodeRef`, listeners, and data attributes so rows can act as\n * drag sources. The kit stays DnD-library-agnostic.\n */\n rowProps?: (ctx: WellManifestTableRowContext<T>) => React.ComponentProps<\"tr\"> | undefined;\n /** Enables an inline filter popover above the table. Defaults to false. */\n filterable?: boolean;\n /**\n * Optional override of filterable column configs. When omitted, every column\n * with a `field` becomes filterable using the default operator set from the\n * shared data-table filter system.\n */\n filterColumns?: FilterColumnConfig[];\n /** Enables an inline group-by selector. Defaults to false. */\n groupable?: boolean;\n className?: string;\n}\n\ninterface GroupedRow<T> {\n key: string;\n rows: Array<{ id: WellId; row: T }>;\n}\n\nfunction groupRowsBy<T extends WellRecord>(rows: Array<{ id: WellId; row: T }>, field: string): GroupedRow<T>[] {\n const map = new Map<string, GroupedRow<T>>();\n for (const entry of rows) {\n const raw = (entry.row as Record<string, unknown>)[field];\n const key = raw === undefined || raw === null || raw === \"\" ? \"(blank)\" : String(raw);\n const existing = map.get(key);\n if (existing) existing.rows.push(entry);\n else map.set(key, { key, rows: [entry] });\n }\n return [...map.values()];\n}\n\nfunction inferFilterColumns<T extends WellRecord>(columns: WellColumn<T>[]): FilterColumnConfig[] {\n return columns.filter((col) => !!col.field).map((col) => ({ columnId: col.field as string, label: col.header }));\n}\n\nexport function WellManifestTable<T extends WellRecord = WellRecord>({\n values,\n columns,\n fields,\n selection,\n onSelectionChange,\n onChange,\n emptyEntry,\n isPopulated,\n pageSize: initialPageSize = DEFAULT_PAGE_SIZE,\n pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,\n enableFillDown = true,\n rowProps,\n filterable = false,\n filterColumns,\n groupable = false,\n className,\n}: WellManifestTableProps<T>) {\n const [showAll, setShowAll] = React.useState(false);\n const [page, setPage] = React.useState(0);\n const [pageSize, setPageSize] = React.useState(initialPageSize);\n const [filters, setFilters] = React.useState<FilterCondition[]>([]);\n const [groupByField, setGroupByField] = React.useState<string>(\"\");\n const [collapsedGroups, setCollapsedGroups] = React.useState<Set<string>>(new Set());\n\n React.useEffect(() => {\n setPage(0);\n }, [showAll]);\n\n const fieldByKey = React.useMemo(() => {\n const m = new Map<string, WellField<T>>();\n (fields ?? []).forEach((f) => m.set(f.key, f));\n return m;\n }, [fields]);\n\n const resolvedFilterColumns = React.useMemo<FilterColumnConfig[]>(\n () => filterColumns ?? inferFilterColumns(columns),\n [columns, filterColumns],\n );\n\n const rows = React.useMemo(() => {\n const arr = [...values.entries()].map(([id, row]) => ({\n id,\n row,\n }));\n let filtered = arr;\n if (!showAll && isPopulated) {\n filtered = arr.filter((r) => isPopulated(r.row));\n }\n if (filterable && filters.length > 0) {\n filtered = filtered.filter((entry) => {\n const record = entry.row as Record<string, unknown>;\n return filters.every((condition) => {\n const cellRaw = record[condition.columnId];\n const cellValue = cellRaw === undefined || cellRaw === null ? \"\" : String(cellRaw);\n return applyFilterCondition(cellValue, condition.operator, condition.value);\n });\n });\n }\n if (selection && selection.size > 0) {\n const have = new Set(filtered.map((r) => r.id));\n selection.forEach((p) => {\n if (!have.has(p) && !values.has(p)) {\n filtered = [...filtered, { id: p, row: emptyEntry(p) }];\n }\n });\n }\n return filtered.sort((a, b) => a.id.localeCompare(b.id));\n }, [values, showAll, isPopulated, selection, emptyEntry, filterable, filters]);\n\n React.useEffect(() => {\n setPage(0);\n }, [filters]);\n\n const pagedRows = React.useMemo(\n () => rows.slice(page * pageSize, page * pageSize + pageSize),\n [rows, page, pageSize],\n );\n\n const updateRow = (wellId: WellId, patch: Partial<T>) => {\n const next = new Map(values);\n const cur = next.get(wellId) ?? emptyEntry(wellId);\n next.set(wellId, { ...cur, ...patch });\n onChange(next);\n };\n\n const toggleSelect = (wellId: WellId) => {\n if (!onSelectionChange) return;\n const s = new Set(selection ?? []);\n if (s.has(wellId)) {\n s.delete(wellId);\n } else {\n s.add(wellId);\n }\n onSelectionChange(s);\n };\n\n const getFillDownPlan = (col: WellColumn<T>) => {\n if (!col.field) return null;\n\n const selectionActive = !!selection && selection.size > 0;\n const groupingActive = groupable && !!groupByField;\n const sourceRows = selectionActive\n ? rows.filter(({ id }) => selection.has(id))\n : groupingActive\n ? rows\n : pagedRows;\n const sourceIndex = sourceRows.findIndex(({ row }) => hasFillValue(row[col.field!]));\n if (sourceIndex < 0) return null;\n\n const source = sourceRows[sourceIndex];\n const targets = selectionActive\n ? sourceRows.filter(({ id }) => id !== source.id)\n : sourceRows.slice(sourceIndex + 1);\n\n return {\n field: col.field,\n source,\n targets,\n value: source.row[col.field],\n };\n };\n\n const fillColumnDown = (col: WellColumn<T>) => {\n const plan = getFillDownPlan(col);\n if (!plan || plan.targets.length === 0) return;\n\n const next = new Map(values);\n plan.targets.forEach(({ id }) => {\n const cur = next.get(id) ?? emptyEntry(id);\n next.set(id, { ...cur, [plan.field]: plan.value } as T);\n });\n onChange(next);\n };\n\n const renderSelectCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Select\n value={(value as string | undefined) ?? \"\"}\n onValueChange={(v) => updateRow(wellId, { [fieldKey]: v } as Partial<T>)}\n >\n <SelectTrigger size=\"sm\" className={cn(\"h-7 w-full\", CELL_EDITOR_CLASS)} aria-label={ariaLabel}>\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n\n const renderBooleanCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => {\n const checked = !!value;\n if (field.boolStyle === \"switch\") {\n return (\n <Switch\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c } as Partial<T>)}\n />\n );\n }\n return (\n <Checkbox\n aria-label={ariaLabel}\n checked={checked}\n onCheckedChange={(c) => updateRow(wellId, { [fieldKey]: c === true } as Partial<T>)}\n />\n );\n };\n\n const renderInputCellEditable = (\n field: WellField<T>,\n fieldKey: keyof T & string,\n value: unknown,\n wellId: WellId,\n ariaLabel: string,\n ) => (\n <Input\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n aria-label={ariaLabel}\n className={cn(\"h-7\", CELL_EDITOR_CLASS)}\n value={(value as string | number | undefined) ?? \"\"}\n onChange={(e) => updateRow(wellId, { [fieldKey]: parseInputValue(field.kind, e.target.value) } as Partial<T>)}\n />\n );\n\n const renderEditableCell = (field: WellField<T>, col: WellColumn<T>, wellId: WellId, row: T) => {\n const fieldKey = col.field!;\n const value = row[fieldKey];\n const ariaLabel = `${field.label} for ${wellId}`;\n\n if (field.kind === \"select\") return renderSelectCellEditable(field, fieldKey, value, wellId, ariaLabel);\n if (field.kind === \"multiselect\") {\n const current = Array.isArray(value) ? (value as string[]) : [];\n return (\n <MultiSelectCell\n ariaLabel={ariaLabel}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => updateRow(wellId, { [fieldKey]: next.length === 0 ? undefined : next } as Partial<T>)}\n />\n );\n }\n if (field.kind === \"boolean\") return renderBooleanCellEditable(field, fieldKey, value, wellId, ariaLabel);\n return renderInputCellEditable(field, fieldKey, value, wellId, ariaLabel);\n };\n\n const renderReadonlyCell = (field: WellField<T> | undefined, value: unknown) => {\n if (field?.kind === \"select\") {\n const option = (field.options ?? []).find((opt) => opt.value === value);\n if (!option) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return (\n <Badge variant=\"secondary\">\n {option.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: option.swatch }}\n aria-hidden\n />\n ) : null}\n {option.label}\n </Badge>\n );\n }\n\n if (field?.kind === \"multiselect\") {\n const arr = Array.isArray(value) ? (value as string[]) : [];\n if (arr.length === 0) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n return (\n <div className=\"flex flex-wrap gap-1\">\n {arr.map((v) => {\n const opt = (field.options ?? []).find((o) => o.value === v);\n return (\n <Badge key={v} variant=\"secondary\">\n {opt?.swatch ? (\n <span\n className=\"size-2 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt?.label ?? v}\n </Badge>\n );\n })}\n </div>\n );\n }\n\n if (field?.kind === \"boolean\") {\n return value ? (\n <Check aria-label=\"Yes\" className=\"size-4 text-foreground\" />\n ) : (\n <span className=\"text-muted-foreground\">—</span>\n );\n }\n\n if (!hasFillValue(value)) {\n return <span className=\"text-muted-foreground\">—</span>;\n }\n\n return String(value);\n };\n\n const renderCell = (col: WellColumn<T>, wellId: WellId, row: T) => {\n if (col.render) {\n return col.render({\n row,\n wellId,\n update: (patch) => updateRow(wellId, patch),\n });\n }\n if (!col.field) return null;\n\n const field = fieldByKey.get(col.field);\n const value = row[col.field];\n\n if (field?.editableInTable && field.kind !== \"custom\") {\n return renderEditableCell(field, col, wellId, row);\n }\n\n return renderReadonlyCell(field, value);\n };\n\n const renderColumnHeader = (col: WellColumn<T>) => {\n const matchingField = col.field ? fieldByKey.get(col.field) : undefined;\n const icon = col.icon ?? matchingField?.icon;\n const fillPlan = enableFillDown ? getFillDownPlan(col) : null;\n const canFillDown = !!fillPlan && fillPlan.targets.length > 0;\n const fillHint =\n selection && selection.size > 0\n ? `Fill selected ${col.header} cells from the first selected value`\n : `Fill visible ${col.header} cells downward from the first value`;\n return (\n <span className=\"flex min-w-0 items-center justify-between gap-2\">\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n {icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{icon}</span> : null}\n <span className=\"truncate\">{col.header}</span>\n </span>\n {enableFillDown && col.field ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n className=\"-mr-1 text-muted-foreground hover:text-foreground\"\n disabled={!canFillDown}\n aria-label={`Fill down ${col.header}`}\n onClick={(e) => {\n e.preventDefault();\n e.stopPropagation();\n fillColumnDown(col);\n }}\n >\n <ArrowDownToLine />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{fillHint}</TooltipContent>\n </Tooltip>\n ) : null}\n </span>\n );\n };\n\n const groupableColumns = React.useMemo(() => columns.filter((col) => !!col.field), [columns]);\n const activeGroupField = groupable && groupByField ? groupByField : \"\";\n const grouped = React.useMemo(\n () => (activeGroupField ? groupRowsBy(rows, activeGroupField) : null),\n [activeGroupField, rows],\n );\n\n const totalRows = rows.length;\n const lastPage = Math.max(0, Math.ceil(totalRows / pageSize) - 1);\n const selSize = selection?.size ?? 0;\n const totalColSpan = columns.length + 1 + (onSelectionChange ? 1 : 0);\n\n const renderDataRow = (id: WellId, row: T) => {\n const isSelected = selection?.has(id);\n const extra = rowProps?.({ wellId: id, row, isSelected: !!isSelected });\n return (\n <TableRow key={id} {...extra}>\n {onSelectionChange ? (\n <TableCell className=\"w-10\">\n <Checkbox checked={!!isSelected} onCheckedChange={() => toggleSelect(id)} aria-label={`Select ${id}`} />\n </TableCell>\n ) : null}\n <TableCell className=\"font-semibold\">{id}</TableCell>\n {columns.map((col) => (\n <TableCell\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderCell(col, id, row)}\n </TableCell>\n ))}\n </TableRow>\n );\n };\n\n const toggleGroup = (key: string) => {\n setCollapsedGroups((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key);\n else next.add(key);\n return next;\n });\n };\n\n const groupHeaderLabel = (() => {\n if (!activeGroupField) return \"\";\n const col = columns.find((c) => c.field === activeGroupField);\n return col?.header ?? activeGroupField;\n })();\n\n return (\n <div data-slot=\"well-manifest-table\" className={cn(\"flex flex-col gap-2\", className)}>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowAll((v) => !v)}>\n {showAll ? \"Hide empty wells\" : \"Show all wells\"}\n </Button>\n {filterable ? (\n <ManifestFilterPopover columns={resolvedFilterColumns} filters={filters} onFiltersChange={setFilters} />\n ) : null}\n {groupable ? (\n <div className=\"inline-flex items-center gap-1.5\">\n <Layers aria-hidden className=\"size-3.5 text-muted-foreground\" />\n <Select value={groupByField || \"__none\"} onValueChange={(v) => setGroupByField(v === \"__none\" ? \"\" : v)}>\n <SelectTrigger size=\"sm\" className=\"h-7 min-w-40\" aria-label=\"Group by\">\n <SelectValue placeholder=\"Group by…\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"__none\">No grouping</SelectItem>\n {groupableColumns.map((col) => (\n <SelectItem key={col.id ?? col.field} value={col.field ?? \"\"}>\n {col.header}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n <span className=\"text-xs text-muted-foreground\">\n {totalRows} rows · {selSize} selected\n </span>\n </div>\n\n <TooltipProvider>\n <Table data-density=\"default\">\n <TableHeader>\n <TableRow>\n {onSelectionChange ? (\n <TableHead className=\"w-10 text-center\">\n <span className=\"inline-flex items-center justify-center text-muted-foreground [&_svg]:size-3.5\">\n <Check aria-hidden />\n <span className=\"sr-only\">Selected</span>\n </span>\n </TableHead>\n ) : null}\n <TableHead style={{ minWidth: 60 }}>Well</TableHead>\n {columns.map((col) => (\n <TableHead\n key={col.id ?? col.field ?? col.header}\n style={col.minWidth ? { minWidth: col.minWidth } : undefined}\n >\n {renderColumnHeader(col)}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {grouped\n ? grouped.map((group) => {\n const isCollapsed = collapsedGroups.has(group.key);\n return (\n <React.Fragment key={group.key}>\n <TableRow\n className=\"cursor-pointer bg-muted/40\"\n onClick={() => toggleGroup(group.key)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n toggleGroup(group.key);\n }\n }}\n role=\"button\"\n tabIndex={0}\n aria-expanded={!isCollapsed}\n >\n <TableCell colSpan={totalColSpan} className=\"py-1.5\">\n <div className=\"flex items-center gap-2 text-xs font-medium\">\n {isCollapsed ? (\n <ChevronRight aria-hidden className=\"size-3.5 text-muted-foreground\" />\n ) : (\n <ChevronDown aria-hidden className=\"size-3.5 text-muted-foreground\" />\n )}\n <span>\n {groupHeaderLabel}: {group.key}\n </span>\n <span className=\"text-muted-foreground\">\n ({group.rows.length} {group.rows.length === 1 ? \"row\" : \"rows\"})\n </span>\n </div>\n </TableCell>\n </TableRow>\n {isCollapsed ? null : group.rows.map(({ id, row }) => renderDataRow(id, row))}\n </React.Fragment>\n );\n })\n : pagedRows.map(({ id, row }) => renderDataRow(id, row))}\n {(grouped ? grouped.length === 0 : pagedRows.length === 0) ? (\n <TableRow>\n <TableCell colSpan={totalColSpan} className=\"text-xs text-muted-foreground\">\n No rows. Paint wells on the plate.\n </TableCell>\n </TableRow>\n ) : null}\n </TableBody>\n </Table>\n </TooltipProvider>\n\n {grouped ? null : (\n <div className=\"flex items-center justify-end gap-3 text-xs text-muted-foreground\">\n <span className=\"text-muted-foreground\">Rows per page</span>\n <Select\n value={String(pageSize)}\n onValueChange={(v) => {\n setPageSize(parseInt(v, 10));\n setPage(0);\n }}\n >\n <SelectTrigger size=\"sm\" className=\"h-7 w-18\" aria-label=\"Rows per page\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {pageSizeOptions.map((s) => (\n <SelectItem key={s} value={String(s)}>\n {s}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <span>\n {totalRows === 0\n ? \"0 of 0\"\n : `${page * pageSize + 1}–${Math.min((page + 1) * pageSize, totalRows)} of ${totalRows}`}\n </span>\n <Button variant=\"outline\" size=\"sm\" disabled={page === 0} onClick={() => setPage((p) => Math.max(0, p - 1))}>\n Prev\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={page >= lastPage}\n onClick={() => setPage((p) => Math.min(lastPage, p + 1))}\n >\n Next\n </Button>\n </div>\n )}\n </div>\n );\n}\n"],"names":["MultiSelectCell","ariaLabel","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","o","jsxs","Combobox","ComboboxChips","cn","CELL_EDITOR_CLASS","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","PAGE_SIZE_SMALL","PAGE_SIZE_MEDIUM","PAGE_SIZE_LARGE","DEFAULT_PAGE_SIZE","DEFAULT_PAGE_SIZE_OPTIONS","hasFillValue","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","groupRowsBy","rows","field","map","entry","key","existing","inferFilterColumns","columns","col","WellManifestTable","values","fields","selection","onSelectionChange","emptyEntry","isPopulated","initialPageSize","pageSizeOptions","enableFillDown","rowProps","filterable","filterColumns","groupable","className","showAll","setShowAll","page","setPage","pageSize","setPageSize","filters","setFilters","groupByField","setGroupByField","collapsedGroups","setCollapsedGroups","fieldByKey","m","f","resolvedFilterColumns","arr","id","row","filtered","record","condition","cellRaw","cellValue","applyFilterCondition","have","r","p","a","b","pagedRows","updateRow","wellId","patch","next","cur","toggleSelect","s","getFillDownPlan","selectionActive","sourceRows","sourceIndex","source","targets","fillColumnDown","plan","renderSelectCellEditable","fieldKey","Select","v","SelectTrigger","SelectValue","SelectContent","opt","SelectItem","renderBooleanCellEditable","checked","Switch","c","Checkbox","renderInputCellEditable","Input","e","renderEditableCell","current","renderReadonlyCell","option","Badge","Check","renderCell","renderColumnHeader","matchingField","icon","fillPlan","canFillDown","fillHint","Tooltip","TooltipTrigger","Button","ArrowDownToLine","TooltipContent","groupableColumns","activeGroupField","grouped","totalRows","lastPage","selSize","totalColSpan","renderDataRow","isSelected","extra","TableRow","TableCell","toggleGroup","prev","groupHeaderLabel","ManifestFilterPopover","Layers","TooltipProvider","Table","TableHeader","TableHead","TableBody","group","isCollapsed","ChevronRight","ChevronDown"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),S=require("react"),k=require("../../ui/button.cjs"),q=require("../../ui/checkbox.cjs"),i=require("../../ui/combobox.cjs"),I=require("../../ui/input.cjs"),F=require("../../ui/label.cjs"),x=require("../../ui/select.cjs"),M=require("../../ui/switch.cjs"),_=require("../../../lib/utils.cjs");function $(o){const l=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(o){for(const r in o)if(r!=="default"){const c=Object.getOwnPropertyDescriptor(o,r);Object.defineProperty(l,r,c.get?c:{enumerable:!0,get:()=>o[r]})}}return l.default=o,Object.freeze(l)}const O=$(S);function T({id:o,value:l,options:r,placeholder:c,onChange:j}){const b=i.useComboboxAnchor(),p=O.useMemo(()=>{const a=new Map;return r.forEach(u=>a.set(u.value,u.label)),a},[r]);return n.jsxs(i.Combobox,{multiple:!0,items:r.map(a=>a.value),value:l,onValueChange:j,children:[n.jsxs(i.ComboboxChips,{ref:b,className:"min-h-9 w-full",children:[n.jsx(i.ComboboxValue,{children:a=>a.map(u=>n.jsx(i.ComboboxChip,{children:p.get(u)??u},u))}),n.jsx(i.ComboboxChipsInput,{id:o,placeholder:c??"Select…"})]}),n.jsxs(i.ComboboxContent,{anchor:b,children:[n.jsx(i.ComboboxEmpty,{children:"No options."}),n.jsx(i.ComboboxList,{children:a=>n.jsx(i.ComboboxItem,{value:a,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[(()=>{const u=r.find(g=>g.value===a);return u?.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:u.swatch},"aria-hidden":!0}):null})(),p.get(a)??a]})},a)})]})]})}const V={number:"number",integer:"number",date:"date",datetime:"datetime-local",time:"time"};function A(o){return V[o]??"text"}function B(o,l){if(l!==""){if(o==="number"){const r=parseFloat(l);return Number.isFinite(r)?r:l}if(o==="integer"){const r=parseInt(l,10);return Number.isFinite(r)?r:l}return l}}function P({fields:o,value:l,onChange:r,selectionSize:c,onApply:j,onClear:b,applyLabel:p="Apply",clearLabel:a="Clear wells",extras:u,className:g}){const d=(e,t)=>{r({...l,[e]:t})},m=e=>n.jsxs(F.Label,{htmlFor:`field-${e.key}`,className:"gap-1.5",children:[e.icon?n.jsx("span",{className:"inline-flex text-muted-foreground [&_svg]:size-3.5",children:e.icon}):null,e.label]}),y=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),e.render({value:t,onChange:s=>d(e.key,s),selectionSize:c})]},e.key),C=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsxs(x.Select,{value:t??"",onValueChange:s=>d(e.key,s),children:[n.jsx(x.SelectTrigger,{id:`field-${e.key}`,size:"sm",className:"w-full",children:n.jsx(x.SelectValue,{placeholder:e.placeholder??"Select…"})}),n.jsx(x.SelectContent,{children:(e.options??[]).map(s=>n.jsx(x.SelectItem,{value:s.value,children:n.jsxs("span",{className:"inline-flex items-center gap-2",children:[s.swatch?n.jsx("span",{className:"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20",style:{backgroundColor:s.swatch},"aria-hidden":!0}):null,s.label]})},s.value))})]})]},e.key),v=(e,t)=>{const s=Array.isArray(t)?t:[];return n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(T,{id:`field-${e.key}`,value:s,options:e.options??[],placeholder:e.placeholder,onChange:h=>d(e.key,h.length===0?void 0:h)})]},e.key)},N=(e,t)=>{const s=!!t;return e.boolStyle==="switch"?n.jsxs("div",{className:"flex items-center justify-between gap-2",children:[m(e),n.jsx(M.Switch,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h)})]},e.key):n.jsxs("div",{className:"flex items-center gap-2",children:[n.jsx(q.Checkbox,{id:`field-${e.key}`,checked:s,onCheckedChange:h=>d(e.key,h===!0)}),m(e)]},e.key)},f=(e,t)=>n.jsxs("div",{className:"flex flex-col gap-1.5",children:[m(e),n.jsx(I.Input,{id:`field-${e.key}`,type:A(e.kind),step:e.kind==="integer"?1:void 0,placeholder:e.placeholder,value:t??"",onChange:s=>d(e.key,B(e.kind,s.target.value))})]},e.key),w=e=>{const t=l[e.key];return e.render?y(e,t):e.kind==="select"?C(e,t):e.kind==="multiselect"?v(e,t):e.kind==="boolean"?N(e,t):f(e,t)};return n.jsxs("div",{"data-slot":"well-metadata-form",className:_.cn("flex flex-col gap-3",g),children:[n.jsx("div",{className:"text-sm font-medium",children:c>0?`Apply to ${c} well${c===1?"":"s"}`:"Select wells to edit"}),o.map(w),u,n.jsxs("div",{className:"mt-auto flex gap-2 pt-1",children:[n.jsx(k.Button,{variant:"default",size:"sm",disabled:c===0,onClick:j,children:p}),n.jsx(k.Button,{variant:"outline",size:"sm",disabled:c===0,onClick:b,children:a})]})]})}exports.WellMetadataForm=P;
2
+ //# sourceMappingURL=WellMetadataForm.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WellMetadataForm.cjs","sources":["../../../../src/components/composed/PlateMapEditor/WellMetadataForm.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport type { WellField, WellRecord, WellSelectOption } from \"./types\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport {\n Combobox,\n ComboboxChip,\n ComboboxChips,\n ComboboxChipsInput,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxItem,\n ComboboxList,\n ComboboxValue,\n useComboboxAnchor,\n} from \"@/components/ui/combobox\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\nimport { Switch } from \"@/components/ui/switch\";\nimport { cn } from \"@/lib/utils\";\n\nfunction MultiSelectControl({\n id,\n value,\n options,\n placeholder,\n onChange,\n}: {\n id: string;\n value: string[];\n options: WellSelectOption[];\n placeholder?: string;\n onChange: (next: string[]) => void;\n}) {\n const anchorRef = useComboboxAnchor();\n const labelByValue = React.useMemo(() => {\n const m = new Map<string, string>();\n options.forEach((o) => m.set(o.value, o.label));\n return m;\n }, [options]);\n\n return (\n <Combobox multiple items={options.map((o) => o.value)} value={value} onValueChange={onChange}>\n <ComboboxChips ref={anchorRef} className=\"min-h-9 w-full\">\n <ComboboxValue>\n {(items: string[]) =>\n items.map((item) => <ComboboxChip key={item}>{labelByValue.get(item) ?? item}</ComboboxChip>)\n }\n </ComboboxValue>\n <ComboboxChipsInput id={id} placeholder={placeholder ?? \"Select…\"} />\n </ComboboxChips>\n <ComboboxContent anchor={anchorRef}>\n <ComboboxEmpty>No options.</ComboboxEmpty>\n <ComboboxList>\n {(item: string) => (\n <ComboboxItem key={item} value={item}>\n <span className=\"inline-flex items-center gap-2\">\n {(() => {\n const opt = options.find((o) => o.value === item);\n return opt?.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null;\n })()}\n {labelByValue.get(item) ?? item}\n </span>\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n );\n}\n\nexport interface WellMetadataFormProps<T extends WellRecord = WellRecord> {\n fields: WellField<T>[];\n /** Staged values used to apply across the selection. */\n value: Partial<T>;\n onChange: (next: Partial<T>) => void;\n selectionSize: number;\n onApply: () => void;\n onClear: () => void;\n applyLabel?: string;\n clearLabel?: string;\n /** Optional extra slot rendered between fields and action row. */\n extras?: React.ReactNode;\n className?: string;\n}\n\nconst INPUT_TYPE_BY_KIND: Record<string, string> = {\n number: \"number\",\n integer: \"number\",\n date: \"date\",\n datetime: \"datetime-local\",\n time: \"time\",\n};\n\nfunction resolveInputType(kind: string): string {\n return INPUT_TYPE_BY_KIND[kind] ?? \"text\";\n}\n\nfunction parseInputValue(kind: string, raw: string): unknown {\n if (raw === \"\") return undefined;\n if (kind === \"number\") {\n const num = parseFloat(raw);\n return Number.isFinite(num) ? num : raw;\n }\n if (kind === \"integer\") {\n const num = parseInt(raw, 10);\n return Number.isFinite(num) ? num : raw;\n }\n return raw;\n}\n\nexport function WellMetadataForm<T extends WellRecord = WellRecord>({\n fields,\n value,\n onChange,\n selectionSize,\n onApply,\n onClear,\n applyLabel = \"Apply\",\n clearLabel = \"Clear wells\",\n extras,\n className,\n}: WellMetadataFormProps<T>) {\n const setField = (key: keyof T & string, next: unknown) => {\n onChange({ ...value, [key]: next } as Partial<T>);\n };\n\n const renderLabel = (field: WellField<T>) => (\n <Label htmlFor={`field-${field.key}`} className=\"gap-1.5\">\n {field.icon ? <span className=\"inline-flex text-muted-foreground [&_svg]:size-3.5\">{field.icon}</span> : null}\n {field.label}\n </Label>\n );\n\n const renderCustom = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n {field.render!({\n value: fieldValue,\n onChange: (next) => setField(field.key, next),\n selectionSize,\n })}\n </div>\n );\n\n const renderSelect = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Select value={(fieldValue as string | undefined) ?? \"\"} onValueChange={(v) => setField(field.key, v)}>\n <SelectTrigger id={`field-${field.key}`} size=\"sm\" className=\"w-full\">\n <SelectValue placeholder={field.placeholder ?? \"Select…\"} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((opt) => (\n <SelectItem key={opt.value} value={opt.value}>\n <span className=\"inline-flex items-center gap-2\">\n {opt.swatch ? (\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-sm border border-foreground/20\"\n style={{ backgroundColor: opt.swatch }}\n aria-hidden\n />\n ) : null}\n {opt.label}\n </span>\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n );\n\n const renderMultiSelect = (field: WellField<T>, fieldValue: unknown) => {\n const current = Array.isArray(fieldValue) ? (fieldValue as string[]) : [];\n return (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <MultiSelectControl\n id={`field-${field.key}`}\n value={current}\n options={field.options ?? []}\n placeholder={field.placeholder}\n onChange={(next) => setField(field.key, next.length === 0 ? undefined : next)}\n />\n </div>\n );\n };\n\n const renderBoolean = (field: WellField<T>, fieldValue: unknown) => {\n const checked = !!fieldValue;\n if (field.boolStyle === \"switch\") {\n return (\n <div key={field.key} className=\"flex items-center justify-between gap-2\">\n {renderLabel(field)}\n <Switch\n id={`field-${field.key}`}\n checked={checked}\n onCheckedChange={(c) => setField(field.key, c)}\n />\n </div>\n );\n }\n return (\n <div key={field.key} className=\"flex items-center gap-2\">\n <Checkbox\n id={`field-${field.key}`}\n checked={checked}\n onCheckedChange={(c) => setField(field.key, c === true)}\n />\n {renderLabel(field)}\n </div>\n );\n };\n\n const renderInput = (field: WellField<T>, fieldValue: unknown) => (\n <div key={field.key} className=\"flex flex-col gap-1.5\">\n {renderLabel(field)}\n <Input\n id={`field-${field.key}`}\n type={resolveInputType(field.kind)}\n step={field.kind === \"integer\" ? 1 : undefined}\n placeholder={field.placeholder}\n value={(fieldValue as string | number | undefined) ?? \"\"}\n onChange={(e) => setField(field.key, parseInputValue(field.kind, e.target.value))}\n />\n </div>\n );\n\n const renderField = (field: WellField<T>) => {\n const fieldValue = value[field.key];\n if (field.render) return renderCustom(field, fieldValue);\n if (field.kind === \"select\") return renderSelect(field, fieldValue);\n if (field.kind === \"multiselect\") return renderMultiSelect(field, fieldValue);\n if (field.kind === \"boolean\") return renderBoolean(field, fieldValue);\n return renderInput(field, fieldValue);\n };\n\n return (\n <div data-slot=\"well-metadata-form\" className={cn(\"flex flex-col gap-3\", className)}>\n <div className=\"text-sm font-medium\">\n {selectionSize > 0 ? `Apply to ${selectionSize} well${selectionSize === 1 ? \"\" : \"s\"}` : \"Select wells to edit\"}\n </div>\n\n {fields.map(renderField)}\n\n {extras}\n\n <div className=\"mt-auto flex gap-2 pt-1\">\n <Button variant=\"default\" size=\"sm\" disabled={selectionSize === 0} onClick={onApply}>\n {applyLabel}\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={selectionSize === 0} onClick={onClear}>\n {clearLabel}\n </Button>\n </div>\n </div>\n );\n}\n"],"names":["MultiSelectControl","id","value","options","placeholder","onChange","anchorRef","useComboboxAnchor","labelByValue","React","m","o","jsxs","Combobox","ComboboxChips","jsx","ComboboxValue","items","item","ComboboxChip","ComboboxChipsInput","ComboboxContent","ComboboxEmpty","ComboboxList","ComboboxItem","opt","INPUT_TYPE_BY_KIND","resolveInputType","kind","parseInputValue","raw","num","WellMetadataForm","fields","selectionSize","onApply","onClear","applyLabel","clearLabel","extras","className","setField","key","next","renderLabel","field","Label","renderCustom","fieldValue","renderSelect","Select","v","SelectTrigger","SelectValue","SelectContent","SelectItem","renderMultiSelect","current","renderBoolean","checked","Switch","c","Checkbox","renderInput","Input","e","renderField","cn","Button"],"mappings":"+qBAwBA,SAASA,EAAmB,CAC1B,GAAAC,EACA,MAAAC,EACA,QAAAC,EACA,YAAAC,EACA,SAAAC,CACF,EAMG,CACD,MAAMC,EAAYC,EAAAA,kBAAA,EACZC,EAAeC,EAAM,QAAQ,IAAM,CACvC,MAAMC,MAAQ,IACd,OAAAP,EAAQ,QAASQ,GAAMD,EAAE,IAAIC,EAAE,MAAOA,EAAE,KAAK,CAAC,EACvCD,CACT,EAAG,CAACP,CAAO,CAAC,EAEZ,OACES,EAAAA,KAACC,EAAAA,SAAA,CAAS,SAAQ,GAAC,MAAOV,EAAQ,IAAKQ,GAAMA,EAAE,KAAK,EAAG,MAAAT,EAAc,cAAeG,EAClF,SAAA,CAAAO,EAAAA,KAACE,EAAAA,cAAA,CAAc,IAAKR,EAAW,UAAU,iBACvC,SAAA,CAAAS,MAACC,EAAAA,eACE,SAACC,GACAA,EAAM,IAAKC,GAASH,EAAAA,IAACI,EAAAA,aAAA,CAAyB,SAAAX,EAAa,IAAIU,CAAI,GAAKA,CAAA,EAAjCA,CAAsC,CAAe,EAEhG,EACAH,EAAAA,IAACK,EAAAA,mBAAA,CAAmB,GAAAnB,EAAQ,YAAaG,GAAe,SAAA,CAAW,CAAA,EACrE,EACAQ,EAAAA,KAACS,EAAAA,gBAAA,CAAgB,OAAQf,EACvB,SAAA,CAAAS,EAAAA,IAACO,EAAAA,eAAc,SAAA,aAAA,CAAW,EAC1BP,EAAAA,IAACQ,EAAAA,aAAA,CACE,SAACL,GACAH,EAAAA,IAACS,eAAA,CAAwB,MAAON,EAC9B,SAAAN,OAAC,OAAA,CAAK,UAAU,iCACZ,SAAA,EAAA,IAAM,CACN,MAAMa,EAAMtB,EAAQ,KAAMQ,GAAMA,EAAE,QAAUO,CAAI,EAChD,OAAOO,GAAK,OACVV,EAAAA,IAAC,OAAA,CACC,UAAU,kEACV,MAAO,CAAE,gBAAiBU,EAAI,MAAA,EAC9B,cAAW,EAAA,CAAA,EAEX,IACN,GAAA,EACCjB,EAAa,IAAIU,CAAI,GAAKA,CAAA,EAC7B,CAAA,EAbiBA,CAcnB,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,CAEJ,CAiBA,MAAMQ,EAA6C,CACjD,OAAQ,SACR,QAAS,SACT,KAAM,OACN,SAAU,iBACV,KAAM,MACR,EAEA,SAASC,EAAiBC,EAAsB,CAC9C,OAAOF,EAAmBE,CAAI,GAAK,MACrC,CAEA,SAASC,EAAgBD,EAAcE,EAAsB,CAC3D,GAAIA,IAAQ,GACZ,IAAIF,IAAS,SAAU,CACrB,MAAMG,EAAM,WAAWD,CAAG,EAC1B,OAAO,OAAO,SAASC,CAAG,EAAIA,EAAMD,CACtC,CACA,GAAIF,IAAS,UAAW,CACtB,MAAMG,EAAM,SAASD,EAAK,EAAE,EAC5B,OAAO,OAAO,SAASC,CAAG,EAAIA,EAAMD,CACtC,CACA,OAAOA,EACT,CAEO,SAASE,EAAoD,CAClE,OAAAC,EACA,MAAA/B,EACA,SAAAG,EACA,cAAA6B,EACA,QAAAC,EACA,QAAAC,EACA,WAAAC,EAAa,QACb,WAAAC,EAAa,cACb,OAAAC,EACA,UAAAC,CACF,EAA6B,CAC3B,MAAMC,EAAW,CAACC,EAAuBC,IAAkB,CACzDtC,EAAS,CAAE,GAAGH,EAAO,CAACwC,CAAG,EAAGC,EAAoB,CAClD,EAEMC,EAAeC,GACnBjC,EAAAA,KAACkC,EAAAA,MAAA,CAAM,QAAS,SAASD,EAAM,GAAG,GAAI,UAAU,UAC7C,SAAA,CAAAA,EAAM,KAAO9B,MAAC,OAAA,CAAK,UAAU,qDAAsD,SAAA8B,EAAM,KAAK,EAAU,KACxGA,EAAM,KAAA,EACT,EAGIE,EAAe,CAACF,EAAqBG,IACzCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EACjBA,EAAM,OAAQ,CACb,MAAOG,EACP,SAAWL,GAASF,EAASI,EAAM,IAAKF,CAAI,EAC5C,cAAAT,CAAA,CACD,CAAA,CAAA,EANOW,EAAM,GAOhB,EAGII,EAAe,CAACJ,EAAqBG,IACzCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClBjC,EAAAA,KAACsC,EAAAA,OAAA,CAAO,MAAQF,GAAqC,GAAI,cAAgBG,GAAMV,EAASI,EAAM,IAAKM,CAAC,EAClG,SAAA,CAAApC,MAACqC,EAAAA,eAAc,GAAI,SAASP,EAAM,GAAG,GAAI,KAAK,KAAK,UAAU,SAC3D,eAACQ,cAAA,CAAY,YAAaR,EAAM,aAAe,UAAW,EAC5D,QACCS,EAAAA,cAAA,CACG,UAAAT,EAAM,SAAW,IAAI,IAAKpB,GAC1BV,EAAAA,IAACwC,EAAAA,YAA2B,MAAO9B,EAAI,MACrC,SAAAb,OAAC,OAAA,CAAK,UAAU,iCACb,SAAA,CAAAa,EAAI,OACHV,EAAAA,IAAC,OAAA,CACC,UAAU,kEACV,MAAO,CAAE,gBAAiBU,EAAI,MAAA,EAC9B,cAAW,EAAA,CAAA,EAEX,KACHA,EAAI,KAAA,CAAA,CACP,CAAA,EAVeA,EAAI,KAWrB,CACD,CAAA,CACH,CAAA,CAAA,CACF,CAAA,CAAA,EAtBQoB,EAAM,GAuBhB,EAGIW,EAAoB,CAACX,EAAqBG,IAAwB,CACtE,MAAMS,EAAU,MAAM,QAAQT,CAAU,EAAKA,EAA0B,CAAA,EACvE,OACEpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAACf,EAAA,CACC,GAAI,SAAS6C,EAAM,GAAG,GACtB,MAAOY,EACP,QAASZ,EAAM,SAAW,CAAA,EAC1B,YAAaA,EAAM,YACnB,SAAWF,GAASF,EAASI,EAAM,IAAKF,EAAK,SAAW,EAAI,OAAYA,CAAI,CAAA,CAAA,CAC9E,CAAA,EARQE,EAAM,GAShB,CAEJ,EAEMa,EAAgB,CAACb,EAAqBG,IAAwB,CAClE,MAAMW,EAAU,CAAC,CAACX,EAClB,OAAIH,EAAM,YAAc,SAEpBjC,EAAAA,KAAC,MAAA,CAAoB,UAAU,0CAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAAC6C,EAAAA,OAAA,CACC,GAAI,SAASf,EAAM,GAAG,GACtB,QAAAc,EACA,gBAAkBE,GAAMpB,EAASI,EAAM,IAAKgB,CAAC,CAAA,CAAA,CAC/C,CAAA,EANQhB,EAAM,GAOhB,EAIFjC,EAAAA,KAAC,MAAA,CAAoB,UAAU,0BAC7B,SAAA,CAAAG,EAAAA,IAAC+C,EAAAA,SAAA,CACC,GAAI,SAASjB,EAAM,GAAG,GACtB,QAAAc,EACA,gBAAkBE,GAAMpB,EAASI,EAAM,IAAKgB,IAAM,EAAI,CAAA,CAAA,EAEvDjB,EAAYC,CAAK,CAAA,CAAA,EANVA,EAAM,GAOhB,CAEJ,EAEMkB,EAAc,CAAClB,EAAqBG,IACxCpC,EAAAA,KAAC,MAAA,CAAoB,UAAU,wBAC5B,SAAA,CAAAgC,EAAYC,CAAK,EAClB9B,EAAAA,IAACiD,EAAAA,MAAA,CACC,GAAI,SAASnB,EAAM,GAAG,GACtB,KAAMlB,EAAiBkB,EAAM,IAAI,EACjC,KAAMA,EAAM,OAAS,UAAY,EAAI,OACrC,YAAaA,EAAM,YACnB,MAAQG,GAA8C,GACtD,SAAWiB,GAAMxB,EAASI,EAAM,IAAKhB,EAAgBgB,EAAM,KAAMoB,EAAE,OAAO,KAAK,CAAC,CAAA,CAAA,CAClF,CAAA,EATQpB,EAAM,GAUhB,EAGIqB,EAAerB,GAAwB,CAC3C,MAAMG,EAAa9C,EAAM2C,EAAM,GAAG,EAClC,OAAIA,EAAM,OAAeE,EAAaF,EAAOG,CAAU,EACnDH,EAAM,OAAS,SAAiBI,EAAaJ,EAAOG,CAAU,EAC9DH,EAAM,OAAS,cAAsBW,EAAkBX,EAAOG,CAAU,EACxEH,EAAM,OAAS,UAAkBa,EAAcb,EAAOG,CAAU,EAC7De,EAAYlB,EAAOG,CAAU,CACtC,EAEA,OACEpC,OAAC,OAAI,YAAU,qBAAqB,UAAWuD,EAAAA,GAAG,sBAAuB3B,CAAS,EAChF,SAAA,CAAAzB,EAAAA,IAAC,MAAA,CAAI,UAAU,sBACZ,SAAAmB,EAAgB,EAAI,YAAYA,CAAa,QAAQA,IAAkB,EAAI,GAAK,GAAG,GAAK,uBAC3F,EAECD,EAAO,IAAIiC,CAAW,EAEtB3B,EAED3B,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACb,SAAA,CAAAG,EAAAA,IAACqD,EAAAA,OAAA,CAAO,QAAQ,UAAU,KAAK,KAAK,SAAUlC,IAAkB,EAAG,QAASC,EACzE,SAAAE,CAAA,CACH,EACAtB,EAAAA,IAACqD,EAAAA,OAAA,CAAO,QAAQ,UAAU,KAAK,KAAK,SAAUlC,IAAkB,EAAG,QAASE,EACzE,SAAAE,CAAA,CACH,CAAA,CAAA,CACF,CAAA,EACF,CAEJ"}