@tetrascience-npm/tetrascience-react-ui 1.0.0-beta.157.1 → 1.0.0-beta.158.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 (68) hide show
  1. package/README.md +113 -0
  2. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +1 -1
  3. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +1 -1
  4. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.d.ts +5 -1
  5. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +32 -30
  6. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +1 -1
  7. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs +1 -1
  8. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs.map +1 -1
  9. package/dist/components/composed/PlateMapEditor/PlateMapEditor.d.ts +269 -13
  10. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js +392 -310
  11. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js.map +1 -1
  12. package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs +1 -1
  13. package/dist/components/composed/PlateMapEditor/PlateMapForm.cjs.map +1 -1
  14. package/dist/components/composed/PlateMapEditor/PlateMapForm.d.ts +5 -1
  15. package/dist/components/composed/PlateMapEditor/PlateMapForm.js +19 -15
  16. package/dist/components/composed/PlateMapEditor/PlateMapForm.js.map +1 -1
  17. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs +1 -1
  18. package/dist/components/composed/PlateMapEditor/PlateMapGrid.cjs.map +1 -1
  19. package/dist/components/composed/PlateMapEditor/PlateMapGrid.d.ts +12 -1
  20. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js +69 -63
  21. package/dist/components/composed/PlateMapEditor/PlateMapGrid.js.map +1 -1
  22. package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs +1 -1
  23. package/dist/components/composed/PlateMapEditor/PlateMapManifest.cjs.map +1 -1
  24. package/dist/components/composed/PlateMapEditor/PlateMapManifest.d.ts +13 -4
  25. package/dist/components/composed/PlateMapEditor/PlateMapManifest.js +38 -29
  26. package/dist/components/composed/PlateMapEditor/PlateMapManifest.js.map +1 -1
  27. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +1 -1
  28. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +1 -1
  29. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.d.ts +6 -1
  30. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +490 -275
  31. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +1 -1
  32. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +1 -1
  33. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +1 -1
  34. package/dist/components/composed/PlateMapEditor/WellLegend.d.ts +8 -2
  35. package/dist/components/composed/PlateMapEditor/WellLegend.js +8 -7
  36. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +1 -1
  37. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +1 -1
  38. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +1 -1
  39. package/dist/components/composed/PlateMapEditor/WellManifestTable.d.ts +6 -2
  40. package/dist/components/composed/PlateMapEditor/WellManifestTable.js +288 -256
  41. package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +1 -1
  42. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs +1 -1
  43. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs.map +1 -1
  44. package/dist/components/composed/PlateMapEditor/WellMetadataForm.d.ts +5 -1
  45. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js +61 -66
  46. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js.map +1 -1
  47. package/dist/components/composed/PlateMapEditor/WellQuickPaint.cjs +2 -0
  48. package/dist/components/composed/PlateMapEditor/WellQuickPaint.cjs.map +1 -0
  49. package/dist/components/composed/PlateMapEditor/WellQuickPaint.d.ts +23 -0
  50. package/dist/components/composed/PlateMapEditor/WellQuickPaint.js +75 -0
  51. package/dist/components/composed/PlateMapEditor/WellQuickPaint.js.map +1 -0
  52. package/dist/components/composed/PlateMapEditor/index.d.ts +6 -2
  53. package/dist/components/composed/PlateMapEditor/types.d.ts +65 -0
  54. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.cjs +2 -0
  55. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.cjs.map +1 -0
  56. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.d.ts +109 -0
  57. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.js +246 -0
  58. package/dist/components/composed/PlateMapEditor/usePlateMapEditorState.js.map +1 -0
  59. package/dist/composed/PlateMapEditor.cjs +1 -1
  60. package/dist/composed/PlateMapEditor.js +48 -42
  61. package/dist/composed/PlateMapEditor.js.map +1 -1
  62. package/dist/index.cjs +1 -1
  63. package/dist/index.css +1 -1
  64. package/dist/index.js +701 -695
  65. package/dist/index.js.map +1 -1
  66. package/dist/index.scoped.css +1 -1
  67. package/dist/index.tailwind.css +1 -1
  68. package/package.json +1 -1
@@ -1,377 +1,592 @@
1
- import { jsx as g, jsxs as U, Fragment as we } from "react/jsx-runtime";
2
- import * as E from "react";
3
- import { rectPositions as te, pos as $, resolveDimensions as ye, rowLabel as _e } from "./wellGrid.js";
4
- import { parsePos as ze } from "./wellGrid.js";
5
- import { cn as oe } from "../../../lib/utils.js";
6
- const be = 34, Ae = 24, Me = 72, ke = 36, n = 26, z = 12, Fe = 1, le = 16, Te = 9, xe = 5, N = 1, Z = 4, se = 4, Re = 3, ne = 5, Y = 650, De = "var(--surface-container)", Oe = "var(--border)";
7
- function Se(i, l) {
8
- const r = [];
9
- for (let o = 0; o < i; o++)
10
- r.push(
11
- /* @__PURE__ */ g(
1
+ import { jsx as v, jsxs as q, Fragment as Ke } from "react/jsx-runtime";
2
+ import * as u from "react";
3
+ import { rectPositions as ne, pos as D, parsePos as Xe, resolveDimensions as Be, rowLabel as Ye, allPositions as Ge } from "./wellGrid.js";
4
+ import { cn as re } from "../../../lib/utils.js";
5
+ const qe = 34, He = 24, Qe = 72, je = 36, a = 26, Z = 12, ge = 1, ke = 16, Ze = 9, Je = 5, G = 1, le = 4, ye = 4, Ee = 8, oe = 10, Ve = 3, Le = 5, se = 650, et = "var(--surface-container)", tt = /* @__PURE__ */ new Set();
6
+ function ce(o, c, s) {
7
+ return `${o}-well-${c}-${s}`;
8
+ }
9
+ const nt = "var(--border)";
10
+ function ot(o, c) {
11
+ const s = [];
12
+ for (let l = 0; l < o; l++)
13
+ s.push(
14
+ /* @__PURE__ */ v(
12
15
  "text",
13
16
  {
14
- x: n + o * l + l / 2,
15
- y: n / 2,
17
+ x: a + l * c + c / 2,
18
+ y: a / 2,
16
19
  textAnchor: "middle",
17
- fontSize: le,
20
+ fontSize: ke,
18
21
  className: "fill-muted-foreground",
19
- children: o + 1
22
+ children: l + 1
20
23
  },
21
- `c${o}`
24
+ `c${l}`
22
25
  )
23
26
  );
24
- return r;
27
+ return s;
25
28
  }
26
- function Ce(i, l) {
27
- const r = [];
28
- for (let o = 0; o < i; o++)
29
- r.push(
30
- /* @__PURE__ */ g(
29
+ function st(o, c) {
30
+ const s = [];
31
+ for (let l = 0; l < o; l++)
32
+ s.push(
33
+ /* @__PURE__ */ v(
31
34
  "text",
32
35
  {
33
- x: n - Te,
34
- y: n + o * l + l / 2 + xe,
36
+ x: a - Ze,
37
+ y: a + l * c + c / 2 + Je,
35
38
  textAnchor: "end",
36
- fontSize: le,
39
+ fontSize: ke,
37
40
  className: "fill-muted-foreground",
38
- children: _e(o)
41
+ children: Ye(l)
39
42
  },
40
- `r${o}`
43
+ `r${l}`
41
44
  )
42
45
  );
43
- return r;
46
+ return s;
44
47
  }
45
- function We(i, l, r) {
48
+ function rt(o, c, s) {
46
49
  const {
47
- dims: o,
48
- cellSize: e,
49
- values: v,
50
- selection: k,
51
- dragPositions: L,
52
- colorForWell: u,
53
- emptyWellFillColor: f,
54
- selectedFillColor: w,
55
- selectedFillOpacity: _,
56
- selectionFillMode: T,
57
- wellShape: p
58
- } = i, h = $(l, r, o.columns), b = v.get(h), y = k.has(h) || L.has(h), D = b === void 0 && f !== null ? f : u(b, h), F = y && !(y && T === "well" && b !== void 0), x = F ? w : D, R = F ? _ : void 0;
59
- if (p === "circle") {
60
- const O = n + r * e + e / 2, A = n + l * e + e / 2, S = e / 2 - N;
61
- return /* @__PURE__ */ g(
50
+ dims: l,
51
+ cellSize: r,
52
+ values: d,
53
+ selection: E,
54
+ dragPositions: y,
55
+ colorForWell: h,
56
+ emptyWellFillColor: m,
57
+ selectedFillColor: P,
58
+ selectedFillOpacity: O,
59
+ selectionFillMode: F,
60
+ wellShape: g,
61
+ instanceId: L
62
+ } = o, w = D(c, s, l.columns), M = d.get(w), k = E.has(w) || y.has(w), N = M === void 0 && m !== null ? m : h(M, w), I = k && !(k && F === "well" && M !== void 0), C = I ? P : N, R = I ? O : void 0;
63
+ if (g === "circle") {
64
+ const _ = a + s * r + r / 2, z = a + c * r + r / 2, x = r / 2 - G;
65
+ return /* @__PURE__ */ v(
62
66
  "circle",
63
67
  {
64
- cx: O,
65
- cy: A,
66
- r: S,
67
- fill: x,
68
+ id: ce(L, c, s),
69
+ cx: _,
70
+ cy: z,
71
+ r: x,
72
+ fill: C,
68
73
  fillOpacity: R,
69
74
  stroke: "none",
70
- "data-well": h,
71
- "data-selected": y ? "true" : void 0
75
+ role: "gridcell",
76
+ "aria-colindex": s + 1,
77
+ "aria-label": w,
78
+ "aria-selected": k,
79
+ "data-well": w,
80
+ "data-selected": k ? "true" : void 0
72
81
  },
73
- h
82
+ w
74
83
  );
75
84
  }
76
- return /* @__PURE__ */ g(
85
+ return /* @__PURE__ */ v(
77
86
  "rect",
78
87
  {
79
- x: n + r * e,
80
- y: n + l * e,
81
- width: e,
82
- height: e,
83
- fill: x,
88
+ id: ce(L, c, s),
89
+ x: a + s * r,
90
+ y: a + c * r,
91
+ width: r,
92
+ height: r,
93
+ fill: C,
84
94
  fillOpacity: R,
85
95
  stroke: "none",
86
- "data-well": h,
87
- "data-selected": y ? "true" : void 0
96
+ role: "gridcell",
97
+ "aria-colindex": s + 1,
98
+ "aria-label": w,
99
+ "aria-selected": k,
100
+ "data-well": w,
101
+ "data-selected": k ? "true" : void 0
88
102
  },
89
- h
103
+ w
90
104
  );
91
105
  }
92
- function Pe({ dims: i, ...l }) {
93
- const r = [];
94
- for (let o = 0; o < i.rows; o++)
95
- for (let e = 0; e < i.columns; e++)
96
- r.push(We({ dims: i, ...l }, o, e));
97
- return r;
106
+ function lt(o, c) {
107
+ const s = o.shiftKey;
108
+ switch (o.key) {
109
+ case "ArrowUp":
110
+ return { kind: "move", dr: -1, dc: 0, extend: s };
111
+ case "ArrowDown":
112
+ return { kind: "move", dr: 1, dc: 0, extend: s };
113
+ case "ArrowLeft":
114
+ return { kind: "move", dr: 0, dc: -1, extend: s };
115
+ case "ArrowRight":
116
+ return { kind: "move", dr: 0, dc: 1, extend: s };
117
+ case "Home":
118
+ return { kind: "move", dr: 0, dc: -c, extend: s };
119
+ case "End":
120
+ return { kind: "move", dr: 0, dc: c, extend: s };
121
+ case " ":
122
+ case "Enter":
123
+ return { kind: "toggle" };
124
+ case "Escape":
125
+ return { kind: "clear" };
126
+ case "a":
127
+ case "A":
128
+ return o.metaKey || o.ctrlKey ? { kind: "selectAll" } : null;
129
+ default:
130
+ return null;
131
+ }
132
+ }
133
+ function ct(o, c, s) {
134
+ if (!o) return null;
135
+ const { w: l, h: r } = c ?? { w: 0, h: 0 }, d = r + Ee, E = o.topY < d, y = E ? o.bottomY + Ee : o.topY - d;
136
+ if (l === 0)
137
+ return { left: o.anchorX, top: y, below: E, tailOffset: 0, ready: !1 };
138
+ const h = Math.min(Math.max(o.anchorX - l / 2, 0), Math.max(0, s - l)), m = Math.min(Math.max(o.anchorX - h, oe), Math.max(oe, l - oe));
139
+ return { left: h, top: y, below: E, tailOffset: m, ready: !0 };
140
+ }
141
+ function it({
142
+ placement: o,
143
+ children: c,
144
+ layerRef: s
145
+ }) {
146
+ return o ? /* @__PURE__ */ v(
147
+ "div",
148
+ {
149
+ ref: s,
150
+ "data-slot": "plate-quick-paint-anchor",
151
+ "data-placement": o.below ? "below" : "above",
152
+ className: "pointer-events-none absolute z-10 w-max",
153
+ style: {
154
+ left: o.left,
155
+ top: o.top,
156
+ // Hidden for the first paint only, while the strip is measured, so it
157
+ // never flashes in the wrong place.
158
+ visibility: o.ready ? void 0 : "hidden"
159
+ },
160
+ children: /* @__PURE__ */ q("div", { className: "pointer-events-auto relative", children: [
161
+ c,
162
+ /* @__PURE__ */ v(
163
+ "span",
164
+ {
165
+ "aria-hidden": !0,
166
+ "data-slot": "plate-quick-paint-tail",
167
+ className: re(
168
+ "absolute size-2 rotate-45 bg-popover",
169
+ o.below ? "-top-1 border-t border-l" : "-bottom-1 border-r border-b"
170
+ ),
171
+ style: { left: o.tailOffset - 4 }
172
+ }
173
+ )
174
+ ] })
175
+ }
176
+ ) : null;
177
+ }
178
+ function at({ dims: o, ...c }) {
179
+ const s = [];
180
+ for (let l = 0; l < o.rows; l++) {
181
+ const r = [];
182
+ for (let d = 0; d < o.columns; d++)
183
+ r.push(rt({ dims: o, ...c }, l, d));
184
+ s.push(
185
+ /* @__PURE__ */ v("g", { role: "row", "aria-rowindex": l + 1, children: r }, `row-${l}`)
186
+ );
187
+ }
188
+ return s;
98
189
  }
99
- function Ne(i, l, r) {
100
- const o = [], e = n, v = n, k = n + i.columns * l, L = n + i.rows * l;
101
- for (let u = 0; u <= i.columns; u++) {
102
- const f = n + u * l;
103
- o.push(
104
- /* @__PURE__ */ g(
190
+ function ut(o, c, s) {
191
+ const l = [], r = a, d = a, E = a + o.columns * c, y = a + o.rows * c;
192
+ for (let h = 0; h <= o.columns; h++) {
193
+ const m = a + h * c;
194
+ l.push(
195
+ /* @__PURE__ */ v(
105
196
  "line",
106
197
  {
107
- x1: f,
108
- y1: v,
109
- x2: f,
110
- y2: L,
111
- stroke: r,
112
- strokeWidth: Z,
198
+ x1: m,
199
+ y1: d,
200
+ x2: m,
201
+ y2: y,
202
+ stroke: s,
203
+ strokeWidth: le,
113
204
  vectorEffect: "non-scaling-stroke",
114
205
  shapeRendering: "crispEdges",
115
206
  pointerEvents: "none",
116
- "data-plate-grid-line": `column-${u}`
207
+ "data-plate-grid-line": `column-${h}`
117
208
  },
118
- `grid-col-${u}`
209
+ `grid-col-${h}`
119
210
  )
120
211
  );
121
212
  }
122
- for (let u = 0; u <= i.rows; u++) {
123
- const f = n + u * l;
124
- o.push(
125
- /* @__PURE__ */ g(
213
+ for (let h = 0; h <= o.rows; h++) {
214
+ const m = a + h * c;
215
+ l.push(
216
+ /* @__PURE__ */ v(
126
217
  "line",
127
218
  {
128
- x1: e,
129
- y1: f,
130
- x2: k,
131
- y2: f,
132
- stroke: r,
133
- strokeWidth: Z,
219
+ x1: r,
220
+ y1: m,
221
+ x2: E,
222
+ y2: m,
223
+ stroke: s,
224
+ strokeWidth: le,
134
225
  vectorEffect: "non-scaling-stroke",
135
226
  shapeRendering: "crispEdges",
136
227
  pointerEvents: "none",
137
- "data-plate-grid-line": `row-${u}`
228
+ "data-plate-grid-line": `row-${h}`
138
229
  },
139
- `grid-row-${u}`
230
+ `grid-row-${h}`
140
231
  )
141
232
  );
142
233
  }
143
- return o;
234
+ return l;
144
235
  }
145
- function $e(i, l, r) {
236
+ function dt(o, c, s) {
146
237
  const {
147
- dims: o,
148
- cellSize: e,
149
- selection: v,
150
- dragPositions: k,
151
- selectedBorderColor: L,
152
- flashWellId: u,
153
- flashWellKey: f,
154
- wellShape: w,
155
- highlightedWellIds: _,
156
- highlightBorderColor: T
157
- } = i, p = $(l, r, o.columns), h = v.has(p) || k.has(p), b = u === p, y = !h && _.has(p);
158
- if (!h && !b && !y) return null;
159
- const D = n + r * e + N, I = n + l * e + N, F = e - N * 2, x = n + r * e + e / 2, R = n + l * e + e / 2, O = e / 2 - N, A = w === "circle", S = A ? { cx: x, cy: R, r: O } : { x: D, y: I, width: F, height: F }, M = (s, C, W) => {
160
- const a = { ...S, ...s, pointerEvents: "none" };
161
- return A ? /* @__PURE__ */ g("circle", { ...a, children: C }, W) : /* @__PURE__ */ g("rect", { ...a, children: C }, W);
162
- }, B = /* @__PURE__ */ U(we, { children: [
163
- /* @__PURE__ */ g("animate", { attributeName: "fill-opacity", values: "0.24;0.1;0", dur: `${Y}ms`, fill: "freeze" }),
164
- /* @__PURE__ */ g("animate", { attributeName: "stroke-opacity", values: "0.92;0.42;0", dur: `${Y}ms`, fill: "freeze" }),
165
- /* @__PURE__ */ g(
238
+ dims: l,
239
+ cellSize: r,
240
+ selection: d,
241
+ dragPositions: E,
242
+ selectedBorderColor: y,
243
+ flashWellId: h,
244
+ flashWellKey: m,
245
+ wellShape: P,
246
+ highlightedWellIds: O,
247
+ highlightBorderColor: F
248
+ } = o, g = D(c, s, l.columns), L = d.has(g) || E.has(g), w = h === g, M = !L && O.has(g);
249
+ if (!L && !w && !M) return null;
250
+ const k = a + s * r + G, N = a + c * r + G, $ = r - G * 2, I = a + s * r + r / 2, C = a + c * r + r / 2, R = r / 2 - G, _ = P === "circle", z = _ ? { cx: I, cy: C, r: R } : { x: k, y: N, width: $, height: $ }, x = (J, t, U) => {
251
+ const K = { ...z, ...J, pointerEvents: "none" };
252
+ return _ ? /* @__PURE__ */ v("circle", { ...K, children: t }, U) : /* @__PURE__ */ v("rect", { ...K, children: t }, U);
253
+ }, W = /* @__PURE__ */ q(Ke, { children: [
254
+ /* @__PURE__ */ v("animate", { attributeName: "fill-opacity", values: "0.24;0.1;0", dur: `${se}ms`, fill: "freeze" }),
255
+ /* @__PURE__ */ v("animate", { attributeName: "stroke-opacity", values: "0.92;0.42;0", dur: `${se}ms`, fill: "freeze" }),
256
+ /* @__PURE__ */ v(
166
257
  "animate",
167
258
  {
168
259
  attributeName: "stroke-width",
169
- values: `${ne};${se}`,
170
- dur: `${Y}ms`,
260
+ values: `${Le};${ye}`,
261
+ dur: `${se}ms`,
171
262
  fill: "freeze"
172
263
  }
173
264
  )
174
265
  ] });
175
- return /* @__PURE__ */ U("g", { children: [
176
- h ? M({
266
+ return /* @__PURE__ */ q("g", { children: [
267
+ L ? x({
177
268
  fill: "none",
178
- stroke: L,
179
- strokeWidth: se,
180
- "data-well-selection": p
269
+ stroke: y,
270
+ strokeWidth: ye,
271
+ "data-well-selection": g
181
272
  }) : null,
182
- y ? M({
273
+ M ? x({
183
274
  fill: "none",
184
- stroke: T,
185
- strokeWidth: Re,
186
- "data-well-highlight": p
275
+ stroke: F,
276
+ strokeWidth: Ve,
277
+ "data-well-highlight": g
187
278
  }) : null,
188
- b ? M(
279
+ w ? x(
189
280
  {
190
- fill: L,
281
+ fill: y,
191
282
  fillOpacity: 0.24,
192
- stroke: L,
283
+ stroke: y,
193
284
  strokeOpacity: 0.92,
194
- strokeWidth: ne,
195
- "data-well-flash": p
285
+ strokeWidth: Le,
286
+ "data-well-flash": g
196
287
  },
197
- B,
198
- `${p}-${f}`
288
+ W,
289
+ `${g}-${m}`
199
290
  ) : null
200
- ] }, `overlay-${p}`);
291
+ ] }, `overlay-${g}`);
201
292
  }
202
- function Ie({ dims: i, ...l }) {
203
- const r = [];
204
- for (let o = 0; o < i.rows; o++)
205
- for (let e = 0; e < i.columns; e++) {
206
- const v = $e({ dims: i, ...l }, o, e);
207
- v && r.push(v);
293
+ function ft({ dims: o, ...c }) {
294
+ const s = [];
295
+ for (let l = 0; l < o.rows; l++)
296
+ for (let r = 0; r < o.columns; r++) {
297
+ const d = dt({ dims: o, ...c }, l, r);
298
+ d && s.push(d);
208
299
  }
209
- return r;
300
+ return s;
210
301
  }
211
- function Xe({
212
- format: i,
213
- rows: l,
214
- columns: r,
215
- values: o,
216
- selection: e,
217
- onSelectionChange: v,
218
- colorForWell: k,
219
- emptyWellFillColor: L = De,
220
- wellShape: u = "rect",
221
- framed: f = !1,
222
- cellSize: w,
223
- autoScale: _ = !0,
224
- minCellSize: T = Ae,
225
- maxCellSize: p,
226
- borderColor: h = Oe,
227
- selectedBorderColor: b = "var(--color-primary)",
228
- selectedFillColor: y = "var(--color-primary)",
229
- selectedFillOpacity: D = 0.18,
230
- selectionFillMode: I = "selection",
231
- flashWellId: F,
232
- flashWellKey: x,
233
- highlightedWellIds: R,
234
- highlightBorderColor: O = "var(--color-primary)",
235
- onWellHover: A,
236
- onWellDoubleClick: S,
237
- wrapWell: M,
238
- className: B
302
+ function wt({
303
+ format: o,
304
+ rows: c,
305
+ columns: s,
306
+ values: l,
307
+ selection: r,
308
+ onSelectionChange: d,
309
+ colorForWell: E,
310
+ emptyWellFillColor: y = et,
311
+ wellShape: h = "rect",
312
+ framed: m = !1,
313
+ cellSize: P,
314
+ autoScale: O = !0,
315
+ minCellSize: F = He,
316
+ maxCellSize: g,
317
+ borderColor: L = nt,
318
+ // Every blue in the palette shares one hue family (265-271), and wells are
319
+ // routinely filled from that same ramp (`--chart-1` is TS Blue 500, #2F45B5),
320
+ // so the selection separates on lightness rather than hue: #6C8DDB at L 0.65
321
+ // against the well's 0.45.
322
+ //
323
+ // An earlier attempt drew a background-coloured ring underneath for extra
324
+ // separation. SVG strokes centre on the path, so a wider under-stroke bleeds
325
+ // outside the selection ring as a white halo — which made adjacent wells look
326
+ // like they were floating apart rather than sitting on a plate. One stroke only.
327
+ selectedBorderColor: w = "var(--color-chart-seq-blue-06)",
328
+ selectedFillColor: M = "var(--color-chart-seq-blue-06)",
329
+ selectedFillOpacity: k = 0.26,
330
+ // "well" by default: a selected well keeps its own colour and the selection
331
+ // reads from the ring overlay instead. Replacing the fill hid the result of
332
+ // an Apply until the user deselected — no feedback on the action they just
333
+ // took. Empty selected wells still get the tint, since they have no colour
334
+ // of their own to show.
335
+ selectionFillMode: N = "well",
336
+ flashWellId: $,
337
+ flashWellKey: I,
338
+ highlightedWellIds: C,
339
+ highlightBorderColor: R = "var(--color-primary)",
340
+ onWellHover: _,
341
+ onWellDoubleClick: z,
342
+ wrapWell: x,
343
+ quickPaint: W,
344
+ className: J
239
345
  }) {
240
- const s = ye(i, l, r), C = E.useRef(null), W = E.useRef(null), [a, H] = E.useState(null), [K, re] = E.useState();
241
- E.useLayoutEffect(() => {
242
- const c = C.current;
243
- if (!c || !_ || w !== void 0) return;
244
- const t = () => re(c.clientWidth);
245
- if (t(), typeof ResizeObserver > "u") return;
246
- const d = new ResizeObserver(t);
247
- return d.observe(c), () => d.disconnect();
248
- }, [_, w]);
249
- const m = E.useMemo(() => {
250
- if (!_ || w !== void 0 || !K)
251
- return w ?? be;
252
- const c = p ?? (s.columns > 12 ? ke : Me), t = f ? (z + Fe) * 2 : 0, d = Math.floor((K - n - t) / s.columns);
253
- return Math.max(T, Math.min(c, d));
254
- }, [_, w, K, s.columns, f, p, T]), X = E.useCallback(
255
- (c) => {
256
- const t = W.current;
257
- if (!t) return null;
258
- const d = t.getBoundingClientRect(), P = c.clientX - d.left - n, Le = c.clientY - d.top - n, G = Math.floor(P / m), j = Math.floor(Le / m);
259
- return j < 0 || j >= s.rows || G < 0 || G >= s.columns ? null : { r: j, c: G };
346
+ const t = Be(o, c, s), U = u.useId(), K = u.useRef(null), ie = u.useRef(null), [p, V] = u.useState(null), [X, Ae] = u.useState();
347
+ u.useLayoutEffect(() => {
348
+ const n = K.current;
349
+ if (!n) return;
350
+ const e = () => Ae(n.clientWidth);
351
+ if (e(), typeof ResizeObserver > "u") return;
352
+ const i = new ResizeObserver(e);
353
+ return i.observe(n), () => i.disconnect();
354
+ }, []);
355
+ const f = u.useMemo(() => {
356
+ if (!O || P !== void 0 || !X)
357
+ return P ?? qe;
358
+ const n = g ?? (t.columns > 12 ? je : Qe), e = m ? (Z + ge) * 2 : 0, i = Math.floor((X - a - e) / t.columns);
359
+ return Math.max(F, Math.min(n, i));
360
+ }, [O, P, X, t.columns, m, g, F]), ee = u.useCallback(
361
+ (n) => {
362
+ const e = ie.current;
363
+ if (!e) return null;
364
+ const i = e.getBoundingClientRect(), A = n.clientX - i.left - a, b = n.clientY - i.top - a, S = Math.floor(A / f), te = Math.floor(b / f);
365
+ return te < 0 || te >= t.rows || S < 0 || S >= t.columns ? null : { r: te, c: S };
366
+ },
367
+ [f, t.rows, t.columns]
368
+ ), _e = (n) => {
369
+ const e = ee(n);
370
+ if (!e) return;
371
+ try {
372
+ n.currentTarget.setPointerCapture?.(n.pointerId);
373
+ } catch {
374
+ }
375
+ const i = n.shiftKey ? "add" : n.altKey ? "remove" : "replace";
376
+ V({ start: e, cur: e, mode: i }), H(e);
377
+ }, xe = (n) => {
378
+ const e = ee(n);
379
+ e && _ && _(D(e.r, e.c, t.columns)), !(!p || !e) && V({ ...p, cur: e });
380
+ }, [T, H] = u.useState(null), Q = u.useRef(null), Me = u.useCallback(
381
+ (n, e, i) => {
382
+ const A = T ?? { r: 0, c: 0 }, b = {
383
+ r: Math.min(t.rows - 1, Math.max(0, A.r + n)),
384
+ c: Math.min(t.columns - 1, Math.max(0, A.c + e))
385
+ };
386
+ if (i) {
387
+ const S = Q.current ?? A;
388
+ Q.current = S, d(new Set(ne(S.r, S.c, b.r, b.c, t.columns)));
389
+ } else
390
+ Q.current = b;
391
+ H(b), _?.(D(b.r, b.c, t.columns));
260
392
  },
261
- [m, s.rows, s.columns]
262
- ), ce = (c) => {
263
- const t = X(c);
264
- if (!t) return;
265
- const d = c.shiftKey ? "add" : c.altKey ? "remove" : "replace";
266
- H({ start: t, cur: t, mode: d });
267
- }, ie = (c) => {
268
- const t = X(c);
269
- t && A && A($(t.r, t.c, s.columns)), !(!a || !t) && H({ ...a, cur: t });
270
- }, q = E.useCallback(() => {
271
- if (!a) return;
272
- const c = te(a.start.r, a.start.c, a.cur.r, a.cur.c, s.columns);
273
- let t;
274
- a.mode === "replace" ? t = new Set(c) : a.mode === "add" ? (t = new Set(e), c.forEach((d) => t.add(d))) : (t = new Set(e), c.forEach((d) => t.delete(d))), v(t), H(null);
275
- }, [a, s.columns, v, e]), ae = () => q(), ue = () => {
276
- q(), A?.(null);
277
- }, de = (c) => {
278
- const t = X(c);
279
- t && S?.($(t.r, t.c, s.columns));
280
- }, fe = E.useMemo(() => a ? new Set(te(a.start.r, a.start.c, a.cur.r, a.cur.c, s.columns)) : /* @__PURE__ */ new Set(), [a, s.columns]), J = Z, Q = s.columns * m + n + J, V = s.rows * m + n + J, he = Se(s.columns, m), me = Ce(s.rows, m), ee = {
281
- dims: s,
282
- cellSize: m,
283
- values: o,
284
- selection: e,
285
- dragPositions: fe,
286
- colorForWell: k,
287
- emptyWellFillColor: L,
288
- borderColor: h,
289
- selectedBorderColor: b,
290
- selectedFillColor: y,
291
- selectedFillOpacity: D,
292
- selectionFillMode: I,
293
- wellShape: u,
294
- highlightedWellIds: R ?? /* @__PURE__ */ new Set(),
295
- highlightBorderColor: O,
296
- flashWellId: F,
297
- flashWellKey: x
298
- }, pe = Pe(ee), ge = u === "circle" ? [] : Ne(s, m, h), ve = Ie(ee), Ee = E.useMemo(() => {
299
- if (!M) return [];
300
- const c = [];
301
- for (let t = 0; t < s.rows; t++)
302
- for (let d = 0; d < s.columns; d++) {
303
- const P = $(t, d, s.columns);
304
- c.push(
305
- /* @__PURE__ */ g(
393
+ [t.columns, t.rows, T, d, _]
394
+ ), Pe = u.useCallback(() => {
395
+ const n = T ?? { r: 0, c: 0 }, e = D(n.r, n.c, t.columns), i = new Set(r);
396
+ i.has(e) ? i.delete(e) : i.add(e), H(n), d(i);
397
+ }, [t.columns, T, d, r]), Ie = (n) => {
398
+ const e = lt(n, t.columns);
399
+ e && (n.preventDefault(), e.kind === "move" ? Me(e.dr, e.dc, e.extend) : e.kind === "toggle" ? Pe() : e.kind === "selectAll" ? d(new Set(Ge(t))) : (Q.current = null, d(/* @__PURE__ */ new Set())));
400
+ }, ae = u.useCallback(() => {
401
+ if (!p) return;
402
+ const n = ne(p.start.r, p.start.c, p.cur.r, p.cur.c, t.columns);
403
+ let e;
404
+ p.mode === "replace" ? e = new Set(n) : p.mode === "add" ? (e = new Set(r), n.forEach((i) => e.add(i))) : (e = new Set(r), n.forEach((i) => e.delete(i))), d(e), V(null);
405
+ }, [p, t.columns, d, r]), ue = (n) => {
406
+ try {
407
+ n.currentTarget.releasePointerCapture?.(n.pointerId);
408
+ } catch {
409
+ }
410
+ ae();
411
+ }, Re = () => {
412
+ ae(), _?.(null);
413
+ }, Te = (n) => {
414
+ const e = ee(n);
415
+ e && z?.(D(e.r, e.c, t.columns));
416
+ }, de = u.useMemo(() => p ? new Set(ne(p.start.r, p.start.c, p.cur.r, p.cur.c, t.columns)) : /* @__PURE__ */ new Set(), [p, t.columns]), fe = le, B = t.columns * f + a + fe, he = t.rows * f + a + fe, Se = B + (m ? (Z + ge) * 2 : 0), Y = X !== void 0 && Se > X + 1, De = `${t.rows} by ${t.columns} plate map, horizontally scrollable.`, me = u.useMemo(() => {
417
+ if (!W || r.size === 0) return null;
418
+ let n = 1 / 0, e = -1 / 0, i = 1 / 0;
419
+ for (const A of r) {
420
+ const b = Xe(A, t);
421
+ b && (b.row < n && (n = b.row), b.row > e && (e = b.row), b.col < i && (i = b.col));
422
+ }
423
+ return !Number.isFinite(n) || !Number.isFinite(i) ? null : {
424
+ anchorX: a + i * f + f / 2,
425
+ topY: a + n * f,
426
+ bottomY: a + (e + 1) * f
427
+ };
428
+ }, [t, W, r, f]), ve = u.useRef(null), [we, pe] = u.useState();
429
+ u.useLayoutEffect(() => {
430
+ const n = ve.current;
431
+ if (!n) {
432
+ pe(void 0);
433
+ return;
434
+ }
435
+ const e = () => pe({ w: n.offsetWidth, h: n.offsetHeight });
436
+ if (e(), typeof ResizeObserver > "u") return;
437
+ const i = new ResizeObserver(e);
438
+ return i.observe(n), () => i.disconnect();
439
+ }, [W]);
440
+ const Oe = u.useMemo(
441
+ () => ct(me, we, B),
442
+ [me, we, B]
443
+ ), Fe = `${t.rows} row by ${t.columns} column plate map. Drag to select wells, or use arrow keys to move and Space to toggle a well.`, Ne = u.useMemo(
444
+ () => ot(t.columns, f),
445
+ [t.columns, f]
446
+ ), $e = u.useMemo(
447
+ () => st(t.rows, f),
448
+ [t.rows, f]
449
+ ), be = C ?? tt, j = u.useMemo(
450
+ () => ({
451
+ dims: t,
452
+ cellSize: f,
453
+ values: l,
454
+ selection: r,
455
+ dragPositions: de,
456
+ colorForWell: E,
457
+ emptyWellFillColor: y,
458
+ borderColor: L,
459
+ selectedBorderColor: w,
460
+ selectedFillColor: M,
461
+ selectedFillOpacity: k,
462
+ selectionFillMode: N,
463
+ wellShape: h,
464
+ highlightedWellIds: be,
465
+ highlightBorderColor: R,
466
+ flashWellId: $,
467
+ flashWellKey: I,
468
+ instanceId: U
469
+ }),
470
+ [
471
+ U,
472
+ L,
473
+ E,
474
+ t,
475
+ de,
476
+ y,
477
+ $,
478
+ I,
479
+ R,
480
+ f,
481
+ be,
482
+ w,
483
+ M,
484
+ k,
485
+ r,
486
+ N,
487
+ l,
488
+ h
489
+ ]
490
+ ), Ce = u.useMemo(() => at(j), [j]), We = u.useMemo(
491
+ () => h === "circle" ? [] : ut(t, f, L),
492
+ [h, t, f, L]
493
+ ), Ue = u.useMemo(() => ft(j), [j]), ze = u.useMemo(() => {
494
+ if (!x) return [];
495
+ const n = [];
496
+ for (let e = 0; e < t.rows; e++)
497
+ for (let i = 0; i < t.columns; i++) {
498
+ const A = D(e, i, t.columns);
499
+ n.push(
500
+ /* @__PURE__ */ v(
306
501
  "div",
307
502
  {
308
503
  style: {
309
504
  position: "absolute",
310
- left: n + d * m,
311
- top: n + t * m,
312
- width: m,
313
- height: m
505
+ left: a + i * f,
506
+ top: a + e * f,
507
+ width: f,
508
+ height: f
314
509
  },
315
- "data-well-id": P,
316
- children: M(P, m)
510
+ "data-well-id": A,
511
+ children: x(A, f)
317
512
  },
318
- P
513
+ A
319
514
  )
320
515
  );
321
516
  }
322
- return c;
323
- }, [M, s.rows, s.columns, m]);
324
- return /* @__PURE__ */ g(
517
+ return n;
518
+ }, [x, t.rows, t.columns, f]);
519
+ return /* @__PURE__ */ v(
325
520
  "div",
326
521
  {
327
- ref: C,
328
- className: oe("relative w-full select-none", B),
522
+ ref: K,
523
+ className: re(
524
+ // `overflow-x-auto` is load-bearing in narrow containers: once
525
+ // auto-scaling hits `minCellSize` the SVG stops shrinking, and a dense
526
+ // plate (384/1536) is wider than a phone. Without it the whole page
527
+ // scrolls sideways instead.
528
+ "relative w-full max-w-full select-none overflow-x-auto",
529
+ // Only a region that actually scrolls becomes a tab stop, so we don't
530
+ // add a dead stop to the tab order on roomy layouts.
531
+ Y && "focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none",
532
+ J
533
+ ),
329
534
  "data-slot": "plate-paint-grid",
330
- children: /* @__PURE__ */ U(
535
+ "data-scrollable": Y || void 0,
536
+ tabIndex: Y ? 0 : void 0,
537
+ role: Y ? "group" : void 0,
538
+ "aria-label": Y ? De : void 0,
539
+ children: /* @__PURE__ */ q(
331
540
  "div",
332
541
  {
333
- className: oe(
334
- "relative inline-block",
335
- f && "rounded-xl border bg-card p-3 shadow-elevation-3"
336
- ),
542
+ className: re("relative inline-block", m && "rounded-xl border bg-card p-3 shadow-elevation-3"),
337
543
  "data-slot": "plate-paint-grid-frame",
338
544
  children: [
339
- /* @__PURE__ */ U(
545
+ /* @__PURE__ */ q(
340
546
  "svg",
341
547
  {
342
- ref: W,
343
- width: Q,
344
- height: V,
548
+ ref: ie,
549
+ width: B,
550
+ height: he,
345
551
  className: "block cursor-crosshair",
346
- onMouseDown: ce,
347
- onMouseMove: ie,
348
- onMouseUp: ae,
349
- onMouseLeave: ue,
350
- onDoubleClick: de,
351
- role: "group",
352
- "aria-label": `${s.rows} row by ${s.columns} column plate map. Drag to select wells.`,
552
+ onPointerDown: _e,
553
+ onPointerMove: xe,
554
+ onPointerUp: ue,
555
+ onPointerCancel: ue,
556
+ onPointerLeave: Re,
557
+ onDoubleClick: Te,
558
+ onKeyDown: Ie,
559
+ onFocus: () => H((n) => n ?? { r: 0, c: 0 }),
560
+ style: { touchAction: "none" },
561
+ tabIndex: 0,
562
+ role: "grid",
563
+ "aria-label": Fe,
564
+ "aria-rowcount": t.rows,
565
+ "aria-colcount": t.columns,
566
+ "aria-activedescendant": T ? ce(U, T.r, T.c) : void 0,
353
567
  children: [
354
- he,
355
- me,
356
- pe,
357
- ge,
358
- ve
568
+ Ne,
569
+ $e,
570
+ Ce,
571
+ We,
572
+ Ue
359
573
  ]
360
574
  }
361
575
  ),
362
- M ? /* @__PURE__ */ g(
576
+ /* @__PURE__ */ v(it, { placement: Oe, layerRef: ve, children: W }),
577
+ x ? /* @__PURE__ */ v(
363
578
  "div",
364
579
  {
365
580
  className: "pointer-events-none absolute",
366
581
  style: {
367
- top: f ? z : 0,
368
- left: f ? z : 0,
369
- width: Q,
370
- height: V
582
+ top: m ? Z : 0,
583
+ left: m ? Z : 0,
584
+ width: B,
585
+ height: he
371
586
  },
372
587
  "aria-hidden": !0,
373
588
  "data-slot": "plate-well-overlay",
374
- children: Ee
589
+ children: ze
375
590
  }
376
591
  ) : null
377
592
  ]
@@ -381,9 +596,9 @@ function Xe({
381
596
  );
382
597
  }
383
598
  export {
384
- Oe as PLATE_MAP_CELL_BORDER,
385
- De as PLATE_MAP_EMPTY_WELL_FILL,
386
- Xe as PlatePaintGrid,
387
- ze as parsePos
599
+ nt as PLATE_MAP_CELL_BORDER,
600
+ et as PLATE_MAP_EMPTY_WELL_FILL,
601
+ wt as PlatePaintGrid,
602
+ Xe as parsePos
388
603
  };
389
604
  //# sourceMappingURL=PlatePaintGrid.js.map