@weasel-js/labkit 1.7.3 → 1.8.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 +24 -0
- package/dist/_dts/{CanvasStackContext-Cjy6I-Iv.d.ts → CanvasStackContext-B05ZM04l.d.ts} +3 -1
- package/dist/_dts/{Stage-D6t7o0pF.d.ts → Stage-CIJlbjrE.d.ts} +5 -3
- package/dist/_dts/{index-DCMA4Fy1.d.ts → index-8geQNQet.d.ts} +84 -12
- package/dist/_dts/{index-BTmaRy6a.d.ts → index-DRi3V5sN.d.ts} +6 -4
- package/dist/_dts/{types-BUBSIZuV.d.ts → types-DUfQ0isU.d.ts} +5 -1
- package/dist/_dts/{useTrialState-Bh8bzFgE.d.ts → useTrialState-Ar0AFpCe.d.ts} +94 -87
- package/dist/canvas/index.d.ts +5 -5
- package/dist/canvas/index.js +2 -2
- package/dist/chrome/index.d.ts +3 -3
- package/dist/chrome/index.js +7 -7
- package/dist/{chunk-HBGH344L.js → chunk-4RCVWX4M.js} +55 -18
- package/dist/chunk-4RCVWX4M.js.map +1 -0
- package/dist/{chunk-WIG6XHJ7.js → chunk-6IIKLXBZ.js} +13 -4
- package/dist/chunk-6IIKLXBZ.js.map +1 -0
- package/dist/{chunk-F4ACIK7Z.js → chunk-6Q6ACJ3H.js} +3 -3
- package/dist/{chunk-F4ACIK7Z.js.map → chunk-6Q6ACJ3H.js.map} +1 -1
- package/dist/{chunk-PMLZP7RT.js → chunk-7ALJOVGP.js} +5 -9
- package/dist/chunk-7ALJOVGP.js.map +1 -0
- package/dist/{chunk-XE5HJOPL.js → chunk-7FMZT2WL.js} +3 -3
- package/dist/{chunk-XE5HJOPL.js.map → chunk-7FMZT2WL.js.map} +1 -1
- package/dist/{chunk-XVUKDSYV.js → chunk-AVOILDN2.js} +2 -2
- package/dist/{chunk-XVUKDSYV.js.map → chunk-AVOILDN2.js.map} +1 -1
- package/dist/{chunk-2N7UBSS2.js → chunk-J5MDJEOZ.js} +3 -3
- package/dist/{chunk-2N7UBSS2.js.map → chunk-J5MDJEOZ.js.map} +1 -1
- package/dist/{chunk-LPGBC63T.js → chunk-KHB3KRRQ.js} +7 -7
- package/dist/chunk-KHB3KRRQ.js.map +1 -0
- package/dist/{chunk-IBVRMHW5.js → chunk-NHIO2O3O.js} +31 -30
- package/dist/chunk-NHIO2O3O.js.map +1 -0
- package/dist/{chunk-EESJUSYR.js → chunk-QMAY74TP.js} +56 -5
- package/dist/chunk-QMAY74TP.js.map +1 -0
- package/dist/{chunk-4X44DMRS.js → chunk-RN7T7OBO.js} +46 -24
- package/dist/chunk-RN7T7OBO.js.map +1 -0
- package/dist/{chunk-4TJ34FXA.js → chunk-RXO5UEGT.js} +5 -12
- package/dist/chunk-RXO5UEGT.js.map +1 -0
- package/dist/{chunk-E6NARGU7.js → chunk-SQX35X5V.js} +3 -3
- package/dist/{chunk-E6NARGU7.js.map → chunk-SQX35X5V.js.map} +1 -1
- package/dist/{chunk-YCFKW5RX.js → chunk-T5OEUNCB.js} +16 -2
- package/dist/chunk-T5OEUNCB.js.map +1 -0
- package/dist/{chunk-RL2LOLNI.js → chunk-UX66USTN.js} +2 -2
- package/dist/chunk-UX66USTN.js.map +1 -0
- package/dist/{chunk-IRMPZIYU.js → chunk-V4SMGEYY.js} +6732 -6507
- package/dist/chunk-V4SMGEYY.js.map +1 -0
- package/dist/{chunk-E23Q6A3Y.js → chunk-VCK5T6EP.js} +3 -3
- package/dist/{chunk-E23Q6A3Y.js.map → chunk-VCK5T6EP.js.map} +1 -1
- package/dist/{chunk-T6DLGEJB.js → chunk-XWR2P6MR.js} +23 -6
- package/dist/chunk-XWR2P6MR.js.map +1 -0
- package/dist/{chunk-XSJJTXNA.js → chunk-YZA73U4A.js} +19 -19
- package/dist/chunk-YZA73U4A.js.map +1 -0
- package/dist/config/index.d.ts +12 -5
- package/dist/config/index.js +2 -2
- package/dist/controls/index.d.ts +2 -2
- package/dist/controls/index.js +5 -5
- package/dist/dragdrop/index.d.ts +2 -2
- package/dist/dragdrop/index.js +2 -2
- package/dist/index.d.ts +158 -16
- package/dist/index.js +1036 -415
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +2 -2
- package/dist/layers/index.js +3 -3
- package/dist/loupe/index.d.ts +176 -28
- package/dist/loupe/index.js +547 -141
- package/dist/loupe/index.js.map +1 -1
- package/dist/overview/index.d.ts +1 -1
- package/dist/overview/index.js +5 -5
- package/dist/passthrough/weasel-ui.js +3 -3
- package/dist/primitives/index.d.ts +4 -19
- package/dist/primitives/index.js +7 -7
- package/dist/state/index.d.ts +6 -8
- package/dist/state/index.js +5 -5
- package/dist/styles.css +181 -44
- package/dist/surface/index.d.ts +20 -1
- package/dist/surface/index.js +2 -2
- package/dist/undo/index.d.ts +19 -8
- package/dist/undo/index.js +1 -1
- package/package.json +11 -11
- package/src/annotations/AnnotationOverlay.abandon.test.tsx +4 -0
- package/src/annotations/AnnotationOverlay.tsx +10 -1
- package/src/annotations/Annotations.less +2 -0
- package/src/annotations/Annotations.overlay.test.tsx +29 -0
- package/src/canvas/CanvasStack.test.tsx +35 -0
- package/src/canvas/CanvasStack.tsx +12 -1
- package/src/canvas/useLayerScheduler.ts +14 -0
- package/src/chrome/builtins.test.ts +14 -0
- package/src/chrome/builtins.tsx +17 -2
- package/src/chrome/regions/StatusRegion.tsx +20 -14
- package/src/chrome/regions/regions.test.tsx +28 -0
- package/src/chrome/types.ts +8 -0
- package/src/clock/clock.browser.test.less +5 -0
- package/src/clock/clock.browser.test.tsx +77 -0
- package/src/clock/clock.integration.test.tsx +95 -0
- package/src/clock/clockRegistry.test.ts +33 -0
- package/src/clock/clockRegistry.ts +46 -0
- package/src/clock/hooks.ts +44 -0
- package/src/clock/index.ts +2 -0
- package/src/clock/trialClock.test.ts +265 -0
- package/src/clock/trialClock.ts +245 -0
- package/src/clock/useClockLoop.ts +45 -0
- package/src/config/builder.ts +11 -1
- package/src/config/resolve.test.ts +12 -0
- package/src/config/resolve.ts +5 -0
- package/src/config/types.ts +5 -1
- package/src/controls/ControlMatrix.test.tsx +10 -0
- package/src/controls/ControlMatrix.tsx +110 -58
- package/src/controls/ControlPanel.test.tsx +30 -0
- package/src/index.ts +3 -2
- package/src/instrument/types.ts +21 -1
- package/src/lab/Lab.chrome.test.tsx +8 -1
- package/src/lab/Lab.presentation.test.tsx +113 -0
- package/src/lab/Lab.surface.test.tsx +20 -9
- package/src/lab/Lab.tsx +132 -257
- package/src/lab/LabLightbox.browser.test.less +17 -0
- package/src/lab/LabLightbox.browser.test.tsx +216 -0
- package/src/lab/LabShell.less +10 -3
- package/src/lab/LabSurface.tsx +129 -0
- package/src/lab/Workspace.stories.tsx +18 -0
- package/src/lab/Workspace.surface.test.tsx +4 -0
- package/src/lab/Workspace.test.tsx +37 -1
- package/src/lab/Workspace.tsx +34 -6
- package/src/lab/index.ts +2 -0
- package/src/lab/nebula.ts +30 -0
- package/src/lab/openLab.test.ts +81 -0
- package/src/lab/openLab.ts +119 -0
- package/src/lab/presentation.browser.test.less +5 -0
- package/src/lab/presentation.browser.test.tsx +119 -0
- package/src/lab/presentation.less +64 -0
- package/src/lab/presentation.tsx +47 -0
- package/src/lab/useFocusPick.ts +43 -0
- package/src/lightbox/Lightbox.browser.test.less +14 -0
- package/src/lightbox/Lightbox.browser.test.tsx +113 -0
- package/src/lightbox/Lightbox.less +128 -0
- package/src/lightbox/Lightbox.test.tsx +195 -0
- package/src/lightbox/Lightbox.tsx +205 -0
- package/src/lightbox/LightboxContext.ts +38 -0
- package/src/lightbox/LightboxLayers.tsx +40 -0
- package/src/lightbox/index.ts +8 -0
- package/src/lightbox/modal.ts +94 -0
- package/src/loupe/AGENTS.md +40 -2
- package/src/loupe/CanvasLoupe.tsx +5 -4
- package/src/loupe/DomLoupe.tsx +7 -5
- package/src/loupe/Loupe.less +15 -0
- package/src/loupe/LoupeBubble.tsx +35 -13
- package/src/loupe/SourceLoupe.browser.test.tsx +204 -0
- package/src/loupe/SourceLoupe.tsx +60 -0
- package/src/loupe/TrialLoupe.browser.test.tsx +342 -0
- package/src/loupe/TrialLoupe.tsx +126 -28
- package/src/loupe/canvasLens.ts +20 -17
- package/src/loupe/index.ts +26 -2
- package/src/loupe/sourceLens.test.ts +65 -0
- package/src/loupe/sourceLens.ts +97 -0
- package/src/loupe/types.test.ts +6 -0
- package/src/loupe/types.ts +109 -7
- package/src/loupe/useLoupe.test.tsx +188 -3
- package/src/loupe/useLoupe.ts +106 -11
- package/src/primitives/index.ts +2 -2
- package/src/specimen/Specimen.tsx +0 -7
- package/src/state/helpers.test.ts +4 -11
- package/src/state/helpers.ts +2 -8
- package/src/state/index.ts +0 -2
- package/src/state/openLabStore.test.ts +10 -8
- package/src/state/openLabStore.ts +1 -1
- package/src/state/store.test.ts +2 -2
- package/src/state/store.ts +15 -16
- package/src/state/types.ts +9 -9
- package/src/styles.less +2 -1
- package/src/surface/AGENTS.md +13 -0
- package/src/surface/index.ts +1 -0
- package/src/surface/useSurfaceTile.test.tsx +4 -0
- package/src/surface/useSurfaceTile.ts +17 -1
- package/src/surface/useTiledSurface.test.tsx +65 -0
- package/src/surface/useTiledSurface.ts +68 -1
- package/src/theme/interstellar.theme.json +0 -14
- package/src/trial/Trial.stories.tsx +0 -1
- package/src/trial/Trial.test.tsx +40 -3
- package/src/trial/Trial.tsx +87 -43
- package/src/trial/TrialChrome.tsx +20 -2
- package/src/trial/trialOps.test.ts +1 -2
- package/src/trial/trialOps.ts +2 -3
- package/src/undo/stateOp.ts +21 -0
- package/src/undo/undoStack.ts +18 -6
- package/dist/chunk-4TJ34FXA.js.map +0 -1
- package/dist/chunk-4X44DMRS.js.map +0 -1
- package/dist/chunk-EESJUSYR.js.map +0 -1
- package/dist/chunk-HBGH344L.js.map +0 -1
- package/dist/chunk-IBVRMHW5.js.map +0 -1
- package/dist/chunk-IRMPZIYU.js.map +0 -1
- package/dist/chunk-LPGBC63T.js.map +0 -1
- package/dist/chunk-PMLZP7RT.js.map +0 -1
- package/dist/chunk-RL2LOLNI.js.map +0 -1
- package/dist/chunk-T6DLGEJB.js.map +0 -1
- package/dist/chunk-WIG6XHJ7.js.map +0 -1
- package/dist/chunk-XSJJTXNA.js.map +0 -1
- package/dist/chunk-YCFKW5RX.js.map +0 -1
- package/src/primitives/StatusBar.less +0 -34
- package/src/primitives/StatusBar.stories.tsx +0 -24
- package/src/primitives/StatusBar.test.tsx +0 -25
- package/src/primitives/StatusBar.tsx +0 -28
package/dist/loupe/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/loupe/canvasLens.ts","../../src/loupe/CanvasLoupe.tsx","../../src/loupe/DomLoupe.tsx","../../src/loupe/LoupeBubble.tsx","../../src/loupe/loupeActions.ts","../../src/loupe/LoupeGestures.tsx","../../src/loupe/types.ts","../../src/loupe/useHostSize.ts","../../../loupe/src/geometry.ts","../../../loupe/src/model.ts","../../src/loupe/useLoupe.ts","../../src/loupe/TrialLoupe.tsx"],"names":["jsx","useEffect","useRef","useLatest","useMemo","useContext"],"mappings":"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","file":"index.js","sourcesContent":["import type { LoupePoint } from '@weasel-js/loupe';\nimport { centerOn } from '../canvas/camera';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport type { CanvasLayerDescriptor } from '../canvas/useLayerScheduler';\nimport { DEFAULT_FRAME, resolveFrame, type WorldFrame, type WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\n\n/** The camera a round lens of `diameter` shows a magnified region through, and\n * the coordinate system it is read in — the instrument's own `WorldSpec`,\n * resolved against the lens rather than the stack. */\nexport interface LensCamera {\n view: ViewTransform;\n frame: WorldFrame;\n}\n\n/**\n * What a lens aimed at `aim` renders the stack's layers through.\n *\n * The lens is its own viewport, so the world spec resolves against its box: an\n * instrument centred on its viewport is centred in the lens too.\n */\nexport function lensCamera(\n aim: LoupePoint,\n outer: ViewTransform,\n outerFrame: WorldFrame,\n factor: number,\n diameter: number,\n worldSpec?: WorldSpec,\n): LensCamera {\n const size = { width: diameter, height: diameter };\n const frame = resolveFrame(worldSpec, size);\n const world = screenToWorld(aim, outer, outerFrame);\n return { view: centerOn(world, outer.zoom * factor, size, frame), frame };\n}\n\n/** A rectangle in a backing store's own device pixels. */\nexport interface SourceRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n}\n\n/**\n * The region a pixel-mode lens copies out of a presented canvas: the `diameter\n * / factor` CSS px around `aim`, in that canvas' backing-store pixels.\n */\nexport function lensSourceRect(\n aim: LoupePoint,\n factor: number,\n diameter: number,\n dpr: number,\n): SourceRect {\n const span = diameter / factor;\n return {\n sx: (aim.x - span / 2) * dpr,\n sy: (aim.y - span / 2) * dpr,\n sw: span * dpr,\n sh: span * dpr,\n };\n}\n\n/**\n * The color a stack presents at a point: the topmost visible layer with\n * anything opaque there, or `null` when every layer is transparent — which is\n * the honest answer for a point showing nothing but the workspace behind.\n */\nexport function sampleStack(\n layers: readonly CanvasLayerDescriptor[],\n canvases: Map<string, HTMLCanvasElement>,\n p: LoupePoint,\n dpr: number,\n): string | null {\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i];\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) continue;\n const x = Math.floor(p.x * dpr);\n const y = Math.floor(p.y * dpr);\n if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) continue;\n const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;\n if (a === 0) continue;\n return `#${[r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('')}`;\n }\n return null;\n}\n\n/** Redraw the stack into a lens' own canvas. `mode` decides whether the layers\n * are re-run at the lens camera or their presented pixels are enlarged. */\nexport function drawCanvasLens(\n ctx: CanvasRenderingContext2D,\n opts: {\n aim: LoupePoint;\n factor: number;\n diameter: number;\n dpr: number;\n mode: 'vector' | 'pixel';\n outer: ViewTransform;\n outerFrame?: WorldFrame;\n worldSpec?: WorldSpec;\n layers: readonly CanvasLayerDescriptor[];\n canvases: Map<string, HTMLCanvasElement>;\n },\n): void {\n const { aim, factor, diameter, dpr, mode, outer, layers, canvases } = opts;\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, diameter, diameter);\n\n if (mode === 'pixel') {\n const { sx, sy, sw, sh } = lensSourceRect(aim, factor, diameter, dpr);\n ctx.imageSmoothingEnabled = false;\n for (const layer of layers) {\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas || canvas.width === 0 || canvas.height === 0) continue;\n ctx.drawImage(canvas, sx, sy, sw, sh, 0, 0, diameter, diameter);\n }\n ctx.restore();\n return;\n }\n\n const lens = lensCamera(\n aim,\n outer,\n opts.outerFrame ?? DEFAULT_FRAME,\n factor,\n diameter,\n opts.worldSpec,\n );\n for (const layer of layers) {\n if (!layer.visible) continue;\n ctx.save();\n layer.render(ctx, lens.view, lens.frame);\n ctx.restore();\n }\n ctx.restore();\n}\n","import { useLatest, useVisibleRaf } from '@weasel-js/core';\nimport type { LoupeMode, LoupePoint } from '@weasel-js/loupe';\nimport { useEffect, useRef } from 'react';\nimport type { CanvasStackSurface } from '../canvas/CanvasStackContext';\nimport type { WorldFrame, WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport { drawCanvasLens } from './canvasLens';\n\n/** Props for `<CanvasLoupe>`. */\nexport interface CanvasLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n diameter: number;\n /** The stack being magnified: its layers, its pixels, and its measured box. */\n surface: CanvasStackSurface;\n view: ViewTransform;\n frame: WorldFrame;\n worldSpec?: WorldSpec;\n}\n\n/**\n * Paints a lens over a `<CanvasStack>` by re-drawing the stack's layers through\n * a zoomed camera — so the magnified content is as sharp as the original, at\n * any factor. `pixel` mode enlarges what the stack presented instead.\n */\nexport function CanvasLoupe({\n aim,\n factor,\n mode,\n diameter,\n surface,\n view,\n frame,\n worldSpec,\n}: CanvasLoupeProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const dpr = surface.size.dpr;\n\n // Whatever the stack redraws every frame, the lens has to redraw too — an\n // instrument that animates from its own loop never re-renders this component.\n const args = { aim, factor, mode, diameter, dpr, view, frame, worldSpec, surface };\n const argsRef = useLatest(args);\n\n const loop = useVisibleRaf(\n () => {\n loop.request();\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext('2d');\n const canvases = argsRef.current.surface.canvases.current;\n if (!ctx || !canvases) return;\n const a = argsRef.current;\n drawCanvasLens(ctx, {\n aim: a.aim,\n factor: a.factor,\n diameter: a.diameter,\n dpr: a.dpr,\n mode: a.mode,\n outer: a.view,\n outerFrame: a.frame,\n worldSpec: a.worldSpec,\n layers: a.surface.layers,\n canvases,\n });\n },\n { target: canvasRef },\n );\n\n useEffect(() => {\n loop.request();\n return () => loop.cancel();\n }, [loop]);\n\n return (\n <canvas\n ref={canvasRef}\n className=\"lk-loupe__canvas\"\n width={Math.max(1, Math.round(diameter * dpr))}\n height={Math.max(1, Math.round(diameter * dpr))}\n />\n );\n}\n","import type { LoupeMode, LoupePoint } from '@weasel-js/loupe';\nimport type { CSSProperties } from 'react';\nimport { zoomAt } from '../canvas/camera';\nimport type { ViewportSize, WorldFrame } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport type { LoupeRenderArgs } from './types';\n\n/** Props for `<DomLoupe>`. */\nexport interface DomLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n diameter: number;\n /** The host the instrument draws into, which the stage reproduces. */\n size: ViewportSize;\n /** The trial's own camera. */\n view: ViewTransform;\n frame?: WorldFrame;\n render: (args: LoupeRenderArgs) => React.ReactNode;\n}\n\n/**\n * Paints a lens over DOM content by asking its `render` to draw it again\n * at a magnified camera.\n *\n * The stage is a full copy of the host, so the instrument's own layout still\n * holds; the camera is composed about the aimed point, which keeps that point\n * where it already was, and the stage is then slid by `diameter / 2 - aim` to\n * bring it to the middle of the lens.\n */\nexport function DomLoupe({\n aim,\n factor,\n mode,\n diameter,\n size,\n view,\n frame,\n render,\n}: DomLoupeProps) {\n const style: CSSProperties = {\n width: `${size.width}px`,\n height: `${size.height}px`,\n transform: `translate(${diameter / 2 - aim.x}px, ${diameter / 2 - aim.y}px)`,\n };\n return (\n <div className=\"lk-loupe__stage\" style={style}>\n {render({\n view: zoomAt(view, factor, aim, { frame }),\n factor,\n mode,\n size,\n })}\n </div>\n );\n}\n","import type { LoupePoint } from '@weasel-js/loupe';\nimport type { CSSProperties, ReactNode, RefObject } from 'react';\n\n/** Props for `<LoupeBubble>`. */\nexport interface LoupeBubbleProps {\n /** Where the lens is aimed, in its container's own pixels. */\n aim: LoupePoint;\n diameter: number;\n hostRef?: RefObject<HTMLDivElement | null>;\n children: ReactNode;\n}\n\n/**\n * The lens itself: a circle centred on the aimed point, clipping whatever a\n * painter draws into it.\n *\n * It takes no pointer events, so the pan, the wheel and anything underneath\n * keep working while it is up — and it is `aria-hidden`, since it magnifies\n * content already on the page rather than adding any.\n */\nexport function LoupeBubble({ aim, diameter, hostRef, children }: LoupeBubbleProps) {\n const style: CSSProperties = {\n width: `${diameter}px`,\n height: `${diameter}px`,\n transform: `translate(${aim.x - diameter / 2}px, ${aim.y - diameter / 2}px)`,\n };\n return (\n <div ref={hostRef} className=\"lk-loupe\" style={style} aria-hidden=\"true\">\n {children}\n </div>\n );\n}\n","/**\n * The loupe's two bindable interactions, as `Action` descriptors the gesture\n * dispatcher routes: hold a key to peek, and walk the magnification with the\n * wheel.\n *\n * Free of React so the routing can be tested without a DOM.\n */\nimport type { Action } from '@weasel-js/core';\n\n/** Canonical id of the hold-to-peek action. */\nexport const LOUPE_PEEK_ID = 'loupe.peek';\n/** Canonical id of the wheel-magnify action. */\nexport const LOUPE_MAGNIFY_ID = 'loupe.magnify';\n\n/** How fast the wheel walks the magnification. Gentler than the pan-zoom\n * wheel: the lens' whole range is one order of magnitude. */\nexport const WHEEL_RATE = 0.002;\n\n/** What the actions do to a live loupe. Every member is read through the\n * object on each invocation, so one stable instance serves the life of the\n * registration. */\nexport interface LoupeInputApi {\n /** Whether the lens is up. The wheel belongs to the loupe only while it is;\n * otherwise `loupe.magnify` declines and the dispatcher falls through to\n * the trial camera's zoom. */\n shown: () => boolean;\n /** Raise or drop the hold-to-peek flag. */\n setPeeking: (on: boolean) => void;\n /** Multiply the magnification by one wheel notch of `deltaY`. */\n magnifyBy: (deltaY: number) => void;\n}\n\n/**\n * Build the loupe's actions. `peekKey` is a `KeyboardEvent.key`; passing\n * `null` omits `loupe.peek` entirely rather than registering a binding no key\n * can match.\n */\nexport function createLoupeActions(\n input: LoupeInputApi,\n peekKey: string | null,\n): readonly Action[] {\n const magnify: Action = {\n id: LOUPE_MAGNIFY_ID,\n label: 'Magnify (loupe)',\n group: 'loupe',\n // Hotkey scope, so while the lens is up it outranks the trial camera's\n // wheel zoom on the same dispatcher; while it is down `enabled` declines\n // and the zoom runs.\n scope: 'hotkey',\n // Every modifier optional: the lens claims the wheel whenever it is up,\n // which is what the hand-rolled capture-phase listener did. A bare spec\n // would forbid modifiers and hand Cmd+wheel back to the lab mid-peek.\n defaultBinding: [\n {\n spec: {\n kind: 'wheel',\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n enabled: () => (input.shown() ? true : 'not-applicable'),\n invoker: {\n timing: 'immediate',\n run(_deps, params) {\n input.magnifyBy((params?.deltaY as number | undefined) ?? 0);\n },\n },\n };\n\n if (peekKey === null) return [magnify];\n\n const peek: Action = {\n id: LOUPE_PEEK_ID,\n label: 'Peek (loupe)',\n group: 'loupe',\n // Hotkey scope: peeking must beat whatever the lab's active tool binds to\n // the same key, the way every other held-key trigger does.\n scope: 'hotkey',\n // Every modifier optional because the peek key may BE one: the keydown\n // that carries `Alt` — the default — also reports `altKey: true`, and the\n // matcher forbids any modifier a spec does not name.\n defaultBinding: [\n {\n spec: {\n kind: 'key-held',\n key: peekKey,\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n invoker: {\n timing: 'ongoing',\n start() {\n input.setPeeking(true);\n return { onEnd: () => input.setPeeking(false) };\n },\n },\n };\n return [peek, magnify];\n}\n","/**\n * Registers the loupe's actions, and mounts the gesture dispatcher on the\n * loupe's host when no camera already has one there, so the peek key and the\n * wheel route the way every other weasel binding does.\n *\n * Three of the dispatcher's four element channels are off. Only `wheel` is\n * wanted here; `contextMenu` suppresses the native menu unconditionally and\n * `ingest` makes the host a file-drop target, neither of which a lab asked\n * for by turning a magnifier on.\n */\nimport {\n type ActionsRegistry,\n type Tool,\n useActionsRegistry,\n useGestureDispatcher,\n} from '@weasel-js/core';\nimport { type RefObject, useContext, useEffect, useMemo } from 'react';\nimport { CameraContext } from '../canvas/CameraInput';\nimport { createLoupeActions, type LoupeInputApi } from './loupeActions';\n\n/** Props for `<LoupeGestures>`. */\nexport interface LoupeGesturesProps {\n /** The element the dispatcher listens on — the same one the lens tracks. */\n hostRef: RefObject<HTMLElement | null>;\n input: LoupeInputApi;\n /** `KeyboardEvent.key` for hold-to-peek, or `null` for no peek binding. */\n peekKey: string | null;\n}\n\nconst NO_TOOLS: ReadonlyMap<string, Tool> = new Map();\n\nconst CHANNELS = { pointer: false, contextMenu: false, ingest: false } as const;\n\nfunction LoupeDispatch({\n hostRef,\n input,\n peekKey,\n registry,\n ownDispatcher,\n}: LoupeGesturesProps & { registry: ActionsRegistry; ownDispatcher: boolean }) {\n const actions = useMemo(() => createLoupeActions(input, peekKey), [input, peekKey]);\n\n useEffect(() => {\n const offs = actions.map((a) => registry.register(a));\n return () => {\n for (const off of offs) off();\n };\n }, [registry, actions]);\n\n useGestureDispatcher({\n canvasRef: hostRef,\n actions: registry,\n entriesById: NO_TOOLS,\n channels: CHANNELS,\n enabled: ownDispatcher,\n });\n\n return null;\n}\n\n/**\n * The loupe's input, routed. Inside a camera (`<CanvasStack>`, `<Stage>`) its\n * actions join the camera's dispatcher, which already listens on the host;\n * elsewhere it mounts a dispatcher of its own. With no registry in scope it\n * renders nothing rather than registering actions that could never fire.\n */\nexport function LoupeGestures(props: LoupeGesturesProps) {\n const registry = useActionsRegistry();\n const camera = useContext(CameraContext);\n if (!registry) return null;\n return <LoupeDispatch {...props} registry={registry} ownDispatcher={camera === null} />;\n}\n","import type { LoupeMode } from '@weasel-js/loupe';\nimport type { ReactNode } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\n\n/** What a DOM loupe's `render` is handed: the camera to draw the content\n * through again. */\nexport interface LoupeRenderArgs {\n /** The trial's own camera composed with the magnification, about the aimed\n * point — so drawing the same content through it magnifies in place. */\n view: ViewTransform;\n /** The magnification on its own, for whatever must not scale with the\n * camera. */\n factor: number;\n mode: LoupeMode;\n /** The size of the viewport `view` is written for: the trial's content well,\n * not the lens. The lens shows a circle cut out of it. */\n size: ViewportSize;\n}\n\n/**\n * How a lens magnifies.\n *\n * With no `render`, the lens re-draws the canvas stack's layers through a\n * zoomed camera, so it stays sharp at any factor. Over DOM content, `render`\n * draws it instead: given a camera, draw me again.\n */\nexport interface LoupeOptions {\n render?: (args: LoupeRenderArgs) => ReactNode;\n /** Opening magnification, clamped to the bounds below. Default 6. */\n factor?: number;\n /** What the wheel clamps to. Defaults 2 and 32. */\n minFactor?: number;\n maxFactor?: number;\n /** `'vector'` (default) re-renders the content magnified; `'pixel'` blows up\n * the pixels the instrument presented. A `render` loupe is always vector —\n * DOM has no framebuffer to enlarge. */\n mode?: LoupeMode;\n /** Lens diameter in CSS px. Default 200. */\n diameter?: number;\n /** Held for a momentary peek while the loupe is off. Default `'Alt'`; `null`\n * turns hold-to-peek off. Matched against `KeyboardEvent.key`. */\n peekKey?: string | null;\n /** Called with the color under the aim, wherever the surface can say. The\n * canvas painter reads it back; a DOM loupe has no pixels to sample. */\n onColorChange?: (hex: string) => void;\n}\n\n/** {@link LoupeOptions} with every default filled in. */\nexport interface ResolvedLoupe {\n render?: (args: LoupeRenderArgs) => ReactNode;\n onColorChange?: (hex: string) => void;\n factor: number;\n minFactor: number;\n maxFactor: number;\n mode: LoupeMode;\n diameter: number;\n peekKey: string | null;\n}\n\n/** What `resolveLoupe` fills in for anything a declaration leaves unset. */\nexport const LOUPE_DEFAULTS = {\n factor: 6,\n minFactor: 2,\n maxFactor: 32,\n mode: 'vector',\n diameter: 200,\n peekKey: 'Alt',\n} as const satisfies Omit<ResolvedLoupe, 'render' | 'onColorChange'>;\n\n/** `options` with every default filled in and `factor` clamped to\n * `[minFactor, maxFactor]`. A loupe with its own `render` is always `'vector'`. */\nexport function resolveLoupe(options: LoupeOptions = {}): ResolvedLoupe {\n const minFactor = options.minFactor ?? LOUPE_DEFAULTS.minFactor;\n const maxFactor = options.maxFactor ?? LOUPE_DEFAULTS.maxFactor;\n return {\n render: options.render,\n onColorChange: options.onColorChange,\n minFactor,\n maxFactor,\n factor: Math.min(maxFactor, Math.max(minFactor, options.factor ?? LOUPE_DEFAULTS.factor)),\n diameter: options.diameter ?? LOUPE_DEFAULTS.diameter,\n peekKey: options.peekKey === undefined ? LOUPE_DEFAULTS.peekKey : options.peekKey,\n // A DOM loupe has no framebuffer, so `pixel` would have nothing to enlarge.\n mode: options.render ? 'vector' : (options.mode ?? LOUPE_DEFAULTS.mode),\n };\n}\n","import { type RefObject, useEffect, useState } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\n\nconst ZERO: ViewportSize = { width: 0, height: 0 };\n\n/** An element's CSS-pixel box, kept current. `{0, 0}` until it is measured, and\n * wherever `ResizeObserver` is absent. */\nexport function useHostSize(ref: RefObject<HTMLElement | null>): ViewportSize {\n const [size, setSize] = useState<ViewportSize>(ZERO);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const update = (): void => {\n const rect = el.getBoundingClientRect();\n setSize((prev) =>\n prev.width === rect.width && prev.height === rect.height\n ? prev\n : { width: rect.width, height: rect.height },\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 }, [ref]);\n\n return size;\n}\n","import type { View } from '@weasel-js/core';\n\n/** A point on the magnified surface, in its own CSS pixels. */\nexport interface LoupePoint {\n x: number;\n y: number;\n}\n\n/** The lens' rectangle on that surface. */\nexport interface LoupeRect extends LoupePoint {\n w: number;\n h: number;\n}\n\n/**\n * The inner `View` a loupe renders its content through: the outer view's\n * magnification times `factor`, positioned so `target` sits at the center of\n * a viewport the size of `rect`.\n */\nexport function loupeInnerView(\n target: LoupePoint,\n outer: View,\n rect: LoupeRect,\n factor: number,\n): View {\n const scale = { x: outer.scale.x * factor, y: outer.scale.y * factor };\n return {\n x: target.x - rect.w / 2 / scale.x,\n y: target.y - rect.h / 2 / scale.y,\n scale,\n };\n}\n\n/**\n * Where on the outer surface a point inside the lens is looking, in\n * screen-space CSS px.\n *\n * The inverse of {@link loupeInnerView}: the lens centers `aim` in `rect` and\n * magnifies by `factor`, and the outer view's own scale cancels out of the\n * round trip — so this needs no `View`.\n */\nexport function loupeSourcePoint(\n p: LoupePoint,\n rect: LoupeRect,\n aim: LoupePoint,\n factor: number,\n): LoupePoint {\n return {\n x: aim.x + (p.x - (rect.x + rect.w / 2)) / factor,\n y: aim.y + (p.y - (rect.y + rect.h / 2)) / factor,\n };\n}\n","import { normalizeZoom } from '@weasel-js/core';\nimport { type LoupePoint, type LoupeRect, loupeSourcePoint } from './geometry';\n\n/** How a loupe magnifies. `'vector'` re-renders the source through a zoomed-in\n * view, so content stays sharp at any factor; `'pixel'` blows up the actual\n * pixels the surface presented. */\nexport type LoupeMode = 'vector' | 'pixel';\n\n/**\n * What a loupe needs from the surface it magnifies. A painter implements it,\n * and the model asks nothing about how the lens is drawn — only where it is,\n * what colour is under a point, and whether anyone can still see it.\n */\nexport interface LoupeSurface {\n /** The lens' rectangle, or `null` while it has none. */\n lens(): LoupeRect | null;\n /**\n * Does the lens itself cover this point? A stationary lens does over its own\n * frame, which is what the freeze rule below is for; a lens that follows the\n * pointer never covers it and answers `false`.\n */\n covers(p: LoupePoint): boolean;\n /** Hex colour at a surface point, or `null` when the surface cannot say. */\n sample(p: LoupePoint): string | null;\n /** Is the lens off screen? Aims are ignored while it is. */\n hidden(): boolean;\n /** Is the lens gone for good? The model tears itself down when it is. */\n gone(): boolean;\n /** Something the painter must redraw for has changed. */\n changed(): void;\n /**\n * Run `fn` after each frame the surface lands; returns an unsubscribe.\n * Implement it when `sample` reads pixels that only show an aim once a\n * frame has painted — a framebuffer read back. The model then samples the\n * aim on the next landed frame, so `color` settles a frame after the aim.\n * Omit it when `sample` can answer for a fresh aim right away.\n */\n subscribeFrame?(fn: () => void): () => void;\n}\n\n/** Options for {@link createLoupeModel}. */\nexport interface LoupeModelOptions {\n surface: LoupeSurface;\n mode?: LoupeMode;\n /** Magnification. Default 8. Always positive and finite: a factor that is\n * not becomes `ZOOM_FLOOR`, the same rule a view's zoom follows. */\n factor?: number;\n /** Bounds `setFactor` clamps to. Unset means bounded only by that rule. */\n minFactor?: number;\n maxFactor?: number;\n /** Called with the hex colour under the aim point whenever it changes. */\n onColorChange?: (hex: string) => void;\n /** Called when a pick lands — an eyedropper on the magnified surface. Where\n * the colour goes is the consumer's business. */\n onPick?: (hex: string) => void;\n /** Called when the model tears itself down because the surface reported the\n * lens gone, so the painter can drop what it was holding. */\n onDispose?: () => void;\n}\n\n/** Where a loupe is aimed, how far it magnifies, and what colour it is over. */\nexport interface LoupeModel {\n readonly mode: LoupeMode;\n readonly factor: number;\n /** Last aimed point, in the surface's CSS px. */\n readonly aim: LoupePoint;\n /** Hex colour under the aim point. `null` until something answers. */\n readonly color: string | null;\n setMode(mode: LoupeMode): void;\n setFactor(factor: number): void;\n /** Aim at a surface point. Ignored while the lens covers it, is hidden, or\n * the model is disposed. */\n aimAt(p: LoupePoint): void;\n /** Sample what the lens shows at `p`, a point inside it, and report that to\n * `onPick`. Omit `p` to pick at the aim point. Leaves the aim, and `color`,\n * alone. */\n pick(p?: LoupePoint): string | null;\n dispose(): void;\n}\n\n/**\n * Build the loupe's model over a surface. It holds the state a magnifier has —\n * aim, factor, mode, colour — and none of the drawing.\n */\nexport function createLoupeModel(opts: LoupeModelOptions): LoupeModel {\n const { surface } = opts;\n let mode: LoupeMode = opts.mode ?? 'vector';\n let factor = normalizeZoom(opts.factor ?? 8);\n let aim: LoupePoint = { x: 0, y: 0 };\n let color: string | null = null;\n let disposed = false;\n let aimUnsampled = false;\n\n const clamp = (n: number): number =>\n normalizeZoom(Math.min(opts.maxFactor ?? Number.POSITIVE_INFINITY,\n Math.max(opts.minFactor ?? Number.NEGATIVE_INFINITY, n)));\n\n const sampleColor = () => {\n const hex = surface.sample(aim);\n if (hex === null || hex === color) return;\n color = hex;\n opts.onColorChange?.(hex);\n };\n\n const unsubscribeFrame = surface.subscribeFrame?.(() => {\n if (!aimUnsampled) return;\n aimUnsampled = false;\n sampleColor();\n });\n\n const teardown = () => {\n if (disposed) return;\n disposed = true;\n unsubscribeFrame?.();\n opts.onDispose?.();\n };\n\n return {\n get mode() { return mode; },\n get factor() { return factor; },\n get aim() { return aim; },\n get color() { return color; },\n\n setMode(next) {\n if (disposed || next === mode) return;\n mode = next;\n surface.changed();\n },\n\n setFactor(next) {\n if (disposed) return;\n factor = clamp(next);\n surface.changed();\n },\n\n aimAt(p) {\n if (disposed) return;\n // A lens can be taken away by whatever owns it, without coming back\n // through `dispose`. Follow it down rather than keep sampling for a\n // magnifier nobody can see.\n if (surface.gone()) { teardown(); return; }\n if (surface.hidden()) return;\n if (surface.covers(p)) return;\n aim = p;\n if (unsubscribeFrame) aimUnsampled = true;\n else sampleColor();\n surface.changed();\n },\n\n pick(p) {\n if (disposed) return null;\n let at = aim;\n if (p) {\n const rect = surface.lens();\n if (!rect) return null;\n at = loupeSourcePoint(p, rect, aim, factor);\n // The lens is part of the picture the surface presents. A point near\n // its frame maps back underneath it, and sampling there reports the\n // lens' own chrome as artwork.\n if (surface.covers(at)) return null;\n }\n const hex = surface.sample(at);\n if (hex !== null) opts.onPick?.(hex);\n return hex;\n },\n\n dispose: teardown,\n };\n}\n","import { useLatest } from '@weasel-js/core';\nimport {\n createLoupeModel,\n type LoupeMode,\n type LoupeModel,\n type LoupePoint,\n} from '@weasel-js/loupe';\nimport { type RefObject, useCallback, useEffect, useReducer, useRef } from 'react';\nimport type { LoupeInputApi } from './loupeActions';\nimport { WHEEL_RATE } from './loupeActions';\nimport type { ResolvedLoupe } from './types';\n\n/** Options for {@link useLoupe}. */\nexport interface UseLoupeOptions {\n options: ResolvedLoupe;\n /** The element the lens tracks the pointer across. */\n hostRef: RefObject<HTMLElement | null>;\n /** Whether the loupe is turned on. Hold-to-peek shows it regardless. */\n enabled: boolean;\n /** Hex color at a host point. Omitted, the loupe reports no color — which\n * is the honest answer for a surface with no pixels to read. */\n sample?: (p: LoupePoint) => string | null;\n}\n\n/** A loupe as a React view reads it. */\nexport interface LoupeState {\n /** Whether the lens should be drawn. */\n visible: boolean;\n /** Where it is aimed, in the host's own pixels. */\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n color: string | null;\n setMode: (mode: LoupeMode) => void;\n setFactor: (factor: number) => void;\n /** Sample what the lens shows at a point inside it. */\n pick: (p?: LoupePoint) => string | null;\n /** What `<LoupeGestures>` drives the lens through. Stable for the life of\n * the hook, so registering the actions on it does not churn. */\n input: LoupeInputApi;\n}\n\n/** Whether the lens is up: the pointer is over the host, and the loupe is on or peeked. */\nfunction lensShown(over: boolean, enabled: boolean, peeking: boolean): boolean {\n return over && (enabled || peeking);\n}\n\n/**\n * Binds `@weasel-js/loupe`'s model to a host element and tracks the pointer\n * across it.\n *\n * The peek key and the wheel are not here: they are `loupe.peek` and\n * `loupe.magnify`, routed through the gesture dispatcher that\n * `<LoupeGestures>` mounts on the same host. Aiming stays a plain listener\n * because a hover is not a gesture the grammar names — `GESTURE_DESCRIPTORS`\n * has no continuous-motion entry, and inventing one to carry the lens' aim\n * would be an input taxonomy change, not a loupe change.\n */\nexport function useLoupe({ options, hostRef, enabled, sample }: UseLoupeOptions): LoupeState {\n const [, bump] = useReducer((n: number) => n + 1, 0);\n\n const overRef = useRef(false);\n const peekingRef = useRef(false);\n const enabledRef = useLatest(enabled);\n const sampleRef = useLatest(sample);\n const onColorChangeRef = useLatest(options.onColorChange);\n\n // Reads nothing but refs, so it is stable and an effect may depend on it.\n const shown = useCallback(\n (): boolean => lensShown(overRef.current, enabledRef.current, peekingRef.current),\n [enabledRef],\n );\n\n const modelRef = useRef<LoupeModel | null>(null);\n if (modelRef.current === null) {\n modelRef.current = createLoupeModel({\n mode: options.mode,\n factor: options.factor,\n minFactor: options.minFactor,\n maxFactor: options.maxFactor,\n onColorChange: (hex) => onColorChangeRef.current?.(hex),\n surface: {\n lens: () => {\n const d = diameterRef.current;\n const { x, y } = modelRef.current?.aim ?? { x: 0, y: 0 };\n return { x: x - d / 2, y: y - d / 2, w: d, h: d };\n },\n // The lens follows the pointer and is painted over the host rather than\n // into it, so it is never part of the picture being magnified.\n covers: () => false,\n sample: (p) => sampleRef.current?.(p) ?? null,\n hidden: () => !shown(),\n gone: () => goneRef.current,\n changed: bump,\n },\n });\n }\n const model = modelRef.current;\n\n const diameterRef = useLatest(options.diameter);\n const goneRef = useRef(false);\n\n // The model holds no resources, and `dispose` is one-way — so unmounting only\n // reports the lens gone. Disposing here instead leaves React's mount / unmount\n // / remount in StrictMode with a permanently dead model that silently ignores\n // every aim.\n useEffect(() => {\n goneRef.current = false;\n return () => {\n goneRef.current = true;\n };\n }, []);\n\n // Turning the loupe off with the pointer still inside must put the lens away,\n // and the model only reconsiders on an aim.\n useEffect(() => {\n if (!enabled && !peekingRef.current) bump();\n }, [enabled]);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const onPointerMove = (e: PointerEvent): void => {\n overRef.current = true;\n const rect = host.getBoundingClientRect();\n model.aimAt({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n if (!shown()) return;\n bump();\n };\n const onPointerLeave = (): void => {\n overRef.current = false;\n bump();\n };\n\n host.addEventListener('pointermove', onPointerMove);\n host.addEventListener('pointerleave', onPointerLeave);\n return () => {\n host.removeEventListener('pointermove', onPointerMove);\n host.removeEventListener('pointerleave', onPointerLeave);\n };\n }, [hostRef, model, shown]);\n\n const inputRef = useRef<LoupeInputApi | null>(null);\n if (inputRef.current === null) {\n inputRef.current = {\n shown,\n setPeeking: (on) => {\n if (peekingRef.current === on) return;\n peekingRef.current = on;\n bump();\n },\n magnifyBy: (deltaY) => {\n const m = modelRef.current;\n if (m) m.setFactor(m.factor * Math.exp(-deltaY * WHEEL_RATE));\n },\n };\n }\n\n return {\n // This render's `enabled`: `enabledRef` holds the last committed one.\n visible: lensShown(overRef.current, enabled, peekingRef.current),\n aim: model.aim,\n factor: model.factor,\n mode: model.mode,\n color: model.color,\n setMode: model.setMode,\n setFactor: model.setFactor,\n pick: model.pick,\n input: inputRef.current,\n };\n}\n","import { type ReactNode, type RefObject, useContext, useEffect, useMemo, useRef } from 'react';\nimport { CameraContext, CameraScope } from '../canvas/CameraInput';\nimport { CanvasStackContext } from '../canvas/CanvasStackContext';\nimport { fromCameraView } from '../canvas/cameraView';\nimport type { ViewTransform } from '../instrument/types';\nimport { LoupeSwitchContext } from '../trial/loupeSwitch';\nimport { CanvasLoupe } from './CanvasLoupe';\nimport { sampleStack } from './canvasLens';\nimport { DomLoupe } from './DomLoupe';\nimport { LoupeBubble } from './LoupeBubble';\nimport { LoupeGestures } from './LoupeGestures';\nimport { type LoupeOptions, resolveLoupe } from './types';\nimport { useHostSize } from './useHostSize';\nimport { useLoupe } from './useLoupe';\n\n/** Props for `<TrialLoupe>`. */\nexport interface TrialLoupeProps extends LoupeOptions {\n /** Whether the lens is turned on. Omitted, it follows the trial's toolbar\n * toggle, which the trial offers while a lens like this is mounted — and is\n * off outside a trial. Hold-to-peek shows it either way. */\n enabled?: boolean;\n /** The camera a `render` lens composes its magnification onto. Defaults to\n * the camera around it, and to the identity outside one. */\n view?: ViewTransform;\n /** The element the lens tracks. Defaults to the canvas stack or stage around\n * it, and outside both to a box wrapped around `children`. */\n hostRef?: RefObject<HTMLElement | null>;\n /** Content for the lens to sit over. Wrapped in a box of the lens's own only\n * when nothing around it gives the lens an element to track. */\n children?: ReactNode;\n}\n\nconst IDENTITY: ViewTransform = { zoom: 1, pan: { x: 0, y: 0 } };\n\n/**\n * A trial's magnifier, mounted by the instrument wherever its content is: in\n * a canvas instrument's `render`, a stage's `overlay`, or around DOM content.\n *\n * With no `render` inside a `<CanvasStack>`, it re-draws the stack's own\n * layers through a zoomed camera. With `render`, it asks for the content again\n * at a magnified camera.\n */\nexport function TrialLoupe({\n enabled,\n view,\n hostRef,\n children,\n render,\n factor,\n minFactor,\n maxFactor,\n mode,\n diameter,\n peekKey,\n onColorChange,\n}: TrialLoupeProps) {\n const options = useMemo(\n () =>\n resolveLoupe({\n render,\n factor,\n minFactor,\n maxFactor,\n mode,\n diameter,\n peekKey,\n onColorChange,\n }),\n [render, factor, minFactor, maxFactor, mode, diameter, peekKey, onColorChange],\n );\n\n const stack = useContext(CanvasStackContext);\n const camera = useContext(CameraContext);\n const loupeSwitch = useContext(LoupeSwitchContext);\n const surface = options.render ? undefined : stack?.surface;\n\n const ownHost = useRef<HTMLDivElement | null>(null);\n const cameraHost = useMemo<RefObject<HTMLElement | null> | null>(\n () =>\n camera\n ? {\n get current() {\n return camera.element();\n },\n }\n : null,\n [camera],\n );\n const host = surface?.element ?? hostRef ?? cameraHost ?? ownHost;\n const wraps = host === ownHost;\n\n // A lens told whether it is on has no use for the trial's toggle.\n const mount = enabled === undefined ? loupeSwitch?.mount : undefined;\n useEffect(() => mount?.(), [mount]);\n\n const sample = useMemo(() => {\n if (!surface) return undefined;\n return (p: { x: number; y: number }): string | null => {\n const canvases = surface.canvases.current;\n return canvases ? sampleStack(surface.layers, canvases, p, surface.size.dpr) : null;\n };\n }, [surface]);\n\n const loupe = useLoupe({\n options,\n hostRef: host,\n enabled: enabled ?? loupeSwitch?.on ?? false,\n sample,\n });\n const measured = useHostSize(host);\n const size = surface?.size ?? measured;\n\n // The gestures mount outside the visibility gate: hold-to-peek is what\n // raises a lens that is down, so its binding has to be live while it is.\n // In a trial they join the trial's scope, and with it the camera's\n // dispatcher; outside one, `<CameraScope>` gives them an isolated scope.\n const gestures = (\n <CameraScope>\n <LoupeGestures hostRef={host} input={loupe.input} peekKey={options.peekKey ?? null} />\n </CameraScope>\n );\n\n const lens = loupe.visible ? (\n <LoupeBubble aim={loupe.aim} diameter={options.diameter}>\n {options.render ? (\n <DomLoupe\n aim={loupe.aim}\n factor={loupe.factor}\n mode={loupe.mode}\n diameter={options.diameter}\n size={size}\n view={\n view ??\n stack?.view ??\n (camera ? fromCameraView(camera.view.get(), camera.frame) : IDENTITY)\n }\n frame={stack?.frame ?? camera?.frame}\n render={options.render}\n />\n ) : surface && stack ? (\n <CanvasLoupe\n aim={loupe.aim}\n factor={loupe.factor}\n mode={loupe.mode}\n diameter={options.diameter}\n surface={surface}\n view={stack.view}\n frame={stack.frame}\n worldSpec={surface.worldSpec}\n />\n ) : null}\n </LoupeBubble>\n ) : null;\n\n if (wraps) {\n return (\n <div ref={ownHost} className=\"lk-loupe-host\">\n {children}\n {gestures}\n {lens}\n </div>\n );\n }\n return (\n <>\n {children}\n {gestures}\n {lens}\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../loupe/src/geometry.ts","../../../loupe/src/model.ts","../../../loupe/src/canvasSource.ts","../../src/loupe/canvasLens.ts","../../src/loupe/CanvasLoupe.tsx","../../src/loupe/DomLoupe.tsx","../../src/loupe/LoupeBubble.tsx","../../src/loupe/loupeActions.ts","../../src/loupe/LoupeGestures.tsx","../../src/loupe/sourceLens.ts","../../src/loupe/SourceLoupe.tsx","../../src/loupe/types.ts","../../src/loupe/useHostSize.ts","../../src/loupe/useLoupe.ts","../../src/loupe/TrialLoupe.tsx"],"names":["jsx","useEffect","useRef","useLatest","useVisibleRaf","useContext","useMemo","useCallback","lens"],"mappings":"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","file":"index.js","sourcesContent":["import type { View } from '@weasel-js/core';\n\n/** A point on the magnified surface, in its own CSS pixels. */\nexport interface LoupePoint {\n x: number;\n y: number;\n}\n\n/** How big a lens is, in CSS px: one number for a round or square lens, or a\n * width and a height. */\nexport type LoupeSize = number | { width: number; height: number };\n\n/** `size` as a width and a height. */\nexport function loupeExtent(size: LoupeSize): { width: number; height: number } {\n return typeof size === 'number' ? { width: size, height: size } : size;\n}\n\n/** The lens' rectangle on that surface. */\nexport interface LoupeRect extends LoupePoint {\n w: number;\n h: number;\n}\n\n/**\n * The inner `View` a loupe renders its content through: the outer view's\n * magnification times `factor`, positioned so `target` sits at the center of\n * a viewport the size of `rect`.\n */\nexport function loupeInnerView(\n target: LoupePoint,\n outer: View,\n rect: LoupeRect,\n factor: number,\n): View {\n const scale = { x: outer.scale.x * factor, y: outer.scale.y * factor };\n return {\n x: target.x - rect.w / 2 / scale.x,\n y: target.y - rect.h / 2 / scale.y,\n scale,\n };\n}\n\n/**\n * Where on the outer surface a point inside the lens is looking, in\n * screen-space CSS px.\n *\n * The inverse of {@link loupeInnerView}: the lens centers `aim` in `rect` and\n * magnifies by `factor`, and the outer view's own scale cancels out of the\n * round trip — so this needs no `View`.\n */\nexport function loupeSourcePoint(\n p: LoupePoint,\n rect: LoupeRect,\n aim: LoupePoint,\n factor: number,\n): LoupePoint {\n return {\n x: aim.x + (p.x - (rect.x + rect.w / 2)) / factor,\n y: aim.y + (p.y - (rect.y + rect.h / 2)) / factor,\n };\n}\n\n/** What {@link placeBand} fits. */\nexport interface PlaceBandArgs {\n /** The region to show whole, in host CSS px. */\n band: LoupeRect;\n /** The most it may be magnified: the lens's own factor. */\n factor: number;\n /** The host's width: the lens is never wider, and is moved to stay inside it. */\n maxWidth: number;\n /** The host's height, likewise. Omitted, the height is not limited. */\n maxHeight?: number;\n}\n\n/** A lens fitted to a band, in the shape a loupe's `place` returns. */\nexport interface BandPlacement {\n /** Where the lens is drawn, moved as far as staying on the host needs. */\n center: LoupePoint;\n /** The band's center, which the lens shows at its middle wherever it is drawn. */\n shows: LoupePoint;\n width: number;\n height: number;\n factor: number;\n}\n\n/**\n * A lens showing all of `band`: magnified by `factor`, or by less where that\n * would make the lens wider than `maxWidth` or taller than `maxHeight`, and\n * drawn over the band except as far as it must move to stay on the host.\n */\nexport function placeBand({ band, factor, maxWidth, maxHeight }: PlaceBandArgs): BandPlacement {\n let fit = factor;\n if (band.w > 0) fit = Math.min(fit, maxWidth / band.w);\n if (maxHeight !== undefined && band.h > 0) fit = Math.min(fit, maxHeight / band.h);\n const width = band.w * fit;\n const height = band.h * fit;\n const shows = { x: band.x + band.w / 2, y: band.y + band.h / 2 };\n const within = (c: number, half: number, max: number): number =>\n Math.min(Math.max(c, half), Math.max(half, max - half));\n return {\n center: {\n x: within(shows.x, width / 2, maxWidth),\n y: maxHeight === undefined ? shows.y : within(shows.y, height / 2, maxHeight),\n },\n shows,\n width,\n height,\n factor: fit,\n };\n}\n","import { normalizeZoom } from '@weasel-js/core';\nimport { type LoupePoint, type LoupeRect, loupeSourcePoint } from './geometry';\n\n/** How a loupe magnifies. `'vector'` re-renders the source through a zoomed-in\n * view, so content stays sharp at any factor; `'pixel'` blows up the actual\n * pixels the surface presented. */\nexport type LoupeMode = 'vector' | 'pixel';\n\n/**\n * What a loupe needs from the surface it magnifies. A painter implements it,\n * and the model asks nothing about how the lens is drawn — only where it is,\n * what colour is under a point, and whether anyone can still see it.\n */\nexport interface LoupeSurface {\n /**\n * The lens' rectangle, or `null` while it has none. A lens placed somewhere\n * other than centered on the aim also says what it shows: `shows` is the\n * surface point at its middle, and `factor` the magnification it shows it at.\n * Either one omitted is the aim, or the model's own factor.\n */\n lens(): (LoupeRect & { shows?: LoupePoint; factor?: number }) | null;\n /**\n * Does the lens itself cover this point? A stationary lens does over its own\n * frame, which is what the freeze rule below is for; a lens that follows the\n * pointer never covers it and answers `false`.\n */\n covers(p: LoupePoint): boolean;\n /** Hex colour at a surface point, or `null` when the surface cannot say. */\n sample(p: LoupePoint): string | null;\n /** Is the lens off screen? Aims are ignored while it is. */\n hidden(): boolean;\n /** Is the lens gone for good? The model tears itself down when it is. */\n gone(): boolean;\n /** Something the painter must redraw for has changed. */\n changed(): void;\n /**\n * Run `fn` after each frame the surface lands; returns an unsubscribe.\n * Implement it when `sample` reads pixels that only show an aim once a\n * frame has painted — a framebuffer read back. The model then samples the\n * aim on the next landed frame, so `color` settles a frame after the aim.\n * Omit it when `sample` can answer for a fresh aim right away.\n */\n subscribeFrame?(fn: () => void): () => void;\n}\n\n/** Options for {@link createLoupeModel}. */\nexport interface LoupeModelOptions {\n surface: LoupeSurface;\n mode?: LoupeMode;\n /** Magnification. Default 8. Always positive and finite: a factor that is\n * not becomes `ZOOM_FLOOR`, the same rule a view's zoom follows. */\n factor?: number;\n /** Bounds `setFactor` clamps to. Unset means bounded only by that rule. */\n minFactor?: number;\n maxFactor?: number;\n /** Called with the hex colour under the aim point whenever it changes. */\n onColorChange?: (hex: string) => void;\n /** Called when a pick lands — an eyedropper on the magnified surface. Where\n * the colour goes is the consumer's business. */\n onPick?: (hex: string) => void;\n /** Called when the model tears itself down because the surface reported the\n * lens gone, so the painter can drop what it was holding. */\n onDispose?: () => void;\n}\n\n/** Where a loupe is aimed, how far it magnifies, and what colour it is over. */\nexport interface LoupeModel {\n readonly mode: LoupeMode;\n readonly factor: number;\n /** Last aimed point, in the surface's CSS px. */\n readonly aim: LoupePoint;\n /** Hex colour under the aim point. `null` until something answers. */\n readonly color: string | null;\n setMode(mode: LoupeMode): void;\n setFactor(factor: number): void;\n /** Aim at a surface point. Ignored while the lens covers it, is hidden, or\n * the model is disposed. */\n aimAt(p: LoupePoint): void;\n /** Sample what the lens shows at `p`, a point inside it, and report that to\n * `onPick`. Omit `p` to pick at the aim point. Leaves the aim, and `color`,\n * alone. */\n pick(p?: LoupePoint): string | null;\n /** Sample the aim again, now: the pixels under it changed without it moving.\n * Reports through `onColorChange` like an aim does. Ignored while hidden. */\n resample(): void;\n dispose(): void;\n}\n\n/**\n * Build the loupe's model over a surface. It holds the state a magnifier has —\n * aim, factor, mode, colour — and none of the drawing.\n */\nexport function createLoupeModel(opts: LoupeModelOptions): LoupeModel {\n const { surface } = opts;\n let mode: LoupeMode = opts.mode ?? 'vector';\n let factor = normalizeZoom(opts.factor ?? 8);\n let aim: LoupePoint = { x: 0, y: 0 };\n let color: string | null = null;\n let disposed = false;\n let aimUnsampled = false;\n\n const clamp = (n: number): number =>\n normalizeZoom(Math.min(opts.maxFactor ?? Number.POSITIVE_INFINITY,\n Math.max(opts.minFactor ?? Number.NEGATIVE_INFINITY, n)));\n\n const sampleColor = () => {\n const hex = surface.sample(aim);\n if (hex === null || hex === color) return;\n color = hex;\n opts.onColorChange?.(hex);\n };\n\n const unsubscribeFrame = surface.subscribeFrame?.(() => {\n if (!aimUnsampled) return;\n aimUnsampled = false;\n sampleColor();\n });\n\n const teardown = () => {\n if (disposed) return;\n disposed = true;\n unsubscribeFrame?.();\n opts.onDispose?.();\n };\n\n return {\n get mode() { return mode; },\n get factor() { return factor; },\n get aim() { return aim; },\n get color() { return color; },\n\n setMode(next) {\n if (disposed || next === mode) return;\n mode = next;\n surface.changed();\n },\n\n setFactor(next) {\n if (disposed) return;\n factor = clamp(next);\n surface.changed();\n },\n\n aimAt(p) {\n if (disposed) return;\n // A lens can be taken away by whatever owns it, without coming back\n // through `dispose`. Follow it down rather than keep sampling for a\n // magnifier nobody can see.\n if (surface.gone()) { teardown(); return; }\n if (surface.hidden()) return;\n if (surface.covers(p)) return;\n aim = p;\n if (unsubscribeFrame) aimUnsampled = true;\n else sampleColor();\n surface.changed();\n },\n\n pick(p) {\n if (disposed) return null;\n let at = aim;\n if (p) {\n const rect = surface.lens();\n if (!rect) return null;\n at = loupeSourcePoint(p, rect, rect.shows ?? aim, rect.factor ?? factor);\n // The lens is part of the picture the surface presents. A point near\n // its frame maps back underneath it, and sampling there reports the\n // lens' own chrome as artwork.\n if (surface.covers(at)) return null;\n }\n const hex = surface.sample(at);\n if (hex !== null) opts.onPick?.(hex);\n return hex;\n },\n\n resample() {\n if (disposed || surface.hidden()) return;\n aimUnsampled = false;\n sampleColor();\n },\n\n dispose: teardown,\n };\n}\n","import { type LoupePoint, type LoupeSize, loupeExtent } from './geometry';\n\n/** A canvas whose pixels a loupe can read. */\nexport type SourceCanvas = HTMLCanvasElement | OffscreenCanvas;\n\n/** A rendering context on a {@link SourceCanvas}. Passing one, rather than the\n * bare canvas, is what tells a source whether the canvas keeps its pixels. */\nexport type SourceContext =\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | WebGLRenderingContext\n | WebGL2RenderingContext\n | ImageBitmapRenderingContext;\n\n/** Where a source canvas's pixels sit on the surface being magnified, in that\n * surface's CSS px. The backing store is stretched over this box, so its\n * width against the canvas's own `width` is the device-pixel ratio. */\nexport interface SourceBox {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Options for {@link createCanvasSource}. */\nexport interface CanvasSourceOptions {\n /**\n * Called when a reader starts and there is no current frame to read: draw\n * the canvas again, and call `capture()` after it. Only needed by a canvas\n * that is captured and does not redraw every frame on its own — without it\n * such a lens stays empty until the next redraw.\n */\n requestRedraw?: () => void;\n /** Where the canvas sits on the magnified surface. Omitted, a reader works\n * it out — a painter over the DOM measures the canvas's own box. */\n box?: () => SourceBox | null;\n}\n\n/**\n * Any canvas, as something a loupe reads pixels from: 2D, WebGL or WebGL2,\n * on the page or offscreen, owned by whoever drew it.\n *\n * A WebGL canvas made without `preserveDrawingBuffer` is cleared once the\n * browser composites it, so reading it from any later task — the lens's own\n * frame — returns nothing. Such a source is *captured*: whoever draws the\n * canvas calls {@link capture} right after drawing, in the same task, and the\n * source copies the frame while it still exists. Every other canvas holds its\n * pixels and is read directly.\n */\nexport interface CanvasSource {\n readonly canvas: SourceCanvas;\n /**\n * Whether frames reach readers only through {@link capture}. True for a\n * source made from a WebGL context without `preserveDrawingBuffer`, and for\n * any source once `capture()` has been called on it.\n */\n readonly captured: boolean;\n readonly box?: () => SourceBox | null;\n /**\n * Copy the frame just drawn. Call it in the same task as the draw — right\n * after `gl.drawArrays`, `renderer.render(...)` or whatever finished the\n * frame. Free while nothing is reading: it copies only while a reader holds\n * the source.\n */\n capture(): void;\n /** The pixels to read now: the last capture, or the canvas itself when it\n * keeps its own. `null` while a captured source has no current frame. */\n frame(): CanvasImageSource | null;\n /** Hex color of the backing-store pixel at `p` (device px, not CSS px), or\n * `null` where it is transparent, off the canvas, or there is no frame. */\n sample(p: LoupePoint): string | null;\n /** Start reading. While any reader holds the source, `capture` copies;\n * returns the release. */\n retain(): () => void;\n /** Run `fn` after each capture lands; returns an unsubscribe. */\n subscribeFrame(fn: () => void): () => void;\n}\n\n/** A frame read this many times with no capture behind it means the drawing\n * code is not calling `capture()`. About two seconds of lens frames. */\nconst MISSED_FRAMES_BEFORE_WARNING = 120;\n\nfunction isWebGL(ctx: SourceContext): ctx is WebGLRenderingContext | WebGL2RenderingContext {\n return 'drawArrays' in ctx;\n}\n\nfunction isContext(target: SourceCanvas | SourceContext): target is SourceContext {\n return 'canvas' in target && !('getContext' in target);\n}\n\nfunction makeCanvas(width: number, height: number): SourceCanvas {\n if (typeof OffscreenCanvas !== 'undefined') return new OffscreenCanvas(width, height);\n const c = document.createElement('canvas');\n c.width = width;\n c.height = height;\n return c;\n}\n\ntype Ctx2D = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;\n\nfunction context2d(canvas: SourceCanvas, willReadFrequently = false): Ctx2D | null {\n return canvas.getContext('2d', { willReadFrequently }) as Ctx2D | null;\n}\n\n/**\n * Make a {@link CanvasSource} for a canvas, or for a context on one.\n *\n * Pass the context when there is one: a WebGL context without\n * `preserveDrawingBuffer` is then known to need capturing before anything has\n * gone blank. A bare canvas is read directly until `capture()` is first\n * called on it. The source never calls `getContext` on the canvas it reads —\n * on a canvas with no context yet, that would create one with the wrong\n * attributes and leave whoever draws it unable to get theirs.\n */\nexport function createCanvasSource(\n target: SourceCanvas | SourceContext,\n options: CanvasSourceOptions = {},\n): CanvasSource {\n const canvas = (isContext(target) ? target.canvas : target) as SourceCanvas;\n const mustCapture =\n isContext(target) && isWebGL(target) && !target.getContextAttributes()?.preserveDrawingBuffer;\n\n let captured = mustCapture;\n let readers = 0;\n let snapshot: SourceCanvas | null = null;\n let current = false;\n let missed = 0;\n let warned = false;\n let probe: Ctx2D | null = null;\n const listeners = new Set<() => void>();\n\n const source: CanvasSource = {\n canvas,\n get captured() {\n return captured;\n },\n box: options.box,\n\n capture() {\n captured = true;\n if (readers === 0) return;\n const { width, height } = canvas;\n if (width === 0 || height === 0) return;\n if (!snapshot) snapshot = makeCanvas(width, height);\n else if (snapshot.width !== width || snapshot.height !== height) {\n snapshot.width = width;\n snapshot.height = height;\n }\n const ctx = context2d(snapshot);\n if (!ctx) return;\n ctx.globalCompositeOperation = 'copy';\n ctx.drawImage(canvas, 0, 0);\n current = true;\n missed = 0;\n for (const fn of listeners) fn();\n },\n\n frame() {\n if (!captured) return canvas.width > 0 && canvas.height > 0 ? canvas : null;\n if (current && snapshot) return snapshot;\n if (!warned && ++missed >= MISSED_FRAMES_BEFORE_WARNING) {\n warned = true;\n console.warn(\n '[weasel loupe] A WebGL canvas without preserveDrawingBuffer is being read, ' +\n 'and nothing has called capture() on its source. Call source.capture() right ' +\n 'after drawing each frame, or pass requestRedraw if the canvas draws on demand.',\n );\n }\n return null;\n },\n\n sample(p) {\n const frame = source.frame();\n if (!frame) return null;\n const x = Math.floor(p.x);\n const y = Math.floor(p.y);\n if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) return null;\n if (!probe) {\n const c = makeCanvas(1, 1);\n probe = context2d(c, true);\n if (!probe) return null;\n }\n probe.globalCompositeOperation = 'copy';\n probe.drawImage(frame, x, y, 1, 1, 0, 0, 1, 1);\n const [r, g, b, a] = probe.getImageData(0, 0, 1, 1).data;\n if (a === 0) return null;\n return `#${[r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('')}`;\n },\n\n retain() {\n readers++;\n if (readers === 1 && captured) {\n // Whatever was copied before the last reader left may be long stale.\n current = false;\n options.requestRedraw?.();\n }\n let held = true;\n return () => {\n if (!held) return;\n held = false;\n readers--;\n };\n },\n\n subscribeFrame(fn) {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n },\n };\n return source;\n}\n\n/**\n * The rectangle of `source`'s backing store a lens of `size` CSS px\n * magnifying `factor` times about `aim` shows, in device px. `box` is where\n * the canvas sits in the same CSS px as `aim`; the scale between the two is\n * measured per axis, so a canvas stretched unevenly is read correctly too.\n */\nexport function sourceRegion(\n aim: LoupePoint,\n factor: number,\n size: LoupeSize,\n box: SourceBox,\n backing: { width: number; height: number },\n): { sx: number; sy: number; sw: number; sh: number } {\n const { width, height } = loupeExtent(size);\n const spanX = width / factor;\n const spanY = height / factor;\n const kx = box.width > 0 ? backing.width / box.width : 1;\n const ky = box.height > 0 ? backing.height / box.height : 1;\n return {\n sx: (aim.x - spanX / 2 - box.x) * kx,\n sy: (aim.y - spanY / 2 - box.y) * ky,\n sw: spanX * kx,\n sh: spanY * ky,\n };\n}\n\n/** A surface point in CSS px, as the backing-store pixel of a canvas laid\n * over `box` that it lands on. */\nexport function sourcePixel(\n p: LoupePoint,\n box: SourceBox,\n backing: { width: number; height: number },\n): LoupePoint {\n const kx = box.width > 0 ? backing.width / box.width : 1;\n const ky = box.height > 0 ? backing.height / box.height : 1;\n return { x: (p.x - box.x) * kx, y: (p.y - box.y) * ky };\n}\n","import { type LoupePoint, type LoupeSize, loupeExtent } from '@weasel-js/loupe';\nimport { centerOn } from '../canvas/camera';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport type { CanvasLayerDescriptor } from '../canvas/useLayerScheduler';\nimport { DEFAULT_FRAME, resolveFrame, type WorldFrame, type WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\n\n/** The camera a lens of `size` shows a magnified region through, and\n * the coordinate system it is read in — the instrument's own `WorldSpec`,\n * resolved against the lens rather than the stack. */\nexport interface LensCamera {\n view: ViewTransform;\n frame: WorldFrame;\n}\n\n/**\n * What a lens aimed at `aim` renders the stack's layers through.\n *\n * The lens is its own viewport, so the world spec resolves against its box: an\n * instrument centred on its viewport is centred in the lens too.\n */\nexport function lensCamera(\n aim: LoupePoint,\n outer: ViewTransform,\n outerFrame: WorldFrame,\n factor: number,\n size: LoupeSize,\n worldSpec?: WorldSpec,\n): LensCamera {\n const extent = loupeExtent(size);\n const frame = resolveFrame(worldSpec, extent);\n const world = screenToWorld(aim, outer, outerFrame);\n return { view: centerOn(world, outer.zoom * factor, extent, frame), frame };\n}\n\n/** A rectangle in a backing store's own device pixels. */\nexport interface SourceRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n}\n\n/**\n * The region a pixel-mode lens copies out of a presented canvas: `size /\n * factor` CSS px around `aim`, in that canvas' backing-store pixels.\n */\nexport function lensSourceRect(\n aim: LoupePoint,\n factor: number,\n size: LoupeSize,\n dpr: number,\n): SourceRect {\n const { width, height } = loupeExtent(size);\n const spanX = width / factor;\n const spanY = height / factor;\n return {\n sx: (aim.x - spanX / 2) * dpr,\n sy: (aim.y - spanY / 2) * dpr,\n sw: spanX * dpr,\n sh: spanY * dpr,\n };\n}\n\n/**\n * The color a stack presents at a point: the topmost visible layer with\n * anything opaque there, or `null` when every layer is transparent — which is\n * the honest answer for a point showing nothing but the workspace behind.\n */\nexport function sampleStack(\n layers: readonly CanvasLayerDescriptor[],\n canvases: Map<string, HTMLCanvasElement>,\n p: LoupePoint,\n dpr: number,\n): string | null {\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i];\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) continue;\n const x = Math.floor(p.x * dpr);\n const y = Math.floor(p.y * dpr);\n if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) continue;\n const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;\n if (a === 0) continue;\n return `#${[r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('')}`;\n }\n return null;\n}\n\n/** Redraw the stack into a lens' own canvas. `mode` decides whether the layers\n * are re-run at the lens camera or their presented pixels are enlarged. */\nexport function drawCanvasLens(\n ctx: CanvasRenderingContext2D,\n opts: {\n aim: LoupePoint;\n factor: number;\n diameter: LoupeSize;\n dpr: number;\n mode: 'vector' | 'pixel';\n outer: ViewTransform;\n outerFrame?: WorldFrame;\n worldSpec?: WorldSpec;\n layers: readonly CanvasLayerDescriptor[];\n canvases: Map<string, HTMLCanvasElement>;\n },\n): void {\n const { aim, factor, diameter, dpr, mode, outer, layers, canvases } = opts;\n const { width, height } = loupeExtent(diameter);\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, width, height);\n\n if (mode === 'pixel') {\n const { sx, sy, sw, sh } = lensSourceRect(aim, factor, diameter, dpr);\n ctx.imageSmoothingEnabled = false;\n for (const layer of layers) {\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas || canvas.width === 0 || canvas.height === 0) continue;\n ctx.drawImage(canvas, sx, sy, sw, sh, 0, 0, width, height);\n }\n ctx.restore();\n return;\n }\n\n const lens = lensCamera(\n aim,\n outer,\n opts.outerFrame ?? DEFAULT_FRAME,\n factor,\n diameter,\n opts.worldSpec,\n );\n for (const layer of layers) {\n if (!layer.visible) continue;\n ctx.save();\n layer.render(ctx, lens.view, lens.frame);\n ctx.restore();\n }\n ctx.restore();\n}\n","import { useLatest, useVisibleRaf } from '@weasel-js/core';\nimport { type LoupeMode, type LoupePoint, type LoupeSize, loupeExtent } from '@weasel-js/loupe';\nimport { useEffect, useRef } from 'react';\nimport type { CanvasStackSurface } from '../canvas/CanvasStackContext';\nimport type { WorldFrame, WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport { drawCanvasLens } from './canvasLens';\n\n/** Props for `<CanvasLoupe>`. */\nexport interface CanvasLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n /** One number for a round or square lens, or a width and a height. */\n diameter: LoupeSize;\n /** The stack being magnified: its layers, its pixels, and its measured box. */\n surface: CanvasStackSurface;\n view: ViewTransform;\n frame: WorldFrame;\n worldSpec?: WorldSpec;\n}\n\n/**\n * Paints a lens over a `<CanvasStack>` by re-drawing the stack's layers through\n * a zoomed camera — so the magnified content is as sharp as the original, at\n * any factor. `pixel` mode enlarges what the stack presented instead.\n */\nexport function CanvasLoupe({\n aim,\n factor,\n mode,\n diameter,\n surface,\n view,\n frame,\n worldSpec,\n}: CanvasLoupeProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const dpr = surface.size.dpr;\n\n // Whatever the stack redraws every frame, the lens has to redraw too — an\n // instrument that animates from its own loop never re-renders this component.\n const args = { aim, factor, mode, diameter, dpr, view, frame, worldSpec, surface };\n const argsRef = useLatest(args);\n\n const loop = useVisibleRaf(\n () => {\n loop.request();\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext('2d');\n const canvases = argsRef.current.surface.canvases.current;\n if (!ctx || !canvases) return;\n const a = argsRef.current;\n drawCanvasLens(ctx, {\n aim: a.aim,\n factor: a.factor,\n diameter: a.diameter,\n dpr: a.dpr,\n mode: a.mode,\n outer: a.view,\n outerFrame: a.frame,\n worldSpec: a.worldSpec,\n layers: a.surface.layers,\n canvases,\n });\n },\n { target: canvasRef },\n );\n\n useEffect(() => {\n loop.request();\n return () => loop.cancel();\n }, [loop]);\n\n return (\n <canvas\n ref={canvasRef}\n className=\"lk-loupe__canvas\"\n width={Math.max(1, Math.round(loupeExtent(diameter).width * dpr))}\n height={Math.max(1, Math.round(loupeExtent(diameter).height * dpr))}\n />\n );\n}\n","import { type LoupeMode, type LoupePoint, type LoupeSize, loupeExtent } from '@weasel-js/loupe';\nimport type { CSSProperties } from 'react';\nimport { zoomAt } from '../canvas/camera';\nimport type { ViewportSize, WorldFrame } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport type { LoupeRenderArgs } from './types';\n\n/** Props for `<DomLoupe>`. */\nexport interface DomLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n /** One number for a round or square lens, or a width and a height. */\n diameter: LoupeSize;\n /** The host the instrument draws into, which the stage reproduces. */\n size: ViewportSize;\n /** The trial's own camera. */\n view: ViewTransform;\n frame?: WorldFrame;\n render: (args: LoupeRenderArgs) => React.ReactNode;\n}\n\n/**\n * Paints a lens over DOM content by asking its `render` to draw it again\n * at a magnified camera.\n *\n * The stage is a full copy of the host, so the instrument's own layout still\n * holds; the camera is composed about the aimed point, which keeps that point\n * where it already was, and the stage is then slid by half the lens less `aim`\n * to bring it to the middle of the lens.\n */\nexport function DomLoupe({\n aim,\n factor,\n mode,\n diameter,\n size,\n view,\n frame,\n render,\n}: DomLoupeProps) {\n const { width, height } = loupeExtent(diameter);\n const style: CSSProperties = {\n width: `${size.width}px`,\n height: `${size.height}px`,\n transform: `translate(${width / 2 - aim.x}px, ${height / 2 - aim.y}px)`,\n };\n return (\n <div className=\"lk-loupe__stage\" style={style}>\n {render({\n view: zoomAt(view, factor, aim, { frame }),\n factor,\n mode,\n size,\n })}\n </div>\n );\n}\n","import { type LoupePoint, type LoupeSize, loupeExtent } from '@weasel-js/loupe';\nimport type { CSSProperties, ReactNode, RefObject } from 'react';\nimport type { LoupeShape } from './types';\n\n/** Props for `<LoupeBubble>`. */\nexport interface LoupeBubbleProps {\n /** Where the lens is centered, in its container's own pixels. */\n aim: LoupePoint;\n /** One number for a round or square lens, or a width and a height. */\n diameter: LoupeSize;\n /** Default `'circle'`; on a box that is not square, `'circle'` is an ellipse. */\n shape?: LoupeShape;\n /** Only the ring and shadow: the inside is left clear for what is under it. */\n hollow?: boolean;\n hostRef?: RefObject<HTMLDivElement | null>;\n children?: ReactNode;\n}\n\n/**\n * The lens itself: a circle or a rectangle centered on `aim`, clipping whatever\n * a painter draws into it.\n *\n * It takes no pointer events, so the pan, the wheel and anything underneath\n * keep working while it is up — and it is `aria-hidden`, since it magnifies\n * content already on the page rather than adding any.\n */\nexport function LoupeBubble({\n aim,\n diameter,\n shape = 'circle',\n hollow,\n hostRef,\n children,\n}: LoupeBubbleProps) {\n const { width, height } = loupeExtent(diameter);\n const square = shape === 'square';\n const style = {\n '--lk-loupe-width': `${width}px`,\n '--lk-loupe-height': `${height}px`,\n transform: `translate(${aim.x - width / 2}px, ${aim.y - height / 2}px)`,\n } as CSSProperties;\n return (\n <div\n ref={hostRef}\n className={['lk-loupe', square && 'lk-loupe--square', hollow && 'lk-loupe--hollow']\n .filter(Boolean)\n .join(' ')}\n style={style}\n aria-hidden=\"true\"\n >\n {children}\n </div>\n );\n}\n","/**\n * The loupe's two bindable interactions, as `Action` descriptors the gesture\n * dispatcher routes: hold a key to peek, and walk the magnification with the\n * wheel.\n *\n * Free of React so the routing can be tested without a DOM.\n */\nimport type { Action } from '@weasel-js/core';\n\n/** Canonical id of the hold-to-peek action. */\nexport const LOUPE_PEEK_ID = 'loupe.peek';\n/** Canonical id of the wheel-magnify action. */\nexport const LOUPE_MAGNIFY_ID = 'loupe.magnify';\n\n/** How fast the wheel walks the magnification. Gentler than the pan-zoom\n * wheel: the lens' whole range is one order of magnitude. */\nexport const WHEEL_RATE = 0.002;\n\n/** What the actions do to a live loupe. Every member is read through the\n * object on each invocation, so one stable instance serves the life of the\n * registration. */\nexport interface LoupeInputApi {\n /** Whether the lens is up. The wheel belongs to the loupe only while it is;\n * otherwise `loupe.magnify` declines and the dispatcher falls through to\n * the trial camera's zoom. */\n shown: () => boolean;\n /** Raise or drop the hold-to-peek flag. */\n setPeeking: (on: boolean) => void;\n /** Multiply the magnification by one wheel notch of `deltaY`. */\n magnifyBy: (deltaY: number) => void;\n}\n\n/**\n * Build the loupe's actions. `peekKey` is a `KeyboardEvent.key`; passing\n * `null` omits `loupe.peek` entirely rather than registering a binding no key\n * can match.\n */\nexport function createLoupeActions(\n input: LoupeInputApi,\n peekKey: string | null,\n): readonly Action[] {\n const magnify: Action = {\n id: LOUPE_MAGNIFY_ID,\n label: 'Magnify (loupe)',\n group: 'loupe',\n // Hotkey scope, so while the lens is up it outranks the trial camera's\n // wheel zoom on the same dispatcher; while it is down `enabled` declines\n // and the zoom runs.\n scope: 'hotkey',\n // Every modifier optional: the lens claims the wheel whenever it is up,\n // which is what the hand-rolled capture-phase listener did. A bare spec\n // would forbid modifiers and hand Cmd+wheel back to the lab mid-peek.\n defaultBinding: [\n {\n spec: {\n kind: 'wheel',\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n enabled: () => (input.shown() ? true : 'not-applicable'),\n invoker: {\n timing: 'immediate',\n run(_deps, params) {\n input.magnifyBy((params?.deltaY as number | undefined) ?? 0);\n },\n },\n };\n\n if (peekKey === null) return [magnify];\n\n const peek: Action = {\n id: LOUPE_PEEK_ID,\n label: 'Peek (loupe)',\n group: 'loupe',\n // Hotkey scope: peeking must beat whatever the lab's active tool binds to\n // the same key, the way every other held-key trigger does.\n scope: 'hotkey',\n // Every modifier optional because the peek key may BE one: the keydown\n // that carries `Alt` — the default — also reports `altKey: true`, and the\n // matcher forbids any modifier a spec does not name.\n defaultBinding: [\n {\n spec: {\n kind: 'key-held',\n key: peekKey,\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n invoker: {\n timing: 'ongoing',\n start() {\n input.setPeeking(true);\n return { onEnd: () => input.setPeeking(false) };\n },\n },\n };\n return [peek, magnify];\n}\n","/**\n * Registers the loupe's actions, and mounts the gesture dispatcher on the\n * loupe's host when no camera already has one there, so the peek key and the\n * wheel route the way every other weasel binding does.\n *\n * Three of the dispatcher's four element channels are off. Only `wheel` is\n * wanted here; `contextMenu` suppresses the native menu unconditionally and\n * `ingest` makes the host a file-drop target, neither of which a lab asked\n * for by turning a magnifier on.\n */\nimport {\n type ActionsRegistry,\n type Tool,\n useActionsRegistry,\n useGestureDispatcher,\n} from '@weasel-js/core';\nimport { type RefObject, useContext, useEffect, useMemo } from 'react';\nimport { CameraContext } from '../canvas/CameraInput';\nimport { createLoupeActions, type LoupeInputApi } from './loupeActions';\n\n/** Props for `<LoupeGestures>`. */\nexport interface LoupeGesturesProps {\n /** The element the dispatcher listens on — the same one the lens tracks. */\n hostRef: RefObject<HTMLElement | null>;\n input: LoupeInputApi;\n /** `KeyboardEvent.key` for hold-to-peek, or `null` for no peek binding. */\n peekKey: string | null;\n}\n\nconst NO_TOOLS: ReadonlyMap<string, Tool> = new Map();\n\nconst CHANNELS = { pointer: false, contextMenu: false, ingest: false } as const;\n\nfunction LoupeDispatch({\n hostRef,\n input,\n peekKey,\n registry,\n ownDispatcher,\n}: LoupeGesturesProps & { registry: ActionsRegistry; ownDispatcher: boolean }) {\n const actions = useMemo(() => createLoupeActions(input, peekKey), [input, peekKey]);\n\n useEffect(() => {\n const offs = actions.map((a) => registry.register(a));\n return () => {\n for (const off of offs) off();\n };\n }, [registry, actions]);\n\n useGestureDispatcher({\n canvasRef: hostRef,\n actions: registry,\n entriesById: NO_TOOLS,\n channels: CHANNELS,\n enabled: ownDispatcher,\n });\n\n return null;\n}\n\n/**\n * The loupe's input, routed. Inside a camera (`<CanvasStack>`, `<Stage>`) its\n * actions join the camera's dispatcher, which already listens on the host;\n * elsewhere it mounts a dispatcher of its own. With no registry in scope it\n * renders nothing rather than registering actions that could never fire.\n */\nexport function LoupeGestures(props: LoupeGesturesProps) {\n const registry = useActionsRegistry();\n const camera = useContext(CameraContext);\n if (!registry) return null;\n return <LoupeDispatch {...props} registry={registry} ownDispatcher={camera === null} />;\n}\n","import {\n type CanvasSource,\n createCanvasSource,\n type LoupePoint,\n type LoupeSize,\n loupeExtent,\n type SourceBox,\n type SourceCanvas,\n type SourceContext,\n sourcePixel,\n sourceRegion,\n} from '@weasel-js/loupe';\n\n/** Anything a lens can be pointed at for its pixels: a `CanvasSource`, a\n * canvas, a context on one, or a function returning any of those once it\n * exists. */\nexport type LoupeSourceTarget = CanvasSource | SourceCanvas | SourceContext;\nexport type LoupeSource = LoupeSourceTarget | (() => LoupeSourceTarget | null | undefined);\n\nfunction isCanvasSource(t: LoupeSourceTarget): t is CanvasSource {\n return 'capture' in t && 'retain' in t;\n}\n\n// One source per canvas or context, so a getter returning the same canvas\n// every frame keeps one snapshot rather than minting a new one per call.\nconst made = new WeakMap<object, CanvasSource>();\n\n/** `source` as a `CanvasSource`, or `null` while a getter has nothing yet. */\nexport function resolveLoupeSource(source: LoupeSource | undefined): CanvasSource | null {\n if (!source) return null;\n const target = typeof source === 'function' ? source() : source;\n if (!target) return null;\n if (isCanvasSource(target)) return target;\n let s = made.get(target);\n if (!s) {\n s = createCanvasSource(target);\n made.set(target, s);\n }\n return s;\n}\n\n/**\n * Where a source canvas sits over the lens's host, in the host's CSS px: its\n * own `box` if it has one, else the canvas's laid-out box measured against the\n * host, else — for an offscreen canvas, or one not on the page — the whole\n * host.\n */\nexport function sourceBoxIn(source: CanvasSource, host: HTMLElement | null): SourceBox {\n const own = source.box?.();\n if (own) return own;\n const hostRect = host?.getBoundingClientRect();\n const c = source.canvas;\n if (typeof HTMLCanvasElement !== 'undefined' && c instanceof HTMLCanvasElement && c.isConnected) {\n const r = c.getBoundingClientRect();\n if (r.width > 0 && r.height > 0) {\n return {\n x: r.left - (hostRect?.left ?? 0),\n y: r.top - (hostRect?.top ?? 0),\n width: r.width,\n height: r.height,\n };\n }\n }\n return { x: 0, y: 0, width: hostRect?.width ?? c.width, height: hostRect?.height ?? c.height };\n}\n\n/** The color a source shows at a host point, or `null` where it shows none. */\nexport function sampleSource(source: CanvasSource, p: LoupePoint, box: SourceBox): string | null {\n return source.sample(sourcePixel(p, box, source.canvas));\n}\n\n/** Enlarge the pixels of `source` around `aim` into a lens' own canvas, with\n * smoothing off. Leaves the lens clear while the source has no frame. */\nexport function drawSourceLens(\n ctx: CanvasRenderingContext2D,\n opts: {\n aim: LoupePoint;\n factor: number;\n diameter: LoupeSize;\n dpr: number;\n source: CanvasSource;\n box: SourceBox;\n },\n): void {\n const { aim, factor, diameter, dpr, source, box } = opts;\n const { width, height } = loupeExtent(diameter);\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, width, height);\n const frame = source.frame();\n if (frame) {\n const { sx, sy, sw, sh } = sourceRegion(aim, factor, diameter, box, source.canvas);\n ctx.imageSmoothingEnabled = false;\n ctx.drawImage(frame, sx, sy, sw, sh, 0, 0, width, height);\n }\n ctx.restore();\n}\n","import { useLatest, useVisibleRaf } from '@weasel-js/core';\nimport { type LoupePoint, type LoupeSize, loupeExtent } from '@weasel-js/loupe';\nimport { type RefObject, useEffect, useRef } from 'react';\nimport { drawSourceLens, type LoupeSource, resolveLoupeSource, sourceBoxIn } from './sourceLens';\n\n/** Props for `<SourceLoupe>`. */\nexport interface SourceLoupeProps {\n aim: LoupePoint;\n factor: number;\n /** One number for a round or square lens, or a width and a height. */\n diameter: LoupeSize;\n /** The canvas whose pixels the lens enlarges. */\n source: LoupeSource;\n /** The element `aim` is measured in, which the source's box is found against. */\n hostRef: RefObject<HTMLElement | null>;\n}\n\n/**\n * Paints a pixel lens from any canvas — one labkit drew or one it has never\n * seen, 2D or WebGL. It redraws every frame, since the canvas it reads moves\n * on its own schedule.\n */\nexport function SourceLoupe({ aim, factor, diameter, source, hostRef }: SourceLoupeProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const dpr = typeof window === 'undefined' ? 1 : window.devicePixelRatio || 1;\n const argsRef = useLatest({ aim, factor, diameter, dpr, source });\n\n const loop = useVisibleRaf(\n () => {\n loop.request();\n const ctx = canvasRef.current?.getContext('2d');\n const a = argsRef.current;\n const src = resolveLoupeSource(a.source);\n if (!ctx || !src) return;\n drawSourceLens(ctx, {\n aim: a.aim,\n factor: a.factor,\n diameter: a.diameter,\n dpr: a.dpr,\n source: src,\n box: sourceBoxIn(src, hostRef.current),\n });\n },\n { target: canvasRef },\n );\n\n useEffect(() => {\n loop.request();\n return () => loop.cancel();\n }, [loop]);\n\n return (\n <canvas\n ref={canvasRef}\n className=\"lk-loupe__canvas\"\n width={Math.max(1, Math.round(loupeExtent(diameter).width * dpr))}\n height={Math.max(1, Math.round(loupeExtent(diameter).height * dpr))}\n />\n );\n}\n","import type { LoupeMode, LoupePoint } from '@weasel-js/loupe';\nimport type { ReactNode } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport type { LoupeSource } from './sourceLens';\n\n/** What a DOM loupe's `render` is handed: the camera to draw the content\n * through again. */\nexport interface LoupeRenderArgs {\n /** The trial's own camera composed with the magnification, about the aimed\n * point — so drawing the same content through it magnifies in place. */\n view: ViewTransform;\n /** The magnification on its own, for whatever must not scale with the\n * camera. */\n factor: number;\n mode: LoupeMode;\n /** The size of the viewport `view` is written for: the trial's content well,\n * not the lens. The lens shows a circle cut out of it. */\n size: ViewportSize;\n}\n\n/** The outline of a lens. On a box that is not square, `'circle'` is an ellipse. */\nexport type LoupeShape = 'circle' | 'square';\n\n/** Where a host puts the lens for one aim, in the host's own CSS px. */\nexport interface LoupePlacement {\n /** Where the lens is drawn: the middle of its box. */\n center: LoupePoint;\n /** The host point the lens shows at its middle. Omitted, `center`; it\n * differs when a lens is moved to stay on the host but keeps showing what\n * it was placed over. */\n shows?: LoupePoint;\n width: number;\n height: number;\n /** The magnification for this placement. Omitted, the wheel's. */\n factor?: number;\n}\n\n/** Where a lens is drawn and what it shows, once `place` has had its say. */\nexport interface LoupeLens {\n /** Where the lens is drawn: the middle of its box. */\n center: LoupePoint;\n /** The host point the lens shows at its middle. */\n shows: LoupePoint;\n width: number;\n height: number;\n /** What it magnifies by: the wheel's, unless `place` chose another. */\n factor: number;\n shape: LoupeShape;\n}\n\n/** What `place` is asked with. */\nexport interface LoupePlaceArgs {\n aim: LoupePoint;\n factor: number;\n}\n\n/**\n * How a lens magnifies.\n *\n * With no `render`, the lens re-draws the canvas stack's layers through a\n * zoomed camera, so it stays sharp at any factor. Over DOM content, `render`\n * draws it instead: given a camera, draw me again. With a `source`, it\n * enlarges the pixels of that canvas — any canvas, labkit's or not.\n */\nexport interface LoupeOptions {\n render?: (args: LoupeRenderArgs) => ReactNode;\n /**\n * A canvas to read pixels from instead of the canvas stack: a\n * `CanvasSource` from `createCanvasSource`, a canvas, a context on one, or\n * a function returning one once it exists. 2D, WebGL and WebGL2 all work.\n * Without `render` the lens enlarges its pixels, so the mode is `'pixel'`;\n * with `render`, `render` draws the lens and the source answers\n * `onColorChange`.\n *\n * A WebGL canvas made without `preserveDrawingBuffer` is blank to anyone\n * reading it after the frame that drew it. Make its source with\n * `createCanvasSource(gl)` and call `source.capture()` right after each\n * draw; a canvas that draws on demand also passes `requestRedraw`.\n */\n source?: LoupeSource;\n /** Opening magnification, clamped to the bounds below. Default 6. */\n factor?: number;\n /** What the wheel clamps to. Defaults 2 and 32. */\n minFactor?: number;\n maxFactor?: number;\n /** `'vector'` (default) re-renders the content magnified; `'pixel'` blows up\n * the pixels the instrument presented. A `render` loupe is always vector —\n * DOM has no framebuffer to enlarge — and a `source` loupe always pixel. */\n mode?: LoupeMode;\n /** Lens diameter in CSS px. Default 200. */\n diameter?: number;\n /** Default `'circle'`. */\n shape?: LoupeShape;\n /**\n * Puts the lens somewhere other than a `diameter` box on the aim: the lens is\n * drawn with the returned box centered on `center`, and shows what is around\n * `shows` (or `center`) magnified by the returned `factor`, or by the wheel's when it\n * returns none. `factor` in the argument is always the wheel's, so a host\n * lowering it to fit something in keeps the wheel as the ceiling. Returning\n * `null` keeps the default. It is\n * called while the lens renders, so a host whose content moves under a still\n * pointer re-renders the lens to re-place it. The color under the aim is\n * still the one `onColorChange` reports.\n */\n place?: (at: LoupePlaceArgs) => LoupePlacement | null;\n /**\n * Draw only the lens's outline — ring, shadow, shape — and leave its inside\n * empty, so whatever is under it shows through: for a host that draws the\n * magnified view itself, into the box `onLens` reports. No painter runs; a\n * `source`, if given, still answers `onColorChange`. Under a tiled surface,\n * each move invalidates the tiles under the box it left and the box it now\n * covers, so the host redraws those and no others.\n */\n hollow?: boolean;\n /**\n * Called with where the lens is drawn and what it shows, in host CSS px,\n * whenever that changes — an aim, the wheel, `place`, `shape` — and with\n * `null` when a lens that was up goes away.\n */\n onLens?: (lens: LoupeLens | null) => void;\n /** Held for a momentary peek while the loupe is off. Default `'Alt'`; `null`\n * turns hold-to-peek off. Matched against `KeyboardEvent.key`. */\n peekKey?: string | null;\n /** Called with the color under the aim, wherever the surface can say. The\n * canvas painter and a `source` read it back; a DOM loupe with no `source`\n * has no pixels to sample. */\n onColorChange?: (hex: string) => void;\n}\n\n/** {@link LoupeOptions} with every default filled in. */\nexport interface ResolvedLoupe {\n render?: (args: LoupeRenderArgs) => ReactNode;\n source?: LoupeSource;\n onColorChange?: (hex: string) => void;\n factor: number;\n minFactor: number;\n maxFactor: number;\n mode: LoupeMode;\n diameter: number;\n shape: LoupeShape;\n place?: (at: LoupePlaceArgs) => LoupePlacement | null;\n hollow: boolean;\n onLens?: (lens: LoupeLens | null) => void;\n peekKey: string | null;\n}\n\n/** What `resolveLoupe` fills in for anything a declaration leaves unset. */\nexport const LOUPE_DEFAULTS = {\n factor: 6,\n minFactor: 2,\n maxFactor: 32,\n mode: 'vector',\n diameter: 200,\n shape: 'circle',\n hollow: false,\n peekKey: 'Alt',\n} as const satisfies Omit<\n ResolvedLoupe,\n 'render' | 'source' | 'onColorChange' | 'place' | 'onLens'\n>;\n\n/** `options` with every default filled in and `factor` clamped to\n * `[minFactor, maxFactor]`. A loupe with its own `render` is always `'vector'`,\n * and one with only a `source` always `'pixel'`. */\nexport function resolveLoupe(options: LoupeOptions = {}): ResolvedLoupe {\n const minFactor = options.minFactor ?? LOUPE_DEFAULTS.minFactor;\n const maxFactor = options.maxFactor ?? LOUPE_DEFAULTS.maxFactor;\n return {\n render: options.render,\n source: options.source,\n onColorChange: options.onColorChange,\n minFactor,\n maxFactor,\n factor: Math.min(maxFactor, Math.max(minFactor, options.factor ?? LOUPE_DEFAULTS.factor)),\n diameter: options.diameter ?? LOUPE_DEFAULTS.diameter,\n shape: options.shape ?? LOUPE_DEFAULTS.shape,\n place: options.place,\n hollow: options.hollow ?? LOUPE_DEFAULTS.hollow,\n onLens: options.onLens,\n peekKey: options.peekKey === undefined ? LOUPE_DEFAULTS.peekKey : options.peekKey,\n // A DOM loupe has no framebuffer, so `pixel` would have nothing to enlarge.\n mode: options.render\n ? 'vector'\n : options.source\n ? 'pixel'\n : (options.mode ?? LOUPE_DEFAULTS.mode),\n };\n}\n","import { type RefObject, useEffect, useState } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\n\nconst ZERO: ViewportSize = { width: 0, height: 0 };\n\n/** An element's CSS-pixel box, kept current. `{0, 0}` until it is measured, and\n * wherever `ResizeObserver` is absent. */\nexport function useHostSize(ref: RefObject<HTMLElement | null>): ViewportSize {\n const [size, setSize] = useState<ViewportSize>(ZERO);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const update = (): void => {\n const rect = el.getBoundingClientRect();\n setSize((prev) =>\n prev.width === rect.width && prev.height === rect.height\n ? prev\n : { width: rect.width, height: rect.height },\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 }, [ref]);\n\n return size;\n}\n","import { useLatest } from '@weasel-js/core';\nimport {\n createLoupeModel,\n type LoupeMode,\n type LoupeModel,\n type LoupePoint,\n} from '@weasel-js/loupe';\nimport { type RefObject, useCallback, useEffect, useReducer, useRef } from 'react';\nimport type { LoupeInputApi } from './loupeActions';\nimport { WHEEL_RATE } from './loupeActions';\nimport type { LoupeLens, ResolvedLoupe } from './types';\n\n/** Options for {@link useLoupe}. */\nexport interface UseLoupeOptions {\n options: ResolvedLoupe;\n /** The element the lens tracks the pointer across. */\n hostRef: RefObject<HTMLElement | null>;\n /** Whether the loupe is turned on. Hold-to-peek shows it regardless. */\n enabled: boolean;\n /** Hex color at a host point. Omitted, the loupe reports no color — which\n * is the honest answer for a surface with no pixels to read. */\n sample?: (p: LoupePoint) => string | null;\n /** Run `fn` whenever what `sample` reads changes without the aim moving — a\n * canvas that animates, or a frame that arrives after the aim did; returns\n * an unsubscribe. While the lens is up, each call samples the aim again, on\n * top of the sample every aim takes at once. Omitted, color changes only on\n * an aim. */\n subscribeResample?: (fn: () => void) => () => void;\n}\n\n/** A loupe as a React view reads it. */\nexport interface LoupeState {\n /** Whether the lens should be drawn. */\n visible: boolean;\n /** Where it is aimed, in the host's own pixels. */\n aim: LoupePoint;\n /** The wheel's magnification. What the lens shows at is `lens.factor`. */\n factor: number;\n /** The box the lens is drawn in, and what it shows. */\n lens: LoupeLens;\n mode: LoupeMode;\n color: string | null;\n setMode: (mode: LoupeMode) => void;\n setFactor: (factor: number) => void;\n /** Sample the aim again, for pixels that changed under a still aim. */\n resample: () => void;\n /** Sample what the lens shows at a point inside it. */\n pick: (p?: LoupePoint) => string | null;\n /** What `<LoupeGestures>` drives the lens through. Stable for the life of\n * the hook, so registering the actions on it does not churn. */\n input: LoupeInputApi;\n}\n\n/** Whether the lens is up: the pointer is over the host, and the loupe is on or peeked. */\nfunction lensShown(over: boolean, enabled: boolean, peeking: boolean): boolean {\n return over && (enabled || peeking);\n}\n\n/**\n * Binds `@weasel-js/loupe`'s model to a host element and tracks the pointer\n * across it.\n *\n * The peek key and the wheel are not here: they are `loupe.peek` and\n * `loupe.magnify`, routed through the gesture dispatcher that\n * `<LoupeGestures>` mounts on the same host. Aiming stays a plain listener\n * because a hover is not a gesture the grammar names — `GESTURE_DESCRIPTORS`\n * has no continuous-motion entry, and inventing one to carry the lens' aim\n * would be an input taxonomy change, not a loupe change.\n */\nexport function useLoupe({\n options,\n hostRef,\n enabled,\n sample,\n subscribeResample,\n}: UseLoupeOptions): LoupeState {\n const [, bump] = useReducer((n: number) => n + 1, 0);\n\n const overRef = useRef(false);\n // Where the pointer last was over the host, in client px. The model ignores\n // aims while the lens is down, so this is what the lens opens at.\n const pointerRef = useRef<{ clientX: number; clientY: number } | null>(null);\n const peekingRef = useRef(false);\n const enabledRef = useLatest(enabled);\n const sampleRef = useLatest(sample);\n const onColorChangeRef = useLatest(options.onColorChange);\n\n // Reads nothing but refs, so it is stable and an effect may depend on it.\n const shown = useCallback(\n (): boolean => lensShown(overRef.current, enabledRef.current, peekingRef.current),\n [enabledRef],\n );\n\n const modelRef = useRef<LoupeModel | null>(null);\n if (modelRef.current === null) {\n modelRef.current = createLoupeModel({\n mode: options.mode,\n factor: options.factor,\n minFactor: options.minFactor,\n maxFactor: options.maxFactor,\n onColorChange: (hex) => onColorChangeRef.current?.(hex),\n surface: {\n lens: () => {\n const { center, shows, width, height, factor } = lensRef.current;\n return {\n x: center.x - width / 2,\n y: center.y - height / 2,\n w: width,\n h: height,\n shows,\n factor,\n };\n },\n // The lens follows the pointer and is painted over the host rather than\n // into it, so it is never part of the picture being magnified.\n covers: () => false,\n sample: (p) => sampleRef.current?.(p) ?? null,\n hidden: () => !shown(),\n gone: () => goneRef.current,\n changed: bump,\n },\n });\n }\n const model = modelRef.current;\n\n const goneRef = useRef(false);\n\n // The model holds no resources, and `dispose` is one-way — so unmounting only\n // reports the lens gone. Disposing here instead leaves React's mount / unmount\n // / remount in StrictMode with a permanently dead model that silently ignores\n // every aim.\n useEffect(() => {\n goneRef.current = false;\n return () => {\n goneRef.current = true;\n };\n }, []);\n\n // Aim at the pointer's last spot over the host, for a lens that has just\n // come up under a pointer that has not moved since. Stable, because `input`\n // captures it once.\n const hostRefRef = useLatest(hostRef);\n const aimAtPointer = useCallback((): void => {\n const host = hostRefRef.current.current;\n const p = pointerRef.current;\n if (!host || !p) return;\n const rect = host.getBoundingClientRect();\n modelRef.current?.aimAt({ x: p.clientX - rect.left, y: p.clientY - rect.top });\n }, [hostRefRef]);\n\n // Turning the loupe off with the pointer still inside must put the lens away,\n // and the model only reconsiders on an aim; turning it on must open the lens\n // where the pointer already is.\n useEffect(() => {\n if (enabled) aimAtPointer();\n else if (!peekingRef.current) bump();\n }, [enabled, aimAtPointer]);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const onPointerMove = (e: PointerEvent): void => {\n overRef.current = true;\n pointerRef.current = { clientX: e.clientX, clientY: e.clientY };\n const rect = host.getBoundingClientRect();\n model.aimAt({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n if (!shown()) return;\n bump();\n };\n const onPointerLeave = (): void => {\n overRef.current = false;\n pointerRef.current = null;\n bump();\n };\n\n host.addEventListener('pointermove', onPointerMove);\n host.addEventListener('pointerleave', onPointerLeave);\n return () => {\n host.removeEventListener('pointermove', onPointerMove);\n host.removeEventListener('pointerleave', onPointerLeave);\n };\n }, [hostRef, model, shown]);\n\n // Subscribed while the lens is up, and before any effect the caller declares\n // after this hook runs — so a frame its own effect provokes is not missed.\n // This render's `enabled`: `enabledRef` holds the last committed one.\n const visible = lensShown(overRef.current, enabled, peekingRef.current);\n\n // Asked only while the lens is up: a host's `place` may measure its layout.\n const placed = visible\n ? (options.place?.({ aim: model.aim, factor: model.factor }) ?? null)\n : null;\n const lens: LoupeLens = placed\n ? {\n center: placed.center,\n shows: placed.shows ?? placed.center,\n width: placed.width,\n height: placed.height,\n factor: placed.factor ?? model.factor,\n shape: options.shape,\n }\n : {\n center: model.aim,\n shows: model.aim,\n width: options.diameter,\n height: options.diameter,\n factor: model.factor,\n shape: options.shape,\n };\n const lensRef = useLatest(lens);\n\n // Told on a change in value, not on every render: a host drawing into this\n // box would otherwise redraw for each one.\n const onLensRef = useLatest(options.onLens);\n const reportedRef = useRef<string>(JSON.stringify(null));\n const report = useCallback(\n (next: LoupeLens | null): void => {\n const key = JSON.stringify(next);\n if (key === reportedRef.current) return;\n reportedRef.current = key;\n onLensRef.current?.(next);\n },\n [onLensRef],\n );\n const shownLens = visible ? lens : null;\n const shownKey = JSON.stringify(shownLens);\n useEffect(() => {\n report(JSON.parse(shownKey) as LoupeLens | null);\n }, [shownKey, report]);\n useEffect(() => () => report(null), [report]);\n useEffect(() => {\n if (!visible || !subscribeResample) return;\n return subscribeResample(() => model.resample());\n }, [visible, subscribeResample, model]);\n\n const inputRef = useRef<LoupeInputApi | null>(null);\n if (inputRef.current === null) {\n inputRef.current = {\n shown,\n setPeeking: (on) => {\n if (peekingRef.current === on) return;\n peekingRef.current = on;\n if (on) aimAtPointer();\n bump();\n },\n magnifyBy: (deltaY) => {\n const m = modelRef.current;\n if (m) m.setFactor(m.factor * Math.exp(-deltaY * WHEEL_RATE));\n },\n };\n }\n\n return {\n visible,\n aim: model.aim,\n factor: model.factor,\n lens,\n mode: model.mode,\n color: model.color,\n setMode: model.setMode,\n setFactor: model.setFactor,\n resample: model.resample,\n pick: model.pick,\n input: inputRef.current,\n };\n}\n","import { useLatest } from '@weasel-js/core';\nimport {\n type ReactNode,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport { CameraContext, CameraScope } from '../canvas/CameraInput';\nimport { CanvasStackContext } from '../canvas/CanvasStackContext';\nimport { fromCameraView } from '../canvas/cameraView';\nimport type { ViewTransform } from '../instrument/types';\nimport type { Box } from '../surface/rect';\nimport { useSurfaceOptional } from '../surface/useSurfaceTile';\nimport { LoupeSwitchContext } from '../trial/loupeSwitch';\nimport { CanvasLoupe } from './CanvasLoupe';\nimport { sampleStack } from './canvasLens';\nimport { DomLoupe } from './DomLoupe';\nimport { LoupeBubble } from './LoupeBubble';\nimport { LoupeGestures } from './LoupeGestures';\nimport { SourceLoupe } from './SourceLoupe';\nimport { resolveLoupeSource, sampleSource, sourceBoxIn } from './sourceLens';\nimport { type LoupeLens, type LoupeOptions, resolveLoupe } from './types';\nimport { useHostSize } from './useHostSize';\nimport { useLoupe } from './useLoupe';\n\n/** Props for `<TrialLoupe>`. */\nexport interface TrialLoupeProps extends LoupeOptions {\n /** Whether the lens is turned on. Omitted, it follows the trial's toolbar\n * toggle, which the trial offers while a lens like this is mounted — and is\n * off outside a trial. Hold-to-peek shows it either way. */\n enabled?: boolean;\n /** The camera a `render` lens composes its magnification onto. Defaults to\n * the camera around it, and to the identity outside one. */\n view?: ViewTransform;\n /** The element the lens tracks. Defaults to the canvas stack or stage around\n * it, and outside both to a box wrapped around `children`. */\n hostRef?: RefObject<HTMLElement | null>;\n /** Content for the lens to sit over. Wrapped in a box of the lens's own only\n * when nothing around it gives the lens an element to track. */\n children?: ReactNode;\n}\n\nconst IDENTITY: ViewTransform = { zoom: 1, pan: { x: 0, y: 0 } };\n\n/**\n * A trial's magnifier, mounted by the instrument wherever its content is: in\n * a canvas instrument's `render`, a stage's `overlay`, or around DOM content.\n *\n * With no `render` inside a `<CanvasStack>`, it re-draws the stack's own\n * layers through a zoomed camera. With `render`, it asks for the content again\n * at a magnified camera. With `source`, it enlarges the pixels of any canvas.\n */\nexport function TrialLoupe({\n enabled,\n view,\n hostRef,\n children,\n render,\n source,\n factor,\n minFactor,\n maxFactor,\n mode,\n diameter,\n shape,\n place,\n hollow,\n onLens,\n peekKey,\n onColorChange,\n}: TrialLoupeProps) {\n const stack = useContext(CanvasStackContext);\n const camera = useContext(CameraContext);\n const loupeSwitch = useContext(LoupeSwitchContext);\n const surface = render || source || hollow ? undefined : stack?.surface;\n\n const ownHost = useRef<HTMLDivElement | null>(null);\n const cameraHost = useMemo<RefObject<HTMLElement | null> | null>(\n () =>\n camera\n ? {\n get current() {\n return camera.element();\n },\n }\n : null,\n [camera],\n );\n const host = surface?.element ?? hostRef ?? cameraHost ?? ownHost;\n const wraps = host === ownHost;\n const hostLatest = useLatest(host);\n\n // A hollow lens is drawn by the host into the tiles under it, so on a shared surface each\n // move dirties the tiles it left and the ones it landed on.\n const tiles = useSurfaceOptional();\n const onLensLatest = useLatest(onLens);\n const was = useRef<Box | null>(null);\n const damage = hollow ? tiles : null;\n const reportLens = useCallback(\n (lens: LoupeLens | null) => {\n onLensLatest.current?.(lens);\n if (!damage) return;\n const at = hostLatest.current.current?.getBoundingClientRect();\n const now =\n lens && at\n ? {\n left: at.left + lens.center.x - lens.width / 2,\n top: at.top + lens.center.y - lens.height / 2,\n width: lens.width,\n height: lens.height,\n }\n : null;\n if (was.current) damage.invalidateBox(was.current);\n if (now) damage.invalidateBox(now);\n was.current = now;\n },\n [damage, onLensLatest, hostLatest],\n );\n const options = useMemo(\n () =>\n resolveLoupe({\n render,\n source,\n factor,\n minFactor,\n maxFactor,\n mode,\n diameter,\n shape,\n place,\n hollow,\n onLens: onLens || damage ? reportLens : undefined,\n peekKey,\n onColorChange,\n }),\n [\n render,\n source,\n factor,\n minFactor,\n maxFactor,\n mode,\n diameter,\n shape,\n place,\n hollow,\n onLens,\n damage,\n reportLens,\n peekKey,\n onColorChange,\n ],\n );\n\n // A lens told whether it is on has no use for the trial's toggle.\n const mount = enabled === undefined ? loupeSwitch?.mount : undefined;\n useEffect(() => mount?.(), [mount]);\n\n const sample = useMemo(() => {\n if (options.source) {\n const input = options.source;\n return (p: { x: number; y: number }): string | null => {\n const src = resolveLoupeSource(input);\n return src ? sampleSource(src, p, sourceBoxIn(src, host.current)) : null;\n };\n }\n if (!surface) return undefined;\n return (p: { x: number; y: number }): string | null => {\n const canvases = surface.canvases.current;\n return canvases ? sampleStack(surface.layers, canvases, p, surface.size.dpr) : null;\n };\n }, [surface, options.source, host]);\n\n // Keyed on the resolved source, not the prop: an inline getter is re-made\n // every render, and every aim renders.\n const resolved = resolveLoupeSource(options.source);\n const subscribeResample = useMemo(\n () => (resolved ? (fn: () => void) => resolved.subscribeFrame(fn) : undefined),\n [resolved],\n );\n\n const loupe = useLoupe({\n options,\n hostRef: host,\n enabled: enabled ?? loupeSwitch?.on ?? false,\n sample,\n subscribeResample,\n });\n // A captured source copies frames only while someone is reading them. Taken\n // after `useLoupe` has subscribed, so the frame a first reader's redraw\n // captures reaches the color too.\n const reading = loupe.visible ? resolved : null;\n useEffect(() => reading?.retain(), [reading]);\n\n const measured = useHostSize(host);\n const size = surface?.size ?? measured;\n\n // The gestures mount outside the visibility gate: hold-to-peek is what\n // raises a lens that is down, so its binding has to be live while it is.\n // In a trial they join the trial's scope, and with it the camera's\n // dispatcher; outside one, `<CameraScope>` gives them an isolated scope.\n const gestures = (\n <CameraScope>\n <LoupeGestures hostRef={host} input={loupe.input} peekKey={options.peekKey ?? null} />\n </CameraScope>\n );\n\n const { center, shows, width, height, factor: shownFactor, shape: lensShape } = loupe.lens;\n const box = { width, height };\n const lens = loupe.visible ? (\n <LoupeBubble aim={center} diameter={box} shape={lensShape} hollow={options.hollow}>\n {options.hollow ? null : options.render ? (\n <DomLoupe\n aim={shows}\n factor={shownFactor}\n mode={loupe.mode}\n diameter={box}\n size={size}\n view={\n view ??\n stack?.view ??\n (camera ? fromCameraView(camera.view.get(), camera.frame) : IDENTITY)\n }\n frame={stack?.frame ?? camera?.frame}\n render={options.render}\n />\n ) : options.source ? (\n <SourceLoupe\n aim={shows}\n factor={shownFactor}\n diameter={box}\n source={options.source}\n hostRef={host}\n />\n ) : surface && stack ? (\n <CanvasLoupe\n aim={shows}\n factor={shownFactor}\n mode={loupe.mode}\n diameter={box}\n surface={surface}\n view={stack.view}\n frame={stack.frame}\n worldSpec={surface.worldSpec}\n />\n ) : null}\n </LoupeBubble>\n ) : null;\n\n if (wraps) {\n return (\n <div ref={ownHost} className=\"lk-loupe-host\">\n {children}\n {gestures}\n {lens}\n </div>\n );\n }\n return (\n <>\n {children}\n {gestures}\n {lens}\n </>\n );\n}\n"]}
|
package/dist/overview/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { FloatingPanelProps } from '../index.js';
|
|
|
5
5
|
import '@weasel-js/ui';
|
|
6
6
|
import '@weasel-js/core';
|
|
7
7
|
import '@weasel-js/theme';
|
|
8
|
-
import '../_dts/types-
|
|
8
|
+
import '../_dts/types-DUfQ0isU.js';
|
|
9
9
|
import '@weasel-js/quantity';
|
|
10
10
|
import '@weasel-js/geom';
|
|
11
11
|
import '../_dts/types-DJ79Tg5J.js';
|
package/dist/overview/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { markSvgNodes } from '../chunk-
|
|
1
|
+
import { markSvgNodes } from '../chunk-6Q6ACJ3H.js';
|
|
2
2
|
import { useAnnotationsOptional } from '../chunk-3RY6WL5T.js';
|
|
3
|
-
import { FloatingPanel } from '../chunk-
|
|
4
|
-
import '../chunk-
|
|
3
|
+
import { FloatingPanel } from '../chunk-7FMZT2WL.js';
|
|
4
|
+
import '../chunk-7ALJOVGP.js';
|
|
5
5
|
import { CameraContext, fromCameraView, pointerElsewhere, usePublishPointer } from '../chunk-VYVGVBGY.js';
|
|
6
6
|
import '../chunk-ULYYNWGP.js';
|
|
7
7
|
import { CanvasStackContext } from '../chunk-ZQIHJXP4.js';
|
|
8
8
|
import '../chunk-2YILQ7Y5.js';
|
|
9
|
-
import { serializeSvg } from '../chunk-
|
|
10
|
-
import '../chunk-
|
|
9
|
+
import { serializeSvg } from '../chunk-VCK5T6EP.js';
|
|
10
|
+
import '../chunk-AVOILDN2.js';
|
|
11
11
|
import { usePointerPosition, crosshairRects, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, useActionsRegistry, useLatest, useDepSource, minimapCenterAction, minimapPanAction, useGestureDispatcher, MINIMAP_CENTER, MINIMAP_PAN } from '@weasel-js/core';
|
|
12
12
|
import { useContext, useMemo, useRef, useLayoutEffect, useEffect, useReducer } from 'react';
|
|
13
13
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../chunk-CZZPXUOU.js';
|
|
2
|
-
export { b2 as ActionBar, Xt as Badge, c as Button,
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
2
|
+
export { b2 as ActionBar, Xt as Badge, c as Button, a7 as ButtonBar, a6 as COLOR_MODE_OPTIONS, v3 as Callout, f6 as CalloutTrigger, c4 as Checkbox, a2 as CloseButton, s4 as ColorModeControl, b4 as ComboBox, C2 as ComboBoxItem, L as CurveEditor, f2 as DataGrid, d2 as Dialog, i3 as Disclosure, r as DisclosureMark, a3 as DisclosureRow, a4 as DragGhost, n4 as DragGrip, Ze as EDGE_PROFILES, n5 as Field, p5 as GestureRoute, n as ICON_PATHS, l as Icon, u2 as Input, f3 as KeyCap, p as KeySequence, A2 as LayerList, l6 as ListEditor, MINUS_SIGN, p6 as MenuButton, y as NumberField, r3 as OptionsBar, w as Plot2D, n9 as PointPlotter, r4 as Powerline, R2 as PrefsDialog, j2 as PrefsForm, u3 as Radio, l5 as RadioGroup, l9 as RangeSlider, O2 as Select, B2 as SelectItem, n6 as Sidebar, a8 as SidebarPanel, w2 as Slider, a5 as Switch, c5 as Tab, s5 as TabList, l8 as TabPanel, o5 as Tabs, o3 as ThemeSwitcher, s3 as ToggleBar, o4 as ToolButton, n8 as ToolGroup, h3 as ToolPalette, Z2 as chromaAt, o2 as detectPlatform, a as dlog, r2 as fieldClasses, formatNumber, n2 as formatShortcut, t as formatShortcutParts, f5 as gestureRouteSegments, d as inferKeycapKind, i as isDebugEnabled, d3 as isPrefLeaf, e as keyGlyph, l4 as keySpecFromKey, s2 as keySpecsFromMods, m as keySpecsFromShortcut, T as moveLayers, X as oklchToHex, D as paintGradientTrack, f4 as prefValueAtPath, x as sampleByInterpolation, ta as useAsyncOptions, f as useReorderDragList, c3 as useRovingTabIndex, p3 as visiblePrefSubtree } from '../chunk-V4SMGEYY.js';
|
|
3
|
+
import '../chunk-VCK5T6EP.js';
|
|
4
|
+
import '../chunk-AVOILDN2.js';
|
|
5
5
|
//# sourceMappingURL=weasel-ui.js.map
|
|
6
6
|
//# sourceMappingURL=weasel-ui.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { DetailRowStatus, DetailListValues } from '@weasel-js/ui';
|
|
2
|
+
export { StatusBar, StatusBarItem, StatusBarItemProps, StatusBarProps, StatusBarSpacer } from '@weasel-js/ui';
|
|
1
3
|
export { a as FloatingPanel, F as FloatingPanelProps } from '../_dts/FloatingPanel-7j0IcXwz.js';
|
|
2
4
|
import * as react from 'react';
|
|
3
5
|
import { ReactNode, MouseEventHandler } from 'react';
|
|
4
6
|
import { JobHandle } from '../index.js';
|
|
5
|
-
import { DetailRowStatus, DetailListValues } from '@weasel-js/ui';
|
|
6
7
|
import 'windease';
|
|
7
8
|
|
|
8
9
|
/** A live frame-rate readout, averaged over the last 30 frames. */
|
|
@@ -133,22 +134,6 @@ interface SplitProps {
|
|
|
133
134
|
*/
|
|
134
135
|
declare function Split({ sidebar, children, side, label, className, sidebarClassName, contentClassName, width, defaultWidth, minWidth, maxWidth, contentMinWidth, onWidthChange, viewport, }: SplitProps): react.JSX.Element;
|
|
135
136
|
|
|
136
|
-
/** Props for `<StatusBar>`. */
|
|
137
|
-
interface StatusBarProps {
|
|
138
|
-
children: ReactNode;
|
|
139
|
-
}
|
|
140
|
-
/** A footer strip for readouts. Fill it with `<StatusBar.Section>`. */
|
|
141
|
-
declare function StatusBar({ children }: StatusBarProps): react.JSX.Element;
|
|
142
|
-
declare namespace StatusBar {
|
|
143
|
-
var Section: ({ children, end }: StatusBarSectionProps) => react.JSX.Element;
|
|
144
|
-
}
|
|
145
|
-
/** Props for `<StatusBar.Section>`. */
|
|
146
|
-
interface StatusBarSectionProps {
|
|
147
|
-
children: ReactNode;
|
|
148
|
-
/** Pushes this section, and everything after it, to the far end. */
|
|
149
|
-
end?: boolean;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
137
|
/** Props for `<Toolbar>`. */
|
|
153
138
|
interface ToolbarProps {
|
|
154
139
|
children: ReactNode;
|
|
@@ -211,5 +196,5 @@ interface ZoomControlProps {
|
|
|
211
196
|
* only the continuous part. */
|
|
212
197
|
declare function ZoomControl({ zoom, onZoomChange, onZoomCommit, min: minProp, max: maxProp, className, }: ZoomControlProps): react.JSX.Element;
|
|
213
198
|
|
|
214
|
-
export { FpsMeter, JobProgress, Legend, Readout, ScaleIndicator, Split,
|
|
215
|
-
export type { JobProgressProps, LegendEntry, LegendMark, LegendProps, ReadoutProps, ReadoutRow, ScaleIndicatorProps, SplitProps,
|
|
199
|
+
export { FpsMeter, JobProgress, Legend, Readout, ScaleIndicator, Split, Toolbar, ZoomControl };
|
|
200
|
+
export type { JobProgressProps, LegendEntry, LegendMark, LegendProps, ReadoutProps, ReadoutRow, ScaleIndicatorProps, SplitProps, ToolbarButtonProps, ToolbarGroupProps, ToolbarProps, ZoomControlProps };
|
package/dist/primitives/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export { JobProgress, Legend, Readout, Split } from '../chunk-
|
|
2
|
-
export { FloatingPanel } from '../chunk-
|
|
3
|
-
export { FpsMeter, ScaleIndicator,
|
|
1
|
+
export { JobProgress, Legend, Readout, Split } from '../chunk-KHB3KRRQ.js';
|
|
2
|
+
export { FloatingPanel } from '../chunk-7FMZT2WL.js';
|
|
3
|
+
export { FpsMeter, ScaleIndicator, Toolbar, ZoomControl } from '../chunk-RXO5UEGT.js';
|
|
4
4
|
import '../chunk-CZZPXUOU.js';
|
|
5
|
-
import '../chunk-
|
|
5
|
+
import '../chunk-7ALJOVGP.js';
|
|
6
6
|
import '../chunk-ZQIHJXP4.js';
|
|
7
7
|
import '../chunk-2YILQ7Y5.js';
|
|
8
|
-
|
|
9
|
-
import '../chunk-
|
|
10
|
-
import '../chunk-
|
|
8
|
+
export { n7 as StatusBar, r5 as StatusBarItem, i5 as StatusBarSpacer } from '../chunk-V4SMGEYY.js';
|
|
9
|
+
import '../chunk-VCK5T6EP.js';
|
|
10
|
+
import '../chunk-AVOILDN2.js';
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
|
12
12
|
//# sourceMappingURL=index.js.map
|
package/dist/state/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { C as CURRENT_DOCUMENT_VERSION, I as IndexedDbAdapterOptions, L as LabStore, a as LabStoreActions, b as LabStoreContext, c as LabStoreProvider, O as OpenLabStoreOptions, d as OpenedLabStore, P as PersistedStateOptions, e as Persistence, f as PersistenceProps, R as RecordCache, g as RecordChange, T as TrialIdContext, h as TrialIdProvider, i as createIndexedDbAdapter, j as createLabStore, k as createMemoryAdapter, l as indexedDbAdapter, m as labDocumentKey, n as localStorageAdapter, o as noneAdapter, p as openLabStore, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as usePersistedState, v as useTrialId, w as useTrialState } from '../_dts/useTrialState-
|
|
2
|
-
import { S as SerializedTrial, I as InstrumentSerializers, T as TrialRecord,
|
|
3
|
-
export { C as CreateLabStoreOptions, L as LabDocument, d as LabStoreState, M as Migration, e as SavedSnapshot, f as StorageChange, g as TrialStateHandle,
|
|
1
|
+
export { C as CURRENT_DOCUMENT_VERSION, I as IndexedDbAdapterOptions, L as LabStore, a as LabStoreActions, b as LabStoreContext, c as LabStoreProvider, O as OpenLabStoreOptions, d as OpenedLabStore, P as PersistedStateOptions, e as Persistence, f as PersistenceProps, R as RecordCache, g as RecordChange, T as TrialIdContext, h as TrialIdProvider, i as createIndexedDbAdapter, j as createLabStore, k as createMemoryAdapter, l as indexedDbAdapter, m as labDocumentKey, n as localStorageAdapter, o as noneAdapter, p as openLabStore, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as usePersistedState, v as useTrialId, w as useTrialState } from '../_dts/useTrialState-Ar0AFpCe.js';
|
|
2
|
+
import { S as SerializedTrial, I as InstrumentSerializers, T as TrialRecord, c as StorageAdapter } from '../_dts/index-8geQNQet.js';
|
|
3
|
+
export { C as CreateLabStoreOptions, L as LabDocument, d as LabStoreState, M as Migration, e as SavedSnapshot, f as StorageChange, g as TrialStateHandle, U as UndockedPanel, h as UndockedPanels, i as dockPanel, p as panelKey, u as undockPanel } from '../_dts/index-8geQNQet.js';
|
|
4
4
|
import * as react from 'react';
|
|
5
5
|
import { ReactNode } from 'react';
|
|
6
|
+
import '@weasel-js/core';
|
|
6
7
|
import 'zustand/vanilla';
|
|
7
8
|
import '@weasel-js/ui';
|
|
8
|
-
import '@weasel-js/core';
|
|
9
9
|
import '@weasel-js/theme';
|
|
10
|
-
import '../_dts/types-
|
|
10
|
+
import '../_dts/types-DUfQ0isU.js';
|
|
11
11
|
import '@weasel-js/quantity';
|
|
12
12
|
import '@weasel-js/geom';
|
|
13
13
|
import '../_dts/types-DJ79Tg5J.js';
|
|
@@ -20,8 +20,6 @@ declare function encodeUrlHash(value: string): string;
|
|
|
20
20
|
/** Decode a URL fragment written by `encodeUrlHash`, or `null` if it is
|
|
21
21
|
* malformed. */
|
|
22
22
|
declare function decodeUrlHash(hash: string): string | null;
|
|
23
|
-
/** A fresh, empty undo history. */
|
|
24
|
-
declare function emptyUndoStack(): UndoStack;
|
|
25
23
|
/** Serialize trials for storage, running each instrument's own serializer
|
|
26
24
|
* over its state. Undo history is deliberately dropped — it does not survive
|
|
27
25
|
* a reload. */
|
|
@@ -54,5 +52,5 @@ interface SingletonExperimentProviderProps<TS, TC> {
|
|
|
54
52
|
*/
|
|
55
53
|
declare function SingletonExperimentProvider<TS, TC>({ id, initialConfig, initialState, storage, storageKey, fallback, children, }: SingletonExperimentProviderProps<TS, TC>): react.JSX.Element;
|
|
56
54
|
|
|
57
|
-
export { InstrumentSerializers, SerializedTrial, SingletonExperimentProvider, StorageAdapter, TrialRecord,
|
|
55
|
+
export { InstrumentSerializers, SerializedTrial, SingletonExperimentProvider, StorageAdapter, TrialRecord, decodeUrlHash, deserializeTrials, encodeUrlHash, labStorageKey, serializeTrials };
|
|
58
56
|
export type { SingletonExperimentProviderProps };
|
package/dist/state/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { openLabStore } from '../chunk-
|
|
2
|
-
export { CURRENT_DOCUMENT_VERSION, createLabStore, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from '../chunk-
|
|
3
|
-
import { useWarnIgnoredChange, useOpenOnce, defaultStorage, PersistenceContext } from '../chunk-
|
|
4
|
-
export { Persistence, createIndexedDbAdapter, createMemoryAdapter, decodeUrlHash, deserializeTrials,
|
|
5
|
-
import '../chunk-
|
|
1
|
+
import { openLabStore } from '../chunk-NHIO2O3O.js';
|
|
2
|
+
export { CURRENT_DOCUMENT_VERSION, createLabStore, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from '../chunk-NHIO2O3O.js';
|
|
3
|
+
import { useWarnIgnoredChange, useOpenOnce, defaultStorage, PersistenceContext } from '../chunk-7ALJOVGP.js';
|
|
4
|
+
export { Persistence, createIndexedDbAdapter, createMemoryAdapter, decodeUrlHash, deserializeTrials, encodeUrlHash, indexedDbAdapter, labStorageKey, localStorageAdapter, noneAdapter, serializeTrials, sessionStorageAdapter, urlHashAdapter, usePersistedState } from '../chunk-7ALJOVGP.js';
|
|
5
|
+
import '../chunk-T5OEUNCB.js';
|
|
6
6
|
import '../chunk-READTDQX.js';
|
|
7
7
|
import { LabStoreProvider, TrialIdProvider } from '../chunk-2YILQ7Y5.js';
|
|
8
8
|
export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from '../chunk-2YILQ7Y5.js';
|