@weasel-js/labkit 1.5.0 → 1.5.2
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 +41 -4
- package/dist/_dts/{CanvasStackContext-CqkxkFJW.d.ts → CanvasStackContext-CMMo180l.d.ts} +1 -1
- package/dist/_dts/{PrefsForm.d-DDHFANkc.d.ts → PrefsForm.d-DPy9I8It.d.ts} +4 -0
- package/dist/_dts/Select.d-ZTiwzYyT.d.ts +479 -0
- package/dist/_dts/{frac-8R6UmlvN.d.ts → frac-B4hFJMiN.d.ts} +54 -6
- package/dist/_dts/{index-retnAut7.d.ts → index-8LiKe3A-.d.ts} +77 -10
- package/dist/_dts/{index-B8uu2ba7.d.ts → index-DlKolEIZ.d.ts} +20 -8
- package/dist/_dts/{types-Ca2LCnPq.d.ts → types-Db-3NNk1.d.ts} +28 -4
- package/dist/_dts/{usePanZoom-nS798rOF.d.ts → usePanZoom-SSTZe410.d.ts} +4 -47
- package/dist/_dts/{useTrialState-jcx_TdU6.d.ts → useTrialState-pnAE-UBD.d.ts} +1 -1
- package/dist/canvas/index.d.ts +5 -5
- package/dist/canvas/index.js +1 -1
- package/dist/chrome/index.d.ts +4 -4
- package/dist/chrome/index.js +7 -7
- package/dist/chunk-6BUQ77ZV.js +18 -0
- package/dist/chunk-6BUQ77ZV.js.map +1 -0
- package/dist/{chunk-KJALCDWE.js → chunk-753Y6HE6.js} +9 -9
- package/dist/chunk-753Y6HE6.js.map +1 -0
- package/dist/{chunk-6ZDGOZQV.js → chunk-A2ACAGW6.js} +72 -20
- package/dist/chunk-A2ACAGW6.js.map +1 -0
- package/dist/{chunk-NS64DXMN.js → chunk-CKUKF72R.js} +44 -21
- package/dist/chunk-CKUKF72R.js.map +1 -0
- package/dist/{chunk-MUKOW3TC.js → chunk-D35PFTS7.js} +4 -4
- package/dist/{chunk-MUKOW3TC.js.map → chunk-D35PFTS7.js.map} +1 -1
- package/dist/{chunk-UU3NJO6N.js → chunk-EMXAIRUJ.js} +3 -3
- package/dist/{chunk-UU3NJO6N.js.map → chunk-EMXAIRUJ.js.map} +1 -1
- package/dist/{chunk-ZPH5WTWF.js → chunk-ERFMC6WU.js} +142 -66
- package/dist/chunk-ERFMC6WU.js.map +1 -0
- package/dist/chunk-FKLT3ITC.js +590 -0
- package/dist/chunk-FKLT3ITC.js.map +1 -0
- package/dist/{chunk-QLSV2N3G.js → chunk-IJJUK4FU.js} +25 -13
- package/dist/chunk-IJJUK4FU.js.map +1 -0
- package/dist/{chunk-EKIICY6X.js → chunk-KJCUERQF.js} +37 -25
- package/dist/chunk-KJCUERQF.js.map +1 -0
- package/dist/chunk-LASCBWW7.js +13456 -0
- package/dist/chunk-LASCBWW7.js.map +1 -0
- package/dist/{chunk-67SJLMC7.js → chunk-LRI3MBGR.js} +45 -12
- package/dist/chunk-LRI3MBGR.js.map +1 -0
- package/dist/chunk-REOBGYMC.js +150 -0
- package/dist/chunk-REOBGYMC.js.map +1 -0
- package/dist/{chunk-PGETSEDK.js → chunk-TT5C5S6R.js} +11 -90
- package/dist/chunk-TT5C5S6R.js.map +1 -0
- package/dist/{chunk-NDRYLVOW.js → chunk-Z76KEZAX.js} +2 -2
- package/dist/chunk-Z76KEZAX.js.map +1 -0
- package/dist/config/index.d.ts +62 -19
- package/dist/config/index.js +6 -4
- package/dist/controls/index.d.ts +3 -3
- package/dist/controls/index.js +4 -4
- package/dist/dragdrop/index.d.ts +3 -3
- package/dist/index.d.ts +230 -62
- package/dist/index.js +1367 -1698
- package/dist/index.js.map +1 -1
- package/dist/layers/index.d.ts +4 -4
- package/dist/layers/index.js +2 -2
- package/dist/loupe/index.d.ts +67 -16
- package/dist/loupe/index.js +1 -1
- package/dist/passthrough/weasel-ui.d.ts +57 -230
- package/dist/passthrough/weasel-ui.js +1 -1
- package/dist/primitives/index.d.ts +3 -1
- package/dist/primitives/index.js +3 -3
- package/dist/state/index.d.ts +5 -5
- package/dist/state/index.js +5 -3
- package/dist/state/index.js.map +1 -1
- package/dist/styles.css +266 -57
- package/dist/surface/index.js +1 -1
- package/dist/ui/layers/index.js +1 -1
- package/dist/undo/index.d.ts +3 -3
- package/package.json +9 -9
- package/src/annotations/AnnotationOverlay.tsx +3 -0
- package/src/annotations/Annotations.less +4 -0
- package/src/annotations/Annotations.overlay.test.tsx +20 -0
- package/src/annotations/svgNodes.ts +1 -0
- package/src/annotations/toolMap.test.ts +9 -5
- package/src/annotations/toolMap.ts +3 -0
- package/src/canvas/CanvasStack.stories.tsx +1 -1
- package/src/canvas/index.ts +0 -9
- package/src/canvas/usePanZoom.test.ts +28 -0
- package/src/canvas/usePanZoom.ts +11 -4
- package/src/chrome/ChromeRegions.stories.tsx +1 -1
- package/src/chrome/LabChrome.tsx +21 -5
- package/src/chrome/builtins.test.ts +1 -0
- package/src/chrome/builtins.tsx +1 -0
- package/src/chrome/index.ts +1 -0
- package/src/chrome/labTypes.ts +3 -3
- package/src/chrome/regions/PaletteRegion.test.tsx +18 -0
- package/src/chrome/regions/PaletteRegion.tsx +6 -10
- package/src/chrome/regions/SidebarRegion.stories.tsx +44 -0
- package/src/chrome/regions/TitleBarRegion.tsx +1 -1
- package/src/chrome/regions/ToolbarRegion.tsx +11 -7
- package/src/chrome/types.ts +11 -2
- package/src/config/auto.test.ts +12 -0
- package/src/config/auto.ts +15 -0
- package/src/config/autoConfig.test.ts +107 -0
- package/src/config/autoConfig.ts +153 -0
- package/src/config/builder.test.ts +38 -0
- package/src/config/builder.ts +55 -11
- package/src/config/index.ts +3 -0
- package/src/config/path.ts +7 -2
- package/src/config/resolve.test.ts +25 -0
- package/src/config/resolve.ts +17 -1
- package/src/config/types.ts +32 -2
- package/src/config/useResolvedConfig.ts +26 -0
- package/src/controls/AutoControls.stories.tsx +88 -0
- package/src/controls/ControlPanel.less +23 -0
- package/src/controls/ControlPanel.stories.tsx +83 -1
- package/src/controls/ControlPanel.test.tsx +457 -4
- package/src/controls/ControlPanel.tsx +534 -73
- package/src/index.test.ts +0 -2
- package/src/index.ts +33 -11
- package/src/instrument/serializers.ts +29 -1
- package/src/lab/Lab.chrome.test.tsx +16 -0
- package/src/lab/Lab.stories.tsx +1 -1
- package/src/lab/Lab.surface.test.tsx +7 -2
- package/src/lab/Lab.test.tsx +79 -1
- package/src/lab/Lab.tsx +124 -16
- package/src/lab/LabContext.ts +8 -0
- package/src/lab/LabFit.stories.tsx +4 -4
- package/src/lab/LabFullChrome.stories.tsx +1 -1
- package/src/lab/LabHeader.tsx +0 -1
- package/src/lab/LabRoot.test.tsx +56 -0
- package/src/lab/LabRoot.tsx +47 -0
- package/src/lab/LabShell.less +24 -3
- package/src/lab/LabShell.stories.tsx +50 -1
- package/src/lab/LabShell.tsx +18 -27
- package/src/lab/LabSwitcher.less +10 -10
- package/src/lab/LabSwitcher.test.tsx +14 -9
- package/src/lab/LabSwitcher.tsx +8 -4
- package/src/lab/Workspace.less +1 -1
- package/src/lab/Workspace.stories.tsx +1 -1
- package/src/lab/Workspace.surface.test.tsx +1 -1
- package/src/lab/index.ts +2 -0
- package/src/layers/LayerList.less +1 -1
- package/src/layers/LayerList.stories.tsx +2 -2
- package/src/loupe/AGENTS.md +16 -4
- package/src/loupe/LoupeGestures.tsx +67 -0
- package/src/loupe/TrialLoupe.tsx +43 -28
- package/src/loupe/index.ts +4 -0
- package/src/loupe/loupeActions.ts +98 -0
- package/src/loupe/useLoupe.test.tsx +59 -2
- package/src/loupe/useLoupe.ts +28 -48
- package/src/passthrough/weasel-ui.ts +3 -3
- package/src/primitives/FloatingPanel.stories.tsx +1 -1
- package/src/primitives/FpsMeter.less +6 -1
- package/src/primitives/FpsMeter.stories.tsx +1 -1
- package/src/primitives/FpsMeter.test.tsx +12 -4
- package/src/primitives/FpsMeter.tsx +6 -1
- package/src/primitives/JobProgress.stories.tsx +2 -2
- package/src/primitives/Legend.stories.tsx +1 -1
- package/src/primitives/ScaleIndicator.stories.tsx +1 -1
- package/src/primitives/Sidebar.less +7 -0
- package/src/primitives/Sidebar.stories.tsx +1 -1
- package/src/primitives/Split.test.tsx +25 -0
- package/src/primitives/Split.tsx +36 -20
- package/src/primitives/StatusBar.less +6 -0
- package/src/primitives/StatusBar.stories.tsx +1 -1
- package/src/primitives/Toolbar.stories.tsx +1 -1
- package/src/specimen/Specimen.less +95 -0
- package/src/specimen/Specimen.stories.tsx +13 -0
- package/src/specimen/Specimen.test.tsx +13 -0
- package/src/specimen/Specimen.tsx +888 -0
- package/src/state/Persistence.stories.tsx +4 -4
- package/src/state/store.test.ts +65 -0
- package/src/state/store.ts +32 -8
- package/src/state/types.ts +31 -2
- package/src/state/useTrialState.test.tsx +85 -0
- package/src/state/useTrialState.ts +9 -1
- package/src/state/view.test.ts +4 -4
- package/src/styles.less +1 -0
- package/src/surface/index.ts +1 -1
- package/src/surface/useSurfaceTile.test.tsx +1 -1
- package/src/surface/useTiledSurface.test.tsx +65 -10
- package/src/surface/useTiledSurface.ts +23 -11
- package/src/theme/Interstellar.stories.tsx +2 -2
- package/src/theme/interstellar.test.ts +16 -5
- package/src/theme/interstellar.theme.json +180 -0
- package/src/theme/interstellar.ts +8 -5
- package/src/tools/labTool.ts +3 -3
- package/src/trial/Trial.annotations.test.tsx +13 -4
- package/src/trial/Trial.canvas.test.tsx +36 -0
- package/src/trial/Trial.config.test.tsx +75 -2
- package/src/trial/Trial.less +4 -0
- package/src/trial/Trial.stories.tsx +4 -1
- package/src/trial/Trial.test.tsx +3 -0
- package/src/trial/Trial.tsx +21 -14
- package/src/trial/TrialChrome.tsx +17 -3
- package/src/trial/trialOps.test.ts +101 -1
- package/src/trial/trialOps.ts +62 -4
- package/dist/_dts/ToggleBar.d-DbHoWKIA.d.ts +0 -116
- package/dist/chunk-67SJLMC7.js.map +0 -1
- package/dist/chunk-6ZDGOZQV.js.map +0 -1
- package/dist/chunk-E44SU6XS.js +0 -50
- package/dist/chunk-E44SU6XS.js.map +0 -1
- package/dist/chunk-EKIICY6X.js.map +0 -1
- package/dist/chunk-KJALCDWE.js.map +0 -1
- package/dist/chunk-NDRYLVOW.js.map +0 -1
- package/dist/chunk-NS64DXMN.js.map +0 -1
- package/dist/chunk-PGETSEDK.js.map +0 -1
- package/dist/chunk-QLSV2N3G.js.map +0 -1
- package/dist/chunk-S2SHZRD7.js +0 -7681
- package/dist/chunk-S2SHZRD7.js.map +0 -1
- package/dist/chunk-TQBBYTAF.js +0 -280
- package/dist/chunk-TQBBYTAF.js.map +0 -1
- package/dist/chunk-ZPH5WTWF.js.map +0 -1
- package/src/canvas/useOrbit.test.ts +0 -167
- package/src/canvas/useOrbit.ts +0 -156
- package/src/theme/interstellar.tokens.json +0 -61
package/dist/index.js
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
|
-
import { resolveLoupe, TrialLoupe } from './chunk-
|
|
2
|
-
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LoupeBubble, TrialLoupe, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-
|
|
1
|
+
import { resolveLoupe, TrialLoupe } from './chunk-ERFMC6WU.js';
|
|
2
|
+
export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LOUPE_MAGNIFY_ID, LOUPE_PEEK_ID, LoupeBubble, LoupeGestures, TrialLoupe, createLoupeActions, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe } from './chunk-ERFMC6WU.js';
|
|
3
3
|
import { createEventBus, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
4
4
|
export { clearUndo, createEventBus, emptyStack, pushSnapshot, redo, undo } from './chunk-RL2LOLNI.js';
|
|
5
5
|
import { useDragDrop, DragOverlay, Palette } from './chunk-RS3HRQWU.js';
|
|
6
|
-
import { useTiledSurface } from './chunk-
|
|
7
|
-
export { composeRects, rectsEqual, toDeviceRect, useTiledSurface } from './chunk-
|
|
6
|
+
import { useTiledSurface } from './chunk-IJJUK4FU.js';
|
|
7
|
+
export { composeRects, rectsEqual, toDeviceRect, useTiledSurface } from './chunk-IJJUK4FU.js';
|
|
8
8
|
import { useJob } from './chunk-HXXTULDN.js';
|
|
9
9
|
export { useJob } from './chunk-HXXTULDN.js';
|
|
10
|
-
import { suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, AnnotationsContext, useLabChromeContext, labContributions, LabHeaderRegion, LabFooterRegion, LabSidebarRegion } from './chunk-
|
|
11
|
-
export { AnnotationsContext, ExportMenu, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useAnnotations, useAnnotationsOptional, useLabChromeContext } from './chunk-
|
|
12
|
-
import { Split, JobProgress } from './chunk-
|
|
13
|
-
export { FloatingPanel, JobProgress, Legend, Sidebar, Split } from './chunk-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
import { suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, AnnotationsContext, useLabChromeContext, labContributions, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-CKUKF72R.js';
|
|
11
|
+
export { AnnotationsContext, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, builtinContributions, contributionsIn, labContributions, mergeContributions, suppressContributions, toolContributions, useAnnotations, useAnnotationsOptional, useLabChromeContext } from './chunk-CKUKF72R.js';
|
|
12
|
+
import { Split, JobProgress, Sidebar, Legend, FloatingPanel } from './chunk-KJCUERQF.js';
|
|
13
|
+
export { FloatingPanel, JobProgress, Legend, Sidebar, Split } from './chunk-KJCUERQF.js';
|
|
14
|
+
import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-753Y6HE6.js';
|
|
15
|
+
export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-753Y6HE6.js';
|
|
16
|
+
import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-LRI3MBGR.js';
|
|
17
|
+
export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-LRI3MBGR.js';
|
|
17
18
|
import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-RWNDDKOH.js';
|
|
18
19
|
export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-RWNDDKOH.js';
|
|
19
|
-
export { ControlPanel } from './chunk-
|
|
20
|
-
import { useConfigSchema } from './chunk-
|
|
21
|
-
export {
|
|
22
|
-
import { useLabContext, LabContext } from './chunk-
|
|
23
|
-
export { LabContext, useLabContext } from './chunk-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export {
|
|
27
|
-
import {
|
|
28
|
-
export {
|
|
20
|
+
export { ControlPanel } from './chunk-FKLT3ITC.js';
|
|
21
|
+
import { useConfigSchema } from './chunk-6BUQ77ZV.js';
|
|
22
|
+
export { useConfigSchema } from './chunk-6BUQ77ZV.js';
|
|
23
|
+
import { useLabContext, LabContext } from './chunk-Z76KEZAX.js';
|
|
24
|
+
export { LabContext, useLabContext } from './chunk-Z76KEZAX.js';
|
|
25
|
+
import { useResolvedConfig } from './chunk-A2ACAGW6.js';
|
|
26
|
+
export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-A2ACAGW6.js';
|
|
27
|
+
export { fromConfigFields, isLeafVisible } from './chunk-EMXAIRUJ.js';
|
|
28
|
+
import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-REOBGYMC.js';
|
|
29
|
+
export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-REOBGYMC.js';
|
|
30
|
+
import { CameraWheelContext, as2DView, DEFAULT_VIEW, CanvasStack, Stage, withZoom, fitStage } from './chunk-TT5C5S6R.js';
|
|
31
|
+
export { CanvasStack, DEFAULT_VIEW, Stage, as2DView, fitStage, usePanZoom } from './chunk-TT5C5S6R.js';
|
|
29
32
|
export { centerOn, zoomAt } from './chunk-H6ZAOWNE.js';
|
|
30
33
|
import { applyCamera } from './chunk-2AYGEN57.js';
|
|
31
34
|
export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from './chunk-2AYGEN57.js';
|
|
@@ -34,625 +37,22 @@ export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, use
|
|
|
34
37
|
export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
|
|
35
38
|
import { LabStoreContext, TrialIdProvider } from './chunk-2YILQ7Y5.js';
|
|
36
39
|
export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
|
|
37
|
-
import { LayerList } from './chunk-
|
|
38
|
-
export { LayerList } from './chunk-
|
|
40
|
+
import { LayerList } from './chunk-D35PFTS7.js';
|
|
41
|
+
export { LayerList } from './chunk-D35PFTS7.js';
|
|
39
42
|
import './chunk-SBXNQW4G.js';
|
|
40
|
-
import { E, w, T, p, u, c, n, f,
|
|
41
|
-
export {
|
|
42
|
-
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext
|
|
43
|
-
import { tileGeometry } from '@weasel-js/core/patterns-builtin';
|
|
43
|
+
import { E, w, T, a2, p, u, c, n, f, r, h, serializeSvg, C, l7, r5, a5, Lt, o2, a3, l3, u3, r7, r8, r6, o5, s5, c7, l6, c3, s3, u2, g, b2, y2, l4, b3, c8, r3, l2, C2, S, D, O, I2, z2, U, W, G2, H, B, X, A2, c4, n5, s4, m2, c2, l, g2, l5, S4, r9, n6, r10, i5, i4, s2, n7, o4, c5, c6, w2, L2, n8, k3, $2 } from './chunk-LASCBWW7.js';
|
|
44
|
+
export { a5 as Button, B as CheckboxRow, y as CloseIcon, $ as CollapseIcon, z2 as ColorRow, S2 as CurveField, q as EffectCard, Y as EffectCardList, te as ExpandIcon, o as Icon, u2 as Input, l9 as Jog, c4 as LayerStack, U as NumberRow, I as PauseIcon, F as PlayIcon, X as PropertyGroup, O as PropertyList, D as PropertyPanel, j2 as PropertyRow, k2 as PropertySpan, v as ResetIcon, b2 as Select, W as SelectRow, I2 as SliderRow, R as StepBackIcon, z as StepForwardIcon, L as StopIcon, K as Subpanel, H as TextRow, r5 as ToggleBar, G2 as ToggleRow, oe as TokenPanel, H2 as inferTokenType, O2 as refitScale } from './chunk-LASCBWW7.js';
|
|
45
|
+
import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
|
|
44
46
|
import { createContext, useState, useRef, useEffect, useCallback, useContext, useMemo, useId, Children, useLayoutEffect, useSyncExternalStore } from 'react';
|
|
45
47
|
import { flushSync, createPortal } from 'react-dom';
|
|
46
48
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
49
|
+
import { useThemeOptional, ThemeProvider } from '@weasel-js/theme/react';
|
|
47
50
|
import { useStore } from 'zustand/react';
|
|
51
|
+
import { defineTheme, weaselTheme } from '@weasel-js/theme';
|
|
48
52
|
import { Provider, StrategyRegistryProvider, DragProvider, Container, useDragHandle } from 'windease/react';
|
|
49
53
|
import { asNodeId, Store, createNode, floatingStrategy, gridStrategy } from 'windease';
|
|
54
|
+
import { Focusable } from 'react-aria-components';
|
|
50
55
|
|
|
51
|
-
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
52
|
-
function multiply(a2, b2) {
|
|
53
|
-
return [
|
|
54
|
-
a2[0] * b2[0] + a2[2] * b2[1],
|
|
55
|
-
a2[1] * b2[0] + a2[3] * b2[1],
|
|
56
|
-
a2[0] * b2[2] + a2[2] * b2[3],
|
|
57
|
-
a2[1] * b2[2] + a2[3] * b2[3],
|
|
58
|
-
a2[0] * b2[4] + a2[2] * b2[5] + a2[4],
|
|
59
|
-
a2[1] * b2[4] + a2[3] * b2[5] + a2[5]
|
|
60
|
-
];
|
|
61
|
-
}
|
|
62
|
-
function isIdentity(m, eps = 1e-9) {
|
|
63
|
-
return Math.abs(m[0] - 1) < eps && Math.abs(m[1]) < eps && Math.abs(m[2]) < eps && Math.abs(m[3] - 1) < eps && Math.abs(m[4]) < eps && Math.abs(m[5]) < eps;
|
|
64
|
-
}
|
|
65
|
-
function formatMatrix(m) {
|
|
66
|
-
if (isIdentity(m)) return null;
|
|
67
|
-
return `matrix(${m.map((n2) => trimNumber(n2)).join(" ")})`;
|
|
68
|
-
}
|
|
69
|
-
function trimNumber(n2) {
|
|
70
|
-
if (!Number.isFinite(n2)) return "0";
|
|
71
|
-
const r3 = Math.round(n2 * 1e6) / 1e6;
|
|
72
|
-
if (Number.isInteger(r3)) return String(r3);
|
|
73
|
-
return String(r3);
|
|
74
|
-
}
|
|
75
|
-
function anchorOffset(style, width) {
|
|
76
|
-
const edge = resolveAlign(style?.align ?? "left", style?.direction ?? "ltr");
|
|
77
|
-
return edge === "center" ? width / 2 : edge === "right" ? width : 0;
|
|
78
|
-
}
|
|
79
|
-
function patternSpecOf(paint) {
|
|
80
|
-
return "tile" in paint.pattern ? paint.pattern : null;
|
|
81
|
-
}
|
|
82
|
-
function patternXml(id, paint, onWarn) {
|
|
83
|
-
const spec = patternSpecOf(paint);
|
|
84
|
-
if (!spec) {
|
|
85
|
-
onWarn?.("pattern fill carries a TextureHandle, which has no vector form \u2014 omitted from <defs>");
|
|
86
|
-
return "";
|
|
87
|
-
}
|
|
88
|
-
const geometry = tileGeometry(spec);
|
|
89
|
-
const body = geometry.shapes.map(shapeXml).join("");
|
|
90
|
-
const origin = paint.origin ?? { x: 0, y: 0 };
|
|
91
|
-
const attrs = [
|
|
92
|
-
`id="${id}"`,
|
|
93
|
-
'patternUnits="userSpaceOnUse"',
|
|
94
|
-
`width="${trimNumber(geometry.size)}"`,
|
|
95
|
-
`height="${trimNumber(geometry.size)}"`
|
|
96
|
-
];
|
|
97
|
-
if (origin.x !== 0 || origin.y !== 0) {
|
|
98
|
-
attrs.push(`x="${trimNumber(origin.x)}"`, `y="${trimNumber(origin.y)}"`);
|
|
99
|
-
}
|
|
100
|
-
attrs.push(`data-weasel-tile="${escapeAttr(JSON.stringify(spec))}"`);
|
|
101
|
-
return `<pattern ${attrs.join(" ")}>${body}</pattern>`;
|
|
102
|
-
}
|
|
103
|
-
function shapeXml(shape) {
|
|
104
|
-
switch (shape.kind) {
|
|
105
|
-
case "line":
|
|
106
|
-
return `<line x1="${trimNumber(shape.x1)}" y1="${trimNumber(shape.y1)}" x2="${trimNumber(shape.x2)}" y2="${trimNumber(shape.y2)}" stroke="${shape.color}" stroke-width="${trimNumber(shape.width)}"/>`;
|
|
107
|
-
case "circle":
|
|
108
|
-
return `<circle cx="${trimNumber(shape.cx)}" cy="${trimNumber(shape.cy)}" r="${trimNumber(shape.r)}" fill="${shape.color}"/>`;
|
|
109
|
-
case "ellipse": {
|
|
110
|
-
const deg = shape.rotation * 180 / Math.PI;
|
|
111
|
-
const transform = deg === 0 ? "" : ` transform="rotate(${trimNumber(deg)} ${trimNumber(shape.cx)} ${trimNumber(shape.cy)})"`;
|
|
112
|
-
return `<ellipse cx="${trimNumber(shape.cx)}" cy="${trimNumber(shape.cy)}" rx="${trimNumber(shape.rx)}" ry="${trimNumber(shape.ry)}" fill="${shape.color}"${transform}/>`;
|
|
113
|
-
}
|
|
114
|
-
case "rect":
|
|
115
|
-
return `<rect x="${trimNumber(shape.x)}" y="${trimNumber(shape.y)}" width="${trimNumber(shape.width)}" height="${trimNumber(shape.height)}" fill="${shape.color}"/>`;
|
|
116
|
-
default:
|
|
117
|
-
return "";
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function escapeAttr(s) {
|
|
121
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
122
|
-
}
|
|
123
|
-
function serializePathD(path) {
|
|
124
|
-
if (path.kind === "rect") {
|
|
125
|
-
const { x, y, width, height } = path;
|
|
126
|
-
return `M${trimNumber(x)} ${trimNumber(y)}h${trimNumber(width)}v${trimNumber(height)}h${trimNumber(-width)}Z`;
|
|
127
|
-
}
|
|
128
|
-
const cmds = path.commands;
|
|
129
|
-
const xs = path.coords;
|
|
130
|
-
const out = [];
|
|
131
|
-
let ci = 0;
|
|
132
|
-
for (let i = 0; i < cmds.length; i++) {
|
|
133
|
-
const c3 = cmds[i];
|
|
134
|
-
if (c3 === PATH_M) {
|
|
135
|
-
out.push(`M${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])}`);
|
|
136
|
-
ci += 2;
|
|
137
|
-
} else if (c3 === PATH_L) {
|
|
138
|
-
out.push(`L${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])}`);
|
|
139
|
-
ci += 2;
|
|
140
|
-
} else if (c3 === PATH_C) {
|
|
141
|
-
out.push(
|
|
142
|
-
`C${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])} ${trimNumber(xs[ci + 2])} ${trimNumber(xs[ci + 3])} ${trimNumber(xs[ci + 4])} ${trimNumber(xs[ci + 5])}`
|
|
143
|
-
);
|
|
144
|
-
ci += 6;
|
|
145
|
-
} else if (c3 === PATH_Q) {
|
|
146
|
-
out.push(
|
|
147
|
-
`Q${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])} ${trimNumber(xs[ci + 2])} ${trimNumber(xs[ci + 3])}`
|
|
148
|
-
);
|
|
149
|
-
ci += 4;
|
|
150
|
-
} else if (c3 === PATH_Z) {
|
|
151
|
-
out.push("Z");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return out.join("");
|
|
155
|
-
}
|
|
156
|
-
var PaintServerRegistry = class {
|
|
157
|
-
byPaint = /* @__PURE__ */ new Map();
|
|
158
|
-
order = [];
|
|
159
|
-
counter = 0;
|
|
160
|
-
// Marker keys referenced by any stroke, in first-use order. The `<defs>`
|
|
161
|
-
// id is the marker key itself, not a minted counter id: `parseSvg` reads a
|
|
162
|
-
// `marker-end="url(#id)"` fragment back as the marker key directly (it
|
|
163
|
-
// never inspects the `<marker>` element), so a synthetic id would come
|
|
164
|
-
// back unresolvable and warn on round-trip.
|
|
165
|
-
markerKeys = [];
|
|
166
|
-
markerKeySet = /* @__PURE__ */ new Set();
|
|
167
|
-
register(paint) {
|
|
168
|
-
const existing = this.byPaint.get(paint);
|
|
169
|
-
if (existing) return existing;
|
|
170
|
-
const id = paint.fill === "pattern" ? `pat${this.counter++}` : `grad${this.counter++}`;
|
|
171
|
-
this.byPaint.set(paint, id);
|
|
172
|
-
this.order.push(paint);
|
|
173
|
-
return id;
|
|
174
|
-
}
|
|
175
|
-
/** The `<defs>` id for a marker key — the key itself, minting nothing.
|
|
176
|
-
* `undefined` when nothing is registered under `key`, so a caller emits no
|
|
177
|
-
* attribute at all rather than a `url(#…)` pointing at a def that will
|
|
178
|
-
* never be written. */
|
|
179
|
-
markerId(key) {
|
|
180
|
-
if (getMarker(key) === void 0) return void 0;
|
|
181
|
-
if (!this.markerKeySet.has(key)) {
|
|
182
|
-
this.markerKeySet.add(key);
|
|
183
|
-
this.markerKeys.push(key);
|
|
184
|
-
}
|
|
185
|
-
return key;
|
|
186
|
-
}
|
|
187
|
-
/** Emit `<defs>...</defs>` XML for every registered paint server and marker. */
|
|
188
|
-
toDefsXml(onWarn) {
|
|
189
|
-
if (this.order.length === 0 && this.markerKeys.length === 0) return "";
|
|
190
|
-
const parts = ["<defs>"];
|
|
191
|
-
for (const paint of this.order) {
|
|
192
|
-
parts.push(paintServerXml(this.byPaint.get(paint), paint, onWarn));
|
|
193
|
-
}
|
|
194
|
-
for (const key of this.markerKeys) {
|
|
195
|
-
const entry = getMarker(key);
|
|
196
|
-
if (!entry) continue;
|
|
197
|
-
parts.push(entry.toSvg ? entry.toSvg(key, entry) : defaultMarkerXml(key, entry));
|
|
198
|
-
}
|
|
199
|
-
parts.push("</defs>");
|
|
200
|
-
return parts.join("");
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
function defaultMarkerXml(id, entry) {
|
|
204
|
-
const path = entry.path({ size: 1, stroke: { paint: { fill: "solid", color: "#000" } } });
|
|
205
|
-
const d = serializePathD(path);
|
|
206
|
-
const fill = entry.fill === "none" ? "none" : "context-stroke";
|
|
207
|
-
const outline = entry.outline ? ` stroke="context-stroke" stroke-width="${entry.outline.width}" stroke-linecap="round" stroke-linejoin="round"` : "";
|
|
208
|
-
return `<marker id="${id}" markerUnits="strokeWidth" markerWidth="8" markerHeight="8" refX="0" refY="0" orient="auto" overflow="visible"><path d="${d}" fill="${fill}"${outline}/></marker>`;
|
|
209
|
-
}
|
|
210
|
-
function paintServerXml(id, paint, onWarn) {
|
|
211
|
-
if (paint.fill === "pattern") return patternXml(id, paint, onWarn);
|
|
212
|
-
const builtin = gradientXml(id, paint);
|
|
213
|
-
if (builtin) return builtin;
|
|
214
|
-
const custom = getPaintKind(paint.fill)?.toSvg?.(id, paint);
|
|
215
|
-
if (custom) return custom;
|
|
216
|
-
onWarn?.(`${paint.fill} fill has no vector form \u2014 omitted from <defs>`);
|
|
217
|
-
return "";
|
|
218
|
-
}
|
|
219
|
-
function gradientUnitsAttr(units) {
|
|
220
|
-
return units === "bounds" ? "objectBoundingBox" : "userSpaceOnUse";
|
|
221
|
-
}
|
|
222
|
-
function gradientXml(id, paint) {
|
|
223
|
-
if (paint.fill === "linear-gradient") {
|
|
224
|
-
const stops = paint.stops.map(stopXml).join("");
|
|
225
|
-
return `<linearGradient id="${id}" gradientUnits="${gradientUnitsAttr(paint.units)}" x1="${trimNumber(paint.from.x)}" y1="${trimNumber(paint.from.y)}" x2="${trimNumber(paint.to.x)}" y2="${trimNumber(paint.to.y)}">${stops}</linearGradient>`;
|
|
226
|
-
}
|
|
227
|
-
if (paint.fill === "radial-gradient") {
|
|
228
|
-
const stops = paint.stops.map(stopXml).join("");
|
|
229
|
-
return `<radialGradient id="${id}" gradientUnits="${gradientUnitsAttr(paint.units)}" cx="${trimNumber(paint.center.x)}" cy="${trimNumber(paint.center.y)}" r="${trimNumber(paint.radius)}">${stops}</radialGradient>`;
|
|
230
|
-
}
|
|
231
|
-
return "";
|
|
232
|
-
}
|
|
233
|
-
function stopXml(s) {
|
|
234
|
-
const m = /^#([0-9a-f]{6})([0-9a-f]{2})$/i.exec(s.color);
|
|
235
|
-
if (m) {
|
|
236
|
-
const alpha = parseInt(m[2], 16) / 255;
|
|
237
|
-
return `<stop offset="${trimNumber(s.offset)}" stop-color="#${m[1].toLowerCase()}" stop-opacity="${trimNumber(alpha)}"/>`;
|
|
238
|
-
}
|
|
239
|
-
return `<stop offset="${trimNumber(s.offset)}" stop-color="${s.color}"/>`;
|
|
240
|
-
}
|
|
241
|
-
function serializeSvg(nodes, opts = {}) {
|
|
242
|
-
const registry = new PaintServerRegistry();
|
|
243
|
-
registerPaintServers(nodes, registry);
|
|
244
|
-
const bounds = opts.viewBox ?? computeBounds(nodes);
|
|
245
|
-
const vb = `${trimNumber(bounds.x)} ${trimNumber(bounds.y)} ${trimNumber(bounds.width)} ${trimNumber(bounds.height)}`;
|
|
246
|
-
const namespaces = opts.namespaces ?? {};
|
|
247
|
-
const rootAttrs = [`xmlns="http://www.w3.org/2000/svg"`];
|
|
248
|
-
for (const [prefix, uri] of Object.entries(namespaces)) {
|
|
249
|
-
rootAttrs.push(`xmlns:${prefix}="${escapeAttr2(uri)}"`);
|
|
250
|
-
}
|
|
251
|
-
rootAttrs.push(`viewBox="${vb}"`);
|
|
252
|
-
if (opts.width != null) rootAttrs.push(`width="${trimNumber(opts.width)}"`);
|
|
253
|
-
if (opts.height != null) rootAttrs.push(`height="${trimNumber(opts.height)}"`);
|
|
254
|
-
if (opts.documentMeta) {
|
|
255
|
-
for (const prefix of Object.keys(namespaces)) {
|
|
256
|
-
const bucket = opts.documentMeta[prefix];
|
|
257
|
-
if (!bucket?.attrs) continue;
|
|
258
|
-
for (const [name, value] of Object.entries(bucket.attrs)) {
|
|
259
|
-
rootAttrs.push(`${prefix}:${name}="${escapeAttr2(value)}"`);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
let docMetaXml = "";
|
|
264
|
-
if (opts.documentMeta) {
|
|
265
|
-
for (const prefix of Object.keys(namespaces)) {
|
|
266
|
-
const bucket = opts.documentMeta[prefix];
|
|
267
|
-
if (!bucket?.elements) continue;
|
|
268
|
-
for (const [localName, list] of Object.entries(bucket.elements)) {
|
|
269
|
-
for (const el of list) docMetaXml += namespacedElementXml(prefix, localName, el);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
const defsXml = registry.toDefsXml(opts.onWarn);
|
|
274
|
-
const bodyXml = nodes.map((n2) => nodeXml(n2, registry, namespaces)).join("");
|
|
275
|
-
const titleXml = opts.title && opts.title.length > 0 ? `<title>${escapeText(opts.title)}</title>` : "";
|
|
276
|
-
return `<svg ${rootAttrs.join(" ")}>${titleXml}${defsXml}${docMetaXml}${bodyXml}</svg>`;
|
|
277
|
-
}
|
|
278
|
-
function namespacedElementXml(prefix, localName, el) {
|
|
279
|
-
const attrs = [];
|
|
280
|
-
for (const [name, value] of Object.entries(el.attrs)) {
|
|
281
|
-
attrs.push(`${name}="${escapeAttr2(value)}"`);
|
|
282
|
-
}
|
|
283
|
-
const head = attrs.length > 0 ? `<${prefix}:${localName} ${attrs.join(" ")}>` : `<${prefix}:${localName}>`;
|
|
284
|
-
let body = "";
|
|
285
|
-
if (el.children) {
|
|
286
|
-
for (const [childName, list] of Object.entries(el.children)) {
|
|
287
|
-
for (const child of list) body += namespacedElementXml(prefix, childName, child);
|
|
288
|
-
}
|
|
289
|
-
} else if (el.text != null) {
|
|
290
|
-
body = escapeText(el.text);
|
|
291
|
-
}
|
|
292
|
-
return `${head}${body}</${prefix}:${localName}>`;
|
|
293
|
-
}
|
|
294
|
-
function metaAttrsXml(meta, namespaces) {
|
|
295
|
-
if (!meta) return "";
|
|
296
|
-
const parts = [];
|
|
297
|
-
for (const prefix of Object.keys(namespaces)) {
|
|
298
|
-
const bucket = meta[prefix];
|
|
299
|
-
if (!bucket?.attrs) continue;
|
|
300
|
-
for (const [name, value] of Object.entries(bucket.attrs)) {
|
|
301
|
-
parts.push(`${prefix}:${name}="${escapeAttr2(value)}"`);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return parts.length > 0 ? ` ${parts.join(" ")}` : "";
|
|
305
|
-
}
|
|
306
|
-
function metaElementsXml(meta, namespaces) {
|
|
307
|
-
if (!meta) return "";
|
|
308
|
-
let out = "";
|
|
309
|
-
for (const prefix of Object.keys(namespaces)) {
|
|
310
|
-
const bucket = meta[prefix];
|
|
311
|
-
if (!bucket?.elements) continue;
|
|
312
|
-
for (const [localName, list] of Object.entries(bucket.elements)) {
|
|
313
|
-
for (const el of list) out += namespacedElementXml(prefix, localName, el);
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return out;
|
|
317
|
-
}
|
|
318
|
-
function registerPaintServers(nodes, registry) {
|
|
319
|
-
for (const n2 of nodes) {
|
|
320
|
-
if (n2.kind === "group") {
|
|
321
|
-
registerPaintServers(n2.children, registry);
|
|
322
|
-
} else if (n2.kind === "path") {
|
|
323
|
-
if (n2.fill.kind === "gradient") registry.register(n2.fill.paint);
|
|
324
|
-
if (n2.stroke && n2.stroke.paint.kind === "gradient") registry.register(n2.stroke.paint.paint);
|
|
325
|
-
registerMarkers(n2.stroke, registry);
|
|
326
|
-
} else if (n2.kind === "text") {
|
|
327
|
-
registerTextPaint(n2.fill, registry);
|
|
328
|
-
registerTextPaint(n2.stroke?.paint, registry);
|
|
329
|
-
registerMarkers(n2.stroke, registry);
|
|
330
|
-
for (const run of n2.runs ?? []) {
|
|
331
|
-
registerTextPaint(run.fill, registry);
|
|
332
|
-
registerTextPaint(run.stroke?.paint, registry);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
function registerTextPaint(paint, registry) {
|
|
338
|
-
if (paint && !("color" in paint)) registry.register(paint);
|
|
339
|
-
}
|
|
340
|
-
function markerKeyOfRef(ref) {
|
|
341
|
-
if (typeof ref === "string") return ref;
|
|
342
|
-
if (ref && typeof ref === "object" && "key" in ref) return String(ref.key);
|
|
343
|
-
return void 0;
|
|
344
|
-
}
|
|
345
|
-
function registerMarkers(stroke, registry) {
|
|
346
|
-
if (!stroke) return;
|
|
347
|
-
for (const ref of [stroke.markerStart, stroke.markerMid, stroke.markerEnd]) {
|
|
348
|
-
const key = markerKeyOfRef(ref);
|
|
349
|
-
if (key) registry.markerId(key);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
function nodeXml(node, registry, namespaces) {
|
|
353
|
-
if (node.kind === "group") return groupXml(node, registry, namespaces);
|
|
354
|
-
if (node.kind === "text") return textXml(node, registry, namespaces);
|
|
355
|
-
if (node.kind === "image") return imageXml(node, namespaces);
|
|
356
|
-
return pathXml(node, registry, namespaces);
|
|
357
|
-
}
|
|
358
|
-
function imageXml(node, namespaces) {
|
|
359
|
-
const attrs = [
|
|
360
|
-
`href="${escapeAttr2(node.href)}"`,
|
|
361
|
-
`x="${trimNumber(node.x)}"`,
|
|
362
|
-
`y="${trimNumber(node.y)}"`,
|
|
363
|
-
`width="${trimNumber(node.width)}"`,
|
|
364
|
-
`height="${trimNumber(node.height)}"`,
|
|
365
|
-
`preserveAspectRatio="none"`
|
|
366
|
-
];
|
|
367
|
-
if (node.opacity != null && node.opacity !== 1) {
|
|
368
|
-
attrs.push(`opacity="${trimNumber(node.opacity)}"`);
|
|
369
|
-
}
|
|
370
|
-
if (node.rotation != null && node.rotation !== 0) {
|
|
371
|
-
const cx = node.x + node.width / 2;
|
|
372
|
-
const cy = node.y + node.height / 2;
|
|
373
|
-
const deg = node.rotation * 180 / Math.PI;
|
|
374
|
-
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
375
|
-
}
|
|
376
|
-
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
377
|
-
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
378
|
-
if (metaEls) return `<image ${attrs.join(" ")}${metaAttrs}>${metaEls}</image>`;
|
|
379
|
-
return `<image ${attrs.join(" ")}${metaAttrs}/>`;
|
|
380
|
-
}
|
|
381
|
-
function groupXml(node, registry, namespaces) {
|
|
382
|
-
const attrs = [];
|
|
383
|
-
if (node.transform) {
|
|
384
|
-
const m = formatMatrix(node.transform);
|
|
385
|
-
if (m) attrs.push(`transform="${m}"`);
|
|
386
|
-
}
|
|
387
|
-
if (node.opacity != null && node.opacity !== 1) {
|
|
388
|
-
attrs.push(`opacity="${trimNumber(node.opacity)}"`);
|
|
389
|
-
}
|
|
390
|
-
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
391
|
-
const head = attrs.length > 0 ? `<g ${attrs.join(" ")}${metaAttrs}>` : `<g${metaAttrs}>`;
|
|
392
|
-
const body = node.children.map((c3) => nodeXml(c3, registry, namespaces)).join("");
|
|
393
|
-
return `${head}${body}${metaElementsXml(node.meta, namespaces)}</g>`;
|
|
394
|
-
}
|
|
395
|
-
function pathXml(node, registry, namespaces) {
|
|
396
|
-
const attrs = [`d="${serializePathD(node.path)}"`];
|
|
397
|
-
const fillAttrs = paintAttrs(node.fill, "fill", registry);
|
|
398
|
-
for (const a2 of fillAttrs) attrs.push(a2);
|
|
399
|
-
if (node.path.kind === "polygon" && node.path.fillRule === "evenodd") {
|
|
400
|
-
attrs.push(`fill-rule="evenodd"`);
|
|
401
|
-
}
|
|
402
|
-
if (node.stroke) {
|
|
403
|
-
const strokeAttrs = strokeAttrsFor(node.stroke, registry);
|
|
404
|
-
for (const a2 of strokeAttrs) attrs.push(a2);
|
|
405
|
-
} else {
|
|
406
|
-
attrs.push('stroke="none"');
|
|
407
|
-
}
|
|
408
|
-
if (node.opacity != null && node.opacity !== 1) {
|
|
409
|
-
attrs.push(`opacity="${trimNumber(node.opacity)}"`);
|
|
410
|
-
}
|
|
411
|
-
if (node.rotation != null && node.rotation !== 0) {
|
|
412
|
-
const b2 = pathBounds(node.path);
|
|
413
|
-
const cx = b2.minX + (b2.maxX - b2.minX) / 2;
|
|
414
|
-
const cy = b2.minY + (b2.maxY - b2.minY) / 2;
|
|
415
|
-
const deg = node.rotation * 180 / Math.PI;
|
|
416
|
-
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
417
|
-
}
|
|
418
|
-
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
419
|
-
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
420
|
-
if (metaEls) {
|
|
421
|
-
return `<path ${attrs.join(" ")}${metaAttrs}>${metaEls}</path>`;
|
|
422
|
-
}
|
|
423
|
-
return `<path ${attrs.join(" ")}${metaAttrs}/>`;
|
|
424
|
-
}
|
|
425
|
-
function paintAttrs(paint, name, registry, includeOpacity = true) {
|
|
426
|
-
if (paint.kind === "none") return [`${name}="none"`];
|
|
427
|
-
if (paint.kind === "solid") {
|
|
428
|
-
const out = [`${name}="${paint.color}"`];
|
|
429
|
-
if (includeOpacity && paint.opacity != null && paint.opacity !== 1) {
|
|
430
|
-
out.push(`${name}-opacity="${trimNumber(paint.opacity)}"`);
|
|
431
|
-
}
|
|
432
|
-
return out;
|
|
433
|
-
}
|
|
434
|
-
const id = registry.register(paint.paint);
|
|
435
|
-
return [`${name}="url(#${id})"`];
|
|
436
|
-
}
|
|
437
|
-
function strokeWidthAttrs(width) {
|
|
438
|
-
if (typeof width === "number") return [`stroke-width="${trimNumber(width)}"`];
|
|
439
|
-
return [`stroke-width="${trimNumber(width.px)}"`, 'vector-effect="non-scaling-stroke"'];
|
|
440
|
-
}
|
|
441
|
-
function coreStrokeAttrs(stroke, registry) {
|
|
442
|
-
const paint = stroke?.paint;
|
|
443
|
-
if (!stroke || !paint) return [];
|
|
444
|
-
const width = stroke.width ?? 1;
|
|
445
|
-
if (!((typeof width === "object" ? width.px : width) > 0)) return [];
|
|
446
|
-
const attrs = [];
|
|
447
|
-
if ("color" in paint) {
|
|
448
|
-
attrs.push(`stroke="${paint.color}"`);
|
|
449
|
-
if (paint.opacity != null && paint.opacity !== 1) {
|
|
450
|
-
attrs.push(`stroke-opacity="${trimNumber(paint.opacity)}"`);
|
|
451
|
-
}
|
|
452
|
-
} else {
|
|
453
|
-
attrs.push(`stroke="url(#${registry.register(paint)})"`);
|
|
454
|
-
}
|
|
455
|
-
attrs.push(...strokeWidthAttrs(width));
|
|
456
|
-
if (stroke.cap) attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
457
|
-
if (stroke.join) attrs.push(`stroke-linejoin="${stroke.join}"`);
|
|
458
|
-
if (stroke.dash && stroke.dash.length > 0) {
|
|
459
|
-
attrs.push(`stroke-dasharray="${stroke.dash.map(trimNumber).join(" ")}"`);
|
|
460
|
-
}
|
|
461
|
-
if (stroke.miterLimit != null) attrs.push(`stroke-miterlimit="${trimNumber(stroke.miterLimit)}"`);
|
|
462
|
-
for (const [field, attr] of [
|
|
463
|
-
["markerStart", "marker-start"],
|
|
464
|
-
["markerMid", "marker-mid"],
|
|
465
|
-
["markerEnd", "marker-end"]
|
|
466
|
-
]) {
|
|
467
|
-
const ref = stroke[field];
|
|
468
|
-
if (ref === void 0) continue;
|
|
469
|
-
const key = typeof ref === "string" ? ref : ref.key;
|
|
470
|
-
const id = registry.markerId(key);
|
|
471
|
-
if (id === void 0) continue;
|
|
472
|
-
attrs.push(`${attr}="url(#${id})"`);
|
|
473
|
-
}
|
|
474
|
-
return attrs;
|
|
475
|
-
}
|
|
476
|
-
function strokeAttrsFor(stroke, registry) {
|
|
477
|
-
const attrs = paintAttrs(stroke.paint, "stroke", registry, false);
|
|
478
|
-
attrs.push(...strokeWidthAttrs(stroke.width));
|
|
479
|
-
const opacity = stroke.opacity ?? (stroke.paint.kind === "solid" ? stroke.paint.opacity : void 0);
|
|
480
|
-
if (opacity != null && opacity !== 1) {
|
|
481
|
-
attrs.push(`stroke-opacity="${trimNumber(opacity)}"`);
|
|
482
|
-
}
|
|
483
|
-
if (stroke.cap) {
|
|
484
|
-
attrs.push(`stroke-linecap="${stroke.cap}"`);
|
|
485
|
-
}
|
|
486
|
-
if (stroke.join) {
|
|
487
|
-
attrs.push(`stroke-linejoin="${stroke.join}"`);
|
|
488
|
-
}
|
|
489
|
-
if (stroke.dash && stroke.dash.length > 0) {
|
|
490
|
-
attrs.push(`stroke-dasharray="${stroke.dash.map(trimNumber).join(" ")}"`);
|
|
491
|
-
}
|
|
492
|
-
if (stroke.miterLimit != null) {
|
|
493
|
-
attrs.push(`stroke-miterlimit="${trimNumber(stroke.miterLimit)}"`);
|
|
494
|
-
}
|
|
495
|
-
for (const [field, attr] of [
|
|
496
|
-
["markerStart", "marker-start"],
|
|
497
|
-
["markerMid", "marker-mid"],
|
|
498
|
-
["markerEnd", "marker-end"]
|
|
499
|
-
]) {
|
|
500
|
-
const ref = stroke[field];
|
|
501
|
-
if (ref === void 0) continue;
|
|
502
|
-
const id = registry.markerId(ref);
|
|
503
|
-
if (id === void 0) continue;
|
|
504
|
-
attrs.push(`${attr}="url(#${id})"`);
|
|
505
|
-
}
|
|
506
|
-
return attrs;
|
|
507
|
-
}
|
|
508
|
-
function computeBounds(nodes) {
|
|
509
|
-
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
510
|
-
const visit = (n2, ctm) => {
|
|
511
|
-
if (n2.kind === "group") {
|
|
512
|
-
const childCtm = n2.transform ? multiply(ctm, n2.transform) : ctm;
|
|
513
|
-
n2.children.forEach((c3) => visit(c3, childCtm));
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
const b2 = n2.kind === "text" || n2.kind === "image" ? { minX: n2.x, minY: n2.y, maxX: n2.x + n2.width, maxY: n2.y + n2.height } : pathBounds(n2.path);
|
|
517
|
-
const local = n2.rotation ? rotateAboutCenter(ctm, b2, n2.rotation) : ctm;
|
|
518
|
-
for (const [x, y] of corners(b2)) {
|
|
519
|
-
const px = local[0] * x + local[2] * y + local[4];
|
|
520
|
-
const py = local[1] * x + local[3] * y + local[5];
|
|
521
|
-
if (px < minX) minX = px;
|
|
522
|
-
if (py < minY) minY = py;
|
|
523
|
-
if (px > maxX) maxX = px;
|
|
524
|
-
if (py > maxY) maxY = py;
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
|
-
nodes.forEach((n2) => visit(n2, IDENTITY_MATRIX));
|
|
528
|
-
if (!Number.isFinite(minX)) {
|
|
529
|
-
return { x: 0, y: 0, width: 0, height: 0 };
|
|
530
|
-
}
|
|
531
|
-
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
532
|
-
}
|
|
533
|
-
function corners(b2) {
|
|
534
|
-
return [[b2.minX, b2.minY], [b2.maxX, b2.minY], [b2.maxX, b2.maxY], [b2.minX, b2.maxY]];
|
|
535
|
-
}
|
|
536
|
-
function rotateAboutCenter(ctm, b2, angle) {
|
|
537
|
-
const cx = (b2.minX + b2.maxX) / 2;
|
|
538
|
-
const cy = (b2.minY + b2.maxY) / 2;
|
|
539
|
-
const c3 = Math.cos(angle);
|
|
540
|
-
const s = Math.sin(angle);
|
|
541
|
-
return multiply(ctm, [c3, s, -s, c3, cx - cx * c3 + cy * s, cy - cx * s - cy * c3]);
|
|
542
|
-
}
|
|
543
|
-
function textXml(node, registry, namespaces) {
|
|
544
|
-
const attrs = [
|
|
545
|
-
`x="${trimNumber(node.x + anchorOffset(node.style, node.width))}"`,
|
|
546
|
-
`y="${trimNumber(node.y)}"`,
|
|
547
|
-
`dominant-baseline="text-before-edge"`,
|
|
548
|
-
// The runs model stores real line breaks; SVG's default whitespace
|
|
549
|
-
// handling would collapse them (and any indentation) away on re-import.
|
|
550
|
-
`xml:space="preserve"`,
|
|
551
|
-
`data-weasel-width="${trimNumber(node.width)}"`,
|
|
552
|
-
`data-weasel-height="${trimNumber(node.height)}"`
|
|
553
|
-
];
|
|
554
|
-
const style = node.style;
|
|
555
|
-
if (style?.fontSize != null) attrs.push(`font-size="${trimNumber(style.fontSize)}"`);
|
|
556
|
-
if (style?.fontFamily) attrs.push(`font-family="${escapeAttr2(style.fontFamily)}"`);
|
|
557
|
-
if (style?.fontWeight != null) attrs.push(`font-weight="${String(style.fontWeight)}"`);
|
|
558
|
-
if (style?.fontStyle && style.fontStyle !== "normal") attrs.push(`font-style="${style.fontStyle}"`);
|
|
559
|
-
const direction = style?.direction ?? "ltr";
|
|
560
|
-
if (direction === "rtl") attrs.push('direction="rtl"');
|
|
561
|
-
if (style?.align != null || direction === "rtl") {
|
|
562
|
-
const align = style?.align ?? "left";
|
|
563
|
-
const anchor = align === "center" ? "middle" : align === "start" ? "start" : align === "end" ? "end" : align === "left" === (direction === "ltr") ? "start" : "end";
|
|
564
|
-
if (anchor !== "start") attrs.push(`text-anchor="${anchor}"`);
|
|
565
|
-
}
|
|
566
|
-
if (style?.letterSpacing != null && style.letterSpacing !== 0) {
|
|
567
|
-
attrs.push(`letter-spacing="${trimNumber(style.letterSpacing)}"`);
|
|
568
|
-
}
|
|
569
|
-
const decoration = textDecorationValue(style?.underline, style?.strikethrough, style?.overline);
|
|
570
|
-
if (decoration) attrs.push(`text-decoration="${decoration}"`);
|
|
571
|
-
if (style?.wrap) attrs.push('data-weasel-wrap="true"');
|
|
572
|
-
if (node.fill === null) {
|
|
573
|
-
attrs.push('fill="none"');
|
|
574
|
-
} else if (node.fill) {
|
|
575
|
-
if ("color" in node.fill) {
|
|
576
|
-
attrs.push(`fill="${node.fill.color}"`);
|
|
577
|
-
if (node.fill.opacity != null && node.fill.opacity !== 1) {
|
|
578
|
-
attrs.push(`fill-opacity="${trimNumber(node.fill.opacity)}"`);
|
|
579
|
-
}
|
|
580
|
-
} else {
|
|
581
|
-
const id = registry.register(node.fill);
|
|
582
|
-
attrs.push(`fill="url(#${id})"`);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
for (const a2 of coreStrokeAttrs(node.stroke, registry)) attrs.push(a2);
|
|
586
|
-
if (node.opacity != null && node.opacity !== 1) {
|
|
587
|
-
attrs.push(`opacity="${trimNumber(node.opacity)}"`);
|
|
588
|
-
}
|
|
589
|
-
if (node.rotation != null && node.rotation !== 0) {
|
|
590
|
-
const cx = node.x + node.width / 2;
|
|
591
|
-
const cy = node.y + node.height / 2;
|
|
592
|
-
const deg = node.rotation * 180 / Math.PI;
|
|
593
|
-
attrs.push(`transform="rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})"`);
|
|
594
|
-
}
|
|
595
|
-
const body = node.runs && node.runs.length > 0 ? node.runs.map((r3) => runXml(r3, registry)).join("") : escapeText(node.text);
|
|
596
|
-
const metaAttrs = metaAttrsXml(node.meta, namespaces);
|
|
597
|
-
const metaEls = metaElementsXml(node.meta, namespaces);
|
|
598
|
-
return `<text ${attrs.join(" ")}${metaAttrs}>${body}${metaEls}</text>`;
|
|
599
|
-
}
|
|
600
|
-
function runXml(run, registry) {
|
|
601
|
-
const attrs = [];
|
|
602
|
-
if (run.bold) attrs.push(`font-weight="700"`);
|
|
603
|
-
if (run.italic) attrs.push(`font-style="italic"`);
|
|
604
|
-
if (run.fontFamily) attrs.push(`font-family="${escapeAttr2(run.fontFamily)}"`);
|
|
605
|
-
const presetScale = run.script != null && run.baselineShift != null ? SCRIPT_METRICS[run.script].size : void 0;
|
|
606
|
-
const scale = run.fontScale ?? presetScale;
|
|
607
|
-
if (run.fontSize != null) attrs.push(`font-size="${trimNumber(run.fontSize)}"`);
|
|
608
|
-
else if (scale != null) attrs.push(`font-size="${trimNumber(scale * 100)}%"`);
|
|
609
|
-
if (run.baselineShift != null) {
|
|
610
|
-
attrs.push(`baseline-shift="${trimNumber(run.baselineShift * 100)}%"`);
|
|
611
|
-
} else if (run.script) {
|
|
612
|
-
attrs.push(`baseline-shift="${run.script}"`);
|
|
613
|
-
}
|
|
614
|
-
if (run.letterSpacing != null) {
|
|
615
|
-
attrs.push(`letter-spacing="${trimNumber(run.letterSpacing)}"`);
|
|
616
|
-
}
|
|
617
|
-
const runDecoration = textDecorationValue(run.underline, run.strikethrough, run.overline);
|
|
618
|
-
if (runDecoration) attrs.push(`text-decoration="${runDecoration}"`);
|
|
619
|
-
if (run.fill) {
|
|
620
|
-
if ("color" in run.fill) {
|
|
621
|
-
attrs.push(`fill="${run.fill.color}"`);
|
|
622
|
-
} else {
|
|
623
|
-
const id = registry.register(run.fill);
|
|
624
|
-
attrs.push(`fill="url(#${id})"`);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
for (const a2 of coreStrokeAttrs(run.stroke, registry)) attrs.push(a2);
|
|
628
|
-
const head = attrs.length > 0 ? `<tspan ${attrs.join(" ")}>` : "<tspan>";
|
|
629
|
-
return `${head}${escapeText(run.text)}</tspan>`;
|
|
630
|
-
}
|
|
631
|
-
function textDecorationValue(underline, strikethrough, overline) {
|
|
632
|
-
const tokens = [];
|
|
633
|
-
if (underline) tokens.push("underline");
|
|
634
|
-
if (strikethrough) tokens.push("line-through");
|
|
635
|
-
if (overline) tokens.push("overline");
|
|
636
|
-
return tokens.length > 0 ? tokens.join(" ") : null;
|
|
637
|
-
}
|
|
638
|
-
function escapeAttr2(s) {
|
|
639
|
-
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
640
|
-
}
|
|
641
|
-
function escapeText(s) {
|
|
642
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
643
|
-
}
|
|
644
|
-
function pathBounds(path) {
|
|
645
|
-
if (path.kind === "rect") {
|
|
646
|
-
return {
|
|
647
|
-
minX: path.x,
|
|
648
|
-
minY: path.y,
|
|
649
|
-
maxX: path.x + path.width,
|
|
650
|
-
maxY: path.y + path.height
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
const b2 = boundsOfPath(path);
|
|
654
|
-
return { minX: b2.x, minY: b2.y, maxX: b2.x + b2.width, maxY: b2.y + b2.height };
|
|
655
|
-
}
|
|
656
56
|
var MARK_COLOR = "#e5484d";
|
|
657
57
|
var MARK_WIDTH = 2;
|
|
658
58
|
var TEXT_SIZE = 14;
|
|
@@ -660,24 +60,24 @@ var toWorld = (p2, content) => ({
|
|
|
660
60
|
x: p2.x * content.w,
|
|
661
61
|
y: p2.y * content.h
|
|
662
62
|
});
|
|
663
|
-
function vertices(
|
|
664
|
-
const stored =
|
|
63
|
+
function vertices(m2, content) {
|
|
64
|
+
const stored = m2.data.points;
|
|
665
65
|
if (stored && stored.length >= 2) return stored.map((p2) => toWorld(p2, content));
|
|
666
|
-
const { x, y, width, height } =
|
|
66
|
+
const { x, y: y3, width, height } = m2.pose;
|
|
667
67
|
return [
|
|
668
|
-
{ x, y },
|
|
669
|
-
{ x: x + width, y:
|
|
68
|
+
{ x, y: y3 },
|
|
69
|
+
{ x: x + width, y: y3 + height }
|
|
670
70
|
];
|
|
671
71
|
}
|
|
672
72
|
function polyline(points) {
|
|
673
|
-
const
|
|
73
|
+
const b3 = new PathBuilder();
|
|
674
74
|
const first = points[0];
|
|
675
75
|
if (!first) return rectPath(0, 0, 0, 0);
|
|
676
|
-
|
|
677
|
-
for (const p2 of points.slice(1))
|
|
678
|
-
return
|
|
76
|
+
b3.moveTo(first.x, first.y);
|
|
77
|
+
for (const p2 of points.slice(1)) b3.lineTo(p2.x, p2.y);
|
|
78
|
+
return b3.build();
|
|
679
79
|
}
|
|
680
|
-
function markCommands(
|
|
80
|
+
function markCommands(m2, content, style = {}) {
|
|
681
81
|
const color = style.color ?? MARK_COLOR;
|
|
682
82
|
const stroke = {
|
|
683
83
|
paint: { color },
|
|
@@ -686,35 +86,35 @@ function markCommands(m, content, style = {}) {
|
|
|
686
86
|
join: "round",
|
|
687
87
|
...style.stale ? { dash: [6, 4] } : {}
|
|
688
88
|
};
|
|
689
|
-
switch (
|
|
89
|
+
switch (m2.data.kind) {
|
|
690
90
|
case "rect":
|
|
691
91
|
return [
|
|
692
|
-
{ kind: "path", path: rectPath(
|
|
92
|
+
{ kind: "path", path: rectPath(m2.pose.x, m2.pose.y, m2.pose.width, m2.pose.height), stroke }
|
|
693
93
|
];
|
|
694
94
|
case "ellipse":
|
|
695
|
-
return [{ kind: "path", path: ellipsePath(
|
|
95
|
+
return [{ kind: "path", path: ellipsePath(m2.pose), stroke }];
|
|
696
96
|
case "line": {
|
|
697
|
-
const [
|
|
698
|
-
return [{ kind: "path", path: linePath(
|
|
97
|
+
const [a4, b3] = vertices(m2, content);
|
|
98
|
+
return [{ kind: "path", path: linePath(a4, b3), stroke }];
|
|
699
99
|
}
|
|
700
100
|
case "arrow": {
|
|
701
|
-
const [
|
|
101
|
+
const [a4, b3] = vertices(m2, content);
|
|
702
102
|
const marked = { ...stroke, markerEnd: "arrow" };
|
|
703
|
-
const path = linePath(
|
|
103
|
+
const path = linePath(a4, b3);
|
|
704
104
|
return [
|
|
705
105
|
{ kind: "path", path, stroke: marked },
|
|
706
106
|
...markerDrawCommands(path, marked, MARK_WIDTH, void 0)
|
|
707
107
|
];
|
|
708
108
|
}
|
|
709
109
|
case "stroke":
|
|
710
|
-
return [{ kind: "path", path: polyline(vertices(
|
|
110
|
+
return [{ kind: "path", path: polyline(vertices(m2, content)), stroke }];
|
|
711
111
|
case "text": {
|
|
712
|
-
const text =
|
|
112
|
+
const text = m2.data.title;
|
|
713
113
|
if (!text) return [];
|
|
714
114
|
return [
|
|
715
115
|
textCommand(
|
|
716
|
-
|
|
717
|
-
|
|
116
|
+
m2.pose.x,
|
|
117
|
+
m2.pose.y,
|
|
718
118
|
text,
|
|
719
119
|
{ fontSize: TEXT_SIZE },
|
|
720
120
|
void 0,
|
|
@@ -734,8 +134,8 @@ function seenFrom(config, keys) {
|
|
|
734
134
|
const out = {};
|
|
735
135
|
if (config === null || typeof config !== "object") return out;
|
|
736
136
|
const src = config;
|
|
737
|
-
for (const
|
|
738
|
-
if (
|
|
137
|
+
for (const k3 of keys) {
|
|
138
|
+
if (k3 in src) out[k3] = src[k3];
|
|
739
139
|
}
|
|
740
140
|
return out;
|
|
741
141
|
}
|
|
@@ -743,9 +143,9 @@ function isStale(seen, config, keys) {
|
|
|
743
143
|
if (!seen || keys.length === 0) return false;
|
|
744
144
|
if (config === null || typeof config !== "object") return false;
|
|
745
145
|
const src = config;
|
|
746
|
-
for (const
|
|
747
|
-
if (!(
|
|
748
|
-
if (!Object.is(seen[
|
|
146
|
+
for (const k3 of keys) {
|
|
147
|
+
if (!(k3 in seen)) continue;
|
|
148
|
+
if (!Object.is(seen[k3], src[k3])) return true;
|
|
749
149
|
}
|
|
750
150
|
return false;
|
|
751
151
|
}
|
|
@@ -756,7 +156,7 @@ function createMarkDrawOne(opts) {
|
|
|
756
156
|
}
|
|
757
157
|
function resolveMarkStyle(data, opts) {
|
|
758
158
|
return {
|
|
759
|
-
color: opts.meaning?.statuses?.find((
|
|
159
|
+
color: opts.meaning?.statuses?.find((s5) => s5.id === data.status)?.color,
|
|
760
160
|
// Read off the node rather than through the store's `isStale`, which
|
|
761
161
|
// wants a projected Annotation this path does not have.
|
|
762
162
|
stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
|
|
@@ -783,10 +183,11 @@ function toSvgStroke(stroke) {
|
|
|
783
183
|
...stroke.cap ? { cap: stroke.cap } : {},
|
|
784
184
|
...stroke.join ? { join: stroke.join } : {},
|
|
785
185
|
...stroke.dash ? { dash: [...stroke.dash] } : {},
|
|
786
|
-
...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {}
|
|
186
|
+
...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {},
|
|
187
|
+
...stroke.align ? { align: stroke.align } : {}
|
|
787
188
|
};
|
|
788
189
|
}
|
|
789
|
-
function toSvgNode(cmd,
|
|
190
|
+
function toSvgNode(cmd, m2) {
|
|
790
191
|
if (cmd.kind === "path") {
|
|
791
192
|
return {
|
|
792
193
|
kind: "path",
|
|
@@ -800,8 +201,8 @@ function toSvgNode(cmd, m) {
|
|
|
800
201
|
kind: "text",
|
|
801
202
|
x: cmd.x,
|
|
802
203
|
y: cmd.y,
|
|
803
|
-
width:
|
|
804
|
-
height:
|
|
204
|
+
width: m2.pose.width,
|
|
205
|
+
height: m2.pose.height,
|
|
805
206
|
text: cmd.runs.map((run) => run.text).join(""),
|
|
806
207
|
style: cmd.style,
|
|
807
208
|
...cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}
|
|
@@ -809,8 +210,8 @@ function toSvgNode(cmd, m) {
|
|
|
809
210
|
}
|
|
810
211
|
throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);
|
|
811
212
|
}
|
|
812
|
-
function markSvgNodes(
|
|
813
|
-
return markCommands(
|
|
213
|
+
function markSvgNodes(m2, content, style = {}) {
|
|
214
|
+
return markCommands(m2, content, style).map((cmd) => toSvgNode(cmd, m2));
|
|
814
215
|
}
|
|
815
216
|
|
|
816
217
|
// src/annotations/capture.ts
|
|
@@ -819,7 +220,7 @@ function capturePlan(base, format) {
|
|
|
819
220
|
if (format === "svg") return "svg-document";
|
|
820
221
|
return base?.kind === "svg" ? "svg-document" : "raster-stack";
|
|
821
222
|
}
|
|
822
|
-
function nestBaseSvg(markup,
|
|
223
|
+
function nestBaseSvg(markup, w3, h2) {
|
|
823
224
|
const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
|
|
824
225
|
const root = doc.documentElement;
|
|
825
226
|
if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
|
|
@@ -827,17 +228,17 @@ function nestBaseSvg(markup, w2, h2) {
|
|
|
827
228
|
}
|
|
828
229
|
root.setAttribute("x", "0");
|
|
829
230
|
root.setAttribute("y", "0");
|
|
830
|
-
root.setAttribute("width", String(
|
|
231
|
+
root.setAttribute("width", String(w3));
|
|
831
232
|
root.setAttribute("height", String(h2));
|
|
832
233
|
return new XMLSerializer().serializeToString(root);
|
|
833
234
|
}
|
|
834
|
-
function embedRasterBase(base,
|
|
235
|
+
function embedRasterBase(base, w3, h2, onWarn) {
|
|
835
236
|
const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
|
|
836
237
|
if (base.kind === "image" && !href.startsWith("data:")) {
|
|
837
238
|
onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
|
|
838
239
|
}
|
|
839
|
-
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width:
|
|
840
|
-
viewBox: { x: 0, y: 0, width:
|
|
240
|
+
return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height: h2 }], {
|
|
241
|
+
viewBox: { x: 0, y: 0, width: w3, height: h2 }
|
|
841
242
|
});
|
|
842
243
|
}
|
|
843
244
|
function markNodesOf(scene, draw) {
|
|
@@ -853,15 +254,15 @@ function markNodesOf(scene, draw) {
|
|
|
853
254
|
}
|
|
854
255
|
function composeCaptureSvg(args) {
|
|
855
256
|
const { base, scene, draw, scale, onWarn } = args;
|
|
856
|
-
const { w:
|
|
857
|
-
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup,
|
|
257
|
+
const { w: w3, h: h2 } = draw.content;
|
|
258
|
+
const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w3, h2) : embedRasterBase(base, w3, h2, onWarn);
|
|
858
259
|
const marksXml = serializeSvg(markNodesOf(scene, draw), {
|
|
859
|
-
viewBox: { x: 0, y: 0, width:
|
|
260
|
+
viewBox: { x: 0, y: 0, width: w3, height: h2 },
|
|
860
261
|
onWarn
|
|
861
262
|
});
|
|
862
|
-
const outW = Math.max(1, Math.round(
|
|
263
|
+
const outW = Math.max(1, Math.round(w3 * scale));
|
|
863
264
|
const outH = Math.max(1, Math.round(h2 * scale));
|
|
864
|
-
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${
|
|
265
|
+
return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${h2}">${baseXml}${marksXml}</svg>`;
|
|
865
266
|
}
|
|
866
267
|
function context2d(width, height) {
|
|
867
268
|
const canvas = document.createElement("canvas");
|
|
@@ -963,10 +364,10 @@ function fracToWorld(f3, content) {
|
|
|
963
364
|
height: f3.h * content.h
|
|
964
365
|
};
|
|
965
366
|
}
|
|
966
|
-
function worldToFrac(
|
|
367
|
+
function worldToFrac(r9, content) {
|
|
967
368
|
const sx = content.w === 0 ? 0 : 1 / content.w;
|
|
968
369
|
const sy = content.h === 0 ? 0 : 1 / content.h;
|
|
969
|
-
return { x:
|
|
370
|
+
return { x: r9.x * sx, y: r9.y * sy, w: r9.width * sx, h: r9.height * sy };
|
|
970
371
|
}
|
|
971
372
|
var DP = 1e4;
|
|
972
373
|
function roundFrac(f3) {
|
|
@@ -1016,8 +417,8 @@ var MarkHistory = class {
|
|
|
1016
417
|
/** The target `undo` would act on, skipping any whose scene has nothing
|
|
1017
418
|
* left — a scene can drop entries this ordering still lists. */
|
|
1018
419
|
next(stack, can, at) {
|
|
1019
|
-
for (let
|
|
1020
|
-
const target = stack[
|
|
420
|
+
for (let i3 = stack.length - 1; i3 >= 0; i3--) {
|
|
421
|
+
const target = stack[i3];
|
|
1021
422
|
if (target === void 0) continue;
|
|
1022
423
|
const scene = at(target);
|
|
1023
424
|
if (scene && can(scene)) return target;
|
|
@@ -1025,13 +426,13 @@ var MarkHistory = class {
|
|
|
1025
426
|
return null;
|
|
1026
427
|
}
|
|
1027
428
|
canUndo(at) {
|
|
1028
|
-
return this.next(this.undoable, (
|
|
429
|
+
return this.next(this.undoable, (s5) => s5.canUndo(), at) !== null;
|
|
1029
430
|
}
|
|
1030
431
|
canRedo(at) {
|
|
1031
|
-
return this.next(this.redoable, (
|
|
432
|
+
return this.next(this.redoable, (s5) => s5.canRedo(), at) !== null;
|
|
1032
433
|
}
|
|
1033
434
|
undo(at) {
|
|
1034
|
-
const target = this.next(this.undoable, (
|
|
435
|
+
const target = this.next(this.undoable, (s5) => s5.canUndo(), at);
|
|
1035
436
|
const scene = target === null ? void 0 : at(target);
|
|
1036
437
|
if (!scene) return false;
|
|
1037
438
|
this.replaying = "undo";
|
|
@@ -1042,7 +443,7 @@ var MarkHistory = class {
|
|
|
1042
443
|
}
|
|
1043
444
|
}
|
|
1044
445
|
redo(at) {
|
|
1045
|
-
const target = this.next(this.redoable, (
|
|
446
|
+
const target = this.next(this.redoable, (s5) => s5.canRedo(), at);
|
|
1046
447
|
const scene = target === null ? void 0 : at(target);
|
|
1047
448
|
if (!scene) return false;
|
|
1048
449
|
this.replaying = "redo";
|
|
@@ -1054,9 +455,9 @@ var MarkHistory = class {
|
|
|
1054
455
|
}
|
|
1055
456
|
};
|
|
1056
457
|
function drop(stack, value) {
|
|
1057
|
-
for (let
|
|
1058
|
-
if (stack[
|
|
1059
|
-
stack.splice(
|
|
458
|
+
for (let i3 = stack.length - 1; i3 >= 0; i3--) {
|
|
459
|
+
if (stack[i3] === value) {
|
|
460
|
+
stack.splice(i3, 1);
|
|
1060
461
|
return;
|
|
1061
462
|
}
|
|
1062
463
|
}
|
|
@@ -1117,21 +518,21 @@ function createAnnotationStore(opts) {
|
|
|
1117
518
|
if (!scene) return [];
|
|
1118
519
|
const out = [];
|
|
1119
520
|
for (const id of scene.renderOrder()) {
|
|
1120
|
-
const
|
|
1121
|
-
if (
|
|
521
|
+
const a4 = project(target, String(id));
|
|
522
|
+
if (a4) out.push(a4);
|
|
1122
523
|
}
|
|
1123
524
|
return out;
|
|
1124
525
|
};
|
|
1125
526
|
const all = () => liveTargets().flatMap(marksOn);
|
|
1126
|
-
const matches = (
|
|
1127
|
-
if (
|
|
1128
|
-
if (
|
|
1129
|
-
if (
|
|
1130
|
-
if (
|
|
1131
|
-
const have =
|
|
1132
|
-
for (const t of
|
|
527
|
+
const matches = (a4, q2) => {
|
|
528
|
+
if (q2.target !== void 0 && a4.target !== q2.target) return false;
|
|
529
|
+
if (q2.kind !== void 0 && a4.kind !== q2.kind) return false;
|
|
530
|
+
if (q2.status !== void 0 && a4.status !== q2.status) return false;
|
|
531
|
+
if (q2.tags !== void 0) {
|
|
532
|
+
const have = a4.tags ?? [];
|
|
533
|
+
for (const t of q2.tags) if (!have.includes(t)) return false;
|
|
1133
534
|
}
|
|
1134
|
-
if (
|
|
535
|
+
if (q2.where && !q2.where(a4)) return false;
|
|
1135
536
|
return true;
|
|
1136
537
|
};
|
|
1137
538
|
const nodeOf = (id) => {
|
|
@@ -1148,18 +549,18 @@ function createAnnotationStore(opts) {
|
|
|
1148
549
|
const parts = splitId(id);
|
|
1149
550
|
return parts ? project(parts.target, parts.node) : void 0;
|
|
1150
551
|
},
|
|
1151
|
-
query(
|
|
1152
|
-
return
|
|
552
|
+
query(q2) {
|
|
553
|
+
return q2 ? all().filter((a4) => matches(a4, q2)) : all();
|
|
1153
554
|
},
|
|
1154
555
|
hitTest(target, pt, tol = 0) {
|
|
1155
|
-
return marksOn(target).filter((
|
|
556
|
+
return marksOn(target).filter((a4) => fracContains(a4.frac, pt, tol)).reverse();
|
|
1156
557
|
},
|
|
1157
558
|
within(target, box) {
|
|
1158
|
-
return marksOn(target).filter((
|
|
559
|
+
return marksOn(target).filter((a4) => fracEncloses(box, a4.frac));
|
|
1159
560
|
},
|
|
1160
|
-
isStale(
|
|
1161
|
-
const keys = targetOf(
|
|
1162
|
-
return isStale(
|
|
561
|
+
isStale(a4, config) {
|
|
562
|
+
const keys = targetOf(a4.target)?.positionDependsOn ?? [];
|
|
563
|
+
return isStale(a4.seen, config, keys);
|
|
1163
564
|
},
|
|
1164
565
|
canUndo() {
|
|
1165
566
|
return history.canUndo(historySceneAt);
|
|
@@ -1197,7 +598,7 @@ function createAnnotationStore(opts) {
|
|
|
1197
598
|
for (const [target, scene] of scenes) {
|
|
1198
599
|
const next = wanted.get(target) ?? [];
|
|
1199
600
|
const now = scene.getSelection();
|
|
1200
|
-
if (now.length === next.length && next.every((
|
|
601
|
+
if (now.length === next.length && next.every((n6, i3) => String(now[i3]) === n6)) continue;
|
|
1201
602
|
scene.setSelection(next.map(asNodeId$1));
|
|
1202
603
|
}
|
|
1203
604
|
},
|
|
@@ -1293,12 +694,14 @@ var TOOLS = {
|
|
|
1293
694
|
text: { weaselTool: "text", kind: "text" }
|
|
1294
695
|
};
|
|
1295
696
|
var ANNOTATION_TOOLS = [
|
|
697
|
+
// Not in `TOOLS`: an id the map does not carry is what leaves the overlay idle.
|
|
698
|
+
{ id: "pointer", label: "Interact", icon: a2, group: "annotate" },
|
|
1296
699
|
{ id: "select", label: "Select", icon: p, group: "annotate" },
|
|
1297
700
|
{ id: "stroke", label: "Freehand", icon: u, group: "annotate" },
|
|
1298
701
|
{ id: "line", label: "Line", icon: c, group: "annotate" },
|
|
1299
702
|
{ id: "arrow", label: "Arrow", icon: n, group: "annotate" },
|
|
1300
703
|
{ id: "rect", label: "Rectangle", icon: f, group: "annotate" },
|
|
1301
|
-
{ id: "ellipse", label: "Ellipse", icon:
|
|
704
|
+
{ id: "ellipse", label: "Ellipse", icon: r, group: "annotate" },
|
|
1302
705
|
{ id: "text", label: "Text", icon: h, group: "annotate" }
|
|
1303
706
|
];
|
|
1304
707
|
function annotationToolInfo(id) {
|
|
@@ -1309,17 +712,17 @@ var ANNOTATION_WEASEL_TOOLS = [
|
|
|
1309
712
|
];
|
|
1310
713
|
|
|
1311
714
|
// src/annotations/view.ts
|
|
1312
|
-
function toWeaselView(
|
|
1313
|
-
return { x:
|
|
715
|
+
function toWeaselView(v2) {
|
|
716
|
+
return { x: v2.pan.x, y: v2.pan.y, scale: { x: v2.zoom, y: v2.zoom } };
|
|
1314
717
|
}
|
|
1315
|
-
function fromWeaselView(
|
|
1316
|
-
return { zoom:
|
|
718
|
+
function fromWeaselView(v2) {
|
|
719
|
+
return { zoom: v2.scale.x, pan: { x: v2.x, y: v2.y } };
|
|
1317
720
|
}
|
|
1318
721
|
function fitView(content, pane) {
|
|
1319
722
|
const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
|
|
1320
723
|
return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
|
|
1321
724
|
}
|
|
1322
|
-
var sameRect = (
|
|
725
|
+
var sameRect = (a4, b3) => a4 !== null && a4.x === b3.x && a4.y === b3.y && a4.w === b3.w && a4.h === b3.h;
|
|
1323
726
|
function ToolBridge({ toolId }) {
|
|
1324
727
|
const tools = useActiveToolContext();
|
|
1325
728
|
const setActive = tools.setActive;
|
|
@@ -1450,6 +853,7 @@ function AnnotationOverlay({
|
|
|
1450
853
|
ref: setInput,
|
|
1451
854
|
className: "lk-annotate__input",
|
|
1452
855
|
"data-annotation-target": id,
|
|
856
|
+
"data-idle": annotationToolInfo(activeToolId) ? void 0 : "",
|
|
1453
857
|
role: "application",
|
|
1454
858
|
"aria-label": `Annotations on ${id}`,
|
|
1455
859
|
tabIndex: 0,
|
|
@@ -1561,823 +965,195 @@ function validateConfigSchema(fields) {
|
|
|
1561
965
|
}
|
|
1562
966
|
return { valid: errors.length === 0, errors };
|
|
1563
967
|
}
|
|
968
|
+
var AnnotationPreloadContext = createContext(null);
|
|
1564
969
|
|
|
1565
|
-
//
|
|
1566
|
-
var
|
|
1567
|
-
"
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
"value": "#25272c"
|
|
1600
|
-
},
|
|
1601
|
-
"gray-800": {
|
|
1602
|
-
"type": "color",
|
|
1603
|
-
"value": "#181a1e"
|
|
1604
|
-
},
|
|
1605
|
-
"gray-900": {
|
|
1606
|
-
"type": "color",
|
|
1607
|
-
"value": "#0e0f12"
|
|
1608
|
-
},
|
|
1609
|
-
"accent-soft": {
|
|
1610
|
-
"type": "color",
|
|
1611
|
-
"value": "#1d1454"
|
|
1612
|
-
},
|
|
1613
|
-
"accent-base": {
|
|
1614
|
-
"type": "color",
|
|
1615
|
-
"value": "#2e1f7a",
|
|
1616
|
-
"description": "Midnight blue-violet. Deep and saturated; anchors primary actions on light and dark surfaces alike."
|
|
1617
|
-
},
|
|
1618
|
-
"accent-strong": {
|
|
1619
|
-
"type": "color",
|
|
1620
|
-
"value": "#5841b8"
|
|
1621
|
-
},
|
|
1622
|
-
"danger-base": {
|
|
1623
|
-
"type": "color",
|
|
1624
|
-
"value": "#d94a3f"
|
|
1625
|
-
},
|
|
1626
|
-
"warning-base": {
|
|
1627
|
-
"type": "color",
|
|
1628
|
-
"value": "#d99a3f"
|
|
1629
|
-
},
|
|
1630
|
-
"success-base": {
|
|
1631
|
-
"type": "color",
|
|
1632
|
-
"value": "#2ec27e"
|
|
1633
|
-
},
|
|
1634
|
-
"fg-on-accent": {
|
|
1635
|
-
"type": "color",
|
|
1636
|
-
"value": "{color.gray-50}"
|
|
1637
|
-
},
|
|
1638
|
-
"line-subtle": {
|
|
1639
|
-
"type": "color",
|
|
1640
|
-
"value": "{color.fg}",
|
|
1641
|
-
"alpha": 0.1,
|
|
1642
|
-
"description": "Barely-there separators (table rows)."
|
|
1643
|
-
},
|
|
1644
|
-
"line": {
|
|
1645
|
-
"type": "color",
|
|
1646
|
-
"value": "{color.fg}",
|
|
1647
|
-
"alpha": 0.2,
|
|
1648
|
-
"description": "Primary gridlines on sunken surfaces."
|
|
1649
|
-
},
|
|
1650
|
-
"line-strong": {
|
|
1651
|
-
"type": "color",
|
|
1652
|
-
"value": "{color.fg}",
|
|
1653
|
-
"alpha": 0.4,
|
|
1654
|
-
"description": "Axes and emphasized dividers."
|
|
1655
|
-
},
|
|
1656
|
-
"curve-color": {
|
|
1657
|
-
"type": "color",
|
|
1658
|
-
"value": "{color.accent-strong}",
|
|
1659
|
-
"description": "Drawn data curves. Routes through the bright accent because accent-base is too dim on sunken surfaces."
|
|
1660
|
-
},
|
|
1661
|
-
"accent": {
|
|
1662
|
-
"type": "color",
|
|
1663
|
-
"value": "{color.accent-base}"
|
|
1664
|
-
},
|
|
1665
|
-
"accent-hover": {
|
|
1666
|
-
"type": "color",
|
|
1667
|
-
"value": "{color.accent-strong}"
|
|
1668
|
-
},
|
|
1669
|
-
"danger": {
|
|
1670
|
-
"type": "color",
|
|
1671
|
-
"value": "{color.danger-base}"
|
|
1672
|
-
},
|
|
1673
|
-
"warning": {
|
|
1674
|
-
"type": "color",
|
|
1675
|
-
"value": "{color.warning-base}"
|
|
1676
|
-
},
|
|
1677
|
-
"success": {
|
|
1678
|
-
"type": "color",
|
|
1679
|
-
"value": "{color.success-base}"
|
|
1680
|
-
},
|
|
1681
|
-
"focus-ring": {
|
|
1682
|
-
"type": "color",
|
|
1683
|
-
"value": "{color.accent-strong}"
|
|
1684
|
-
},
|
|
1685
|
-
"glass-tint": {
|
|
1686
|
-
"type": "color",
|
|
1687
|
-
"value": "{color.accent}",
|
|
1688
|
-
"description": "Frosted-glass tint. Components compose it as color-mix(in srgb, var(--wzl-glass-tint) 78%, transparent) with backdrop-filter: blur(3px)."
|
|
1689
|
-
},
|
|
1690
|
-
"surface-hover": {
|
|
1691
|
-
"type": "color",
|
|
1692
|
-
"value": "{color.fg}",
|
|
1693
|
-
"alpha": 0.1,
|
|
1694
|
-
"description": "Hover wash over a raised surface. Same formula as line-subtle, different job \u2014 do not collapse them."
|
|
1695
|
-
},
|
|
1696
|
-
"surface-pressed": {
|
|
1697
|
-
"type": "color",
|
|
1698
|
-
"value": "{color.fg}",
|
|
1699
|
-
"alpha": 0.18,
|
|
1700
|
-
"description": "Pressed wash over a raised surface."
|
|
1701
|
-
},
|
|
1702
|
-
"swatch-fuchsia": {
|
|
1703
|
-
"type": "color",
|
|
1704
|
-
"value": "#f641f7",
|
|
1705
|
-
"description": "First of ten categorical spot colors for plotting, status and data viz. Take them in sequence: the order is farthest-point over hue, so the first N are as separated as N colors can be (first three 87\xB0 apart, all ten 32\xB0). Mode-invariant on purpose \u2014 a series keeps its color when the mode flips, which is why they are tuned for a dark surface and clear only 1.5:1 on a light one."
|
|
1706
|
-
},
|
|
1707
|
-
"swatch-green": {
|
|
1708
|
-
"type": "color",
|
|
1709
|
-
"value": "#48e628"
|
|
1710
|
-
},
|
|
1711
|
-
"swatch-sky": {
|
|
1712
|
-
"type": "color",
|
|
1713
|
-
"value": "#36bff2"
|
|
1714
|
-
},
|
|
1715
|
-
"swatch-amber": {
|
|
1716
|
-
"type": "color",
|
|
1717
|
-
"value": "#e69628"
|
|
1718
|
-
},
|
|
1719
|
-
"swatch-teal": {
|
|
1720
|
-
"type": "color",
|
|
1721
|
-
"value": "#3ee1cb"
|
|
1722
|
-
},
|
|
1723
|
-
"swatch-red": {
|
|
1724
|
-
"type": "color",
|
|
1725
|
-
"value": "#f75034"
|
|
1726
|
-
},
|
|
1727
|
-
"swatch-blue": {
|
|
1728
|
-
"type": "color",
|
|
1729
|
-
"value": "#407ef7"
|
|
1730
|
-
},
|
|
1731
|
-
"swatch-citron": {
|
|
1732
|
-
"type": "color",
|
|
1733
|
-
"value": "#d5d23a"
|
|
1734
|
-
},
|
|
1735
|
-
"swatch-rose": {
|
|
1736
|
-
"type": "color",
|
|
1737
|
-
"value": "#fa4590"
|
|
1738
|
-
},
|
|
1739
|
-
"swatch-violet": {
|
|
1740
|
-
"type": "color",
|
|
1741
|
-
"value": "#955cf9"
|
|
1742
|
-
},
|
|
1743
|
-
"radius-sm": {
|
|
1744
|
-
"type": "dimension",
|
|
1745
|
-
"value": "3px"
|
|
1746
|
-
},
|
|
1747
|
-
"radius-md": {
|
|
1748
|
-
"type": "dimension",
|
|
1749
|
-
"value": "5px"
|
|
1750
|
-
},
|
|
1751
|
-
"radius-lg": {
|
|
1752
|
-
"type": "dimension",
|
|
1753
|
-
"value": "14px"
|
|
1754
|
-
},
|
|
1755
|
-
"radius-pill": {
|
|
1756
|
-
"type": "dimension",
|
|
1757
|
-
"value": "999px",
|
|
1758
|
-
"description": "Fully rounded ends \u2014 segmented controls, progress tracks."
|
|
1759
|
-
},
|
|
1760
|
-
"border-w": {
|
|
1761
|
-
"type": "dimension",
|
|
1762
|
-
"value": "1px"
|
|
1763
|
-
},
|
|
1764
|
-
"line-width": {
|
|
1765
|
-
"type": "dimension",
|
|
1766
|
-
"value": "2px",
|
|
1767
|
-
"description": "Structural lines \u2014 gridlines, dividers, axes."
|
|
1768
|
-
},
|
|
1769
|
-
"curve-width": {
|
|
1770
|
-
"type": "dimension",
|
|
1771
|
-
"value": "3px",
|
|
1772
|
-
"description": "Drawn data curves. Heavier than structural lines so data reads as primary content."
|
|
1773
|
-
},
|
|
1774
|
-
"tb-height": {
|
|
1775
|
-
"type": "dimension",
|
|
1776
|
-
"value": "28px",
|
|
1777
|
-
"description": "Height of a horizontal toolbar strip (ActionsBar, OptionsBar, ToolOptionsBar). Taller than control-h so the controls inside a strip are not flush with its edges."
|
|
1778
|
-
},
|
|
1779
|
-
"control-h": {
|
|
1780
|
-
"type": "dimension",
|
|
1781
|
-
"value": "24px",
|
|
1782
|
-
"description": "Height of an interactive control \u2014 button, input, select, segmented control. Distinct from tb-height, which sizes the strip a row of them sits in."
|
|
1783
|
-
},
|
|
1784
|
-
"slider-track-h": {
|
|
1785
|
-
"type": "dimension",
|
|
1786
|
-
"value": "4px",
|
|
1787
|
-
"description": "Height of a linear range track. The kit's single-thumb ranges all wear this; Slider's default 24px canvas track does not."
|
|
1788
|
-
},
|
|
1789
|
-
"slider-thumb-size": {
|
|
1790
|
-
"type": "dimension",
|
|
1791
|
-
"value": "8px",
|
|
1792
|
-
"description": "Diameter of a linear range thumb."
|
|
1793
|
-
},
|
|
1794
|
-
"slider-track-mix": {
|
|
1795
|
-
"type": "dimension",
|
|
1796
|
-
"value": "18%",
|
|
1797
|
-
"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."
|
|
1798
|
-
},
|
|
1799
|
-
"slider-thumb-mix": {
|
|
1800
|
-
"type": "dimension",
|
|
1801
|
-
"value": "70%",
|
|
1802
|
-
"description": "Accent proportion in a range thumb, as a color-mix percentage \u2014 not a color."
|
|
1803
|
-
},
|
|
1804
|
-
"field-pad-x": {
|
|
1805
|
-
"type": "dimension",
|
|
1806
|
-
"value": "8px",
|
|
1807
|
-
"description": "Horizontal padding inside a boxed field. Pairs with --wzl-field-h, which is a container override and has no :root default."
|
|
1808
|
-
},
|
|
1809
|
-
"glass-blur": {
|
|
1810
|
-
"type": "dimension",
|
|
1811
|
-
"value": "3px",
|
|
1812
|
-
"description": "Backdrop blur radius for frosted surfaces. Pairs with glass-tint."
|
|
1813
|
-
},
|
|
1814
|
-
"font-size-2xs": {
|
|
1815
|
-
"type": "dimension",
|
|
1816
|
-
"value": "9px",
|
|
1817
|
-
"description": "Shortcut keys and index badges. The floor for chrome text."
|
|
1818
|
-
},
|
|
1819
|
-
"font-size-xs": {
|
|
1820
|
-
"type": "dimension",
|
|
1821
|
-
"value": "10px",
|
|
1822
|
-
"description": "Tool-button labels under an icon."
|
|
1823
|
-
},
|
|
1824
|
-
"font-size-sm": {
|
|
1825
|
-
"type": "dimension",
|
|
1826
|
-
"value": "11px",
|
|
1827
|
-
"description": "Chrome labels, status readouts, section headings."
|
|
1828
|
-
},
|
|
1829
|
-
"font-size": {
|
|
1830
|
-
"type": "dimension",
|
|
1831
|
-
"value": "13px",
|
|
1832
|
-
"description": "Controls and body text."
|
|
1833
|
-
},
|
|
1834
|
-
"font-size-lg": {
|
|
1835
|
-
"type": "dimension",
|
|
1836
|
-
"value": "16px",
|
|
1837
|
-
"description": "Panel and dialog titles."
|
|
1838
|
-
},
|
|
1839
|
-
"font-size-xl": {
|
|
1840
|
-
"type": "dimension",
|
|
1841
|
-
"value": "20px",
|
|
1842
|
-
"description": "The largest chrome text \u2014 a lab or app title."
|
|
1843
|
-
},
|
|
1844
|
-
"space-xs": {
|
|
1845
|
-
"type": "dimension",
|
|
1846
|
-
"value": "4px"
|
|
1847
|
-
},
|
|
1848
|
-
"space-sm": {
|
|
1849
|
-
"type": "dimension",
|
|
1850
|
-
"value": "8px"
|
|
1851
|
-
},
|
|
1852
|
-
"space-md": {
|
|
1853
|
-
"type": "dimension",
|
|
1854
|
-
"value": "12px"
|
|
1855
|
-
},
|
|
1856
|
-
"space-lg": {
|
|
1857
|
-
"type": "dimension",
|
|
1858
|
-
"value": "16px"
|
|
1859
|
-
},
|
|
1860
|
-
"tracking-none": {
|
|
1861
|
-
"type": "dimension",
|
|
1862
|
-
"value": "0"
|
|
1863
|
-
},
|
|
1864
|
-
"tracking-wide": {
|
|
1865
|
-
"type": "dimension",
|
|
1866
|
-
"value": "0.06em",
|
|
1867
|
-
"description": "Uppercase section headings."
|
|
1868
|
-
},
|
|
1869
|
-
"tracking-wider": {
|
|
1870
|
-
"type": "dimension",
|
|
1871
|
-
"value": "0.08em",
|
|
1872
|
-
"description": "Uppercase at 11px and below."
|
|
1873
|
-
},
|
|
1874
|
-
"z-toolbar": {
|
|
1875
|
-
"type": "number",
|
|
1876
|
-
"value": 10
|
|
1877
|
-
},
|
|
1878
|
-
"z-overlay": {
|
|
1879
|
-
"type": "number",
|
|
1880
|
-
"value": 20
|
|
1881
|
-
},
|
|
1882
|
-
"z-modal": {
|
|
1883
|
-
"type": "number",
|
|
1884
|
-
"value": 30
|
|
1885
|
-
},
|
|
1886
|
-
"leading-tight": {
|
|
1887
|
-
"type": "number",
|
|
1888
|
-
"value": 1,
|
|
1889
|
-
"description": "Single-line controls; the box sets the height."
|
|
1890
|
-
},
|
|
1891
|
-
"leading-snug": {
|
|
1892
|
-
"type": "number",
|
|
1893
|
-
"value": 1.2,
|
|
1894
|
-
"description": "Headings and two-line labels."
|
|
1895
|
-
},
|
|
1896
|
-
"leading": {
|
|
1897
|
-
"type": "number",
|
|
1898
|
-
"value": 1.4,
|
|
1899
|
-
"description": "Body and anything that wraps."
|
|
1900
|
-
},
|
|
1901
|
-
"backdrop": {
|
|
1902
|
-
"type": "gradient",
|
|
1903
|
-
"value": "none",
|
|
1904
|
-
"description": "Layered backdrop fill for a page or lab root. `none` here; a theme with a signature background sets it."
|
|
1905
|
-
},
|
|
1906
|
-
"motion-fast": {
|
|
1907
|
-
"type": "duration",
|
|
1908
|
-
"value": "120ms",
|
|
1909
|
-
"description": "Micro-interactions \u2014 hover, focus, pressed."
|
|
1910
|
-
},
|
|
1911
|
-
"motion-medium": {
|
|
1912
|
-
"type": "duration",
|
|
1913
|
-
"value": "240ms",
|
|
1914
|
-
"description": "Entrances and exits \u2014 toasts, popovers, panels."
|
|
1915
|
-
},
|
|
1916
|
-
"ease-in-cubic": {
|
|
1917
|
-
"type": "cubicBezier",
|
|
1918
|
-
"value": [
|
|
1919
|
-
0.32,
|
|
1920
|
-
0,
|
|
1921
|
-
0.67,
|
|
1922
|
-
0
|
|
1923
|
-
]
|
|
1924
|
-
},
|
|
1925
|
-
"ease-out-cubic": {
|
|
1926
|
-
"type": "cubicBezier",
|
|
1927
|
-
"value": [
|
|
1928
|
-
0.33,
|
|
1929
|
-
1,
|
|
1930
|
-
0.68,
|
|
1931
|
-
1
|
|
1932
|
-
]
|
|
1933
|
-
},
|
|
1934
|
-
"ease-in-out-cubic": {
|
|
1935
|
-
"type": "cubicBezier",
|
|
1936
|
-
"value": [
|
|
1937
|
-
0.65,
|
|
1938
|
-
0,
|
|
1939
|
-
0.35,
|
|
1940
|
-
1
|
|
1941
|
-
]
|
|
1942
|
-
},
|
|
1943
|
-
"ease-out-back": {
|
|
1944
|
-
"type": "cubicBezier",
|
|
1945
|
-
"value": [
|
|
1946
|
-
0.34,
|
|
1947
|
-
1.56,
|
|
1948
|
-
0.64,
|
|
1949
|
-
1
|
|
1950
|
-
]
|
|
1951
|
-
},
|
|
1952
|
-
"font-ui": {
|
|
1953
|
-
"type": "fontFamily",
|
|
1954
|
-
"value": [
|
|
1955
|
-
"Oswald",
|
|
1956
|
-
"Helvetica Neue Condensed",
|
|
1957
|
-
"Arial Narrow",
|
|
1958
|
-
"system-ui",
|
|
1959
|
-
"sans-serif"
|
|
1960
|
-
],
|
|
1961
|
-
"description": "Condensed UI/display face. The heavier cuts get blocky at any size, so the weight tokens stay in the 200-400 range."
|
|
1962
|
-
},
|
|
1963
|
-
"font-display": {
|
|
1964
|
-
"type": "fontFamily",
|
|
1965
|
-
"value": [
|
|
1966
|
-
"Oswald",
|
|
1967
|
-
"Helvetica Neue Condensed",
|
|
1968
|
-
"Arial Narrow",
|
|
1969
|
-
"system-ui",
|
|
1970
|
-
"sans-serif"
|
|
1971
|
-
]
|
|
1972
|
-
},
|
|
1973
|
-
"font-body": {
|
|
1974
|
-
"type": "fontFamily",
|
|
1975
|
-
"value": [
|
|
1976
|
-
"Inter",
|
|
1977
|
-
"system-ui",
|
|
1978
|
-
"-apple-system",
|
|
1979
|
-
"Segoe UI",
|
|
1980
|
-
"sans-serif"
|
|
1981
|
-
]
|
|
1982
|
-
},
|
|
1983
|
-
"font-mono": {
|
|
1984
|
-
"type": "fontFamily",
|
|
1985
|
-
"value": [
|
|
1986
|
-
"ui-monospace",
|
|
1987
|
-
"SFMono-Regular",
|
|
1988
|
-
"Menlo",
|
|
1989
|
-
"Consolas",
|
|
1990
|
-
"monospace"
|
|
1991
|
-
]
|
|
1992
|
-
},
|
|
1993
|
-
"font-weight-light": {
|
|
1994
|
-
"type": "fontWeight",
|
|
1995
|
-
"value": 200
|
|
1996
|
-
},
|
|
1997
|
-
"font-weight-normal": {
|
|
1998
|
-
"type": "fontWeight",
|
|
1999
|
-
"value": 300
|
|
2000
|
-
},
|
|
2001
|
-
"font-weight-medium": {
|
|
2002
|
-
"type": "fontWeight",
|
|
2003
|
-
"value": 350
|
|
2004
|
-
},
|
|
2005
|
-
"font-weight-bold": {
|
|
2006
|
-
"type": "fontWeight",
|
|
2007
|
-
"value": 400
|
|
970
|
+
// src/theme/interstellar.theme.json
|
|
971
|
+
var interstellar_theme_default = {
|
|
972
|
+
name: "interstellar",
|
|
973
|
+
extends: "weasel",
|
|
974
|
+
pins: {
|
|
975
|
+
"radius-md": {
|
|
976
|
+
value: "6px",
|
|
977
|
+
type: "dimension"
|
|
978
|
+
},
|
|
979
|
+
"glass-blur": {
|
|
980
|
+
value: "12px",
|
|
981
|
+
type: "dimension"
|
|
982
|
+
},
|
|
983
|
+
"font-weight-light": {
|
|
984
|
+
value: 300,
|
|
985
|
+
type: "fontWeight"
|
|
986
|
+
},
|
|
987
|
+
"font-weight-medium": {
|
|
988
|
+
value: 500,
|
|
989
|
+
type: "fontWeight"
|
|
990
|
+
},
|
|
991
|
+
"font-weight-bold": {
|
|
992
|
+
value: 700,
|
|
993
|
+
type: "fontWeight"
|
|
994
|
+
},
|
|
995
|
+
surface: {
|
|
996
|
+
by: "mode",
|
|
997
|
+
dark: {
|
|
998
|
+
value: "#0a0a14",
|
|
999
|
+
type: "color"
|
|
1000
|
+
},
|
|
1001
|
+
light: {
|
|
1002
|
+
value: "#fafaf7",
|
|
1003
|
+
type: "color"
|
|
2008
1004
|
}
|
|
2009
1005
|
},
|
|
2010
|
-
"
|
|
2011
|
-
"
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
},
|
|
2020
|
-
"surface-sunken": {
|
|
2021
|
-
"type": "color",
|
|
2022
|
-
"value": "{color.gray-900}"
|
|
2023
|
-
},
|
|
2024
|
-
"fg": {
|
|
2025
|
-
"type": "color",
|
|
2026
|
-
"value": "{color.gray-100}"
|
|
2027
|
-
},
|
|
2028
|
-
"fg-muted": {
|
|
2029
|
-
"type": "color",
|
|
2030
|
-
"value": "{color.gray-300}"
|
|
2031
|
-
},
|
|
2032
|
-
"fg-subtle": {
|
|
2033
|
-
"type": "color",
|
|
2034
|
-
"value": "{color.gray-400}"
|
|
2035
|
-
},
|
|
2036
|
-
"border": {
|
|
2037
|
-
"type": "color",
|
|
2038
|
-
"value": "{color.gray-700}"
|
|
2039
|
-
},
|
|
2040
|
-
"border-strong": {
|
|
2041
|
-
"type": "color",
|
|
2042
|
-
"value": "{color.gray-400}",
|
|
2043
|
-
"description": "The line that has to be seen: a control's edge, a raised surface's outline. Clears WCAG 1.4.11's 3:1 against every surface in both modes."
|
|
2044
|
-
},
|
|
2045
|
-
"accent-fg": {
|
|
2046
|
-
"type": "color",
|
|
2047
|
-
"value": "{color.accent-strong}",
|
|
2048
|
-
"description": "Accent for foreground use \u2014 text, icons, selected labels drawn on a surface. accent is a fill; the midnight base is too dim to read as text on dark surfaces."
|
|
2049
|
-
},
|
|
2050
|
-
"fg-inverse": {
|
|
2051
|
-
"type": "color",
|
|
2052
|
-
"value": "{color.gray-900}",
|
|
2053
|
-
"description": "Text drawn on a filled foreground-colored element (e.g. a slider thumb). Flips with the mode, so it is a semantic, not an alias to a primitive."
|
|
2054
|
-
},
|
|
2055
|
-
"shadow": {
|
|
2056
|
-
"type": "color",
|
|
2057
|
-
"value": "rgba(0, 0, 0, 0.6)",
|
|
2058
|
-
"description": "Elevation. Always darker than any surface \u2014 never derived from fg, which is near-white on dark."
|
|
2059
|
-
}
|
|
2060
|
-
},
|
|
2061
|
-
"light": {
|
|
2062
|
-
"surface": {
|
|
2063
|
-
"type": "color",
|
|
2064
|
-
"value": "{color.gray-50}"
|
|
2065
|
-
},
|
|
2066
|
-
"surface-raised": {
|
|
2067
|
-
"type": "color",
|
|
2068
|
-
"value": "{color.gray-100}"
|
|
2069
|
-
},
|
|
2070
|
-
"surface-sunken": {
|
|
2071
|
-
"type": "color",
|
|
2072
|
-
"value": "{color.gray-200}"
|
|
2073
|
-
},
|
|
2074
|
-
"fg": {
|
|
2075
|
-
"type": "color",
|
|
2076
|
-
"value": "{color.gray-900}"
|
|
2077
|
-
},
|
|
2078
|
-
"fg-muted": {
|
|
2079
|
-
"type": "color",
|
|
2080
|
-
"value": "{color.gray-600}"
|
|
2081
|
-
},
|
|
2082
|
-
"fg-subtle": {
|
|
2083
|
-
"type": "color",
|
|
2084
|
-
"value": "{color.gray-500}"
|
|
2085
|
-
},
|
|
2086
|
-
"border": {
|
|
2087
|
-
"type": "color",
|
|
2088
|
-
"value": "{color.gray-200}"
|
|
2089
|
-
},
|
|
2090
|
-
"border-strong": {
|
|
2091
|
-
"type": "color",
|
|
2092
|
-
"value": "{color.gray-500}"
|
|
2093
|
-
},
|
|
2094
|
-
"accent-fg": {
|
|
2095
|
-
"type": "color",
|
|
2096
|
-
"value": "{color.accent-base}",
|
|
2097
|
-
"description": "Flips to the deep base in light mode, where it is the legible one."
|
|
2098
|
-
},
|
|
2099
|
-
"fg-inverse": {
|
|
2100
|
-
"type": "color",
|
|
2101
|
-
"value": "{color.gray-50}",
|
|
2102
|
-
"description": "Flips with the mode \u2014 see the dark layer."
|
|
2103
|
-
},
|
|
2104
|
-
"shadow": {
|
|
2105
|
-
"type": "color",
|
|
2106
|
-
"value": "rgba(0, 0, 0, 0.18)"
|
|
2107
|
-
}
|
|
1006
|
+
"surface-raised": {
|
|
1007
|
+
by: "mode",
|
|
1008
|
+
dark: {
|
|
1009
|
+
value: "rgba(20, 20, 36, 0.55)",
|
|
1010
|
+
type: "color"
|
|
1011
|
+
},
|
|
1012
|
+
light: {
|
|
1013
|
+
value: "#ffffff",
|
|
1014
|
+
type: "color"
|
|
2108
1015
|
}
|
|
2109
|
-
}
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
function hexToRgba(hex, alpha) {
|
|
2120
|
-
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
|
|
2121
|
-
if (!m) throw new Error(`Expected a hex color, got "${hex}"`);
|
|
2122
|
-
const body = m[1];
|
|
2123
|
-
const full = body.length === 3 ? body.replace(/./g, (c3) => c3 + c3) : body;
|
|
2124
|
-
const r3 = Number.parseInt(full.slice(0, 2), 16);
|
|
2125
|
-
const g = Number.parseInt(full.slice(2, 4), 16);
|
|
2126
|
-
const b2 = Number.parseInt(full.slice(4, 6), 16);
|
|
2127
|
-
return `rgba(${r3}, ${g}, ${b2}, ${alpha})`;
|
|
2128
|
-
}
|
|
2129
|
-
var REF = /^\{([^}]+)\}$/;
|
|
2130
|
-
function refTarget(value) {
|
|
2131
|
-
if (typeof value !== "string") return null;
|
|
2132
|
-
const m = REF.exec(value.trim());
|
|
2133
|
-
if (!m) return null;
|
|
2134
|
-
const path = m[1];
|
|
2135
|
-
const dot = path.indexOf(".");
|
|
2136
|
-
return dot === -1 ? path : path.slice(dot + 1);
|
|
2137
|
-
}
|
|
2138
|
-
function fontStack(value) {
|
|
2139
|
-
return value.map((f3) => typeof f3 === "string" && /\s/.test(f3) ? `'${f3}'` : String(f3)).join(", ");
|
|
2140
|
-
}
|
|
2141
|
-
function serialize(type, value) {
|
|
2142
|
-
if (Array.isArray(value)) {
|
|
2143
|
-
if (type === "cubicBezier") return `cubic-bezier(${value.join(", ")})`;
|
|
2144
|
-
if (type === "fontFamily") return fontStack(value);
|
|
2145
|
-
return value.join(", ");
|
|
2146
|
-
}
|
|
2147
|
-
return String(value);
|
|
2148
|
-
}
|
|
2149
|
-
function resolveTokens(tokens) {
|
|
2150
|
-
const out = {};
|
|
2151
|
-
const inProgress = /* @__PURE__ */ new Set();
|
|
2152
|
-
const resolveOne = (name) => {
|
|
2153
|
-
const cached = out[name];
|
|
2154
|
-
if (cached !== void 0) return cached;
|
|
2155
|
-
const token = tokens[name];
|
|
2156
|
-
if (!token) throw new Error(`Unknown token "${name}"`);
|
|
2157
|
-
if (inProgress.has(name)) {
|
|
2158
|
-
throw new Error(`Reference cycle at token "${name}" (${[...inProgress].join(" \u2192 ")})`);
|
|
2159
|
-
}
|
|
2160
|
-
inProgress.add(name);
|
|
2161
|
-
const target = refTarget(token.value);
|
|
2162
|
-
let value;
|
|
2163
|
-
if (target === null) {
|
|
2164
|
-
value = serialize(token.type, token.value);
|
|
2165
|
-
} else if (!tokens[target]) {
|
|
2166
|
-
throw new Error(`Token "${name}" references "${target}", which is not defined`);
|
|
2167
|
-
} else {
|
|
2168
|
-
value = resolveOne(target);
|
|
2169
|
-
}
|
|
2170
|
-
if (token.alpha !== void 0) value = hexToRgba(value, token.alpha);
|
|
2171
|
-
inProgress.delete(name);
|
|
2172
|
-
out[name] = value;
|
|
2173
|
-
return value;
|
|
2174
|
-
};
|
|
2175
|
-
for (const name of Object.keys(tokens)) resolveOne(name);
|
|
2176
|
-
return out;
|
|
2177
|
-
}
|
|
2178
|
-
function chain(theme) {
|
|
2179
|
-
const out = [];
|
|
2180
|
-
for (let t = theme; t; t = t.extends) out.unshift(t);
|
|
2181
|
-
return out;
|
|
2182
|
-
}
|
|
2183
|
-
function resolveTheme(theme, mode) {
|
|
2184
|
-
const themes = chain(theme);
|
|
2185
|
-
const effectiveMode = themes.some((t) => mode in t.modes) ? mode : theme.defaultMode;
|
|
2186
|
-
let merged = {};
|
|
2187
|
-
for (const t of themes) {
|
|
2188
|
-
merged = { ...merged, ...t.tokens, ...t.modes[effectiveMode] ?? {} };
|
|
2189
|
-
}
|
|
2190
|
-
const resolved = resolveTokens(merged);
|
|
2191
|
-
const out = {};
|
|
2192
|
-
for (const [name, value] of Object.entries(resolved)) out[`--wzl-${name}`] = value;
|
|
2193
|
-
return out;
|
|
2194
|
-
}
|
|
2195
|
-
var STYLE_ID = "wzl-themes";
|
|
2196
|
-
var emitted = /* @__PURE__ */ new Map();
|
|
2197
|
-
var sheet = null;
|
|
2198
|
-
var styleEl = null;
|
|
2199
|
-
function canAdopt() {
|
|
2200
|
-
return typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype && Array.isArray(document.adoptedStyleSheets);
|
|
2201
|
-
}
|
|
2202
|
-
function flushRules() {
|
|
2203
|
-
const css = [...emitted.values()].join("\n");
|
|
2204
|
-
if (canAdopt()) {
|
|
2205
|
-
if (!sheet) {
|
|
2206
|
-
sheet = new CSSStyleSheet();
|
|
2207
|
-
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
2208
|
-
}
|
|
2209
|
-
sheet.replaceSync(css);
|
|
2210
|
-
return;
|
|
2211
|
-
}
|
|
2212
|
-
if (!styleEl) {
|
|
2213
|
-
styleEl = document.createElement("style");
|
|
2214
|
-
styleEl.id = STYLE_ID;
|
|
2215
|
-
document.head.appendChild(styleEl);
|
|
2216
|
-
}
|
|
2217
|
-
styleEl.textContent = css;
|
|
2218
|
-
}
|
|
2219
|
-
function applyTheme(el, theme, mode) {
|
|
2220
|
-
if (typeof document === "undefined") return;
|
|
2221
|
-
const key = `${theme.name}::${mode}`;
|
|
2222
|
-
const resolved = resolveTheme(theme, mode);
|
|
2223
|
-
const body = Object.entries(resolved).map(([name, value]) => `${name}: ${value};`).join(" ");
|
|
2224
|
-
const rule = `[data-wzl-theme='${theme.name}'][data-wzl-mode='${mode}'] { ${body} }`;
|
|
2225
|
-
if (emitted.get(key) !== rule) {
|
|
2226
|
-
emitted.set(key, rule);
|
|
2227
|
-
flushRules();
|
|
2228
|
-
}
|
|
2229
|
-
el.setAttribute("data-wzl-theme", theme.name);
|
|
2230
|
-
el.setAttribute("data-wzl-mode", mode);
|
|
2231
|
-
}
|
|
2232
|
-
var ThemeContext = createContext(null);
|
|
2233
|
-
function ThemeProvider({
|
|
2234
|
-
theme = weaselTheme,
|
|
2235
|
-
mode,
|
|
2236
|
-
className,
|
|
2237
|
-
style,
|
|
2238
|
-
children
|
|
2239
|
-
}) {
|
|
2240
|
-
const ref = useRef(null);
|
|
2241
|
-
const effectiveMode = mode ?? theme.defaultMode;
|
|
2242
|
-
const value = useMemo(
|
|
2243
|
-
() => ({ theme, mode: effectiveMode, resolved: resolveTheme(theme, effectiveMode) }),
|
|
2244
|
-
[theme, effectiveMode]
|
|
2245
|
-
);
|
|
2246
|
-
useLayoutEffect(() => {
|
|
2247
|
-
if (ref.current) applyTheme(ref.current, theme, effectiveMode);
|
|
2248
|
-
}, [theme, effectiveMode]);
|
|
2249
|
-
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children: /* @__PURE__ */ jsx(
|
|
2250
|
-
"div",
|
|
2251
|
-
{
|
|
2252
|
-
ref,
|
|
2253
|
-
className,
|
|
2254
|
-
style,
|
|
2255
|
-
"data-wzl-theme": theme.name,
|
|
2256
|
-
"data-wzl-mode": effectiveMode,
|
|
2257
|
-
children
|
|
2258
|
-
}
|
|
2259
|
-
) });
|
|
2260
|
-
}
|
|
2261
|
-
function useThemeOptional() {
|
|
2262
|
-
return useContext(ThemeContext);
|
|
2263
|
-
}
|
|
2264
|
-
var AnnotationPreloadContext = createContext(null);
|
|
2265
|
-
|
|
2266
|
-
// ../theme/dist/index.js
|
|
2267
|
-
var ALPHA_EXT = "com.weasel.alpha";
|
|
2268
|
-
var isToken = (v) => typeof v === "object" && v !== null && "$value" in v;
|
|
2269
|
-
function flattenTokens(doc) {
|
|
2270
|
-
const out = {};
|
|
2271
|
-
for (const [groupName, group] of Object.entries(doc)) {
|
|
2272
|
-
if (groupName.startsWith("$")) continue;
|
|
2273
|
-
if (typeof group !== "object" || group === null) continue;
|
|
2274
|
-
const g = group;
|
|
2275
|
-
const groupType = g.$type;
|
|
2276
|
-
for (const [leaf, node] of Object.entries(g)) {
|
|
2277
|
-
if (leaf.startsWith("$")) continue;
|
|
2278
|
-
if (!isToken(node)) continue;
|
|
2279
|
-
const type = node.$type ?? groupType;
|
|
2280
|
-
if (!type) {
|
|
2281
|
-
throw new Error(`Token "${leaf}" has no $type and its group "${groupName}" declares none`);
|
|
1016
|
+
},
|
|
1017
|
+
"surface-sunken": {
|
|
1018
|
+
by: "mode",
|
|
1019
|
+
dark: {
|
|
1020
|
+
value: "#02020a",
|
|
1021
|
+
type: "color"
|
|
1022
|
+
},
|
|
1023
|
+
light: {
|
|
1024
|
+
value: "#f0ebe2",
|
|
1025
|
+
type: "color"
|
|
2282
1026
|
}
|
|
2283
|
-
|
|
2284
|
-
|
|
1027
|
+
},
|
|
1028
|
+
border: {
|
|
1029
|
+
by: "mode",
|
|
1030
|
+
dark: {
|
|
1031
|
+
value: "rgba(255, 255, 255, 0.14)",
|
|
1032
|
+
type: "color"
|
|
1033
|
+
},
|
|
1034
|
+
light: {
|
|
1035
|
+
value: "#c9bba5",
|
|
1036
|
+
type: "color"
|
|
2285
1037
|
}
|
|
2286
|
-
const alphaRaw = node.$extensions?.[ALPHA_EXT];
|
|
2287
|
-
const token = {
|
|
2288
|
-
type,
|
|
2289
|
-
value: node.$value,
|
|
2290
|
-
alpha: typeof alphaRaw === "number" ? alphaRaw : void 0,
|
|
2291
|
-
description: node.$description
|
|
2292
|
-
};
|
|
2293
|
-
out[leaf] = token;
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
return out;
|
|
2297
|
-
}
|
|
2298
|
-
function loadDTCG(doc) {
|
|
2299
|
-
if (typeof doc.name !== "string" || doc.name === "") {
|
|
2300
|
-
throw new Error('DTCG document needs a string "name"');
|
|
2301
|
-
}
|
|
2302
|
-
const modes = {};
|
|
2303
|
-
for (const [mode, body] of Object.entries(doc.modes ?? {})) {
|
|
2304
|
-
modes[mode] = flattenTokens(body);
|
|
2305
|
-
}
|
|
2306
|
-
const base = doc.extends === void 0 ? weaselTheme : doc.extends;
|
|
2307
|
-
return {
|
|
2308
|
-
name: doc.name,
|
|
2309
|
-
extends: base,
|
|
2310
|
-
defaultMode: typeof doc.defaultMode === "string" ? doc.defaultMode : base?.defaultMode ?? "dark",
|
|
2311
|
-
tokens: flattenTokens(doc.primitives ?? {}),
|
|
2312
|
-
modes
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
// src/theme/interstellar.tokens.json
|
|
2317
|
-
var interstellar_tokens_default = {
|
|
2318
|
-
name: "interstellar",
|
|
2319
|
-
defaultMode: "dark",
|
|
2320
|
-
primitives: {
|
|
2321
|
-
dimension: {
|
|
2322
|
-
$type: "dimension",
|
|
2323
|
-
"radius-md": { $value: "6px" },
|
|
2324
|
-
"glass-blur": { $value: "12px" }
|
|
2325
1038
|
},
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
"accent-hover": { $value: "#c6a3ee" },
|
|
2347
|
-
"focus-ring": { $value: "rgba(176, 138, 219, 0.45)" },
|
|
2348
|
-
shadow: { $value: "rgba(0, 0, 0, 0.7)" },
|
|
2349
|
-
"border-strong": { $value: "rgba(255, 255, 255, 0.36)" }
|
|
2350
|
-
},
|
|
2351
|
-
gradient: {
|
|
2352
|
-
$type: "gradient",
|
|
2353
|
-
backdrop: {
|
|
2354
|
-
$value: "radial-gradient(ellipse 60% 80% at 18% 30%, rgba(150, 80, 200, 0.22), transparent 70%), radial-gradient(ellipse 55% 90% at 78% 70%, rgba(220, 100, 140, 0.18), transparent 65%), radial-gradient(ellipse 50% 70% at 50% 50%, rgba(60, 110, 200, 0.18), transparent 75%), radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)"
|
|
2355
|
-
}
|
|
1039
|
+
"line-subtle": {
|
|
1040
|
+
by: "mode",
|
|
1041
|
+
dark: {
|
|
1042
|
+
value: "rgba(255, 255, 255, 0.08)",
|
|
1043
|
+
type: "color"
|
|
1044
|
+
},
|
|
1045
|
+
light: {
|
|
1046
|
+
value: "rgba(0, 0, 0, 0.08)",
|
|
1047
|
+
type: "color"
|
|
1048
|
+
}
|
|
1049
|
+
},
|
|
1050
|
+
fg: {
|
|
1051
|
+
by: "mode",
|
|
1052
|
+
dark: {
|
|
1053
|
+
value: "#e8e8f0",
|
|
1054
|
+
type: "color"
|
|
1055
|
+
},
|
|
1056
|
+
light: {
|
|
1057
|
+
value: "#2a2018",
|
|
1058
|
+
type: "color"
|
|
2356
1059
|
}
|
|
2357
1060
|
},
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
1061
|
+
"fg-muted": {
|
|
1062
|
+
by: "mode",
|
|
1063
|
+
dark: {
|
|
1064
|
+
value: "#a8a8c0",
|
|
1065
|
+
type: "color"
|
|
1066
|
+
},
|
|
1067
|
+
light: {
|
|
1068
|
+
value: "#6b5c4a",
|
|
1069
|
+
type: "color"
|
|
1070
|
+
}
|
|
1071
|
+
},
|
|
1072
|
+
"fg-subtle": {
|
|
1073
|
+
by: "mode",
|
|
1074
|
+
dark: {
|
|
1075
|
+
value: "#5a5a78",
|
|
1076
|
+
type: "color"
|
|
1077
|
+
},
|
|
1078
|
+
light: {
|
|
1079
|
+
value: "#a89b85",
|
|
1080
|
+
type: "color"
|
|
1081
|
+
}
|
|
1082
|
+
},
|
|
1083
|
+
accent: {
|
|
1084
|
+
by: "mode",
|
|
1085
|
+
dark: {
|
|
1086
|
+
value: "#b08adb",
|
|
1087
|
+
type: "color"
|
|
1088
|
+
},
|
|
1089
|
+
light: {
|
|
1090
|
+
value: "#a86f3c",
|
|
1091
|
+
type: "color"
|
|
1092
|
+
}
|
|
1093
|
+
},
|
|
1094
|
+
"accent-hover": {
|
|
1095
|
+
by: "mode",
|
|
1096
|
+
dark: {
|
|
1097
|
+
value: "#c6a3ee",
|
|
1098
|
+
type: "color"
|
|
1099
|
+
},
|
|
1100
|
+
light: {
|
|
1101
|
+
value: "#c2854f",
|
|
1102
|
+
type: "color"
|
|
1103
|
+
}
|
|
1104
|
+
},
|
|
1105
|
+
"focus-ring": {
|
|
1106
|
+
by: "mode",
|
|
1107
|
+
dark: {
|
|
1108
|
+
value: "rgba(176, 138, 219, 0.45)",
|
|
1109
|
+
type: "color"
|
|
1110
|
+
},
|
|
1111
|
+
light: {
|
|
1112
|
+
value: "rgba(168, 111, 60, 0.35)",
|
|
1113
|
+
type: "color"
|
|
1114
|
+
}
|
|
1115
|
+
},
|
|
1116
|
+
shadow: {
|
|
1117
|
+
by: "mode",
|
|
1118
|
+
dark: {
|
|
1119
|
+
value: "rgba(0, 0, 0, 0.7)",
|
|
1120
|
+
type: "color"
|
|
1121
|
+
},
|
|
1122
|
+
light: {
|
|
1123
|
+
value: "rgba(80, 60, 40, 0.18)",
|
|
1124
|
+
type: "color"
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
"border-strong": {
|
|
1128
|
+
by: "mode",
|
|
1129
|
+
dark: {
|
|
1130
|
+
value: "rgba(255, 255, 255, 0.36)",
|
|
1131
|
+
type: "color"
|
|
1132
|
+
},
|
|
1133
|
+
light: {
|
|
1134
|
+
value: "#9e8b71",
|
|
1135
|
+
type: "color"
|
|
1136
|
+
}
|
|
1137
|
+
},
|
|
1138
|
+
backdrop: {
|
|
1139
|
+
by: "mode",
|
|
1140
|
+
dark: {
|
|
1141
|
+
value: "radial-gradient(ellipse 60% 80% at 18% 30%, rgba(150, 80, 200, 0.22), transparent 70%), radial-gradient(ellipse 55% 90% at 78% 70%, rgba(220, 100, 140, 0.18), transparent 65%), radial-gradient(ellipse 50% 70% at 50% 50%, rgba(60, 110, 200, 0.18), transparent 75%), radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)",
|
|
1142
|
+
type: "gradient"
|
|
1143
|
+
},
|
|
1144
|
+
light: {
|
|
1145
|
+
value: "none",
|
|
1146
|
+
type: "gradient"
|
|
2374
1147
|
}
|
|
2375
1148
|
}
|
|
2376
1149
|
}
|
|
2377
1150
|
};
|
|
2378
1151
|
|
|
2379
1152
|
// src/theme/interstellar.ts
|
|
2380
|
-
var interstellarTheme =
|
|
1153
|
+
var interstellarTheme = defineTheme({
|
|
1154
|
+
...interstellar_theme_default,
|
|
1155
|
+
extends: weaselTheme
|
|
1156
|
+
});
|
|
2381
1157
|
function TrialBody({ sidebar, children, contentClassName, ...rest }) {
|
|
2382
1158
|
return /* @__PURE__ */ jsx(
|
|
2383
1159
|
Split,
|
|
@@ -2474,7 +1250,7 @@ function Portalled({
|
|
|
2474
1250
|
}
|
|
2475
1251
|
function UndockedSections({ trialId, sections, onDock }) {
|
|
2476
1252
|
if (sections.length === 0) return null;
|
|
2477
|
-
return /* @__PURE__ */ jsx(Fragment, { children: sections.map((
|
|
1253
|
+
return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c9) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c9, onDock }, c9.id)) });
|
|
2478
1254
|
}
|
|
2479
1255
|
var NO_OP = () => {
|
|
2480
1256
|
};
|
|
@@ -2497,27 +1273,32 @@ function TrialChrome({
|
|
|
2497
1273
|
const lab = useLabContext();
|
|
2498
1274
|
const storeCtx = useContext(LabStoreContext);
|
|
2499
1275
|
if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
|
|
2500
|
-
const updateTrialView = useStore(storeCtx.store, (
|
|
2501
|
-
const updateTrialSidebarWidth = useStore(storeCtx.store, (
|
|
2502
|
-
const setTrialTitle = useStore(storeCtx.store, (
|
|
2503
|
-
const setTrialSectionCollapsed = useStore(storeCtx.store, (
|
|
2504
|
-
const updateTrialConfig = useStore(storeCtx.store, (
|
|
2505
|
-
const updateTrialState = useStore(storeCtx.store, (
|
|
2506
|
-
const undockPanelAction = useStore(storeCtx.store, (
|
|
2507
|
-
const dockPanelAction = useStore(storeCtx.store, (
|
|
2508
|
-
const undockedPanels = useStore(storeCtx.store, (
|
|
1276
|
+
const updateTrialView = useStore(storeCtx.store, (s5) => s5.updateTrialView);
|
|
1277
|
+
const updateTrialSidebarWidth = useStore(storeCtx.store, (s5) => s5.updateTrialSidebarWidth);
|
|
1278
|
+
const setTrialTitle = useStore(storeCtx.store, (s5) => s5.setTrialTitle);
|
|
1279
|
+
const setTrialSectionCollapsed = useStore(storeCtx.store, (s5) => s5.setTrialSectionCollapsed);
|
|
1280
|
+
const updateTrialConfig = useStore(storeCtx.store, (s5) => s5.updateTrialConfig);
|
|
1281
|
+
const updateTrialState = useStore(storeCtx.store, (s5) => s5.updateTrialState);
|
|
1282
|
+
const undockPanelAction = useStore(storeCtx.store, (s5) => s5.undockPanel);
|
|
1283
|
+
const dockPanelAction = useStore(storeCtx.store, (s5) => s5.dockPanel);
|
|
1284
|
+
const undockedPanels = useStore(storeCtx.store, (s5) => s5.undockedPanels);
|
|
2509
1285
|
const undockedIds = useMemo(
|
|
2510
1286
|
() => Object.values(undockedPanels).filter((p2) => p2.trialId === trialId).map((p2) => p2.sectionId),
|
|
2511
1287
|
[undockedPanels, trialId]
|
|
2512
1288
|
);
|
|
2513
1289
|
const view2d = as2DView(record.view);
|
|
2514
1290
|
const configSchema = useConfigSchema(instrument);
|
|
1291
|
+
const { config: resolvedConfig, auto: auto2 } = useResolvedConfig(
|
|
1292
|
+
configSchema,
|
|
1293
|
+
record.config,
|
|
1294
|
+
record.auto
|
|
1295
|
+
);
|
|
2515
1296
|
const title = record.title ?? instrument.title ?? instrument.name;
|
|
2516
1297
|
const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
|
|
2517
1298
|
const ctx = useMemo(() => {
|
|
2518
|
-
const setZoom = (
|
|
1299
|
+
const setZoom = (z3) => {
|
|
2519
1300
|
if (!view2d) return;
|
|
2520
|
-
updateTrialView(trialId, withZoom(view2d,
|
|
1301
|
+
updateTrialView(trialId, withZoom(view2d, z3));
|
|
2521
1302
|
};
|
|
2522
1303
|
return {
|
|
2523
1304
|
trialId,
|
|
@@ -2536,6 +1317,7 @@ function TrialChrome({
|
|
|
2536
1317
|
configSchema,
|
|
2537
1318
|
configFields: instrument.config ? [] : instrument.configSchema?.() ?? [],
|
|
2538
1319
|
config: record.config,
|
|
1320
|
+
auto: auto2,
|
|
2539
1321
|
setConfig: (path, value) => {
|
|
2540
1322
|
const prevConfig = record.config;
|
|
2541
1323
|
if (process.env.NODE_ENV !== "production" && !hasConfigPath(prevConfig, path) && schemaNodeAtPath(configSchema.group, path) === void 0) {
|
|
@@ -2545,8 +1327,9 @@ function TrialChrome({
|
|
|
2545
1327
|
}
|
|
2546
1328
|
updateTrialConfig(trialId, path, value);
|
|
2547
1329
|
if (instrument.onConfigChange) {
|
|
2548
|
-
const
|
|
2549
|
-
const
|
|
1330
|
+
const next = applyConfigWrite(prevConfig, record.auto ?? [], path, value);
|
|
1331
|
+
const nextConfig = resolveAutoConfig(configSchema, next.config, new Set(next.autoPaths));
|
|
1332
|
+
const nextState = instrument.onConfigChange(nextConfig, resolvedConfig, record.state);
|
|
2550
1333
|
updateTrialState(trialId, nextState);
|
|
2551
1334
|
}
|
|
2552
1335
|
},
|
|
@@ -2555,7 +1338,7 @@ function TrialChrome({
|
|
|
2555
1338
|
undockedPanels: undockedIds,
|
|
2556
1339
|
undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
|
|
2557
1340
|
dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
|
|
2558
|
-
savedSnapshots: lab.savedSnapshots.filter((
|
|
1341
|
+
savedSnapshots: lab.savedSnapshots.filter((s5) => s5.trialId === trialId),
|
|
2559
1342
|
saveSnapshot: (name) => lab.saveSnapshot(trialId, name),
|
|
2560
1343
|
loadSnapshot: (snapshotId) => lab.loadSnapshot(trialId, snapshotId),
|
|
2561
1344
|
clone: () => lab.cloneTrial(trialId),
|
|
@@ -2580,6 +1363,8 @@ function TrialChrome({
|
|
|
2580
1363
|
activeToolId,
|
|
2581
1364
|
setActiveTool,
|
|
2582
1365
|
configSchema,
|
|
1366
|
+
resolvedConfig,
|
|
1367
|
+
auto2,
|
|
2583
1368
|
undockedIds,
|
|
2584
1369
|
undockPanelAction,
|
|
2585
1370
|
dockPanelAction,
|
|
@@ -2599,7 +1384,7 @@ function TrialChrome({
|
|
|
2599
1384
|
),
|
|
2600
1385
|
[instrument, ctx, trialChrome, chrome, suppress, lab.controls]
|
|
2601
1386
|
);
|
|
2602
|
-
const inRegion = (region) => contributions.filter((
|
|
1387
|
+
const inRegion = (region) => contributions.filter((c9) => c9.region === region);
|
|
2603
1388
|
const handleKeyDown = (e) => {
|
|
2604
1389
|
const mod = e.metaKey || e.ctrlKey;
|
|
2605
1390
|
if (!mod) return;
|
|
@@ -2617,6 +1402,7 @@ function TrialChrome({
|
|
|
2617
1402
|
{
|
|
2618
1403
|
className: "lk-trial",
|
|
2619
1404
|
"data-trial-id": trialId,
|
|
1405
|
+
"data-focused": lab.trials.length > 1 && lab.focusedTrialId === trialId ? "true" : void 0,
|
|
2620
1406
|
"aria-label": `Trial ${title}`,
|
|
2621
1407
|
tabIndex: -1,
|
|
2622
1408
|
onKeyDown: handleKeyDown,
|
|
@@ -2636,7 +1422,7 @@ function TrialChrome({
|
|
|
2636
1422
|
TrialBody,
|
|
2637
1423
|
{
|
|
2638
1424
|
width: record.sidebarWidth,
|
|
2639
|
-
onWidthChange: (
|
|
1425
|
+
onWidthChange: (w3) => updateTrialSidebarWidth(trialId, w3),
|
|
2640
1426
|
contentClassName: instrument.canvas || instrument.stage ? "lk-trial__content--flush" : void 0,
|
|
2641
1427
|
sidebar: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2642
1428
|
/* @__PURE__ */ jsx(SidebarRegion, { contributions: inRegion("sidebar"), ctx }),
|
|
@@ -2644,7 +1430,7 @@ function TrialChrome({
|
|
|
2644
1430
|
UndockedSections,
|
|
2645
1431
|
{
|
|
2646
1432
|
trialId,
|
|
2647
|
-
sections: inRegion("sidebar").filter((
|
|
1433
|
+
sections: inRegion("sidebar").filter((c9) => undockedIds.includes(c9.id)),
|
|
2648
1434
|
onDock: ctx.dockPanel
|
|
2649
1435
|
}
|
|
2650
1436
|
)
|
|
@@ -2668,9 +1454,9 @@ function Trial({ id, chrome, suppress }) {
|
|
|
2668
1454
|
const lab = useLabContext();
|
|
2669
1455
|
const storeCtx = useContext(LabStoreContext);
|
|
2670
1456
|
if (!storeCtx) throw new Error("[labkit] <Trial> requires <LabStoreProvider>");
|
|
2671
|
-
const instruments = useStore(storeCtx.store, (
|
|
2672
|
-
const record = useStore(storeCtx.store, (
|
|
2673
|
-
const instrument = record ? instruments.find((
|
|
1457
|
+
const instruments = useStore(storeCtx.store, (s5) => s5.instruments) ?? lab.instruments;
|
|
1458
|
+
const record = useStore(storeCtx.store, (s5) => s5.trials.find((w3) => w3.id === id));
|
|
1459
|
+
const instrument = record ? instruments.find((i3) => i3.name === record.instrumentName) : void 0;
|
|
2674
1460
|
const kept = useKeptMarks(instrument?.annotations?.storage, id);
|
|
2675
1461
|
if (!record) {
|
|
2676
1462
|
return /* @__PURE__ */ jsxs("div", { className: "lk-trial lk-trial--unknown", children: [
|
|
@@ -2736,14 +1522,16 @@ function TrialRuntime({
|
|
|
2736
1522
|
const wheelSlot = useRef(null);
|
|
2737
1523
|
const canvasContainerRef = useRef(null);
|
|
2738
1524
|
const loupeHostRef = useRef(null);
|
|
2739
|
-
const updateTrialState = useStore(store, (
|
|
2740
|
-
const updateTrialConfig = useStore(store, (
|
|
2741
|
-
const updateTrialView = useStore(store, (
|
|
2742
|
-
const updateTrialUndoStack = useStore(store, (
|
|
2743
|
-
const updateTrialAnnotations = useStore(store, (
|
|
2744
|
-
const labToolId = useStore(store, (
|
|
2745
|
-
const setLabTool = useStore(store, (
|
|
2746
|
-
const setTrialTool = useStore(store, (
|
|
1525
|
+
const updateTrialState = useStore(store, (s5) => s5.updateTrialState);
|
|
1526
|
+
const updateTrialConfig = useStore(store, (s5) => s5.updateTrialConfig);
|
|
1527
|
+
const updateTrialView = useStore(store, (s5) => s5.updateTrialView);
|
|
1528
|
+
const updateTrialUndoStack = useStore(store, (s5) => s5.updateTrialUndoStack);
|
|
1529
|
+
const updateTrialAnnotations = useStore(store, (s5) => s5.updateTrialAnnotations);
|
|
1530
|
+
const labToolId = useStore(store, (s5) => s5.activeToolId);
|
|
1531
|
+
const setLabTool = useStore(store, (s5) => s5.setLabTool);
|
|
1532
|
+
const setTrialTool = useStore(store, (s5) => s5.setTrialTool);
|
|
1533
|
+
const schema = useConfigSchema(instrument);
|
|
1534
|
+
const { config } = useResolvedConfig(schema, record.config, record.auto);
|
|
2747
1535
|
const busRef = useRef(null);
|
|
2748
1536
|
if (busRef.current === null) busRef.current = createEventBus();
|
|
2749
1537
|
const bus = busRef.current;
|
|
@@ -2751,7 +1539,7 @@ function TrialRuntime({
|
|
|
2751
1539
|
const [layerOrder, setLayerOrder] = useState(null);
|
|
2752
1540
|
const [loupeOn, setLoupeOn] = useState(false);
|
|
2753
1541
|
const visibleLayers = useMemo(
|
|
2754
|
-
() => (instrument.canvas?.layers ?? []).filter((
|
|
1542
|
+
() => (instrument.canvas?.layers ?? []).filter((l9) => layerVisibility[l9.id] !== false).map((l9) => l9.id),
|
|
2755
1543
|
[instrument.canvas, layerVisibility]
|
|
2756
1544
|
);
|
|
2757
1545
|
const undoCap = instrument.undo;
|
|
@@ -2759,12 +1547,12 @@ function TrialRuntime({
|
|
|
2759
1547
|
const maxDepth = undoCap?.maxDepth ?? 50;
|
|
2760
1548
|
const snapshotIfNeeded = (event) => {
|
|
2761
1549
|
if (!undoCap || !undoEvents.has(event)) return;
|
|
2762
|
-
const current = store.getState().trials.find((
|
|
1550
|
+
const current = store.getState().trials.find((w3) => w3.id === record.id);
|
|
2763
1551
|
if (!current) return;
|
|
2764
1552
|
const snap = structuredClone(current.state);
|
|
2765
1553
|
updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
|
|
2766
1554
|
};
|
|
2767
|
-
const setView = (
|
|
1555
|
+
const setView = (v2) => updateTrialView(record.id, v2);
|
|
2768
1556
|
const stage = instrument.canvas ? void 0 : instrument.stage;
|
|
2769
1557
|
const placeView = (size) => {
|
|
2770
1558
|
const declared = instrument.canvas?.initialView ?? (stage ? stage.initialView ?? ((vp) => fitStage(stage.size, vp)) : void 0);
|
|
@@ -2774,10 +1562,10 @@ function TrialRuntime({
|
|
|
2774
1562
|
};
|
|
2775
1563
|
const annotationsCap = instrument.annotations;
|
|
2776
1564
|
const targetsRef = useRef(() => []);
|
|
2777
|
-
targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state,
|
|
1565
|
+
targetsRef.current = () => annotationsCap ? annotationsCap.targets(record.state, config, { id: record.id, view: record.view }) : [];
|
|
2778
1566
|
const annotationsRef = useRef(null);
|
|
2779
|
-
const configRef = useRef(
|
|
2780
|
-
configRef.current =
|
|
1567
|
+
const configRef = useRef(config);
|
|
1568
|
+
configRef.current = config;
|
|
2781
1569
|
const capRef = useRef(annotationsCap);
|
|
2782
1570
|
capRef.current = annotationsCap;
|
|
2783
1571
|
if (annotationsRef.current === null) {
|
|
@@ -2841,13 +1629,13 @@ function TrialRuntime({
|
|
|
2841
1629
|
const job = useJob({
|
|
2842
1630
|
capability: jobCap ?? { run: async function* () {
|
|
2843
1631
|
}, onItem: (_i, st) => st },
|
|
2844
|
-
config
|
|
1632
|
+
config,
|
|
2845
1633
|
state: record.state,
|
|
2846
1634
|
setState: (next) => updateTrialState(record.id, next)
|
|
2847
1635
|
});
|
|
2848
1636
|
const renderCtx = {
|
|
2849
1637
|
state: record.state,
|
|
2850
|
-
config
|
|
1638
|
+
config,
|
|
2851
1639
|
setState: (next) => {
|
|
2852
1640
|
snapshotIfNeeded("state.change");
|
|
2853
1641
|
updateTrialState(record.id, next);
|
|
@@ -2866,9 +1654,9 @@ function TrialRuntime({
|
|
|
2866
1654
|
view: record.view,
|
|
2867
1655
|
setView,
|
|
2868
1656
|
zoom: view2d?.zoom ?? 1,
|
|
2869
|
-
setZoom: (
|
|
1657
|
+
setZoom: (z3) => {
|
|
2870
1658
|
if (!view2d) return;
|
|
2871
|
-
updateTrialView(record.id, withZoom(view2d,
|
|
1659
|
+
updateTrialView(record.id, withZoom(view2d, z3));
|
|
2872
1660
|
},
|
|
2873
1661
|
activeToolId: resolvedToolId,
|
|
2874
1662
|
visibleLayers
|
|
@@ -2906,33 +1694,33 @@ function TrialRuntime({
|
|
|
2906
1694
|
const loupeCap = useMemo(() => {
|
|
2907
1695
|
const declared = instrument.loupe;
|
|
2908
1696
|
if (declared == null) return null;
|
|
2909
|
-
return resolveLoupe(typeof declared === "function" ? declared(
|
|
2910
|
-
}, [instrument.loupe,
|
|
2911
|
-
const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((
|
|
1697
|
+
return resolveLoupe(typeof declared === "function" ? declared(config) : declared);
|
|
1698
|
+
}, [instrument.loupe, config]);
|
|
1699
|
+
const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((v2) => !v2) } : void 0;
|
|
2912
1700
|
const canvasLayers = useMemo(() => {
|
|
2913
1701
|
if (!instrument.canvas) return [];
|
|
2914
1702
|
const baseLayers = instrument.canvas.layers;
|
|
2915
|
-
const ordered = layerOrder ? [...baseLayers].sort((
|
|
1703
|
+
const ordered = layerOrder ? [...baseLayers].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : baseLayers;
|
|
2916
1704
|
return ordered.map((layer) => ({
|
|
2917
1705
|
id: layer.id,
|
|
2918
1706
|
visible: layerVisibility[layer.id] !== false,
|
|
2919
1707
|
render: (ctx, view, frame) => {
|
|
2920
1708
|
applyCamera(ctx, view, frame);
|
|
2921
|
-
layer.draw(ctx, { state: record.state, config
|
|
1709
|
+
layer.draw(ctx, { state: record.state, config, zoom: view.zoom });
|
|
2922
1710
|
}
|
|
2923
1711
|
}));
|
|
2924
|
-
}, [instrument.canvas, record.state,
|
|
1712
|
+
}, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
|
|
2925
1713
|
const layerDescriptors = useMemo(() => {
|
|
2926
1714
|
if (!instrument.layers) return [];
|
|
2927
|
-
return instrument.layers.ids.map((
|
|
1715
|
+
return instrument.layers.ids.map((l9) => typeof l9 === "string" ? { id: l9, label: l9 } : l9);
|
|
2928
1716
|
}, [instrument.layers]);
|
|
2929
1717
|
const dragDropResult = useDragDrop({
|
|
2930
|
-
capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i,
|
|
1718
|
+
capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s5) => s5 },
|
|
2931
1719
|
canvasContainerRef,
|
|
2932
1720
|
view: view2d ?? DEFAULT_VIEW,
|
|
2933
1721
|
worldSpec: instrument.canvas?.worldSpec,
|
|
2934
1722
|
state: record.state,
|
|
2935
|
-
config
|
|
1723
|
+
config,
|
|
2936
1724
|
setState: (next) => {
|
|
2937
1725
|
snapshotIfNeeded("canvas.itemAdded");
|
|
2938
1726
|
updateTrialState(record.id, next);
|
|
@@ -2945,8 +1733,8 @@ function TrialRuntime({
|
|
|
2945
1733
|
const paletteItems = useMemo(() => {
|
|
2946
1734
|
if (!instrument.dragDrop) return [];
|
|
2947
1735
|
const p2 = instrument.dragDrop.palette;
|
|
2948
|
-
return typeof p2 === "function" ? p2(record.state,
|
|
2949
|
-
}, [instrument.dragDrop, record.state,
|
|
1736
|
+
return typeof p2 === "function" ? p2(record.state, config) : p2;
|
|
1737
|
+
}, [instrument.dragDrop, record.state, config]);
|
|
2950
1738
|
const layersWithFeedback = useMemo(() => {
|
|
2951
1739
|
if (!dragDropResult.drag?.feedback) return canvasLayers;
|
|
2952
1740
|
const fb = dragDropResult.drag.feedback;
|
|
@@ -2959,12 +1747,12 @@ function TrialRuntime({
|
|
|
2959
1747
|
render: (ctx) => {
|
|
2960
1748
|
const el = canvasContainerRef.current;
|
|
2961
1749
|
if (!el) return;
|
|
2962
|
-
const
|
|
1750
|
+
const r9 = el.getBoundingClientRect();
|
|
2963
1751
|
ctx.save();
|
|
2964
1752
|
ctx.strokeStyle = fb.ok ? "#3a7" : "#c44";
|
|
2965
1753
|
ctx.lineWidth = 2;
|
|
2966
1754
|
ctx.beginPath();
|
|
2967
|
-
ctx.arc(screen.x -
|
|
1755
|
+
ctx.arc(screen.x - r9.left, screen.y - r9.top, 16, 0, Math.PI * 2);
|
|
2968
1756
|
ctx.stroke();
|
|
2969
1757
|
ctx.restore();
|
|
2970
1758
|
}
|
|
@@ -2977,7 +1765,7 @@ function TrialRuntime({
|
|
|
2977
1765
|
capability: loupeCap,
|
|
2978
1766
|
enabled: loupeOn,
|
|
2979
1767
|
state: record.state,
|
|
2980
|
-
config
|
|
1768
|
+
config,
|
|
2981
1769
|
view: view2d ?? DEFAULT_VIEW,
|
|
2982
1770
|
worldSpec: instrument.canvas?.worldSpec,
|
|
2983
1771
|
hostRef: loupeHostRef
|
|
@@ -3039,7 +1827,7 @@ function TrialRuntime({
|
|
|
3039
1827
|
layers: layerDescriptors,
|
|
3040
1828
|
visibility: layerVisibility,
|
|
3041
1829
|
onReorder: (next) => {
|
|
3042
|
-
setLayerOrder(next.map((
|
|
1830
|
+
setLayerOrder(next.map((l9) => l9.id));
|
|
3043
1831
|
bus.emit("layers.reorder");
|
|
3044
1832
|
},
|
|
3045
1833
|
onToggle: (lid, visible) => {
|
|
@@ -3073,7 +1861,7 @@ function TrialRuntime({
|
|
|
3073
1861
|
{
|
|
3074
1862
|
capability: annotationsCap,
|
|
3075
1863
|
state: record.state,
|
|
3076
|
-
config
|
|
1864
|
+
config,
|
|
3077
1865
|
trial: { id: record.id, view: record.view },
|
|
3078
1866
|
annotations,
|
|
3079
1867
|
activeToolId: labTool
|
|
@@ -3105,7 +1893,7 @@ function TrialRuntime({
|
|
|
3105
1893
|
// src/trial/trialOps.ts
|
|
3106
1894
|
var DEFAULT_VIEW2 = { zoom: 1, pan: { x: 0, y: 0 } };
|
|
3107
1895
|
function findInstrument(instruments, name) {
|
|
3108
|
-
const found = instruments.find((
|
|
1896
|
+
const found = instruments.find((i3) => i3.name === name);
|
|
3109
1897
|
if (!found) {
|
|
3110
1898
|
throw new Error(`[labkit] Unknown instrument: "${name}"`);
|
|
3111
1899
|
}
|
|
@@ -3120,9 +1908,32 @@ function initialView(instrument) {
|
|
|
3120
1908
|
function seedConfig(defaults, seed) {
|
|
3121
1909
|
return seed ? fillConfigDefaults(seed, defaults) : defaults;
|
|
3122
1910
|
}
|
|
1911
|
+
function splitAutoSeed(seed, at = "") {
|
|
1912
|
+
const config = {};
|
|
1913
|
+
const autoPaths = [];
|
|
1914
|
+
for (const [key, value] of Object.entries(seed ?? {})) {
|
|
1915
|
+
const path = at === "" ? key : `${at}.${key}`;
|
|
1916
|
+
if (isAuto(value)) {
|
|
1917
|
+
autoPaths.push(path);
|
|
1918
|
+
} else if (isRecord(value)) {
|
|
1919
|
+
const inner = splitAutoSeed(value, path);
|
|
1920
|
+
config[key] = inner.config;
|
|
1921
|
+
autoPaths.push(...inner.autoPaths);
|
|
1922
|
+
} else {
|
|
1923
|
+
config[key] = value;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return { config, autoPaths };
|
|
1927
|
+
}
|
|
1928
|
+
function schemaAutoPaths(instrument) {
|
|
1929
|
+
const schema = unruledConfigSchema(instrument);
|
|
1930
|
+
return schema ? autoPathsOf(schema) : [];
|
|
1931
|
+
}
|
|
3123
1932
|
function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
3124
1933
|
const instrument = findInstrument(instruments, instrumentName);
|
|
3125
|
-
const
|
|
1934
|
+
const seeded = splitAutoSeed(options.config);
|
|
1935
|
+
const autoPaths = [.../* @__PURE__ */ new Set([...schemaAutoPaths(instrument), ...seeded.autoPaths])];
|
|
1936
|
+
const config = seedConfig(instrument.defaultConfig(), seeded.config);
|
|
3126
1937
|
const state = instrument.initialState(config);
|
|
3127
1938
|
const record = {
|
|
3128
1939
|
id: newId(),
|
|
@@ -3132,11 +1943,13 @@ function addTrial(trials, instruments, instrumentName, options = {}) {
|
|
|
3132
1943
|
view: initialView(instrument),
|
|
3133
1944
|
undoStack: { past: [], future: [] }
|
|
3134
1945
|
};
|
|
3135
|
-
if (options.config) record.configSeed =
|
|
1946
|
+
if (options.config) record.configSeed = seeded.config;
|
|
1947
|
+
if (seeded.autoPaths.length > 0) record.autoSeed = seeded.autoPaths;
|
|
1948
|
+
if (autoPaths.length > 0) record.auto = autoPaths;
|
|
3136
1949
|
return [...trials, record];
|
|
3137
1950
|
}
|
|
3138
1951
|
function cloneTrial(trials, id) {
|
|
3139
|
-
const sourceIdx = trials.findIndex((
|
|
1952
|
+
const sourceIdx = trials.findIndex((w3) => w3.id === id);
|
|
3140
1953
|
const source = trials[sourceIdx];
|
|
3141
1954
|
if (!source) return trials;
|
|
3142
1955
|
const clone = {
|
|
@@ -3151,44 +1964,55 @@ function cloneTrial(trials, id) {
|
|
|
3151
1964
|
}
|
|
3152
1965
|
function closeTrial(trials, id) {
|
|
3153
1966
|
if (trials.length <= 1) return trials;
|
|
3154
|
-
const next = trials.filter((
|
|
1967
|
+
const next = trials.filter((w3) => w3.id !== id);
|
|
3155
1968
|
return next.length === trials.length ? trials : next;
|
|
3156
1969
|
}
|
|
3157
1970
|
function resetTrial(trials, id, instruments) {
|
|
3158
|
-
const idx = trials.findIndex((
|
|
1971
|
+
const idx = trials.findIndex((w3) => w3.id === id);
|
|
3159
1972
|
const current = trials[idx];
|
|
3160
1973
|
if (!current) return trials;
|
|
3161
1974
|
const instrument = findInstrument(instruments, current.instrumentName);
|
|
3162
1975
|
const config = seedConfig(instrument.defaultConfig(), current.configSeed);
|
|
3163
1976
|
const state = instrument.initialState(config);
|
|
1977
|
+
const autoPaths = [.../* @__PURE__ */ new Set([...schemaAutoPaths(instrument), ...current.autoSeed ?? []])];
|
|
1978
|
+
const { auto: _unpinnedNow, ...kept } = current;
|
|
3164
1979
|
const reset = {
|
|
3165
|
-
...
|
|
1980
|
+
...kept,
|
|
3166
1981
|
config,
|
|
3167
1982
|
state,
|
|
3168
1983
|
view: initialView(instrument)
|
|
3169
1984
|
};
|
|
1985
|
+
if (autoPaths.length > 0) reset.auto = autoPaths;
|
|
3170
1986
|
return [...trials.slice(0, idx), reset, ...trials.slice(idx + 1)];
|
|
3171
1987
|
}
|
|
1988
|
+
function swapTrial(trials, instruments, id, instrumentName, options = {}) {
|
|
1989
|
+
const idx = trials.findIndex((w3) => w3.id === id);
|
|
1990
|
+
const current = trials[idx];
|
|
1991
|
+
if (!current) return trials;
|
|
1992
|
+
const [record] = addTrial([], instruments, instrumentName, options);
|
|
1993
|
+
if (current.sidebarWidth !== void 0) record.sidebarWidth = current.sidebarWidth;
|
|
1994
|
+
return [...trials.slice(0, idx), record, ...trials.slice(idx + 1)];
|
|
1995
|
+
}
|
|
3172
1996
|
function reorderTrials(trials, ids) {
|
|
3173
|
-
const byId = new Map(trials.map((
|
|
3174
|
-
const named = ids.map((id) => byId.get(id)).filter((
|
|
3175
|
-
const seen = new Set(named.map((
|
|
3176
|
-
const rest = trials.filter((
|
|
1997
|
+
const byId = new Map(trials.map((w3) => [w3.id, w3]));
|
|
1998
|
+
const named = ids.map((id) => byId.get(id)).filter((w3) => w3 !== void 0);
|
|
1999
|
+
const seen = new Set(named.map((w3) => w3.id));
|
|
2000
|
+
const rest = trials.filter((w3) => !seen.has(w3.id));
|
|
3177
2001
|
return [...named, ...rest];
|
|
3178
2002
|
}
|
|
3179
2003
|
function findOvershoot(bound, items, tolerance = 1) {
|
|
3180
2004
|
let worst = null;
|
|
3181
2005
|
for (const { item, edges } of items) {
|
|
3182
|
-
const
|
|
2006
|
+
const y3 = edges.bottom - bound.bottom;
|
|
3183
2007
|
const x = edges.right - bound.right;
|
|
3184
|
-
const by = Math.max(x,
|
|
2008
|
+
const by = Math.max(x, y3);
|
|
3185
2009
|
if (by <= tolerance) continue;
|
|
3186
|
-
if (!worst || by > worst.by) worst = { item, by, axis:
|
|
2010
|
+
if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x ? "y" : "x" };
|
|
3187
2011
|
}
|
|
3188
2012
|
return worst;
|
|
3189
2013
|
}
|
|
3190
2014
|
function tagAndClasses(el) {
|
|
3191
|
-
return el.tagName.toLowerCase() + [...el.classList].map((
|
|
2015
|
+
return el.tagName.toLowerCase() + [...el.classList].map((c9) => `.${c9}`).join("");
|
|
3192
2016
|
}
|
|
3193
2017
|
function describeElement(el) {
|
|
3194
2018
|
if (el.classList.length > 0) return tagAndClasses(el);
|
|
@@ -3197,8 +2021,8 @@ function describeElement(el) {
|
|
|
3197
2021
|
return up ? `${tagAndClasses(el)} in ${tagAndClasses(up)}` : tagAndClasses(el);
|
|
3198
2022
|
}
|
|
3199
2023
|
function edgesOf(el) {
|
|
3200
|
-
const
|
|
3201
|
-
return { top:
|
|
2024
|
+
const r9 = el.getBoundingClientRect();
|
|
2025
|
+
return { top: r9.top, left: r9.left, bottom: r9.bottom, right: r9.right };
|
|
3202
2026
|
}
|
|
3203
2027
|
function* candidates(root) {
|
|
3204
2028
|
yield { item: root, edges: edgesOf(root) };
|
|
@@ -3209,24 +2033,24 @@ function overflows(el) {
|
|
|
3209
2033
|
}
|
|
3210
2034
|
function explainLabScroll(lab, shellBody) {
|
|
3211
2035
|
if (overflows(shellBody)) {
|
|
3212
|
-
const
|
|
2036
|
+
const r10 = shellBody.getBoundingClientRect();
|
|
3213
2037
|
const bound2 = {
|
|
3214
|
-
top:
|
|
3215
|
-
left:
|
|
3216
|
-
bottom:
|
|
3217
|
-
right:
|
|
2038
|
+
top: r10.top,
|
|
2039
|
+
left: r10.left,
|
|
2040
|
+
bottom: r10.top + shellBody.clientHeight,
|
|
2041
|
+
right: r10.left + shellBody.clientWidth
|
|
3218
2042
|
};
|
|
3219
2043
|
const hit2 = findOvershoot(bound2, candidates(shellBody));
|
|
3220
2044
|
return hit2 ? `.lk-shell-body scrolls: ${describeElement(hit2.item)} reaches ${Math.round(hit2.by)}px past it (${hit2.axis})` : ".lk-shell-body scrolls";
|
|
3221
2045
|
}
|
|
3222
2046
|
const doc = document.scrollingElement ?? document.documentElement;
|
|
3223
2047
|
if (!overflows(doc)) return null;
|
|
3224
|
-
const
|
|
2048
|
+
const r9 = lab.getBoundingClientRect();
|
|
3225
2049
|
const bound = {
|
|
3226
|
-
top:
|
|
3227
|
-
left:
|
|
3228
|
-
bottom:
|
|
3229
|
-
right:
|
|
2050
|
+
top: r9.top,
|
|
2051
|
+
left: r9.left,
|
|
2052
|
+
bottom: r9.top + Math.min(r9.height, doc.clientHeight),
|
|
2053
|
+
right: r9.left + Math.min(r9.width, doc.clientWidth)
|
|
3230
2054
|
};
|
|
3231
2055
|
const hit = findOvershoot(bound, candidates(lab));
|
|
3232
2056
|
return hit ? `the page scrolls: ${describeElement(hit.item)} reaches ${Math.round(hit.by)}px past the lab's box (${hit.axis})` : null;
|
|
@@ -3282,20 +2106,19 @@ function LabHeader({ addTrial: addTrial2 = true }) {
|
|
|
3282
2106
|
]
|
|
3283
2107
|
}
|
|
3284
2108
|
) : /* @__PURE__ */ jsx(
|
|
3285
|
-
|
|
2109
|
+
l7,
|
|
3286
2110
|
{
|
|
3287
2111
|
"aria-label": "Add trial",
|
|
3288
2112
|
label: "Add trial\u2026",
|
|
3289
|
-
items: lab.instruments.map((
|
|
2113
|
+
items: lab.instruments.map((i3) => ({ value: i3.name, label: i3.title ?? i3.name })),
|
|
3290
2114
|
onAction: (name) => lab.addTrial(name)
|
|
3291
2115
|
}
|
|
3292
2116
|
),
|
|
3293
2117
|
/* @__PURE__ */ jsx(
|
|
3294
|
-
|
|
2118
|
+
r5,
|
|
3295
2119
|
{
|
|
3296
2120
|
className: "lk-lab-header__mode",
|
|
3297
2121
|
ariaLabel: "Color mode",
|
|
3298
|
-
size: "sm",
|
|
3299
2122
|
variant: "flat",
|
|
3300
2123
|
items: MODE_ITEMS,
|
|
3301
2124
|
value: lab.mode,
|
|
@@ -3309,17 +2132,44 @@ function LabHeader({ addTrial: addTrial2 = true }) {
|
|
|
3309
2132
|
function LabPalette({ tools, contributions }) {
|
|
3310
2133
|
const ctx = useLabChromeContext();
|
|
3311
2134
|
const all = labContributions(tools, contributions);
|
|
3312
|
-
return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((
|
|
2135
|
+
return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c9) => c9.region === "palette"), ctx });
|
|
2136
|
+
}
|
|
2137
|
+
function query() {
|
|
2138
|
+
if (typeof window === "undefined" || !window.matchMedia) return null;
|
|
2139
|
+
return window.matchMedia("(prefers-color-scheme: light)");
|
|
2140
|
+
}
|
|
2141
|
+
function useResolvedMode(mode) {
|
|
2142
|
+
const [system, setSystem] = useState(
|
|
2143
|
+
() => query()?.matches ? "light" : "dark"
|
|
2144
|
+
);
|
|
2145
|
+
useEffect(() => {
|
|
2146
|
+
if (mode !== "auto") return;
|
|
2147
|
+
const mq = query();
|
|
2148
|
+
if (!mq) return;
|
|
2149
|
+
const onChange = (e) => setSystem(e.matches ? "light" : "dark");
|
|
2150
|
+
mq.addEventListener("change", onChange);
|
|
2151
|
+
return () => mq.removeEventListener("change", onChange);
|
|
2152
|
+
}, [mode]);
|
|
2153
|
+
return mode === "auto" ? system : mode;
|
|
2154
|
+
}
|
|
2155
|
+
function LabRoot({ children, mode = "auto", className }) {
|
|
2156
|
+
const resolved = useResolvedMode(mode);
|
|
2157
|
+
const outer = useThemeOptional();
|
|
2158
|
+
const root = /* @__PURE__ */ jsx("div", { className: className ? `lk-root ${className}` : "lk-root", "data-wzl-portal-host": "", children });
|
|
2159
|
+
return outer ? root : /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, selection: { mode: resolved }, children: root });
|
|
3313
2160
|
}
|
|
3314
2161
|
function currentPage(path, pages) {
|
|
3315
|
-
const here = path.
|
|
2162
|
+
const here = path.replace(/[?#].*$/, "").replace(/\/$/, "").replace(/\.html$/, "");
|
|
3316
2163
|
return pages.findIndex((p2) => here.endsWith(p2.href.replace(/\.html$/, "")));
|
|
3317
2164
|
}
|
|
3318
2165
|
function LabSwitcher({ title, pages, path, className }) {
|
|
3319
2166
|
const [open, setOpen] = useState(false);
|
|
3320
2167
|
const root = useRef(null);
|
|
3321
2168
|
const menuId = useId();
|
|
3322
|
-
const here = currentPage(
|
|
2169
|
+
const here = currentPage(
|
|
2170
|
+
path ?? (typeof window === "undefined" ? "" : window.location.pathname),
|
|
2171
|
+
pages
|
|
2172
|
+
);
|
|
3323
2173
|
const close = useCallback(() => setOpen(false), []);
|
|
3324
2174
|
useEffect(() => {
|
|
3325
2175
|
if (!open) return;
|
|
@@ -3358,13 +2208,13 @@ function LabSwitcher({ title, pages, path, className }) {
|
|
|
3358
2208
|
]
|
|
3359
2209
|
}
|
|
3360
2210
|
) }),
|
|
3361
|
-
open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page,
|
|
2211
|
+
open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i3) => /* @__PURE__ */ jsx(
|
|
3362
2212
|
"a",
|
|
3363
2213
|
{
|
|
3364
2214
|
href: page.href,
|
|
3365
2215
|
role: "menuitem",
|
|
3366
2216
|
className: "lk-switcher-item",
|
|
3367
|
-
"aria-current":
|
|
2217
|
+
"aria-current": i3 === here ? "page" : void 0,
|
|
3368
2218
|
onClick: close,
|
|
3369
2219
|
children: page.label
|
|
3370
2220
|
},
|
|
@@ -3372,24 +2222,6 @@ function LabSwitcher({ title, pages, path, className }) {
|
|
|
3372
2222
|
)) })
|
|
3373
2223
|
] });
|
|
3374
2224
|
}
|
|
3375
|
-
function query() {
|
|
3376
|
-
if (typeof window === "undefined" || !window.matchMedia) return null;
|
|
3377
|
-
return window.matchMedia("(prefers-color-scheme: light)");
|
|
3378
|
-
}
|
|
3379
|
-
function useResolvedMode(mode) {
|
|
3380
|
-
const [system, setSystem] = useState(
|
|
3381
|
-
() => query()?.matches ? "light" : "dark"
|
|
3382
|
-
);
|
|
3383
|
-
useEffect(() => {
|
|
3384
|
-
if (mode !== "auto") return;
|
|
3385
|
-
const mq = query();
|
|
3386
|
-
if (!mq) return;
|
|
3387
|
-
const onChange = (e) => setSystem(e.matches ? "light" : "dark");
|
|
3388
|
-
mq.addEventListener("change", onChange);
|
|
3389
|
-
return () => mq.removeEventListener("change", onChange);
|
|
3390
|
-
}, [mode]);
|
|
3391
|
-
return mode === "auto" ? system : mode;
|
|
3392
|
-
}
|
|
3393
2225
|
function LabShell({
|
|
3394
2226
|
title,
|
|
3395
2227
|
children,
|
|
@@ -3399,29 +2231,14 @@ function LabShell({
|
|
|
3399
2231
|
pages,
|
|
3400
2232
|
path
|
|
3401
2233
|
}) {
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
/* @__PURE__ */
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
LabSwitcher,
|
|
3411
|
-
{
|
|
3412
|
-
title,
|
|
3413
|
-
pages,
|
|
3414
|
-
path,
|
|
3415
|
-
className: "lk-shell-title"
|
|
3416
|
-
}
|
|
3417
|
-
) : /* @__PURE__ */ jsx("h1", { className: "lk-shell-title", children: title }),
|
|
3418
|
-
header && /* @__PURE__ */ jsx("div", { className: "lk-shell-header-actions", children: header })
|
|
3419
|
-
] }),
|
|
3420
|
-
/* @__PURE__ */ jsx("main", { className: "lk-shell-body", children }),
|
|
3421
|
-
footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
|
|
3422
|
-
] })
|
|
3423
|
-
);
|
|
3424
|
-
return outer ? shell : /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, mode: resolved, children: shell });
|
|
2234
|
+
return /* @__PURE__ */ jsxs(LabRoot, { mode, className: "lk-shell", children: [
|
|
2235
|
+
/* @__PURE__ */ jsxs("header", { className: "lk-shell-header", children: [
|
|
2236
|
+
pages && pages.length > 0 ? /* @__PURE__ */ jsx(LabSwitcher, { title, pages, path, className: "lk-shell-title" }) : /* @__PURE__ */ jsx("h1", { className: "lk-shell-title", children: title }),
|
|
2237
|
+
header && /* @__PURE__ */ jsx("div", { className: "lk-shell-header-actions", children: header })
|
|
2238
|
+
] }),
|
|
2239
|
+
/* @__PURE__ */ jsx("main", { className: "lk-shell-body", children }),
|
|
2240
|
+
footer && /* @__PURE__ */ jsx("footer", { className: "lk-shell-footer", children: footer })
|
|
2241
|
+
] });
|
|
3425
2242
|
}
|
|
3426
2243
|
var ZONE_ID = asNodeId("lk-workspace");
|
|
3427
2244
|
var STRATEGIES = { grid: gridStrategy, floating: floatingStrategy };
|
|
@@ -3457,7 +2274,7 @@ function Workspace({
|
|
|
3457
2274
|
const tilePanels = useMemo(() => (panels ?? []).filter((p2) => p2.as === "tile"), [panels]);
|
|
3458
2275
|
const floatPanels = useMemo(() => (panels ?? []).filter((p2) => p2.as === "floating"), [panels]);
|
|
3459
2276
|
const wantedIds = [
|
|
3460
|
-
...items.map((_,
|
|
2277
|
+
...items.map((_, i3) => ids?.[i3] ?? `lk-ws-${i3}`),
|
|
3461
2278
|
...tilePanels.map((p2) => `lk-panel-${p2.key}`)
|
|
3462
2279
|
];
|
|
3463
2280
|
const idKey = wantedIds.join(",");
|
|
@@ -3533,7 +2350,7 @@ function Workspace({
|
|
|
3533
2350
|
[onReorder]
|
|
3534
2351
|
);
|
|
3535
2352
|
const chrome = useMemo(() => {
|
|
3536
|
-
const byId = new Map(nodeIds.map((id,
|
|
2353
|
+
const byId = new Map(nodeIds.map((id, i3) => [id, items[i3]]));
|
|
3537
2354
|
const panelByNode = new Map(
|
|
3538
2355
|
tilePanels.map((p2) => [`lk-panel-${p2.key}`, p2])
|
|
3539
2356
|
);
|
|
@@ -3599,7 +2416,7 @@ async function openStoredLab({ instruments, defaultInstrument, mode }, storageKe
|
|
|
3599
2416
|
const marks = /* @__PURE__ */ new Map();
|
|
3600
2417
|
await Promise.all(
|
|
3601
2418
|
opened.store.getState().trials.map(async (trial) => {
|
|
3602
|
-
const kept = instruments.find((
|
|
2419
|
+
const kept = instruments.find((i3) => i3.name === trial.instrumentName)?.annotations?.storage;
|
|
3603
2420
|
if (!kept) return;
|
|
3604
2421
|
try {
|
|
3605
2422
|
marks.set(trial.id, await kept.load());
|
|
@@ -3614,20 +2431,29 @@ async function openStoredLab({ instruments, defaultInstrument, mode }, storageKe
|
|
|
3614
2431
|
function LabFallback({
|
|
3615
2432
|
title,
|
|
3616
2433
|
mode,
|
|
2434
|
+
density,
|
|
3617
2435
|
pages,
|
|
3618
2436
|
path
|
|
3619
2437
|
}) {
|
|
3620
2438
|
const resolvedMode = useResolvedMode(mode ?? "auto");
|
|
3621
|
-
return /* @__PURE__ */ jsx(
|
|
3622
|
-
|
|
2439
|
+
return /* @__PURE__ */ jsx(
|
|
2440
|
+
ThemeProvider,
|
|
3623
2441
|
{
|
|
3624
|
-
|
|
3625
|
-
mode,
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
2442
|
+
theme: interstellarTheme,
|
|
2443
|
+
selection: { mode: resolvedMode, density: density ?? "comfortable" },
|
|
2444
|
+
className: "lk-lab",
|
|
2445
|
+
children: /* @__PURE__ */ jsx(
|
|
2446
|
+
LabShell,
|
|
2447
|
+
{
|
|
2448
|
+
title: title ?? "Labkit",
|
|
2449
|
+
mode,
|
|
2450
|
+
...pages ? { pages } : {},
|
|
2451
|
+
...path !== void 0 ? { path } : {},
|
|
2452
|
+
children: null
|
|
2453
|
+
}
|
|
2454
|
+
)
|
|
3629
2455
|
}
|
|
3630
|
-
)
|
|
2456
|
+
);
|
|
3631
2457
|
}
|
|
3632
2458
|
var NEBULA_SLOTS = [
|
|
3633
2459
|
{ cx: "18%", cy: "30%", sx: "60%", sy: "80%", stop: "70%" },
|
|
@@ -3637,9 +2463,9 @@ var NEBULA_SLOTS = [
|
|
|
3637
2463
|
{ cx: "85%", cy: "18%", sx: "55%", sy: "80%", stop: "70%" }
|
|
3638
2464
|
];
|
|
3639
2465
|
function buildNebula(colors) {
|
|
3640
|
-
const blobs = colors.map((
|
|
3641
|
-
const p2 = NEBULA_SLOTS[
|
|
3642
|
-
return `radial-gradient(ellipse ${p2.sx} ${p2.sy} at ${p2.cx} ${p2.cy}, color-mix(in srgb, ${
|
|
2466
|
+
const blobs = colors.map((c9, i3) => {
|
|
2467
|
+
const p2 = NEBULA_SLOTS[i3 % NEBULA_SLOTS.length];
|
|
2468
|
+
return `radial-gradient(ellipse ${p2.sx} ${p2.sy} at ${p2.cx} ${p2.cy}, color-mix(in srgb, ${c9} 22%, transparent), transparent ${p2.stop})`;
|
|
3643
2469
|
});
|
|
3644
2470
|
blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
|
|
3645
2471
|
return blobs.join(", ");
|
|
@@ -3654,6 +2480,30 @@ function LabPanes({
|
|
|
3654
2480
|
void 0,
|
|
3655
2481
|
{ scope: "lab" }
|
|
3656
2482
|
);
|
|
2483
|
+
const [asideWidth, setAsideWidth] = usePersistedState(
|
|
2484
|
+
"lk-lab-aside-width",
|
|
2485
|
+
void 0,
|
|
2486
|
+
{ scope: "lab" }
|
|
2487
|
+
);
|
|
2488
|
+
const main = contributions.some((c9) => c9.region === "aside") ? /* @__PURE__ */ jsx(
|
|
2489
|
+
Split,
|
|
2490
|
+
{
|
|
2491
|
+
className: "lk-lab__panes",
|
|
2492
|
+
side: "end",
|
|
2493
|
+
sidebarClassName: "lk-lab__aside",
|
|
2494
|
+
contentClassName: "lk-lab__main",
|
|
2495
|
+
label: "Lab aside",
|
|
2496
|
+
defaultWidth: 320,
|
|
2497
|
+
width: asideWidth,
|
|
2498
|
+
onWidthChange: (w3) => {
|
|
2499
|
+
setAsideWidth(w3);
|
|
2500
|
+
surface?.invalidateRects();
|
|
2501
|
+
},
|
|
2502
|
+
sidebar: /* @__PURE__ */ jsx(LabAsideRegion, { contributions }),
|
|
2503
|
+
children
|
|
2504
|
+
}
|
|
2505
|
+
) : children;
|
|
2506
|
+
if (!contributions.some((c9) => c9.region === "sidebar")) return main;
|
|
3657
2507
|
return /* @__PURE__ */ jsx(
|
|
3658
2508
|
Split,
|
|
3659
2509
|
{
|
|
@@ -3663,12 +2513,12 @@ function LabPanes({
|
|
|
3663
2513
|
label: "Lab sidebar",
|
|
3664
2514
|
defaultWidth: 260,
|
|
3665
2515
|
width: sidebarWidth,
|
|
3666
|
-
onWidthChange: (
|
|
3667
|
-
setSidebarWidth(
|
|
2516
|
+
onWidthChange: (w3) => {
|
|
2517
|
+
setSidebarWidth(w3);
|
|
3668
2518
|
surface?.invalidateRects();
|
|
3669
2519
|
},
|
|
3670
2520
|
sidebar: /* @__PURE__ */ jsx(LabSidebarRegion, { contributions }),
|
|
3671
|
-
children
|
|
2521
|
+
children: main
|
|
3672
2522
|
}
|
|
3673
2523
|
);
|
|
3674
2524
|
}
|
|
@@ -3682,13 +2532,24 @@ function Lab(props) {
|
|
|
3682
2532
|
() => storageKey === void 0 ? openUnstoredLab(props) : openStoredLab(props, storageKey, storage)
|
|
3683
2533
|
);
|
|
3684
2534
|
if (!opened) {
|
|
3685
|
-
|
|
2535
|
+
if (props.fallback !== void 0) return props.fallback;
|
|
2536
|
+
return /* @__PURE__ */ jsx(
|
|
2537
|
+
LabFallback,
|
|
2538
|
+
{
|
|
2539
|
+
title: props.title,
|
|
2540
|
+
mode: props.mode,
|
|
2541
|
+
density: props.density,
|
|
2542
|
+
pages: props.pages,
|
|
2543
|
+
path: props.path
|
|
2544
|
+
}
|
|
2545
|
+
);
|
|
3686
2546
|
}
|
|
3687
2547
|
return /* @__PURE__ */ jsx(LabRuntime, { ...props, opened });
|
|
3688
2548
|
}
|
|
3689
2549
|
function LabRuntime({
|
|
3690
2550
|
instruments,
|
|
3691
2551
|
mode,
|
|
2552
|
+
density,
|
|
3692
2553
|
nebula,
|
|
3693
2554
|
title,
|
|
3694
2555
|
pages,
|
|
@@ -3708,11 +2569,13 @@ function LabRuntime({
|
|
|
3708
2569
|
useLayoutEffect(() => {
|
|
3709
2570
|
store.getState().setInstruments(instruments);
|
|
3710
2571
|
}, [instruments, store]);
|
|
3711
|
-
const trials = useStore(store, (
|
|
3712
|
-
const
|
|
3713
|
-
const
|
|
3714
|
-
const
|
|
3715
|
-
const
|
|
2572
|
+
const trials = useStore(store, (s5) => s5.trials);
|
|
2573
|
+
const [focusPick, setFocusPick] = useState(null);
|
|
2574
|
+
const focusedTrialId = trials.some((t) => t.id === focusPick) ? focusPick : trials[0]?.id ?? null;
|
|
2575
|
+
const savedSnapshots = useStore(store, (s5) => s5.savedSnapshots);
|
|
2576
|
+
const modeValue = useStore(store, (s5) => s5.mode);
|
|
2577
|
+
const layout = useStore(store, (s5) => s5.layout);
|
|
2578
|
+
const undockedPanels = useStore(store, (s5) => s5.undockedPanels);
|
|
3716
2579
|
const panelHostsRef = useRef(null);
|
|
3717
2580
|
if (panelHostsRef.current === null) panelHostsRef.current = createPanelHostRegistry();
|
|
3718
2581
|
const outerSurface = useSurfaceOptional();
|
|
@@ -3725,17 +2588,17 @@ function LabRuntime({
|
|
|
3725
2588
|
const bufferRef = useRef({ w: 0, h: 0 });
|
|
3726
2589
|
const surfaceRef = useRef(null);
|
|
3727
2590
|
const onFrame = useCallback((frame) => {
|
|
3728
|
-
const canvases = [ownUnderRef.current, ownOverRef.current].filter((
|
|
2591
|
+
const canvases = [ownUnderRef.current, ownOverRef.current].filter((c9) => c9 !== null);
|
|
3729
2592
|
if (canvases.length === 0) return;
|
|
3730
|
-
const
|
|
2593
|
+
const w3 = Math.round(frame.size.width * frame.dpr);
|
|
3731
2594
|
const h2 = Math.round(frame.size.height * frame.dpr);
|
|
3732
|
-
if (bufferRef.current.w !==
|
|
3733
|
-
bufferRef.current = { w:
|
|
3734
|
-
for (const
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
2595
|
+
if (bufferRef.current.w !== w3 || bufferRef.current.h !== h2) {
|
|
2596
|
+
bufferRef.current = { w: w3, h: h2 };
|
|
2597
|
+
for (const c9 of canvases) {
|
|
2598
|
+
c9.width = w3;
|
|
2599
|
+
c9.height = h2;
|
|
2600
|
+
c9.style.width = `${frame.size.width}px`;
|
|
2601
|
+
c9.style.height = `${frame.size.height}px`;
|
|
3739
2602
|
}
|
|
3740
2603
|
surfaceRef.current?.invalidateAll();
|
|
3741
2604
|
return;
|
|
@@ -3753,6 +2616,33 @@ function LabRuntime({
|
|
|
3753
2616
|
[outerSurface, attachOwnSurface]
|
|
3754
2617
|
);
|
|
3755
2618
|
useLabFitWarning(labBody);
|
|
2619
|
+
useEffect(() => {
|
|
2620
|
+
if (!labBody) return;
|
|
2621
|
+
const pick = (node) => {
|
|
2622
|
+
const owned = new Set(store.getState().trials.map((t) => t.id));
|
|
2623
|
+
const nearest = (from) => from?.closest(".lk-trial[data-trial-id]") ?? null;
|
|
2624
|
+
let trial = typeof node?.closest === "function" ? nearest(node) : null;
|
|
2625
|
+
while (trial && !owned.has(trial.dataset.trialId ?? "")) trial = nearest(trial.parentElement);
|
|
2626
|
+
if (trial?.dataset.trialId) setFocusPick(trial.dataset.trialId);
|
|
2627
|
+
};
|
|
2628
|
+
const onInput = (event) => pick(event.target);
|
|
2629
|
+
let pending;
|
|
2630
|
+
const doc = labBody.ownerDocument;
|
|
2631
|
+
const win = doc.defaultView;
|
|
2632
|
+
const onBlur = () => {
|
|
2633
|
+
clearTimeout(pending);
|
|
2634
|
+
pending = setTimeout(() => pick(doc.activeElement), 0);
|
|
2635
|
+
};
|
|
2636
|
+
labBody.addEventListener("pointerdown", onInput, true);
|
|
2637
|
+
labBody.addEventListener("focusin", onInput, true);
|
|
2638
|
+
win?.addEventListener("blur", onBlur);
|
|
2639
|
+
return () => {
|
|
2640
|
+
clearTimeout(pending);
|
|
2641
|
+
labBody.removeEventListener("pointerdown", onInput, true);
|
|
2642
|
+
labBody.removeEventListener("focusin", onInput, true);
|
|
2643
|
+
win?.removeEventListener("blur", onBlur);
|
|
2644
|
+
};
|
|
2645
|
+
}, [labBody, store]);
|
|
3756
2646
|
const surface = outerSurface ?? ownSurface;
|
|
3757
2647
|
const surfaceCanvases = useMemo(
|
|
3758
2648
|
() => outerSurface ? { over: outerOver, under: outerUnder } : { over: ownOver, under: ownUnder },
|
|
@@ -3767,13 +2657,13 @@ function LabRuntime({
|
|
|
3767
2657
|
[undockedPanels]
|
|
3768
2658
|
);
|
|
3769
2659
|
const resolvedMode = useResolvedMode(modeValue);
|
|
3770
|
-
const annotates = instruments.some((
|
|
2660
|
+
const annotates = instruments.some((i3) => i3.annotations != null);
|
|
3771
2661
|
const labChromeAll = useMemo(
|
|
3772
2662
|
() => labContributions([...annotates ? ANNOTATION_TOOLS : [], ...tools ?? []], labChrome),
|
|
3773
2663
|
[annotates, tools, labChrome]
|
|
3774
2664
|
);
|
|
3775
|
-
const hasFooterChrome = labChromeAll.some((
|
|
3776
|
-
const
|
|
2665
|
+
const hasFooterChrome = labChromeAll.some((c9) => c9.region === "footer");
|
|
2666
|
+
const hasPaneChrome = labChromeAll.some((c9) => c9.region === "sidebar" || c9.region === "aside");
|
|
3777
2667
|
useEffect(() => {
|
|
3778
2668
|
if (mode && mode !== store.getState().mode) {
|
|
3779
2669
|
store.getState().setMode(mode);
|
|
@@ -3781,20 +2671,26 @@ function LabRuntime({
|
|
|
3781
2671
|
}, [mode, store]);
|
|
3782
2672
|
const contextValue = useMemo(() => {
|
|
3783
2673
|
const replaceTrials = (next) => {
|
|
3784
|
-
const currentById = new Map(store.getState().trials.map((
|
|
3785
|
-
const merged = next.map((
|
|
2674
|
+
const currentById = new Map(store.getState().trials.map((w3) => [w3.id, w3]));
|
|
2675
|
+
const merged = next.map((w3) => currentById.get(w3.id) ?? w3);
|
|
3786
2676
|
store.setState({ trials: merged });
|
|
3787
2677
|
};
|
|
2678
|
+
const replaceAndFocusAdded = (next) => {
|
|
2679
|
+
const before = new Set(store.getState().trials.map((w3) => w3.id));
|
|
2680
|
+
replaceTrials(next);
|
|
2681
|
+
const added = next.find((w3) => !before.has(w3.id));
|
|
2682
|
+
if (added) setFocusPick(added.id);
|
|
2683
|
+
};
|
|
3788
2684
|
return {
|
|
3789
2685
|
instruments,
|
|
3790
2686
|
trials,
|
|
3791
2687
|
addTrial: (instrumentName, options) => {
|
|
3792
|
-
|
|
3793
|
-
|
|
2688
|
+
replaceAndFocusAdded(
|
|
2689
|
+
addTrial(store.getState().trials, instruments, instrumentName, options)
|
|
2690
|
+
);
|
|
3794
2691
|
},
|
|
3795
2692
|
cloneTrial: (id) => {
|
|
3796
|
-
|
|
3797
|
-
replaceTrials(next);
|
|
2693
|
+
replaceAndFocusAdded(cloneTrial(store.getState().trials, id));
|
|
3798
2694
|
},
|
|
3799
2695
|
closeTrial: (id) => {
|
|
3800
2696
|
const next = closeTrial(store.getState().trials, id);
|
|
@@ -3803,19 +2699,31 @@ function LabRuntime({
|
|
|
3803
2699
|
reorderTrials: (ids) => {
|
|
3804
2700
|
replaceTrials(reorderTrials(store.getState().trials, ids));
|
|
3805
2701
|
},
|
|
2702
|
+
swapTrial: (id, instrumentName, options) => {
|
|
2703
|
+
const current = store.getState();
|
|
2704
|
+
const next = swapTrial(current.trials, instruments, id, instrumentName, options);
|
|
2705
|
+
if (next === current.trials) return;
|
|
2706
|
+
const record = next[current.trials.findIndex((w3) => w3.id === id)];
|
|
2707
|
+
const { [id]: extent, ...layoutRest } = current.layout;
|
|
2708
|
+
if (extent) current.setLayout({ ...layoutRest, [record.id]: extent });
|
|
2709
|
+
replaceTrials(next);
|
|
2710
|
+
if (focusedTrialId === id) setFocusPick(record.id);
|
|
2711
|
+
},
|
|
2712
|
+
focusedTrialId,
|
|
2713
|
+
focusTrial: (id) => setFocusPick(id),
|
|
3806
2714
|
resetTrial: (id) => {
|
|
3807
2715
|
const next = resetTrial(store.getState().trials, id, instruments);
|
|
3808
|
-
const record = next.find((
|
|
2716
|
+
const record = next.find((w3) => w3.id === id);
|
|
3809
2717
|
if (!record) return;
|
|
3810
|
-
store.setState((
|
|
3811
|
-
trials:
|
|
3812
|
-
(
|
|
2718
|
+
store.setState((s5) => ({
|
|
2719
|
+
trials: s5.trials.map(
|
|
2720
|
+
(w3) => w3.id === id ? { ...w3, config: record.config, state: record.state, view: record.view } : w3
|
|
3813
2721
|
)
|
|
3814
2722
|
}));
|
|
3815
2723
|
},
|
|
3816
2724
|
savedSnapshots,
|
|
3817
2725
|
saveSnapshot: (trialId, name) => {
|
|
3818
|
-
const taken = store.getState().savedSnapshots.filter((
|
|
2726
|
+
const taken = store.getState().savedSnapshots.filter((s5) => s5.trialId === trialId).length;
|
|
3819
2727
|
store.getState().saveSnapshot(trialId, name ?? `Snapshot ${taken + 1}`);
|
|
3820
2728
|
},
|
|
3821
2729
|
loadSnapshot: (trialId, snapshotId) => {
|
|
@@ -3825,32 +2733,41 @@ function LabRuntime({
|
|
|
3825
2733
|
store.getState().deleteSnapshot(snapshotId);
|
|
3826
2734
|
},
|
|
3827
2735
|
mode: modeValue,
|
|
3828
|
-
setMode: (
|
|
3829
|
-
store.getState().setMode(
|
|
2736
|
+
setMode: (m2) => {
|
|
2737
|
+
store.getState().setMode(m2);
|
|
3830
2738
|
},
|
|
3831
2739
|
configRules,
|
|
3832
2740
|
controls
|
|
3833
2741
|
};
|
|
3834
|
-
}, [
|
|
2742
|
+
}, [
|
|
2743
|
+
instruments,
|
|
2744
|
+
trials,
|
|
2745
|
+
focusedTrialId,
|
|
2746
|
+
savedSnapshots,
|
|
2747
|
+
modeValue,
|
|
2748
|
+
store,
|
|
2749
|
+
configRules,
|
|
2750
|
+
controls
|
|
2751
|
+
]);
|
|
3835
2752
|
const backdropStyle = resolvedMode === "dark" && nebula && nebula.length > 0 ? { ["--wzl-backdrop"]: buildNebula(nebula) } : void 0;
|
|
3836
2753
|
const workspace = /* @__PURE__ */ jsx(
|
|
3837
2754
|
Workspace,
|
|
3838
2755
|
{
|
|
3839
2756
|
panels: workspacePanels,
|
|
3840
|
-
ids: trials.map((
|
|
2757
|
+
ids: trials.map((w3) => w3.id),
|
|
3841
2758
|
resizable: true,
|
|
3842
2759
|
reorderable: true,
|
|
3843
2760
|
onReorder: (ids) => contextValue.reorderTrials(ids),
|
|
3844
2761
|
layout,
|
|
3845
2762
|
onLayoutChange: (next) => store.getState().setLayout(next),
|
|
3846
|
-
children: trials.map((
|
|
2763
|
+
children: trials.map((w3) => /* @__PURE__ */ jsx(Trial, { id: w3.id, chrome, suppress }, w3.id))
|
|
3847
2764
|
}
|
|
3848
2765
|
);
|
|
3849
2766
|
return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: { store }, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: opened.records, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: opened.marks, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
3850
2767
|
ThemeProvider,
|
|
3851
2768
|
{
|
|
3852
2769
|
theme: interstellarTheme,
|
|
3853
|
-
mode: resolvedMode,
|
|
2770
|
+
selection: { mode: resolvedMode, density: density ?? "comfortable" },
|
|
3854
2771
|
className: "lk-lab",
|
|
3855
2772
|
style: backdropStyle,
|
|
3856
2773
|
children: /* @__PURE__ */ jsx(
|
|
@@ -3899,7 +2816,7 @@ function LabRuntime({
|
|
|
3899
2816
|
)
|
|
3900
2817
|
] })
|
|
3901
2818
|
),
|
|
3902
|
-
|
|
2819
|
+
hasPaneChrome ? /* @__PURE__ */ jsxs(LabPanes, { contributions: labChromeAll, children: [
|
|
3903
2820
|
/* @__PURE__ */ jsx(LabPalette, { contributions: labChromeAll }),
|
|
3904
2821
|
workspace
|
|
3905
2822
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -3912,7 +2829,759 @@ function LabRuntime({
|
|
|
3912
2829
|
}
|
|
3913
2830
|
) }) }) }) });
|
|
3914
2831
|
}
|
|
2832
|
+
var SPECIMEN_SECTIONS = [
|
|
2833
|
+
"Buttons & toggles",
|
|
2834
|
+
"Fields & pickers",
|
|
2835
|
+
"Panels & property rows",
|
|
2836
|
+
"Overlays & feedback",
|
|
2837
|
+
"Lists & data",
|
|
2838
|
+
"Tool chrome",
|
|
2839
|
+
"Editors & plots",
|
|
2840
|
+
"Lab chrome"
|
|
2841
|
+
];
|
|
2842
|
+
function Section({ title, children }) {
|
|
2843
|
+
const id = useId();
|
|
2844
|
+
return /* @__PURE__ */ jsxs("section", { className: "lk-specimen__section", "aria-labelledby": id, children: [
|
|
2845
|
+
/* @__PURE__ */ jsx("h2", { id, className: "lk-specimen__heading", children: title }),
|
|
2846
|
+
/* @__PURE__ */ jsx("div", { className: "lk-specimen__grid", children })
|
|
2847
|
+
] });
|
|
2848
|
+
}
|
|
2849
|
+
function Cell({ label, wide, children }) {
|
|
2850
|
+
return /* @__PURE__ */ jsxs("div", { className: wide ? "lk-specimen__cell lk-specimen__cell--wide" : "lk-specimen__cell", children: [
|
|
2851
|
+
/* @__PURE__ */ jsx("span", { className: "lk-specimen__label", children: label }),
|
|
2852
|
+
children
|
|
2853
|
+
] });
|
|
2854
|
+
}
|
|
2855
|
+
function Dot() {
|
|
2856
|
+
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": "true", children: /* @__PURE__ */ jsx("circle", { cx: 8, cy: 8, r: 4, fill: "currentColor" }) });
|
|
2857
|
+
}
|
|
2858
|
+
var LEGEND = [
|
|
2859
|
+
{ key: "contour", label: "contour", color: "var(--wzl-fg-muted)" },
|
|
2860
|
+
{ key: "floor", label: "floor", color: "var(--wzl-fg-subtle)", mark: "dash" },
|
|
2861
|
+
{ key: "authored", label: "authored", color: "var(--wzl-success)", mark: "dot" },
|
|
2862
|
+
{ key: "replaced", label: "replaced", color: "var(--wzl-danger)", mark: "band" }
|
|
2863
|
+
];
|
|
2864
|
+
var PREFS = {
|
|
2865
|
+
name: "Preferences",
|
|
2866
|
+
children: {
|
|
2867
|
+
canvas: {
|
|
2868
|
+
name: "Canvas",
|
|
2869
|
+
children: {
|
|
2870
|
+
showGrid: {
|
|
2871
|
+
kind: "boolean",
|
|
2872
|
+
name: "Show grid",
|
|
2873
|
+
description: "Draw a grid behind the scene.",
|
|
2874
|
+
default: true
|
|
2875
|
+
},
|
|
2876
|
+
zoomStep: {
|
|
2877
|
+
kind: "number",
|
|
2878
|
+
name: "Zoom step",
|
|
2879
|
+
description: "Percent the zoom controls move per click.",
|
|
2880
|
+
default: 10,
|
|
2881
|
+
min: 1,
|
|
2882
|
+
max: 50
|
|
2883
|
+
},
|
|
2884
|
+
format: {
|
|
2885
|
+
kind: "enum",
|
|
2886
|
+
name: "Format",
|
|
2887
|
+
description: "File type for exported images.",
|
|
2888
|
+
default: "svg",
|
|
2889
|
+
options: [
|
|
2890
|
+
{ value: "svg", label: "SVG" },
|
|
2891
|
+
{ value: "png", label: "PNG" }
|
|
2892
|
+
]
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
};
|
|
2898
|
+
var JOB = {
|
|
2899
|
+
status: "running",
|
|
2900
|
+
done: 34,
|
|
2901
|
+
total: 120,
|
|
2902
|
+
failures: [],
|
|
2903
|
+
error: null,
|
|
2904
|
+
start: () => {
|
|
2905
|
+
},
|
|
2906
|
+
cancel: () => {
|
|
2907
|
+
}
|
|
2908
|
+
};
|
|
2909
|
+
function setAt(values, path, value) {
|
|
2910
|
+
const [head, ...rest] = path.split(".");
|
|
2911
|
+
if (head === void 0) return values;
|
|
2912
|
+
if (rest.length === 0) return { ...values, [head]: value };
|
|
2913
|
+
const inner = values[head] ?? {};
|
|
2914
|
+
return { ...values, [head]: setAt(inner, rest.join("."), value) };
|
|
2915
|
+
}
|
|
2916
|
+
function ButtonsAndToggles() {
|
|
2917
|
+
const [snap, setSnap] = useState(true);
|
|
2918
|
+
const [wifi, setWifi] = useState(false);
|
|
2919
|
+
const [align, setAlign] = useState("center");
|
|
2920
|
+
const [bold, setBold] = useState(true);
|
|
2921
|
+
const [italic, setItalic] = useState(false);
|
|
2922
|
+
const [open, setOpen] = useState(true);
|
|
2923
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Buttons & toggles", children: [
|
|
2924
|
+
/* @__PURE__ */ jsx(Cell, { label: "Button", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
2925
|
+
/* @__PURE__ */ jsx(a5, { variant: "primary", children: "Save" }),
|
|
2926
|
+
/* @__PURE__ */ jsx(a5, { variant: "secondary", children: "Cancel" }),
|
|
2927
|
+
/* @__PURE__ */ jsx(a5, { variant: "ghost", children: "Ghost" }),
|
|
2928
|
+
/* @__PURE__ */ jsx(a5, { variant: "secondary", disabled: true, children: "Disabled" }),
|
|
2929
|
+
/* @__PURE__ */ jsx(a5, { variant: "secondary", iconOnly: true, ariaLabel: "Add", children: /* @__PURE__ */ jsx(Dot, {}) })
|
|
2930
|
+
] }) }),
|
|
2931
|
+
/* @__PURE__ */ jsx(Cell, { label: "Badge", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
2932
|
+
/* @__PURE__ */ jsx(Lt, { shape: "pill", tone: "accent", variant: "outline", size: "sm", children: "ACCENT" }),
|
|
2933
|
+
/* @__PURE__ */ jsx(Lt, { tone: "info", variant: "subtle", children: "INFO" }),
|
|
2934
|
+
/* @__PURE__ */ jsx(Lt, { tone: "warn", variant: "solid", children: "WARN" }),
|
|
2935
|
+
/* @__PURE__ */ jsx(Lt, { tone: "danger", variant: "solid", children: "DANGER" }),
|
|
2936
|
+
/* @__PURE__ */ jsx(Lt, { tone: "muted", children: "MUTED" })
|
|
2937
|
+
] }) }),
|
|
2938
|
+
/* @__PURE__ */ jsx(Cell, { label: "Checkbox, Switch", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
2939
|
+
/* @__PURE__ */ jsx(o2, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
|
|
2940
|
+
/* @__PURE__ */ jsx(o2, { isIndeterminate: true, children: "Mixed" }),
|
|
2941
|
+
/* @__PURE__ */ jsx(a3, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
|
|
2942
|
+
] }) }),
|
|
2943
|
+
/* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l3, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
|
|
2944
|
+
/* @__PURE__ */ jsx(u3, { value: "off", children: "Off" }),
|
|
2945
|
+
/* @__PURE__ */ jsx(u3, { value: "grid", children: "Grid" }),
|
|
2946
|
+
/* @__PURE__ */ jsx(u3, { value: "pixel", children: "Pixel" })
|
|
2947
|
+
] }) }),
|
|
2948
|
+
/* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
|
|
2949
|
+
/* @__PURE__ */ jsx(
|
|
2950
|
+
r5,
|
|
2951
|
+
{
|
|
2952
|
+
ariaLabel: "Align",
|
|
2953
|
+
value: align,
|
|
2954
|
+
onChange: setAlign,
|
|
2955
|
+
items: [
|
|
2956
|
+
{ value: "left", label: "Left" },
|
|
2957
|
+
{ value: "center", label: "Center" },
|
|
2958
|
+
{ value: "right", label: "Right" }
|
|
2959
|
+
]
|
|
2960
|
+
}
|
|
2961
|
+
),
|
|
2962
|
+
/* @__PURE__ */ jsx(
|
|
2963
|
+
r5,
|
|
2964
|
+
{
|
|
2965
|
+
ariaLabel: "Align, flat",
|
|
2966
|
+
variant: "flat",
|
|
2967
|
+
value: align,
|
|
2968
|
+
onChange: setAlign,
|
|
2969
|
+
items: [
|
|
2970
|
+
{ value: "left", label: "Left" },
|
|
2971
|
+
{ value: "center", label: "Center" },
|
|
2972
|
+
{ value: "right", label: "Right" }
|
|
2973
|
+
]
|
|
2974
|
+
}
|
|
2975
|
+
)
|
|
2976
|
+
] }),
|
|
2977
|
+
/* @__PURE__ */ jsx(Cell, { label: "OptionsBar, ActionsBar", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
2978
|
+
/* @__PURE__ */ jsx(
|
|
2979
|
+
r7,
|
|
2980
|
+
{
|
|
2981
|
+
ariaLabel: "Text style",
|
|
2982
|
+
items: [
|
|
2983
|
+
{ value: "b", label: "B", selected: bold, onChange: setBold },
|
|
2984
|
+
{ value: "i", label: "I", selected: italic, onChange: setItalic }
|
|
2985
|
+
]
|
|
2986
|
+
}
|
|
2987
|
+
),
|
|
2988
|
+
/* @__PURE__ */ jsx(
|
|
2989
|
+
r8,
|
|
2990
|
+
{
|
|
2991
|
+
items: [
|
|
2992
|
+
{ value: "undo", label: "Undo", onAction: () => {
|
|
2993
|
+
} },
|
|
2994
|
+
{ value: "redo", label: "Redo", onAction: () => {
|
|
2995
|
+
} }
|
|
2996
|
+
]
|
|
2997
|
+
}
|
|
2998
|
+
)
|
|
2999
|
+
] }) }),
|
|
3000
|
+
/* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
3001
|
+
/* @__PURE__ */ jsx(
|
|
3002
|
+
l7,
|
|
3003
|
+
{
|
|
3004
|
+
label: "Add trial\u2026",
|
|
3005
|
+
onAction: () => {
|
|
3006
|
+
},
|
|
3007
|
+
items: [
|
|
3008
|
+
{ value: "sine", label: "Sine wave" },
|
|
3009
|
+
{ value: "annotate", label: "Annotate" }
|
|
3010
|
+
]
|
|
3011
|
+
}
|
|
3012
|
+
),
|
|
3013
|
+
/* @__PURE__ */ jsx(r6, { open, onToggle: () => setOpen((o5) => !o5), label: "Shapes" }),
|
|
3014
|
+
/* @__PURE__ */ jsx(r6, { open: false, onToggle: () => {
|
|
3015
|
+
}, label: "Down", direction: "down" })
|
|
3016
|
+
] }) }),
|
|
3017
|
+
/* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o5, { children: [
|
|
3018
|
+
/* @__PURE__ */ jsxs(s5, { "aria-label": "Sections", children: [
|
|
3019
|
+
/* @__PURE__ */ jsx(c7, { id: "props", children: "Props" }),
|
|
3020
|
+
/* @__PURE__ */ jsx(c7, { id: "events", children: "Events" }),
|
|
3021
|
+
/* @__PURE__ */ jsx(c7, { id: "snapshot", children: "Snapshot" })
|
|
3022
|
+
] }),
|
|
3023
|
+
/* @__PURE__ */ jsx(l6, { id: "props", children: "Props panel." }),
|
|
3024
|
+
/* @__PURE__ */ jsx(l6, { id: "events", children: "Events panel." }),
|
|
3025
|
+
/* @__PURE__ */ jsx(l6, { id: "snapshot", children: "Snapshot panel." })
|
|
3026
|
+
] }) }),
|
|
3027
|
+
/* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
3028
|
+
/* @__PURE__ */ jsx(c3, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
|
|
3029
|
+
/* @__PURE__ */ jsx(s3, { label: "K" }),
|
|
3030
|
+
/* @__PURE__ */ jsx(s3, { label: "\u2325", variant: "minimal" })
|
|
3031
|
+
] }) })
|
|
3032
|
+
] });
|
|
3033
|
+
}
|
|
3034
|
+
function FieldsAndPickers() {
|
|
3035
|
+
const [thumbs, setThumbs] = useState([{ value: 0.25 }, { value: 0.75 }]);
|
|
3036
|
+
const [rate, setRate] = useState(1);
|
|
3037
|
+
const [width, setWidth] = useState(6);
|
|
3038
|
+
const [color, setColor] = useState("#b08adbff");
|
|
3039
|
+
const [gradient, setGradient] = useState({
|
|
3040
|
+
fill: "linear-gradient",
|
|
3041
|
+
from: { x: 0.1, y: 0.1 },
|
|
3042
|
+
to: { x: 0.9, y: 0.9 },
|
|
3043
|
+
stops: [
|
|
3044
|
+
{ offset: 0, color: "#0fb5a8" },
|
|
3045
|
+
{ offset: 1, color: "#f4c43c" }
|
|
3046
|
+
]
|
|
3047
|
+
});
|
|
3048
|
+
const [paint, setPaint] = useState({ fill: "solid", color: "#b08adb" });
|
|
3049
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Fields & pickers", children: [
|
|
3050
|
+
/* @__PURE__ */ jsxs(Cell, { label: "Input", children: [
|
|
3051
|
+
/* @__PURE__ */ jsx(u2, { label: "Name", placeholder: "e.g. Pico" }),
|
|
3052
|
+
/* @__PURE__ */ jsx(
|
|
3053
|
+
u2,
|
|
3054
|
+
{
|
|
3055
|
+
label: "Size",
|
|
3056
|
+
leadingAdornment: /* @__PURE__ */ jsx("span", { children: "W" }),
|
|
3057
|
+
trailingAdornment: /* @__PURE__ */ jsx("span", { children: "px" }),
|
|
3058
|
+
defaultValue: "120"
|
|
3059
|
+
}
|
|
3060
|
+
),
|
|
3061
|
+
/* @__PURE__ */ jsx(u2, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
|
|
3062
|
+
] }),
|
|
3063
|
+
/* @__PURE__ */ jsxs(Cell, { label: "NumberField, Select, ComboBox", children: [
|
|
3064
|
+
/* @__PURE__ */ jsx(g, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
|
|
3065
|
+
/* @__PURE__ */ jsx(
|
|
3066
|
+
b2,
|
|
3067
|
+
{
|
|
3068
|
+
label: "Color",
|
|
3069
|
+
defaultSelectedKey: "g",
|
|
3070
|
+
options: [
|
|
3071
|
+
{ value: "r", label: "Red" },
|
|
3072
|
+
{ value: "g", label: "Green" },
|
|
3073
|
+
{ value: "b", label: "Blue" }
|
|
3074
|
+
]
|
|
3075
|
+
}
|
|
3076
|
+
),
|
|
3077
|
+
/* @__PURE__ */ jsx(
|
|
3078
|
+
y2,
|
|
3079
|
+
{
|
|
3080
|
+
label: "Filter",
|
|
3081
|
+
placeholder: "Type to filter\u2026",
|
|
3082
|
+
options: [
|
|
3083
|
+
{ value: "r", label: "Red" },
|
|
3084
|
+
{ value: "g", label: "Green" }
|
|
3085
|
+
]
|
|
3086
|
+
}
|
|
3087
|
+
)
|
|
3088
|
+
] }),
|
|
3089
|
+
/* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
|
|
3090
|
+
/* @__PURE__ */ jsx(l4, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
|
|
3091
|
+
/* @__PURE__ */ jsx(
|
|
3092
|
+
l4,
|
|
3093
|
+
{
|
|
3094
|
+
label: "Opacity",
|
|
3095
|
+
defaultValue: 75,
|
|
3096
|
+
minValue: 0,
|
|
3097
|
+
maxValue: 100,
|
|
3098
|
+
formatOutput: (v2) => `${v2}%`
|
|
3099
|
+
}
|
|
3100
|
+
),
|
|
3101
|
+
/* @__PURE__ */ jsx(
|
|
3102
|
+
b3,
|
|
3103
|
+
{
|
|
3104
|
+
ariaLabel: "Pair",
|
|
3105
|
+
min: 0,
|
|
3106
|
+
max: 1,
|
|
3107
|
+
step: 0.01,
|
|
3108
|
+
constraint: "ordered",
|
|
3109
|
+
thumbs,
|
|
3110
|
+
onInput: setThumbs,
|
|
3111
|
+
readoutPlacement: "inline-after"
|
|
3112
|
+
}
|
|
3113
|
+
)
|
|
3114
|
+
] }),
|
|
3115
|
+
/* @__PURE__ */ jsxs(Cell, { label: "DetentSlider, InlineRange", children: [
|
|
3116
|
+
/* @__PURE__ */ jsx(
|
|
3117
|
+
c8,
|
|
3118
|
+
{
|
|
3119
|
+
items: [0.25, 0.5, 1, 2, 4],
|
|
3120
|
+
value: rate,
|
|
3121
|
+
onChange: setRate,
|
|
3122
|
+
formatLabel: (r9) => `${r9}\xD7`,
|
|
3123
|
+
labels: "all",
|
|
3124
|
+
ariaLabel: "Playback rate"
|
|
3125
|
+
}
|
|
3126
|
+
),
|
|
3127
|
+
/* @__PURE__ */ jsx(
|
|
3128
|
+
r3,
|
|
3129
|
+
{
|
|
3130
|
+
"aria-label": "Width",
|
|
3131
|
+
min: 0,
|
|
3132
|
+
max: 20,
|
|
3133
|
+
value: width,
|
|
3134
|
+
onChange: (event) => setWidth(Number(event.target.value))
|
|
3135
|
+
}
|
|
3136
|
+
)
|
|
3137
|
+
] }),
|
|
3138
|
+
/* @__PURE__ */ jsxs(Cell, { label: "ColorField, GradientEditor", children: [
|
|
3139
|
+
/* @__PURE__ */ jsx(l2, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
|
|
3140
|
+
/* @__PURE__ */ jsx(C2, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
|
|
3141
|
+
] }),
|
|
3142
|
+
/* @__PURE__ */ jsx(Cell, { label: "PaintInput", children: /* @__PURE__ */ jsx(
|
|
3143
|
+
S,
|
|
3144
|
+
{
|
|
3145
|
+
value: paint,
|
|
3146
|
+
onInput: setPaint,
|
|
3147
|
+
onChange: setPaint,
|
|
3148
|
+
allowNone: true,
|
|
3149
|
+
"aria-label": "Fill"
|
|
3150
|
+
}
|
|
3151
|
+
) })
|
|
3152
|
+
] });
|
|
3153
|
+
}
|
|
3154
|
+
function PanelsAndRows() {
|
|
3155
|
+
const [opacity, setOpacity] = useState(0.8);
|
|
3156
|
+
const [radius, setRadius] = useState(12);
|
|
3157
|
+
const [fill, setFill] = useState("#5841b8");
|
|
3158
|
+
const [alpha, setAlpha] = useState(1);
|
|
3159
|
+
const [stroke, setStroke] = useState("#2ec27e");
|
|
3160
|
+
const [count, setCount] = useState(8);
|
|
3161
|
+
const [cap, setCap] = useState("round");
|
|
3162
|
+
const [side, setSide] = useState("center");
|
|
3163
|
+
const [label, setLabel] = useState("Badge");
|
|
3164
|
+
const [visible, setVisible] = useState(true);
|
|
3165
|
+
const [prefs, setPrefs] = useState({});
|
|
3166
|
+
const [layers, setLayers] = useState([
|
|
3167
|
+
{ id: "base", label: "Base coat" },
|
|
3168
|
+
{ id: "wash", label: "Wash" }
|
|
3169
|
+
]);
|
|
3170
|
+
const [panelCollapsed, setPanelCollapsed] = useState(false);
|
|
3171
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Panels & property rows", children: [
|
|
3172
|
+
/* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(D, { title: "Shape", children: /* @__PURE__ */ jsxs(O, { children: [
|
|
3173
|
+
/* @__PURE__ */ jsx(
|
|
3174
|
+
I2,
|
|
3175
|
+
{
|
|
3176
|
+
label: "Opacity",
|
|
3177
|
+
value: opacity,
|
|
3178
|
+
min: 0,
|
|
3179
|
+
max: 1,
|
|
3180
|
+
step: 0.01,
|
|
3181
|
+
onChange: setOpacity
|
|
3182
|
+
}
|
|
3183
|
+
),
|
|
3184
|
+
/* @__PURE__ */ jsx(
|
|
3185
|
+
I2,
|
|
3186
|
+
{
|
|
3187
|
+
label: "Radius",
|
|
3188
|
+
value: radius,
|
|
3189
|
+
min: 0,
|
|
3190
|
+
max: 64,
|
|
3191
|
+
unit: "px",
|
|
3192
|
+
onChange: setRadius
|
|
3193
|
+
}
|
|
3194
|
+
),
|
|
3195
|
+
/* @__PURE__ */ jsx(
|
|
3196
|
+
z2,
|
|
3197
|
+
{
|
|
3198
|
+
label: "Fill",
|
|
3199
|
+
value: fill,
|
|
3200
|
+
onChange: setFill,
|
|
3201
|
+
alpha,
|
|
3202
|
+
onAlphaChange: setAlpha
|
|
3203
|
+
}
|
|
3204
|
+
),
|
|
3205
|
+
/* @__PURE__ */ jsx(z2, { label: "Stroke", value: stroke, onChange: setStroke }),
|
|
3206
|
+
/* @__PURE__ */ jsx(U, { label: "Count", value: count, min: 0, max: 100, step: 1, onChange: setCount }),
|
|
3207
|
+
/* @__PURE__ */ jsx(
|
|
3208
|
+
W,
|
|
3209
|
+
{
|
|
3210
|
+
label: "Line cap",
|
|
3211
|
+
value: cap,
|
|
3212
|
+
onChange: setCap,
|
|
3213
|
+
options: [
|
|
3214
|
+
{ value: "butt", label: "Butt" },
|
|
3215
|
+
{ value: "round", label: "Round" }
|
|
3216
|
+
]
|
|
3217
|
+
}
|
|
3218
|
+
),
|
|
3219
|
+
/* @__PURE__ */ jsx(
|
|
3220
|
+
G2,
|
|
3221
|
+
{
|
|
3222
|
+
label: "Align",
|
|
3223
|
+
value: side,
|
|
3224
|
+
onChange: setSide,
|
|
3225
|
+
options: [
|
|
3226
|
+
{ value: "left", label: "L" },
|
|
3227
|
+
{ value: "center", label: "C" },
|
|
3228
|
+
{ value: "right", label: "R" }
|
|
3229
|
+
]
|
|
3230
|
+
}
|
|
3231
|
+
),
|
|
3232
|
+
/* @__PURE__ */ jsx(H, { label: "Label", value: label, onChange: setLabel }),
|
|
3233
|
+
/* @__PURE__ */ jsx(B, { label: "Visible", value: visible, onChange: setVisible }),
|
|
3234
|
+
/* @__PURE__ */ jsx(X, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(I2, { label: "Rings", value: 32, min: 4, max: 96, step: 1, onChange: () => {
|
|
3235
|
+
} }) })
|
|
3236
|
+
] }) }) }),
|
|
3237
|
+
/* @__PURE__ */ jsx(Cell, { label: "PrefsForm", children: /* @__PURE__ */ jsx(
|
|
3238
|
+
A2,
|
|
3239
|
+
{
|
|
3240
|
+
schema: PREFS,
|
|
3241
|
+
values: prefs,
|
|
3242
|
+
onChange: (path, value) => setPrefs((prev) => setAt(prev, path, value))
|
|
3243
|
+
}
|
|
3244
|
+
) }),
|
|
3245
|
+
/* @__PURE__ */ jsx(Cell, { label: "LayerStack", children: /* @__PURE__ */ jsx(
|
|
3246
|
+
c4,
|
|
3247
|
+
{
|
|
3248
|
+
items: layers,
|
|
3249
|
+
onReorder: (ids) => setLayers(ids.flatMap((id) => layers.filter((item) => item.id === id))),
|
|
3250
|
+
renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
|
|
3251
|
+
"settings for ",
|
|
3252
|
+
item.label
|
|
3253
|
+
] })
|
|
3254
|
+
}
|
|
3255
|
+
) }),
|
|
3256
|
+
/* @__PURE__ */ jsx(Cell, { label: "Sidebar, SidebarPanel", children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__box", children: /* @__PURE__ */ jsx(n5, { side: "right", ariaLabel: "Specimen sidebar", children: /* @__PURE__ */ jsx(
|
|
3257
|
+
s4,
|
|
3258
|
+
{
|
|
3259
|
+
title: "Selection",
|
|
3260
|
+
collapsed: panelCollapsed,
|
|
3261
|
+
onToggleCollapse: () => setPanelCollapsed((v2) => !v2),
|
|
3262
|
+
onHide: () => {
|
|
3263
|
+
},
|
|
3264
|
+
children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "2 items selected" })
|
|
3265
|
+
}
|
|
3266
|
+
) }) }) })
|
|
3267
|
+
] });
|
|
3268
|
+
}
|
|
3269
|
+
function OverlaysAndFeedback() {
|
|
3270
|
+
const calloutAnchor = useRef(null);
|
|
3271
|
+
const [calloutOpen, setCalloutOpen] = useState(false);
|
|
3272
|
+
const [dialogOpen, setDialogOpen] = useState(false);
|
|
3273
|
+
const toasts = useMemo(() => m2(), []);
|
|
3274
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Overlays & feedback", children: [
|
|
3275
|
+
/* @__PURE__ */ jsx(Cell, { label: "Tooltip, Callout, Dialog, Toast", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
|
|
3276
|
+
/* @__PURE__ */ jsxs(c2, { children: [
|
|
3277
|
+
/* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx("button", { type: "button", children: "Hover me" }) }),
|
|
3278
|
+
/* @__PURE__ */ jsx(l, { placement: "bottom", children: "Duplicates the selected layer" })
|
|
3279
|
+
] }),
|
|
3280
|
+
/* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
|
|
3281
|
+
/* @__PURE__ */ jsx(
|
|
3282
|
+
g2,
|
|
3283
|
+
{
|
|
3284
|
+
triggerRef: calloutAnchor,
|
|
3285
|
+
isOpen: calloutOpen,
|
|
3286
|
+
onOpenChange: setCalloutOpen,
|
|
3287
|
+
tone: "info",
|
|
3288
|
+
title: "Info",
|
|
3289
|
+
children: "Neutral guidance."
|
|
3290
|
+
}
|
|
3291
|
+
),
|
|
3292
|
+
/* @__PURE__ */ jsx(a5, { onClick: () => setDialogOpen(true), children: "Dialog" }),
|
|
3293
|
+
/* @__PURE__ */ jsx(
|
|
3294
|
+
l5,
|
|
3295
|
+
{
|
|
3296
|
+
isOpen: dialogOpen,
|
|
3297
|
+
onOpenChange: setDialogOpen,
|
|
3298
|
+
title: "Preferences",
|
|
3299
|
+
footer: /* @__PURE__ */ jsx(a5, { variant: "primary", onClick: () => setDialogOpen(false), children: "OK" }),
|
|
3300
|
+
children: /* @__PURE__ */ jsx("p", { children: "Dialog body." })
|
|
3301
|
+
}
|
|
3302
|
+
),
|
|
3303
|
+
/* @__PURE__ */ jsx(
|
|
3304
|
+
a5,
|
|
3305
|
+
{
|
|
3306
|
+
onClick: () => toasts.add("success", "Saved", { description: "All changes stored.", ttlMs: null }),
|
|
3307
|
+
children: "Toast"
|
|
3308
|
+
}
|
|
3309
|
+
),
|
|
3310
|
+
/* @__PURE__ */ jsx(S4, { queue: toasts, placement: "bottom-right" })
|
|
3311
|
+
] }) }),
|
|
3312
|
+
/* @__PURE__ */ jsx(Cell, { label: "Powerline", children: /* @__PURE__ */ jsx(
|
|
3313
|
+
r9,
|
|
3314
|
+
{
|
|
3315
|
+
variant: "solid",
|
|
3316
|
+
size: "sm",
|
|
3317
|
+
segments: [
|
|
3318
|
+
{ text: "main", tone: "accent", endCap: "chevron" },
|
|
3319
|
+
{ text: "\u2713 12", tone: "info", endCap: "slant" },
|
|
3320
|
+
{ text: "~/proj", tone: "muted" }
|
|
3321
|
+
]
|
|
3322
|
+
}
|
|
3323
|
+
) }),
|
|
3324
|
+
/* @__PURE__ */ jsx(Cell, { label: "StatusBar", children: /* @__PURE__ */ jsxs(n6, { ariaLabel: "Editor status", children: [
|
|
3325
|
+
/* @__PURE__ */ jsx(r10, { children: "tool: select" }),
|
|
3326
|
+
/* @__PURE__ */ jsx(r10, { children: "sel: 3" }),
|
|
3327
|
+
/* @__PURE__ */ jsx(i5, {}),
|
|
3328
|
+
/* @__PURE__ */ jsx(r10, { muted: true, children: "0.7.0" })
|
|
3329
|
+
] }) })
|
|
3330
|
+
] });
|
|
3331
|
+
}
|
|
3332
|
+
function ListsAndData() {
|
|
3333
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Lists & data", children: [
|
|
3334
|
+
/* @__PURE__ */ jsx(Cell, { label: "ItemList", children: /* @__PURE__ */ jsx(
|
|
3335
|
+
i4,
|
|
3336
|
+
{
|
|
3337
|
+
rows: [
|
|
3338
|
+
{ id: "a", label: "Draw rect" },
|
|
3339
|
+
{ id: "b", label: "Fill", selected: true },
|
|
3340
|
+
{ id: "c", label: "Move", muted: true }
|
|
3341
|
+
],
|
|
3342
|
+
empty: "Nothing"
|
|
3343
|
+
}
|
|
3344
|
+
) }),
|
|
3345
|
+
/* @__PURE__ */ jsx(Cell, { label: "DataGrid", children: /* @__PURE__ */ jsx(
|
|
3346
|
+
s2,
|
|
3347
|
+
{
|
|
3348
|
+
rows: [
|
|
3349
|
+
{ id: "1", name: "accent", count: 3 },
|
|
3350
|
+
{ id: "2", name: "info", count: 1 },
|
|
3351
|
+
{ id: "3", name: "danger", count: 2 }
|
|
3352
|
+
],
|
|
3353
|
+
columns: [
|
|
3354
|
+
{ id: "name", header: "name", accessor: (r9) => r9.name, sortable: true },
|
|
3355
|
+
{ id: "count", header: "count", accessor: (r9) => r9.count, sortable: true }
|
|
3356
|
+
],
|
|
3357
|
+
defaultSort: { columnId: "name", direction: "asc" }
|
|
3358
|
+
}
|
|
3359
|
+
) })
|
|
3360
|
+
] });
|
|
3361
|
+
}
|
|
3362
|
+
function ToolChrome() {
|
|
3363
|
+
const [tool, setTool] = useState("select");
|
|
3364
|
+
const [paneWidth, setPaneWidth] = useState(160);
|
|
3365
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Tool chrome", children: [
|
|
3366
|
+
/* @__PURE__ */ jsx(Cell, { label: "ToolGroup, ToolButton", children: /* @__PURE__ */ jsx(n7, { orientation: "horizontal", ariaLabel: "Tools", children: ["select", "rect", "ellipse"].map((id) => /* @__PURE__ */ jsx(
|
|
3367
|
+
o4,
|
|
3368
|
+
{
|
|
3369
|
+
icon: /* @__PURE__ */ jsx(Dot, {}),
|
|
3370
|
+
label: id,
|
|
3371
|
+
shortcut: id.slice(0, 1).toUpperCase(),
|
|
3372
|
+
active: tool === id,
|
|
3373
|
+
tabbable: tool === id,
|
|
3374
|
+
onClick: () => setTool(id)
|
|
3375
|
+
},
|
|
3376
|
+
id
|
|
3377
|
+
)) }) }),
|
|
3378
|
+
/* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c5, { label: "Text", children: [
|
|
3379
|
+
/* @__PURE__ */ jsx(a5, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
|
|
3380
|
+
/* @__PURE__ */ jsx(a5, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
|
|
3381
|
+
] }) }),
|
|
3382
|
+
/* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
|
|
3383
|
+
/* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
|
|
3384
|
+
/* @__PURE__ */ jsx(
|
|
3385
|
+
c6,
|
|
3386
|
+
{
|
|
3387
|
+
value: paneWidth,
|
|
3388
|
+
min: 100,
|
|
3389
|
+
max: 220,
|
|
3390
|
+
invert: true,
|
|
3391
|
+
onInput: setPaneWidth,
|
|
3392
|
+
ariaLabel: "Resize"
|
|
3393
|
+
}
|
|
3394
|
+
),
|
|
3395
|
+
/* @__PURE__ */ jsxs(
|
|
3396
|
+
"div",
|
|
3397
|
+
{
|
|
3398
|
+
className: "lk-specimen__pane",
|
|
3399
|
+
style: { "--lk-specimen-pane-w": `${paneWidth}px` },
|
|
3400
|
+
children: [
|
|
3401
|
+
paneWidth,
|
|
3402
|
+
"px"
|
|
3403
|
+
]
|
|
3404
|
+
}
|
|
3405
|
+
)
|
|
3406
|
+
] }) })
|
|
3407
|
+
] });
|
|
3408
|
+
}
|
|
3409
|
+
function EditorsAndPlots() {
|
|
3410
|
+
const [curve, setCurve] = useState([
|
|
3411
|
+
{ x: 0, y: 0 },
|
|
3412
|
+
{ x: 0.3, y: 0.1 },
|
|
3413
|
+
{ x: 0.7, y: 0.9 },
|
|
3414
|
+
{ x: 1, y: 1 }
|
|
3415
|
+
]);
|
|
3416
|
+
const [points, setPoints] = useState([
|
|
3417
|
+
{ x: 0.2, y: 0.3 },
|
|
3418
|
+
{ x: 0.5, y: 0.6 },
|
|
3419
|
+
{ x: 0.8, y: 0.2 }
|
|
3420
|
+
]);
|
|
3421
|
+
const [bands, setBands] = useState([
|
|
3422
|
+
{ from: 1 / 64, data: { name: "Radial" } },
|
|
3423
|
+
{ from: 1 / 12, data: { name: "Name plate" } }
|
|
3424
|
+
]);
|
|
3425
|
+
const [band, setBand] = useState(null);
|
|
3426
|
+
const [tracks, setTracks] = useState(
|
|
3427
|
+
() => [
|
|
3428
|
+
{
|
|
3429
|
+
kind: "sampled",
|
|
3430
|
+
label: "x",
|
|
3431
|
+
keys: [
|
|
3432
|
+
{ t: 0, value: 0 },
|
|
3433
|
+
{ t: 800, value: 120, easing: "easeOutCubic" },
|
|
3434
|
+
{ t: 1600, value: 40 }
|
|
3435
|
+
],
|
|
3436
|
+
onTick: () => {
|
|
3437
|
+
}
|
|
3438
|
+
},
|
|
3439
|
+
{
|
|
3440
|
+
kind: "event",
|
|
3441
|
+
label: "footstep",
|
|
3442
|
+
events: [
|
|
3443
|
+
{ t: 300, fire: () => {
|
|
3444
|
+
} },
|
|
3445
|
+
{ t: 900, fire: () => {
|
|
3446
|
+
} }
|
|
3447
|
+
]
|
|
3448
|
+
}
|
|
3449
|
+
]
|
|
3450
|
+
);
|
|
3451
|
+
const [playhead, setPlayhead] = useState(0);
|
|
3452
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Editors & plots", children: [
|
|
3453
|
+
/* @__PURE__ */ jsx(Cell, { label: "Plot2D", children: /* @__PURE__ */ jsx(
|
|
3454
|
+
w2,
|
|
3455
|
+
{
|
|
3456
|
+
width: 260,
|
|
3457
|
+
height: 130,
|
|
3458
|
+
grid: { divisions: 3 },
|
|
3459
|
+
axes: {},
|
|
3460
|
+
xRange: [0, 2e3],
|
|
3461
|
+
yRange: [-0.35, 1.2]
|
|
3462
|
+
}
|
|
3463
|
+
) }),
|
|
3464
|
+
/* @__PURE__ */ jsx(Cell, { label: "CurveEditor", children: /* @__PURE__ */ jsx(
|
|
3465
|
+
L2,
|
|
3466
|
+
{
|
|
3467
|
+
value: curve,
|
|
3468
|
+
onInput: setCurve,
|
|
3469
|
+
domain: "1d",
|
|
3470
|
+
interpolation: "catmull-rom",
|
|
3471
|
+
endpoints: "pinned-both",
|
|
3472
|
+
addPointMode: "click-curve",
|
|
3473
|
+
axes: {},
|
|
3474
|
+
fill: { side: "below" },
|
|
3475
|
+
width: 260,
|
|
3476
|
+
height: 130
|
|
3477
|
+
}
|
|
3478
|
+
) }),
|
|
3479
|
+
/* @__PURE__ */ jsx(Cell, { label: "PointPlotter", children: /* @__PURE__ */ jsx(
|
|
3480
|
+
n8,
|
|
3481
|
+
{
|
|
3482
|
+
value: points,
|
|
3483
|
+
onInput: setPoints,
|
|
3484
|
+
xRange: [0, 1],
|
|
3485
|
+
yRange: [0, 1],
|
|
3486
|
+
grid: { divisions: 3 },
|
|
3487
|
+
axes: {},
|
|
3488
|
+
addPointMode: "click-empty",
|
|
3489
|
+
width: 260,
|
|
3490
|
+
height: 130
|
|
3491
|
+
}
|
|
3492
|
+
) }),
|
|
3493
|
+
/* @__PURE__ */ jsx(Cell, { label: "BandEditor", wide: true, children: /* @__PURE__ */ jsx(
|
|
3494
|
+
k3,
|
|
3495
|
+
{
|
|
3496
|
+
min: 1 / 64,
|
|
3497
|
+
max: 1 / 2,
|
|
3498
|
+
scale: "log",
|
|
3499
|
+
snap: true,
|
|
3500
|
+
value: bands,
|
|
3501
|
+
onChange: setBands,
|
|
3502
|
+
selectedIndex: band,
|
|
3503
|
+
onSelect: setBand,
|
|
3504
|
+
renderBand: (b3) => b3.data.name,
|
|
3505
|
+
ticks: [1 / 24, 1 / 12, 1 / 6].map((at) => ({ at, label: `1/${Math.round(1 / at)}` }))
|
|
3506
|
+
}
|
|
3507
|
+
) }),
|
|
3508
|
+
/* @__PURE__ */ jsx(Cell, { label: "Timeline", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__timeline", children: /* @__PURE__ */ jsx(
|
|
3509
|
+
$2,
|
|
3510
|
+
{
|
|
3511
|
+
tracks,
|
|
3512
|
+
duration: 2e3,
|
|
3513
|
+
playhead,
|
|
3514
|
+
onChange: setTracks,
|
|
3515
|
+
onScrub: setPlayhead
|
|
3516
|
+
}
|
|
3517
|
+
) }) })
|
|
3518
|
+
] });
|
|
3519
|
+
}
|
|
3520
|
+
function LabChrome() {
|
|
3521
|
+
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
3522
|
+
const [zoom, setZoom] = useState(1);
|
|
3523
|
+
return /* @__PURE__ */ jsxs(Section, { title: "Lab chrome", children: [
|
|
3524
|
+
/* @__PURE__ */ jsx(Cell, { label: "Toolbar", wide: true, children: /* @__PURE__ */ jsxs(Toolbar, { "aria-label": "Trial actions", children: [
|
|
3525
|
+
/* @__PURE__ */ jsx(Toolbar.Title, { children: "My Trial" }),
|
|
3526
|
+
/* @__PURE__ */ jsxs(Toolbar.Group, { children: [
|
|
3527
|
+
/* @__PURE__ */ jsx(Toolbar.Button, { onClick: () => {
|
|
3528
|
+
}, children: "Undo" }),
|
|
3529
|
+
/* @__PURE__ */ jsx(Toolbar.Button, { onClick: () => {
|
|
3530
|
+
}, disabled: true, children: "Redo" })
|
|
3531
|
+
] }),
|
|
3532
|
+
/* @__PURE__ */ jsx(Toolbar.Group, { end: true, children: /* @__PURE__ */ jsx(Toolbar.Button, { onClick: () => {
|
|
3533
|
+
}, children: "Save" }) })
|
|
3534
|
+
] }) }),
|
|
3535
|
+
/* @__PURE__ */ jsx(Cell, { label: "StatusBar", children: /* @__PURE__ */ jsxs(StatusBar, { children: [
|
|
3536
|
+
/* @__PURE__ */ jsx(StatusBar.Section, { children: "Items: 12" }),
|
|
3537
|
+
/* @__PURE__ */ jsx(StatusBar.Section, { children: "Zoom: 100%" })
|
|
3538
|
+
] }) }),
|
|
3539
|
+
/* @__PURE__ */ jsx(Cell, { label: "Sidebar", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
|
|
3540
|
+
/* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "main" }),
|
|
3541
|
+
/* @__PURE__ */ jsx(
|
|
3542
|
+
Sidebar,
|
|
3543
|
+
{
|
|
3544
|
+
title: "Controls",
|
|
3545
|
+
collapsed: sidebarCollapsed,
|
|
3546
|
+
onToggle: () => setSidebarCollapsed((v2) => !v2),
|
|
3547
|
+
children: /* @__PURE__ */ jsx("p", { children: "One slider" })
|
|
3548
|
+
}
|
|
3549
|
+
)
|
|
3550
|
+
] }) }),
|
|
3551
|
+
/* @__PURE__ */ jsxs(Cell, { label: "Legend, JobProgress", children: [
|
|
3552
|
+
/* @__PURE__ */ jsx(Legend, { entries: LEGEND }),
|
|
3553
|
+
/* @__PURE__ */ jsx(JobProgress, { job: JOB })
|
|
3554
|
+
] }),
|
|
3555
|
+
/* @__PURE__ */ jsxs(Cell, { label: "ScaleIndicator, ZoomControl", children: [
|
|
3556
|
+
/* @__PURE__ */ jsx(ScaleIndicator, { zoom, unit: "ft", pixelsPerUnit: 50 }),
|
|
3557
|
+
/* @__PURE__ */ jsx(ZoomControl, { zoom, onZoomChange: setZoom, min: 0.1, max: 8 })
|
|
3558
|
+
] }),
|
|
3559
|
+
/* @__PURE__ */ jsx(Cell, { label: "FloatingPanel", children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__floating-host", children: /* @__PURE__ */ jsx(FloatingPanel, { anchor: "top-right", children: /* @__PURE__ */ jsx(Legend, { entries: LEGEND.slice(0, 2) }) }) }) }),
|
|
3560
|
+
/* @__PURE__ */ jsx(Cell, { label: "Split", wide: true, children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__box", children: /* @__PURE__ */ jsx(
|
|
3561
|
+
Split,
|
|
3562
|
+
{
|
|
3563
|
+
sidebar: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "sidebar" }),
|
|
3564
|
+
defaultWidth: 160,
|
|
3565
|
+
minWidth: 100,
|
|
3566
|
+
maxWidth: 260,
|
|
3567
|
+
children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "content" })
|
|
3568
|
+
}
|
|
3569
|
+
) }) })
|
|
3570
|
+
] });
|
|
3571
|
+
}
|
|
3572
|
+
function Specimen({ className }) {
|
|
3573
|
+
return /* @__PURE__ */ jsxs("div", { className: className ? `lk-specimen ${className}` : "lk-specimen", "data-wzl-portal-host": "", children: [
|
|
3574
|
+
/* @__PURE__ */ jsx(ButtonsAndToggles, {}),
|
|
3575
|
+
/* @__PURE__ */ jsx(FieldsAndPickers, {}),
|
|
3576
|
+
/* @__PURE__ */ jsx(PanelsAndRows, {}),
|
|
3577
|
+
/* @__PURE__ */ jsx(OverlaysAndFeedback, {}),
|
|
3578
|
+
/* @__PURE__ */ jsx(ListsAndData, {}),
|
|
3579
|
+
/* @__PURE__ */ jsx(ToolChrome, {}),
|
|
3580
|
+
/* @__PURE__ */ jsx(EditorsAndPlots, {}),
|
|
3581
|
+
/* @__PURE__ */ jsx(LabChrome, {})
|
|
3582
|
+
] });
|
|
3583
|
+
}
|
|
3915
3584
|
|
|
3916
|
-
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationOverlay, AnnotationTargets, Lab, LabPalette, LabShell, LabSwitcher, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationToolInfo, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fracContains, fracEncloses, fracToWorld, fromWeaselView, interstellarTheme, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveMarkStyle, roundFrac, seenFrom, toWeaselView, validateConfigSchema, worldToFrac };
|
|
3585
|
+
export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationOverlay, AnnotationTargets, Lab, LabPalette, LabRoot, LabShell, LabSwitcher, SPECIMEN_SECTIONS, Specimen, Trial, TrialBody, TrialChrome, Workspace, addTrial, annotationToolInfo, annotationsFromJSON, capturePlan, captureTarget, cloneTrial, closeTrial, composeCaptureSvg, createAnnotationScene, createAnnotationStore, createMarkDrawOne, currentPage, defineInstrument, fitView, fracContains, fracEncloses, fracToWorld, fromWeaselView, interstellarTheme, isStale, markCommands, markSvgNodes, reorderTrials, resetTrial, resolveMarkStyle, roundFrac, seenFrom, toWeaselView, validateConfigSchema, worldToFrac };
|
|
3917
3586
|
//# sourceMappingURL=index.js.map
|
|
3918
3587
|
//# sourceMappingURL=index.js.map
|