@tetrascience-npm/tetrascience-react-ui 0.5.0-beta.58.1 → 0.5.0-beta.60.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 (75) hide show
  1. package/dist/components/ui/data-table/data-table-filter.cjs +1 -1
  2. package/dist/components/ui/data-table/data-table-filter.cjs.map +1 -1
  3. package/dist/components/ui/data-table/data-table-filter.js +139 -124
  4. package/dist/components/ui/data-table/data-table-filter.js.map +1 -1
  5. package/dist/components/ui/data-table/data-table.cjs +1 -1
  6. package/dist/components/ui/data-table/data-table.cjs.map +1 -1
  7. package/dist/components/ui/data-table/data-table.js +0 -1
  8. package/dist/components/ui/data-table/data-table.js.map +1 -1
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.css +1 -1
  11. package/dist/index.d.ts +0 -555
  12. package/dist/index.js +595 -637
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.tailwind.css +1 -1
  15. package/package.json +1 -1
  16. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs +0 -2
  17. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.cjs.map +0 -1
  18. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js +0 -140
  19. package/dist/components/composed/PlateMapEditor/ManifestFilterPopover.js.map +0 -1
  20. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs +0 -2
  21. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.cjs.map +0 -1
  22. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js +0 -126
  23. package/dist/components/composed/PlateMapEditor/PlateMapActionsMenu.js.map +0 -1
  24. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs +0 -2
  25. package/dist/components/composed/PlateMapEditor/PlateMapEditor.cjs.map +0 -1
  26. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js +0 -422
  27. package/dist/components/composed/PlateMapEditor/PlateMapEditor.js.map +0 -1
  28. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs +0 -2
  29. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.cjs.map +0 -1
  30. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js +0 -136
  31. package/dist/components/composed/PlateMapEditor/PlateMapPlateSelector.js.map +0 -1
  32. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs +0 -2
  33. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.cjs.map +0 -1
  34. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js +0 -389
  35. package/dist/components/composed/PlateMapEditor/PlatePaintGrid.js.map +0 -1
  36. package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs +0 -2
  37. package/dist/components/composed/PlateMapEditor/PlateZoomControl.cjs.map +0 -1
  38. package/dist/components/composed/PlateMapEditor/PlateZoomControl.js +0 -54
  39. package/dist/components/composed/PlateMapEditor/PlateZoomControl.js.map +0 -1
  40. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs +0 -2
  41. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.cjs.map +0 -1
  42. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js +0 -96
  43. package/dist/components/composed/PlateMapEditor/TemplateIOPanel.js.map +0 -1
  44. package/dist/components/composed/PlateMapEditor/WellLegend.cjs +0 -2
  45. package/dist/components/composed/PlateMapEditor/WellLegend.cjs.map +0 -1
  46. package/dist/components/composed/PlateMapEditor/WellLegend.js +0 -58
  47. package/dist/components/composed/PlateMapEditor/WellLegend.js.map +0 -1
  48. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs +0 -2
  49. package/dist/components/composed/PlateMapEditor/WellManifestTable.cjs.map +0 -1
  50. package/dist/components/composed/PlateMapEditor/WellManifestTable.js +0 -408
  51. package/dist/components/composed/PlateMapEditor/WellManifestTable.js.map +0 -1
  52. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs +0 -2
  53. package/dist/components/composed/PlateMapEditor/WellMetadataForm.cjs.map +0 -1
  54. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js +0 -177
  55. package/dist/components/composed/PlateMapEditor/WellMetadataForm.js.map +0 -1
  56. package/dist/components/composed/PlateMapEditor/autoFill.cjs +0 -2
  57. package/dist/components/composed/PlateMapEditor/autoFill.cjs.map +0 -1
  58. package/dist/components/composed/PlateMapEditor/autoFill.js +0 -41
  59. package/dist/components/composed/PlateMapEditor/autoFill.js.map +0 -1
  60. package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs +0 -4
  61. package/dist/components/composed/PlateMapEditor/csvPlateTriage.cjs.map +0 -1
  62. package/dist/components/composed/PlateMapEditor/csvPlateTriage.js +0 -103
  63. package/dist/components/composed/PlateMapEditor/csvPlateTriage.js.map +0 -1
  64. package/dist/components/composed/PlateMapEditor/helpers.cjs +0 -2
  65. package/dist/components/composed/PlateMapEditor/helpers.cjs.map +0 -1
  66. package/dist/components/composed/PlateMapEditor/helpers.js +0 -11
  67. package/dist/components/composed/PlateMapEditor/helpers.js.map +0 -1
  68. package/dist/components/composed/PlateMapEditor/wellGrid.cjs +0 -2
  69. package/dist/components/composed/PlateMapEditor/wellGrid.cjs.map +0 -1
  70. package/dist/components/composed/PlateMapEditor/wellGrid.js +0 -56
  71. package/dist/components/composed/PlateMapEditor/wellGrid.js.map +0 -1
  72. package/dist/components/ui/popover.cjs +0 -2
  73. package/dist/components/ui/popover.cjs.map +0 -1
  74. package/dist/components/ui/popover.js +0 -45
  75. package/dist/components/ui/popover.js.map +0 -1
@@ -1,136 +0,0 @@
1
- import { jsxs as n, jsx as i, Fragment as C } from "react/jsx-runtime";
2
- import { X as D, Plus as h, ChevronDown as M, Check as z } from "lucide-react";
3
- import { Badge as x } from "../../ui/badge.js";
4
- import { Button as c } from "../../ui/button.js";
5
- import { DropdownMenu as j, DropdownMenuTrigger as G, DropdownMenuContent as T, DropdownMenuGroup as B, DropdownMenuItem as w, DropdownMenuSeparator as S } from "../../ui/dropdown-menu.js";
6
- import { ToggleGroup as $, ToggleGroupItem as F } from "../../ui/toggle-group.js";
7
- import { cn as u } from "../../../lib/utils.js";
8
- function v({ plate: r, selected: l }) {
9
- return /* @__PURE__ */ i(x, { variant: l ? "info" : "outline", className: "max-w-44", children: /* @__PURE__ */ i("span", { className: "truncate", children: r.label ?? r.barcode }) });
10
- }
11
- function J({
12
- plates: r = [],
13
- activePlateId: l,
14
- onPlateChange: s,
15
- onAddPlate: o,
16
- onRemovePlate: b,
17
- addPlateLabel: t = "Add Plate",
18
- removePlateLabel: g = "Remove plate",
19
- label: f = "Plate",
20
- variant: N = "dropdown",
21
- align: y = "start",
22
- side: k = "bottom",
23
- className: m
24
- }) {
25
- const a = r.find((e) => e.id === l) ?? (l ? void 0 : r[0]);
26
- return N === "tabs" ? /* @__PURE__ */ n("div", { className: u("inline-flex flex-wrap items-center gap-1", m), "data-slot": "plate-tabs", children: [
27
- /* @__PURE__ */ i(
28
- $,
29
- {
30
- type: "single",
31
- variant: "outline",
32
- size: "sm",
33
- value: a?.id ?? "",
34
- "aria-label": f,
35
- onValueChange: (e) => {
36
- e && s?.(e);
37
- },
38
- children: r.map((e) => {
39
- const d = e.id === a?.id, p = !!b && r.length > 1;
40
- return /* @__PURE__ */ n("div", { className: "inline-flex items-stretch", children: [
41
- /* @__PURE__ */ n(
42
- F,
43
- {
44
- value: e.id,
45
- disabled: e.disabled || !s,
46
- "aria-label": e.label ?? e.barcode,
47
- className: u(p && "rounded-r-none border-r-0"),
48
- children: [
49
- /* @__PURE__ */ i("span", { className: "truncate", children: e.label ?? e.barcode }),
50
- e.count === void 0 ? null : /* @__PURE__ */ i(x, { variant: d ? "secondary" : "outline", className: "ml-1 h-4 px-1 text-[0.65rem]", children: e.count })
51
- ]
52
- }
53
- ),
54
- p ? /* @__PURE__ */ i(
55
- c,
56
- {
57
- type: "button",
58
- variant: "outline",
59
- size: "icon-sm",
60
- "aria-label": `${g} ${e.label ?? e.barcode}`,
61
- className: "rounded-l-none",
62
- onClick: () => b?.(e.id),
63
- children: /* @__PURE__ */ i(D, { "aria-hidden": !0 })
64
- }
65
- ) : null
66
- ] }, e.id);
67
- })
68
- }
69
- ),
70
- o ? /* @__PURE__ */ i(c, { type: "button", variant: "ghost", size: "icon-sm", "aria-label": t, onClick: () => o(), children: /* @__PURE__ */ i(h, { "aria-hidden": !0 }) }) : null
71
- ] }) : r.length === 0 ? /* @__PURE__ */ n(
72
- c,
73
- {
74
- type: "button",
75
- variant: "outline",
76
- size: "sm",
77
- disabled: !o,
78
- "aria-label": t,
79
- className: u("min-w-28 justify-start", m),
80
- onClick: () => o?.(),
81
- children: [
82
- /* @__PURE__ */ i(h, { "aria-hidden": !0 }),
83
- t
84
- ]
85
- }
86
- ) : /* @__PURE__ */ n(j, { children: [
87
- /* @__PURE__ */ i(G, { asChild: !0, children: /* @__PURE__ */ n(
88
- c,
89
- {
90
- type: "button",
91
- variant: "outline",
92
- size: "sm",
93
- "aria-label": f,
94
- className: u("min-w-36 justify-between", m),
95
- children: [
96
- /* @__PURE__ */ i("span", { className: "flex min-w-0 items-center gap-1.5", children: a ? /* @__PURE__ */ i(v, { plate: a, selected: !0 }) : /* @__PURE__ */ i("span", { children: t }) }),
97
- /* @__PURE__ */ i(M, { "aria-hidden": !0 })
98
- ]
99
- }
100
- ) }),
101
- /* @__PURE__ */ n(T, { align: y, side: k, className: "w-64", children: [
102
- /* @__PURE__ */ i(B, { children: r.map((e) => {
103
- const d = e.id === a?.id;
104
- return /* @__PURE__ */ n(
105
- w,
106
- {
107
- disabled: e.disabled || !s,
108
- onClick: () => s?.(e.id),
109
- children: [
110
- d ? /* @__PURE__ */ i(z, { "aria-hidden": !0 }) : /* @__PURE__ */ i("span", { className: "size-4", "aria-hidden": !0 }),
111
- /* @__PURE__ */ n("span", { className: "flex min-w-0 flex-1 items-center justify-between gap-2", children: [
112
- /* @__PURE__ */ i(v, { plate: e, selected: d }),
113
- e.count === void 0 ? null : /* @__PURE__ */ n("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
114
- e.count,
115
- " wells"
116
- ] })
117
- ] })
118
- ]
119
- },
120
- e.id
121
- );
122
- }) }),
123
- o ? /* @__PURE__ */ n(C, { children: [
124
- /* @__PURE__ */ i(S, {}),
125
- /* @__PURE__ */ n(w, { onClick: () => o(), children: [
126
- /* @__PURE__ */ i(h, { "aria-hidden": !0 }),
127
- t
128
- ] })
129
- ] }) : null
130
- ] })
131
- ] });
132
- }
133
- export {
134
- J as PlateMapPlateSelector
135
- };
136
- //# sourceMappingURL=PlateMapPlateSelector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PlateMapPlateSelector.js","sources":["../../../../src/components/composed/PlateMapEditor/PlateMapPlateSelector.tsx"],"sourcesContent":["import { Check, ChevronDown, Plus, X } from \"lucide-react\";\n\nimport type { PlateMapPlateOption } from \"./types\";\n\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\";\nimport { cn } from \"@/lib/utils\";\n\nexport type PlateMapPlateSelectorVariant = \"dropdown\" | \"tabs\";\n\nexport interface PlateMapPlateSelectorProps {\n plates?: PlateMapPlateOption[];\n activePlateId?: string;\n onPlateChange?: (plateId: string) => void;\n onAddPlate?: () => void;\n /** When supplied, the tabs variant renders a delete affordance per plate. */\n onRemovePlate?: (plateId: string) => void;\n addPlateLabel?: string;\n removePlateLabel?: string;\n label?: string;\n /** Layout. `\"dropdown\"` is the default single-trigger menu, `\"tabs\"` is a horizontal tab strip. */\n variant?: PlateMapPlateSelectorVariant;\n align?: \"start\" | \"center\" | \"end\";\n side?: \"top\" | \"right\" | \"bottom\" | \"left\";\n className?: string;\n}\n\nfunction PlatePill({ plate, selected }: { plate: PlateMapPlateOption; selected?: boolean }) {\n return (\n <Badge variant={selected ? \"info\" : \"outline\"} className=\"max-w-44\">\n <span className=\"truncate\">{plate.label ?? plate.barcode}</span>\n </Badge>\n );\n}\n\nexport function PlateMapPlateSelector({\n plates = [],\n activePlateId,\n onPlateChange,\n onAddPlate,\n onRemovePlate,\n addPlateLabel = \"Add Plate\",\n removePlateLabel = \"Remove plate\",\n label = \"Plate\",\n variant = \"dropdown\",\n align = \"start\",\n side = \"bottom\",\n className,\n}: PlateMapPlateSelectorProps) {\n const activePlate = plates.find((plate) => plate.id === activePlateId) ?? (activePlateId ? undefined : plates[0]);\n\n if (variant === \"tabs\") {\n return (\n <div className={cn(\"inline-flex flex-wrap items-center gap-1\", className)} data-slot=\"plate-tabs\">\n <ToggleGroup\n type=\"single\"\n variant=\"outline\"\n size=\"sm\"\n value={activePlate?.id ?? \"\"}\n aria-label={label}\n onValueChange={(value) => {\n if (value) onPlateChange?.(value);\n }}\n >\n {plates.map((plate) => {\n const selected = plate.id === activePlate?.id;\n const canRemove = !!onRemovePlate && plates.length > 1;\n return (\n <div key={plate.id} className=\"inline-flex items-stretch\">\n <ToggleGroupItem\n value={plate.id}\n disabled={plate.disabled || !onPlateChange}\n aria-label={plate.label ?? plate.barcode}\n className={cn(canRemove && \"rounded-r-none border-r-0\")}\n >\n <span className=\"truncate\">{plate.label ?? plate.barcode}</span>\n {plate.count === undefined ? null : (\n <Badge variant={selected ? \"secondary\" : \"outline\"} className=\"ml-1 h-4 px-1 text-[0.65rem]\">\n {plate.count}\n </Badge>\n )}\n </ToggleGroupItem>\n {canRemove ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"icon-sm\"\n aria-label={`${removePlateLabel} ${plate.label ?? plate.barcode}`}\n className=\"rounded-l-none\"\n onClick={() => onRemovePlate?.(plate.id)}\n >\n <X aria-hidden />\n </Button>\n ) : null}\n </div>\n );\n })}\n </ToggleGroup>\n {onAddPlate ? (\n <Button type=\"button\" variant=\"ghost\" size=\"icon-sm\" aria-label={addPlateLabel} onClick={() => onAddPlate()}>\n <Plus aria-hidden />\n </Button>\n ) : null}\n </div>\n );\n }\n\n if (plates.length === 0) {\n return (\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={!onAddPlate}\n aria-label={addPlateLabel}\n className={cn(\"min-w-28 justify-start\", className)}\n onClick={() => onAddPlate?.()}\n >\n <Plus aria-hidden />\n {addPlateLabel}\n </Button>\n );\n }\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-label={label}\n className={cn(\"min-w-36 justify-between\", className)}\n >\n <span className=\"flex min-w-0 items-center gap-1.5\">\n {activePlate ? <PlatePill plate={activePlate} selected /> : <span>{addPlateLabel}</span>}\n </span>\n <ChevronDown aria-hidden />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align={align} side={side} className=\"w-64\">\n <DropdownMenuGroup>\n {plates.map((plate) => {\n const selected = plate.id === activePlate?.id;\n return (\n <DropdownMenuItem\n key={plate.id}\n disabled={plate.disabled || !onPlateChange}\n onClick={() => onPlateChange?.(plate.id)}\n >\n {selected ? <Check aria-hidden /> : <span className=\"size-4\" aria-hidden />}\n <span className=\"flex min-w-0 flex-1 items-center justify-between gap-2\">\n <PlatePill plate={plate} selected={selected} />\n {plate.count === undefined ? null : (\n <span className=\"shrink-0 text-xs text-muted-foreground\">{plate.count} wells</span>\n )}\n </span>\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuGroup>\n {onAddPlate ? (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem onClick={() => onAddPlate()}>\n <Plus aria-hidden />\n {addPlateLabel}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"names":["PlatePill","plate","selected","Badge","jsx","PlateMapPlateSelector","plates","activePlateId","onPlateChange","onAddPlate","onRemovePlate","addPlateLabel","removePlateLabel","label","variant","align","side","className","activePlate","jsxs","cn","ToggleGroup","value","canRemove","ToggleGroupItem","Button","X","Plus","DropdownMenu","DropdownMenuTrigger","ChevronDown","DropdownMenuContent","DropdownMenuGroup","DropdownMenuItem","Check","Fragment","DropdownMenuSeparator"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react/jsx-runtime"),_e=require("react"),v=require("./wellGrid.cjs"),ee=require("../../../lib/utils.cjs");function ye(n){const l=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const o in n)if(o!=="default"){const s=Object.getOwnPropertyDescriptor(n,o);Object.defineProperty(l,o,s.get?s:{enumerable:!0,get:()=>n[o]})}}return l.default=n,Object.freeze(l)}const L=ye(_e),we=34,be=24,xe=72,Ae=36,c=26,X=12,Me=1,oe=16,Pe=9,Te=5,N=1,z=4,te=4,Oe=3,se=5,q=650,ne="var(--surface-container)",le="var(--border)";function Re(n,l){const o=[];for(let s=0;s<n;s++)o.push(u.jsx("text",{x:c+s*l+l/2,y:c/2,textAnchor:"middle",fontSize:oe,className:"fill-muted-foreground",children:s+1},`c${s}`));return o}function je(n,l){const o=[];for(let s=0;s<n;s++)o.push(u.jsx("text",{x:c-Pe,y:c+s*l+l/2+Te,textAnchor:"end",fontSize:oe,className:"fill-muted-foreground",children:v.rowLabel(s)},`r${s}`));return o}function ke(n,l,o){const{dims:s,cellSize:e,values:E,selection:P,dragPositions:_,colorForWell:d,emptyWellFillColor:h,selectedFillColor:y,selectedFillOpacity:b,selectionFillMode:O,wellShape:m}=n,p=v.pos(l,o,s.columns),x=E.get(p),w=P.has(p)||_.has(p),k=x===void 0&&h!==null?h:d(x,p),T=w&&!(w&&O==="well"&&x!==void 0),R=T?y:k,j=T?b:void 0;if(m==="circle"){const F=c+o*e+e/2,A=c+l*e+e/2,S=e/2-N;return u.jsx("circle",{cx:F,cy:A,r:S,fill:R,fillOpacity:j,stroke:"none","data-well":p,"data-selected":w?"true":void 0},p)}return u.jsx("rect",{x:c+o*e,y:c+l*e,width:e,height:e,fill:R,fillOpacity:j,stroke:"none","data-well":p,"data-selected":w?"true":void 0},p)}function Fe({dims:n,...l}){const o=[];for(let s=0;s<n.rows;s++)for(let e=0;e<n.columns;e++)o.push(ke({dims:n,...l},s,e));return o}function Se(n,l,o){const s=[],e=c,E=c,P=c+n.columns*l,_=c+n.rows*l;for(let d=0;d<=n.columns;d++){const h=c+d*l;s.push(u.jsx("line",{x1:h,y1:E,x2:h,y2:_,stroke:o,strokeWidth:z,vectorEffect:"non-scaling-stroke",shapeRendering:"crispEdges",pointerEvents:"none","data-plate-grid-line":`column-${d}`},`grid-col-${d}`))}for(let d=0;d<=n.rows;d++){const h=c+d*l;s.push(u.jsx("line",{x1:e,y1:h,x2:P,y2:h,stroke:o,strokeWidth:z,vectorEffect:"non-scaling-stroke",shapeRendering:"crispEdges",pointerEvents:"none","data-plate-grid-line":`row-${d}`},`grid-row-${d}`))}return s}function De(n,l,o){const{dims:s,cellSize:e,selection:E,dragPositions:P,selectedBorderColor:_,flashWellId:d,flashWellKey:h,wellShape:y,highlightedWellIds:b,highlightBorderColor:O}=n,m=v.pos(l,o,s.columns),p=E.has(m)||P.has(m),x=d===m,w=!p&&b.has(m);if(!p&&!x&&!w)return null;const k=c+o*e+N,I=c+l*e+N,T=e-N*2,R=c+o*e+e/2,j=c+l*e+e/2,F=e/2-N,A=y==="circle",S=A?{cx:R,cy:j,r:F}:{x:k,y:I,width:T,height:T},M=(r,D,C)=>{const a={...S,...r,pointerEvents:"none"};return A?u.jsx("circle",{...a,children:D},C):u.jsx("rect",{...a,children:D},C)},$=u.jsxs(u.Fragment,{children:[u.jsx("animate",{attributeName:"fill-opacity",values:"0.24;0.1;0",dur:`${q}ms`,fill:"freeze"}),u.jsx("animate",{attributeName:"stroke-opacity",values:"0.92;0.42;0",dur:`${q}ms`,fill:"freeze"}),u.jsx("animate",{attributeName:"stroke-width",values:`${se};${te}`,dur:`${q}ms`,fill:"freeze"})]});return u.jsxs("g",{children:[p?M({fill:"none",stroke:_,strokeWidth:te,"data-well-selection":m}):null,w?M({fill:"none",stroke:O,strokeWidth:Oe,"data-well-highlight":m}):null,x?M({fill:_,fillOpacity:.24,stroke:_,strokeOpacity:.92,strokeWidth:se,"data-well-flash":m},$,`${m}-${h}`):null]},`overlay-${m}`)}function Ce({dims:n,...l}){const o=[];for(let s=0;s<n.rows;s++)for(let e=0;e<n.columns;e++){const E=De({dims:n,...l},s,e);E&&o.push(E)}return o}function We({format:n,rows:l,columns:o,values:s,selection:e,onSelectionChange:E,colorForWell:P,emptyWellFillColor:_=ne,wellShape:d="rect",framed:h=!1,cellSize:y,autoScale:b=!0,minCellSize:O=be,maxCellSize:m,borderColor:p=le,selectedBorderColor:x="var(--color-primary)",selectedFillColor:w="var(--color-primary)",selectedFillOpacity:k=.18,selectionFillMode:I="selection",flashWellId:T,flashWellKey:R,highlightedWellIds:j,highlightBorderColor:F="var(--color-primary)",onWellHover:A,onWellDoubleClick:S,wrapWell:M,className:$}){const r=v.resolveDimensions(n,l,o),D=L.useRef(null),C=L.useRef(null),[a,B]=L.useState(null),[U,re]=L.useState();L.useLayoutEffect(()=>{const i=D.current;if(!i||!b||y!==void 0)return;const t=()=>re(i.clientWidth);if(t(),typeof ResizeObserver>"u")return;const f=new ResizeObserver(t);return f.observe(i),()=>f.disconnect()},[b,y]);const g=L.useMemo(()=>{if(!b||y!==void 0||!U)return y??we;const i=m??(r.columns>12?Ae:xe),t=h?(X+Me)*2:0,f=Math.floor((U-c-t)/r.columns);return Math.max(O,Math.min(i,f))},[b,y,U,r.columns,h,m,O]),G=L.useCallback(i=>{const t=C.current;if(!t)return null;const f=t.getBoundingClientRect(),W=i.clientX-f.left-c,ve=i.clientY-f.top-c,H=Math.floor(W/g),K=Math.floor(ve/g);return K<0||K>=r.rows||H<0||H>=r.columns?null:{r:K,c:H}},[g,r.rows,r.columns]),ce=i=>{const t=G(i);if(!t)return;const f=i.shiftKey?"add":i.altKey?"remove":"replace";B({start:t,cur:t,mode:f})},ie=i=>{const t=G(i);t&&A&&A(v.pos(t.r,t.c,r.columns)),!(!a||!t)&&B({...a,cur:t})},Y=L.useCallback(()=>{if(!a)return;const i=v.rectPositions(a.start.r,a.start.c,a.cur.r,a.cur.c,r.columns);let t;a.mode==="replace"?t=new Set(i):a.mode==="add"?(t=new Set(e),i.forEach(f=>t.add(f))):(t=new Set(e),i.forEach(f=>t.delete(f))),E(t),B(null)},[a,r.columns,E,e]),ae=()=>Y(),ue=()=>{Y(),A?.(null)},de=i=>{const t=G(i);t&&S?.(v.pos(t.r,t.c,r.columns))},fe=L.useMemo(()=>a?new Set(v.rectPositions(a.start.r,a.start.c,a.cur.r,a.cur.c,r.columns)):new Set,[a,r.columns]),Z=z,J=r.columns*g+c+Z,Q=r.rows*g+c+Z,he=Re(r.columns,g),pe=je(r.rows,g),V={dims:r,cellSize:g,values:s,selection:e,dragPositions:fe,colorForWell:P,emptyWellFillColor:_,borderColor:p,selectedBorderColor:x,selectedFillColor:w,selectedFillOpacity:k,selectionFillMode:I,wellShape:d,highlightedWellIds:j??new Set,highlightBorderColor:F,flashWellId:T,flashWellKey:R},ge=Fe(V),me=d==="circle"?[]:Se(r,g,p),Ee=Ce(V),Le=L.useMemo(()=>{if(!M)return[];const i=[];for(let t=0;t<r.rows;t++)for(let f=0;f<r.columns;f++){const W=v.pos(t,f,r.columns);i.push(u.jsx("div",{style:{position:"absolute",left:c+f*g,top:c+t*g,width:g,height:g},"data-well-id":W,children:M(W,g)},W))}return i},[M,r.rows,r.columns,g]);return u.jsx("div",{ref:D,className:ee.cn("relative w-full select-none",$),"data-slot":"plate-paint-grid",children:u.jsxs("div",{className:ee.cn("relative inline-block",h&&"rounded-xl border bg-card p-3 shadow-sm"),"data-slot":"plate-paint-grid-frame",children:[u.jsxs("svg",{ref:C,width:J,height:Q,className:"block cursor-crosshair",onMouseDown:ce,onMouseMove:ie,onMouseUp:ae,onMouseLeave:ue,onDoubleClick:de,role:"group","aria-label":`${r.rows} row by ${r.columns} column plate map. Drag to select wells.`,children:[he,pe,ge,me,Ee]}),M?u.jsx("div",{className:"pointer-events-none absolute",style:{top:h?X:0,left:h?X:0,width:J,height:Q},"aria-hidden":!0,"data-slot":"plate-well-overlay",children:Le}):null]})})}exports.parsePos=v.parsePos;exports.PLATE_MAP_CELL_BORDER=le;exports.PLATE_MAP_EMPTY_WELL_FILL=ne;exports.PlatePaintGrid=We;
2
- //# sourceMappingURL=PlatePaintGrid.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PlatePaintGrid.cjs","sources":["../../../../src/components/composed/PlateMapEditor/PlatePaintGrid.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { parsePos, pos, rectPositions, resolveDimensions, rowLabel } from \"./wellGrid\";\n\nimport type { PlateDimensions, PlateFormat, WellId, WellRecord } from \"./types\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst DEFAULT_CELL = 34;\nconst DEFAULT_MIN_AUTO_CELL = 24;\nconst DEFAULT_MAX_AUTO_CELL = 72;\nconst DEFAULT_MAX_DENSE_AUTO_CELL = 36;\nconst LABEL_PAD = 26;\nconst FRAME_PADDING_PX = 12;\nconst FRAME_BORDER_PX = 1;\nconst LABEL_FONT_SIZE = 16;\nconst LABEL_TEXT_INSET = 9;\nconst LABEL_BASELINE_OFFSET = 5;\nconst WELL_INSET = 1;\nconst STROKE_DEFAULT = 4;\nconst STROKE_SELECTED = 4;\nconst STROKE_HIGHLIGHT = 3;\nconst STROKE_FLASH = 5;\nconst FLASH_DURATION_MS = 650;\nexport const PLATE_MAP_EMPTY_WELL_FILL = \"var(--surface-container)\";\nexport const PLATE_MAP_CELL_BORDER = \"var(--border)\";\n\nexport type WellShape = \"rect\" | \"circle\";\n\nexport interface PlatePaintGridProps<T extends WellRecord = WellRecord> {\n format: PlateFormat;\n rows?: number;\n columns?: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n onSelectionChange: (next: Set<WellId>) => void;\n /** Returns the fill color for a given well record (or undefined if empty). */\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n /** Fill color for empty wells. Pass `null` to delegate empty wells to `colorForWell`. */\n emptyWellFillColor?: string | null;\n /** Geometric shape of each well. `\"circle\"` matches scientific plate visuals. Defaults to `\"rect\"`. */\n wellShape?: WellShape;\n /**\n * When true, wraps the grid in a card-like surface (rounded, bordered,\n * padded, soft shadow) so it reads as a physical plate. Pairs well with\n * `wellShape=\"circle\"`.\n */\n framed?: boolean;\n /** Pixel size of each well cell. Defaults to 34 when fixed. */\n cellSize?: number;\n /** Resize wells to fill available width when `cellSize` is not fixed. */\n autoScale?: boolean;\n minCellSize?: number;\n /** Defaults to 72 for 96-well style plates and 36 for denser plates. */\n maxCellSize?: number;\n /** Stroke color for non-selected wells. Defaults to a light border. */\n borderColor?: string;\n /** Stroke color for selected wells. Defaults to the kit primary blue. */\n selectedBorderColor?: string;\n /** Fill color for selected wells. Defaults to the kit primary blue. */\n selectedFillColor?: string;\n /** Selected fill opacity. */\n selectedFillOpacity?: number;\n /** Whether selected wells use the selection fill or keep their assigned well color. */\n selectionFillMode?: \"selection\" | \"well\";\n /** Well id that should briefly flash, usually after a double-click assignment. */\n flashWellId?: WellId;\n /** Changing this value restarts the flash animation for the same well. */\n flashWellKey?: number;\n /**\n * Well ids that should render with a highlight ring. Used for cross-component\n * hover sync (e.g. hovering a legend item to highlight matching wells).\n */\n highlightedWellIds?: ReadonlySet<WellId>;\n /** Stroke color for highlighted wells. Defaults to the kit primary blue. */\n highlightBorderColor?: string;\n onWellHover?: (wellId: WellId | null) => void;\n onWellDoubleClick?: (wellId: WellId) => void;\n /**\n * Optional render-prop invoked once per well. The returned node is placed\n * inside an absolutely-positioned cell on top of the SVG, sized to\n * `cellSize`. The wrapper layer is `pointer-events: none` so the SVG keeps\n * pointer interaction by default; consumers wiring drop targets are expected\n * to set `pointer-events: auto` on their own element while a drag is active.\n */\n wrapWell?: (wellId: WellId, cellSize: number) => React.ReactNode;\n className?: string;\n}\n\ntype DragMode = \"replace\" | \"add\" | \"remove\";\n\ninterface DragState {\n start: { r: number; c: number };\n cur: { r: number; c: number };\n mode: DragMode;\n}\n\nfunction buildColumnLabels(columns: number, cellSize: number): React.ReactNode[] {\n const labels: React.ReactNode[] = [];\n for (let c = 0; c < columns; c++) {\n labels.push(\n <text\n key={`c${c}`}\n x={LABEL_PAD + c * cellSize + cellSize / 2}\n y={LABEL_PAD / 2}\n textAnchor=\"middle\"\n fontSize={LABEL_FONT_SIZE}\n className=\"fill-muted-foreground\"\n >\n {c + 1}\n </text>,\n );\n }\n return labels;\n}\n\nfunction buildRowLabels(rows: number, cellSize: number): React.ReactNode[] {\n const labels: React.ReactNode[] = [];\n for (let r = 0; r < rows; r++) {\n labels.push(\n <text\n key={`r${r}`}\n x={LABEL_PAD - LABEL_TEXT_INSET}\n y={LABEL_PAD + r * cellSize + cellSize / 2 + LABEL_BASELINE_OFFSET}\n textAnchor=\"end\"\n fontSize={LABEL_FONT_SIZE}\n className=\"fill-muted-foreground\"\n >\n {rowLabel(r)}\n </text>,\n );\n }\n return labels;\n}\n\ninterface BuildWellCellsArgs<T extends WellRecord> {\n dims: PlateDimensions;\n cellSize: number;\n values: Map<WellId, T>;\n selection: Set<WellId>;\n dragPositions: Set<WellId>;\n colorForWell: (well: T | undefined, wellId: WellId) => string;\n emptyWellFillColor: string | null;\n borderColor: string;\n selectedBorderColor: string;\n selectedFillColor: string;\n selectedFillOpacity: number;\n selectionFillMode: \"selection\" | \"well\";\n wellShape: WellShape;\n highlightedWellIds: ReadonlySet<WellId>;\n highlightBorderColor: string;\n flashWellId?: WellId;\n flashWellKey?: number;\n}\n\nfunction buildWellCell<T extends WellRecord>(\n args: BuildWellCellsArgs<T>,\n row: number,\n column: number,\n): React.ReactNode {\n const {\n dims,\n cellSize,\n values,\n selection,\n dragPositions,\n colorForWell,\n emptyWellFillColor,\n selectedFillColor,\n selectedFillOpacity,\n selectionFillMode,\n wellShape,\n } = args;\n const id = pos(row, column, dims.columns);\n const entry = values.get(id);\n const isSelected = selection.has(id) || dragPositions.has(id);\n const wellFill = entry === undefined && emptyWellFillColor !== null ? emptyWellFillColor : colorForWell(entry, id);\n const usesWellFill = isSelected && selectionFillMode === \"well\" && entry !== undefined;\n const usesSelectionFill = isSelected && !usesWellFill;\n const fill = usesSelectionFill ? selectedFillColor : wellFill;\n const fillOpacity = usesSelectionFill ? selectedFillOpacity : undefined;\n\n if (wellShape === \"circle\") {\n const cx = LABEL_PAD + column * cellSize + cellSize / 2;\n const cy = LABEL_PAD + row * cellSize + cellSize / 2;\n const r = cellSize / 2 - WELL_INSET;\n return (\n <circle\n key={id}\n cx={cx}\n cy={cy}\n r={r}\n fill={fill}\n fillOpacity={fillOpacity}\n stroke=\"none\"\n data-well={id}\n data-selected={isSelected ? \"true\" : undefined}\n />\n );\n }\n\n return (\n <rect\n key={id}\n x={LABEL_PAD + column * cellSize}\n y={LABEL_PAD + row * cellSize}\n width={cellSize}\n height={cellSize}\n fill={fill}\n fillOpacity={fillOpacity}\n stroke=\"none\"\n data-well={id}\n data-selected={isSelected ? \"true\" : undefined}\n />\n );\n}\n\nfunction buildWellCells<T extends WellRecord>({ dims, ...args }: BuildWellCellsArgs<T>): React.ReactNode[] {\n const cells: React.ReactNode[] = [];\n for (let r = 0; r < dims.rows; r++) {\n for (let c = 0; c < dims.columns; c++) {\n cells.push(buildWellCell({ dims, ...args }, r, c));\n }\n }\n return cells;\n}\n\nfunction buildGridLines(dims: PlateDimensions, cellSize: number, borderColor: string): React.ReactNode[] {\n const lines: React.ReactNode[] = [];\n const left = LABEL_PAD;\n const top = LABEL_PAD;\n const right = LABEL_PAD + dims.columns * cellSize;\n const bottom = LABEL_PAD + dims.rows * cellSize;\n\n for (let c = 0; c <= dims.columns; c++) {\n const x = LABEL_PAD + c * cellSize;\n lines.push(\n <line\n key={`grid-col-${c}`}\n x1={x}\n y1={top}\n x2={x}\n y2={bottom}\n stroke={borderColor}\n strokeWidth={STROKE_DEFAULT}\n vectorEffect=\"non-scaling-stroke\"\n shapeRendering=\"crispEdges\"\n pointerEvents=\"none\"\n data-plate-grid-line={`column-${c}`}\n />,\n );\n }\n\n for (let r = 0; r <= dims.rows; r++) {\n const y = LABEL_PAD + r * cellSize;\n lines.push(\n <line\n key={`grid-row-${r}`}\n x1={left}\n y1={y}\n x2={right}\n y2={y}\n stroke={borderColor}\n strokeWidth={STROKE_DEFAULT}\n vectorEffect=\"non-scaling-stroke\"\n shapeRendering=\"crispEdges\"\n pointerEvents=\"none\"\n data-plate-grid-line={`row-${r}`}\n />,\n );\n }\n\n return lines;\n}\n\nfunction buildWellOverlay<T extends WellRecord>(\n args: BuildWellCellsArgs<T>,\n row: number,\n column: number,\n): React.ReactNode {\n const {\n dims,\n cellSize,\n selection,\n dragPositions,\n selectedBorderColor,\n flashWellId,\n flashWellKey,\n wellShape,\n highlightedWellIds,\n highlightBorderColor,\n } = args;\n const id = pos(row, column, dims.columns);\n const isSelected = selection.has(id) || dragPositions.has(id);\n const isFlashing = flashWellId === id;\n const isHighlighted = !isSelected && highlightedWellIds.has(id);\n\n if (!isSelected && !isFlashing && !isHighlighted) return null;\n\n const x = LABEL_PAD + column * cellSize + WELL_INSET;\n const y = LABEL_PAD + row * cellSize + WELL_INSET;\n const size = cellSize - WELL_INSET * 2;\n const cx = LABEL_PAD + column * cellSize + cellSize / 2;\n const cy = LABEL_PAD + row * cellSize + cellSize / 2;\n const r = cellSize / 2 - WELL_INSET;\n const isCircle = wellShape === \"circle\";\n\n type WellShapeProps = Record<string, string | number | undefined>;\n const shapeProps: WellShapeProps = isCircle\n ? { cx, cy, r }\n : { x, y, width: size, height: size };\n\n const renderShape = (\n extraProps: Record<string, string | number | undefined>,\n children?: React.ReactNode,\n elementKey?: string | number,\n ): React.ReactNode => {\n const props = { ...shapeProps, ...extraProps, pointerEvents: \"none\" as const };\n return isCircle ? (\n <circle key={elementKey} {...props}>\n {children}\n </circle>\n ) : (\n <rect key={elementKey} {...props}>\n {children}\n </rect>\n );\n };\n\n const flashAnimations = (\n <>\n <animate attributeName=\"fill-opacity\" values=\"0.24;0.1;0\" dur={`${FLASH_DURATION_MS}ms`} fill=\"freeze\" />\n <animate attributeName=\"stroke-opacity\" values=\"0.92;0.42;0\" dur={`${FLASH_DURATION_MS}ms`} fill=\"freeze\" />\n <animate\n attributeName=\"stroke-width\"\n values={`${STROKE_FLASH};${STROKE_SELECTED}`}\n dur={`${FLASH_DURATION_MS}ms`}\n fill=\"freeze\"\n />\n </>\n );\n\n return (\n <g key={`overlay-${id}`}>\n {isSelected\n ? renderShape({\n fill: \"none\",\n stroke: selectedBorderColor,\n strokeWidth: STROKE_SELECTED,\n \"data-well-selection\": id,\n })\n : null}\n {isHighlighted\n ? renderShape({\n fill: \"none\",\n stroke: highlightBorderColor,\n strokeWidth: STROKE_HIGHLIGHT,\n \"data-well-highlight\": id,\n })\n : null}\n {isFlashing\n ? renderShape(\n {\n fill: selectedBorderColor,\n fillOpacity: 0.24,\n stroke: selectedBorderColor,\n strokeOpacity: 0.92,\n strokeWidth: STROKE_FLASH,\n \"data-well-flash\": id,\n },\n flashAnimations,\n `${id}-${flashWellKey}`,\n )\n : null}\n </g>\n );\n}\n\nfunction buildWellOverlays<T extends WellRecord>({ dims, ...args }: BuildWellCellsArgs<T>): React.ReactNode[] {\n const overlays: React.ReactNode[] = [];\n for (let r = 0; r < dims.rows; r++) {\n for (let c = 0; c < dims.columns; c++) {\n const overlay = buildWellOverlay({ dims, ...args }, r, c);\n if (overlay) overlays.push(overlay);\n }\n }\n return overlays;\n}\n\n/**\n * Interactive plate grid with drag-rectangle selection.\n * - Click & drag: replace selection\n * - Shift + drag: add to selection\n * - Alt + drag: remove from selection\n */\nexport function PlatePaintGrid<T extends WellRecord = WellRecord>({\n format,\n rows,\n columns,\n values,\n selection,\n onSelectionChange,\n colorForWell,\n emptyWellFillColor = PLATE_MAP_EMPTY_WELL_FILL,\n wellShape = \"rect\",\n framed = false,\n cellSize,\n autoScale = true,\n minCellSize = DEFAULT_MIN_AUTO_CELL,\n maxCellSize,\n borderColor = PLATE_MAP_CELL_BORDER,\n selectedBorderColor = \"var(--color-primary)\",\n selectedFillColor = \"var(--color-primary)\",\n selectedFillOpacity = 0.18,\n selectionFillMode = \"selection\",\n flashWellId,\n flashWellKey,\n highlightedWellIds,\n highlightBorderColor = \"var(--color-primary)\",\n onWellHover,\n onWellDoubleClick,\n wrapWell,\n className,\n}: PlatePaintGridProps<T>) {\n const dims = resolveDimensions(format, rows, columns);\n const containerRef = React.useRef<HTMLDivElement>(null);\n const svgRef = React.useRef<SVGSVGElement>(null);\n const [drag, setDrag] = React.useState<DragState | null>(null);\n const [containerWidth, setContainerWidth] = React.useState<number>();\n\n React.useLayoutEffect(() => {\n const node = containerRef.current;\n if (!node || !autoScale || cellSize !== undefined) return;\n\n const update = () => setContainerWidth(node.clientWidth);\n update();\n\n if (typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver(update);\n observer.observe(node);\n return () => observer.disconnect();\n }, [autoScale, cellSize]);\n\n const resolvedCellSize = React.useMemo(() => {\n if (!autoScale || cellSize !== undefined || !containerWidth) {\n return cellSize ?? DEFAULT_CELL;\n }\n const autoMaxCellSize = maxCellSize ?? (dims.columns > 12 ? DEFAULT_MAX_DENSE_AUTO_CELL : DEFAULT_MAX_AUTO_CELL);\n const frameAdjust = framed ? (FRAME_PADDING_PX + FRAME_BORDER_PX) * 2 : 0;\n const fitSize = Math.floor((containerWidth - LABEL_PAD - frameAdjust) / dims.columns);\n return Math.max(minCellSize, Math.min(autoMaxCellSize, fitSize));\n }, [autoScale, cellSize, containerWidth, dims.columns, framed, maxCellSize, minCellSize]);\n\n const cellAt = React.useCallback(\n (evt: React.MouseEvent): { r: number; c: number } | null => {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n const x = evt.clientX - rect.left - LABEL_PAD;\n const y = evt.clientY - rect.top - LABEL_PAD;\n const c = Math.floor(x / resolvedCellSize);\n const r = Math.floor(y / resolvedCellSize);\n if (r < 0 || r >= dims.rows || c < 0 || c >= dims.columns) return null;\n return { r, c };\n },\n [resolvedCellSize, dims.rows, dims.columns],\n );\n\n const handleDown = (e: React.MouseEvent) => {\n const cell = cellAt(e);\n if (!cell) return;\n const mode: DragMode = e.shiftKey ? \"add\" : e.altKey ? \"remove\" : \"replace\";\n setDrag({ start: cell, cur: cell, mode });\n };\n\n const handleMove = (e: React.MouseEvent) => {\n const cell = cellAt(e);\n if (cell && onWellHover) {\n onWellHover(pos(cell.r, cell.c, dims.columns));\n }\n if (!drag || !cell) return;\n setDrag({ ...drag, cur: cell });\n };\n\n const commitDrag = React.useCallback(() => {\n if (!drag) return;\n const positions = rectPositions(drag.start.r, drag.start.c, drag.cur.r, drag.cur.c, dims.columns);\n let next: Set<WellId>;\n if (drag.mode === \"replace\") {\n next = new Set(positions);\n } else if (drag.mode === \"add\") {\n next = new Set(selection);\n positions.forEach((p) => next.add(p));\n } else {\n next = new Set(selection);\n positions.forEach((p) => next.delete(p));\n }\n onSelectionChange(next);\n setDrag(null);\n }, [drag, dims.columns, onSelectionChange, selection]);\n\n const handleUp = () => commitDrag();\n const handleLeave = () => {\n commitDrag();\n onWellHover?.(null);\n };\n const handleDoubleClick = (e: React.MouseEvent) => {\n const cell = cellAt(e);\n if (!cell) return;\n onWellDoubleClick?.(pos(cell.r, cell.c, dims.columns));\n };\n\n const dragPositions = React.useMemo(() => {\n if (!drag) return new Set<WellId>();\n return new Set(rectPositions(drag.start.r, drag.start.c, drag.cur.r, drag.cur.c, dims.columns));\n }, [drag, dims.columns]);\n\n // Right and bottom edge strokes sit on the plate boundary; give the SVG room so they are not clipped.\n const edgeStrokePadding = STROKE_DEFAULT;\n const width = dims.columns * resolvedCellSize + LABEL_PAD + edgeStrokePadding;\n const height = dims.rows * resolvedCellSize + LABEL_PAD + edgeStrokePadding;\n\n const colLabels = buildColumnLabels(dims.columns, resolvedCellSize);\n const rowLabels = buildRowLabels(dims.rows, resolvedCellSize);\n const resolvedHighlightedWellIds: ReadonlySet<WellId> = highlightedWellIds ?? new Set();\n const wellRenderArgs = {\n dims,\n cellSize: resolvedCellSize,\n values,\n selection,\n dragPositions,\n colorForWell,\n emptyWellFillColor,\n borderColor,\n selectedBorderColor,\n selectedFillColor,\n selectedFillOpacity,\n selectionFillMode,\n wellShape,\n highlightedWellIds: resolvedHighlightedWellIds,\n highlightBorderColor,\n flashWellId,\n flashWellKey,\n };\n const wellCells = buildWellCells(wellRenderArgs);\n const gridLines = wellShape === \"circle\" ? [] : buildGridLines(dims, resolvedCellSize, borderColor);\n const wellOverlays = buildWellOverlays(wellRenderArgs);\n\n const overlayCells = React.useMemo<React.ReactNode[]>(() => {\n if (!wrapWell) return [];\n const cells: React.ReactNode[] = [];\n for (let r = 0; r < dims.rows; r++) {\n for (let c = 0; c < dims.columns; c++) {\n const id = pos(r, c, dims.columns);\n cells.push(\n <div\n key={id}\n style={{\n position: \"absolute\",\n left: LABEL_PAD + c * resolvedCellSize,\n top: LABEL_PAD + r * resolvedCellSize,\n width: resolvedCellSize,\n height: resolvedCellSize,\n }}\n data-well-id={id}\n >\n {wrapWell(id, resolvedCellSize)}\n </div>,\n );\n }\n }\n return cells;\n }, [wrapWell, dims.rows, dims.columns, resolvedCellSize]);\n\n return (\n <div\n ref={containerRef}\n className={cn(\"relative w-full select-none\", className)}\n data-slot=\"plate-paint-grid\"\n >\n <div\n className={cn(\n \"relative inline-block\",\n framed && \"rounded-xl border bg-card p-3 shadow-sm\",\n )}\n data-slot=\"plate-paint-grid-frame\"\n >\n <svg\n ref={svgRef}\n width={width}\n height={height}\n className=\"block cursor-crosshair\"\n onMouseDown={handleDown}\n onMouseMove={handleMove}\n onMouseUp={handleUp}\n onMouseLeave={handleLeave}\n onDoubleClick={handleDoubleClick}\n role=\"group\"\n aria-label={`${dims.rows} row by ${dims.columns} column plate map. Drag to select wells.`}\n >\n {colLabels}\n {rowLabels}\n {wellCells}\n {gridLines}\n {wellOverlays}\n </svg>\n {wrapWell ? (\n <div\n className=\"pointer-events-none absolute\"\n style={{\n top: framed ? FRAME_PADDING_PX : 0,\n left: framed ? FRAME_PADDING_PX : 0,\n width,\n height,\n }}\n aria-hidden\n data-slot=\"plate-well-overlay\"\n >\n {overlayCells}\n </div>\n ) : null}\n </div>\n </div>\n );\n}\n\nexport { parsePos };\n"],"names":["DEFAULT_CELL","DEFAULT_MIN_AUTO_CELL","DEFAULT_MAX_AUTO_CELL","DEFAULT_MAX_DENSE_AUTO_CELL","LABEL_PAD","FRAME_PADDING_PX","FRAME_BORDER_PX","LABEL_FONT_SIZE","LABEL_TEXT_INSET","LABEL_BASELINE_OFFSET","WELL_INSET","STROKE_DEFAULT","STROKE_SELECTED","STROKE_HIGHLIGHT","STROKE_FLASH","FLASH_DURATION_MS","PLATE_MAP_EMPTY_WELL_FILL","PLATE_MAP_CELL_BORDER","buildColumnLabels","columns","cellSize","labels","c","jsx","buildRowLabels","rows","r","buildWellCell","args","row","column","dims","values","selection","dragPositions","colorForWell","emptyWellFillColor","selectedFillColor","selectedFillOpacity","selectionFillMode","wellShape","id","pos","entry","isSelected","wellFill","usesSelectionFill","fill","fillOpacity","cx","cy","buildWellCells","cells","buildGridLines","borderColor","lines","left","top","right","bottom","x","y","buildWellOverlay","selectedBorderColor","flashWellId","flashWellKey","highlightedWellIds","highlightBorderColor","isFlashing","isHighlighted","size","isCircle","shapeProps","renderShape","extraProps","children","elementKey","props","flashAnimations","jsxs","Fragment","buildWellOverlays","overlays","overlay","PlatePaintGrid","format","onSelectionChange","framed","autoScale","minCellSize","maxCellSize","onWellHover","onWellDoubleClick","wrapWell","className","resolveDimensions","containerRef","React","svgRef","drag","setDrag","containerWidth","setContainerWidth","node","update","observer","resolvedCellSize","autoMaxCellSize","frameAdjust","fitSize","cellAt","evt","svg","rect","handleDown","e","cell","mode","handleMove","commitDrag","positions","rectPositions","next","p","handleUp","handleLeave","handleDoubleClick","edgeStrokePadding","width","height","colLabels","rowLabels","wellRenderArgs","wellCells","gridLines","wellOverlays","overlayCells","cn"],"mappings":"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"}
@@ -1,389 +0,0 @@
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(
12
- "text",
13
- {
14
- x: n + o * l + l / 2,
15
- y: n / 2,
16
- textAnchor: "middle",
17
- fontSize: le,
18
- className: "fill-muted-foreground",
19
- children: o + 1
20
- },
21
- `c${o}`
22
- )
23
- );
24
- return r;
25
- }
26
- function Ce(i, l) {
27
- const r = [];
28
- for (let o = 0; o < i; o++)
29
- r.push(
30
- /* @__PURE__ */ g(
31
- "text",
32
- {
33
- x: n - Te,
34
- y: n + o * l + l / 2 + xe,
35
- textAnchor: "end",
36
- fontSize: le,
37
- className: "fill-muted-foreground",
38
- children: _e(o)
39
- },
40
- `r${o}`
41
- )
42
- );
43
- return r;
44
- }
45
- function We(i, l, r) {
46
- 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(
62
- "circle",
63
- {
64
- cx: O,
65
- cy: A,
66
- r: S,
67
- fill: x,
68
- fillOpacity: R,
69
- stroke: "none",
70
- "data-well": h,
71
- "data-selected": y ? "true" : void 0
72
- },
73
- h
74
- );
75
- }
76
- return /* @__PURE__ */ g(
77
- "rect",
78
- {
79
- x: n + r * e,
80
- y: n + l * e,
81
- width: e,
82
- height: e,
83
- fill: x,
84
- fillOpacity: R,
85
- stroke: "none",
86
- "data-well": h,
87
- "data-selected": y ? "true" : void 0
88
- },
89
- h
90
- );
91
- }
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;
98
- }
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(
105
- "line",
106
- {
107
- x1: f,
108
- y1: v,
109
- x2: f,
110
- y2: L,
111
- stroke: r,
112
- strokeWidth: Z,
113
- vectorEffect: "non-scaling-stroke",
114
- shapeRendering: "crispEdges",
115
- pointerEvents: "none",
116
- "data-plate-grid-line": `column-${u}`
117
- },
118
- `grid-col-${u}`
119
- )
120
- );
121
- }
122
- for (let u = 0; u <= i.rows; u++) {
123
- const f = n + u * l;
124
- o.push(
125
- /* @__PURE__ */ g(
126
- "line",
127
- {
128
- x1: e,
129
- y1: f,
130
- x2: k,
131
- y2: f,
132
- stroke: r,
133
- strokeWidth: Z,
134
- vectorEffect: "non-scaling-stroke",
135
- shapeRendering: "crispEdges",
136
- pointerEvents: "none",
137
- "data-plate-grid-line": `row-${u}`
138
- },
139
- `grid-row-${u}`
140
- )
141
- );
142
- }
143
- return o;
144
- }
145
- function $e(i, l, r) {
146
- 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(
166
- "animate",
167
- {
168
- attributeName: "stroke-width",
169
- values: `${ne};${se}`,
170
- dur: `${Y}ms`,
171
- fill: "freeze"
172
- }
173
- )
174
- ] });
175
- return /* @__PURE__ */ U("g", { children: [
176
- h ? M({
177
- fill: "none",
178
- stroke: L,
179
- strokeWidth: se,
180
- "data-well-selection": p
181
- }) : null,
182
- y ? M({
183
- fill: "none",
184
- stroke: T,
185
- strokeWidth: Re,
186
- "data-well-highlight": p
187
- }) : null,
188
- b ? M(
189
- {
190
- fill: L,
191
- fillOpacity: 0.24,
192
- stroke: L,
193
- strokeOpacity: 0.92,
194
- strokeWidth: ne,
195
- "data-well-flash": p
196
- },
197
- B,
198
- `${p}-${f}`
199
- ) : null
200
- ] }, `overlay-${p}`);
201
- }
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);
208
- }
209
- return r;
210
- }
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
239
- }) {
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 };
260
- },
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(
306
- "div",
307
- {
308
- style: {
309
- position: "absolute",
310
- left: n + d * m,
311
- top: n + t * m,
312
- width: m,
313
- height: m
314
- },
315
- "data-well-id": P,
316
- children: M(P, m)
317
- },
318
- P
319
- )
320
- );
321
- }
322
- return c;
323
- }, [M, s.rows, s.columns, m]);
324
- return /* @__PURE__ */ g(
325
- "div",
326
- {
327
- ref: C,
328
- className: oe("relative w-full select-none", B),
329
- "data-slot": "plate-paint-grid",
330
- children: /* @__PURE__ */ U(
331
- "div",
332
- {
333
- className: oe(
334
- "relative inline-block",
335
- f && "rounded-xl border bg-card p-3 shadow-sm"
336
- ),
337
- "data-slot": "plate-paint-grid-frame",
338
- children: [
339
- /* @__PURE__ */ U(
340
- "svg",
341
- {
342
- ref: W,
343
- width: Q,
344
- height: V,
345
- 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.`,
353
- children: [
354
- he,
355
- me,
356
- pe,
357
- ge,
358
- ve
359
- ]
360
- }
361
- ),
362
- M ? /* @__PURE__ */ g(
363
- "div",
364
- {
365
- className: "pointer-events-none absolute",
366
- style: {
367
- top: f ? z : 0,
368
- left: f ? z : 0,
369
- width: Q,
370
- height: V
371
- },
372
- "aria-hidden": !0,
373
- "data-slot": "plate-well-overlay",
374
- children: Ee
375
- }
376
- ) : null
377
- ]
378
- }
379
- )
380
- }
381
- );
382
- }
383
- export {
384
- Oe as PLATE_MAP_CELL_BORDER,
385
- De as PLATE_MAP_EMPTY_WELL_FILL,
386
- Xe as PlatePaintGrid,
387
- ze as parsePos
388
- };
389
- //# sourceMappingURL=PlatePaintGrid.js.map