@weasel-js/labkit 1.7.0 → 1.7.2

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 (242) hide show
  1. package/README.md +3 -3
  2. package/dist/_dts/{CanvasStackContext-D2jnIwfk.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
  3. package/dist/_dts/{Stage-CCWfQQWM.d.ts → Stage-D6t7o0pF.d.ts} +3 -2
  4. package/dist/_dts/{index-CsYqUHD3.d.ts → index-BTmaRy6a.d.ts} +10 -6
  5. package/dist/_dts/{types-CSm9jgol.d.ts → index-DCMA4Fy1.d.ts} +59 -113
  6. package/dist/_dts/{types-CRPSGFAp.d.ts → types-BUBSIZuV.d.ts} +8 -7
  7. package/dist/_dts/{useTrialState-CTZPgeZ7.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
  8. package/dist/canvas/index.d.ts +8 -6
  9. package/dist/canvas/index.js +6 -6
  10. package/dist/chrome/index.d.ts +7 -5
  11. package/dist/chrome/index.js +10 -9
  12. package/dist/chunk-2ES4W47N.js +8 -0
  13. package/dist/chunk-2ES4W47N.js.map +1 -0
  14. package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
  15. package/dist/chunk-2N7UBSS2.js.map +1 -0
  16. package/dist/{chunk-275JRRVD.js → chunk-E23Q6A3Y.js} +232 -37
  17. package/dist/chunk-E23Q6A3Y.js.map +1 -0
  18. package/dist/{chunk-GOZLNM4L.js → chunk-E6NARGU7.js} +5 -5
  19. package/dist/{chunk-GOZLNM4L.js.map → chunk-E6NARGU7.js.map} +1 -1
  20. package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
  21. package/dist/chunk-EESJUSYR.js.map +1 -0
  22. package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
  23. package/dist/chunk-EFXRM6XQ.js.map +1 -0
  24. package/dist/chunk-F4ACIK7Z.js +210 -0
  25. package/dist/chunk-F4ACIK7Z.js.map +1 -0
  26. package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
  27. package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
  28. package/dist/{chunk-YT75VYRD.js → chunk-IBVRMHW5.js} +5 -5
  29. package/dist/{chunk-YT75VYRD.js.map → chunk-IBVRMHW5.js.map} +1 -1
  30. package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
  31. package/dist/chunk-PMLZP7RT.js.map +1 -0
  32. package/dist/{chunk-Y23G2VZL.js → chunk-READTDQX.js} +2 -2
  33. package/dist/chunk-READTDQX.js.map +1 -0
  34. package/dist/{chunk-I5DUQ5HM.js → chunk-RODIY7HI.js} +75 -72
  35. package/dist/chunk-RODIY7HI.js.map +1 -0
  36. package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
  37. package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
  38. package/dist/{chunk-ZIFPHIWZ.js → chunk-T6DLGEJB.js} +12 -14
  39. package/dist/chunk-T6DLGEJB.js.map +1 -0
  40. package/dist/chunk-U6UQVGFP.js +15583 -0
  41. package/dist/chunk-U6UQVGFP.js.map +1 -0
  42. package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
  43. package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
  44. package/dist/{chunk-UNAZSLWE.js → chunk-VYVGVBGY.js} +17 -20
  45. package/dist/chunk-VYVGVBGY.js.map +1 -0
  46. package/dist/chunk-WFALF2X2.js +302 -0
  47. package/dist/chunk-WFALF2X2.js.map +1 -0
  48. package/dist/{chunk-KMJ7RWD3.js → chunk-WLMDTI2Q.js} +3 -3
  49. package/dist/{chunk-KMJ7RWD3.js.map → chunk-WLMDTI2Q.js.map} +1 -1
  50. package/dist/{chunk-T5IBSPAM.js → chunk-WWJDPNZZ.js} +43 -33
  51. package/dist/chunk-WWJDPNZZ.js.map +1 -0
  52. package/dist/{chunk-J7OWWTCW.js → chunk-XE5HJOPL.js} +5 -6
  53. package/dist/chunk-XE5HJOPL.js.map +1 -0
  54. package/dist/{chunk-7BO7HNGF.js → chunk-XRX5S5NT.js} +8 -61
  55. package/dist/chunk-XRX5S5NT.js.map +1 -0
  56. package/dist/chunk-XVUKDSYV.js +38 -0
  57. package/dist/chunk-XVUKDSYV.js.map +1 -0
  58. package/dist/{chunk-FMK7UQ6V.js → chunk-XZDCEMEL.js} +64 -47
  59. package/dist/chunk-XZDCEMEL.js.map +1 -0
  60. package/dist/{chunk-FZ7YFQN7.js → chunk-YCFKW5RX.js} +3 -3
  61. package/dist/chunk-YCFKW5RX.js.map +1 -0
  62. package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
  63. package/dist/chunk-ZQIHJXP4.js.map +1 -0
  64. package/dist/config/index.d.ts +18 -10
  65. package/dist/config/index.js +4 -4
  66. package/dist/controls/index.d.ts +58 -9
  67. package/dist/controls/index.js +7 -5
  68. package/dist/dragdrop/index.d.ts +23 -3
  69. package/dist/dragdrop/index.js +4 -3
  70. package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
  71. package/dist/index.d.ts +61 -715
  72. package/dist/index.js +456 -432
  73. package/dist/index.js.map +1 -1
  74. package/dist/job/index.d.ts +8 -0
  75. package/dist/job/index.js +1 -1
  76. package/dist/layers/index.d.ts +6 -5
  77. package/dist/layers/index.js +3 -2
  78. package/dist/loupe/index.d.ts +100 -30
  79. package/dist/loupe/index.js +585 -6
  80. package/dist/loupe/index.js.map +1 -1
  81. package/dist/overview/index.d.ts +4 -2
  82. package/dist/overview/index.js +15 -14
  83. package/dist/overview/index.js.map +1 -1
  84. package/dist/passthrough/weasel-canvas.d.ts +2 -0
  85. package/dist/passthrough/weasel-ui.d.ts +2 -2871
  86. package/dist/passthrough/weasel-ui.js +3 -2
  87. package/dist/primitives/index.d.ts +213 -3
  88. package/dist/primitives/index.js +8 -7
  89. package/dist/state/index.d.ts +7 -5
  90. package/dist/state/index.js +6 -6
  91. package/dist/styles.css +284 -51
  92. package/dist/surface/index.d.ts +10 -2
  93. package/dist/surface/index.js +1 -1
  94. package/dist/undo/index.d.ts +5 -3
  95. package/package.json +11 -11
  96. package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
  97. package/src/annotations/AnnotationOverlay.tsx +50 -31
  98. package/src/annotations/Annotations.overlay.test.tsx +31 -0
  99. package/src/annotations/capture.browser.test.ts +47 -0
  100. package/src/annotations/capture.ts +14 -7
  101. package/src/annotations/drawOne.ts +2 -2
  102. package/src/annotations/frac.test.ts +44 -1
  103. package/src/annotations/frac.ts +46 -18
  104. package/src/annotations/index.ts +1 -0
  105. package/src/annotations/paint.test.ts +74 -33
  106. package/src/annotations/paint.ts +70 -32
  107. package/src/annotations/store.test.ts +212 -2
  108. package/src/annotations/store.ts +130 -27
  109. package/src/annotations/svgNodes.test.ts +22 -10
  110. package/src/annotations/svgNodes.ts +3 -3
  111. package/src/annotations/types.ts +29 -10
  112. package/src/canvas/CameraInput.test.tsx +30 -0
  113. package/src/canvas/CameraInput.tsx +16 -15
  114. package/src/canvas/CanvasStack.tsx +5 -5
  115. package/src/canvas/CanvasStackContext.ts +4 -1
  116. package/src/canvas/Stage.test.tsx +34 -25
  117. package/src/canvas/Stage.tsx +3 -3
  118. package/src/canvas/cameraRegistry.ts +1 -0
  119. package/src/canvas/worldSpec.ts +3 -1
  120. package/src/chrome/builtins.test.ts +7 -6
  121. package/src/chrome/builtins.tsx +5 -1
  122. package/src/chrome/index.ts +1 -1
  123. package/src/chrome/labRegions.test.tsx +37 -26
  124. package/src/chrome/merge.test.ts +5 -0
  125. package/src/chrome/merge.ts +4 -2
  126. package/src/chrome/regions/PaletteRegion.test.tsx +4 -5
  127. package/src/chrome/regions/PaletteRegion.tsx +3 -4
  128. package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
  129. package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
  130. package/src/chrome/regions/ViewportRegion.less +6 -0
  131. package/src/chrome/regions/ViewportRegion.tsx +10 -4
  132. package/src/chrome/types.ts +4 -2
  133. package/src/config/auto.ts +1 -0
  134. package/src/config/builder.ts +6 -0
  135. package/src/config/types.ts +2 -1
  136. package/src/controls/ControlMatrix.less +245 -0
  137. package/src/controls/ControlMatrix.stories.less +13 -0
  138. package/src/controls/ControlMatrix.stories.tsx +135 -0
  139. package/src/controls/ControlMatrix.test.tsx +206 -0
  140. package/src/controls/ControlMatrix.tsx +446 -0
  141. package/src/controls/ControlPanel.test.tsx +37 -3
  142. package/src/controls/ControlPanel.tsx +16 -5
  143. package/src/controls/index.ts +6 -0
  144. package/src/dragdrop/DragDropRuntime.tsx +22 -13
  145. package/src/dragdrop/DragGhost.tsx +3 -0
  146. package/src/dragdrop/Palette.tsx +2 -0
  147. package/src/dragdrop/dragDrop.test.tsx +34 -33
  148. package/src/index.test.ts +5 -0
  149. package/src/index.ts +7 -1
  150. package/src/instrument/types.ts +0 -6
  151. package/src/job/useJob.ts +14 -9
  152. package/src/lab/Lab.chrome.test.tsx +15 -10
  153. package/src/lab/Lab.nebula.test.tsx +5 -5
  154. package/src/lab/Lab.surface.test.tsx +30 -21
  155. package/src/lab/Lab.test.tsx +75 -74
  156. package/src/lab/Lab.tsx +5 -1
  157. package/src/lab/Lab.undock.test.tsx +15 -10
  158. package/src/lab/LabHeader.test.tsx +15 -14
  159. package/src/lab/LabPalette.test.tsx +12 -7
  160. package/src/lab/LabShell.less +1 -1
  161. package/src/lab/LabSwitcher.browser.test.tsx +27 -0
  162. package/src/lab/LabSwitcher.less +2 -0
  163. package/src/lab/LabZoom.test.tsx +55 -44
  164. package/src/lab/LabZoom.tsx +4 -4
  165. package/src/lab/Workspace.surface.test.tsx +16 -13
  166. package/src/lab/Workspace.test.tsx +32 -27
  167. package/src/lab/Workspace.tsx +48 -52
  168. package/src/loupe/AGENTS.md +28 -15
  169. package/src/loupe/CanvasLoupe.tsx +2 -3
  170. package/src/loupe/DomLoupe.tsx +1 -7
  171. package/src/loupe/Loupe.less +16 -0
  172. package/src/loupe/TrialLoupe.tsx +120 -57
  173. package/src/loupe/index.ts +1 -6
  174. package/src/loupe/types.test.ts +3 -3
  175. package/src/loupe/types.ts +24 -27
  176. package/src/loupe/useLoupe.test.tsx +29 -4
  177. package/src/loupe/useLoupe.ts +20 -17
  178. package/src/overview/OverviewMarks.test.tsx +9 -8
  179. package/src/overview/OverviewMarks.tsx +12 -4
  180. package/src/overview/TrialOverview.test.tsx +18 -17
  181. package/src/overview/TrialOverview.tsx +3 -3
  182. package/src/passthrough/weasel-ui.test.ts +1 -1
  183. package/src/passthrough/weasel-ui.ts +1 -1
  184. package/src/primitives/FloatingPanel.tsx +7 -3
  185. package/src/primitives/FpsMeter.less +1 -2
  186. package/src/primitives/JobProgress.less +1 -1
  187. package/src/primitives/Readout.test.tsx +2 -2
  188. package/src/primitives/ScaleIndicator.less +1 -1
  189. package/src/primitives/Split.tsx +69 -41
  190. package/src/primitives/StatusBar.less +1 -1
  191. package/src/primitives/Toolbar.tsx +3 -3
  192. package/src/primitives/ZoomControl.less +1 -2
  193. package/src/specimen/Specimen.less +1 -0
  194. package/src/specimen/Specimen.tsx +0 -1
  195. package/src/state/undock.ts +3 -0
  196. package/src/state/useOpenOnce.ts +20 -16
  197. package/src/state/view.ts +1 -0
  198. package/src/styles.less +3 -0
  199. package/src/surface/index.ts +1 -1
  200. package/src/surface/useTiledSurface.test.tsx +14 -0
  201. package/src/surface/useTiledSurface.ts +11 -3
  202. package/src/trial/Trial.annotations.persist.test.tsx +20 -9
  203. package/src/trial/Trial.annotations.test.tsx +105 -27
  204. package/src/trial/Trial.canvas.test.tsx +21 -17
  205. package/src/trial/Trial.config.test.tsx +34 -27
  206. package/src/trial/Trial.less +0 -16
  207. package/src/trial/Trial.loupe.test.tsx +51 -25
  208. package/src/trial/Trial.targets.test.tsx +9 -8
  209. package/src/trial/Trial.test.tsx +51 -46
  210. package/src/trial/Trial.trialId.test.tsx +7 -6
  211. package/src/trial/Trial.tsx +74 -62
  212. package/src/trial/TrialChrome.tsx +6 -3
  213. package/src/trial/index.ts +2 -0
  214. package/src/trial/loupeSwitch.ts +15 -0
  215. package/dist/_dts/LayerList.d-DiuEArKq.d.ts +0 -83
  216. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +0 -79
  217. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +0 -141
  218. package/dist/_dts/Select.d-Bensr_MT.d.ts +0 -579
  219. package/dist/_dts/index-B2Yj5aA0.d.ts +0 -274
  220. package/dist/chunk-275JRRVD.js.map +0 -1
  221. package/dist/chunk-4LJSC7MB.js +0 -143
  222. package/dist/chunk-4LJSC7MB.js.map +0 -1
  223. package/dist/chunk-7BO7HNGF.js.map +0 -1
  224. package/dist/chunk-CQLQPQ4P.js.map +0 -1
  225. package/dist/chunk-FMK7UQ6V.js.map +0 -1
  226. package/dist/chunk-FZ7YFQN7.js.map +0 -1
  227. package/dist/chunk-HXXTULDN.js.map +0 -1
  228. package/dist/chunk-I5DUQ5HM.js.map +0 -1
  229. package/dist/chunk-IJJUK4FU.js.map +0 -1
  230. package/dist/chunk-J7OWWTCW.js.map +0 -1
  231. package/dist/chunk-M7HP3FTK.js +0 -549
  232. package/dist/chunk-M7HP3FTK.js.map +0 -1
  233. package/dist/chunk-MIM5R4ZT.js +0 -14972
  234. package/dist/chunk-MIM5R4ZT.js.map +0 -1
  235. package/dist/chunk-RWNDDKOH.js.map +0 -1
  236. package/dist/chunk-T5IBSPAM.js.map +0 -1
  237. package/dist/chunk-UNAZSLWE.js.map +0 -1
  238. package/dist/chunk-WPLAANH4.js.map +0 -1
  239. package/dist/chunk-Y23G2VZL.js.map +0 -1
  240. package/dist/chunk-ZIFPHIWZ.js.map +0 -1
  241. package/src/primitives/useRovingTabIndex.test.ts +0 -48
  242. package/src/primitives/useRovingTabIndex.ts +0 -88
@@ -0,0 +1,210 @@
1
+ import { boxContainsPoint, boxContainsBox, boundsOfCoords } from './chunk-XVUKDSYV.js';
2
+ import { textCommand, pxExtent, meanScale, ellipsePath, linePath, rectPath, HANDLE_BASE_PX, PathBuilder } from '@weasel-js/core';
3
+
4
+ // src/annotations/frac.ts
5
+ var boxOfFrac = (f) => [f.x, f.y, f.x + f.w, f.y + f.h];
6
+ function fracToWorld(f, content) {
7
+ return {
8
+ x: f.x * content.w,
9
+ y: f.y * content.h,
10
+ width: f.w * content.w,
11
+ height: f.h * content.h
12
+ };
13
+ }
14
+ function worldToFrac(r, content) {
15
+ const sx = content.w === 0 ? 0 : 1 / content.w;
16
+ const sy = content.h === 0 ? 0 : 1 / content.h;
17
+ return { x: r.x * sx, y: r.y * sy, w: r.width * sx, h: r.height * sy };
18
+ }
19
+ var DP = 1e4;
20
+ function roundFrac(f) {
21
+ return {
22
+ x: Math.round(f.x * DP) / DP,
23
+ y: Math.round(f.y * DP) / DP,
24
+ w: Math.round(f.w * DP) / DP,
25
+ h: Math.round(f.h * DP) / DP
26
+ };
27
+ }
28
+ function fracContains(box, pt, tol = 0) {
29
+ const [x0, y0, x1, y1] = boxOfFrac(box);
30
+ return boxContainsPoint([x0 - tol, y0 - tol, x1 + tol, y1 + tol], pt.x, pt.y);
31
+ }
32
+ function fracEncloses(outer, inner) {
33
+ return boxContainsBox(boxOfFrac(outer), boxOfFrac(inner));
34
+ }
35
+ function boundsOf(points) {
36
+ const b = boundsOfCoords(points.flatMap((p) => [p.x, p.y]));
37
+ return b && { x: b[0], y: b[1], w: b[2] - b[0], h: b[3] - b[1] };
38
+ }
39
+ function toShape(points, box) {
40
+ return points.map((p) => ({
41
+ x: box.w === 0 ? 0 : (p.x - box.x) / box.w,
42
+ y: box.h === 0 ? 0 : (p.y - box.y) / box.h
43
+ }));
44
+ }
45
+ function fromShape(shape, box) {
46
+ return shape.map((s) => ({ x: box.x + s.x * box.w, y: box.y + s.y * box.h }));
47
+ }
48
+ var boxOf = (r) => ({ x: r.x, y: r.y, w: r.width, h: r.height });
49
+ var roundPoint = (p) => ({
50
+ x: Math.round(p.x * DP) / DP,
51
+ y: Math.round(p.y * DP) / DP
52
+ });
53
+ var roundPoints = (pts) => pts.map(roundPoint);
54
+ var MARK_COLOR = "#e5484d";
55
+ var MARK_WIDTH = 2;
56
+ var TEXT_SIZE = 14;
57
+ var STALE_DASH = [6, 4];
58
+ var POINT_RADIUS_PX = HANDLE_BASE_PX / 2;
59
+ var UNIT_SCALE = { x: 1, y: 1 };
60
+ function vertices(m) {
61
+ const stored = m.data.shape;
62
+ if (stored && stored.length >= 2) return fromShape(stored, boxOf(m.pose));
63
+ const { x, y, width, height } = m.pose;
64
+ return [
65
+ { x, y },
66
+ { x: x + width, y: y + height }
67
+ ];
68
+ }
69
+ function polyline(points) {
70
+ const b = new PathBuilder();
71
+ const first = points[0];
72
+ if (!first) return rectPath(0, 0, 0, 0);
73
+ b.moveTo(first.x, first.y);
74
+ for (const p of points.slice(1)) b.lineTo(p.x, p.y);
75
+ return b.build();
76
+ }
77
+ function markCommands(m, style = {}, scale = UNIT_SCALE) {
78
+ const color = style.color ?? MARK_COLOR;
79
+ const stroke = {
80
+ paint: { color },
81
+ width: MARK_WIDTH,
82
+ cap: "round",
83
+ join: "round",
84
+ ...style.stale ? { dash: STALE_DASH } : {}
85
+ };
86
+ switch (m.data.kind) {
87
+ case "rect":
88
+ return [
89
+ { kind: "path", path: rectPath(m.pose.x, m.pose.y, m.pose.width, m.pose.height), stroke }
90
+ ];
91
+ case "ellipse":
92
+ return [{ kind: "path", path: ellipsePath(m.pose), stroke }];
93
+ case "line": {
94
+ const [a, b] = vertices(m);
95
+ return [{ kind: "path", path: linePath(a, b), stroke }];
96
+ }
97
+ case "arrow": {
98
+ const [a, b] = vertices(m);
99
+ return [{ kind: "path", path: linePath(a, b), stroke: { ...stroke, markerEnd: "arrow" } }];
100
+ }
101
+ case "stroke":
102
+ return [{ kind: "path", path: polyline(vertices(m)), stroke }];
103
+ case "point": {
104
+ const c = { x: m.pose.x, y: m.pose.y };
105
+ const r = pxExtent(POINT_RADIUS_PX, scale);
106
+ const ring = { x: c.x - r.x, y: c.y - r.y, width: 2 * r.x, height: 2 * r.y };
107
+ const px = 1 / meanScale(scale);
108
+ return [
109
+ {
110
+ kind: "path",
111
+ path: ellipsePath(ring),
112
+ stroke: {
113
+ ...stroke,
114
+ width: MARK_WIDTH * px,
115
+ ...stroke.dash ? { dash: stroke.dash.map((d) => d * px) } : {}
116
+ }
117
+ }
118
+ ];
119
+ }
120
+ case "text": {
121
+ const text = m.data.title;
122
+ if (!text) return [];
123
+ return [
124
+ textCommand(
125
+ m.pose.x,
126
+ m.pose.y,
127
+ text,
128
+ { fontSize: TEXT_SIZE },
129
+ void 0,
130
+ void 0,
131
+ void 0,
132
+ {
133
+ fill: { color }
134
+ }
135
+ )
136
+ ];
137
+ }
138
+ }
139
+ }
140
+ var POINT_MARK_SHAPE = {
141
+ id: "labkit:point-mark",
142
+ matches: (node) => node.layer === "marks" && node.data?.kind === "point" && typeof node.data.target === "string",
143
+ // The overlay paints through its own draw callback. This is for a scene
144
+ // drawn without one.
145
+ paint: (node, pose) => markCommands({ pose, data: node.data }),
146
+ silhouette: (_node, pose) => rectPath(pose.x, pose.y, 0, 0),
147
+ // Filled, so a click inside the ring lands on it as it would on a handle.
148
+ ink: (_node, _pose, ctx) => {
149
+ const s = ctx?.scale ?? 1;
150
+ return { filled: true, outset: (POINT_RADIUS_PX + MARK_WIDTH / 2) / s, inset: 0 };
151
+ }
152
+ };
153
+
154
+ // src/annotations/svgNodes.ts
155
+ var NO_PAINT = { kind: "none" };
156
+ function toSvgPaint(paint) {
157
+ if (!paint) return NO_PAINT;
158
+ if ("color" in paint && typeof paint.color === "string") {
159
+ return {
160
+ kind: "solid",
161
+ color: paint.color,
162
+ ...paint.opacity != null ? { opacity: paint.opacity } : {}
163
+ };
164
+ }
165
+ return { kind: "gradient", paint };
166
+ }
167
+ function toSvgStroke(stroke) {
168
+ return {
169
+ paint: toSvgPaint(stroke.paint),
170
+ width: stroke.width ?? 1,
171
+ ...stroke.cap ? { cap: stroke.cap } : {},
172
+ ...stroke.join ? { join: stroke.join } : {},
173
+ ...stroke.dash ? { dash: [...stroke.dash] } : {},
174
+ ...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {},
175
+ ...stroke.align ? { align: stroke.align } : {},
176
+ ...stroke.markerStart ? { markerStart: stroke.markerStart } : {},
177
+ ...stroke.markerMid ? { markerMid: stroke.markerMid } : {},
178
+ ...stroke.markerEnd ? { markerEnd: stroke.markerEnd } : {}
179
+ };
180
+ }
181
+ function toSvgNode(cmd, m) {
182
+ if (cmd.kind === "path") {
183
+ return {
184
+ kind: "path",
185
+ path: cmd.path,
186
+ fill: toSvgPaint(cmd.fill),
187
+ ...cmd.stroke ? { stroke: toSvgStroke(cmd.stroke) } : {}
188
+ };
189
+ }
190
+ if (cmd.kind === "text") {
191
+ return {
192
+ kind: "text",
193
+ x: cmd.x,
194
+ y: cmd.y,
195
+ width: m.pose.width,
196
+ height: m.pose.height,
197
+ text: cmd.runs.map((run) => run.text).join(""),
198
+ style: cmd.style,
199
+ ...cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}
200
+ };
201
+ }
202
+ throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);
203
+ }
204
+ function markSvgNodes(m, style = {}, scale) {
205
+ return markCommands(m, style, scale).map((cmd) => toSvgNode(cmd, m));
206
+ }
207
+
208
+ export { POINT_MARK_SHAPE, boundsOf, fracContains, fracEncloses, fracToWorld, fromShape, markCommands, markSvgNodes, roundFrac, roundPoints, toShape, worldToFrac };
209
+ //# sourceMappingURL=chunk-F4ACIK7Z.js.map
210
+ //# sourceMappingURL=chunk-F4ACIK7Z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/annotations/frac.ts","../src/annotations/paint.ts","../src/annotations/svgNodes.ts"],"names":[],"mappings":"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","file":"chunk-F4ACIK7Z.js","sourcesContent":["import {\n type Box,\n boundsOfCoords,\n boxContainsBox,\n boxContainsPoint,\n type Rect,\n} from '@weasel-js/geom';\nimport type { FracPoint, FracRect } from './types';\n\n/** A mark's box in its target's world: CSS pixels at zoom 1. Matches weasel's\n * default `RectPose`, which is what the scene stores. */\nexport type WorldRect = Rect;\n\nconst boxOfFrac = (f: FracRect): Box => [f.x, f.y, f.x + f.w, f.y + f.h];\n\n/** Where a fraction lands on a content box of this size. */\nexport function fracToWorld(f: FracRect, content: { w: number; h: number }): WorldRect {\n return {\n x: f.x * content.w,\n y: f.y * content.h,\n width: f.w * content.w,\n height: f.h * content.h,\n };\n}\n\n/** What fraction of the content box a world rect covers.\n *\n * A pane measured before layout is 0×0, and dividing by that would seed every\n * stored position with `NaN` — which compares false against everything and so\n * fails silently rather than loudly. Zero sides give zeros. */\nexport function worldToFrac(r: WorldRect, content: { w: number; h: number }): FracRect {\n const sx = content.w === 0 ? 0 : 1 / content.w;\n const sy = content.h === 0 ? 0 : 1 / content.h;\n return { x: r.x * sx, y: r.y * sy, w: r.width * sx, h: r.height * sy };\n}\n\nconst DP = 10_000;\n\n/** Snap to 4dp. Positions are diffed by humans in stored documents, so the\n * last digits of a float are noise that hides the change that matters. */\nexport function roundFrac(f: FracRect): FracRect {\n return {\n x: Math.round(f.x * DP) / DP,\n y: Math.round(f.y * DP) / DP,\n w: Math.round(f.w * DP) / DP,\n h: Math.round(f.h * DP) / DP,\n };\n}\n\n/** Whether `pt` falls in `box`, widened by `tol` on every side so a hairline\n * mark stays reachable. */\nexport function fracContains(box: FracRect, pt: FracPoint, tol = 0): boolean {\n const [x0, y0, x1, y1] = boxOfFrac(box);\n return boxContainsPoint([x0 - tol, y0 - tol, x1 + tol, y1 + tol], pt.x, pt.y);\n}\n\n/** Whether `outer` wholly encloses `inner`. A marquee takes what it encloses,\n * not what it grazes — brushing selection is a different gesture, and this\n * answers false for two rects that merely overlap. */\nexport function fracEncloses(outer: FracRect, inner: FracRect): boolean {\n return boxContainsBox(boxOfFrac(outer), boxOfFrac(inner));\n}\n\n/** The smallest box holding every point — zero-size for a single one, and\n * `null` for none. */\nexport function boundsOf(points: readonly FracPoint[]): FracRect | null {\n const b = boundsOfCoords(points.flatMap((p) => [p.x, p.y]));\n return b && { x: b[0], y: b[1], w: b[2] - b[0], h: b[3] - b[1] };\n}\n\n/** Points restated as fractions of `box` itself, so they move and stretch with\n * it. Unit-agnostic: `points` and `box` only have to share one. A box with no\n * width or height puts every point on its edge along that axis. */\nexport function toShape(points: readonly FracPoint[], box: FracRect): FracPoint[] {\n return points.map((p) => ({\n x: box.w === 0 ? 0 : (p.x - box.x) / box.w,\n y: box.h === 0 ? 0 : (p.y - box.y) / box.h,\n }));\n}\n\n/** `toShape`'s inverse: a shape placed in `box`, in `box`'s units. */\nexport function fromShape(shape: readonly FracPoint[], box: FracRect): FracPoint[] {\n return shape.map((s) => ({ x: box.x + s.x * box.w, y: box.y + s.y * box.h }));\n}\n\n/** A world rect as the `{ x, y, w, h }` the shape helpers take. */\nexport const boxOf = (r: WorldRect): FracRect => ({ x: r.x, y: r.y, w: r.width, h: r.height });\n\nconst roundPoint = (p: FracPoint): FracPoint => ({\n x: Math.round(p.x * DP) / DP,\n y: Math.round(p.y * DP) / DP,\n});\n\n/** `roundFrac` for points. */\nexport const roundPoints = (pts: readonly FracPoint[]): FracPoint[] => pts.map(roundPoint);\n","import type { DrawCommand, NodeShapeEntry, Path, Stroke, View } from '@weasel-js/core';\nimport {\n ellipsePath,\n HANDLE_BASE_PX,\n linePath,\n meanScale,\n PathBuilder,\n pxExtent,\n rectPath,\n textCommand,\n} from '@weasel-js/core';\nimport { boxOf, fromShape, type WorldRect } from './frac';\nimport type { AnnotationData } from './types';\n\n/** One loud color, not a themed one: a mark sits over the instrument's own\n * picture and has to be legible against whatever that picture is. */\nconst MARK_COLOR = '#e5484d';\n/** World units, so a mark thickens with the picture it annotates. */\nconst MARK_WIDTH = 2;\nconst TEXT_SIZE = 14;\nconst STALE_DASH = [6, 4];\n/** Screen pixels: a point marks a place rather than a region of the picture,\n * so it holds its size like a selection handle. */\nconst POINT_RADIUS_PX = HANDLE_BASE_PX / 2;\nconst UNIT_SCALE: View['scale'] = { x: 1, y: 1 };\n\n/** The subset of a mark's scene node this needs: where it is, and what it is. */\nexport interface PaintableMark {\n pose: WorldRect;\n data: AnnotationData;\n}\n\n/** How a mark is drawn, as opposed to where. Resolved by the overlay from the\n * instrument's vocabulary and the mark's own staleness. */\nexport interface MarkStyle {\n /** The status's color, or the default. */\n color?: string;\n /** A mark whose stored position no longer describes the picture. Drawn\n * dashed rather than hidden: it still describes *something*, and dropping\n * it would lose it. */\n stale?: boolean;\n}\n\n/** A mark's stored vertices placed in its pose, or the pose's diagonal — a\n * stored mark whose `shape` did not survive still has to draw somewhere. */\nfunction vertices(m: PaintableMark): { x: number; y: number }[] {\n const stored = m.data.shape;\n if (stored && stored.length >= 2) return fromShape(stored, boxOf(m.pose));\n const { x, y, width, height } = m.pose;\n return [\n { x, y },\n { x: x + width, y: y + height },\n ];\n}\n\nfunction polyline(points: { x: number; y: number }[]): Path {\n const b = new PathBuilder();\n const first = points[0];\n if (!first) return rectPath(0, 0, 0, 0);\n b.moveTo(first.x, first.y);\n for (const p of points.slice(1)) b.lineTo(p.x, p.y);\n return b.build();\n}\n\n/**\n * What one mark draws, in its target's world.\n *\n * Pure: a node in, draw commands out, in its target's world. Geometry that a\n * bounding box cannot describe — a line's ends, a stroke's path — comes from\n * `data.shape`, placed in the pose.\n *\n * `scale` is the view's, world to screen. Only a point reads it — its ring is\n * sized in screen pixels — and the default draws that ring as though a world\n * unit were a pixel.\n */\nexport function markCommands(\n m: PaintableMark,\n style: MarkStyle = {},\n scale: View['scale'] = UNIT_SCALE,\n): DrawCommand[] {\n const color = style.color ?? MARK_COLOR;\n const stroke: Stroke = {\n paint: { color },\n width: MARK_WIDTH,\n cap: 'round',\n join: 'round',\n ...(style.stale ? { dash: STALE_DASH } : {}),\n };\n\n switch (m.data.kind) {\n case 'rect':\n return [\n { kind: 'path', path: rectPath(m.pose.x, m.pose.y, m.pose.width, m.pose.height), stroke },\n ];\n case 'ellipse':\n return [{ kind: 'path', path: ellipsePath(m.pose), stroke }];\n case 'line': {\n const [a, b] = vertices(m);\n return [{ kind: 'path', path: linePath(a, b), stroke }];\n }\n case 'arrow': {\n const [a, b] = vertices(m);\n // The spec's arrow: a line carrying an end marker, not its own geometry.\n return [{ kind: 'path', path: linePath(a, b), stroke: { ...stroke, markerEnd: 'arrow' } }];\n }\n case 'stroke':\n return [{ kind: 'path', path: polyline(vertices(m)), stroke }];\n case 'point': {\n const c = { x: m.pose.x, y: m.pose.y };\n const r = pxExtent(POINT_RADIUS_PX, scale);\n const ring = { x: c.x - r.x, y: c.y - r.y, width: 2 * r.x, height: 2 * r.y };\n const px = 1 / meanScale(scale);\n return [\n {\n kind: 'path',\n path: ellipsePath(ring),\n stroke: {\n ...stroke,\n width: MARK_WIDTH * px,\n ...(stroke.dash ? { dash: stroke.dash.map((d) => d * px) } : {}),\n },\n },\n ];\n }\n case 'text': {\n const text = m.data.title;\n if (!text) return [];\n return [\n textCommand(\n m.pose.x,\n m.pose.y,\n text,\n { fontSize: TEXT_SIZE },\n undefined,\n undefined,\n undefined,\n {\n fill: { color },\n },\n ),\n ];\n }\n }\n}\n\n/**\n * What picking reads for a point mark: its pose is zero-size, so without this\n * the pointer slop alone decides how close counts, whatever the ring's size.\n * Registered by the overlay, which is the one place marks are picked.\n */\nexport const POINT_MARK_SHAPE: NodeShapeEntry<AnnotationData, WorldRect> = {\n id: 'labkit:point-mark',\n matches: (node) =>\n node.layer === 'marks' && node.data?.kind === 'point' && typeof node.data.target === 'string',\n // The overlay paints through its own draw callback. This is for a scene\n // drawn without one.\n paint: (node, pose) => markCommands({ pose, data: node.data }),\n silhouette: (_node, pose) => rectPath(pose.x, pose.y, 0, 0),\n // Filled, so a click inside the ring lands on it as it would on a handle.\n ink: (_node, _pose, ctx) => {\n const s = ctx?.scale ?? 1;\n return { filled: true, outset: (POINT_RADIUS_PX + MARK_WIDTH / 2) / s, inset: 0 };\n },\n};\n","import type { DrawCommand, FillStyle, Stroke, View } from '@weasel-js/core';\nimport type { SvgNode, SvgPaint, SvgStroke } from '@weasel-js/svg';\nimport { type MarkStyle, markCommands, type PaintableMark } from './paint';\n\nconst NO_PAINT: SvgPaint = { kind: 'none' };\n\nfunction toSvgPaint(paint: FillStyle | undefined): SvgPaint {\n if (!paint) return NO_PAINT;\n if ('color' in paint && typeof paint.color === 'string') {\n return {\n kind: 'solid',\n color: paint.color,\n ...(paint.opacity != null ? { opacity: paint.opacity } : {}),\n };\n }\n return { kind: 'gradient', paint };\n}\n\nfunction toSvgStroke(stroke: Stroke): SvgStroke {\n return {\n paint: toSvgPaint(stroke.paint),\n width: stroke.width ?? 1,\n ...(stroke.cap ? { cap: stroke.cap } : {}),\n ...(stroke.join ? { join: stroke.join } : {}),\n ...(stroke.dash ? { dash: [...stroke.dash] } : {}),\n ...(stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {}),\n ...(stroke.align ? { align: stroke.align } : {}),\n ...(stroke.markerStart ? { markerStart: stroke.markerStart } : {}),\n ...(stroke.markerMid ? { markerMid: stroke.markerMid } : {}),\n ...(stroke.markerEnd ? { markerEnd: stroke.markerEnd } : {}),\n };\n}\n\nfunction toSvgNode(cmd: DrawCommand, m: PaintableMark): SvgNode {\n if (cmd.kind === 'path') {\n return {\n kind: 'path',\n path: cmd.path,\n fill: toSvgPaint(cmd.fill),\n ...(cmd.stroke ? { stroke: toSvgStroke(cmd.stroke) } : {}),\n };\n }\n if (cmd.kind === 'text') {\n return {\n kind: 'text',\n x: cmd.x,\n y: cmd.y,\n width: m.pose.width,\n height: m.pose.height,\n text: cmd.runs.map((run) => run.text).join(''),\n style: cmd.style,\n ...(cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}),\n };\n }\n // Unreachable while `markCommands` emits only paths and text. A throw rather\n // than a skip: a new mark kind silently vanishing from every export is a\n // worse afternoon than a loud one.\n throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);\n}\n\n/**\n * One mark as SVG nodes, converted from the very commands the pane paints.\n *\n * Deliberately not a second switch over `data.kind`: geometry has one source,\n * and this is a translation of it. `serializeSvg` turns the result into a\n * document.\n */\nexport function markSvgNodes(\n m: PaintableMark,\n style: MarkStyle = {},\n scale?: View['scale'],\n): SvgNode[] {\n return markCommands(m, style, scale).map((cmd) => toSvgNode(cmd, m));\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { DEFAULT_FRAME } from './chunk-24W5VEJW.js';
1
+ import { DEFAULT_FRAME } from './chunk-ULYYNWGP.js';
2
2
 
3
3
  // src/canvas/canvasCoords.ts
4
4
  function worldToScreen(world, view, frame = DEFAULT_FRAME) {
@@ -15,5 +15,5 @@ function screenToWorld(screen, view, frame = DEFAULT_FRAME) {
15
15
  }
16
16
 
17
17
  export { screenToWorld, worldToScreen };
18
- //# sourceMappingURL=chunk-AWQG7FCC.js.map
19
- //# sourceMappingURL=chunk-AWQG7FCC.js.map
18
+ //# sourceMappingURL=chunk-FG3EXZDV.js.map
19
+ //# sourceMappingURL=chunk-FG3EXZDV.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/canvas/canvasCoords.ts"],"names":[],"mappings":";;;AAQO,SAAS,aAAA,CACd,KAAA,EACA,IAAA,EACA,KAAA,GAAoB,aAAA,EACb;AACP,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,MAAM,QAAA,CAAS,CAAA,GAAI,KAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,IAAA;AAAA,IAClD,CAAA,EAAG,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,IAAA,GAAO,KAAA,CAAM;AAAA,GACjE;AACF;AAGO,SAAS,aAAA,CACd,MAAA,EACA,IAAA,EACA,KAAA,GAAoB,aAAA,EACb;AACP,EAAA,OAAO;AAAA,IACL,CAAA,EAAA,CAAI,OAAO,CAAA,GAAI,KAAA,CAAM,SAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,IAAK,IAAA,CAAK,IAAA;AAAA,IACrD,CAAA,EAAA,CAAI,MAAA,CAAO,CAAA,GAAI,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,KAAM,IAAA,CAAK,IAAA,GAAO,KAAA,CAAM,IAAA;AAAA,GACrE;AACF","file":"chunk-AWQG7FCC.js","sourcesContent":["import type { Point, ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** Project a world point into screen coordinates under a view.\n *\n * `frame` is the instrument's declared coordinate system, resolved against the\n * viewport; omitting it gives labkit's original one — origin at the top-left,\n * y downward. */\nexport function worldToScreen(\n world: Point,\n view: ViewTransform,\n frame: WorldFrame = DEFAULT_FRAME,\n): Point {\n return {\n x: frame.originPx.x + view.pan.x + world.x * view.zoom,\n y: frame.originPx.y + view.pan.y + world.y * view.zoom * frame.yDir,\n };\n}\n\n/** Unproject a screen point back to world coordinates under a view. */\nexport function screenToWorld(\n screen: Point,\n view: ViewTransform,\n frame: WorldFrame = DEFAULT_FRAME,\n): Point {\n return {\n x: (screen.x - frame.originPx.x - view.pan.x) / view.zoom,\n y: (screen.y - frame.originPx.y - view.pan.y) / (view.zoom * frame.yDir),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/canvas/canvasCoords.ts"],"names":[],"mappings":";;;AAQO,SAAS,aAAA,CACd,KAAA,EACA,IAAA,EACA,KAAA,GAAoB,aAAA,EACb;AACP,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,MAAM,QAAA,CAAS,CAAA,GAAI,KAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,IAAA;AAAA,IAClD,CAAA,EAAG,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,KAAA,CAAM,CAAA,GAAI,IAAA,CAAK,IAAA,GAAO,KAAA,CAAM;AAAA,GACjE;AACF;AAGO,SAAS,aAAA,CACd,MAAA,EACA,IAAA,EACA,KAAA,GAAoB,aAAA,EACb;AACP,EAAA,OAAO;AAAA,IACL,CAAA,EAAA,CAAI,OAAO,CAAA,GAAI,KAAA,CAAM,SAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,IAAK,IAAA,CAAK,IAAA;AAAA,IACrD,CAAA,EAAA,CAAI,MAAA,CAAO,CAAA,GAAI,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,KAAM,IAAA,CAAK,IAAA,GAAO,KAAA,CAAM,IAAA;AAAA,GACrE;AACF","file":"chunk-FG3EXZDV.js","sourcesContent":["import type { Point, ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** Project a world point into screen coordinates under a view.\n *\n * `frame` is the instrument's declared coordinate system, resolved against the\n * viewport; omitting it gives labkit's original one — origin at the top-left,\n * y downward. */\nexport function worldToScreen(\n world: Point,\n view: ViewTransform,\n frame: WorldFrame = DEFAULT_FRAME,\n): Point {\n return {\n x: frame.originPx.x + view.pan.x + world.x * view.zoom,\n y: frame.originPx.y + view.pan.y + world.y * view.zoom * frame.yDir,\n };\n}\n\n/** Unproject a screen point back to world coordinates under a view. */\nexport function screenToWorld(\n screen: Point,\n view: ViewTransform,\n frame: WorldFrame = DEFAULT_FRAME,\n): Point {\n return {\n x: (screen.x - frame.originPx.x - view.pan.x) / view.zoom,\n y: (screen.y - frame.originPx.y - view.pan.y) / (view.zoom * frame.yDir),\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { newId, emptyUndoStack, deserializeTrials, openRecords, labPrefix, documentOfRecords, recordsOfDocument, trialRecord, trialValuesPrefix, saveRecord, LAYOUT_RECORD, UNDOCK_RECORD, META_RECORD, parseRecordName, compareTrialOrder, serializeTrials, labStorageKey } from './chunk-RWNDDKOH.js';
2
- import { resolveConfigSchema, useResolvedConfig } from './chunk-FZ7YFQN7.js';
3
- import { applyConfigWrite, fillConfigDefaults } from './chunk-Y23G2VZL.js';
1
+ import { newId, emptyUndoStack, deserializeTrials, openRecords, labPrefix, documentOfRecords, recordsOfDocument, trialRecord, trialValuesPrefix, saveRecord, LAYOUT_RECORD, UNDOCK_RECORD, META_RECORD, parseRecordName, compareTrialOrder, serializeTrials, labStorageKey } from './chunk-PMLZP7RT.js';
2
+ import { resolveConfigSchema, useResolvedConfig } from './chunk-YCFKW5RX.js';
3
+ import { applyConfigWrite, fillConfigDefaults } from './chunk-READTDQX.js';
4
4
  import { LabStoreContext, TrialIdContext } from './chunk-2YILQ7Y5.js';
5
5
  import { createStore } from 'zustand/vanilla';
6
6
  import { useContext } from 'react';
@@ -733,5 +733,5 @@ function useTrialState() {
733
733
  }
734
734
 
735
735
  export { CURRENT_DOCUMENT_VERSION, createLabStore, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, unruledConfigSchema, useTrialState };
736
- //# sourceMappingURL=chunk-YT75VYRD.js.map
737
- //# sourceMappingURL=chunk-YT75VYRD.js.map
736
+ //# sourceMappingURL=chunk-IBVRMHW5.js.map
737
+ //# sourceMappingURL=chunk-IBVRMHW5.js.map