@weasel-js/labkit 1.4.2 → 1.4.4
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 +20 -2
- package/dist/_dts/{CanvasStackContext-kjILVnPj.d.ts → CanvasStackContext-kTEZvEgE.d.ts} +1 -1
- package/dist/_dts/{PrefsForm.d-CgxUequc.d.ts → PrefsForm.d-DDHFANkc.d.ts} +1 -1
- package/dist/_dts/{frac-A4R6v4ld.d.ts → frac-z7ker2Vx.d.ts} +11 -7
- package/dist/_dts/{index-CsU9WhjM.d.ts → index-Blv9uQzu.d.ts} +42 -9
- package/dist/_dts/types-B9_zrHmb.d.ts +166 -0
- package/dist/_dts/{types-BbXpvQa8.d.ts → types-BP2OCcpg.d.ts} +21 -3
- package/dist/_dts/types-x92Kfeme.d.ts +62 -0
- package/dist/_dts/{useTrialState-DKjqpv20.d.ts → useTrialState-D6Vb3T-g.d.ts} +7 -7
- package/dist/canvas/index.d.ts +9 -8
- package/dist/canvas/index.js +1 -2
- package/dist/chrome/index.d.ts +7 -6
- package/dist/chrome/index.js +5 -5
- package/dist/{chunk-ULDW42CR.js → chunk-2P6PP5N4.js} +33 -23
- package/dist/chunk-2P6PP5N4.js.map +1 -0
- package/dist/{chunk-W2FJR5FF.js → chunk-64ZCN3DA.js} +74 -76
- package/dist/chunk-64ZCN3DA.js.map +1 -0
- package/dist/{chunk-NSOVI3AZ.js → chunk-BKFVHKJH.js} +6 -6
- package/dist/{chunk-NSOVI3AZ.js.map → chunk-BKFVHKJH.js.map} +1 -1
- package/dist/chunk-E44SU6XS.js +50 -0
- package/dist/chunk-E44SU6XS.js.map +1 -0
- package/dist/{chunk-WS6ZRV75.js → chunk-FQMJUVHJ.js} +3 -3
- package/dist/{chunk-WS6ZRV75.js.map → chunk-FQMJUVHJ.js.map} +1 -1
- package/dist/{chunk-FJG4PHTL.js → chunk-I6JCVE24.js} +3 -3
- package/dist/chunk-I6JCVE24.js.map +1 -0
- package/dist/{chunk-UDXOYZEC.js → chunk-MOM3GOVY.js} +4 -4
- package/dist/{chunk-UDXOYZEC.js.map → chunk-MOM3GOVY.js.map} +1 -1
- package/dist/{chunk-TN7YSJVU.js → chunk-RS3HRQWU.js} +3 -3
- package/dist/{chunk-TN7YSJVU.js.map → chunk-RS3HRQWU.js.map} +1 -1
- package/dist/{chunk-UTOEDPNU.js → chunk-SMHP6XZ4.js} +7 -6
- package/dist/chunk-SMHP6XZ4.js.map +1 -0
- package/dist/{chunk-D5KQ5OY6.js → chunk-TJ7QY3OC.js} +3 -3
- package/dist/{chunk-D5KQ5OY6.js.map → chunk-TJ7QY3OC.js.map} +1 -1
- package/dist/{chunk-XKENZTNE.js → chunk-U3IYHIAE.js} +71 -55
- package/dist/chunk-U3IYHIAE.js.map +1 -0
- package/dist/chunk-W3ECWC2K.js +7335 -0
- package/dist/chunk-W3ECWC2K.js.map +1 -0
- package/dist/controls/index.d.ts +5 -4
- package/dist/controls/index.js +3 -3
- package/dist/dragdrop/index.d.ts +6 -5
- package/dist/dragdrop/index.js +1 -2
- package/dist/index.d.ts +139 -26
- package/dist/index.js +309 -144
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +7 -6
- package/dist/layers/index.js +2 -3
- package/dist/loupe/index.d.ts +8 -7
- package/dist/loupe/index.js +1 -2
- package/dist/passthrough/weasel-canvas.d.ts +1 -3
- package/dist/passthrough/weasel-canvas.js +1 -1
- package/dist/passthrough/weasel-canvas.js.map +1 -1
- package/dist/passthrough/weasel-ui.d.ts +98 -20
- package/dist/passthrough/weasel-ui.js +1 -2
- package/dist/primitives/index.js +3 -4
- package/dist/state/index.d.ts +6 -3
- package/dist/state/index.js +3 -2
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +82 -15
- package/dist/surface/index.js +1 -2
- package/dist/ui/layers/index.js +1 -2
- package/dist/undo/index.d.ts +6 -6
- package/package.json +7 -7
- package/src/annotations/ExportMenu.test.tsx +16 -0
- package/src/annotations/ExportMenu.tsx +0 -5
- package/src/annotations/frac.test.ts +4 -4
- package/src/annotations/frac.ts +3 -2
- package/src/annotations/index.ts +1 -1
- package/src/annotations/store.ts +2 -2
- package/src/annotations/svgNodes.ts +1 -2
- package/src/config/builder.test.ts +56 -2
- package/src/config/builder.ts +73 -13
- package/src/config/index.ts +16 -1
- package/src/config/path.test.ts +109 -0
- package/src/config/path.ts +76 -0
- package/src/config/resolve.test.ts +93 -2
- package/src/config/resolve.ts +72 -29
- package/src/config/types.ts +99 -9
- package/src/config/visible.ts +6 -4
- package/src/controls/ControlPanel.stories.tsx +38 -4
- package/src/controls/ControlPanel.test.tsx +114 -0
- package/src/controls/ControlPanel.tsx +99 -50
- package/src/index.ts +17 -2
- package/src/instrument/serializers.ts +36 -0
- package/src/instrument/types.ts +4 -2
- package/src/lab/Lab.test.tsx +29 -1
- package/src/lab/Lab.tsx +10 -1
- package/src/lab/LabShell.test.tsx +8 -0
- package/src/lab/LabShell.tsx +17 -3
- package/src/lab/LabSwitcher.less +85 -0
- package/src/lab/LabSwitcher.test.tsx +96 -0
- package/src/lab/LabSwitcher.tsx +112 -0
- package/src/lab/index.ts +2 -0
- package/src/primitives/ZoomControl.less +6 -2
- package/src/primitives/ZoomControl.tsx +1 -0
- package/src/state/helpers.test.ts +20 -0
- package/src/state/helpers.ts +17 -1
- package/src/state/store.test.ts +155 -1
- package/src/state/store.ts +32 -26
- package/src/state/types.ts +24 -3
- package/src/state/useTrialState.ts +1 -1
- package/src/styles.less +1 -0
- package/src/theme/base.less +4 -4
- package/src/trial/Trial.config.test.tsx +44 -0
- package/src/trial/Trial.tsx +3 -3
- package/src/trial/TrialChrome.tsx +10 -5
- package/src/trial/trialOps.ts +7 -10
- package/dist/_dts/types-lg4TSCb2.d.ts +0 -164
- package/dist/_dts/weasel-canvas-FJTFi3ZZ.d.ts +0 -5041
- package/dist/chunk-54ZWZ5FQ.js +0 -29997
- package/dist/chunk-54ZWZ5FQ.js.map +0 -1
- package/dist/chunk-FJG4PHTL.js.map +0 -1
- package/dist/chunk-ISSVF5PT.js +0 -7263
- package/dist/chunk-ISSVF5PT.js.map +0 -1
- package/dist/chunk-ULDW42CR.js.map +0 -1
- package/dist/chunk-UTOEDPNU.js.map +0 -1
- package/dist/chunk-W2FJR5FF.js.map +0 -1
- package/dist/chunk-XKENZTNE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
import { createEventBus, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
2
2
|
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
3
|
-
import { useDragDrop, DragOverlay, Palette } from './chunk-
|
|
4
|
-
import { useSurfaceOptional, useSurfaceCanvas, useTileId, useTiledSurface, SurfaceContext, SurfaceCanvasContext } from './chunk-
|
|
5
|
-
export { SurfaceCanvasContext, SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './chunk-
|
|
3
|
+
import { useDragDrop, DragOverlay, Palette } from './chunk-RS3HRQWU.js';
|
|
4
|
+
import { useSurfaceOptional, useSurfaceCanvas, useTileId, useTiledSurface, SurfaceContext, SurfaceCanvasContext } from './chunk-FQMJUVHJ.js';
|
|
5
|
+
export { SurfaceCanvasContext, SurfaceContext, composeRects, rectsEqual, toDeviceRect, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId, useTiledSurface } from './chunk-FQMJUVHJ.js';
|
|
6
6
|
import { useJob } from './chunk-HXXTULDN.js';
|
|
7
7
|
export { useJob } from './chunk-HXXTULDN.js';
|
|
8
|
-
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, AnnotationsContext } from './chunk-
|
|
9
|
-
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationsContext, ExportMenu, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, mergeContributions, suppressContributions, useAnnotations, useAnnotationsOptional } from './chunk-
|
|
10
|
-
import { JobProgress } from './chunk-
|
|
11
|
-
export { FloatingPanel, JobProgress, Legend, Sidebar } from './chunk-
|
|
12
|
-
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-
|
|
13
|
-
import { createLabStore, panelKey, noneAdapter } from './chunk-
|
|
14
|
-
export { CURRENT_DOCUMENT_VERSION, createMemoryAdapter, dockPanel, labDocumentKey, localStorageAdapter, noneAdapter, panelKey, quarantineKey, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState } from './chunk-
|
|
8
|
+
import { ANNOTATION_WEASEL_TOOLS, annotationToolInfo, suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, AnnotationsContext } from './chunk-64ZCN3DA.js';
|
|
9
|
+
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationsContext, ExportMenu, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, mergeContributions, suppressContributions, useAnnotations, useAnnotationsOptional } from './chunk-64ZCN3DA.js';
|
|
10
|
+
import { JobProgress } from './chunk-MOM3GOVY.js';
|
|
11
|
+
export { FloatingPanel, JobProgress, Legend, Sidebar } from './chunk-MOM3GOVY.js';
|
|
12
|
+
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-SMHP6XZ4.js';
|
|
13
|
+
import { newId, createLabStore, panelKey, noneAdapter } from './chunk-2P6PP5N4.js';
|
|
14
|
+
export { CURRENT_DOCUMENT_VERSION, createMemoryAdapter, dockPanel, labDocumentKey, localStorageAdapter, noneAdapter, panelKey, quarantineKey, sessionStorageAdapter, undockPanel, urlHashAdapter, useTrialState } from './chunk-2P6PP5N4.js';
|
|
15
15
|
import { LabStoreContext, TrialIdProvider } from './chunk-2YILQ7Y5.js';
|
|
16
16
|
export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
|
|
17
|
-
import { fromConfigFields } from './chunk-
|
|
18
|
-
export { ControlPanel, fromConfigFields, isLeafVisible } from './chunk-
|
|
19
|
-
import {
|
|
20
|
-
export {
|
|
21
|
-
import {
|
|
22
|
-
export {
|
|
17
|
+
import { fromConfigFields } from './chunk-U3IYHIAE.js';
|
|
18
|
+
export { ControlPanel, fromConfigFields, isLeafVisible } from './chunk-U3IYHIAE.js';
|
|
19
|
+
import { hasConfigPath, schemaNodeAtPath, withValueAtPath, fillConfigDefaults } from './chunk-E44SU6XS.js';
|
|
20
|
+
export { fillConfigDefaults, hasConfigPath, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-E44SU6XS.js';
|
|
21
|
+
import { CanvasStack } from './chunk-I6JCVE24.js';
|
|
22
|
+
export { CanvasStack, PITCH_LIMIT, clampPitch, orbitAfterDrag, orbitAfterWheel, useOrbit, usePanZoom, wrapYaw } from './chunk-I6JCVE24.js';
|
|
23
|
+
import { LayerList } from './chunk-BKFVHKJH.js';
|
|
24
|
+
export { LayerList } from './chunk-BKFVHKJH.js';
|
|
23
25
|
import './chunk-SBXNQW4G.js';
|
|
24
|
-
import { E, w, T, C,
|
|
25
|
-
export {
|
|
26
|
-
import { resolveLoupe, TrialLoupe } from './chunk-
|
|
27
|
-
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LoupeBubble, TrialLoupe, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-
|
|
26
|
+
import { E, w, T, C, g, r6 } from './chunk-W3ECWC2K.js';
|
|
27
|
+
export { N2 as CheckboxRow, M2 as ColorRow, y3 as CurveField, z as EffectCard, V as EffectCardList, c3 as LayerStack, F as NumberRow, H as PropertyGroup, T2 as PropertyList, w2 as PropertyPanel, D as PropertyRow, E2 as PropertySpan, I as SelectRow, A2 as SliderRow, R as Subpanel, P2 as TextRow, L2 as ToggleRow } from './chunk-W3ECWC2K.js';
|
|
28
|
+
import { resolveLoupe, TrialLoupe } from './chunk-TJ7QY3OC.js';
|
|
29
|
+
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LoupeBubble, TrialLoupe, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-TJ7QY3OC.js';
|
|
28
30
|
export { centerOn, zoomAt } from './chunk-CTRKTLYZ.js';
|
|
29
31
|
import { applyCamera } from './chunk-2AYGEN57.js';
|
|
30
32
|
export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from './chunk-2AYGEN57.js';
|
|
31
33
|
export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
|
|
32
|
-
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext,
|
|
33
|
-
import {
|
|
34
|
+
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext, getMarker, getPaintKind, boundsOfPath, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, SCRIPT_METRICS } from '@weasel-js/core';
|
|
35
|
+
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
36
|
+
import { createContext, useState, useRef, useEffect, useContext, useMemo, useId, useCallback, Children, useLayoutEffect, useSyncExternalStore } from 'react';
|
|
34
37
|
import { createPortal } from 'react-dom';
|
|
35
38
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
36
39
|
import { useStore } from 'zustand/react';
|
|
37
40
|
import { asNodeId, Store, createNode, stripStrategy, floatingStrategy, gridStrategy } from 'windease';
|
|
38
41
|
import { Provider, StrategyRegistryProvider, Container, DragProvider, useDragHandle } from 'windease/react';
|
|
39
42
|
|
|
40
|
-
// ../svg/dist/index.js
|
|
41
43
|
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
42
44
|
function multiply(a, b) {
|
|
43
45
|
return [
|
|
@@ -420,20 +422,25 @@ function paintAttrs(paint, name, registry, includeOpacity = true) {
|
|
|
420
422
|
const id = registry.register(paint.paint);
|
|
421
423
|
return [`${name}="url(#${id})"`];
|
|
422
424
|
}
|
|
425
|
+
function strokeWidthAttrs(width) {
|
|
426
|
+
if (typeof width === "number") return [`stroke-width="${trimNumber(width)}"`];
|
|
427
|
+
return [`stroke-width="${trimNumber(width.px)}"`, 'vector-effect="non-scaling-stroke"'];
|
|
428
|
+
}
|
|
423
429
|
function coreStrokeAttrs(stroke, registry) {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
430
|
+
const paint = stroke?.paint;
|
|
431
|
+
if (!stroke || !paint) return [];
|
|
432
|
+
const width = stroke.width ?? 1;
|
|
433
|
+
if (!((typeof width === "object" ? width.px : width) > 0)) return [];
|
|
427
434
|
const attrs = [];
|
|
428
|
-
if ("color" in
|
|
429
|
-
attrs.push(`stroke="${
|
|
430
|
-
if (
|
|
431
|
-
attrs.push(`stroke-opacity="${trimNumber(
|
|
435
|
+
if ("color" in paint) {
|
|
436
|
+
attrs.push(`stroke="${paint.color}"`);
|
|
437
|
+
if (paint.opacity != null && paint.opacity !== 1) {
|
|
438
|
+
attrs.push(`stroke-opacity="${trimNumber(paint.opacity)}"`);
|
|
432
439
|
}
|
|
433
440
|
} else {
|
|
434
|
-
attrs.push(`stroke="url(#${registry.register(
|
|
441
|
+
attrs.push(`stroke="url(#${registry.register(paint)})"`);
|
|
435
442
|
}
|
|
436
|
-
attrs.push(
|
|
443
|
+
attrs.push(...strokeWidthAttrs(width));
|
|
437
444
|
if (stroke.cap) attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
438
445
|
if (stroke.join) attrs.push(`stroke-linejoin="${stroke.join}"`);
|
|
439
446
|
if (stroke.dash && stroke.dash.length > 0) {
|
|
@@ -456,7 +463,7 @@ function coreStrokeAttrs(stroke, registry) {
|
|
|
456
463
|
}
|
|
457
464
|
function strokeAttrsFor(stroke, registry) {
|
|
458
465
|
const attrs = paintAttrs(stroke.paint, "stroke", registry, false);
|
|
459
|
-
attrs.push(
|
|
466
|
+
attrs.push(...strokeWidthAttrs(stroke.width));
|
|
460
467
|
const opacity = stroke.opacity ?? (stroke.paint.kind === "solid" ? stroke.paint.opacity : void 0);
|
|
461
468
|
if (opacity != null && opacity !== 1) {
|
|
462
469
|
attrs.push(`stroke-opacity="${trimNumber(opacity)}"`);
|
|
@@ -549,7 +556,9 @@ function textXml(node, registry, namespaces) {
|
|
|
549
556
|
}
|
|
550
557
|
const decoration = textDecorationValue(style?.underline, style?.strikethrough, style?.overline);
|
|
551
558
|
if (decoration) attrs.push(`text-decoration="${decoration}"`);
|
|
552
|
-
if (node.fill) {
|
|
559
|
+
if (node.fill === null) {
|
|
560
|
+
attrs.push('fill="none"');
|
|
561
|
+
} else if (node.fill) {
|
|
553
562
|
if ("color" in node.fill) {
|
|
554
563
|
attrs.push(`fill="${node.fill.color}"`);
|
|
555
564
|
if (node.fill.opacity != null && node.fill.opacity !== 1) {
|
|
@@ -631,8 +640,6 @@ function pathBounds(path) {
|
|
|
631
640
|
const b = boundsOfPath(path);
|
|
632
641
|
return { minX: b.x, minY: b.y, maxX: b.x + b.width, maxY: b.y + b.height };
|
|
633
642
|
}
|
|
634
|
-
|
|
635
|
-
// src/annotations/paint.ts
|
|
636
643
|
var MARK_COLOR = "#e5484d";
|
|
637
644
|
var MARK_WIDTH = 2;
|
|
638
645
|
var TEXT_SIZE = 14;
|
|
@@ -714,8 +721,8 @@ function seenFrom(config, keys) {
|
|
|
714
721
|
const out = {};
|
|
715
722
|
if (config === null || typeof config !== "object") return out;
|
|
716
723
|
const src = config;
|
|
717
|
-
for (const
|
|
718
|
-
if (
|
|
724
|
+
for (const k of keys) {
|
|
725
|
+
if (k in src) out[k] = src[k];
|
|
719
726
|
}
|
|
720
727
|
return out;
|
|
721
728
|
}
|
|
@@ -723,9 +730,9 @@ function isStale(seen, config, keys) {
|
|
|
723
730
|
if (!seen || keys.length === 0) return false;
|
|
724
731
|
if (config === null || typeof config !== "object") return false;
|
|
725
732
|
const src = config;
|
|
726
|
-
for (const
|
|
727
|
-
if (!(
|
|
728
|
-
if (!Object.is(seen[
|
|
733
|
+
for (const k of keys) {
|
|
734
|
+
if (!(k in seen)) continue;
|
|
735
|
+
if (!Object.is(seen[k], src[k])) return true;
|
|
729
736
|
}
|
|
730
737
|
return false;
|
|
731
738
|
}
|
|
@@ -759,7 +766,7 @@ function toSvgPaint(paint) {
|
|
|
759
766
|
function toSvgStroke(stroke) {
|
|
760
767
|
return {
|
|
761
768
|
paint: toSvgPaint(stroke.paint),
|
|
762
|
-
width:
|
|
769
|
+
width: stroke.width ?? 1,
|
|
763
770
|
...stroke.cap ? { cap: stroke.cap } : {},
|
|
764
771
|
...stroke.join ? { join: stroke.join } : {},
|
|
765
772
|
...stroke.dash ? { dash: [...stroke.dash] } : {},
|
|
@@ -799,7 +806,7 @@ function capturePlan(base, format) {
|
|
|
799
806
|
if (format === "svg") return "svg-document";
|
|
800
807
|
return base?.kind === "svg" ? "svg-document" : "raster-stack";
|
|
801
808
|
}
|
|
802
|
-
function nestBaseSvg(markup, w3,
|
|
809
|
+
function nestBaseSvg(markup, w3, h) {
|
|
803
810
|
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
|
|
804
811
|
const root = doc.documentElement;
|
|
805
812
|
if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
|
|
@@ -808,16 +815,16 @@ function nestBaseSvg(markup, w3, h2) {
|
|
|
808
815
|
root.setAttribute("x", "0");
|
|
809
816
|
root.setAttribute("y", "0");
|
|
810
817
|
root.setAttribute("width", String(w3));
|
|
811
|
-
root.setAttribute("height", String(
|
|
818
|
+
root.setAttribute("height", String(h));
|
|
812
819
|
return new XMLSerializer().serializeToString(root);
|
|
813
820
|
}
|
|
814
|
-
function embedRasterBase(base, w3,
|
|
821
|
+
function embedRasterBase(base, w3, h, onWarn) {
|
|
815
822
|
const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
|
|
816
823
|
if (base.kind === "image" && !href.startsWith("data:")) {
|
|
817
824
|
onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
|
|
818
825
|
}
|
|
819
|
-
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height:
|
|
820
|
-
viewBox: { x: 0, y: 0, width: w3, height:
|
|
826
|
+
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height: h }], {
|
|
827
|
+
viewBox: { x: 0, y: 0, width: w3, height: h }
|
|
821
828
|
});
|
|
822
829
|
}
|
|
823
830
|
function markNodesOf(scene, draw) {
|
|
@@ -833,15 +840,15 @@ function markNodesOf(scene, draw) {
|
|
|
833
840
|
}
|
|
834
841
|
function composeCaptureSvg(args) {
|
|
835
842
|
const { base, scene, draw, scale, onWarn } = args;
|
|
836
|
-
const { w: w3, h
|
|
837
|
-
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3,
|
|
843
|
+
const { w: w3, h } = draw.content;
|
|
844
|
+
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3, h) : embedRasterBase(base, w3, h, onWarn);
|
|
838
845
|
const marksXml = serializeSvg(markNodesOf(scene, draw), {
|
|
839
|
-
viewBox: { x: 0, y: 0, width: w3, height:
|
|
846
|
+
viewBox: { x: 0, y: 0, width: w3, height: h },
|
|
840
847
|
onWarn
|
|
841
848
|
});
|
|
842
849
|
const outW = Math.max(1, Math.round(w3 * scale));
|
|
843
|
-
const outH = Math.max(1, Math.round(
|
|
844
|
-
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${
|
|
850
|
+
const outH = Math.max(1, Math.round(h * scale));
|
|
851
|
+
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${h}">${baseXml}${marksXml}</svg>`;
|
|
845
852
|
}
|
|
846
853
|
function context2d(width, height) {
|
|
847
854
|
const canvas = document.createElement("canvas");
|
|
@@ -960,7 +967,7 @@ function roundFrac(f2) {
|
|
|
960
967
|
function fracContains(box, pt, tol = 0) {
|
|
961
968
|
return pt.x >= box.x - tol && pt.x <= box.x + box.w + tol && pt.y >= box.y - tol && pt.y <= box.y + box.h + tol;
|
|
962
969
|
}
|
|
963
|
-
function
|
|
970
|
+
function fracEncloses(outer, inner) {
|
|
964
971
|
return inner.x >= outer.x && inner.y >= outer.y && inner.x + inner.w <= outer.x + outer.w && inner.y + inner.h <= outer.y + outer.h;
|
|
965
972
|
}
|
|
966
973
|
|
|
@@ -1041,8 +1048,6 @@ function drop(stack, value) {
|
|
|
1041
1048
|
}
|
|
1042
1049
|
}
|
|
1043
1050
|
}
|
|
1044
|
-
|
|
1045
|
-
// src/annotations/store.ts
|
|
1046
1051
|
function createAnnotationScene() {
|
|
1047
1052
|
return createScene({ systemLayers: [{ id: "marks" }] });
|
|
1048
1053
|
}
|
|
@@ -1137,7 +1142,7 @@ function createAnnotationStore(opts) {
|
|
|
1137
1142
|
return marksOn(target).filter((a) => fracContains(a.frac, pt, tol)).reverse();
|
|
1138
1143
|
},
|
|
1139
1144
|
within(target, box) {
|
|
1140
|
-
return marksOn(target).filter((a) =>
|
|
1145
|
+
return marksOn(target).filter((a) => fracEncloses(box, a.frac));
|
|
1141
1146
|
},
|
|
1142
1147
|
isStale(a, config) {
|
|
1143
1148
|
const keys = targetOf(a.target)?.positionDependsOn ?? [];
|
|
@@ -1430,6 +1435,9 @@ function AnnotationTargets({
|
|
|
1430
1435
|
}
|
|
1431
1436
|
|
|
1432
1437
|
// src/config/builder.ts
|
|
1438
|
+
function isConfigBranch(entry) {
|
|
1439
|
+
return "children" in entry;
|
|
1440
|
+
}
|
|
1433
1441
|
var BaseNode = class {
|
|
1434
1442
|
constructor(defaultValue, annotations = {}, options = {}) {
|
|
1435
1443
|
this.annotations = annotations;
|
|
@@ -1469,9 +1477,10 @@ var BaseNode = class {
|
|
|
1469
1477
|
pair(pair) {
|
|
1470
1478
|
return this.ann({ pair });
|
|
1471
1479
|
}
|
|
1472
|
-
/** Render under a named section heading.
|
|
1473
|
-
section
|
|
1474
|
-
|
|
1480
|
+
/** Render under a named section heading. `collapsed` opens the section
|
|
1481
|
+
* folded — say it on any one of the section's leaves. */
|
|
1482
|
+
section(label, opts = {}) {
|
|
1483
|
+
return this.opt({ section: { label, ...opts } });
|
|
1475
1484
|
}
|
|
1476
1485
|
/** Show this row only while the predicate holds. Presentational — the value
|
|
1477
1486
|
* stays in config and the instrument still reads it. */
|
|
@@ -1555,6 +1564,45 @@ var CustomNode = class _CustomNode extends BaseNode {
|
|
|
1555
1564
|
return new _CustomNode(this.kind, this.default, annotations, options);
|
|
1556
1565
|
}
|
|
1557
1566
|
};
|
|
1567
|
+
var GroupNode = class _GroupNode {
|
|
1568
|
+
constructor(children, annotations = {}, options = {}) {
|
|
1569
|
+
this.children = children;
|
|
1570
|
+
this.annotations = annotations;
|
|
1571
|
+
this.options = options;
|
|
1572
|
+
}
|
|
1573
|
+
children;
|
|
1574
|
+
annotations;
|
|
1575
|
+
options;
|
|
1576
|
+
with(annotations, options) {
|
|
1577
|
+
return new _GroupNode(this.children, annotations, options);
|
|
1578
|
+
}
|
|
1579
|
+
/** Heading for the group's rows. Defaults to the key, title-cased. */
|
|
1580
|
+
label(name) {
|
|
1581
|
+
return this.with({ ...this.annotations, name }, this.options);
|
|
1582
|
+
}
|
|
1583
|
+
/** Longer help text. Carried on the resolved `PrefGroup`, where weasel-ui's
|
|
1584
|
+
* `PrefsForm` draws it under the heading; `ControlPanel` has no place for
|
|
1585
|
+
* it yet and shows the heading alone. */
|
|
1586
|
+
describe(description) {
|
|
1587
|
+
return this.with({ ...this.annotations, description }, this.options);
|
|
1588
|
+
}
|
|
1589
|
+
/** Render this whole group under a named section heading. */
|
|
1590
|
+
section(label, opts = {}) {
|
|
1591
|
+
return this.with(this.annotations, { ...this.options, section: { label, ...opts } });
|
|
1592
|
+
}
|
|
1593
|
+
/** Show this group only while the predicate holds. Presentational — every
|
|
1594
|
+
* value beneath it stays in config and the instrument still reads it. */
|
|
1595
|
+
showIf(predicate) {
|
|
1596
|
+
return this.with(this.annotations, { ...this.options, showIf: predicate });
|
|
1597
|
+
}
|
|
1598
|
+
};
|
|
1599
|
+
function shapeDefaults(shape) {
|
|
1600
|
+
const out = {};
|
|
1601
|
+
for (const [key, entry] of Object.entries(shape)) {
|
|
1602
|
+
out[key] = isConfigBranch(entry) ? shapeDefaults(entry.children) : entry.default;
|
|
1603
|
+
}
|
|
1604
|
+
return out;
|
|
1605
|
+
}
|
|
1558
1606
|
var expand = (options) => options.map((o) => typeof o === "string" ? { value: o, label: o } : o);
|
|
1559
1607
|
var f = {
|
|
1560
1608
|
number: (def) => new NumberNode(def),
|
|
@@ -1568,18 +1616,15 @@ var f = {
|
|
|
1568
1616
|
/** A leaf with no declared kind: the rule chain decides, which is how a lab
|
|
1569
1617
|
* states a convention like "every `*Color` key is a color picker". */
|
|
1570
1618
|
value: (def) => new ValueNode(def),
|
|
1619
|
+
/** A branch: its children nest under this key, so `grid: f.group({ size })`
|
|
1620
|
+
* puts the value at `config.grid.size` and addresses it as `'grid.size'`.
|
|
1621
|
+
* Groups nest as deeply as the schema wants. */
|
|
1622
|
+
group: (children) => new GroupNode(children),
|
|
1571
1623
|
/** A leaf of a kind a lab supplies the control for, through `controls`. */
|
|
1572
1624
|
custom: (kind, def, validate) => new CustomNode(kind, def, {}, validate ? { validate } : {}),
|
|
1573
|
-
/** Collect leaves into an instrument's config. */
|
|
1625
|
+
/** Collect leaves and groups into an instrument's config. */
|
|
1574
1626
|
schema(nodes) {
|
|
1575
|
-
return {
|
|
1576
|
-
nodes,
|
|
1577
|
-
defaults: () => {
|
|
1578
|
-
const out = {};
|
|
1579
|
-
for (const [key, node] of Object.entries(nodes)) out[key] = node.default;
|
|
1580
|
-
return out;
|
|
1581
|
-
}
|
|
1582
|
-
};
|
|
1627
|
+
return { nodes, defaults: () => shapeDefaults(nodes) };
|
|
1583
1628
|
}
|
|
1584
1629
|
};
|
|
1585
1630
|
|
|
@@ -1611,9 +1656,9 @@ function applyRules(seed, ctx, rules) {
|
|
|
1611
1656
|
for (const rule of rules) {
|
|
1612
1657
|
const patch = rule({ ...ctx, leaf: acc });
|
|
1613
1658
|
if (patch === null) continue;
|
|
1614
|
-
for (const [
|
|
1615
|
-
if (v !== void 0 && acc[
|
|
1616
|
-
acc[
|
|
1659
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
1660
|
+
if (v !== void 0 && acc[k] === void 0) {
|
|
1661
|
+
acc[k] = v;
|
|
1617
1662
|
}
|
|
1618
1663
|
}
|
|
1619
1664
|
}
|
|
@@ -1623,40 +1668,59 @@ function applyRules(seed, ctx, rules) {
|
|
|
1623
1668
|
// src/config/resolve.ts
|
|
1624
1669
|
function defined(annotations) {
|
|
1625
1670
|
const out = {};
|
|
1626
|
-
for (const [
|
|
1671
|
+
for (const [k, v] of Object.entries(annotations)) if (v !== void 0) out[k] = v;
|
|
1627
1672
|
return out;
|
|
1628
1673
|
}
|
|
1629
1674
|
function resolveConfigSchema(schema, rules = []) {
|
|
1675
|
+
const sink = {
|
|
1676
|
+
sections: [],
|
|
1677
|
+
showIf: /* @__PURE__ */ new Map(),
|
|
1678
|
+
renderers: {},
|
|
1679
|
+
chain: [...rules, ...builtinRules]
|
|
1680
|
+
};
|
|
1681
|
+
const group = resolveShape(schema.nodes, "", "", sink);
|
|
1682
|
+
return { group, sections: sink.sections, showIf: sink.showIf, renderers: sink.renderers };
|
|
1683
|
+
}
|
|
1684
|
+
function resolveShape(shape, at, name, sink) {
|
|
1630
1685
|
const children = {};
|
|
1631
|
-
const
|
|
1632
|
-
const
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
for (const [key, node] of Object.entries(schema.nodes)) {
|
|
1637
|
-
const seed = defined({
|
|
1638
|
-
...node.annotations,
|
|
1639
|
-
...node.kind === null ? {} : { kind: node.kind }
|
|
1640
|
-
});
|
|
1641
|
-
const patch = applyRules(seed, { key, path: key, default: node.default }, chain2);
|
|
1642
|
-
children[key] = { ...patch, default: node.default };
|
|
1643
|
-
const { section, showIf: predicate, render } = node.options;
|
|
1686
|
+
const sections = /* @__PURE__ */ new Map();
|
|
1687
|
+
for (const [key, entry] of Object.entries(shape)) {
|
|
1688
|
+
const path = at === "" ? key : `${at}.${key}`;
|
|
1689
|
+
children[key] = resolveEntry(entry, key, path, sink);
|
|
1690
|
+
const { section, showIf: predicate } = entry.options;
|
|
1644
1691
|
if (section !== void 0) {
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1692
|
+
let spec = sections.get(section.label);
|
|
1693
|
+
if (!spec) {
|
|
1694
|
+
spec = { at, label: section.label, paths: [] };
|
|
1695
|
+
sections.set(section.label, spec);
|
|
1696
|
+
sink.sections.push(spec);
|
|
1697
|
+
}
|
|
1698
|
+
spec.paths.push(path);
|
|
1699
|
+
if (section.collapsed !== void 0) {
|
|
1700
|
+
spec.collapsed = (spec.collapsed ?? false) || section.collapsed;
|
|
1648
1701
|
}
|
|
1649
|
-
sectionPaths.get(section)?.push(key);
|
|
1650
1702
|
}
|
|
1651
|
-
if (predicate) showIf.set(
|
|
1652
|
-
if (render) renderers[
|
|
1703
|
+
if (predicate) sink.showIf.set(path, predicate);
|
|
1704
|
+
if (!isConfigBranch(entry) && entry.options.render) sink.renderers[path] = entry.options.render;
|
|
1705
|
+
}
|
|
1706
|
+
return { name, children };
|
|
1707
|
+
}
|
|
1708
|
+
function resolveEntry(entry, key, path, sink) {
|
|
1709
|
+
if (isConfigBranch(entry)) {
|
|
1710
|
+
const group = resolveShape(
|
|
1711
|
+
entry.children,
|
|
1712
|
+
path,
|
|
1713
|
+
entry.annotations.name ?? titleCase(key),
|
|
1714
|
+
sink
|
|
1715
|
+
);
|
|
1716
|
+
return entry.annotations.description === void 0 ? group : { ...group, description: entry.annotations.description };
|
|
1653
1717
|
}
|
|
1654
|
-
const
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
})
|
|
1659
|
-
return {
|
|
1718
|
+
const seed = defined({
|
|
1719
|
+
...entry.annotations,
|
|
1720
|
+
...entry.kind === null ? {} : { kind: entry.kind }
|
|
1721
|
+
});
|
|
1722
|
+
const patch = applyRules(seed, { key, path, default: entry.default }, sink.chain);
|
|
1723
|
+
return { ...patch, default: entry.default };
|
|
1660
1724
|
}
|
|
1661
1725
|
var LabContext = createContext(null);
|
|
1662
1726
|
function useLabContext() {
|
|
@@ -1736,7 +1800,7 @@ function validateConfigSchema(fields) {
|
|
|
1736
1800
|
return { valid: errors.length === 0, errors };
|
|
1737
1801
|
}
|
|
1738
1802
|
|
|
1739
|
-
// ../theme/dist/chunk-
|
|
1803
|
+
// ../theme/dist/chunk-D6AFL2JW.js
|
|
1740
1804
|
var THEME_SOURCES = {
|
|
1741
1805
|
"weasel": {
|
|
1742
1806
|
"primitives": {
|
|
@@ -1965,15 +2029,15 @@ var THEME_SOURCES = {
|
|
|
1965
2029
|
"value": "8px",
|
|
1966
2030
|
"description": "Diameter of a linear range thumb."
|
|
1967
2031
|
},
|
|
1968
|
-
"slider-track-
|
|
2032
|
+
"slider-track-mix": {
|
|
1969
2033
|
"type": "dimension",
|
|
1970
2034
|
"value": "18%",
|
|
1971
|
-
"description": "Accent proportion in a range track. Mixed into a real property, never into another custom property."
|
|
2035
|
+
"description": "Accent proportion in a range track, as a color-mix percentage \u2014 not a color. Mixed into a real property, never into another custom property."
|
|
1972
2036
|
},
|
|
1973
|
-
"slider-thumb-
|
|
2037
|
+
"slider-thumb-mix": {
|
|
1974
2038
|
"type": "dimension",
|
|
1975
2039
|
"value": "70%",
|
|
1976
|
-
"description": "Accent proportion in a range thumb."
|
|
2040
|
+
"description": "Accent proportion in a range thumb, as a color-mix percentage \u2014 not a color."
|
|
1977
2041
|
},
|
|
1978
2042
|
"field-pad-x": {
|
|
1979
2043
|
"type": "dimension",
|
|
@@ -2304,9 +2368,9 @@ function hexToRgba(hex, alpha) {
|
|
|
2304
2368
|
const body = m[1];
|
|
2305
2369
|
const full = body.length === 3 ? body.replace(/./g, (c2) => c2 + c2) : body;
|
|
2306
2370
|
const r2 = Number.parseInt(full.slice(0, 2), 16);
|
|
2307
|
-
const
|
|
2371
|
+
const g2 = Number.parseInt(full.slice(2, 4), 16);
|
|
2308
2372
|
const b = Number.parseInt(full.slice(4, 6), 16);
|
|
2309
|
-
return `rgba(${r2}, ${
|
|
2373
|
+
return `rgba(${r2}, ${g2}, ${b}, ${alpha})`;
|
|
2310
2374
|
}
|
|
2311
2375
|
var REF = /^\{([^}]+)\}$/;
|
|
2312
2376
|
function refTarget(value) {
|
|
@@ -2444,6 +2508,25 @@ function useThemeOptional() {
|
|
|
2444
2508
|
return useContext(ThemeContext);
|
|
2445
2509
|
}
|
|
2446
2510
|
|
|
2511
|
+
// src/instrument/serializers.ts
|
|
2512
|
+
function configDefaultsOf(instruments) {
|
|
2513
|
+
const out = {};
|
|
2514
|
+
for (const instrument of instruments) out[instrument.name] = () => instrument.defaultConfig();
|
|
2515
|
+
return out;
|
|
2516
|
+
}
|
|
2517
|
+
function serializersOf(instruments) {
|
|
2518
|
+
const out = {};
|
|
2519
|
+
for (const instrument of instruments) {
|
|
2520
|
+
const { name, serialize: serialize2, deserialize } = instrument;
|
|
2521
|
+
if (!serialize2 && !deserialize) continue;
|
|
2522
|
+
out[name] = {
|
|
2523
|
+
...serialize2 ? { serialize: (state) => serialize2(state) } : {},
|
|
2524
|
+
...deserialize ? { deserialize: (data, config) => deserialize(data, config) } : {}
|
|
2525
|
+
};
|
|
2526
|
+
}
|
|
2527
|
+
return out;
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2447
2530
|
// ../theme/dist/index.js
|
|
2448
2531
|
var ALPHA_EXT = "com.weasel.alpha";
|
|
2449
2532
|
var isToken = (v) => typeof v === "object" && v !== null && "$value" in v;
|
|
@@ -2452,9 +2535,9 @@ function flattenTokens(doc) {
|
|
|
2452
2535
|
for (const [groupName, group] of Object.entries(doc)) {
|
|
2453
2536
|
if (groupName.startsWith("$")) continue;
|
|
2454
2537
|
if (typeof group !== "object" || group === null) continue;
|
|
2455
|
-
const
|
|
2456
|
-
const groupType =
|
|
2457
|
-
for (const [leaf, node] of Object.entries(
|
|
2538
|
+
const g2 = group;
|
|
2539
|
+
const groupType = g2.$type;
|
|
2540
|
+
for (const [leaf, node] of Object.entries(g2)) {
|
|
2458
2541
|
if (leaf.startsWith("$")) continue;
|
|
2459
2542
|
if (!isToken(node)) continue;
|
|
2460
2543
|
const type = node.$type ?? groupType;
|
|
@@ -2792,9 +2875,9 @@ function TrialChrome({
|
|
|
2792
2875
|
const title = record.title ?? record.instrumentName;
|
|
2793
2876
|
const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
|
|
2794
2877
|
const ctx = useMemo(() => {
|
|
2795
|
-
const setZoom = (
|
|
2878
|
+
const setZoom = (z2) => {
|
|
2796
2879
|
if (!view2d) return;
|
|
2797
|
-
updateTrialView(trialId, { ...view2d, zoom:
|
|
2880
|
+
updateTrialView(trialId, { ...view2d, zoom: z2 });
|
|
2798
2881
|
};
|
|
2799
2882
|
return {
|
|
2800
2883
|
trialId,
|
|
@@ -2813,16 +2896,16 @@ function TrialChrome({
|
|
|
2813
2896
|
configSchema,
|
|
2814
2897
|
configFields: instrument.config ? [] : instrument.configSchema?.() ?? [],
|
|
2815
2898
|
config: record.config,
|
|
2816
|
-
setConfig: (
|
|
2899
|
+
setConfig: (path, value) => {
|
|
2817
2900
|
const prevConfig = record.config;
|
|
2818
|
-
if (process.env.NODE_ENV !== "production" && !(
|
|
2901
|
+
if (process.env.NODE_ENV !== "production" && !hasConfigPath(prevConfig, path) && schemaNodeAtPath(configSchema.group, path) === void 0) {
|
|
2819
2902
|
console.warn(
|
|
2820
|
-
`[labkit] setConfig: unknown
|
|
2903
|
+
`[labkit] setConfig: unknown path "${path}" for instrument "${record.instrumentName}"`
|
|
2821
2904
|
);
|
|
2822
2905
|
}
|
|
2823
|
-
updateTrialConfig(trialId,
|
|
2906
|
+
updateTrialConfig(trialId, path, value);
|
|
2824
2907
|
if (instrument.onConfigChange) {
|
|
2825
|
-
const nextConfig =
|
|
2908
|
+
const nextConfig = withValueAtPath(prevConfig, path, value);
|
|
2826
2909
|
const nextState = instrument.onConfigChange(nextConfig, prevConfig, record.state);
|
|
2827
2910
|
updateTrialState(trialId, nextState);
|
|
2828
2911
|
}
|
|
@@ -3086,11 +3169,11 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3086
3169
|
updateTrialState(record.id, next);
|
|
3087
3170
|
bus.emit("state.change");
|
|
3088
3171
|
},
|
|
3089
|
-
setConfig: (
|
|
3090
|
-
const evt = `config.change:${
|
|
3172
|
+
setConfig: (path, value) => {
|
|
3173
|
+
const evt = `config.change:${path}`;
|
|
3091
3174
|
snapshotIfNeeded("config.change");
|
|
3092
3175
|
snapshotIfNeeded(evt);
|
|
3093
|
-
updateTrialConfig(record.id,
|
|
3176
|
+
updateTrialConfig(record.id, path, value);
|
|
3094
3177
|
bus.emit("config.change");
|
|
3095
3178
|
bus.emit(evt);
|
|
3096
3179
|
},
|
|
@@ -3099,9 +3182,9 @@ function TrialRuntime({ record, instrument, store, isLast, chrome, suppress }) {
|
|
|
3099
3182
|
view: record.view,
|
|
3100
3183
|
setView,
|
|
3101
3184
|
zoom: view2d?.zoom ?? 1,
|
|
3102
|
-
setZoom: (
|
|
3185
|
+
setZoom: (z2) => {
|
|
3103
3186
|
if (!view2d) return;
|
|
3104
|
-
updateTrialView(record.id, { ...view2d, zoom:
|
|
3187
|
+
updateTrialView(record.id, { ...view2d, zoom: z2 });
|
|
3105
3188
|
},
|
|
3106
3189
|
activeToolId: resolvedToolId,
|
|
3107
3190
|
visibleLayers
|
|
@@ -3335,19 +3418,14 @@ function initialView(instrument) {
|
|
|
3335
3418
|
return declared ? structuredClone(declared) : { ...DEFAULT_VIEW2, pan: { ...DEFAULT_VIEW2.pan } };
|
|
3336
3419
|
}
|
|
3337
3420
|
function seedConfig(defaults, seed) {
|
|
3338
|
-
|
|
3339
|
-
const out = { ...defaults };
|
|
3340
|
-
for (const [key, value] of Object.entries(seed)) {
|
|
3341
|
-
if (value !== void 0) out[key] = value;
|
|
3342
|
-
}
|
|
3343
|
-
return out;
|
|
3421
|
+
return seed ? fillConfigDefaults(seed, defaults) : defaults;
|
|
3344
3422
|
}
|
|
3345
3423
|
function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
3346
3424
|
const instrument = findInstrument(instruments, instrumentName);
|
|
3347
3425
|
const config = seedConfig(instrument.defaultConfig(), options.config);
|
|
3348
3426
|
const state = instrument.initialState(config);
|
|
3349
3427
|
const record = {
|
|
3350
|
-
id:
|
|
3428
|
+
id: newId(),
|
|
3351
3429
|
instrumentName,
|
|
3352
3430
|
config,
|
|
3353
3431
|
state,
|
|
@@ -3363,7 +3441,7 @@ function cloneTrial(trials, id) {
|
|
|
3363
3441
|
if (!source) return trials;
|
|
3364
3442
|
const clone = {
|
|
3365
3443
|
...source,
|
|
3366
|
-
id:
|
|
3444
|
+
id: newId(),
|
|
3367
3445
|
config: structuredClone(source.config),
|
|
3368
3446
|
state: structuredClone(source.state),
|
|
3369
3447
|
view: structuredClone(source.view),
|
|
@@ -3427,7 +3505,7 @@ function LabHeader() {
|
|
|
3427
3505
|
// Held at null so the control stays an "add one" action rather than
|
|
3428
3506
|
// reading as the current instrument.
|
|
3429
3507
|
/* @__PURE__ */ jsx(
|
|
3430
|
-
|
|
3508
|
+
g,
|
|
3431
3509
|
{
|
|
3432
3510
|
className: "lk-lab-header__add-select",
|
|
3433
3511
|
"aria-label": "Add trial",
|
|
@@ -3441,7 +3519,7 @@ function LabHeader() {
|
|
|
3441
3519
|
)
|
|
3442
3520
|
),
|
|
3443
3521
|
/* @__PURE__ */ jsx(
|
|
3444
|
-
|
|
3522
|
+
r6,
|
|
3445
3523
|
{
|
|
3446
3524
|
className: "lk-lab-header__mode",
|
|
3447
3525
|
ariaLabel: "Color mode",
|
|
@@ -3473,6 +3551,67 @@ function LabPalette({ tools }) {
|
|
|
3473
3551
|
};
|
|
3474
3552
|
return /* @__PURE__ */ jsx(PaletteRegion, { contributions, ctx });
|
|
3475
3553
|
}
|
|
3554
|
+
function currentPage(path, pages) {
|
|
3555
|
+
const here = path.split("?")[0].split("#")[0].replace(/\/$/, "").replace(/\.html$/, "");
|
|
3556
|
+
return pages.findIndex((p) => here.endsWith(p.href.replace(/\.html$/, "")));
|
|
3557
|
+
}
|
|
3558
|
+
function LabSwitcher({ title, pages, path, className }) {
|
|
3559
|
+
const [open, setOpen] = useState(false);
|
|
3560
|
+
const root = useRef(null);
|
|
3561
|
+
const menuId = useId();
|
|
3562
|
+
const here = currentPage(path ?? (typeof window === "undefined" ? "" : window.location.pathname), pages);
|
|
3563
|
+
const close = useCallback(() => setOpen(false), []);
|
|
3564
|
+
useEffect(() => {
|
|
3565
|
+
if (!open) return;
|
|
3566
|
+
const onKey = (e) => {
|
|
3567
|
+
if (e.key === "Escape") {
|
|
3568
|
+
close();
|
|
3569
|
+
root.current?.querySelector("button")?.focus();
|
|
3570
|
+
}
|
|
3571
|
+
};
|
|
3572
|
+
const onDown = (e) => {
|
|
3573
|
+
if (!root.current?.contains(e.target)) close();
|
|
3574
|
+
};
|
|
3575
|
+
document.addEventListener("keydown", onKey);
|
|
3576
|
+
document.addEventListener("pointerdown", onDown);
|
|
3577
|
+
return () => {
|
|
3578
|
+
document.removeEventListener("keydown", onKey);
|
|
3579
|
+
document.removeEventListener("pointerdown", onDown);
|
|
3580
|
+
};
|
|
3581
|
+
}, [open, close]);
|
|
3582
|
+
if (pages.length < 2) {
|
|
3583
|
+
return /* @__PURE__ */ jsx("h1", { className: `lk-switcher-title${className ? ` ${className}` : ""}`, children: title });
|
|
3584
|
+
}
|
|
3585
|
+
return /* @__PURE__ */ jsxs("div", { className: `lk-switcher${className ? ` ${className}` : ""}`, ref: root, children: [
|
|
3586
|
+
/* @__PURE__ */ jsx("h1", { className: "lk-switcher-title", children: /* @__PURE__ */ jsxs(
|
|
3587
|
+
"button",
|
|
3588
|
+
{
|
|
3589
|
+
type: "button",
|
|
3590
|
+
className: "lk-switcher-trigger",
|
|
3591
|
+
"aria-expanded": open,
|
|
3592
|
+
"aria-haspopup": "menu",
|
|
3593
|
+
"aria-controls": open ? menuId : void 0,
|
|
3594
|
+
onClick: () => setOpen((was) => !was),
|
|
3595
|
+
children: [
|
|
3596
|
+
title,
|
|
3597
|
+
/* @__PURE__ */ jsx("span", { className: "lk-switcher-caret", "aria-hidden": "true" })
|
|
3598
|
+
]
|
|
3599
|
+
}
|
|
3600
|
+
) }),
|
|
3601
|
+
open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i) => /* @__PURE__ */ jsx(
|
|
3602
|
+
"a",
|
|
3603
|
+
{
|
|
3604
|
+
href: page.href,
|
|
3605
|
+
role: "menuitem",
|
|
3606
|
+
className: "lk-switcher-item",
|
|
3607
|
+
"aria-current": i === here ? "page" : void 0,
|
|
3608
|
+
onClick: close,
|
|
3609
|
+
children: page.label
|
|
3610
|
+
},
|
|
3611
|
+
page.href
|
|
3612
|
+
)) })
|
|
3613
|
+
] });
|
|
3614
|
+
}
|
|
3476
3615
|
function query() {
|
|
3477
3616
|
if (typeof window === "undefined" || !window.matchMedia) return null;
|
|
3478
3617
|
return window.matchMedia("(prefers-color-scheme: light)");
|
|
@@ -3491,17 +3630,37 @@ function useResolvedMode(mode) {
|
|
|
3491
3630
|
}, [mode]);
|
|
3492
3631
|
return mode === "auto" ? system : mode;
|
|
3493
3632
|
}
|
|
3494
|
-
function LabShell({
|
|
3633
|
+
function LabShell({
|
|
3634
|
+
title,
|
|
3635
|
+
children,
|
|
3636
|
+
header,
|
|
3637
|
+
footer,
|
|
3638
|
+
mode = "auto",
|
|
3639
|
+
pages,
|
|
3640
|
+
path
|
|
3641
|
+
}) {
|
|
3495
3642
|
const resolved = useResolvedMode(mode);
|
|
3496
3643
|
const outer = useThemeOptional();
|
|
3497
|
-
const shell =
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3644
|
+
const shell = (
|
|
3645
|
+
// Overlays portal here rather than to the themed wrapper above: `.lk-root`
|
|
3646
|
+
// carries the element defaults a lab's bare markup is styled by.
|
|
3647
|
+
/* @__PURE__ */ jsxs("div", { className: "lk-root lk-shell", "data-wzl-portal-host": "", children: [
|
|
3648
|
+
/* @__PURE__ */ jsxs("header", { className: "lk-shell-header", children: [
|
|
3649
|
+
pages && pages.length > 0 ? /* @__PURE__ */ jsx(
|
|
3650
|
+
LabSwitcher,
|
|
3651
|
+
{
|
|
3652
|
+
title,
|
|
3653
|
+
pages,
|
|
3654
|
+
path,
|
|
3655
|
+
className: "lk-shell-title"
|
|
3656
|
+
}
|
|
3657
|
+
) : /* @__PURE__ */ jsx("h1", { className: "lk-shell-title", children: title }),
|
|
3658
|
+
header && /* @__PURE__ */ jsx("div", { className: "lk-shell-header-actions", children: header })
|
|
3659
|
+
] }),
|
|
3660
|
+
/* @__PURE__ */ jsx("main", { className: "lk-shell-body", children }),
|
|
3661
|
+
footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
|
|
3662
|
+
] })
|
|
3663
|
+
);
|
|
3505
3664
|
return outer ? shell : /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, mode: resolved, children: shell });
|
|
3506
3665
|
}
|
|
3507
3666
|
var ZONE_ID2 = asNodeId("lk-workspace");
|
|
@@ -3657,7 +3816,13 @@ function Workspace({
|
|
|
3657
3816
|
) : reorderable ? /* @__PURE__ */ jsx(DragProvider, { children: grid }) : grid }) });
|
|
3658
3817
|
}
|
|
3659
3818
|
function buildStore(instruments, defaultInstrument, storage, storageKey, initialMode) {
|
|
3660
|
-
const store = createLabStore({
|
|
3819
|
+
const store = createLabStore({
|
|
3820
|
+
storageKey,
|
|
3821
|
+
storage,
|
|
3822
|
+
initialMode,
|
|
3823
|
+
serializers: serializersOf(instruments),
|
|
3824
|
+
configDefaults: configDefaultsOf(instruments)
|
|
3825
|
+
});
|
|
3661
3826
|
if (store.getState().trials.length === 0) {
|
|
3662
3827
|
const seeded = addTrial([], instruments, defaultInstrument);
|
|
3663
3828
|
const record = seeded[0];
|
|
@@ -3730,11 +3895,11 @@ function Lab({
|
|
|
3730
3895
|
const c2 = ownCanvasRef.current;
|
|
3731
3896
|
if (!c2) return;
|
|
3732
3897
|
const w3 = Math.round(frame.size.width * frame.dpr);
|
|
3733
|
-
const
|
|
3734
|
-
if (bufferRef.current.w === w3 && bufferRef.current.h ===
|
|
3735
|
-
bufferRef.current = { w: w3, h
|
|
3898
|
+
const h = Math.round(frame.size.height * frame.dpr);
|
|
3899
|
+
if (bufferRef.current.w === w3 && bufferRef.current.h === h) return;
|
|
3900
|
+
bufferRef.current = { w: w3, h };
|
|
3736
3901
|
c2.width = w3;
|
|
3737
|
-
c2.height =
|
|
3902
|
+
c2.height = h;
|
|
3738
3903
|
c2.style.width = `${frame.size.width}px`;
|
|
3739
3904
|
c2.style.height = `${frame.size.height}px`;
|
|
3740
3905
|
surfaceRef.current?.invalidateAll();
|
|
@@ -3874,6 +4039,6 @@ function Lab({
|
|
|
3874
4039
|
) }) });
|
|
3875
4040
|
}
|
|
3876
4041
|
|
|
3877
|
-
export { AnnotationOverlay, AnnotationTargets, DEFAULT_VIEW, Lab, LabContext, LabPalette, LabShell, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, applyRules, as2DView, builtinRules, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, defineInstrument, f, fitView, fracContains,
|
|
4042
|
+
export { AnnotationOverlay, AnnotationTargets, DEFAULT_VIEW, Lab, LabContext, LabPalette, LabShell, LabSwitcher, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationsFromJSON, applyRules, as2DView, builtinRules, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, f, fitView, fracContains, fracEncloses, fracToWorld, fromWeaselView, interstellarTheme, isConfigBranch, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveConfigSchema, resolveMarkStyle, roundFrac, seenFrom, titleCase, toWeaselView, useConfigSchema, useLabContext, validateConfigSchema, worldToFrac };
|
|
3878
4043
|
//# sourceMappingURL=index.js.map
|
|
3879
4044
|
//# sourceMappingURL=index.js.map
|