@weasel-js/labkit 1.6.1 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/_dts/{CanvasStackContext-Wo6OwIVM.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
- package/dist/_dts/{Stage-DWBBi8IU.d.ts → Stage-D6t7o0pF.d.ts} +59 -18
- package/dist/_dts/{index-CKyX0ME_.d.ts → index-BTmaRy6a.d.ts} +10 -6
- package/dist/_dts/{types-B7yBTTF9.d.ts → index-DCMA4Fy1.d.ts} +59 -113
- package/dist/_dts/{types-DTuViBvc.d.ts → types-BUBSIZuV.d.ts} +18 -8
- package/dist/_dts/{useTrialState-CMaV6UD4.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
- package/dist/canvas/index.d.ts +8 -6
- package/dist/canvas/index.js +6 -6
- package/dist/chrome/index.d.ts +6 -4
- package/dist/chrome/index.js +11 -10
- package/dist/chunk-2ES4W47N.js +8 -0
- package/dist/chunk-2ES4W47N.js.map +1 -0
- package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
- package/dist/chunk-2N7UBSS2.js.map +1 -0
- package/dist/chunk-4KSC7NXL.js +15491 -0
- package/dist/chunk-4KSC7NXL.js.map +1 -0
- package/dist/{chunk-SLAQPUI4.js → chunk-CEGFXTBD.js} +10 -63
- package/dist/chunk-CEGFXTBD.js.map +1 -0
- package/dist/chunk-CZZPXUOU.js +3 -0
- package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
- package/dist/{chunk-QGMOA2YE.js → chunk-E23Q6A3Y.js} +296 -104
- package/dist/chunk-E23Q6A3Y.js.map +1 -0
- package/dist/{chunk-GHGO52SO.js → chunk-E6NARGU7.js} +5 -5
- package/dist/{chunk-GHGO52SO.js.map → chunk-E6NARGU7.js.map} +1 -1
- package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
- package/dist/chunk-EESJUSYR.js.map +1 -0
- package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
- package/dist/chunk-EFXRM6XQ.js.map +1 -0
- package/dist/chunk-F4ACIK7Z.js +210 -0
- package/dist/chunk-F4ACIK7Z.js.map +1 -0
- package/dist/{chunk-6FLXL3I7.js → chunk-FB4MIZOO.js} +77 -45
- package/dist/chunk-FB4MIZOO.js.map +1 -0
- package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
- package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
- package/dist/{chunk-4TT3PNPR.js → chunk-GAHELLJT.js} +95 -95
- package/dist/chunk-GAHELLJT.js.map +1 -0
- package/dist/{chunk-HKV7LRHY.js → chunk-IBVRMHW5.js} +5 -5
- package/dist/{chunk-HKV7LRHY.js.map → chunk-IBVRMHW5.js.map} +1 -1
- package/dist/{chunk-ASOK76ZH.js → chunk-JFOJESJF.js} +72 -29
- package/dist/chunk-JFOJESJF.js.map +1 -0
- package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
- package/dist/chunk-PMLZP7RT.js.map +1 -0
- package/dist/{chunk-TJ77A4A3.js → chunk-READTDQX.js} +5 -9
- package/dist/chunk-READTDQX.js.map +1 -0
- package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
- package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
- package/dist/{chunk-CGHF6RZV.js → chunk-T6DLGEJB.js} +18 -18
- package/dist/chunk-T6DLGEJB.js.map +1 -0
- package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
- package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
- package/dist/{chunk-DWMSB4CA.js → chunk-VYVGVBGY.js} +95 -32
- package/dist/chunk-VYVGVBGY.js.map +1 -0
- package/dist/{chunk-IRTGUQ5O.js → chunk-WLMDTI2Q.js} +16 -6
- package/dist/chunk-WLMDTI2Q.js.map +1 -0
- package/dist/{chunk-NEXR37YJ.js → chunk-XE5HJOPL.js} +6 -8
- package/dist/chunk-XE5HJOPL.js.map +1 -0
- package/dist/chunk-XVUKDSYV.js +38 -0
- package/dist/chunk-XVUKDSYV.js.map +1 -0
- package/dist/{chunk-O6FFFOHS.js → chunk-YCFKW5RX.js} +16 -8
- package/dist/chunk-YCFKW5RX.js.map +1 -0
- package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
- package/dist/chunk-ZQIHJXP4.js.map +1 -0
- package/dist/config/index.d.ts +28 -13
- package/dist/config/index.js +4 -4
- package/dist/controls/index.d.ts +4 -7
- package/dist/controls/index.js +6 -5
- package/dist/dragdrop/index.d.ts +23 -3
- package/dist/dragdrop/index.js +4 -3
- package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
- package/dist/index.d.ts +72 -487
- package/dist/index.js +603 -441
- package/dist/index.js.map +1 -1
- package/dist/job/index.d.ts +8 -0
- package/dist/job/index.js +1 -1
- package/dist/layers/index.d.ts +6 -5
- package/dist/layers/index.js +3 -2
- package/dist/loupe/index.d.ts +100 -30
- package/dist/loupe/index.js +585 -6
- package/dist/loupe/index.js.map +1 -1
- package/dist/overview/index.d.ts +4 -2
- package/dist/overview/index.js +20 -18
- package/dist/overview/index.js.map +1 -1
- package/dist/passthrough/weasel-canvas.d.ts +2 -0
- package/dist/passthrough/weasel-ui.d.ts +2 -2701
- package/dist/passthrough/weasel-ui.js +4 -3
- package/dist/primitives/index.d.ts +37 -2
- package/dist/primitives/index.js +9 -8
- package/dist/state/index.d.ts +7 -5
- package/dist/state/index.js +6 -6
- package/dist/styles.css +150 -126
- package/dist/surface/index.d.ts +10 -2
- package/dist/surface/index.js +1 -1
- package/dist/undo/index.d.ts +5 -3
- package/package.json +14 -13
- package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
- package/src/annotations/AnnotationOverlay.tsx +52 -33
- package/src/annotations/Annotations.less +0 -10
- package/src/annotations/Annotations.overlay.test.tsx +31 -0
- package/src/annotations/MarkList.tsx +4 -8
- package/src/annotations/capture.browser.test.ts +41 -0
- package/src/annotations/capture.ts +14 -7
- package/src/annotations/drawOne.ts +2 -2
- package/src/annotations/frac.test.ts +44 -1
- package/src/annotations/frac.ts +46 -18
- package/src/annotations/index.ts +1 -0
- package/src/annotations/paint.test.ts +76 -46
- package/src/annotations/paint.ts +65 -43
- package/src/annotations/store.test.ts +212 -2
- package/src/annotations/store.ts +130 -27
- package/src/annotations/svgNodes.test.ts +28 -19
- package/src/annotations/svgNodes.ts +6 -6
- package/src/annotations/types.ts +29 -10
- package/src/canvas/AGENTS.md +1 -0
- package/src/canvas/CameraInput.test.tsx +30 -0
- package/src/canvas/CameraInput.tsx +60 -48
- package/src/canvas/CanvasStack.tsx +11 -6
- package/src/canvas/CanvasStackContext.ts +4 -1
- package/src/canvas/LinkedCursor.less +1 -1
- package/src/canvas/Stage.test.tsx +33 -4
- package/src/canvas/Stage.tsx +9 -4
- package/src/canvas/cameraRegistry.test.ts +55 -0
- package/src/canvas/cameraRegistry.ts +87 -0
- package/src/canvas/cameraZoom.test.ts +46 -0
- package/src/canvas/cameraZoom.ts +24 -0
- package/src/canvas/index.ts +14 -2
- package/src/canvas/sharedScope.test.tsx +94 -0
- package/src/canvas/worldSpec.ts +3 -1
- package/src/chrome/ChromeRegions.stories.tsx +1 -0
- package/src/chrome/builtins.test.ts +7 -6
- package/src/chrome/builtins.tsx +5 -1
- package/src/chrome/index.ts +1 -1
- package/src/chrome/merge.test.ts +5 -0
- package/src/chrome/merge.ts +4 -2
- package/src/chrome/regions/PaletteRegion.less +0 -7
- package/src/chrome/regions/PaletteRegion.test.tsx +2 -3
- package/src/chrome/regions/PaletteRegion.tsx +3 -4
- package/src/chrome/regions/SidebarRegion.less +12 -2
- package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
- package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
- package/src/chrome/regions/ViewportRegion.less +6 -0
- package/src/chrome/regions/ViewportRegion.tsx +10 -4
- package/src/chrome/types.ts +4 -2
- package/src/config/auto.ts +1 -0
- package/src/config/builder.test.ts +2 -1
- package/src/config/builder.ts +18 -5
- package/src/config/fromConfigField.test.ts +14 -0
- package/src/config/fromConfigField.ts +18 -4
- package/src/config/path.ts +2 -5
- package/src/config/resolve.ts +4 -0
- package/src/config/types.ts +14 -9
- package/src/controls/ControlPanel.less +1 -1
- package/src/controls/ControlPanel.stories.tsx +3 -2
- package/src/controls/ControlPanel.test.tsx +98 -11
- package/src/controls/ControlPanel.tsx +61 -2
- package/src/dragdrop/DragDropRuntime.tsx +22 -13
- package/src/dragdrop/DragGhost.tsx +3 -0
- package/src/dragdrop/Palette.tsx +2 -0
- package/src/index.test.ts +5 -0
- package/src/index.ts +16 -2
- package/src/instrument/types.ts +0 -6
- package/src/job/useJob.ts +14 -9
- package/src/lab/Lab.tsx +88 -73
- package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
- package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
- package/src/lab/LabFullChrome.stories.tsx +1 -0
- package/src/lab/LabHeader.test.tsx +24 -14
- package/src/lab/LabHeader.tsx +11 -12
- package/src/lab/LabShell.less +9 -17
- package/src/lab/LabSwitcher.browser.test.tsx +27 -0
- package/src/lab/LabSwitcher.less +8 -6
- package/src/lab/LabZoom.test.tsx +223 -0
- package/src/lab/LabZoom.tsx +170 -0
- package/src/lab/Workspace.tsx +48 -52
- package/src/lab/index.ts +1 -0
- package/src/loupe/AGENTS.md +28 -15
- package/src/loupe/CanvasLoupe.tsx +2 -3
- package/src/loupe/DomLoupe.tsx +1 -7
- package/src/loupe/Loupe.less +16 -0
- package/src/loupe/LoupeGestures.tsx +1 -1
- package/src/loupe/TrialLoupe.tsx +120 -57
- package/src/loupe/index.ts +1 -6
- package/src/loupe/types.test.ts +3 -3
- package/src/loupe/types.ts +24 -27
- package/src/loupe/useLoupe.test.tsx +29 -4
- package/src/loupe/useLoupe.ts +20 -17
- package/src/overview/OverviewMarks.tsx +12 -4
- package/src/overview/TrialOverview.tsx +10 -8
- package/src/passthrough/weasel-ui.test.ts +2 -0
- package/src/passthrough/weasel-ui.ts +17 -5
- package/src/primitives/FloatingPanel.test.tsx +11 -0
- package/src/primitives/FloatingPanel.tsx +8 -7
- package/src/primitives/JobProgress.less +2 -1
- package/src/primitives/Legend.stories.tsx +1 -0
- package/src/primitives/Readout.browser.test.tsx +137 -0
- package/src/primitives/Readout.less +12 -0
- package/src/primitives/Readout.stories.tsx +58 -0
- package/src/primitives/Readout.test.tsx +93 -0
- package/src/primitives/Readout.tsx +56 -0
- package/src/primitives/Split.tsx +69 -41
- package/src/primitives/Toolbar.tsx +3 -3
- package/src/primitives/ZoomControl.less +1 -2
- package/src/primitives/index.ts +2 -0
- package/src/specimen/Specimen.stories.tsx +1 -0
- package/src/specimen/Specimen.tsx +2 -3
- package/src/state/Persistence.browser.test.tsx +47 -0
- package/src/state/store.test.ts +5 -1
- package/src/state/undock.ts +3 -0
- package/src/state/useOpenOnce.ts +20 -16
- package/src/state/usePersistedState.test.tsx +1 -1
- package/src/state/view.ts +1 -0
- package/src/styles.less +1 -0
- package/src/surface/index.ts +1 -1
- package/src/surface/useTiledSurface.test.tsx +14 -0
- package/src/surface/useTiledSurface.ts +11 -3
- package/src/theme/Interstellar.stories.tsx +3 -1
- package/src/theme/base.less +21 -47
- package/src/theme/interstellar.test.ts +1 -1
- package/src/theme/interstellar.theme.json +10 -3
- package/src/trial/Trial.annotations.test.tsx +73 -0
- package/src/trial/Trial.less +0 -29
- package/src/trial/Trial.loupe.test.tsx +28 -11
- package/src/trial/Trial.tsx +85 -67
- package/src/trial/TrialChrome.tsx +27 -6
- package/src/trial/index.ts +2 -0
- package/src/trial/loupeSwitch.ts +15 -0
- package/dist/_dts/LayerList.d-BoELAMsM.d.ts +0 -83
- package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
- package/dist/_dts/PropertyField.d-D0ndfIIt.d.ts +0 -404
- package/dist/_dts/Select.d-Cr8-zoup.d.ts +0 -569
- package/dist/chunk-4TT3PNPR.js.map +0 -1
- package/dist/chunk-6FLXL3I7.js.map +0 -1
- package/dist/chunk-ASOK76ZH.js.map +0 -1
- package/dist/chunk-CGHF6RZV.js.map +0 -1
- package/dist/chunk-CQLQPQ4P.js.map +0 -1
- package/dist/chunk-DWMSB4CA.js.map +0 -1
- package/dist/chunk-HXXTULDN.js.map +0 -1
- package/dist/chunk-IJJUK4FU.js.map +0 -1
- package/dist/chunk-IRTGUQ5O.js.map +0 -1
- package/dist/chunk-KHK5FGER.js +0 -145
- package/dist/chunk-KHK5FGER.js.map +0 -1
- package/dist/chunk-NEXR37YJ.js.map +0 -1
- package/dist/chunk-O6FFFOHS.js.map +0 -1
- package/dist/chunk-QGMOA2YE.js.map +0 -1
- package/dist/chunk-RWNDDKOH.js.map +0 -1
- package/dist/chunk-S4NCI32V.js +0 -549
- package/dist/chunk-S4NCI32V.js.map +0 -1
- package/dist/chunk-SBXNQW4G.js +0 -3
- package/dist/chunk-SLAQPUI4.js.map +0 -1
- package/dist/chunk-TJ77A4A3.js.map +0 -1
- package/dist/chunk-TYN6MLXX.js +0 -13864
- package/dist/chunk-TYN6MLXX.js.map +0 -1
- package/dist/chunk-WPLAANH4.js.map +0 -1
- package/src/primitives/useRovingTabIndex.test.ts +0 -48
- package/src/primitives/useRovingTabIndex.ts +0 -88
- package/src/state/Persistence.stories.tsx +0 -75
|
@@ -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,7 +1,8 @@
|
|
|
1
|
-
import { je, Me } from './chunk-
|
|
1
|
+
import { je, Me, i3, a4 } from './chunk-4KSC7NXL.js';
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useLatest } from '@weasel-js/core';
|
|
3
4
|
import { useRef, useEffect, useMemo } from 'react';
|
|
4
|
-
import { asNodeId, Store, createNode
|
|
5
|
+
import { asNodeId, stripStrategy, Store, createNode } from 'windease';
|
|
5
6
|
import { Provider, StrategyRegistryProvider, Container } from 'windease/react';
|
|
6
7
|
|
|
7
8
|
function JobProgress({ job, className }) {
|
|
@@ -61,10 +62,72 @@ function Legend({ entries, className }) {
|
|
|
61
62
|
] }, entry.key);
|
|
62
63
|
}) });
|
|
63
64
|
}
|
|
65
|
+
function Readout({ rows, title, children, className }) {
|
|
66
|
+
return /* @__PURE__ */ jsxs("div", { className: className ? `lk-readout ${className}` : "lk-readout", children: [
|
|
67
|
+
/* @__PURE__ */ jsx(i3, { title, values: "figures", children: rows.map((row, i2) => /* @__PURE__ */ jsx(
|
|
68
|
+
a4,
|
|
69
|
+
{
|
|
70
|
+
label: row.label,
|
|
71
|
+
status: row.status,
|
|
72
|
+
values: row.values,
|
|
73
|
+
children: row.value
|
|
74
|
+
},
|
|
75
|
+
row.key ?? (typeof row.label === "string" ? row.label : i2)
|
|
76
|
+
)) }),
|
|
77
|
+
children != null && /* @__PURE__ */ jsx("div", { className: "lk-readout__footer", children })
|
|
78
|
+
] });
|
|
79
|
+
}
|
|
64
80
|
var ZONE_ID = asNodeId("lk-split");
|
|
65
81
|
var SIDEBAR_ID = asNodeId("lk-split-sidebar");
|
|
66
82
|
var CONTENT_ID = asNodeId("lk-split-content");
|
|
67
83
|
var STRATEGIES = { strip: stripStrategy };
|
|
84
|
+
function createSplitStore({
|
|
85
|
+
side,
|
|
86
|
+
label,
|
|
87
|
+
sidebarWidth,
|
|
88
|
+
minWidth,
|
|
89
|
+
maxWidth,
|
|
90
|
+
contentMinWidth
|
|
91
|
+
}) {
|
|
92
|
+
const store = new Store();
|
|
93
|
+
store.registerNode(
|
|
94
|
+
createNode({
|
|
95
|
+
kind: "zone",
|
|
96
|
+
id: ZONE_ID,
|
|
97
|
+
// A strip's seam resizes the pane before it, which on the end side is the
|
|
98
|
+
// content; 'neighbor' has the seam size the sidebar after it too.
|
|
99
|
+
container: {
|
|
100
|
+
strategyId: "strip",
|
|
101
|
+
config: {
|
|
102
|
+
axis: "x",
|
|
103
|
+
resizable: true,
|
|
104
|
+
...side === "end" ? { resizeMode: "neighbor" } : {}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
const sidebarNode = createNode({
|
|
110
|
+
kind: "sidebar",
|
|
111
|
+
id: SIDEBAR_ID,
|
|
112
|
+
parentId: ZONE_ID,
|
|
113
|
+
meta: { title: label },
|
|
114
|
+
placement: { size: { w: sidebarWidth } },
|
|
115
|
+
hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } }
|
|
116
|
+
});
|
|
117
|
+
const contentNode = createNode({
|
|
118
|
+
kind: "content",
|
|
119
|
+
id: CONTENT_ID,
|
|
120
|
+
parentId: ZONE_ID,
|
|
121
|
+
meta: { title: "Content" },
|
|
122
|
+
hints: { minSize: { w: contentMinWidth, h: 0 } }
|
|
123
|
+
});
|
|
124
|
+
for (const node of side === "end" ? [contentNode, sidebarNode] : [sidebarNode, contentNode]) {
|
|
125
|
+
store.registerNode(node);
|
|
126
|
+
}
|
|
127
|
+
store.showNode(SIDEBAR_ID);
|
|
128
|
+
store.showNode(CONTENT_ID);
|
|
129
|
+
return store;
|
|
130
|
+
}
|
|
68
131
|
function Split({
|
|
69
132
|
sidebar,
|
|
70
133
|
children,
|
|
@@ -83,44 +146,14 @@ function Split({
|
|
|
83
146
|
}) {
|
|
84
147
|
const storeRef = useRef(null);
|
|
85
148
|
if (storeRef.current === null) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
container: {
|
|
94
|
-
strategyId: "strip",
|
|
95
|
-
config: {
|
|
96
|
-
axis: "x",
|
|
97
|
-
resizable: true,
|
|
98
|
-
...side === "end" ? { resizeMode: "neighbor" } : {}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
const sidebarNode = createNode({
|
|
104
|
-
kind: "sidebar",
|
|
105
|
-
id: SIDEBAR_ID,
|
|
106
|
-
parentId: ZONE_ID,
|
|
107
|
-
meta: { title: label },
|
|
108
|
-
placement: { size: { w: width ?? defaultWidth } },
|
|
109
|
-
hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } }
|
|
149
|
+
storeRef.current = createSplitStore({
|
|
150
|
+
side,
|
|
151
|
+
label,
|
|
152
|
+
sidebarWidth: width ?? defaultWidth,
|
|
153
|
+
minWidth,
|
|
154
|
+
maxWidth,
|
|
155
|
+
contentMinWidth
|
|
110
156
|
});
|
|
111
|
-
const contentNode = createNode({
|
|
112
|
-
kind: "content",
|
|
113
|
-
id: CONTENT_ID,
|
|
114
|
-
parentId: ZONE_ID,
|
|
115
|
-
meta: { title: "Content" },
|
|
116
|
-
hints: { minSize: { w: contentMinWidth, h: 0 } }
|
|
117
|
-
});
|
|
118
|
-
for (const node of side === "end" ? [contentNode, sidebarNode] : [sidebarNode, contentNode]) {
|
|
119
|
-
store2.registerNode(node);
|
|
120
|
-
}
|
|
121
|
-
store2.showNode(SIDEBAR_ID);
|
|
122
|
-
store2.showNode(CONTENT_ID);
|
|
123
|
-
storeRef.current = store2;
|
|
124
157
|
}
|
|
125
158
|
const store = storeRef.current;
|
|
126
159
|
const widthRef = useRef(width ?? defaultWidth);
|
|
@@ -139,8 +172,7 @@ function Split({
|
|
|
139
172
|
widthRef.current = width;
|
|
140
173
|
store.patchPlacement(SIDEBAR_ID, { size: { w: width } });
|
|
141
174
|
}, [store, width]);
|
|
142
|
-
const onWidthChangeRef =
|
|
143
|
-
onWidthChangeRef.current = onWidthChange;
|
|
175
|
+
const onWidthChangeRef = useLatest(onWidthChange);
|
|
144
176
|
useEffect(
|
|
145
177
|
() => store.events.on("node.placementChanged", () => {
|
|
146
178
|
if (store.getPlacement(CONTENT_ID)?.size?.w !== void 0) {
|
|
@@ -151,7 +183,7 @@ function Split({
|
|
|
151
183
|
widthRef.current = next;
|
|
152
184
|
onWidthChangeRef.current?.(next);
|
|
153
185
|
}),
|
|
154
|
-
[store]
|
|
186
|
+
[onWidthChangeRef, store]
|
|
155
187
|
);
|
|
156
188
|
const chrome = useMemo(
|
|
157
189
|
() => ({
|
|
@@ -172,6 +204,6 @@ function Split({
|
|
|
172
204
|
) }) });
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
export { JobProgress, Legend, Split };
|
|
176
|
-
//# sourceMappingURL=chunk-
|
|
177
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
export { JobProgress, Legend, Readout, Split };
|
|
208
|
+
//# sourceMappingURL=chunk-FB4MIZOO.js.map
|
|
209
|
+
//# sourceMappingURL=chunk-FB4MIZOO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives/JobProgress.tsx","../src/primitives/Legend.tsx","../src/primitives/Readout.tsx","../src/primitives/Split.tsx"],"names":["jsx","jsxs","i","a"],"mappings":"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","file":"chunk-FB4MIZOO.js","sourcesContent":["import { ErrorIcon, WarningIcon } from '@weasel-js/ui';\nimport type { JobHandle } from '../job/types';\n\n/** Props for `<JobProgress>`. */\nexport interface JobProgressProps {\n job: JobHandle;\n className?: string;\n}\n\n/** A running job's progress, failures and outcome. Determinate once the job\n * reports a total; a job that cannot count up front never sends one, so the\n * bar stays indeterminate rather than inventing a denominator. */\nexport function JobProgress({ job, className }: JobProgressProps) {\n const { status, done, total, failures, error } = job;\n if (status === 'idle') return null;\n\n const determinate = total !== null && total > 0;\n const fraction = determinate ? Math.min(1, done / total) : 0;\n const cls = ['lk-job', `lk-job--${status}`, className].filter(Boolean).join(' ');\n\n return (\n <div className={cls}>\n <div\n className={`lk-job__track${determinate ? '' : ' lk-job__track--indeterminate'}`}\n role=\"progressbar\"\n aria-label=\"Job progress\"\n aria-valuenow={determinate ? done : undefined}\n aria-valuemin={determinate ? 0 : undefined}\n aria-valuemax={determinate ? total : undefined}\n >\n {/* Scaling a full-width bar keeps the fill off the layout path, so\n progress updates never reflow the status bar. */}\n <div\n className=\"lk-job__fill\"\n style={{ transform: `scaleX(${determinate ? fraction : 1})` }}\n />\n </div>\n\n <span className=\"lk-job__count\">\n {done}\n {determinate ? ` / ${total}` : ''}\n </span>\n\n {failures.length > 0 && (\n <span className=\"lk-job__failures\" title={failures.map((f) => f.error).join('\\n')}>\n <WarningIcon size={14} />\n {failures.length} failed\n </span>\n )}\n\n {error && (\n <span className=\"lk-job__error\" title={error}>\n <ErrorIcon size={14} />\n {error}\n </span>\n )}\n\n {status === 'running' && (\n <button type=\"button\" className=\"lk-job__cancel\" onClick={job.cancel}>\n Cancel\n </button>\n )}\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\n\n/** How a legend entry's swatch is drawn, matching how the thing looks on canvas. */\nexport type LegendMark = 'line' | 'dash' | 'dot' | 'band';\n\n/** One row of a legend: a swatch and what it means. */\nexport interface LegendEntry {\n key: string;\n label: string;\n color: string;\n /** Defaults to `'line'`. */\n mark?: LegendMark;\n}\n\n/** Props for `<Legend>`. */\nexport interface LegendProps {\n entries: readonly LegendEntry[];\n className?: string;\n}\n\n/** A color key. Presentational only — no handlers, no state, no hover behavior. */\nexport function Legend({ entries, className }: LegendProps) {\n return (\n <ul className={className ? `lk-legend ${className}` : 'lk-legend'}>\n {entries.map((entry) => {\n const mark = entry.mark ?? 'line';\n return (\n <li className=\"lk-legend__row\" key={entry.key}>\n <span\n aria-hidden=\"true\"\n className={`lk-legend__swatch lk-legend__swatch--${mark}`}\n style={{ '--lk-legend-ink': entry.color } as CSSProperties}\n />\n <span className=\"lk-legend__label\">{entry.label}</span>\n </li>\n );\n })}\n </ul>\n );\n}\n","import { DetailList, type DetailListValues, DetailRow, type DetailRowStatus } from '@weasel-js/ui';\nimport type { ReactNode } from 'react';\n\n/** One measurement in a {@link Readout}. */\nexport interface ReadoutRow {\n /** React key. Defaults to `label` when that is a string, else the row's index. */\n key?: string;\n label: ReactNode;\n /** `null` or `undefined` keeps the row in place showing an en dash, so the\n * readout holds its height while a measurement comes and goes. */\n value?: ReactNode;\n /** A dot in the status color before the value. Color is never the only\n * signal: the value has to say the same thing in words. */\n status?: DetailRowStatus;\n /** `text` sets this row's value as wrapping prose instead of a figure. */\n values?: DetailListValues;\n}\n\n/** Props for {@link Readout}. */\nexport interface ReadoutProps {\n rows: readonly ReadoutRow[];\n /** Heading above the rows, which also names the list. */\n title?: ReactNode;\n /** Drawn below the rows — a small table, a note. */\n children?: ReactNode;\n className?: string;\n}\n\n/**\n * Values a lab only reads — measurements shown beside its picture, such as\n * \"Lock margin +47.9°\". A {@link DetailList} set as figures: labels take the\n * params label recipe and `--wzl-params-label-width` rail, so a readout lines\n * up with a `ControlPanel` beside it, and values sit right-aligned in the mono\n * face with spaces kept, so figure-space padding aligns a column on its\n * decimal point. Rows compose by hand as `DetailRow`s inside a `DetailList`\n * with `values=\"figures\"`.\n */\nexport function Readout({ rows, title, children, className }: ReadoutProps) {\n return (\n <div className={className ? `lk-readout ${className}` : 'lk-readout'}>\n <DetailList title={title} values=\"figures\">\n {rows.map((row, i) => (\n <DetailRow\n key={row.key ?? (typeof row.label === 'string' ? row.label : i)}\n label={row.label}\n status={row.status}\n values={row.values}\n >\n {row.value}\n </DetailRow>\n ))}\n </DetailList>\n {children != null && <div className=\"lk-readout__footer\">{children}</div>}\n </div>\n );\n}\n","import { useLatest } from '@weasel-js/core';\nimport { type ReactNode, useEffect, useMemo, useRef } from 'react';\nimport { asNodeId, createNode, Store, stripStrategy } from 'windease';\nimport { type ChromeMap, Container, Provider, StrategyRegistryProvider } from 'windease/react';\n\nconst ZONE_ID = asNodeId('lk-split');\nconst SIDEBAR_ID = asNodeId('lk-split-sidebar');\nconst CONTENT_ID = asNodeId('lk-split-content');\nconst STRATEGIES = { strip: stripStrategy as never };\n\n/** Props for `<Split>`. */\nexport interface SplitProps {\n /** The sidebar pane's contents. */\n sidebar: ReactNode;\n /** The edge the sidebar sits on. Read once, when the strip mounts. Default `'start'`. */\n side?: 'start' | 'end';\n /** The content pane's contents. */\n children: ReactNode;\n /** Names the sidebar pane, and through it the seam. Default `'Sidebar'`. */\n label?: string;\n /** Extra classes on the strip, which always has `lk-split`. */\n className?: string;\n /** The class on the sidebar pane. */\n sidebarClassName?: string;\n /** The class on the content pane. */\n contentClassName?: string;\n /** The sidebar's current extent in pixels. Omit to leave it unpersisted: the\n * seam still works, its result just does not outlive the mount. */\n width?: number;\n /** Where the sidebar starts before anyone drags it. */\n defaultWidth?: number;\n minWidth?: number;\n maxWidth?: number;\n /** How little the content pane may be squeezed to. Reported as the seam's\n * reachable maximum, so the drag stops there rather than clamping silently. */\n contentMinWidth?: number;\n /** Fires through the drag, not on release: the pane is already there. */\n onWidthChange?: (width: number) => void;\n /**\n * Fixed extent. Omit in an app — the strip measures its own box. Supply it\n * where nothing measures, notably jsdom, or both panes lay out at zero.\n */\n viewport?: { w: number; h: number };\n}\n\ninterface SplitInit {\n side: 'start' | 'end';\n label: string;\n sidebarWidth: number;\n minWidth: number;\n maxWidth: number;\n contentMinWidth: number;\n}\n\n/** A strip holding the sidebar and the content pane, sized as the first render asks. */\nfunction createSplitStore({\n side,\n label,\n sidebarWidth,\n minWidth,\n maxWidth,\n contentMinWidth,\n}: SplitInit): Store {\n const store = new Store();\n store.registerNode(\n createNode({\n kind: 'zone',\n id: ZONE_ID,\n // A strip's seam resizes the pane before it, which on the end side is the\n // content; 'neighbor' has the seam size the sidebar after it too.\n container: {\n strategyId: 'strip',\n config: {\n axis: 'x',\n resizable: true,\n ...(side === 'end' ? { resizeMode: 'neighbor' } : {}),\n },\n },\n }),\n );\n const sidebarNode = createNode({\n kind: 'sidebar',\n id: SIDEBAR_ID,\n parentId: ZONE_ID,\n meta: { title: label },\n placement: { size: { w: sidebarWidth } },\n hints: { minSize: { w: minWidth, h: 0 }, maxSize: { w: maxWidth, h: 0 } },\n });\n const contentNode = createNode({\n kind: 'content',\n id: CONTENT_ID,\n parentId: ZONE_ID,\n meta: { title: 'Content' },\n hints: { minSize: { w: contentMinWidth, h: 0 } },\n });\n // A strip lays its children out in registration order.\n for (const node of side === 'end' ? [contentNode, sidebarNode] : [sidebarNode, contentNode]) {\n store.registerNode(node);\n }\n store.showNode(SIDEBAR_ID);\n store.showNode(CONTENT_ID);\n return store;\n}\n\n/**\n * A sidebar and a content pane as a two-pane strip with a draggable seam.\n *\n * The seam is `stripStrategy`'s own resize affordance, so it arrives as a\n * `role=\"separator\"` carrying the reachable range, operable by pointer and by\n * arrows / Home / End, and clamped against the content pane's floor rather\n * than against the sidebar's alone.\n */\nexport function Split({\n sidebar,\n children,\n side = 'start',\n label = 'Sidebar',\n className,\n sidebarClassName,\n contentClassName,\n width,\n defaultWidth = 320,\n minWidth = 140,\n maxWidth = 720,\n contentMinWidth = 160,\n onWidthChange,\n viewport,\n}: SplitProps) {\n // The cross-axis half of every size hint below is inert: a horizontal strip\n // stretches its panes to the container's height and never reads `h`.\n const storeRef = useRef<Store | null>(null);\n if (storeRef.current === null) {\n storeRef.current = createSplitStore({\n side,\n label,\n sidebarWidth: width ?? defaultWidth,\n minWidth,\n maxWidth,\n contentMinWidth,\n });\n }\n const store = storeRef.current;\n\n // What the store last held, so the placement event can tell a drag from the\n // echo of our own write and a controlled `width` does not fight the seam.\n const widthRef = useRef(width ?? defaultWidth);\n\n useEffect(() => {\n store.setHints(SIDEBAR_ID, {\n minSize: { w: minWidth, h: 0 },\n maxSize: { w: maxWidth, h: 0 },\n });\n store.setHints(CONTENT_ID, { minSize: { w: contentMinWidth, h: 0 } });\n }, [store, minWidth, maxWidth, contentMinWidth]);\n\n useEffect(() => {\n store.setMeta(SIDEBAR_ID, { title: label });\n }, [store, label]);\n\n useEffect(() => {\n if (width === undefined || width === widthRef.current) return;\n widthRef.current = width;\n store.patchPlacement(SIDEBAR_ID, { size: { w: width } });\n }, [store, width]);\n\n const onWidthChangeRef = useLatest(onWidthChange);\n useEffect(\n () =>\n store.events.on('node.placementChanged', () => {\n // A neighbor drag pins the content's width too; unpinned, it goes on filling the strip.\n if ((store.getPlacement(CONTENT_ID)?.size as { w?: number } | undefined)?.w !== undefined) {\n store.patchPlacement(CONTENT_ID, { size: {} });\n }\n const next = (store.getPlacement(SIDEBAR_ID)?.size as { w?: number } | undefined)?.w;\n if (typeof next !== 'number' || next === widthRef.current) return;\n widthRef.current = next;\n onWidthChangeRef.current?.(next);\n }),\n [onWidthChangeRef, store],\n );\n\n const chrome = useMemo<ChromeMap>(\n () => ({\n sidebar: () => <div className={sidebarClassName}>{sidebar}</div>,\n content: () => <div className={contentClassName}>{children}</div>,\n }),\n [sidebar, children, sidebarClassName, contentClassName],\n );\n\n return (\n <Provider store={store}>\n <StrategyRegistryProvider strategies={STRATEGIES}>\n <Container\n parentId={ZONE_ID}\n chrome={chrome}\n className={className ? `lk-split windease-zone ${className}` : 'lk-split windease-zone'}\n affordances\n viewport={viewport}\n />\n </StrategyRegistryProvider>\n </Provider>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_FRAME } from './chunk-
|
|
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-
|
|
19
|
-
//# sourceMappingURL=chunk-
|
|
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-
|
|
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"]}
|