@weasel-js/labkit 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/_dts/{DrawCommand-BkZztJsW.d.ts → DrawCommand-C_XboUpz.d.ts} +48 -6
- package/dist/_dts/{index-iAP6XbH3.d.ts → index-JFAYj5Tv.d.ts} +12 -0
- package/dist/_dts/types-DJ79Tg5J.d.ts +56 -0
- package/dist/_dts/{useTrialState-DYe2vUwN.d.ts → useTrialState-BMNIx3Cy.d.ts} +5 -9
- package/dist/canvas/index.d.ts +2 -1
- package/dist/{chunk-C6GJKPUI.js → chunk-73KA7WBO.js} +69 -63
- package/dist/chunk-73KA7WBO.js.map +1 -0
- package/dist/{chunk-DJLDIRFN.js → chunk-BOHF3PQO.js} +4375 -3720
- package/dist/chunk-BOHF3PQO.js.map +1 -0
- package/dist/{chunk-NRKWVTVT.js → chunk-G5TJVQQT.js} +3 -3
- package/dist/{chunk-NRKWVTVT.js.map → chunk-G5TJVQQT.js.map} +1 -1
- package/dist/chunk-LN6JDUGB.js +106 -0
- package/dist/chunk-LN6JDUGB.js.map +1 -0
- package/dist/chunk-THBG7FQZ.js +167 -0
- package/dist/chunk-THBG7FQZ.js.map +1 -0
- package/dist/{chunk-3TYUJR7Z.js → chunk-VUU5UXHE.js} +6 -3
- package/dist/chunk-VUU5UXHE.js.map +1 -0
- package/dist/dragdrop/index.d.ts +2 -1
- package/dist/index.d.ts +71 -11
- package/dist/index.js +165 -22
- package/dist/index.js.map +1 -1
- package/dist/job/index.d.ts +13 -0
- package/dist/job/index.js +3 -0
- package/dist/job/index.js.map +1 -0
- package/dist/layers/index.d.ts +3 -2
- package/dist/passthrough/weasel-canvas.d.ts +1 -1
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +20 -4
- package/dist/passthrough/weasel-ui.js +2 -2
- package/dist/state/index.d.ts +2 -2
- package/dist/state/index.js +2 -2
- package/dist/styles.css +10 -0
- package/dist/surface/index.d.ts +77 -0
- package/dist/surface/index.js +3 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/ui/layers/index.js +3 -3
- package/dist/undo/index.d.ts +2 -1
- package/package.json +9 -1
- package/src/canvas/AGENTS.md +8 -0
- package/src/canvas/useOrbit.test.ts +71 -0
- package/src/canvas/useOrbit.ts +149 -0
- package/src/index.test.ts +18 -0
- package/src/index.ts +13 -0
- package/src/instrument/SineWave.smoke.test.tsx +2 -1
- package/src/instrument/types.ts +13 -1
- package/src/job/index.ts +3 -0
- package/src/job/types.ts +47 -0
- package/src/job/useJob.test.tsx +210 -0
- package/src/job/useJob.ts +134 -0
- package/src/lab/Lab.stories.tsx +1 -2
- package/src/lab/Workspace.surface.test.tsx +49 -0
- package/src/lab/Workspace.tsx +14 -1
- package/src/state/store.ts +8 -2
- package/src/state/types.ts +4 -2
- package/src/state/view.test.ts +127 -0
- package/src/state/view.ts +18 -0
- package/src/surface/AGENTS.md +64 -0
- package/src/surface/SurfaceContext.ts +5 -0
- package/src/surface/composeRects.test.ts +50 -0
- package/src/surface/composeRects.ts +19 -0
- package/src/surface/deviceRect.test.ts +40 -0
- package/src/surface/deviceRect.ts +19 -0
- package/src/surface/index.ts +7 -0
- package/src/surface/rect.ts +16 -0
- package/src/surface/useSurfaceTile.test.tsx +67 -0
- package/src/surface/useSurfaceTile.ts +32 -0
- package/src/surface/useTiledSurface.test.tsx +231 -0
- package/src/surface/useTiledSurface.ts +157 -0
- package/src/trial/DefaultStatusBar.tsx +2 -2
- package/src/trial/Trial.job.test.tsx +75 -0
- package/src/trial/Trial.less +12 -0
- package/src/trial/Trial.stories.tsx +8 -1
- package/src/trial/Trial.tsx +32 -6
- package/src/trial/TrialChrome.tsx +33 -6
- package/src/trial/slotTypes.ts +2 -1
- package/dist/chunk-3TYUJR7Z.js.map +0 -1
- package/dist/chunk-C6GJKPUI.js.map +0 -1
- package/dist/chunk-DJLDIRFN.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,69 @@
|
|
|
1
1
|
export { CanvasLayerDescriptor, CanvasStack, CanvasStackContext, CanvasStackContextValue, CanvasStackProps, screenToWorld, worldToScreen } from './canvas/index.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { WheelEvent, PointerEvent, ReactNode } from 'react';
|
|
2
4
|
export { ControlPanel } from './controls/index.js';
|
|
3
5
|
import { C as ConfigField } from './_dts/types-x92Kfeme.js';
|
|
4
6
|
export { a as CheckboxField, b as ColorField, c as ConfigFieldBase, d as ConfigFieldType, N as NumberField, S as SelectField, e as SelectOption, f as SliderField, T as TextField } from './_dts/types-x92Kfeme.js';
|
|
5
|
-
import { I as Instrument, a as InstrumentList } from './_dts/index-
|
|
6
|
-
export { C as CanvasCapability, b as CanvasLayer, D as DragDropCapability, c as DragFeedback, H as HitResult, L as LayerCapability, d as LayerDescriptor, P as PaletteItem, e as Point, R as RenderContext, S as SystemEvent, U as UndoCapability
|
|
7
|
+
import { I as Instrument, a as InstrumentList, V as ViewTransform } from './_dts/index-JFAYj5Tv.js';
|
|
8
|
+
export { C as CanvasCapability, b as CanvasLayer, D as DragDropCapability, c as DragFeedback, H as HitResult, L as LayerCapability, d as LayerDescriptor, P as PaletteItem, e as Point, R as RenderContext, S as SystemEvent, U as UndoCapability } from './_dts/index-JFAYj5Tv.js';
|
|
9
|
+
import { J as JobHandle } from './_dts/types-DJ79Tg5J.js';
|
|
10
|
+
export { a as JobCapability, b as JobEvent, c as JobFailure, d as JobStatus } from './_dts/types-DJ79Tg5J.js';
|
|
11
|
+
export { UseJobOptions, useJob } from './job/index.js';
|
|
7
12
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
import { a as StorageAdapter, w as LabMode, T as TrialRecord, h as SavedSnapshot } from './_dts/useTrialState-DYe2vUwN.js';
|
|
11
|
-
export { C as CURRENT_DOCUMENT_VERSION, b as CreateLabStoreOptions, L as LabDocument, e as LabStoreContext, f as LabStoreProvider, g as LabStoreState, S as SerializedTrial, i as TrialIdContext, j as TrialIdProvider, k as TrialStateHandle, U as UndoStack, m as createMemoryAdapter, n as labDocumentKey, o as localStorageAdapter, p as noneAdapter, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as useTrialId, v as useTrialState } from './_dts/useTrialState-DYe2vUwN.js';
|
|
13
|
+
import { a as StorageAdapter, w as LabMode, T as TrialRecord, h as SavedSnapshot } from './_dts/useTrialState-BMNIx3Cy.js';
|
|
14
|
+
export { C as CURRENT_DOCUMENT_VERSION, b as CreateLabStoreOptions, L as LabDocument, e as LabStoreContext, f as LabStoreProvider, g as LabStoreState, S as SerializedTrial, i as TrialIdContext, j as TrialIdProvider, k as TrialStateHandle, U as UndoStack, m as createMemoryAdapter, n as labDocumentKey, o as localStorageAdapter, p as noneAdapter, q as quarantineKey, s as sessionStorageAdapter, u as urlHashAdapter, r as useLabStore, t as useTrialId, v as useTrialState } from './_dts/useTrialState-BMNIx3Cy.js';
|
|
12
15
|
export { LayerList, LayerListProps } from './layers/index.js';
|
|
13
16
|
export { FpsMeter, ScaleIndicator, ScaleIndicatorProps, Sidebar, SidebarProps, StatusBar, StatusBarProps, Toolbar, ToolbarProps } from './primitives/index.js';
|
|
17
|
+
export { Box, Rect, SurfaceContext, SurfaceFrame, SurfaceHandle, UseTiledSurfaceOptions, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface } from './surface/index.js';
|
|
14
18
|
export { LayerStack, LayerStackItem, LayerStackProps } from './ui/layers/index.js';
|
|
15
19
|
export { EventBus, EventListener, clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './undo/index.js';
|
|
16
20
|
import 'zustand/vanilla';
|
|
17
21
|
|
|
22
|
+
/** A point in the space the instrument works in. */
|
|
23
|
+
interface Vec3 {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
z: number;
|
|
27
|
+
}
|
|
28
|
+
/** An orbit camera as a trial view: where it looks from, and what it looks at.
|
|
29
|
+
* labkit does not turn this into a matrix — the host's renderer does. */
|
|
30
|
+
interface OrbitView {
|
|
31
|
+
yaw: number;
|
|
32
|
+
pitch: number;
|
|
33
|
+
distance: number;
|
|
34
|
+
target: Vec3;
|
|
35
|
+
}
|
|
36
|
+
/** Just short of the pole. At exactly ±PI/2 the azimuth is undefined and the
|
|
37
|
+
* camera rolls, which reads as the model jumping rather than as a limit. */
|
|
38
|
+
declare const PITCH_LIMIT: number;
|
|
39
|
+
declare function clampPitch(pitch: number): number;
|
|
40
|
+
declare function wrapYaw(yaw: number): number;
|
|
41
|
+
/** The view a drag of (dx, dy) from `start` produces. Absolute against the drag
|
|
42
|
+
* start, so it can be re-applied any number of times without compounding. */
|
|
43
|
+
declare function orbitAfterDrag(start: OrbitView, dx: number, dy: number): OrbitView;
|
|
44
|
+
/** Multiplicative, so one notch covers the same proportion of the distance
|
|
45
|
+
* whether the camera is near or far. */
|
|
46
|
+
declare function orbitAfterWheel(view: OrbitView, deltaY: number, minDistance: number, maxDistance: number): OrbitView;
|
|
47
|
+
interface UseOrbitOptions {
|
|
48
|
+
view: OrbitView;
|
|
49
|
+
onViewChange: (v: OrbitView) => void;
|
|
50
|
+
/** Restored on double-click. Defaults to the view the hook first saw. */
|
|
51
|
+
home?: OrbitView;
|
|
52
|
+
minDistance?: number;
|
|
53
|
+
maxDistance?: number;
|
|
54
|
+
}
|
|
55
|
+
interface OrbitHandlers {
|
|
56
|
+
onWheel: (e: WheelEvent<HTMLElement>) => void;
|
|
57
|
+
onPointerDown: (e: PointerEvent<HTMLElement>) => void;
|
|
58
|
+
onPointerMove: (e: PointerEvent<HTMLElement>) => void;
|
|
59
|
+
onPointerUp: (e: PointerEvent<HTMLElement>) => void;
|
|
60
|
+
onDoubleClick: () => void;
|
|
61
|
+
isDragging: () => boolean;
|
|
62
|
+
}
|
|
63
|
+
/** Pointer gestures over an orbit view: drag to turn, wheel or pinch to dolly,
|
|
64
|
+
* double-click to go home. The 3D peer of `usePanZoom`. */
|
|
65
|
+
declare function useOrbit({ view, onViewChange, home, minDistance, maxDistance, }: UseOrbitOptions): OrbitHandlers;
|
|
66
|
+
|
|
18
67
|
/** Which optional capabilities an instrument declared — what the trial
|
|
19
68
|
* consults to decide which chrome to show. */
|
|
20
69
|
interface CapabilityFlags {
|
|
@@ -158,6 +207,14 @@ interface WorkspaceProps {
|
|
|
158
207
|
*/
|
|
159
208
|
declare function Workspace({ children, ids, resizable, reorderable, onReorder, layout, onLayoutChange, gap, padding, viewport, }: WorkspaceProps): react_jsx_runtime.JSX.Element;
|
|
160
209
|
|
|
210
|
+
/** The 2D view labkit has always shipped, and what a trial gets when it names no
|
|
211
|
+
* other. Re-exported under its own name so a consumer can say which it means. */
|
|
212
|
+
type ViewTransform2D = ViewTransform;
|
|
213
|
+
declare const DEFAULT_VIEW: ViewTransform2D;
|
|
214
|
+
/** A trial's view is opaque to labkit, so anything that needs the 2D shape — the
|
|
215
|
+
* zoom chrome, `CanvasStack` — asks for it and handles not getting it. */
|
|
216
|
+
declare function as2DView(view: unknown): ViewTransform2D | null;
|
|
217
|
+
|
|
161
218
|
type TokenValue = string | number | readonly (string | number)[];
|
|
162
219
|
/**
|
|
163
220
|
* A single design token as authored, before aliases are resolved: a DTCG-shaped
|
|
@@ -233,7 +290,8 @@ interface TrialSidebarContext {
|
|
|
233
290
|
interface TrialStatusBarContext {
|
|
234
291
|
trialId: string;
|
|
235
292
|
instrumentName: string;
|
|
236
|
-
|
|
293
|
+
/** Null when the trial holds a view that is not the 2D one. */
|
|
294
|
+
zoom: number | null;
|
|
237
295
|
}
|
|
238
296
|
/** Replaces a trial's toolbar. Receives everything the default one uses,
|
|
239
297
|
* so a custom toolbar need not reach into the store. */
|
|
@@ -256,7 +314,7 @@ interface DefaultStatusBarProps {
|
|
|
256
314
|
ctx: TrialStatusBarContext;
|
|
257
315
|
}
|
|
258
316
|
/** The status bar a trial renders when no `statusBar` slot is supplied:
|
|
259
|
-
* the instrument's name and the
|
|
317
|
+
* the instrument's name, and the zoom when the trial's view has one. */
|
|
260
318
|
declare function DefaultStatusBar({ ctx }: DefaultStatusBarProps): react_jsx_runtime.JSX.Element;
|
|
261
319
|
|
|
262
320
|
/** Props for `<DefaultToolbar>`. */
|
|
@@ -291,13 +349,15 @@ interface TrialChromeProps {
|
|
|
291
349
|
sidebar?: SidebarSlot;
|
|
292
350
|
statusBar?: StatusBarSlot;
|
|
293
351
|
undoBindings?: UndoBindings;
|
|
352
|
+
/** Supplied when the instrument declares a `job`. */
|
|
353
|
+
job?: JobHandle;
|
|
294
354
|
sidebarExtras?: ReactNode;
|
|
295
355
|
children: ReactNode;
|
|
296
356
|
}
|
|
297
357
|
/** The frame around a running instrument — toolbar, sidebar, status bar —
|
|
298
358
|
* each replaceable by a slot. Assembles the slot contexts and wires the undo
|
|
299
359
|
* keyboard shortcuts. */
|
|
300
|
-
declare function TrialChrome({ trialId, record, instrument, isLastTrial, toolbar, sidebar, statusBar, undoBindings, sidebarExtras, children, }: TrialChromeProps): react_jsx_runtime.JSX.Element;
|
|
360
|
+
declare function TrialChrome({ trialId, record, instrument, isLastTrial, toolbar, sidebar, statusBar, undoBindings, job, sidebarExtras, children, }: TrialChromeProps): react_jsx_runtime.JSX.Element;
|
|
301
361
|
|
|
302
362
|
/** Append a new trial running `instrumentName`, at that instrument's
|
|
303
363
|
* default config and initial state. */
|
|
@@ -595,5 +655,5 @@ interface ToggleRowProps<T extends string> {
|
|
|
595
655
|
* visible at once. */
|
|
596
656
|
declare function ToggleRow<T extends string>({ label, value, options, onChange, layout, }: ToggleRowProps<T>): react_jsx_runtime.JSX.Element;
|
|
597
657
|
|
|
598
|
-
export { CheckboxRow, ColorRow, ConfigField, CurveField, DefaultSidebar, DefaultStatusBar, DefaultToolbar, EffectCard, EffectCardList, Instrument, InstrumentList, Lab, LabContext, LabMode, LabShell, NumberRow, PropertyGroup, PropertyList, PropertyPanel, PropertyRow, SavedSnapshot, SelectRow, SliderRow, StorageAdapter, Subpanel, TextRow, ToggleRow, Trial, TrialChrome, TrialRecord, Workspace, addTrial, cloneTrial, closeTrial, defineInstrument, detectCapabilities, interstellarTheme, reorderTrials, resetTrial, useLabContext, validateConfigSchema };
|
|
599
|
-
export type { CapabilityFlags, CheckboxRowProps, ColorRowProps, CurveFieldProps, CurveMark, DefaultSidebarProps, DefaultStatusBarProps, DefaultToolbarProps, EffectCardListItem, EffectCardListProps, EffectCardProps, LabContextValue, LabProps, LabShellProps, NumberRowProps, PropertyGroupProps, PropertyListPack, PropertyListProps, PropertyPanelProps, PropertyRowLayout, PropertyRowProps, PropertyRowVariant, SelectRowProps, SidebarSlot, SliderRowProps, StatusBarSlot, SubpanelProps, TextRowProps, ToggleRowProps, ToolbarSlot, TrialChromeProps, TrialProps, TrialSidebarContext, TrialStatusBarContext, TrialToolbarContext, ValidationResult, WorkspaceProps };
|
|
658
|
+
export { CheckboxRow, ColorRow, ConfigField, CurveField, DEFAULT_VIEW, DefaultSidebar, DefaultStatusBar, DefaultToolbar, EffectCard, EffectCardList, Instrument, InstrumentList, JobHandle, Lab, LabContext, LabMode, LabShell, NumberRow, PITCH_LIMIT, PropertyGroup, PropertyList, PropertyPanel, PropertyRow, SavedSnapshot, SelectRow, SliderRow, StorageAdapter, Subpanel, TextRow, ToggleRow, Trial, TrialChrome, TrialRecord, ViewTransform, Workspace, addTrial, as2DView, clampPitch, cloneTrial, closeTrial, defineInstrument, detectCapabilities, interstellarTheme, orbitAfterDrag, orbitAfterWheel, reorderTrials, resetTrial, useLabContext, useOrbit, validateConfigSchema, wrapYaw };
|
|
659
|
+
export type { CapabilityFlags, CheckboxRowProps, ColorRowProps, CurveFieldProps, CurveMark, DefaultSidebarProps, DefaultStatusBarProps, DefaultToolbarProps, EffectCardListItem, EffectCardListProps, EffectCardProps, LabContextValue, LabProps, LabShellProps, NumberRowProps, OrbitHandlers, OrbitView, PropertyGroupProps, PropertyListPack, PropertyListProps, PropertyPanelProps, PropertyRowLayout, PropertyRowProps, PropertyRowVariant, SelectRowProps, SidebarSlot, SliderRowProps, StatusBarSlot, SubpanelProps, TextRowProps, ToggleRowProps, ToolbarSlot, TrialChromeProps, TrialProps, TrialSidebarContext, TrialStatusBarContext, TrialToolbarContext, UseOrbitOptions, ValidationResult, Vec3, ViewTransform2D, WorkspaceProps };
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { useSurfaceOptional } from './chunk-THBG7FQZ.js';
|
|
2
|
+
export { SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceOptional, useSurfaceTile, useTiledSurface } from './chunk-THBG7FQZ.js';
|
|
3
|
+
import { useJob } from './chunk-LN6JDUGB.js';
|
|
4
|
+
export { useJob } from './chunk-LN6JDUGB.js';
|
|
5
|
+
export { LayerStack } from './chunk-G5TJVQQT.js';
|
|
6
|
+
import { p, F } from './chunk-73KA7WBO.js';
|
|
7
|
+
import './chunk-BOHF3PQO.js';
|
|
4
8
|
import { Sidebar, StatusBar, Toolbar } from './chunk-PMAU3SEE.js';
|
|
5
9
|
export { FpsMeter, ScaleIndicator, Sidebar, StatusBar, Toolbar } from './chunk-PMAU3SEE.js';
|
|
6
|
-
import { LabStoreContext, createLabStore, noneAdapter } from './chunk-
|
|
7
|
-
export { CURRENT_DOCUMENT_VERSION, LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, createMemoryAdapter, labDocumentKey, localStorageAdapter, noneAdapter, quarantineKey, sessionStorageAdapter, urlHashAdapter, useLabStore, useTrialId, useTrialState } from './chunk-
|
|
10
|
+
import { LabStoreContext, createLabStore, noneAdapter } from './chunk-VUU5UXHE.js';
|
|
11
|
+
export { CURRENT_DOCUMENT_VERSION, LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, createMemoryAdapter, labDocumentKey, localStorageAdapter, noneAdapter, quarantineKey, sessionStorageAdapter, urlHashAdapter, useLabStore, useTrialId, useTrialState } from './chunk-VUU5UXHE.js';
|
|
8
12
|
import { ControlPanel } from './chunk-5R2ATYPJ.js';
|
|
9
13
|
export { ControlPanel } from './chunk-5R2ATYPJ.js';
|
|
10
14
|
import { CanvasStack, screenToWorld } from './chunk-574LJAV4.js';
|
|
@@ -14,13 +18,94 @@ import { LayerList } from './chunk-SFL7NFKN.js';
|
|
|
14
18
|
export { LayerList } from './chunk-SFL7NFKN.js';
|
|
15
19
|
import { createEventBus, redo, undo, pushSnapshot } from './chunk-RL2LOLNI.js';
|
|
16
20
|
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
17
|
-
import { createContext, useContext, useMemo,
|
|
21
|
+
import { createContext, useRef, useCallback, useContext, useMemo, useState, Children, useLayoutEffect, useEffect } from 'react';
|
|
18
22
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
19
23
|
import { useStore } from 'zustand/react';
|
|
20
24
|
import { createPortal } from 'react-dom';
|
|
21
25
|
import { asNodeId, Store, createNode, gridStrategy } from 'windease';
|
|
22
26
|
import { DragHandle, Provider, StrategyRegistryProvider, DragProvider, Container } from 'windease/react';
|
|
23
27
|
|
|
28
|
+
var PITCH_LIMIT = Math.PI / 2 - 0.01;
|
|
29
|
+
var YAW_PER_PX = 8e-3;
|
|
30
|
+
var PITCH_PER_PX = 8e-3;
|
|
31
|
+
var DISTANCE_PER_NOTCH = 15e-4;
|
|
32
|
+
var DRAG_THRESHOLD = 3;
|
|
33
|
+
function clampPitch(pitch) {
|
|
34
|
+
return Math.min(PITCH_LIMIT, Math.max(-PITCH_LIMIT, pitch));
|
|
35
|
+
}
|
|
36
|
+
function wrapYaw(yaw) {
|
|
37
|
+
const wrapped = ((yaw + Math.PI) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) - Math.PI;
|
|
38
|
+
return wrapped === -Math.PI ? Math.PI : wrapped;
|
|
39
|
+
}
|
|
40
|
+
function orbitAfterDrag(start, dx, dy) {
|
|
41
|
+
return {
|
|
42
|
+
...start,
|
|
43
|
+
yaw: wrapYaw(start.yaw + dx * YAW_PER_PX),
|
|
44
|
+
pitch: clampPitch(start.pitch + dy * PITCH_PER_PX)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function orbitAfterWheel(view, deltaY, minDistance, maxDistance) {
|
|
48
|
+
const factor = Math.exp(deltaY * DISTANCE_PER_NOTCH);
|
|
49
|
+
return {
|
|
50
|
+
...view,
|
|
51
|
+
distance: Math.min(maxDistance, Math.max(minDistance, view.distance * factor))
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function useOrbit({
|
|
55
|
+
view,
|
|
56
|
+
onViewChange,
|
|
57
|
+
home,
|
|
58
|
+
minDistance = 0.1,
|
|
59
|
+
maxDistance = 1e3
|
|
60
|
+
}) {
|
|
61
|
+
const dragRef = useRef(null);
|
|
62
|
+
const viewRef = useRef(view);
|
|
63
|
+
viewRef.current = view;
|
|
64
|
+
const homeRef = useRef(home ?? view);
|
|
65
|
+
if (home) homeRef.current = home;
|
|
66
|
+
const onWheel = useCallback(
|
|
67
|
+
(e) => {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
onViewChange(orbitAfterWheel(viewRef.current, e.deltaY, minDistance, maxDistance));
|
|
70
|
+
},
|
|
71
|
+
[onViewChange, minDistance, maxDistance]
|
|
72
|
+
);
|
|
73
|
+
const onPointerDown = useCallback((e) => {
|
|
74
|
+
if (e.button !== 0) return;
|
|
75
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
76
|
+
dragRef.current = {
|
|
77
|
+
pointerId: e.pointerId,
|
|
78
|
+
startX: e.clientX,
|
|
79
|
+
startY: e.clientY,
|
|
80
|
+
startView: viewRef.current,
|
|
81
|
+
moved: false
|
|
82
|
+
};
|
|
83
|
+
}, []);
|
|
84
|
+
const onPointerMove = useCallback(
|
|
85
|
+
(e) => {
|
|
86
|
+
const drag = dragRef.current;
|
|
87
|
+
if (!drag || drag.pointerId !== e.pointerId) return;
|
|
88
|
+
const dx = e.clientX - drag.startX;
|
|
89
|
+
const dy = e.clientY - drag.startY;
|
|
90
|
+
if (!drag.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
|
|
91
|
+
drag.moved = true;
|
|
92
|
+
onViewChange(orbitAfterDrag(drag.startView, dx, dy));
|
|
93
|
+
},
|
|
94
|
+
[onViewChange]
|
|
95
|
+
);
|
|
96
|
+
const onPointerUp = useCallback((e) => {
|
|
97
|
+
const drag = dragRef.current;
|
|
98
|
+
if (!drag || drag.pointerId !== e.pointerId) return;
|
|
99
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
100
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
101
|
+
}
|
|
102
|
+
dragRef.current = null;
|
|
103
|
+
}, []);
|
|
104
|
+
const onDoubleClick = useCallback(() => onViewChange(homeRef.current), [onViewChange]);
|
|
105
|
+
const isDragging = useCallback(() => dragRef.current?.moved === true, []);
|
|
106
|
+
return { onWheel, onPointerDown, onPointerMove, onPointerUp, onDoubleClick, isDragging };
|
|
107
|
+
}
|
|
108
|
+
|
|
24
109
|
// src/instrument/capabilityDetector.ts
|
|
25
110
|
function detectCapabilities(instrument) {
|
|
26
111
|
return {
|
|
@@ -934,6 +1019,17 @@ function useLabContext() {
|
|
|
934
1019
|
}
|
|
935
1020
|
return ctx;
|
|
936
1021
|
}
|
|
1022
|
+
|
|
1023
|
+
// src/state/view.ts
|
|
1024
|
+
var DEFAULT_VIEW = { zoom: 1, pan: { x: 0, y: 0 } };
|
|
1025
|
+
function as2DView(view) {
|
|
1026
|
+
if (typeof view !== "object" || view === null) return null;
|
|
1027
|
+
const v = view;
|
|
1028
|
+
if (typeof v.zoom !== "number") return null;
|
|
1029
|
+
if (typeof v.pan !== "object" || v.pan === null) return null;
|
|
1030
|
+
if (typeof v.pan.x !== "number" || typeof v.pan.y !== "number") return null;
|
|
1031
|
+
return { zoom: v.zoom, pan: { x: v.pan.x, y: v.pan.y } };
|
|
1032
|
+
}
|
|
937
1033
|
function DefaultSidebar({ ctx }) {
|
|
938
1034
|
if (ctx.configFields.length === 0) {
|
|
939
1035
|
return /* @__PURE__ */ jsx(Sidebar, { title: ctx.instrumentName, children: /* @__PURE__ */ jsxs("div", { className: "lk-sidebar__placeholder", children: [
|
|
@@ -970,7 +1066,7 @@ function formatZoom(zoom) {
|
|
|
970
1066
|
function DefaultStatusBar({ ctx }) {
|
|
971
1067
|
return /* @__PURE__ */ jsxs(StatusBar, { children: [
|
|
972
1068
|
/* @__PURE__ */ jsx(StatusBar.Section, { children: ctx.instrumentName }),
|
|
973
|
-
/* @__PURE__ */ jsx(StatusBar.Section, { children: formatZoom(ctx.zoom) })
|
|
1069
|
+
ctx.zoom === null ? null : /* @__PURE__ */ jsx(StatusBar.Section, { children: formatZoom(ctx.zoom) })
|
|
974
1070
|
] });
|
|
975
1071
|
}
|
|
976
1072
|
function DefaultToolbar({ ctx }) {
|
|
@@ -1038,6 +1134,7 @@ function TrialChrome({
|
|
|
1038
1134
|
sidebar,
|
|
1039
1135
|
statusBar,
|
|
1040
1136
|
undoBindings,
|
|
1137
|
+
job,
|
|
1041
1138
|
sidebarExtras,
|
|
1042
1139
|
children
|
|
1043
1140
|
}) {
|
|
@@ -1047,9 +1144,11 @@ function TrialChrome({
|
|
|
1047
1144
|
const updateTrialView = useStore(storeCtx.store, (s) => s.updateTrialView);
|
|
1048
1145
|
const updateTrialConfig = useStore(storeCtx.store, (s) => s.updateTrialConfig);
|
|
1049
1146
|
const updateTrialState = useStore(storeCtx.store, (s) => s.updateTrialState);
|
|
1147
|
+
const view2d = as2DView(record.view);
|
|
1050
1148
|
const toolbarCtx = useMemo(() => {
|
|
1051
1149
|
const setZoom = (z) => {
|
|
1052
|
-
|
|
1150
|
+
if (!view2d) return;
|
|
1151
|
+
updateTrialView(trialId, { ...view2d, zoom: z });
|
|
1053
1152
|
};
|
|
1054
1153
|
return {
|
|
1055
1154
|
trialId,
|
|
@@ -1061,10 +1160,10 @@ function TrialChrome({
|
|
|
1061
1160
|
}),
|
|
1062
1161
|
redo: undoBindings?.redo ?? (() => {
|
|
1063
1162
|
}),
|
|
1064
|
-
zoom:
|
|
1163
|
+
zoom: view2d?.zoom ?? 1,
|
|
1065
1164
|
setZoom,
|
|
1066
|
-
zoomIn: () => setZoom(
|
|
1067
|
-
zoomOut: () => setZoom(
|
|
1165
|
+
zoomIn: () => setZoom((view2d?.zoom ?? 1) * 1.25),
|
|
1166
|
+
zoomOut: () => setZoom((view2d?.zoom ?? 1) * 0.8),
|
|
1068
1167
|
resetZoom: () => setZoom(1),
|
|
1069
1168
|
hasCanvas: instrument.canvas != null,
|
|
1070
1169
|
savedSnapshots: lab.savedSnapshots.filter((s) => s.trialId === trialId),
|
|
@@ -1075,7 +1174,7 @@ function TrialChrome({
|
|
|
1075
1174
|
close: () => lab.closeTrial(trialId),
|
|
1076
1175
|
isLastTrial
|
|
1077
1176
|
};
|
|
1078
|
-
}, [trialId, record, instrument, lab, isLastTrial, updateTrialView, undoBindings]);
|
|
1177
|
+
}, [trialId, record, instrument, lab, isLastTrial, updateTrialView, undoBindings, view2d]);
|
|
1079
1178
|
const sidebarCtx = useMemo(
|
|
1080
1179
|
() => ({
|
|
1081
1180
|
trialId,
|
|
@@ -1102,7 +1201,7 @@ function TrialChrome({
|
|
|
1102
1201
|
const statusCtx = {
|
|
1103
1202
|
trialId,
|
|
1104
1203
|
instrumentName: record.instrumentName,
|
|
1105
|
-
zoom:
|
|
1204
|
+
zoom: view2d ? view2d.zoom : null
|
|
1106
1205
|
};
|
|
1107
1206
|
const handleKeyDown = (e) => {
|
|
1108
1207
|
const mod = e.metaKey || e.ctrlKey;
|
|
@@ -1131,7 +1230,21 @@ function TrialChrome({
|
|
|
1131
1230
|
] }),
|
|
1132
1231
|
/* @__PURE__ */ jsx("div", { className: "lk-trial__content", children })
|
|
1133
1232
|
] }),
|
|
1134
|
-
/* @__PURE__ */
|
|
1233
|
+
/* @__PURE__ */ jsxs("div", { className: "lk-trial__status", children: [
|
|
1234
|
+
job ? /* @__PURE__ */ jsxs("div", { className: "lk-trial__job", children: [
|
|
1235
|
+
/* @__PURE__ */ jsxs("span", { className: "lk-trial__job-count", children: [
|
|
1236
|
+
job.done,
|
|
1237
|
+
job.total === null ? "" : ` / ${job.total}`
|
|
1238
|
+
] }),
|
|
1239
|
+
job.failures.length > 0 ? /* @__PURE__ */ jsxs("span", { className: "lk-trial__job-failures", children: [
|
|
1240
|
+
job.failures.length,
|
|
1241
|
+
" failed"
|
|
1242
|
+
] }) : null,
|
|
1243
|
+
job.error ? /* @__PURE__ */ jsx("span", { className: "lk-trial__job-error", children: job.error }) : null,
|
|
1244
|
+
job.status === "running" ? /* @__PURE__ */ jsx("button", { type: "button", className: "lk-trial__job-cancel", onClick: job.cancel, children: "Cancel" }) : null
|
|
1245
|
+
] }) : null,
|
|
1246
|
+
statusBar ? statusBar(statusCtx) : /* @__PURE__ */ jsx(DefaultStatusBar, { ctx: statusCtx })
|
|
1247
|
+
] })
|
|
1135
1248
|
]
|
|
1136
1249
|
}
|
|
1137
1250
|
);
|
|
@@ -1186,6 +1299,15 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1186
1299
|
updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
|
|
1187
1300
|
};
|
|
1188
1301
|
const setView = (v) => updateTrialView(record.id, v);
|
|
1302
|
+
const view2d = as2DView(record.view);
|
|
1303
|
+
const jobCap = instrument.job;
|
|
1304
|
+
const job = useJob({
|
|
1305
|
+
capability: jobCap ?? { run: async function* () {
|
|
1306
|
+
}, onItem: (_i, st) => st },
|
|
1307
|
+
config: record.config,
|
|
1308
|
+
state: record.state,
|
|
1309
|
+
setState: (next) => updateTrialState(record.id, next)
|
|
1310
|
+
});
|
|
1189
1311
|
const renderCtx = {
|
|
1190
1312
|
state: record.state,
|
|
1191
1313
|
config: record.config,
|
|
@@ -1204,13 +1326,19 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1204
1326
|
},
|
|
1205
1327
|
trial: {
|
|
1206
1328
|
id: record.id,
|
|
1207
|
-
|
|
1208
|
-
|
|
1329
|
+
view: record.view,
|
|
1330
|
+
setView,
|
|
1331
|
+
zoom: view2d?.zoom ?? 1,
|
|
1332
|
+
setZoom: (z) => {
|
|
1333
|
+
if (!view2d) return;
|
|
1334
|
+
updateTrialView(record.id, { ...view2d, zoom: z });
|
|
1335
|
+
}
|
|
1209
1336
|
},
|
|
1210
1337
|
emit: (event) => {
|
|
1211
1338
|
snapshotIfNeeded(event);
|
|
1212
1339
|
bus.emit(event);
|
|
1213
|
-
}
|
|
1340
|
+
},
|
|
1341
|
+
job: jobCap ? job : void 0
|
|
1214
1342
|
};
|
|
1215
1343
|
const undoBindings = undoCap ? {
|
|
1216
1344
|
canUndo: record.undoStack.past.length > 0,
|
|
@@ -1249,7 +1377,7 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1249
1377
|
const dragDropResult = useDragDrop({
|
|
1250
1378
|
capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s) => s },
|
|
1251
1379
|
canvasContainerRef,
|
|
1252
|
-
view:
|
|
1380
|
+
view: view2d ?? DEFAULT_VIEW,
|
|
1253
1381
|
state: record.state,
|
|
1254
1382
|
config: record.config,
|
|
1255
1383
|
setState: (next) => {
|
|
@@ -1299,7 +1427,15 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1299
1427
|
className: "lk-trial__canvas-host",
|
|
1300
1428
|
style: { width: "100%", height: "100%", position: "relative" },
|
|
1301
1429
|
children: [
|
|
1302
|
-
/* @__PURE__ */ jsx(
|
|
1430
|
+
/* @__PURE__ */ jsx(
|
|
1431
|
+
CanvasStack,
|
|
1432
|
+
{
|
|
1433
|
+
layers: layersWithFeedback,
|
|
1434
|
+
view: view2d ?? DEFAULT_VIEW,
|
|
1435
|
+
onViewChange: setView,
|
|
1436
|
+
children: instrument.render(renderCtx)
|
|
1437
|
+
}
|
|
1438
|
+
),
|
|
1303
1439
|
/* @__PURE__ */ jsx(DragOverlay, { drag: dragDropResult.drag })
|
|
1304
1440
|
]
|
|
1305
1441
|
}
|
|
@@ -1326,6 +1462,7 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1326
1462
|
return /* @__PURE__ */ jsx(
|
|
1327
1463
|
TrialChrome,
|
|
1328
1464
|
{
|
|
1465
|
+
job: jobCap ? job : void 0,
|
|
1329
1466
|
trialId: record.id,
|
|
1330
1467
|
record,
|
|
1331
1468
|
instrument,
|
|
@@ -1341,7 +1478,7 @@ function TrialRuntime({ record, instrument, store, isLast }) {
|
|
|
1341
1478
|
}
|
|
1342
1479
|
|
|
1343
1480
|
// src/trial/trialOps.ts
|
|
1344
|
-
var
|
|
1481
|
+
var DEFAULT_VIEW2 = { zoom: 1, pan: { x: 0, y: 0 } };
|
|
1345
1482
|
function findInstrument(instruments, name) {
|
|
1346
1483
|
const found = instruments.find((i) => i.name === name);
|
|
1347
1484
|
if (!found) {
|
|
@@ -1350,7 +1487,7 @@ function findInstrument(instruments, name) {
|
|
|
1350
1487
|
return found;
|
|
1351
1488
|
}
|
|
1352
1489
|
function initialView(instrument) {
|
|
1353
|
-
return instrument.canvas?.initialView ? structuredClone(instrument.canvas.initialView) : { ...
|
|
1490
|
+
return instrument.canvas?.initialView ? structuredClone(instrument.canvas.initialView) : { ...DEFAULT_VIEW2, pan: { ...DEFAULT_VIEW2.pan } };
|
|
1354
1491
|
}
|
|
1355
1492
|
function addTrial(trials, instruments, instrumentName) {
|
|
1356
1493
|
const instrument = findInstrument(instruments, instrumentName);
|
|
@@ -1481,6 +1618,7 @@ function Workspace({
|
|
|
1481
1618
|
storeRef.current = store2;
|
|
1482
1619
|
}
|
|
1483
1620
|
const store = storeRef.current;
|
|
1621
|
+
const surface = useSurfaceOptional();
|
|
1484
1622
|
useLayoutEffect(() => {
|
|
1485
1623
|
store.updateContainerConfig(ZONE_ID, { resizable, gap, padding });
|
|
1486
1624
|
}, [store, resizable, gap, padding]);
|
|
@@ -1499,6 +1637,11 @@ function Workspace({
|
|
|
1499
1637
|
}
|
|
1500
1638
|
store.setChildOrder(ZONE_ID, [...nodeIds]);
|
|
1501
1639
|
}, [store, nodeIds]);
|
|
1640
|
+
useEffect(() => {
|
|
1641
|
+
if (!surface) return;
|
|
1642
|
+
surface.invalidateRects();
|
|
1643
|
+
return store.events.on("node.placementChanged", () => surface.invalidateRects());
|
|
1644
|
+
}, [store, surface, nodeIds]);
|
|
1502
1645
|
useEffect(() => {
|
|
1503
1646
|
if (!onLayoutChange) return;
|
|
1504
1647
|
return store.events.on("node.placementChanged", () => {
|
|
@@ -2283,6 +2426,6 @@ function ToggleRow({
|
|
|
2283
2426
|
}) }) });
|
|
2284
2427
|
}
|
|
2285
2428
|
|
|
2286
|
-
export { CheckboxRow, ColorRow, CurveField, DefaultSidebar, DefaultStatusBar, DefaultToolbar, EffectCard, EffectCardList, Lab, LabContext, LabShell, NumberRow, PropertyGroup, PropertyList, PropertyPanel, PropertyRow, SelectRow, SliderRow, Subpanel, TextRow, ToggleRow, Trial, TrialChrome, Workspace, addTrial, cloneTrial, closeTrial, defineInstrument, detectCapabilities, interstellarTheme, reorderTrials, resetTrial, useLabContext, validateConfigSchema };
|
|
2429
|
+
export { CheckboxRow, ColorRow, CurveField, DEFAULT_VIEW, DefaultSidebar, DefaultStatusBar, DefaultToolbar, EffectCard, EffectCardList, Lab, LabContext, LabShell, NumberRow, PITCH_LIMIT, PropertyGroup, PropertyList, PropertyPanel, PropertyRow, SelectRow, SliderRow, Subpanel, TextRow, ToggleRow, Trial, TrialChrome, Workspace, addTrial, as2DView, clampPitch, cloneTrial, closeTrial, defineInstrument, detectCapabilities, interstellarTheme, orbitAfterDrag, orbitAfterWheel, reorderTrials, resetTrial, useLabContext, useOrbit, validateConfigSchema, wrapYaw };
|
|
2287
2430
|
//# sourceMappingURL=index.js.map
|
|
2288
2431
|
//# sourceMappingURL=index.js.map
|