@weasel-js/labkit 1.3.0-pre.0 → 1.4.0-pre.0
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/dist/_dts/CanvasStackContext-DtAn_3O-.d.ts +42 -0
- package/dist/_dts/DrawCommand-B3bskUsC.d.ts +564 -0
- package/dist/_dts/{PrefsForm-BYa6cWnO.d.ts → PrefsForm-BkUJZx0A.d.ts} +4 -1
- package/dist/_dts/fitViewToBounds-dZ2UDB6e.d.ts +21 -0
- package/dist/_dts/frac-Cp3NivlC.d.ts +728 -0
- package/dist/_dts/index-BDVzvRzQ.d.ts +236 -0
- package/dist/_dts/shapeKinds-Cx_rxwsa.d.ts +87 -0
- package/dist/_dts/{DrawCommand-DBB45NfN.d.ts → types-C-gh9Ap-.d.ts} +1 -582
- package/dist/_dts/{types-AHlQxBNN.d.ts → types-D6s4b7if.d.ts} +2 -2
- package/dist/_dts/{types-1Sdxy_Pv.d.ts → types-DYMaEvM5.d.ts} +26 -1
- package/dist/_dts/{useTrialState-CsGMjhu9.d.ts → useTrialState-gmMvZqPc.d.ts} +7 -2
- package/dist/canvas/index.d.ts +43 -25
- package/dist/canvas/index.js +5 -3
- package/dist/chrome/index.d.ts +9 -6
- package/dist/chrome/index.js +7 -6
- package/dist/chunk-2AYGEN57.js +32 -0
- package/dist/chunk-2AYGEN57.js.map +1 -0
- package/dist/{chunk-RVNN4CHQ.js → chunk-3P5TTTA7.js} +16 -8
- package/dist/chunk-3P5TTTA7.js.map +1 -0
- package/dist/{chunk-NS54R52R.js → chunk-3ZELRRBV.js} +45 -40
- package/dist/chunk-3ZELRRBV.js.map +1 -0
- package/dist/{chunk-HFDVGF4X.js → chunk-4EY67BKJ.js} +32 -7
- package/dist/chunk-4EY67BKJ.js.map +1 -0
- package/dist/chunk-5TCEVMPI.js +140 -0
- package/dist/chunk-5TCEVMPI.js.map +1 -0
- package/dist/{chunk-O7NVSCLN.js → chunk-6JMU56CU.js} +133 -134
- package/dist/chunk-6JMU56CU.js.map +1 -0
- package/dist/{chunk-CPUJ3QXL.js → chunk-CQLQPQ4P.js} +2 -2
- package/dist/chunk-CQLQPQ4P.js.map +1 -0
- package/dist/chunk-CTRKTLYZ.js +33 -0
- package/dist/chunk-CTRKTLYZ.js.map +1 -0
- package/dist/chunk-EQIB2PGC.js +458 -0
- package/dist/chunk-EQIB2PGC.js.map +1 -0
- package/dist/chunk-HEORBLVT.js +7128 -0
- package/dist/chunk-HEORBLVT.js.map +1 -0
- package/dist/{chunk-V7PRSIRQ.js → chunk-JDDIZSLL.js} +4 -4
- package/dist/chunk-JDDIZSLL.js.map +1 -0
- package/dist/chunk-LITE5YFB.js +669 -0
- package/dist/chunk-LITE5YFB.js.map +1 -0
- package/dist/{chunk-Z6HJ5FEM.js → chunk-ROQDRXKW.js} +732 -315
- package/dist/chunk-ROQDRXKW.js.map +1 -0
- package/dist/chunk-SBXNQW4G.js +3 -0
- package/dist/chunk-SBXNQW4G.js.map +1 -0
- package/dist/{chunk-4TMMVIDM.js → chunk-XJ6N32QP.js} +50 -6
- package/dist/chunk-XJ6N32QP.js.map +1 -0
- package/dist/chunk-YQJNT4XQ.js +293 -0
- package/dist/chunk-YQJNT4XQ.js.map +1 -0
- package/dist/controls/index.d.ts +4 -28
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +50 -5
- package/dist/dragdrop/index.js +3 -1
- package/dist/index.d.ts +660 -302
- package/dist/index.js +1793 -587
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +6 -5
- package/dist/layers/index.js +4 -2
- package/dist/loupe/index.d.ts +187 -0
- package/dist/loupe/index.js +7 -0
- package/dist/loupe/index.js.map +1 -0
- package/dist/passthrough/weasel-canvas.d.ts +3 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +151 -91
- package/dist/passthrough/weasel-ui.js +3 -2
- package/dist/primitives/index.d.ts +3 -1
- package/dist/primitives/index.js +6 -5
- package/dist/state/index.d.ts +3 -3
- package/dist/state/index.js +2 -2
- package/dist/styles.css +229 -703
- package/dist/surface/index.d.ts +18 -2
- package/dist/surface/index.js +2 -2
- package/dist/ui/layers/index.d.ts +8 -2
- package/dist/ui/layers/index.js +2 -4
- package/dist/undo/index.d.ts +5 -4
- package/package.json +14 -7
- package/src/annotations/AnnotationOverlay.tsx +205 -0
- package/src/annotations/AnnotationTargets.tsx +37 -0
- package/src/annotations/Annotations.less +129 -0
- package/src/annotations/Annotations.meaning.test.tsx +111 -0
- package/src/annotations/Annotations.overlay.test.tsx +142 -0
- package/src/annotations/AnnotationsContext.ts +49 -0
- package/src/annotations/ExportMenu.test.tsx +86 -0
- package/src/annotations/ExportMenu.tsx +182 -0
- package/src/annotations/MarkList.tsx +75 -0
- package/src/annotations/capture.test.ts +140 -0
- package/src/annotations/capture.ts +237 -0
- package/src/annotations/drawOne.test.ts +56 -0
- package/src/annotations/drawOne.ts +47 -0
- package/src/annotations/frac.test.ts +59 -0
- package/src/annotations/frac.ts +66 -0
- package/src/annotations/history.test.ts +82 -0
- package/src/annotations/history.ts +118 -0
- package/src/annotations/index.ts +37 -0
- package/src/annotations/paint.test.ts +125 -0
- package/src/annotations/paint.ts +130 -0
- package/src/annotations/staleness.test.ts +56 -0
- package/src/annotations/staleness.ts +41 -0
- package/src/annotations/store.test.ts +175 -0
- package/src/annotations/store.ts +317 -0
- package/src/annotations/svgNodes.test.ts +77 -0
- package/src/annotations/svgNodes.ts +74 -0
- package/src/annotations/toolMap.test.ts +36 -0
- package/src/annotations/toolMap.ts +54 -0
- package/src/annotations/types.ts +222 -0
- package/src/annotations/view.test.ts +37 -0
- package/src/annotations/view.ts +40 -0
- package/src/canvas/AGENTS.md +55 -5
- package/src/canvas/CanvasStack.test.tsx +27 -1
- package/src/canvas/CanvasStack.tsx +29 -4
- package/src/canvas/CanvasStackContext.ts +23 -4
- package/src/canvas/camera.test.ts +78 -0
- package/src/canvas/camera.ts +62 -0
- package/src/canvas/canvasCoords.test.ts +26 -0
- package/src/canvas/canvasCoords.ts +20 -7
- package/src/canvas/index.ts +5 -1
- package/src/canvas/useLayerScheduler.ts +7 -3
- package/src/canvas/usePanZoom.test.ts +36 -5
- package/src/canvas/usePanZoom.ts +20 -15
- package/src/canvas/worldSpec.test.ts +63 -0
- package/src/canvas/worldSpec.ts +48 -0
- package/src/chrome/builtins.test.ts +31 -1
- package/src/chrome/builtins.tsx +63 -19
- package/src/chrome/regions/PaletteRegion.test.tsx +22 -1
- package/src/chrome/regions/PaletteRegion.tsx +4 -0
- package/src/chrome/regions/SidebarRegion.tsx +37 -13
- package/src/chrome/regions/ToolbarRegion.tsx +2 -1
- package/src/chrome/regions/ViewportRegion.tsx +9 -1
- package/src/chrome/regions/regions.test.tsx +6 -1
- package/src/chrome/types.ts +20 -0
- package/src/config/builder.test.ts +7 -1
- package/src/config/builder.ts +1 -5
- package/src/config/resolve.test.ts +1 -2
- package/src/controls/ControlPanel.stories.tsx +41 -2
- package/src/controls/ControlPanel.test.tsx +69 -9
- package/src/controls/ControlPanel.tsx +106 -25
- package/src/dragdrop/DragDropRuntime.tsx +8 -2
- package/src/dragdrop/dragDrop.test.tsx +29 -2
- package/src/dragdrop/index.ts +11 -0
- package/src/index.test.ts +22 -0
- package/src/index.ts +136 -4
- package/src/instrument/SineWave.smoke.test.tsx +1 -0
- package/src/instrument/types.ts +24 -1
- package/src/lab/Lab.surface.test.tsx +162 -0
- package/src/lab/Lab.tsx +102 -17
- package/src/lab/Lab.undock.test.tsx +85 -0
- package/src/lab/LabFullChrome.stories.tsx +20 -0
- package/src/lab/LabShell.less +11 -0
- package/src/lab/Workspace.less +73 -0
- package/src/lab/Workspace.surface.test.tsx +2 -0
- package/src/lab/Workspace.tsx +97 -8
- package/src/lab/index.ts +1 -1
- package/src/lab/panelHost.ts +37 -0
- package/src/layers/AGENTS.md +1 -1
- package/src/layers/LayerList.tsx +1 -1
- package/src/loupe/AGENTS.md +49 -0
- package/src/loupe/CanvasLoupe.tsx +83 -0
- package/src/loupe/DomLoupe.tsx +62 -0
- package/src/loupe/Loupe.less +38 -0
- package/src/loupe/LoupeBubble.tsx +32 -0
- package/src/loupe/TrialLoupe.tsx +93 -0
- package/src/loupe/canvasLens.test.ts +205 -0
- package/src/loupe/canvasLens.ts +141 -0
- package/src/loupe/index.ts +19 -0
- package/src/loupe/types.test.ts +29 -0
- package/src/loupe/types.ts +90 -0
- package/src/loupe/useHostSize.ts +30 -0
- package/src/loupe/useLoupe.test.tsx +197 -0
- package/src/loupe/useLoupe.ts +189 -0
- package/src/passthrough/weasel-ui.ts +25 -17
- package/src/primitives/FloatingPanel.test.tsx +76 -1
- package/src/primitives/FloatingPanel.tsx +19 -3
- package/src/primitives/ScaleIndicator.test.tsx +7 -2
- package/src/primitives/Sidebar.less +18 -0
- package/src/primitives/Toolbar.less +8 -0
- package/src/primitives/Toolbar.tsx +5 -0
- package/src/primitives/useRovingTabIndex.test.ts +21 -0
- package/src/primitives/useRovingTabIndex.ts +26 -17
- package/src/state/document.test.ts +23 -0
- package/src/state/document.ts +14 -2
- package/src/state/index.ts +2 -0
- package/src/state/store.test.ts +24 -0
- package/src/state/store.ts +35 -1
- package/src/state/types.ts +11 -0
- package/src/state/undock.test.ts +40 -0
- package/src/state/undock.ts +39 -0
- package/src/styles.less +2 -4
- package/src/surface/SurfaceContext.ts +4 -0
- package/src/surface/index.ts +8 -3
- package/src/surface/useSurfaceTile.test.tsx +2 -0
- package/src/surface/useSurfaceTile.ts +7 -1
- package/src/surface/useTiledSurface.test.tsx +58 -0
- package/src/surface/useTiledSurface.ts +38 -3
- package/src/theme/Interstellar.stories.tsx +1 -1
- package/src/trial/Trial.annotations.persist.test.tsx +166 -0
- package/src/trial/Trial.annotations.test.tsx +121 -0
- package/src/trial/Trial.canvas.test.tsx +76 -1
- package/src/trial/Trial.config.test.tsx +3 -8
- package/src/trial/Trial.less +19 -0
- package/src/trial/Trial.loupe.test.tsx +128 -0
- package/src/trial/Trial.stories.tsx +1 -0
- package/src/trial/Trial.test.tsx +12 -0
- package/src/trial/Trial.trialId.test.tsx +36 -0
- package/src/trial/Trial.tsx +215 -40
- package/src/trial/TrialChrome.tsx +35 -0
- package/src/trial/UndockedSections.tsx +65 -0
- package/src/trial/trialOps.test.ts +21 -0
- package/src/trial/trialOps.ts +5 -3
- package/src/ui/layers/index.ts +5 -1
- package/dist/_dts/index-DgcNdEdh.d.ts +0 -314
- package/dist/chunk-4TMMVIDM.js.map +0 -1
- package/dist/chunk-CPUJ3QXL.js.map +0 -1
- package/dist/chunk-HFDVGF4X.js.map +0 -1
- package/dist/chunk-NS54R52R.js.map +0 -1
- package/dist/chunk-O2BULFHX.js +0 -152
- package/dist/chunk-O2BULFHX.js.map +0 -1
- package/dist/chunk-O7NVSCLN.js.map +0 -1
- package/dist/chunk-PO6L3NSH.js +0 -366
- package/dist/chunk-PO6L3NSH.js.map +0 -1
- package/dist/chunk-PQJ5B2U2.js +0 -27
- package/dist/chunk-PQJ5B2U2.js.map +0 -1
- package/dist/chunk-RVNN4CHQ.js.map +0 -1
- package/dist/chunk-TLGRYALP.js +0 -6151
- package/dist/chunk-TLGRYALP.js.map +0 -1
- package/dist/chunk-V7PRSIRQ.js.map +0 -1
- package/dist/chunk-Z6HJ5FEM.js.map +0 -1
- package/dist/chunk-ZZAYVX4X.js +0 -505
- package/dist/chunk-ZZAYVX4X.js.map +0 -1
- package/src/primitives/DragHandleGlyph.tsx +0 -29
- package/src/ui/format.test.ts +0 -33
- package/src/ui/format.ts +0 -30
- package/src/ui/layers/LayerStack.less +0 -143
- package/src/ui/layers/LayerStack.stories.tsx +0 -45
- package/src/ui/layers/LayerStack.test.tsx +0 -170
- package/src/ui/layers/LayerStack.tsx +0 -208
- package/src/ui/properties/CheckboxRow.stories.tsx +0 -27
- package/src/ui/properties/ColorRow.stories.tsx +0 -106
- package/src/ui/properties/CurveField.less +0 -48
- package/src/ui/properties/CurveField.stories.tsx +0 -20
- package/src/ui/properties/CurveField.test.tsx +0 -127
- package/src/ui/properties/CurveField.tsx +0 -184
- package/src/ui/properties/EffectCard.tsx +0 -324
- package/src/ui/properties/Gallery.stories.tsx +0 -178
- package/src/ui/properties/NumberRow.stories.tsx +0 -65
- package/src/ui/properties/PropertyGroup.less +0 -50
- package/src/ui/properties/PropertyGroup.stories.tsx +0 -34
- package/src/ui/properties/PropertyGroup.test.tsx +0 -33
- package/src/ui/properties/PropertyGroup.tsx +0 -45
- package/src/ui/properties/PropertyList.stories.tsx +0 -83
- package/src/ui/properties/PropertyPanel.less +0 -606
- package/src/ui/properties/PropertyPanel.stories.tsx +0 -190
- package/src/ui/properties/PropertyPanel.test.tsx +0 -193
- package/src/ui/properties/PropertyPanel.tsx +0 -469
- package/src/ui/properties/PropertyRow.stories.tsx +0 -53
- package/src/ui/properties/SelectRow.stories.tsx +0 -58
- package/src/ui/properties/SliderRow.stories.tsx +0 -74
- package/src/ui/properties/SpeechBalloonPanels.stories.tsx +0 -398
- package/src/ui/properties/TextRow.stories.tsx +0 -62
- package/src/ui/properties/ToggleRow.stories.tsx +0 -57
- package/src/ui/properties/index.ts +0 -39
- package/src/ui/properties/storyLayouts.tsx +0 -36
package/dist/canvas/index.d.ts
CHANGED
|
@@ -1,50 +1,68 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import * as react from 'react';
|
|
3
2
|
import { ReactNode } from 'react';
|
|
4
|
-
import { V as ViewTransform,
|
|
5
|
-
|
|
6
|
-
import '../_dts/
|
|
7
|
-
|
|
3
|
+
import { V as ViewTransform, c as WorldSpec, a2 as ViewportSize, a as Point, W as WorldFrame } from '../_dts/frac-Cp3NivlC.js';
|
|
4
|
+
export { x as DEFAULT_FRAME, a4 as applyCamera, aa as resolveFrame } from '../_dts/frac-Cp3NivlC.js';
|
|
5
|
+
import { C as CanvasLayerDescriptor } from '../_dts/CanvasStackContext-DtAn_3O-.js';
|
|
6
|
+
export { a as CanvasStackContext, b as CanvasStackContextValue, c as CanvasStackSurface } from '../_dts/CanvasStackContext-DtAn_3O-.js';
|
|
7
|
+
import '../_dts/types-D6s4b7if.js';
|
|
8
|
+
import '../_dts/PrefsForm-BkUJZx0A.js';
|
|
9
|
+
import '../_dts/types-DYMaEvM5.js';
|
|
8
10
|
import '../_dts/types-DJ79Tg5J.js';
|
|
9
|
-
|
|
10
|
-
/** One layer of a canvas stack: its id, whether it is currently shown, and how
|
|
11
|
-
* it paints itself. */
|
|
12
|
-
interface CanvasLayerDescriptor {
|
|
13
|
-
id: string;
|
|
14
|
-
visible: boolean;
|
|
15
|
-
render: (ctx: CanvasRenderingContext2D, view: ViewTransform) => void;
|
|
16
|
-
}
|
|
11
|
+
import '../_dts/types-C-gh9Ap-.js';
|
|
17
12
|
|
|
18
13
|
/** Props for `<CanvasStack>`. */
|
|
19
14
|
interface CanvasStackProps {
|
|
20
15
|
layers: CanvasLayerDescriptor[];
|
|
21
16
|
view: ViewTransform;
|
|
22
17
|
onViewChange: (v: ViewTransform) => void;
|
|
18
|
+
/** The instrument's coordinate system. Omitted, world (0,0) sits at the
|
|
19
|
+
* element's top-left with y running down. */
|
|
20
|
+
worldSpec?: WorldSpec;
|
|
23
21
|
minZoom?: number;
|
|
24
22
|
maxZoom?: number;
|
|
25
23
|
width?: number | string;
|
|
26
24
|
height?: number | string;
|
|
27
25
|
className?: string;
|
|
26
|
+
/** Fired whenever the stack is measured, so a consumer can place a view that
|
|
27
|
+
* only makes sense in terms of the viewport. */
|
|
28
|
+
onResize?: (size: ViewportSize) => void;
|
|
28
29
|
onHitTest?: (worldPos: Point) => void;
|
|
29
30
|
children?: ReactNode;
|
|
30
31
|
}
|
|
31
32
|
/** Stacks one `<canvas>` per layer and drives them from a shared view, so a
|
|
32
33
|
* layer that changes rarely is not redrawn with one that changes every frame.
|
|
33
34
|
* Handles sizing, device pixel ratio, and pan/zoom. */
|
|
34
|
-
declare function CanvasStack({ layers, view, onViewChange, minZoom, maxZoom, width, height, className, onHitTest, children, }: CanvasStackProps): react_jsx_runtime.JSX.Element;
|
|
35
|
+
declare function CanvasStack({ layers, view, onViewChange, worldSpec, minZoom, maxZoom, width, height, className, onResize, onHitTest, children, }: CanvasStackProps): react_jsx_runtime.JSX.Element;
|
|
35
36
|
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
/** Bounds and coordinate system a {@link zoomAt} works in. */
|
|
38
|
+
interface ZoomAtOptions {
|
|
39
|
+
/** The instrument's coordinate system, resolved against the viewport.
|
|
40
|
+
* Omitted, `at` is measured from the element's top-left. */
|
|
41
|
+
frame?: WorldFrame;
|
|
42
|
+
min?: number;
|
|
43
|
+
max?: number;
|
|
40
44
|
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Zoom a view by `factor` about a fixed point, so whatever world coordinate
|
|
47
|
+
* `at` was over stays under it.
|
|
48
|
+
*
|
|
49
|
+
* `at` is in the element's own pixels — a cursor position, or the centre of a
|
|
50
|
+
* lens. The clamp is applied before the pan is solved, so a zoom that hits a
|
|
51
|
+
* bound still anchors on the zoom it actually reached.
|
|
52
|
+
*/
|
|
53
|
+
declare function zoomAt(view: ViewTransform, factor: number, at: Point, { frame, min, max }?: ZoomAtOptions): ViewTransform;
|
|
54
|
+
/** The view that puts a world point at the centre of a `size` viewport, at
|
|
55
|
+
* `zoom`. What a lens showing a region around one point renders through. */
|
|
56
|
+
declare function centerOn(world: Point, zoom: number, size: ViewportSize, frame?: WorldFrame): ViewTransform;
|
|
43
57
|
|
|
44
|
-
/** Project a world point into screen coordinates under a view.
|
|
45
|
-
|
|
58
|
+
/** Project a world point into screen coordinates under a view.
|
|
59
|
+
*
|
|
60
|
+
* `frame` is the instrument's declared coordinate system, resolved against the
|
|
61
|
+
* viewport; omitting it gives labkit's original one — origin at the top-left,
|
|
62
|
+
* y downward. */
|
|
63
|
+
declare function worldToScreen(world: Point, view: ViewTransform, frame?: WorldFrame): Point;
|
|
46
64
|
/** Unproject a screen point back to world coordinates under a view. */
|
|
47
|
-
declare function screenToWorld(screen: Point, view: ViewTransform): Point;
|
|
65
|
+
declare function screenToWorld(screen: Point, view: ViewTransform, frame?: WorldFrame): Point;
|
|
48
66
|
|
|
49
|
-
export { CanvasStack,
|
|
50
|
-
export type {
|
|
67
|
+
export { CanvasLayerDescriptor, CanvasStack, ViewportSize, WorldFrame, WorldSpec, centerOn, screenToWorld, worldToScreen, zoomAt };
|
|
68
|
+
export type { CanvasStackProps, ZoomAtOptions };
|
package/dist/canvas/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { CanvasStack
|
|
2
|
-
export {
|
|
3
|
-
|
|
1
|
+
export { CanvasStack } from '../chunk-3ZELRRBV.js';
|
|
2
|
+
export { centerOn, zoomAt } from '../chunk-CTRKTLYZ.js';
|
|
3
|
+
export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from '../chunk-2AYGEN57.js';
|
|
4
|
+
export { CanvasStackContext } from '../chunk-CQLQPQ4P.js';
|
|
5
|
+
import '../chunk-ROQDRXKW.js';
|
|
4
6
|
//# sourceMappingURL=index.js.map
|
|
5
7
|
//# sourceMappingURL=index.js.map
|
package/dist/chrome/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { I as Instrument,
|
|
3
|
-
export {
|
|
1
|
+
import { c as ControlRenderer } from '../_dts/types-D6s4b7if.js';
|
|
2
|
+
import { I as Instrument, _ as TrialChromeContext, m as TrialContribution } from '../_dts/frac-Cp3NivlC.js';
|
|
3
|
+
export { z as IconComponent, O as SidebarSection, Q as StatusReadout, Y as ToolItem, Z as ToolbarItem, $ as TrialRegion, a1 as ViewportControl } from '../_dts/frac-Cp3NivlC.js';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
|
-
import '../_dts/PrefsForm-
|
|
5
|
+
import '../_dts/PrefsForm-BkUJZx0A.js';
|
|
6
6
|
import 'react';
|
|
7
|
-
import '../_dts/types-
|
|
7
|
+
import '../_dts/types-DYMaEvM5.js';
|
|
8
8
|
import '../_dts/types-DJ79Tg5J.js';
|
|
9
|
+
import '../_dts/types-C-gh9Ap-.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* The contributions a trial gets from what its instrument declared. This is
|
|
@@ -44,7 +45,9 @@ interface SidebarRegionProps {
|
|
|
44
45
|
contributions: readonly TrialContribution[];
|
|
45
46
|
ctx: TrialChromeContext;
|
|
46
47
|
}
|
|
47
|
-
/** Lays a trial's `sidebar` contributions out as titled, collapsible sections.
|
|
48
|
+
/** Lays a trial's `sidebar` contributions out as titled, collapsible sections.
|
|
49
|
+
* A section the trial has torn out is not rendered here — `Trial` portals its
|
|
50
|
+
* body into the workspace instead. */
|
|
48
51
|
declare function SidebarRegion({ contributions, ctx }: SidebarRegionProps): react_jsx_runtime.JSX.Element | null;
|
|
49
52
|
|
|
50
53
|
/** Props for `<StatusRegion>`. */
|
package/dist/chrome/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
export { PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, mergeContributions, suppressContributions } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
5
|
-
import '../chunk-
|
|
6
|
-
import '../chunk-
|
|
1
|
+
export { PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, mergeContributions, suppressContributions } from '../chunk-LITE5YFB.js';
|
|
2
|
+
import '../chunk-6JMU56CU.js';
|
|
3
|
+
import '../chunk-YQJNT4XQ.js';
|
|
4
|
+
import '../chunk-SBXNQW4G.js';
|
|
5
|
+
import '../chunk-HEORBLVT.js';
|
|
6
|
+
import '../chunk-CQLQPQ4P.js';
|
|
7
|
+
import '../chunk-ROQDRXKW.js';
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
8
9
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/canvas/worldSpec.ts
|
|
2
|
+
var DEFAULT_FRAME = { originPx: { x: 0, y: 0 }, yDir: 1 };
|
|
3
|
+
function resolveFrame(spec, size) {
|
|
4
|
+
if (!spec) return DEFAULT_FRAME;
|
|
5
|
+
const origin = spec.origin ?? { x: 0, y: 0 };
|
|
6
|
+
return {
|
|
7
|
+
originPx: { x: origin.x * size.width, y: origin.y * size.height },
|
|
8
|
+
yDir: spec.yAxis === "up" ? -1 : 1
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function applyCamera(ctx, view, frame = DEFAULT_FRAME) {
|
|
12
|
+
ctx.translate(frame.originPx.x + view.pan.x, frame.originPx.y + view.pan.y);
|
|
13
|
+
ctx.scale(view.zoom, view.zoom * frame.yDir);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/canvas/canvasCoords.ts
|
|
17
|
+
function worldToScreen(world, view, frame = DEFAULT_FRAME) {
|
|
18
|
+
return {
|
|
19
|
+
x: frame.originPx.x + view.pan.x + world.x * view.zoom,
|
|
20
|
+
y: frame.originPx.y + view.pan.y + world.y * view.zoom * frame.yDir
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function screenToWorld(screen, view, frame = DEFAULT_FRAME) {
|
|
24
|
+
return {
|
|
25
|
+
x: (screen.x - frame.originPx.x - view.pan.x) / view.zoom,
|
|
26
|
+
y: (screen.y - frame.originPx.y - view.pan.y) / (view.zoom * frame.yDir)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen };
|
|
31
|
+
//# sourceMappingURL=chunk-2AYGEN57.js.map
|
|
32
|
+
//# sourceMappingURL=chunk-2AYGEN57.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/canvas/worldSpec.ts","../src/canvas/canvasCoords.ts"],"names":[],"mappings":";AA2BO,IAAM,aAAA,GAA4B,EAAE,QAAA,EAAU,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAE,EAAG,IAAA,EAAM,CAAA;AAEpE,SAAS,YAAA,CAAa,MAA6B,IAAA,EAAgC;AACxF,EAAA,IAAI,CAAC,MAAM,OAAO,aAAA;AAClB,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA,IAAU,EAAE,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC3C,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,EAAE,CAAA,EAAG,MAAA,CAAO,CAAA,GAAI,IAAA,CAAK,KAAA,EAAO,CAAA,EAAG,MAAA,CAAO,CAAA,GAAI,IAAA,CAAK,MAAA,EAAO;AAAA,IAChE,IAAA,EAAM,IAAA,CAAK,KAAA,KAAU,IAAA,GAAO,EAAA,GAAK;AAAA,GACnC;AACF;AAIO,SAAS,WAAA,CACd,GAAA,EACA,IAAA,EACA,KAAA,GAAoB,aAAA,EACd;AACN,EAAA,GAAA,CAAI,SAAA,CAAU,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAA,CAAM,QAAA,CAAS,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA;AAC1E,EAAA,GAAA,CAAI,MAAM,IAAA,CAAK,IAAA,EAAM,IAAA,CAAK,IAAA,GAAO,MAAM,IAAI,CAAA;AAC7C;;;ACvCO,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-2AYGEN57.js","sourcesContent":["import type { Point, ViewTransform } from '../instrument/types';\n\n/** How an instrument's world sits on the canvas, independent of the camera.\n * The defaults reproduce the convention labkit shipped before this existed:\n * world (0,0) at the element's top-left, y growing downward. */\nexport interface WorldSpec {\n /** Where world (0,0) sits at `pan` zero, as a fraction of the viewport.\n * `{x:0,y:0}` top-left (default); `{x:0.5,y:0.5}` centre. */\n origin?: Point;\n /** Which way the world y axis runs on screen. Default `'down'`. */\n yAxis?: 'down' | 'up';\n}\n\n/** A viewport's CSS-pixel size. */\nexport interface ViewportSize {\n width: number;\n height: number;\n}\n\n/** A `WorldSpec` resolved against a viewport: what the coordinate helpers,\n * the camera and the wheel all read. */\nexport interface WorldFrame {\n /** Screen position of world (0,0) at `pan` zero. */\n originPx: Point;\n yDir: 1 | -1;\n}\n\nexport const DEFAULT_FRAME: WorldFrame = { originPx: { x: 0, y: 0 }, yDir: 1 };\n\nexport function resolveFrame(spec: WorldSpec | undefined, size: ViewportSize): WorldFrame {\n if (!spec) return DEFAULT_FRAME;\n const origin = spec.origin ?? { x: 0, y: 0 };\n return {\n originPx: { x: origin.x * size.width, y: origin.y * size.height },\n yDir: spec.yAxis === 'up' ? -1 : 1,\n };\n}\n\n/** Put a 2D context into the instrument's world coordinates, so a layer's\n * `draw` works in them. Must stay the exact inverse of `screenToWorld`. */\nexport function applyCamera(\n ctx: CanvasRenderingContext2D,\n view: ViewTransform,\n frame: WorldFrame = DEFAULT_FRAME,\n): void {\n ctx.translate(frame.originPx.x + view.pan.x, frame.originPx.y + view.pan.y);\n ctx.scale(view.zoom, view.zoom * frame.yDir);\n}\n","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,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ae, oe } from './chunk-HEORBLVT.js';
|
|
2
2
|
import { useRef, useMemo, useState, useEffect } from 'react';
|
|
3
3
|
import { floatingStrategy, DEFAULT_INSET, DEFAULT_ANCHOR, FLOATING_DRAG_PREFIX } from 'windease';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
@@ -9,6 +9,7 @@ function borderBoxOf(entry) {
|
|
|
9
9
|
if (box) return { w: box.inlineSize, h: box.blockSize };
|
|
10
10
|
return { w: entry.contentRect.width, h: entry.contentRect.height };
|
|
11
11
|
}
|
|
12
|
+
var DRAG_THRESHOLD = 3;
|
|
12
13
|
function isInteractive(target) {
|
|
13
14
|
if (!(target instanceof Element)) return false;
|
|
14
15
|
return target.closest("input, button, a, select, textarea, [data-no-drag]") !== null;
|
|
@@ -77,15 +78,21 @@ function FloatingPanel({
|
|
|
77
78
|
options
|
|
78
79
|
}).placements.get(ITEM_ID);
|
|
79
80
|
const dragging = useRef(null);
|
|
81
|
+
const pending = useRef(null);
|
|
80
82
|
const [isDragging, setDragging] = useState(false);
|
|
81
83
|
const onPointerDown = (e) => {
|
|
82
84
|
if (isInteractive(e.target)) return;
|
|
83
85
|
e.stopPropagation();
|
|
84
|
-
|
|
85
|
-
setDragging(true);
|
|
86
|
-
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
86
|
+
pending.current = { x: e.clientX, y: e.clientY, pointerId: e.pointerId };
|
|
87
87
|
};
|
|
88
88
|
const onPointerMove = (e) => {
|
|
89
|
+
const armed = pending.current;
|
|
90
|
+
if (armed && armed.pointerId === e.pointerId && !dragging.current) {
|
|
91
|
+
if (Math.hypot(e.clientX - armed.x, e.clientY - armed.y) < DRAG_THRESHOLD) return;
|
|
92
|
+
dragging.current = { x: armed.x, y: armed.y };
|
|
93
|
+
setDragging(true);
|
|
94
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
95
|
+
}
|
|
89
96
|
const from = dragging.current;
|
|
90
97
|
if (!from) return;
|
|
91
98
|
const dx = e.clientX - from.x;
|
|
@@ -105,6 +112,7 @@ function FloatingPanel({
|
|
|
105
112
|
);
|
|
106
113
|
};
|
|
107
114
|
const endDrag = (e) => {
|
|
115
|
+
pending.current = null;
|
|
108
116
|
if (!dragging.current) return;
|
|
109
117
|
dragging.current = null;
|
|
110
118
|
setDragging(false);
|
|
@@ -160,12 +168,12 @@ function JobProgress({ job, className }) {
|
|
|
160
168
|
determinate ? ` / ${total}` : ""
|
|
161
169
|
] }),
|
|
162
170
|
failures.length > 0 && /* @__PURE__ */ jsxs("span", { className: "lk-job__failures", title: failures.map((f) => f.error).join("\n"), children: [
|
|
163
|
-
/* @__PURE__ */ jsx(
|
|
171
|
+
/* @__PURE__ */ jsx(ae, { size: 14 }),
|
|
164
172
|
failures.length,
|
|
165
173
|
" failed"
|
|
166
174
|
] }),
|
|
167
175
|
error && /* @__PURE__ */ jsxs("span", { className: "lk-job__error", title: error, children: [
|
|
168
|
-
/* @__PURE__ */ jsx(
|
|
176
|
+
/* @__PURE__ */ jsx(oe, { size: 14 }),
|
|
169
177
|
error
|
|
170
178
|
] }),
|
|
171
179
|
status === "running" && /* @__PURE__ */ jsx("button", { type: "button", className: "lk-job__cancel", onClick: job.cancel, children: "Cancel" })
|
|
@@ -208,5 +216,5 @@ function Sidebar({ children, title, collapsed = false, onToggle }) {
|
|
|
208
216
|
}
|
|
209
217
|
|
|
210
218
|
export { FloatingPanel, JobProgress, Legend, Sidebar };
|
|
211
|
-
//# sourceMappingURL=chunk-
|
|
212
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-3P5TTTA7.js.map
|
|
220
|
+
//# sourceMappingURL=chunk-3P5TTTA7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/primitives/FloatingPanel.tsx","../src/primitives/JobProgress.tsx","../src/primitives/Legend.tsx","../src/primitives/Sidebar.tsx"],"names":["jsx","jsxs"],"mappings":"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","file":"chunk-3P5TTTA7.js","sourcesContent":["import type React from 'react';\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n type Corner,\n DEFAULT_ANCHOR,\n DEFAULT_INSET,\n FLOATING_DRAG_PREFIX,\n type FloatingPlacement,\n floatingStrategy,\n} from 'windease';\n\n/** The strategy holds a map keyed by item id; a panel is always a lone item. */\nconst ITEM_ID = 'panel';\n\n/** Props for `<FloatingPanel>`. */\nexport interface FloatingPanelProps {\n children: ReactNode;\n /** Corner it rests in before it has ever been dragged. Default `'bottom-left'`. */\n anchor?: Corner;\n /** Corners that may capture it. Default: all four. */\n snapCorners?: readonly Corner[];\n /** Pixels in from a corner when snapped. Default 12. */\n inset?: number;\n /** localStorage key to remember its position under. Omit to forget on reload. */\n storageKey?: string;\n className?: string;\n}\n\n/**\n * The panel's footprint is its border box — `contentRect` excludes padding and\n * border, which would place a panel that then overflows its corner by exactly\n * that much.\n */\nfunction borderBoxOf(entry: ResizeObserverEntry): { w: number; h: number } {\n const box = entry.borderBoxSize?.[0];\n if (box) return { w: box.inlineSize, h: box.blockSize };\n return { w: entry.contentRect.width, h: entry.contentRect.height };\n}\n\n/** How far the pointer must travel before a press becomes a drag. */\nconst DRAG_THRESHOLD = 3;\n\n/** A pointerdown on one of these is the child's, not a drag. */\nfunction isInteractive(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false;\n return target.closest('input, button, a, select, textarea, [data-no-drag]') !== null;\n}\n\nfunction readStored(key: string | undefined): FloatingPlacement | null {\n if (!key) return null;\n try {\n const raw = localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as FloatingPlacement) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * A draggable box that floats over its offset parent and snaps to its corners.\n *\n * Drives windease's `floatingStrategy` as a pure function rather than mounting a\n * windease container: a lab overlay has one item and no zone tree, so the node\n * model would be all cost. Pointer handling is therefore this component's, and\n * windease's own affordance rendering never participates.\n */\nexport function FloatingPanel({\n children,\n anchor = DEFAULT_ANCHOR,\n snapCorners,\n inset = DEFAULT_INSET,\n storageKey,\n className,\n}: FloatingPanelProps) {\n const ref = useRef<HTMLDivElement>(null);\n const strategy = useMemo(() => floatingStrategy(), []);\n const options = useMemo(() => ({ defaultAnchor: anchor, inset }), [anchor, inset]);\n\n const [container, setContainer] = useState({ w: 0, h: 0 });\n const [size, setSize] = useState({ w: 0, h: 0 });\n const [place, setPlace] = useState<FloatingPlacement>(\n () => readStored(storageKey) ?? { x: 0, y: 0, anchor },\n );\n\n useEffect(() => {\n if (!storageKey) return;\n try {\n localStorage.setItem(storageKey, JSON.stringify(place));\n } catch {\n // A full or disabled store is not worth failing a lab over.\n }\n }, [place, storageKey]);\n\n const item = useMemo(\n () => ({\n id: ITEM_ID,\n meta: { floating: true, ...(snapCorners ? { snapCorners: [...snapCorners] } : {}) },\n natural: size,\n }),\n [size, snapCorners],\n );\n\n useEffect(() => {\n const el = ref.current;\n const parent = el?.offsetParent ?? el?.parentElement;\n if (!el || !parent) return;\n // Sizes come off the entry, not the DOM: jsdom reports 0 for every\n // clientWidth/offsetWidth, and an unmeasured item is withheld from layout.\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === parent) {\n setContainer({ w: entry.contentRect.width, h: entry.contentRect.height });\n } else {\n setSize(borderBoxOf(entry));\n }\n }\n });\n observer.observe(parent);\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const rect = strategy\n .layout({\n items: [item],\n container,\n state: { at: { [ITEM_ID]: place }, inner: undefined },\n options,\n })\n .placements.get(ITEM_ID);\n\n const dragging = useRef<{ x: number; y: number } | null>(null);\n /** Pressed but not yet moved far enough to be a drag. */\n const pending = useRef<{ x: number; y: number; pointerId: number } | null>(null);\n const [isDragging, setDragging] = useState(false);\n\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (isInteractive(e.target)) return;\n // The canvas stack underneath owns pan/zoom on the same pointer events.\n e.stopPropagation();\n // Armed, not capturing. Capture retargets mouseup to this element, and the\n // browser then synthesizes no `click` on the child under the cursor — so\n // capturing on press makes every non-native control in the panel dead to a\n // real mouse, silently. `isInteractive` only exempts the names it lists; a\n // `role=\"button\"` span, a react-aria control or a canvas is not among them.\n pending.current = { x: e.clientX, y: e.clientY, pointerId: e.pointerId };\n };\n\n const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n const armed = pending.current;\n if (armed && armed.pointerId === e.pointerId && !dragging.current) {\n if (Math.hypot(e.clientX - armed.x, e.clientY - armed.y) < DRAG_THRESHOLD) return;\n dragging.current = { x: armed.x, y: armed.y };\n setDragging(true);\n e.currentTarget.setPointerCapture?.(e.pointerId);\n }\n const from = dragging.current;\n if (!from) return;\n const dx = e.clientX - from.x;\n const dy = e.clientY - from.y;\n if (dx === 0 && dy === 0) return;\n dragging.current = { x: e.clientX, y: e.clientY };\n setPlace(\n (prev) =>\n strategy.reduce?.(\n { at: { [ITEM_ID]: prev }, inner: undefined },\n {\n affordanceId: `${FLOATING_DRAG_PREFIX}${ITEM_ID}`,\n kind: 'drag',\n payload: { dx, dy },\n },\n { container, options, items: [item] },\n ).at[ITEM_ID] ?? prev,\n );\n };\n\n const endDrag = (e: React.PointerEvent<HTMLDivElement>) => {\n pending.current = null;\n if (!dragging.current) return;\n dragging.current = null;\n setDragging(false);\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n };\n\n return (\n <div\n className={className ? `lk-floating-panel ${className}` : 'lk-floating-panel'}\n data-dragging={isDragging ? 'true' : undefined}\n data-placed={rect ? 'true' : undefined}\n onPointerCancel={endDrag}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n ref={ref}\n style={\n {\n position: 'absolute',\n left: `${rect?.x ?? 0}px`,\n top: `${rect?.y ?? 0}px`,\n } as CSSProperties\n }\n >\n {children}\n </div>\n );\n}\n","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 type { ReactNode } from 'react';\n\n/** Props for `<Sidebar>`. */\nexport interface SidebarProps {\n children: ReactNode;\n title?: string;\n collapsed?: boolean;\n onToggle?: () => void;\n}\n\n/** A collapsible side panel with an optional title. Collapse state is the\n * caller's to hold. */\nexport function Sidebar({ children, title, collapsed = false, onToggle }: SidebarProps) {\n const className = `lk-sidebar${collapsed ? ' lk-sidebar--collapsed' : ''}`;\n return (\n <aside className={className}>\n {(title || onToggle) && (\n <div className=\"lk-sidebar-header\">\n {title && <span className=\"lk-sidebar-title\">{title}</span>}\n {onToggle && (\n <button\n type=\"button\"\n className=\"lk-sidebar-toggle\"\n onClick={onToggle}\n aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\n >\n {collapsed ? '›' : '‹'}\n </button>\n )}\n </div>\n )}\n <div className=\"lk-sidebar-body\">{children}</div>\n </aside>\n );\n}\n"]}
|
|
@@ -1,24 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { zoomAt } from './chunk-CTRKTLYZ.js';
|
|
2
|
+
import { resolveFrame, screenToWorld, DEFAULT_FRAME } from './chunk-2AYGEN57.js';
|
|
3
|
+
import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
|
|
4
|
+
import { useVisibleRaf } from './chunk-ROQDRXKW.js';
|
|
3
5
|
import { useRef, useState, useEffect, useMemo, useCallback } from 'react';
|
|
4
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
7
|
|
|
6
|
-
// src/canvas/canvasCoords.ts
|
|
7
|
-
function worldToScreen(world, view) {
|
|
8
|
-
return {
|
|
9
|
-
x: world.x * view.zoom + view.pan.x,
|
|
10
|
-
y: world.y * view.zoom + view.pan.y
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
function screenToWorld(screen, view) {
|
|
14
|
-
return {
|
|
15
|
-
x: (screen.x - view.pan.x) / view.zoom,
|
|
16
|
-
y: (screen.y - view.pan.y) / view.zoom
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
8
|
function useLayerScheduler({
|
|
20
9
|
layers,
|
|
21
10
|
view,
|
|
11
|
+
frame = DEFAULT_FRAME,
|
|
22
12
|
canvasRefs,
|
|
23
13
|
size,
|
|
24
14
|
host
|
|
@@ -37,7 +27,7 @@ function useLayerScheduler({
|
|
|
37
27
|
}, [layers]);
|
|
38
28
|
useEffect(() => {
|
|
39
29
|
for (const layer of layers) dirty.current.add(layer.id);
|
|
40
|
-
}, [view, size, layers]);
|
|
30
|
+
}, [view, frame, size, layers]);
|
|
41
31
|
const frameLoop = useVisibleRaf(
|
|
42
32
|
() => {
|
|
43
33
|
if (dirty.current.size === 0) return;
|
|
@@ -56,7 +46,7 @@ function useLayerScheduler({
|
|
|
56
46
|
ctx.save();
|
|
57
47
|
ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);
|
|
58
48
|
ctx.clearRect(0, 0, size.width, size.height);
|
|
59
|
-
layer.render(ctx, view);
|
|
49
|
+
layer.render(ctx, view, frame);
|
|
60
50
|
ctx.restore();
|
|
61
51
|
}
|
|
62
52
|
dirty.current.clear();
|
|
@@ -75,7 +65,8 @@ function usePanZoom({
|
|
|
75
65
|
view,
|
|
76
66
|
onViewChange,
|
|
77
67
|
minZoom = 0.1,
|
|
78
|
-
maxZoom = 32
|
|
68
|
+
maxZoom = 32,
|
|
69
|
+
frame = DEFAULT_FRAME
|
|
79
70
|
}) {
|
|
80
71
|
const dragRef = useRef(null);
|
|
81
72
|
const viewRef = useRef(view);
|
|
@@ -85,23 +76,21 @@ function usePanZoom({
|
|
|
85
76
|
(e) => {
|
|
86
77
|
e.preventDefault();
|
|
87
78
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
88
|
-
const cursorX = e.clientX - rect.left;
|
|
89
|
-
const cursorY = e.clientY - rect.top;
|
|
90
|
-
const v = viewRef.current;
|
|
91
79
|
const initialZoom = initialZoomRef.current;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
80
|
+
onViewChange(
|
|
81
|
+
zoomAt(
|
|
82
|
+
viewRef.current,
|
|
83
|
+
Math.exp(-e.deltaY * 1e-3),
|
|
84
|
+
{ x: e.clientX - rect.left, y: e.clientY - rect.top },
|
|
85
|
+
{
|
|
86
|
+
frame,
|
|
87
|
+
min: initialZoom == null ? minZoom : Math.min(minZoom, initialZoom),
|
|
88
|
+
max: initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom)
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
);
|
|
103
92
|
},
|
|
104
|
-
[onViewChange, minZoom, maxZoom]
|
|
93
|
+
[onViewChange, minZoom, maxZoom, frame]
|
|
105
94
|
);
|
|
106
95
|
const onPointerDown = useCallback((e) => {
|
|
107
96
|
if (e.button !== 0) return;
|
|
@@ -144,11 +133,13 @@ function CanvasStack({
|
|
|
144
133
|
layers,
|
|
145
134
|
view,
|
|
146
135
|
onViewChange,
|
|
136
|
+
worldSpec,
|
|
147
137
|
minZoom,
|
|
148
138
|
maxZoom,
|
|
149
139
|
width = "100%",
|
|
150
140
|
height = "100%",
|
|
151
141
|
className,
|
|
142
|
+
onResize,
|
|
152
143
|
onHitTest,
|
|
153
144
|
children
|
|
154
145
|
}) {
|
|
@@ -178,9 +169,23 @@ function CanvasStack({
|
|
|
178
169
|
ro.observe(el);
|
|
179
170
|
return () => ro.disconnect();
|
|
180
171
|
}, []);
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
const onResizeRef = useRef(onResize);
|
|
173
|
+
onResizeRef.current = onResize;
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (size.width === 0 && size.height === 0) return;
|
|
176
|
+
onResizeRef.current?.({ width: size.width, height: size.height });
|
|
177
|
+
}, [size.width, size.height]);
|
|
178
|
+
const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);
|
|
179
|
+
const handlers = usePanZoom({ view, onViewChange, minZoom, maxZoom, frame });
|
|
180
|
+
useLayerScheduler({ layers, view, frame, canvasRefs: canvasMap, size, host: containerRef });
|
|
181
|
+
const ctxValue = useMemo(
|
|
182
|
+
() => ({
|
|
183
|
+
view,
|
|
184
|
+
frame,
|
|
185
|
+
surface: { element: containerRef, size, canvases: canvasMap, layers }
|
|
186
|
+
}),
|
|
187
|
+
[view, frame, size, layers]
|
|
188
|
+
);
|
|
184
189
|
const containerStyle = { width, height };
|
|
185
190
|
const canvasPx = {
|
|
186
191
|
width: Math.max(0, Math.round(size.width * size.dpr)),
|
|
@@ -196,7 +201,7 @@ function CanvasStack({
|
|
|
196
201
|
if (!wasDragging && onHitTest && containerRef.current) {
|
|
197
202
|
const rect = containerRef.current.getBoundingClientRect();
|
|
198
203
|
const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
199
|
-
onHitTest(screenToWorld(screen, view));
|
|
204
|
+
onHitTest(screenToWorld(screen, view, frame));
|
|
200
205
|
}
|
|
201
206
|
};
|
|
202
207
|
return /* @__PURE__ */ jsx(CanvasStackContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxs(
|
|
@@ -227,6 +232,6 @@ function CanvasStack({
|
|
|
227
232
|
) });
|
|
228
233
|
}
|
|
229
234
|
|
|
230
|
-
export { CanvasStack
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
232
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
export { CanvasStack };
|
|
236
|
+
//# sourceMappingURL=chunk-3ZELRRBV.js.map
|
|
237
|
+
//# sourceMappingURL=chunk-3ZELRRBV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/canvas/useLayerScheduler.ts","../src/canvas/usePanZoom.ts","../src/canvas/CanvasStack.tsx"],"names":["useRef","useEffect"],"mappings":"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","file":"chunk-3ZELRRBV.js","sourcesContent":["import { useVisibleRaf } from '@weasel-js/core';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** One layer of a canvas stack: its id, whether it is currently shown, and how\n * it paints itself. */\nexport interface CanvasLayerDescriptor {\n id: string;\n visible: boolean;\n render: (ctx: CanvasRenderingContext2D, view: ViewTransform, frame: WorldFrame) => void;\n}\n\ninterface SchedulerOptions {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against `size`. */\n frame?: WorldFrame;\n canvasRefs: RefObject<Map<string, HTMLCanvasElement>>;\n size: { width: number; height: number; dpr: number };\n /** The element the stack occupies. Given one, the scheduler also stops while\n * the stack sits outside the viewport. */\n host?: RefObject<Element | null>;\n}\n\nexport function useLayerScheduler({\n layers,\n view,\n frame = DEFAULT_FRAME,\n canvasRefs,\n size,\n host,\n}: SchedulerOptions): void {\n const dirty = useRef<Set<string>>(new Set());\n const lastRenderRef = useRef<Map<string, CanvasLayerDescriptor['render']>>(new Map());\n\n useEffect(() => {\n for (const layer of layers) {\n const prev = lastRenderRef.current.get(layer.id);\n if (prev !== layer.render) dirty.current.add(layer.id);\n lastRenderRef.current.set(layer.id, layer.render);\n }\n for (const id of [...lastRenderRef.current.keys()]) {\n if (!layers.find((l) => l.id === id)) lastRenderRef.current.delete(id);\n }\n }, [layers]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-mark dirty when view or size changes\n useEffect(() => {\n for (const layer of layers) dirty.current.add(layer.id);\n }, [view, frame, size, layers]);\n\n // Painting only what is dirty is not the same as doing nothing: a hidden tab\n // still commits React updates, and the effect above marks every layer dirty\n // on any view or size change. The gate is what actually stops the work.\n const frameLoop = useVisibleRaf(\n () => {\n if (dirty.current.size === 0) return;\n const map = canvasRefs.current;\n if (!map) {\n dirty.current.clear();\n return;\n }\n for (const layer of layers) {\n if (!dirty.current.has(layer.id)) continue;\n if (!layer.visible) continue;\n const canvas = map.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n ctx.save();\n ctx.setTransform(size.dpr, 0, 0, size.dpr, 0, 0);\n ctx.clearRect(0, 0, size.width, size.height);\n layer.render(ctx, view, frame);\n ctx.restore();\n }\n dirty.current.clear();\n },\n { target: host },\n );\n\n useEffect(() => {\n if (dirty.current.size > 0) frameLoop.request();\n });\n}\n","import { type PointerEvent, useCallback, useRef, type WheelEvent } from 'react';\nimport type { ViewTransform } from '../instrument/types';\nimport { zoomAt } from './camera';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\nexport interface UsePanZoomOptions {\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The opening `view.zoom` always stays reachable, widening these past\n * whatever is passed here if it would otherwise exclude it. */\n minZoom?: number;\n maxZoom?: number;\n /** The instrument's coordinate system, resolved against the viewport. The\n * wheel anchors in this frame; omitting it anchors at the element's\n * top-left, which is what labkit did before a frame could be declared. */\n frame?: WorldFrame;\n}\n\nexport interface PanZoomHandlers {\n onWheel: (e: WheelEvent<HTMLElement>) => void;\n onPointerDown: (e: PointerEvent<HTMLElement>) => void;\n onPointerMove: (e: PointerEvent<HTMLElement>) => void;\n onPointerUp: (e: PointerEvent<HTMLElement>) => void;\n isDragging: () => boolean;\n}\n\ninterface DragState {\n pointerId: number;\n startScreenX: number;\n startScreenY: number;\n startPan: { x: number; y: number };\n moved: boolean;\n}\n\nconst DRAG_THRESHOLD = 3;\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n\nexport function usePanZoom({\n view,\n onViewChange,\n minZoom = 0.1,\n maxZoom = 32,\n frame = DEFAULT_FRAME,\n}: UsePanZoomOptions): PanZoomHandlers {\n const dragRef = useRef<DragState | null>(null);\n const viewRef = useRef(view);\n viewRef.current = view;\n // Captured once, from the view the canvas opened at — not the current view,\n // which would let a prior zoom-out shrink the range and trap the opening\n // view unreachable behind it.\n const initialZoomRef = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);\n\n const onWheel = useCallback(\n (e: WheelEvent<HTMLElement>) => {\n e.preventDefault();\n const rect = e.currentTarget.getBoundingClientRect();\n const initialZoom = initialZoomRef.current;\n onViewChange(\n zoomAt(\n viewRef.current,\n Math.exp(-e.deltaY * 0.001),\n { x: e.clientX - rect.left, y: e.clientY - rect.top },\n {\n frame,\n min: initialZoom == null ? minZoom : Math.min(minZoom, initialZoom),\n max: initialZoom == null ? maxZoom : Math.max(maxZoom, initialZoom),\n },\n ),\n );\n },\n [onViewChange, minZoom, maxZoom, frame],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLElement>) => {\n if (e.button !== 0) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragRef.current = {\n pointerId: e.pointerId,\n startScreenX: e.clientX,\n startScreenY: e.clientY,\n startPan: { ...viewRef.current.pan },\n moved: false,\n };\n }, []);\n\n const onPointerMove = useCallback(\n (e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n const dx = e.clientX - drag.startScreenX;\n const dy = e.clientY - drag.startScreenY;\n if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n drag.moved = true;\n onViewChange({\n zoom: viewRef.current.zoom,\n pan: { x: drag.startPan.x + dx, y: drag.startPan.y + dy },\n });\n },\n [onViewChange],\n );\n\n const onPointerUp = useCallback((e: PointerEvent<HTMLElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== e.pointerId) return;\n if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n e.currentTarget.releasePointerCapture(e.pointerId);\n }\n dragRef.current = null;\n }, []);\n\n const isDragging = useCallback(() => dragRef.current?.moved === true, []);\n\n return { onWheel, onPointerDown, onPointerMove, onPointerUp, isDragging };\n}\n","import { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { CanvasStackContext } from './CanvasStackContext';\nimport { screenToWorld } from './canvasCoords';\nimport { type CanvasLayerDescriptor, useLayerScheduler } from './useLayerScheduler';\nimport { usePanZoom } from './usePanZoom';\nimport { resolveFrame, type ViewportSize, type WorldSpec } from './worldSpec';\n\n/** Props for `<CanvasStack>`. */\nexport interface CanvasStackProps {\n layers: CanvasLayerDescriptor[];\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n /** The instrument's coordinate system. Omitted, world (0,0) sits at the\n * element's top-left with y running down. */\n worldSpec?: WorldSpec;\n minZoom?: number;\n maxZoom?: number;\n width?: number | string;\n height?: number | string;\n className?: string;\n /** Fired whenever the stack is measured, so a consumer can place a view that\n * only makes sense in terms of the viewport. */\n onResize?: (size: ViewportSize) => void;\n onHitTest?: (worldPos: Point) => void;\n children?: ReactNode;\n}\n\n/** Stacks one `<canvas>` per layer and drives them from a shared view, so a\n * layer that changes rarely is not redrawn with one that changes every frame.\n * Handles sizing, device pixel ratio, and pan/zoom. */\nexport function CanvasStack({\n layers,\n view,\n onViewChange,\n worldSpec,\n minZoom,\n maxZoom,\n width = '100%',\n height = '100%',\n className,\n onResize,\n onHitTest,\n children,\n}: CanvasStackProps) {\n const containerRef = useRef<HTMLDivElement | null>(null);\n const canvasMap = useRef<Map<string, HTMLCanvasElement>>(new Map());\n const [size, setSize] = useState({ width: 0, height: 0, dpr: 1 });\n\n const setCanvasRef = (id: string, el: HTMLCanvasElement | null): void => {\n if (el) canvasMap.current.set(id, el);\n else canvasMap.current.delete(id);\n };\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n const update = () => {\n const rect = el.getBoundingClientRect();\n const dpr = window.devicePixelRatio ?? 1;\n setSize((prev) => {\n if (prev.width === rect.width && prev.height === rect.height && prev.dpr === dpr) {\n return prev;\n }\n return { width: rect.width, height: rect.height, dpr };\n });\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const onResizeRef = useRef(onResize);\n onResizeRef.current = onResize;\n useEffect(() => {\n if (size.width === 0 && size.height === 0) return;\n onResizeRef.current?.({ width: size.width, height: size.height });\n }, [size.width, size.height]);\n\n const frame = useMemo(() => resolveFrame(worldSpec, size), [worldSpec, size]);\n\n const handlers = usePanZoom({ view, onViewChange, minZoom, maxZoom, frame });\n useLayerScheduler({ layers, view, frame, canvasRefs: canvasMap, size, host: containerRef });\n\n const ctxValue = useMemo(\n () => ({\n view,\n frame,\n surface: { element: containerRef, size, canvases: canvasMap, layers },\n }),\n [view, frame, size, layers],\n );\n\n const containerStyle: CSSProperties = { width, height };\n const canvasPx = {\n width: Math.max(0, Math.round(size.width * size.dpr)),\n height: Math.max(0, Math.round(size.height * size.dpr)),\n };\n const canvasCss: CSSProperties = {\n width: size.width,\n height: size.height,\n };\n\n const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n const wasDragging = handlers.isDragging();\n handlers.onPointerUp(e);\n if (!wasDragging && onHitTest && containerRef.current) {\n const rect = containerRef.current.getBoundingClientRect();\n const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n onHitTest(screenToWorld(screen, view, frame));\n }\n };\n\n return (\n <CanvasStackContext.Provider value={ctxValue}>\n <div\n ref={containerRef}\n className={className ? `lk-canvas-stack ${className}` : 'lk-canvas-stack'}\n style={containerStyle}\n onWheel={handlers.onWheel}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlePointerUp}\n >\n {layers.map((layer) => (\n <canvas\n key={layer.id}\n ref={(el) => setCanvasRef(layer.id, el)}\n className=\"lk-canvas-stack__canvas\"\n width={canvasPx.width}\n height={canvasPx.height}\n style={{ ...canvasCss, display: layer.visible ? 'block' : 'none' }}\n />\n ))}\n <div className=\"lk-canvas-stack__overlay\">{children}</div>\n </div>\n </CanvasStackContext.Provider>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useVisibleRaf } from './chunk-
|
|
1
|
+
import { useVisibleRaf } from './chunk-ROQDRXKW.js';
|
|
2
2
|
import { createContext, useContext, useCallback, useRef, useEffect } from 'react';
|
|
3
3
|
|
|
4
4
|
// src/surface/composeRects.ts
|
|
@@ -31,6 +31,10 @@ function toDeviceRect(rect, surfaceHeight, dpr) {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
var SurfaceContext = createContext(null);
|
|
34
|
+
var SurfaceCanvasContext = createContext(null);
|
|
35
|
+
function useSurfaceCanvas() {
|
|
36
|
+
return useContext(SurfaceCanvasContext);
|
|
37
|
+
}
|
|
34
38
|
function useSurfaceOptional() {
|
|
35
39
|
return useContext(SurfaceContext);
|
|
36
40
|
}
|
|
@@ -53,6 +57,7 @@ function useTiledSurface({ onFrame }) {
|
|
|
53
57
|
const tiles = useRef(/* @__PURE__ */ new Map());
|
|
54
58
|
const rects = useRef(/* @__PURE__ */ new Map());
|
|
55
59
|
const dirty = useRef(/* @__PURE__ */ new Set());
|
|
60
|
+
const painters = useRef(/* @__PURE__ */ new Map());
|
|
56
61
|
const needsMeasure = useRef(true);
|
|
57
62
|
const observer = useRef(null);
|
|
58
63
|
const lastDpr = useRef(0);
|
|
@@ -89,12 +94,17 @@ function useTiledSurface({ onFrame }) {
|
|
|
89
94
|
}
|
|
90
95
|
if (dirty.current.size === 0) return;
|
|
91
96
|
const box = el.getBoundingClientRect();
|
|
92
|
-
|
|
97
|
+
const frame = {
|
|
93
98
|
dirty: new Set(dirty.current),
|
|
94
99
|
rects: new Map(rects.current),
|
|
95
100
|
dpr,
|
|
96
101
|
size: { width: box.width, height: box.height }
|
|
97
|
-
}
|
|
102
|
+
};
|
|
103
|
+
onFrameRef.current(frame);
|
|
104
|
+
for (const id of frame.dirty) {
|
|
105
|
+
const rect = frame.rects.get(id);
|
|
106
|
+
if (rect) painters.current.get(id)?.(rect, frame);
|
|
107
|
+
}
|
|
98
108
|
dirty.current.clear();
|
|
99
109
|
},
|
|
100
110
|
// The host attaches its container through `containerRef`, which may land
|
|
@@ -137,6 +147,13 @@ function useTiledSurface({ onFrame }) {
|
|
|
137
147
|
},
|
|
138
148
|
[schedule]
|
|
139
149
|
);
|
|
150
|
+
const registerPainter = useCallback((id, paint) => {
|
|
151
|
+
painters.current.set(id, paint);
|
|
152
|
+
return () => {
|
|
153
|
+
if (painters.current.get(id) === paint) painters.current.delete(id);
|
|
154
|
+
};
|
|
155
|
+
}, []);
|
|
156
|
+
const getContainer = useCallback(() => container.current, []);
|
|
140
157
|
const containerRef = useCallback(
|
|
141
158
|
(el) => {
|
|
142
159
|
if (container.current === el) return;
|
|
@@ -162,9 +179,17 @@ function useTiledSurface({ onFrame }) {
|
|
|
162
179
|
frameLoop.cancel();
|
|
163
180
|
};
|
|
164
181
|
}, [schedule, frameLoop]);
|
|
165
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
invalidate,
|
|
184
|
+
invalidateAll,
|
|
185
|
+
invalidateRects,
|
|
186
|
+
registerTile,
|
|
187
|
+
registerPainter,
|
|
188
|
+
containerRef,
|
|
189
|
+
getContainer
|
|
190
|
+
};
|
|
166
191
|
}
|
|
167
192
|
|
|
168
|
-
export { SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface };
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
170
|
-
//# sourceMappingURL=chunk-
|
|
193
|
+
export { SurfaceCanvasContext, SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTiledSurface };
|
|
194
|
+
//# sourceMappingURL=chunk-4EY67BKJ.js.map
|
|
195
|
+
//# sourceMappingURL=chunk-4EY67BKJ.js.map
|