@weasel-js/labkit 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +3 -7
  2. package/dist/_dts/{CanvasStackContext-CJNMS6mz.d.ts → CanvasStackContext-DQgcH1ny.d.ts} +1 -1
  3. package/dist/_dts/LayerList.d-2c9yup5Y.d.ts +83 -0
  4. package/dist/_dts/{PrefsForm.d-DPy9I8It.d.ts → PrefsRow.d-DFpPIeIC.d.ts} +16 -1
  5. package/dist/_dts/{Select.d-Gwr8fLpK.d.ts → Select.d-BchGMC2Y.d.ts} +129 -12
  6. package/dist/_dts/{frac-B4okC2lX.d.ts → frac-DTRq7Xpb.d.ts} +31 -13
  7. package/dist/_dts/inDialog-D5ZKGjiD.d.ts +23 -0
  8. package/dist/_dts/{index-CSJoj4LC.d.ts → index-B0--8PEM.d.ts} +5 -4
  9. package/dist/_dts/index-DINmCuLA.d.ts +453 -0
  10. package/dist/_dts/number.d-OeQYQoUO.d.ts +28 -0
  11. package/dist/_dts/{types-DzoNY1pO.d.ts → types-B7y8hX1D.d.ts} +6 -6
  12. package/dist/_dts/{usePanZoom-Pzf9f2jh.d.ts → usePanZoom-Bq73pwFe.d.ts} +4 -47
  13. package/dist/_dts/{useTrialState-uLlmaccn.d.ts → useTrialState-CP4jfuKl.d.ts} +1 -1
  14. package/dist/canvas/index.d.ts +6 -5
  15. package/dist/canvas/index.js +1 -1
  16. package/dist/chrome/index.d.ts +5 -4
  17. package/dist/chrome/index.js +7 -7
  18. package/dist/chunk-2RVCB2PT.js +3 -0
  19. package/dist/chunk-2RVCB2PT.js.map +1 -0
  20. package/dist/{chunk-UN4U4P63.js → chunk-3FI7Y4R4.js} +9 -9
  21. package/dist/chunk-3FI7Y4R4.js.map +1 -0
  22. package/dist/{chunk-7PFH3CNM.js → chunk-AWH3SRPW.js} +31 -5
  23. package/dist/chunk-AWH3SRPW.js.map +1 -0
  24. package/dist/{chunk-ZDHY47EV.js → chunk-BVL7Y574.js} +25 -9
  25. package/dist/chunk-BVL7Y574.js.map +1 -0
  26. package/dist/{chunk-IHUVQ3TX.js → chunk-H5VIV7MQ.js} +31 -27
  27. package/dist/chunk-H5VIV7MQ.js.map +1 -0
  28. package/dist/chunk-HFRE4QQV.js +400 -0
  29. package/dist/chunk-HFRE4QQV.js.map +1 -0
  30. package/dist/{chunk-IXTQI7JX.js → chunk-MOLIUNVH.js} +4 -4
  31. package/dist/{chunk-IXTQI7JX.js.map → chunk-MOLIUNVH.js.map} +1 -1
  32. package/dist/{chunk-CEIUBPPW.js → chunk-TT5C5S6R.js} +3 -86
  33. package/dist/chunk-TT5C5S6R.js.map +1 -0
  34. package/dist/chunk-USO6TERP.js +90 -0
  35. package/dist/chunk-USO6TERP.js.map +1 -0
  36. package/dist/{chunk-PHK4W562.js → chunk-VQ47KWD5.js} +3 -3
  37. package/dist/{chunk-PHK4W562.js.map → chunk-VQ47KWD5.js.map} +1 -1
  38. package/dist/chunk-WUJXJC5O.js +14568 -0
  39. package/dist/chunk-WUJXJC5O.js.map +1 -0
  40. package/dist/{chunk-EHGVROVV.js → chunk-ZORVNOKX.js} +6 -25
  41. package/dist/chunk-ZORVNOKX.js.map +1 -0
  42. package/dist/config/index.d.ts +53 -11
  43. package/dist/config/index.js +5 -5
  44. package/dist/controls/index.d.ts +6 -3
  45. package/dist/controls/index.js +4 -4
  46. package/dist/dragdrop/index.d.ts +4 -3
  47. package/dist/index.d.ts +139 -114
  48. package/dist/index.js +470 -479
  49. package/dist/index.js.map +1 -1
  50. package/dist/layers/index.d.ts +6 -35
  51. package/dist/layers/index.js +2 -3
  52. package/dist/loupe/index.d.ts +6 -5
  53. package/dist/passthrough/weasel-ui.d.ts +421 -215
  54. package/dist/passthrough/weasel-ui.js +1 -1
  55. package/dist/primitives/index.d.ts +2 -13
  56. package/dist/primitives/index.js +4 -4
  57. package/dist/state/index.d.ts +6 -5
  58. package/dist/state/index.js +5 -5
  59. package/dist/styles.css +410 -190
  60. package/dist/undo/index.d.ts +4 -3
  61. package/package.json +9 -13
  62. package/src/annotations/frac.test.ts +7 -0
  63. package/src/annotations/paint.test.ts +21 -0
  64. package/src/annotations/paint.ts +12 -0
  65. package/src/annotations/store.test.ts +31 -0
  66. package/src/annotations/types.ts +3 -2
  67. package/src/canvas/Stage.test.tsx +18 -0
  68. package/src/canvas/index.ts +0 -9
  69. package/src/chrome/labTypes.ts +1 -1
  70. package/src/chrome/regions/PaletteRegion.test.tsx +18 -0
  71. package/src/chrome/regions/PaletteRegion.tsx +5 -4
  72. package/src/chrome/regions/SidebarRegion.less +197 -0
  73. package/src/chrome/regions/SidebarRegion.test.tsx +20 -0
  74. package/src/chrome/regions/SidebarRegion.tsx +7 -2
  75. package/src/chrome/regions/TitleBarRegion.tsx +1 -1
  76. package/src/chrome/types.ts +13 -4
  77. package/src/config/autoConfig.ts +2 -2
  78. package/src/config/builder.ts +23 -5
  79. package/src/config/entry.test.ts +8 -0
  80. package/src/config/index.ts +2 -0
  81. package/src/config/rules.ts +2 -0
  82. package/src/config/sectionTree.test.ts +146 -0
  83. package/src/config/sectionTree.ts +124 -0
  84. package/src/config/types.ts +4 -4
  85. package/src/controls/AutoControls.stories.tsx +6 -6
  86. package/src/controls/ControlPanel.less +27 -0
  87. package/src/controls/ControlPanel.stories.tsx +95 -1
  88. package/src/controls/ControlPanel.test.tsx +82 -112
  89. package/src/controls/ControlPanel.tsx +159 -396
  90. package/src/controls/inDialog.test.tsx +82 -0
  91. package/src/controls/inDialog.tsx +46 -0
  92. package/src/controls/index.ts +1 -0
  93. package/src/index.test.ts +0 -2
  94. package/src/index.ts +14 -35
  95. package/src/instrument/types.ts +5 -2
  96. package/src/lab/Lab.nebula.test.tsx +31 -0
  97. package/src/lab/Lab.tsx +57 -18
  98. package/src/lab/LabBoundary.test.tsx +66 -0
  99. package/src/lab/LabBoundary.tsx +56 -0
  100. package/src/lab/LabHeader.tsx +4 -23
  101. package/src/lab/LabRoot.tsx +2 -3
  102. package/src/lab/LabShell.less +0 -1
  103. package/src/lab/LabShell.stories.tsx +15 -0
  104. package/src/lab/LabShell.test.tsx +18 -0
  105. package/src/lab/LabShell.tsx +14 -1
  106. package/src/lab/LabSwitcher.less +1 -1
  107. package/src/lab/LabSwitcher.test.tsx +41 -0
  108. package/src/lab/LabSwitcher.tsx +30 -8
  109. package/src/lab/index.ts +1 -0
  110. package/src/layers/AGENTS.md +18 -74
  111. package/src/layers/index.ts +4 -2
  112. package/src/passthrough/weasel-ui.ts +25 -10
  113. package/src/primitives/FpsMeter.less +6 -1
  114. package/src/primitives/FpsMeter.test.tsx +12 -4
  115. package/src/primitives/FpsMeter.tsx +6 -1
  116. package/src/primitives/JobProgress.stories.tsx +1 -1
  117. package/src/primitives/StatusBar.less +6 -0
  118. package/src/primitives/index.ts +0 -2
  119. package/src/specimen/Specimen.tsx +42 -56
  120. package/src/state/types.ts +8 -2
  121. package/src/state/view.test.ts +4 -4
  122. package/src/styles.less +4 -2
  123. package/src/theme/Interstellar.stories.tsx +8 -9
  124. package/src/theme/base.less +3 -20
  125. package/src/theme/interstellar.test.ts +6 -3
  126. package/src/theme/interstellar.theme.json +0 -56
  127. package/src/theme/interstellar.ts +2 -2
  128. package/src/trial/Trial.canvas.test.tsx +9 -5
  129. package/src/trial/Trial.config.test.tsx +1 -1
  130. package/src/trial/Trial.tsx +30 -8
  131. package/dist/_dts/index-BNdz-tNd.d.ts +0 -423
  132. package/dist/chunk-7PFH3CNM.js.map +0 -1
  133. package/dist/chunk-CEIUBPPW.js.map +0 -1
  134. package/dist/chunk-EH7UEQV7.js +0 -590
  135. package/dist/chunk-EH7UEQV7.js.map +0 -1
  136. package/dist/chunk-EHGVROVV.js.map +0 -1
  137. package/dist/chunk-IHUVQ3TX.js.map +0 -1
  138. package/dist/chunk-MDVTK5U3.js +0 -170
  139. package/dist/chunk-MDVTK5U3.js.map +0 -1
  140. package/dist/chunk-PJ7WEQBJ.js +0 -18
  141. package/dist/chunk-PJ7WEQBJ.js.map +0 -1
  142. package/dist/chunk-T3EC2DXD.js +0 -12628
  143. package/dist/chunk-T3EC2DXD.js.map +0 -1
  144. package/dist/chunk-UN4U4P63.js.map +0 -1
  145. package/dist/chunk-ZDHY47EV.js.map +0 -1
  146. package/dist/ui/layers/index.d.ts +0 -66
  147. package/dist/ui/layers/index.js +0 -3
  148. package/dist/ui/layers/index.js.map +0 -1
  149. package/src/canvas/useOrbit.test.ts +0 -167
  150. package/src/canvas/useOrbit.ts +0 -156
  151. package/src/lab/useSystemMode.ts +0 -30
  152. package/src/layers/LayerList.less +0 -93
  153. package/src/layers/LayerList.stories.tsx +0 -66
  154. package/src/layers/LayerList.test.tsx +0 -232
  155. package/src/layers/LayerList.tsx +0 -268
  156. package/src/primitives/Sidebar.less +0 -112
  157. package/src/primitives/Sidebar.stories.tsx +0 -38
  158. package/src/primitives/Sidebar.test.tsx +0 -74
  159. package/src/primitives/Sidebar.tsx +0 -35
  160. package/src/ui/layers/index.ts +0 -5
package/dist/index.js CHANGED
@@ -7,48 +7,48 @@ import { useTiledSurface } from './chunk-IJJUK4FU.js';
7
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, LabAsideRegion, LabSidebarRegion } from './chunk-IHUVQ3TX.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-IHUVQ3TX.js';
12
- import { Split, JobProgress, Sidebar, Legend, FloatingPanel } from './chunk-EHGVROVV.js';
13
- export { FloatingPanel, JobProgress, Legend, Sidebar, Split } from './chunk-EHGVROVV.js';
14
- import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-UN4U4P63.js';
15
- export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-UN4U4P63.js';
16
- import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-IXTQI7JX.js';
17
- export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-IXTQI7JX.js';
10
+ import { suppressContributions, mergeContributions, builtinContributions, TitleBarRegion, ToolbarRegion, PaletteRegion, ViewportRegion, SidebarRegion, StatusRegion, resolveLabTool, AnnotationsContext, useLabChromeContext, labContributions, LabHeaderRegion, LabFooterRegion, LabAsideRegion, LabSidebarRegion } from './chunk-H5VIV7MQ.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-H5VIV7MQ.js';
12
+ import { Split, JobProgress, Legend, FloatingPanel } from './chunk-ZORVNOKX.js';
13
+ export { FloatingPanel, JobProgress, Legend, Split } from './chunk-ZORVNOKX.js';
14
+ import { Toolbar, StatusBar, ScaleIndicator, ZoomControl } from './chunk-3FI7Y4R4.js';
15
+ export { FpsMeter, ScaleIndicator, StatusBar, Toolbar, ZoomControl } from './chunk-3FI7Y4R4.js';
16
+ import './chunk-SBXNQW4G.js';
17
+ import { unruledConfigSchema, createLabStore, openLabStore, panelKey } from './chunk-MOLIUNVH.js';
18
+ export { CURRENT_DOCUMENT_VERSION, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, useTrialState } from './chunk-MOLIUNVH.js';
18
19
  import { newId, useWarnIgnoredChange, useOpenOnce, PersistenceContext, createRecordCache, noneAdapter, defaultStorage, usePersistedState } from './chunk-RWNDDKOH.js';
19
20
  export { Persistence, createIndexedDbAdapter, createMemoryAdapter, indexedDbAdapter, localStorageAdapter, noneAdapter, sessionStorageAdapter, urlHashAdapter, usePersistedState } from './chunk-RWNDDKOH.js';
20
- export { ControlPanel } from './chunk-EH7UEQV7.js';
21
- import { useConfigSchema } from './chunk-PJ7WEQBJ.js';
22
- export { useConfigSchema } from './chunk-PJ7WEQBJ.js';
21
+ export { ControlPanel } from './chunk-HFRE4QQV.js';
22
+ import { useConfigSchema } from './chunk-USO6TERP.js';
23
+ export { sectionTree, useConfigSchema } from './chunk-USO6TERP.js';
23
24
  import { useLabContext, LabContext } from './chunk-Z76KEZAX.js';
24
25
  export { LabContext, useLabContext } from './chunk-Z76KEZAX.js';
25
- import { useResolvedConfig } from './chunk-ZDHY47EV.js';
26
- export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-ZDHY47EV.js';
27
- export { fromConfigFields, isLeafVisible } from './chunk-PHK4W562.js';
28
- import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-7PFH3CNM.js';
29
- export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath } from './chunk-7PFH3CNM.js';
30
- import { CameraWheelContext, as2DView, DEFAULT_VIEW, CanvasStack, Stage, withZoom, fitStage } from './chunk-CEIUBPPW.js';
31
- export { CanvasStack, DEFAULT_VIEW, PITCH_LIMIT, Stage, as2DView, clampPitch, fitStage, orbitAfterDrag, orbitAfterWheel, useOrbit, usePanZoom, wrapYaw } from './chunk-CEIUBPPW.js';
26
+ import { useResolvedConfig } from './chunk-BVL7Y574.js';
27
+ export { BaseNode, BooleanNode, ColorNode, CustomNode, EnumNode, GroupNode, ListNode, NumberNode, StringNode, ValueNode, applyRules, builtinRules, f, isConfigBranch, resolveConfigSchema, titleCase, useResolvedConfig } from './chunk-BVL7Y574.js';
28
+ export { fromConfigFields, isLeafVisible } from './chunk-VQ47KWD5.js';
29
+ import { hasConfigPath, schemaNodeAtPath, applyConfigWrite, resolveAutoConfig, isAuto, isRecord, autoPathsOf, fillConfigDefaults } from './chunk-AWH3SRPW.js';
30
+ export { auto, autoPathsOf, fillConfigDefaults, hasConfigPath, inDialog, isAuto, resolveAutoConfig, schemaNodeAtPath, summarizeValue, valueAtPath, withValueAtPath } from './chunk-AWH3SRPW.js';
31
+ import { CameraWheelContext, as2DView, DEFAULT_VIEW, CanvasStack, Stage, withZoom, fitStage } from './chunk-TT5C5S6R.js';
32
+ export { CanvasStack, DEFAULT_VIEW, Stage, as2DView, fitStage, usePanZoom } from './chunk-TT5C5S6R.js';
32
33
  export { centerOn, zoomAt } from './chunk-H6ZAOWNE.js';
33
34
  import { applyCamera } from './chunk-2AYGEN57.js';
34
35
  export { DEFAULT_FRAME, applyCamera, resolveFrame, screenToWorld, worldToScreen } from './chunk-2AYGEN57.js';
35
36
  import { useSurfaceOptional, useSurfaceCanvas, useTileId, SurfaceContext, SurfaceCanvasContext } from './chunk-WIG6XHJ7.js';
36
37
  export { SurfaceCanvasContext, SurfaceContext, useSurface, useSurfaceCanvas, useSurfaceOptional, useSurfaceTile, useTileId } from './chunk-WIG6XHJ7.js';
38
+ import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
37
39
  export { CanvasStackContext } from './chunk-CQLQPQ4P.js';
38
- import { LabStoreContext, TrialIdProvider } from './chunk-2YILQ7Y5.js';
40
+ import { LabStoreContext, TrialIdProvider, TrialIdContext } from './chunk-2YILQ7Y5.js';
39
41
  export { LabStoreContext, LabStoreProvider, TrialIdContext, TrialIdProvider, useLabStore, useTrialId } from './chunk-2YILQ7Y5.js';
40
- import { LayerList } from './chunk-MDVTK5U3.js';
41
- export { LayerList } from './chunk-MDVTK5U3.js';
42
- import './chunk-SBXNQW4G.js';
43
- import { E, w, T, a2, p, u, c, n, f, r, h, serializeSvg, C, l7, r3, a5, Lt, o2, a4, l3, u3, r7, r8, r6, o5, s5, c6, l6, c3, s3, u2, g2, g, y2, l4, b2, c7, r2, l2, C2, S, O, k, F2, L3, V, H, U, B, R2, J, A2, c4, n5, s4, m2, c2, l, g3, l5, S4, r10, n6, r11, i5, i4, s2, n7, o4, r9, c5, w2, L2, n8, k2, $2 } from './chunk-T3EC2DXD.js';
44
- export { a5 as Button, R2 as CheckboxRow, y as CloseIcon, $ as CollapseIcon, L3 as ColorRow, S2 as CurveField, G2 as EffectCard, q as EffectCardList, te as ExpandIcon, o as Icon, u2 as Input, l9 as Jog, c4 as LayerStack, V as NumberRow, I as PauseIcon, F as PlayIcon, J as PropertyGroup, k as PropertyList, O as PropertyPanel, j2 as PropertyRow, A3 as PropertySpan, v as ResetIcon, g as Select, H as SelectRow, F2 as SliderRow, R as StepBackIcon, z as StepForwardIcon, L as StopIcon, W as Subpanel, B as TextRow, r3 as ToggleBar, U as ToggleRow, q2 as TokenPanel, I2 as inferTokenType } from './chunk-T3EC2DXD.js';
45
- import { textCommand, linePath, markerDrawCommands, ellipsePath, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
42
+ import './chunk-2RVCB2PT.js';
43
+ import { y, I, A, T, i2, P, m, H, serializeSvg, D, S2, oe, d2, s3, c, Ht, o2, a6, l5, u5, a5, r3, a7, i3, o4, s6, c5, l7, p, f2, u4, g, T2, y2, l8, b, c6, i4, l4, C, S, ae, oe2, B, b2, A2, n6, s5, m4, l2, u, g2, u3, S4, r4, n7, r5, i5, p2, f, n8, o3, c3, c4, w, L, n9, k, $2 } from './chunk-WUJXJC5O.js';
44
+ export { c as Button, re as CloseIcon, Pe as CollapseIcon, _ as CurveField, Fe as ExpandIcon, l as Icon, u4 as Input, l9 as Jog, D as LayerList, ge as PauseIcon, he as PlayIcon, V as PropertyControl, B as PropertyField, b2 as PropertyGroup, oe2 as PropertyList, ae as PropertyPanel, L3 as PropertyRow, se as PropertySpan, Z as ResetIcon, T2 as Select, ve as StepBackIcon, $ as StepForwardIcon, _e as StopIcon, x as Subpanel, a5 as ToggleBar, oe3 as TokenPanel, H2 as inferTokenType, S2 as moveLayers, O as refitScale } from './chunk-WUJXJC5O.js';
45
+ import { textCommand, ellipsePath, linePath, markerDrawCommands, rectPath, createScene, asNodeId as asNodeId$1, WeaselProvider, SceneCanvas, sceneFromJSON, PathBuilder, renderSceneToPixels, useActiveToolContext } from '@weasel-js/core';
46
46
  import { createContext, useState, useRef, useEffect, useCallback, useContext, useMemo, useId, Children, useLayoutEffect, useSyncExternalStore } from 'react';
47
47
  import { flushSync, createPortal } from 'react-dom';
48
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
49
- import { useThemeOptional, ThemeProvider } from '@weasel-js/theme/react';
48
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
49
+ import { defineTheme, weaselTheme, colorCount, resolveTheme, colorAt } from '@weasel-js/theme';
50
+ import { useResolvedColorMode, useThemeOptional, ThemeProvider, ThemeContext } from '@weasel-js/theme/react';
50
51
  import { useStore } from 'zustand/react';
51
- import { defineTheme, weaselTheme } from '@weasel-js/theme';
52
52
  import { Provider, StrategyRegistryProvider, DragProvider, Container, useDragHandle } from 'windease/react';
53
53
  import { asNodeId, Store, createNode, floatingStrategy, gridStrategy } from 'windease';
54
54
  import { Focusable } from 'react-aria-components';
@@ -56,28 +56,29 @@ import { Focusable } from 'react-aria-components';
56
56
  var MARK_COLOR = "#e5484d";
57
57
  var MARK_WIDTH = 2;
58
58
  var TEXT_SIZE = 14;
59
- var toWorld = (p2, content) => ({
60
- x: p2.x * content.w,
61
- y: p2.y * content.h
59
+ var POINT_RADIUS = 4;
60
+ var toWorld = (p3, content) => ({
61
+ x: p3.x * content.w,
62
+ y: p3.y * content.h
62
63
  });
63
- function vertices(m2, content) {
64
- const stored = m2.data.points;
65
- if (stored && stored.length >= 2) return stored.map((p2) => toWorld(p2, content));
66
- const { x, y: y3, width, height } = m2.pose;
64
+ function vertices(m3, content) {
65
+ const stored = m3.data.points;
66
+ if (stored && stored.length >= 2) return stored.map((p3) => toWorld(p3, content));
67
+ const { x: x2, y: y3, width, height } = m3.pose;
67
68
  return [
68
- { x, y: y3 },
69
- { x: x + width, y: y3 + height }
69
+ { x: x2, y: y3 },
70
+ { x: x2 + width, y: y3 + height }
70
71
  ];
71
72
  }
72
73
  function polyline(points) {
73
- const b2 = new PathBuilder();
74
+ const b3 = new PathBuilder();
74
75
  const first = points[0];
75
76
  if (!first) return rectPath(0, 0, 0, 0);
76
- b2.moveTo(first.x, first.y);
77
- for (const p2 of points.slice(1)) b2.lineTo(p2.x, p2.y);
78
- return b2.build();
77
+ b3.moveTo(first.x, first.y);
78
+ for (const p3 of points.slice(1)) b3.lineTo(p3.x, p3.y);
79
+ return b3.build();
79
80
  }
80
- function markCommands(m2, content, style = {}) {
81
+ function markCommands(m3, content, style = {}) {
81
82
  const color = style.color ?? MARK_COLOR;
82
83
  const stroke = {
83
84
  paint: { color },
@@ -86,35 +87,46 @@ function markCommands(m2, content, style = {}) {
86
87
  join: "round",
87
88
  ...style.stale ? { dash: [6, 4] } : {}
88
89
  };
89
- switch (m2.data.kind) {
90
+ switch (m3.data.kind) {
90
91
  case "rect":
91
92
  return [
92
- { kind: "path", path: rectPath(m2.pose.x, m2.pose.y, m2.pose.width, m2.pose.height), stroke }
93
+ { kind: "path", path: rectPath(m3.pose.x, m3.pose.y, m3.pose.width, m3.pose.height), stroke }
93
94
  ];
94
95
  case "ellipse":
95
- return [{ kind: "path", path: ellipsePath(m2.pose), stroke }];
96
+ return [{ kind: "path", path: ellipsePath(m3.pose), stroke }];
96
97
  case "line": {
97
- const [a4, b2] = vertices(m2, content);
98
- return [{ kind: "path", path: linePath(a4, b2), stroke }];
98
+ const [a4, b3] = vertices(m3, content);
99
+ return [{ kind: "path", path: linePath(a4, b3), stroke }];
99
100
  }
100
101
  case "arrow": {
101
- const [a4, b2] = vertices(m2, content);
102
+ const [a4, b3] = vertices(m3, content);
102
103
  const marked = { ...stroke, markerEnd: "arrow" };
103
- const path = linePath(a4, b2);
104
+ const path = linePath(a4, b3);
104
105
  return [
105
106
  { kind: "path", path, stroke: marked },
106
107
  ...markerDrawCommands(path, marked, MARK_WIDTH, void 0)
107
108
  ];
108
109
  }
109
110
  case "stroke":
110
- return [{ kind: "path", path: polyline(vertices(m2, content)), stroke }];
111
+ return [{ kind: "path", path: polyline(vertices(m3, content)), stroke }];
112
+ case "point": {
113
+ const stored = m3.data.points?.[0];
114
+ const c6 = stored ? toWorld(stored, content) : { x: m3.pose.x, y: m3.pose.y };
115
+ const ring = {
116
+ x: c6.x - POINT_RADIUS,
117
+ y: c6.y - POINT_RADIUS,
118
+ width: 2 * POINT_RADIUS,
119
+ height: 2 * POINT_RADIUS
120
+ };
121
+ return [{ kind: "path", path: ellipsePath(ring), stroke }];
122
+ }
111
123
  case "text": {
112
- const text = m2.data.title;
124
+ const text = m3.data.title;
113
125
  if (!text) return [];
114
126
  return [
115
127
  textCommand(
116
- m2.pose.x,
117
- m2.pose.y,
128
+ m3.pose.x,
129
+ m3.pose.y,
118
130
  text,
119
131
  { fontSize: TEXT_SIZE },
120
132
  void 0,
@@ -134,8 +146,8 @@ function seenFrom(config, keys) {
134
146
  const out = {};
135
147
  if (config === null || typeof config !== "object") return out;
136
148
  const src = config;
137
- for (const k3 of keys) {
138
- if (k3 in src) out[k3] = src[k3];
149
+ for (const k2 of keys) {
150
+ if (k2 in src) out[k2] = src[k2];
139
151
  }
140
152
  return out;
141
153
  }
@@ -143,9 +155,9 @@ function isStale(seen, config, keys) {
143
155
  if (!seen || keys.length === 0) return false;
144
156
  if (config === null || typeof config !== "object") return false;
145
157
  const src = config;
146
- for (const k3 of keys) {
147
- if (!(k3 in seen)) continue;
148
- if (!Object.is(seen[k3], src[k3])) return true;
158
+ for (const k2 of keys) {
159
+ if (!(k2 in seen)) continue;
160
+ if (!Object.is(seen[k2], src[k2])) return true;
149
161
  }
150
162
  return false;
151
163
  }
@@ -156,7 +168,7 @@ function createMarkDrawOne(opts) {
156
168
  }
157
169
  function resolveMarkStyle(data, opts) {
158
170
  return {
159
- color: opts.meaning?.statuses?.find((s5) => s5.id === data.status)?.color,
171
+ color: opts.meaning?.statuses?.find((s4) => s4.id === data.status)?.color,
160
172
  // Read off the node rather than through the store's `isStale`, which
161
173
  // wants a projected Annotation this path does not have.
162
174
  stale: isStale(data.seen, opts.config, opts.positionDependsOn ?? [])
@@ -187,7 +199,7 @@ function toSvgStroke(stroke) {
187
199
  ...stroke.align ? { align: stroke.align } : {}
188
200
  };
189
201
  }
190
- function toSvgNode(cmd, m2) {
202
+ function toSvgNode(cmd, m3) {
191
203
  if (cmd.kind === "path") {
192
204
  return {
193
205
  kind: "path",
@@ -201,8 +213,8 @@ function toSvgNode(cmd, m2) {
201
213
  kind: "text",
202
214
  x: cmd.x,
203
215
  y: cmd.y,
204
- width: m2.pose.width,
205
- height: m2.pose.height,
216
+ width: m3.pose.width,
217
+ height: m3.pose.height,
206
218
  text: cmd.runs.map((run) => run.text).join(""),
207
219
  style: cmd.style,
208
220
  ...cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}
@@ -210,8 +222,8 @@ function toSvgNode(cmd, m2) {
210
222
  }
211
223
  throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);
212
224
  }
213
- function markSvgNodes(m2, content, style = {}) {
214
- return markCommands(m2, content, style).map((cmd) => toSvgNode(cmd, m2));
225
+ function markSvgNodes(m3, content, style = {}) {
226
+ return markCommands(m3, content, style).map((cmd) => toSvgNode(cmd, m3));
215
227
  }
216
228
 
217
229
  // src/annotations/capture.ts
@@ -220,7 +232,7 @@ function capturePlan(base, format) {
220
232
  if (format === "svg") return "svg-document";
221
233
  return base?.kind === "svg" ? "svg-document" : "raster-stack";
222
234
  }
223
- function nestBaseSvg(markup, w3, h2) {
235
+ function nestBaseSvg(markup, w2, h) {
224
236
  const doc = new DOMParser().parseFromString(markup, "image/svg+xml");
225
237
  const root = doc.documentElement;
226
238
  if (doc.getElementsByTagName("parsererror").length > 0 || root.localName !== "svg") {
@@ -228,17 +240,17 @@ function nestBaseSvg(markup, w3, h2) {
228
240
  }
229
241
  root.setAttribute("x", "0");
230
242
  root.setAttribute("y", "0");
231
- root.setAttribute("width", String(w3));
232
- root.setAttribute("height", String(h2));
243
+ root.setAttribute("width", String(w2));
244
+ root.setAttribute("height", String(h));
233
245
  return new XMLSerializer().serializeToString(root);
234
246
  }
235
- function embedRasterBase(base, w3, h2, onWarn) {
247
+ function embedRasterBase(base, w2, h, onWarn) {
236
248
  const href = base.kind === "canvas" ? base.canvas.toDataURL() : base.kind === "image" ? base.src : "";
237
249
  if (base.kind === "image" && !href.startsWith("data:")) {
238
250
  onWarn?.(`base image '${href}' is a reference, so this SVG is not self-contained`);
239
251
  }
240
- return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w3, height: h2 }], {
241
- viewBox: { x: 0, y: 0, width: w3, height: h2 }
252
+ return serializeSvg([{ kind: "image", href, x: 0, y: 0, width: w2, height: h }], {
253
+ viewBox: { x: 0, y: 0, width: w2, height: h }
242
254
  });
243
255
  }
244
256
  function markNodesOf(scene, draw) {
@@ -254,15 +266,15 @@ function markNodesOf(scene, draw) {
254
266
  }
255
267
  function composeCaptureSvg(args) {
256
268
  const { base, scene, draw, scale, onWarn } = args;
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);
269
+ const { w: w2, h } = draw.content;
270
+ const baseXml = base === void 0 ? "" : base.kind === "svg" ? nestBaseSvg(base.markup, w2, h) : embedRasterBase(base, w2, h, onWarn);
259
271
  const marksXml = serializeSvg(markNodesOf(scene, draw), {
260
- viewBox: { x: 0, y: 0, width: w3, height: h2 },
272
+ viewBox: { x: 0, y: 0, width: w2, height: h },
261
273
  onWarn
262
274
  });
263
- const outW = Math.max(1, Math.round(w3 * scale));
264
- const outH = Math.max(1, Math.round(h2 * scale));
265
- return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w3} ${h2}">${baseXml}${marksXml}</svg>`;
275
+ const outW = Math.max(1, Math.round(w2 * scale));
276
+ const outH = Math.max(1, Math.round(h * scale));
277
+ return `<svg xmlns="${SVG_NS}" width="${outW}" height="${outH}" viewBox="0 0 ${w2} ${h}">${baseXml}${marksXml}</svg>`;
266
278
  }
267
279
  function context2d(width, height) {
268
280
  const canvas = document.createElement("canvas");
@@ -356,26 +368,26 @@ async function captureTarget(args, opts = {}) {
356
368
  }
357
369
 
358
370
  // src/annotations/frac.ts
359
- function fracToWorld(f3, content) {
371
+ function fracToWorld(f4, content) {
360
372
  return {
361
- x: f3.x * content.w,
362
- y: f3.y * content.h,
363
- width: f3.w * content.w,
364
- height: f3.h * content.h
373
+ x: f4.x * content.w,
374
+ y: f4.y * content.h,
375
+ width: f4.w * content.w,
376
+ height: f4.h * content.h
365
377
  };
366
378
  }
367
- function worldToFrac(r10, content) {
379
+ function worldToFrac(r4, content) {
368
380
  const sx = content.w === 0 ? 0 : 1 / content.w;
369
381
  const sy = content.h === 0 ? 0 : 1 / content.h;
370
- return { x: r10.x * sx, y: r10.y * sy, w: r10.width * sx, h: r10.height * sy };
382
+ return { x: r4.x * sx, y: r4.y * sy, w: r4.width * sx, h: r4.height * sy };
371
383
  }
372
384
  var DP = 1e4;
373
- function roundFrac(f3) {
385
+ function roundFrac(f4) {
374
386
  return {
375
- x: Math.round(f3.x * DP) / DP,
376
- y: Math.round(f3.y * DP) / DP,
377
- w: Math.round(f3.w * DP) / DP,
378
- h: Math.round(f3.h * DP) / DP
387
+ x: Math.round(f4.x * DP) / DP,
388
+ y: Math.round(f4.y * DP) / DP,
389
+ w: Math.round(f4.w * DP) / DP,
390
+ h: Math.round(f4.h * DP) / DP
379
391
  };
380
392
  }
381
393
  function fracContains(box, pt, tol = 0) {
@@ -417,8 +429,8 @@ var MarkHistory = class {
417
429
  /** The target `undo` would act on, skipping any whose scene has nothing
418
430
  * left — a scene can drop entries this ordering still lists. */
419
431
  next(stack, can, at) {
420
- for (let i3 = stack.length - 1; i3 >= 0; i3--) {
421
- const target = stack[i3];
432
+ for (let i5 = stack.length - 1; i5 >= 0; i5--) {
433
+ const target = stack[i5];
422
434
  if (target === void 0) continue;
423
435
  const scene = at(target);
424
436
  if (scene && can(scene)) return target;
@@ -426,13 +438,13 @@ var MarkHistory = class {
426
438
  return null;
427
439
  }
428
440
  canUndo(at) {
429
- return this.next(this.undoable, (s5) => s5.canUndo(), at) !== null;
441
+ return this.next(this.undoable, (s4) => s4.canUndo(), at) !== null;
430
442
  }
431
443
  canRedo(at) {
432
- return this.next(this.redoable, (s5) => s5.canRedo(), at) !== null;
444
+ return this.next(this.redoable, (s4) => s4.canRedo(), at) !== null;
433
445
  }
434
446
  undo(at) {
435
- const target = this.next(this.undoable, (s5) => s5.canUndo(), at);
447
+ const target = this.next(this.undoable, (s4) => s4.canUndo(), at);
436
448
  const scene = target === null ? void 0 : at(target);
437
449
  if (!scene) return false;
438
450
  this.replaying = "undo";
@@ -443,7 +455,7 @@ var MarkHistory = class {
443
455
  }
444
456
  }
445
457
  redo(at) {
446
- const target = this.next(this.redoable, (s5) => s5.canRedo(), at);
458
+ const target = this.next(this.redoable, (s4) => s4.canRedo(), at);
447
459
  const scene = target === null ? void 0 : at(target);
448
460
  if (!scene) return false;
449
461
  this.replaying = "redo";
@@ -455,9 +467,9 @@ var MarkHistory = class {
455
467
  }
456
468
  };
457
469
  function drop(stack, value) {
458
- for (let i3 = stack.length - 1; i3 >= 0; i3--) {
459
- if (stack[i3] === value) {
460
- stack.splice(i3, 1);
470
+ for (let i5 = stack.length - 1; i5 >= 0; i5--) {
471
+ if (stack[i5] === value) {
472
+ stack.splice(i5, 1);
461
473
  return;
462
474
  }
463
475
  }
@@ -524,15 +536,15 @@ function createAnnotationStore(opts) {
524
536
  return out;
525
537
  };
526
538
  const all = () => liveTargets().flatMap(marksOn);
527
- const matches = (a4, q3) => {
528
- if (q3.target !== void 0 && a4.target !== q3.target) return false;
529
- if (q3.kind !== void 0 && a4.kind !== q3.kind) return false;
530
- if (q3.status !== void 0 && a4.status !== q3.status) return false;
531
- if (q3.tags !== void 0) {
539
+ const matches = (a4, q) => {
540
+ if (q.target !== void 0 && a4.target !== q.target) return false;
541
+ if (q.kind !== void 0 && a4.kind !== q.kind) return false;
542
+ if (q.status !== void 0 && a4.status !== q.status) return false;
543
+ if (q.tags !== void 0) {
532
544
  const have = a4.tags ?? [];
533
- for (const t of q3.tags) if (!have.includes(t)) return false;
545
+ for (const t of q.tags) if (!have.includes(t)) return false;
534
546
  }
535
- if (q3.where && !q3.where(a4)) return false;
547
+ if (q.where && !q.where(a4)) return false;
536
548
  return true;
537
549
  };
538
550
  const nodeOf = (id) => {
@@ -549,8 +561,8 @@ function createAnnotationStore(opts) {
549
561
  const parts = splitId(id);
550
562
  return parts ? project(parts.target, parts.node) : void 0;
551
563
  },
552
- query(q3) {
553
- return q3 ? all().filter((a4) => matches(a4, q3)) : all();
564
+ query(q) {
565
+ return q ? all().filter((a4) => matches(a4, q)) : all();
554
566
  },
555
567
  hitTest(target, pt, tol = 0) {
556
568
  return marksOn(target).filter((a4) => fracContains(a4.frac, pt, tol)).reverse();
@@ -598,7 +610,7 @@ function createAnnotationStore(opts) {
598
610
  for (const [target, scene] of scenes) {
599
611
  const next = wanted.get(target) ?? [];
600
612
  const now = scene.getSelection();
601
- if (now.length === next.length && next.every((n6, i3) => String(now[i3]) === n6)) continue;
613
+ if (now.length === next.length && next.every((n5, i5) => String(now[i5]) === n5)) continue;
602
614
  scene.setSelection(next.map(asNodeId$1));
603
615
  }
604
616
  },
@@ -695,14 +707,14 @@ var TOOLS = {
695
707
  };
696
708
  var ANNOTATION_TOOLS = [
697
709
  // 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" },
699
- { id: "select", label: "Select", icon: p, group: "annotate" },
700
- { id: "stroke", label: "Freehand", icon: u, group: "annotate" },
701
- { id: "line", label: "Line", icon: c, group: "annotate" },
702
- { id: "arrow", label: "Arrow", icon: n, group: "annotate" },
703
- { id: "rect", label: "Rectangle", icon: f, group: "annotate" },
704
- { id: "ellipse", label: "Ellipse", icon: r, group: "annotate" },
705
- { id: "text", label: "Text", icon: h, group: "annotate" }
710
+ { id: "pointer", label: "Interact", icon: y, group: "annotate" },
711
+ { id: "select", label: "Select", icon: I, group: "annotate" },
712
+ { id: "stroke", label: "Freehand", icon: A, group: "annotate" },
713
+ { id: "line", label: "Line", icon: T, group: "annotate" },
714
+ { id: "arrow", label: "Arrow", icon: i2, group: "annotate" },
715
+ { id: "rect", label: "Rectangle", icon: P, group: "annotate" },
716
+ { id: "ellipse", label: "Ellipse", icon: m, group: "annotate" },
717
+ { id: "text", label: "Text", icon: H, group: "annotate" }
706
718
  ];
707
719
  function annotationToolInfo(id) {
708
720
  return id === null ? void 0 : TOOLS[id];
@@ -712,17 +724,17 @@ var ANNOTATION_WEASEL_TOOLS = [
712
724
  ];
713
725
 
714
726
  // src/annotations/view.ts
715
- function toWeaselView(v2) {
716
- return { x: v2.pan.x, y: v2.pan.y, scale: { x: v2.zoom, y: v2.zoom } };
727
+ function toWeaselView(v) {
728
+ return { x: v.pan.x, y: v.pan.y, scale: { x: v.zoom, y: v.zoom } };
717
729
  }
718
- function fromWeaselView(v2) {
719
- return { zoom: v2.scale.x, pan: { x: v2.x, y: v2.y } };
730
+ function fromWeaselView(v) {
731
+ return { zoom: v.scale.x, pan: { x: v.x, y: v.y } };
720
732
  }
721
733
  function fitView(content, pane) {
722
734
  const zoom = content.w > 0 && content.h > 0 ? Math.min(pane.w / content.w, pane.h / content.h) : 1;
723
735
  return { zoom: Number.isFinite(zoom) && zoom > 0 ? zoom : 1, pan: { x: 0, y: 0 } };
724
736
  }
725
- var sameRect = (a4, b2) => a4 !== null && a4.x === b2.x && a4.y === b2.y && a4.w === b2.w && a4.h === b2.h;
737
+ var sameRect = (a4, b3) => a4 !== null && a4.x === b3.x && a4.y === b3.y && a4.w === b3.w && a4.h === b3.h;
726
738
  function ToolBridge({ toolId }) {
727
739
  const tools = useActiveToolContext();
728
740
  const setActive = tools.setActive;
@@ -732,9 +744,9 @@ function ToolBridge({ toolId }) {
732
744
  return null;
733
745
  }
734
746
  function pointsOf(extras, content) {
735
- const toFrac = (p2) => ({
736
- x: content.w === 0 ? 0 : p2.x / content.w,
737
- y: content.h === 0 ? 0 : p2.y / content.h
747
+ const toFrac = (p3) => ({
748
+ x: content.w === 0 ? 0 : p3.x / content.w,
749
+ y: content.h === 0 ? 0 : p3.y / content.h
738
750
  });
739
751
  if (extras.kind === "line") {
740
752
  return [toFrac(extras.a), toFrac(extras.b)];
@@ -997,10 +1009,6 @@ var interstellar_theme_default = {
997
1009
  dark: {
998
1010
  value: "#0a0a14",
999
1011
  type: "color"
1000
- },
1001
- light: {
1002
- value: "#fafaf7",
1003
- type: "color"
1004
1012
  }
1005
1013
  },
1006
1014
  "surface-raised": {
@@ -1008,10 +1016,6 @@ var interstellar_theme_default = {
1008
1016
  dark: {
1009
1017
  value: "rgba(20, 20, 36, 0.55)",
1010
1018
  type: "color"
1011
- },
1012
- light: {
1013
- value: "#ffffff",
1014
- type: "color"
1015
1019
  }
1016
1020
  },
1017
1021
  "surface-sunken": {
@@ -1019,10 +1023,6 @@ var interstellar_theme_default = {
1019
1023
  dark: {
1020
1024
  value: "#02020a",
1021
1025
  type: "color"
1022
- },
1023
- light: {
1024
- value: "#f0ebe2",
1025
- type: "color"
1026
1026
  }
1027
1027
  },
1028
1028
  border: {
@@ -1030,10 +1030,6 @@ var interstellar_theme_default = {
1030
1030
  dark: {
1031
1031
  value: "rgba(255, 255, 255, 0.14)",
1032
1032
  type: "color"
1033
- },
1034
- light: {
1035
- value: "#c9bba5",
1036
- type: "color"
1037
1033
  }
1038
1034
  },
1039
1035
  "line-subtle": {
@@ -1041,10 +1037,6 @@ var interstellar_theme_default = {
1041
1037
  dark: {
1042
1038
  value: "rgba(255, 255, 255, 0.08)",
1043
1039
  type: "color"
1044
- },
1045
- light: {
1046
- value: "rgba(0, 0, 0, 0.08)",
1047
- type: "color"
1048
1040
  }
1049
1041
  },
1050
1042
  fg: {
@@ -1052,10 +1044,6 @@ var interstellar_theme_default = {
1052
1044
  dark: {
1053
1045
  value: "#e8e8f0",
1054
1046
  type: "color"
1055
- },
1056
- light: {
1057
- value: "#2a2018",
1058
- type: "color"
1059
1047
  }
1060
1048
  },
1061
1049
  "fg-muted": {
@@ -1063,10 +1051,6 @@ var interstellar_theme_default = {
1063
1051
  dark: {
1064
1052
  value: "#a8a8c0",
1065
1053
  type: "color"
1066
- },
1067
- light: {
1068
- value: "#6b5c4a",
1069
- type: "color"
1070
1054
  }
1071
1055
  },
1072
1056
  "fg-subtle": {
@@ -1074,10 +1058,6 @@ var interstellar_theme_default = {
1074
1058
  dark: {
1075
1059
  value: "#5a5a78",
1076
1060
  type: "color"
1077
- },
1078
- light: {
1079
- value: "#a89b85",
1080
- type: "color"
1081
1061
  }
1082
1062
  },
1083
1063
  accent: {
@@ -1085,10 +1065,6 @@ var interstellar_theme_default = {
1085
1065
  dark: {
1086
1066
  value: "#b08adb",
1087
1067
  type: "color"
1088
- },
1089
- light: {
1090
- value: "#a86f3c",
1091
- type: "color"
1092
1068
  }
1093
1069
  },
1094
1070
  "accent-hover": {
@@ -1096,10 +1072,6 @@ var interstellar_theme_default = {
1096
1072
  dark: {
1097
1073
  value: "#c6a3ee",
1098
1074
  type: "color"
1099
- },
1100
- light: {
1101
- value: "#c2854f",
1102
- type: "color"
1103
1075
  }
1104
1076
  },
1105
1077
  "focus-ring": {
@@ -1107,10 +1079,6 @@ var interstellar_theme_default = {
1107
1079
  dark: {
1108
1080
  value: "rgba(176, 138, 219, 0.45)",
1109
1081
  type: "color"
1110
- },
1111
- light: {
1112
- value: "rgba(168, 111, 60, 0.35)",
1113
- type: "color"
1114
1082
  }
1115
1083
  },
1116
1084
  shadow: {
@@ -1118,10 +1086,6 @@ var interstellar_theme_default = {
1118
1086
  dark: {
1119
1087
  value: "rgba(0, 0, 0, 0.7)",
1120
1088
  type: "color"
1121
- },
1122
- light: {
1123
- value: "rgba(80, 60, 40, 0.18)",
1124
- type: "color"
1125
1089
  }
1126
1090
  },
1127
1091
  "border-strong": {
@@ -1129,10 +1093,6 @@ var interstellar_theme_default = {
1129
1093
  dark: {
1130
1094
  value: "rgba(255, 255, 255, 0.36)",
1131
1095
  type: "color"
1132
- },
1133
- light: {
1134
- value: "#9e8b71",
1135
- type: "color"
1136
1096
  }
1137
1097
  },
1138
1098
  backdrop: {
@@ -1140,10 +1100,6 @@ var interstellar_theme_default = {
1140
1100
  dark: {
1141
1101
  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
1102
  type: "gradient"
1143
- },
1144
- light: {
1145
- value: "none",
1146
- type: "gradient"
1147
1103
  }
1148
1104
  }
1149
1105
  }
@@ -1250,7 +1206,7 @@ function Portalled({
1250
1206
  }
1251
1207
  function UndockedSections({ trialId, sections, onDock }) {
1252
1208
  if (sections.length === 0) return null;
1253
- return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c8) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c8, onDock }, c8.id)) });
1209
+ return /* @__PURE__ */ jsx(Fragment, { children: sections.map((c6) => /* @__PURE__ */ jsx(Portalled, { trialId, contribution: c6, onDock }, c6.id)) });
1254
1210
  }
1255
1211
  var NO_OP = () => {
1256
1212
  };
@@ -1273,17 +1229,17 @@ function TrialChrome({
1273
1229
  const lab = useLabContext();
1274
1230
  const storeCtx = useContext(LabStoreContext);
1275
1231
  if (!storeCtx) throw new Error("[labkit] TrialChrome requires <LabStoreProvider>");
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);
1232
+ const updateTrialView = useStore(storeCtx.store, (s4) => s4.updateTrialView);
1233
+ const updateTrialSidebarWidth = useStore(storeCtx.store, (s4) => s4.updateTrialSidebarWidth);
1234
+ const setTrialTitle = useStore(storeCtx.store, (s4) => s4.setTrialTitle);
1235
+ const setTrialSectionCollapsed = useStore(storeCtx.store, (s4) => s4.setTrialSectionCollapsed);
1236
+ const updateTrialConfig = useStore(storeCtx.store, (s4) => s4.updateTrialConfig);
1237
+ const updateTrialState = useStore(storeCtx.store, (s4) => s4.updateTrialState);
1238
+ const undockPanelAction = useStore(storeCtx.store, (s4) => s4.undockPanel);
1239
+ const dockPanelAction = useStore(storeCtx.store, (s4) => s4.dockPanel);
1240
+ const undockedPanels = useStore(storeCtx.store, (s4) => s4.undockedPanels);
1285
1241
  const undockedIds = useMemo(
1286
- () => Object.values(undockedPanels).filter((p2) => p2.trialId === trialId).map((p2) => p2.sectionId),
1242
+ () => Object.values(undockedPanels).filter((p3) => p3.trialId === trialId).map((p3) => p3.sectionId),
1287
1243
  [undockedPanels, trialId]
1288
1244
  );
1289
1245
  const view2d = as2DView(record.view);
@@ -1296,9 +1252,9 @@ function TrialChrome({
1296
1252
  const title = record.title ?? instrument.title ?? instrument.name;
1297
1253
  const collapsedSections = record.collapsedSections ?? NO_SECTIONS;
1298
1254
  const ctx = useMemo(() => {
1299
- const setZoom = (z2) => {
1255
+ const setZoom = (z) => {
1300
1256
  if (!view2d) return;
1301
- updateTrialView(trialId, withZoom(view2d, z2));
1257
+ updateTrialView(trialId, withZoom(view2d, z));
1302
1258
  };
1303
1259
  return {
1304
1260
  trialId,
@@ -1338,7 +1294,7 @@ function TrialChrome({
1338
1294
  undockedPanels: undockedIds,
1339
1295
  undockPanel: (sectionId, as) => undockPanelAction(trialId, sectionId, as),
1340
1296
  dockPanel: (sectionId) => dockPanelAction(trialId, sectionId),
1341
- savedSnapshots: lab.savedSnapshots.filter((s5) => s5.trialId === trialId),
1297
+ savedSnapshots: lab.savedSnapshots.filter((s4) => s4.trialId === trialId),
1342
1298
  saveSnapshot: (name) => lab.saveSnapshot(trialId, name),
1343
1299
  loadSnapshot: (snapshotId) => lab.loadSnapshot(trialId, snapshotId),
1344
1300
  clone: () => lab.cloneTrial(trialId),
@@ -1384,7 +1340,7 @@ function TrialChrome({
1384
1340
  ),
1385
1341
  [instrument, ctx, trialChrome, chrome, suppress, lab.controls]
1386
1342
  );
1387
- const inRegion = (region) => contributions.filter((c8) => c8.region === region);
1343
+ const inRegion = (region) => contributions.filter((c6) => c6.region === region);
1388
1344
  const handleKeyDown = (e) => {
1389
1345
  const mod = e.metaKey || e.ctrlKey;
1390
1346
  if (!mod) return;
@@ -1422,7 +1378,7 @@ function TrialChrome({
1422
1378
  TrialBody,
1423
1379
  {
1424
1380
  width: record.sidebarWidth,
1425
- onWidthChange: (w3) => updateTrialSidebarWidth(trialId, w3),
1381
+ onWidthChange: (w2) => updateTrialSidebarWidth(trialId, w2),
1426
1382
  contentClassName: instrument.canvas || instrument.stage ? "lk-trial__content--flush" : void 0,
1427
1383
  sidebar: /* @__PURE__ */ jsxs(Fragment, { children: [
1428
1384
  /* @__PURE__ */ jsx(SidebarRegion, { contributions: inRegion("sidebar"), ctx }),
@@ -1430,7 +1386,7 @@ function TrialChrome({
1430
1386
  UndockedSections,
1431
1387
  {
1432
1388
  trialId,
1433
- sections: inRegion("sidebar").filter((c8) => undockedIds.includes(c8.id)),
1389
+ sections: inRegion("sidebar").filter((c6) => undockedIds.includes(c6.id)),
1434
1390
  onDock: ctx.dockPanel
1435
1391
  }
1436
1392
  )
@@ -1454,9 +1410,9 @@ function Trial({ id, chrome, suppress }) {
1454
1410
  const lab = useLabContext();
1455
1411
  const storeCtx = useContext(LabStoreContext);
1456
1412
  if (!storeCtx) throw new Error("[labkit] <Trial> requires <LabStoreProvider>");
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;
1413
+ const instruments = useStore(storeCtx.store, (s4) => s4.instruments) ?? lab.instruments;
1414
+ const record = useStore(storeCtx.store, (s4) => s4.trials.find((w2) => w2.id === id));
1415
+ const instrument = record ? instruments.find((i5) => i5.name === record.instrumentName) : void 0;
1460
1416
  const kept = useKeptMarks(instrument?.annotations?.storage, id);
1461
1417
  if (!record) {
1462
1418
  return /* @__PURE__ */ jsxs("div", { className: "lk-trial lk-trial--unknown", children: [
@@ -1522,14 +1478,14 @@ function TrialRuntime({
1522
1478
  const wheelSlot = useRef(null);
1523
1479
  const canvasContainerRef = useRef(null);
1524
1480
  const loupeHostRef = useRef(null);
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);
1481
+ const updateTrialState = useStore(store, (s4) => s4.updateTrialState);
1482
+ const updateTrialConfig = useStore(store, (s4) => s4.updateTrialConfig);
1483
+ const updateTrialView = useStore(store, (s4) => s4.updateTrialView);
1484
+ const updateTrialUndoStack = useStore(store, (s4) => s4.updateTrialUndoStack);
1485
+ const updateTrialAnnotations = useStore(store, (s4) => s4.updateTrialAnnotations);
1486
+ const labToolId = useStore(store, (s4) => s4.activeToolId);
1487
+ const setLabTool = useStore(store, (s4) => s4.setLabTool);
1488
+ const setTrialTool = useStore(store, (s4) => s4.setTrialTool);
1533
1489
  const schema = useConfigSchema(instrument);
1534
1490
  const { config } = useResolvedConfig(schema, record.config, record.auto);
1535
1491
  const busRef = useRef(null);
@@ -1539,7 +1495,7 @@ function TrialRuntime({
1539
1495
  const [layerOrder, setLayerOrder] = useState(null);
1540
1496
  const [loupeOn, setLoupeOn] = useState(false);
1541
1497
  const visibleLayers = useMemo(
1542
- () => (instrument.canvas?.layers ?? []).filter((l9) => layerVisibility[l9.id] !== false).map((l9) => l9.id),
1498
+ () => (instrument.canvas?.layers ?? []).filter((l8) => layerVisibility[l8.id] !== false).map((l8) => l8.id),
1543
1499
  [instrument.canvas, layerVisibility]
1544
1500
  );
1545
1501
  const undoCap = instrument.undo;
@@ -1547,12 +1503,12 @@ function TrialRuntime({
1547
1503
  const maxDepth = undoCap?.maxDepth ?? 50;
1548
1504
  const snapshotIfNeeded = (event) => {
1549
1505
  if (!undoCap || !undoEvents.has(event)) return;
1550
- const current = store.getState().trials.find((w3) => w3.id === record.id);
1506
+ const current = store.getState().trials.find((w2) => w2.id === record.id);
1551
1507
  if (!current) return;
1552
1508
  const snap = structuredClone(current.state);
1553
1509
  updateTrialUndoStack(record.id, (prev) => pushSnapshot(prev, snap, maxDepth));
1554
1510
  };
1555
- const setView = (v2) => updateTrialView(record.id, v2);
1511
+ const setView = (v) => updateTrialView(record.id, v);
1556
1512
  const stage = instrument.canvas ? void 0 : instrument.stage;
1557
1513
  const placeView = (size) => {
1558
1514
  const declared = instrument.canvas?.initialView ?? (stage ? stage.initialView ?? ((vp) => fitStage(stage.size, vp)) : void 0);
@@ -1654,9 +1610,9 @@ function TrialRuntime({
1654
1610
  view: record.view,
1655
1611
  setView,
1656
1612
  zoom: view2d?.zoom ?? 1,
1657
- setZoom: (z2) => {
1613
+ setZoom: (z) => {
1658
1614
  if (!view2d) return;
1659
- updateTrialView(record.id, withZoom(view2d, z2));
1615
+ updateTrialView(record.id, withZoom(view2d, z));
1660
1616
  },
1661
1617
  activeToolId: resolvedToolId,
1662
1618
  visibleLayers
@@ -1696,11 +1652,11 @@ function TrialRuntime({
1696
1652
  if (declared == null) return null;
1697
1653
  return resolveLoupe(typeof declared === "function" ? declared(config) : declared);
1698
1654
  }, [instrument.loupe, config]);
1699
- const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((v2) => !v2) } : void 0;
1655
+ const loupeBindings = loupeCap ? { on: loupeOn, toggle: () => setLoupeOn((v) => !v) } : void 0;
1700
1656
  const canvasLayers = useMemo(() => {
1701
1657
  if (!instrument.canvas) return [];
1702
1658
  const baseLayers = instrument.canvas.layers;
1703
- const ordered = layerOrder ? [...baseLayers].sort((a4, b2) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b2.id)) : baseLayers;
1659
+ const ordered = layerOrder ? [...baseLayers].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : baseLayers;
1704
1660
  return ordered.map((layer) => ({
1705
1661
  id: layer.id,
1706
1662
  visible: layerVisibility[layer.id] !== false,
@@ -1712,10 +1668,23 @@ function TrialRuntime({
1712
1668
  }, [instrument.canvas, record.state, config, layerVisibility, layerOrder]);
1713
1669
  const layerDescriptors = useMemo(() => {
1714
1670
  if (!instrument.layers) return [];
1715
- return instrument.layers.ids.map((l9) => typeof l9 === "string" ? { id: l9, label: l9 } : l9);
1671
+ return instrument.layers.ids.map((l8) => typeof l8 === "string" ? { id: l8, label: l8 } : l8);
1716
1672
  }, [instrument.layers]);
1673
+ const layerItems = useMemo(() => {
1674
+ const ordered = layerOrder ? [...layerDescriptors].sort((a4, b3) => layerOrder.indexOf(a4.id) - layerOrder.indexOf(b3.id)) : layerDescriptors;
1675
+ const pinnedLast = [
1676
+ ...ordered.filter((l8) => !l8.alwaysOn),
1677
+ ...ordered.filter((l8) => l8.alwaysOn)
1678
+ ];
1679
+ return pinnedLast.map((l8) => ({
1680
+ id: l8.id,
1681
+ label: l8.label,
1682
+ locked: l8.alwaysOn === true,
1683
+ visible: l8.alwaysOn === true || layerVisibility[l8.id] !== false
1684
+ }));
1685
+ }, [layerDescriptors, layerOrder, layerVisibility]);
1717
1686
  const dragDropResult = useDragDrop({
1718
- capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s5) => s5 },
1687
+ capability: instrument.dragDrop ?? { palette: [], onDrop: (_p, _i, s4) => s4 },
1719
1688
  canvasContainerRef,
1720
1689
  view: view2d ?? DEFAULT_VIEW,
1721
1690
  worldSpec: instrument.canvas?.worldSpec,
@@ -1732,8 +1701,8 @@ function TrialRuntime({
1732
1701
  });
1733
1702
  const paletteItems = useMemo(() => {
1734
1703
  if (!instrument.dragDrop) return [];
1735
- const p2 = instrument.dragDrop.palette;
1736
- return typeof p2 === "function" ? p2(record.state, config) : p2;
1704
+ const p3 = instrument.dragDrop.palette;
1705
+ return typeof p3 === "function" ? p3(record.state, config) : p3;
1737
1706
  }, [instrument.dragDrop, record.state, config]);
1738
1707
  const layersWithFeedback = useMemo(() => {
1739
1708
  if (!dragDropResult.drag?.feedback) return canvasLayers;
@@ -1747,12 +1716,12 @@ function TrialRuntime({
1747
1716
  render: (ctx) => {
1748
1717
  const el = canvasContainerRef.current;
1749
1718
  if (!el) return;
1750
- const r10 = el.getBoundingClientRect();
1719
+ const r4 = el.getBoundingClientRect();
1751
1720
  ctx.save();
1752
1721
  ctx.strokeStyle = fb.ok ? "#3a7" : "#c44";
1753
1722
  ctx.lineWidth = 2;
1754
1723
  ctx.beginPath();
1755
- ctx.arc(screen.x - r10.left, screen.y - r10.top, 16, 0, Math.PI * 2);
1724
+ ctx.arc(screen.x - r4.left, screen.y - r4.top, 16, 0, Math.PI * 2);
1756
1725
  ctx.stroke();
1757
1726
  ctx.restore();
1758
1727
  }
@@ -1803,7 +1772,10 @@ function TrialRuntime({
1803
1772
  minZoom: stage.minZoom,
1804
1773
  maxZoom: stage.maxZoom,
1805
1774
  hostRef: loupeHostRef,
1806
- overlay: lens,
1775
+ overlay: /* @__PURE__ */ jsxs(Fragment, { children: [
1776
+ stage.overlay?.(renderCtx),
1777
+ lens
1778
+ ] }),
1807
1779
  children: instrument.render(renderCtx)
1808
1780
  }
1809
1781
  );
@@ -1822,21 +1794,20 @@ function TrialRuntime({
1822
1794
  );
1823
1795
  const layerListNode = useMemo(
1824
1796
  () => instrument.layers && layerDescriptors.length > 0 ? /* @__PURE__ */ jsx(
1825
- LayerList,
1797
+ D,
1826
1798
  {
1827
- layers: layerDescriptors,
1828
- visibility: layerVisibility,
1829
- onReorder: (next) => {
1830
- setLayerOrder(next.map((l9) => l9.id));
1799
+ items: layerItems,
1800
+ onReorder: (move) => {
1801
+ setLayerOrder(S2(layerItems, move).map((l8) => l8.id));
1831
1802
  bus.emit("layers.reorder");
1832
1803
  },
1833
- onToggle: (lid, visible) => {
1804
+ onVisibilityChange: (lid, visible) => {
1834
1805
  setLayerVisibility((prev) => ({ ...prev, [lid]: visible }));
1835
1806
  bus.emit("layers.toggle");
1836
1807
  }
1837
1808
  }
1838
1809
  ) : null,
1839
- [instrument.layers, layerDescriptors, layerVisibility, bus]
1810
+ [instrument.layers, layerDescriptors, layerItems, bus]
1840
1811
  );
1841
1812
  const extraChrome = useMemo(() => {
1842
1813
  const out = [];
@@ -1893,7 +1864,7 @@ function TrialRuntime({
1893
1864
  // src/trial/trialOps.ts
1894
1865
  var DEFAULT_VIEW2 = { zoom: 1, pan: { x: 0, y: 0 } };
1895
1866
  function findInstrument(instruments, name) {
1896
- const found = instruments.find((i3) => i3.name === name);
1867
+ const found = instruments.find((i5) => i5.name === name);
1897
1868
  if (!found) {
1898
1869
  throw new Error(`[labkit] Unknown instrument: "${name}"`);
1899
1870
  }
@@ -1949,7 +1920,7 @@ function addTrial(trials, instruments, instrumentName, options = {}) {
1949
1920
  return [...trials, record];
1950
1921
  }
1951
1922
  function cloneTrial(trials, id) {
1952
- const sourceIdx = trials.findIndex((w3) => w3.id === id);
1923
+ const sourceIdx = trials.findIndex((w2) => w2.id === id);
1953
1924
  const source = trials[sourceIdx];
1954
1925
  if (!source) return trials;
1955
1926
  const clone = {
@@ -1964,11 +1935,11 @@ function cloneTrial(trials, id) {
1964
1935
  }
1965
1936
  function closeTrial(trials, id) {
1966
1937
  if (trials.length <= 1) return trials;
1967
- const next = trials.filter((w3) => w3.id !== id);
1938
+ const next = trials.filter((w2) => w2.id !== id);
1968
1939
  return next.length === trials.length ? trials : next;
1969
1940
  }
1970
1941
  function resetTrial(trials, id, instruments) {
1971
- const idx = trials.findIndex((w3) => w3.id === id);
1942
+ const idx = trials.findIndex((w2) => w2.id === id);
1972
1943
  const current = trials[idx];
1973
1944
  if (!current) return trials;
1974
1945
  const instrument = findInstrument(instruments, current.instrumentName);
@@ -1986,7 +1957,7 @@ function resetTrial(trials, id, instruments) {
1986
1957
  return [...trials.slice(0, idx), reset, ...trials.slice(idx + 1)];
1987
1958
  }
1988
1959
  function swapTrial(trials, instruments, id, instrumentName, options = {}) {
1989
- const idx = trials.findIndex((w3) => w3.id === id);
1960
+ const idx = trials.findIndex((w2) => w2.id === id);
1990
1961
  const current = trials[idx];
1991
1962
  if (!current) return trials;
1992
1963
  const [record] = addTrial([], instruments, instrumentName, options);
@@ -1994,25 +1965,25 @@ function swapTrial(trials, instruments, id, instrumentName, options = {}) {
1994
1965
  return [...trials.slice(0, idx), record, ...trials.slice(idx + 1)];
1995
1966
  }
1996
1967
  function reorderTrials(trials, ids) {
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));
1968
+ const byId = new Map(trials.map((w2) => [w2.id, w2]));
1969
+ const named = ids.map((id) => byId.get(id)).filter((w2) => w2 !== void 0);
1970
+ const seen = new Set(named.map((w2) => w2.id));
1971
+ const rest = trials.filter((w2) => !seen.has(w2.id));
2001
1972
  return [...named, ...rest];
2002
1973
  }
2003
1974
  function findOvershoot(bound, items, tolerance = 1) {
2004
1975
  let worst = null;
2005
1976
  for (const { item, edges } of items) {
2006
1977
  const y3 = edges.bottom - bound.bottom;
2007
- const x = edges.right - bound.right;
2008
- const by = Math.max(x, y3);
1978
+ const x2 = edges.right - bound.right;
1979
+ const by = Math.max(x2, y3);
2009
1980
  if (by <= tolerance) continue;
2010
- if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x ? "y" : "x" };
1981
+ if (!worst || by > worst.by) worst = { item, by, axis: y3 >= x2 ? "y" : "x" };
2011
1982
  }
2012
1983
  return worst;
2013
1984
  }
2014
1985
  function tagAndClasses(el) {
2015
- return el.tagName.toLowerCase() + [...el.classList].map((c8) => `.${c8}`).join("");
1986
+ return el.tagName.toLowerCase() + [...el.classList].map((c6) => `.${c6}`).join("");
2016
1987
  }
2017
1988
  function describeElement(el) {
2018
1989
  if (el.classList.length > 0) return tagAndClasses(el);
@@ -2021,8 +1992,8 @@ function describeElement(el) {
2021
1992
  return up ? `${tagAndClasses(el)} in ${tagAndClasses(up)}` : tagAndClasses(el);
2022
1993
  }
2023
1994
  function edgesOf(el) {
2024
- const r10 = el.getBoundingClientRect();
2025
- return { top: r10.top, left: r10.left, bottom: r10.bottom, right: r10.right };
1995
+ const r4 = el.getBoundingClientRect();
1996
+ return { top: r4.top, left: r4.left, bottom: r4.bottom, right: r4.right };
2026
1997
  }
2027
1998
  function* candidates(root) {
2028
1999
  yield { item: root, edges: edgesOf(root) };
@@ -2033,24 +2004,24 @@ function overflows(el) {
2033
2004
  }
2034
2005
  function explainLabScroll(lab, shellBody) {
2035
2006
  if (overflows(shellBody)) {
2036
- const r11 = shellBody.getBoundingClientRect();
2007
+ const r5 = shellBody.getBoundingClientRect();
2037
2008
  const bound2 = {
2038
- top: r11.top,
2039
- left: r11.left,
2040
- bottom: r11.top + shellBody.clientHeight,
2041
- right: r11.left + shellBody.clientWidth
2009
+ top: r5.top,
2010
+ left: r5.left,
2011
+ bottom: r5.top + shellBody.clientHeight,
2012
+ right: r5.left + shellBody.clientWidth
2042
2013
  };
2043
2014
  const hit2 = findOvershoot(bound2, candidates(shellBody));
2044
2015
  return hit2 ? `.lk-shell-body scrolls: ${describeElement(hit2.item)} reaches ${Math.round(hit2.by)}px past it (${hit2.axis})` : ".lk-shell-body scrolls";
2045
2016
  }
2046
2017
  const doc = document.scrollingElement ?? document.documentElement;
2047
2018
  if (!overflows(doc)) return null;
2048
- const r10 = lab.getBoundingClientRect();
2019
+ const r4 = lab.getBoundingClientRect();
2049
2020
  const bound = {
2050
- top: r10.top,
2051
- left: r10.left,
2052
- bottom: r10.top + Math.min(r10.height, doc.clientHeight),
2053
- right: r10.left + Math.min(r10.width, doc.clientWidth)
2021
+ top: r4.top,
2022
+ left: r4.left,
2023
+ bottom: r4.top + Math.min(r4.height, doc.clientHeight),
2024
+ right: r4.left + Math.min(r4.width, doc.clientWidth)
2054
2025
  };
2055
2026
  const hit = findOvershoot(bound, candidates(lab));
2056
2027
  return hit ? `the page scrolls: ${describeElement(hit.item)} reaches ${Math.round(hit.by)}px past the lab's box (${hit.axis})` : null;
@@ -2080,16 +2051,6 @@ function useLabFitWarning(labBody) {
2080
2051
  };
2081
2052
  }, [labBody]);
2082
2053
  }
2083
- var MODES = [
2084
- { value: "auto", label: "Auto", glyph: /* @__PURE__ */ jsx(E, { size: 14 }) },
2085
- { value: "light", label: "Light", glyph: /* @__PURE__ */ jsx(w, { size: 14 }) },
2086
- { value: "dark", label: "Dark", glyph: /* @__PURE__ */ jsx(T, { size: 14 }) }
2087
- ];
2088
- var MODE_ITEMS = MODES.map(({ value, label, glyph }) => ({
2089
- value,
2090
- label: glyph,
2091
- ariaLabel: label
2092
- }));
2093
2054
  function LabHeader({ addTrial: addTrial2 = true }) {
2094
2055
  const lab = useLabContext();
2095
2056
  const only = lab.instruments.length === 1 ? lab.instruments[0] : null;
@@ -2101,30 +2062,26 @@ function LabHeader({ addTrial: addTrial2 = true }) {
2101
2062
  className: "lk-lab-header__add",
2102
2063
  onClick: () => lab.addTrial(only.name),
2103
2064
  children: [
2104
- /* @__PURE__ */ jsx(C, { size: 16 }),
2065
+ /* @__PURE__ */ jsx(oe, { size: 16 }),
2105
2066
  /* @__PURE__ */ jsx("span", { children: "Add trial" })
2106
2067
  ]
2107
2068
  }
2108
2069
  ) : /* @__PURE__ */ jsx(
2109
- l7,
2070
+ d2,
2110
2071
  {
2111
2072
  "aria-label": "Add trial",
2112
2073
  label: "Add trial\u2026",
2113
- items: lab.instruments.map((i3) => ({ value: i3.name, label: i3.title ?? i3.name })),
2074
+ items: lab.instruments.map((i5) => ({ value: i5.name, label: i5.title ?? i5.name })),
2114
2075
  onAction: (name) => lab.addTrial(name)
2115
2076
  }
2116
2077
  ),
2117
2078
  /* @__PURE__ */ jsx(
2118
- r3,
2079
+ s3,
2119
2080
  {
2120
2081
  className: "lk-lab-header__mode",
2121
- ariaLabel: "Color mode",
2122
2082
  variant: "flat",
2123
- items: MODE_ITEMS,
2124
2083
  value: lab.mode,
2125
- onChange: (next) => {
2126
- if (next) lab.setMode(next);
2127
- }
2084
+ onChange: lab.setMode
2128
2085
  }
2129
2086
  )
2130
2087
  ] });
@@ -2132,42 +2089,39 @@ function LabHeader({ addTrial: addTrial2 = true }) {
2132
2089
  function LabPalette({ tools, contributions }) {
2133
2090
  const ctx = useLabChromeContext();
2134
2091
  const all = labContributions(tools, contributions);
2135
- return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c8) => c8.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;
2092
+ return /* @__PURE__ */ jsx(PaletteRegion, { contributions: all.filter((c6) => c6.region === "palette"), ctx });
2154
2093
  }
2155
2094
  function LabRoot({ children, mode = "auto", className }) {
2156
- const resolved = useResolvedMode(mode);
2095
+ const resolved = useResolvedColorMode(mode);
2157
2096
  const outer = useThemeOptional();
2158
2097
  const root = /* @__PURE__ */ jsx("div", { className: className ? `lk-root ${className}` : "lk-root", "data-wzl-portal-host": "", children });
2159
2098
  return outer ? root : /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, selection: { mode: resolved }, children: root });
2160
2099
  }
2100
+ function locate(url) {
2101
+ const hash = url.indexOf("#");
2102
+ const trim = (part) => part.replace(/\?.*$/, "").replace(/\/$/, "");
2103
+ return {
2104
+ doc: trim(hash < 0 ? url : url.slice(0, hash)).replace(/\.html$/, ""),
2105
+ route: hash < 0 ? "" : trim(url.slice(hash + 1))
2106
+ };
2107
+ }
2161
2108
  function currentPage(path, pages) {
2162
- const here = path.replace(/[?#].*$/, "").replace(/\/$/, "").replace(/\.html$/, "");
2163
- return pages.findIndex((p2) => here.endsWith(p2.href.replace(/\.html$/, "")));
2109
+ const here = locate(path);
2110
+ const onDoc = (doc) => here.doc.endsWith(doc);
2111
+ const routed = pages.findIndex((p3) => {
2112
+ if (!p3.href.includes("#")) return false;
2113
+ const page = locate(p3.href);
2114
+ return onDoc(page.doc) && (here.route === page.route || here.route.startsWith(`${page.route}/`));
2115
+ });
2116
+ if (routed >= 0) return routed;
2117
+ return pages.findIndex((p3) => !p3.href.includes("#") && onDoc(locate(p3.href).doc));
2164
2118
  }
2165
2119
  function LabSwitcher({ title, pages, path, className }) {
2166
2120
  const [open, setOpen] = useState(false);
2167
2121
  const root = useRef(null);
2168
2122
  const menuId = useId();
2169
2123
  const here = currentPage(
2170
- path ?? (typeof window === "undefined" ? "" : window.location.pathname),
2124
+ path ?? (typeof window === "undefined" ? "" : window.location.pathname + window.location.hash),
2171
2125
  pages
2172
2126
  );
2173
2127
  const close = useCallback(() => setOpen(false), []);
@@ -2208,13 +2162,13 @@ function LabSwitcher({ title, pages, path, className }) {
2208
2162
  ]
2209
2163
  }
2210
2164
  ) }),
2211
- open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i3) => /* @__PURE__ */ jsx(
2165
+ open && /* @__PURE__ */ jsx("div", { className: "lk-switcher-menu", id: menuId, role: "menu", children: pages.map((page, i5) => /* @__PURE__ */ jsx(
2212
2166
  "a",
2213
2167
  {
2214
2168
  href: page.href,
2215
2169
  role: "menuitem",
2216
2170
  className: "lk-switcher-item",
2217
- "aria-current": i3 === here ? "page" : void 0,
2171
+ "aria-current": i5 === here ? "page" : void 0,
2218
2172
  onClick: close,
2219
2173
  children: page.label
2220
2174
  },
@@ -2229,8 +2183,17 @@ function LabShell({
2229
2183
  footer,
2230
2184
  mode = "auto",
2231
2185
  pages,
2232
- path
2186
+ path,
2187
+ documentTitle
2233
2188
  }) {
2189
+ useEffect(() => {
2190
+ if (documentTitle === void 0) return;
2191
+ const previous = document.title;
2192
+ document.title = documentTitle;
2193
+ return () => {
2194
+ document.title = previous;
2195
+ };
2196
+ }, [documentTitle]);
2234
2197
  return /* @__PURE__ */ jsxs(LabRoot, { mode, className: "lk-shell", children: [
2235
2198
  /* @__PURE__ */ jsxs("header", { className: "lk-shell-header", children: [
2236
2199
  pages && pages.length > 0 ? /* @__PURE__ */ jsx(LabSwitcher, { title, pages, path, className: "lk-shell-title" }) : /* @__PURE__ */ jsx("h1", { className: "lk-shell-title", children: title }),
@@ -2246,11 +2209,11 @@ var FLOAT_ZONE_ID = asNodeId("lk-workspace-floating");
2246
2209
  var PANEL_KIND = "panel";
2247
2210
  var KIND = "trial";
2248
2211
  function extentOf(store, id) {
2249
- const p2 = store.getNode(id)?.membership?.placement;
2250
- if (!p2) return null;
2212
+ const p3 = store.getNode(id)?.membership?.placement;
2213
+ if (!p3) return null;
2251
2214
  const out = {};
2252
- if (p2.size) out.size = p2.size;
2253
- if (p2.span) out.span = p2.span;
2215
+ if (p3.size) out.size = p3.size;
2216
+ if (p3.span) out.span = p3.span;
2254
2217
  return Object.keys(out).length > 0 ? out : null;
2255
2218
  }
2256
2219
  function PanelFrame({ panel, floating = false }) {
@@ -2271,11 +2234,11 @@ function Workspace({
2271
2234
  viewport
2272
2235
  }) {
2273
2236
  const items = Children.toArray(children);
2274
- const tilePanels = useMemo(() => (panels ?? []).filter((p2) => p2.as === "tile"), [panels]);
2275
- const floatPanels = useMemo(() => (panels ?? []).filter((p2) => p2.as === "floating"), [panels]);
2237
+ const tilePanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "tile"), [panels]);
2238
+ const floatPanels = useMemo(() => (panels ?? []).filter((p3) => p3.as === "floating"), [panels]);
2276
2239
  const wantedIds = [
2277
- ...items.map((_, i3) => ids?.[i3] ?? `lk-ws-${i3}`),
2278
- ...tilePanels.map((p2) => `lk-panel-${p2.key}`)
2240
+ ...items.map((_2, i5) => ids?.[i5] ?? `lk-ws-${i5}`),
2241
+ ...tilePanels.map((p3) => `lk-panel-${p3.key}`)
2279
2242
  ];
2280
2243
  const idKey = wantedIds.join(",");
2281
2244
  const idKeyRef = useRef(null);
@@ -2350,9 +2313,9 @@ function Workspace({
2350
2313
  [onReorder]
2351
2314
  );
2352
2315
  const chrome = useMemo(() => {
2353
- const byId = new Map(nodeIds.map((id, i3) => [id, items[i3]]));
2316
+ const byId = new Map(nodeIds.map((id, i5) => [id, items[i5]]));
2354
2317
  const panelByNode = new Map(
2355
- tilePanels.map((p2) => [`lk-panel-${p2.key}`, p2])
2318
+ tilePanels.map((p3) => [`lk-panel-${p3.key}`, p3])
2356
2319
  );
2357
2320
  return {
2358
2321
  [PANEL_KIND]: ({ node }) => {
@@ -2370,7 +2333,7 @@ function Workspace({
2370
2333
  }
2371
2334
  };
2372
2335
  }, [nodeIds, items, reorderable, tilePanels]);
2373
- const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p2) => /* @__PURE__ */ jsx(PanelFrame, { panel: p2, floating: true }, p2.key)) });
2336
+ const floatingLayer = floatPanels.length === 0 ? null : /* @__PURE__ */ jsx("div", { className: "lk-workspace__floating", children: floatPanels.map((p3) => /* @__PURE__ */ jsx(PanelFrame, { panel: p3, floating: true }, p3.key)) });
2374
2337
  const grid = /* @__PURE__ */ jsx(
2375
2338
  Container,
2376
2339
  {
@@ -2416,7 +2379,7 @@ async function openStoredLab({ instruments, defaultInstrument, mode }, storageKe
2416
2379
  const marks = /* @__PURE__ */ new Map();
2417
2380
  await Promise.all(
2418
2381
  opened.store.getState().trials.map(async (trial) => {
2419
- const kept = instruments.find((i3) => i3.name === trial.instrumentName)?.annotations?.storage;
2382
+ const kept = instruments.find((i5) => i5.name === trial.instrumentName)?.annotations?.storage;
2420
2383
  if (!kept) return;
2421
2384
  try {
2422
2385
  marks.set(trial.id, await kept.load());
@@ -2431,20 +2394,30 @@ async function openStoredLab({ instruments, defaultInstrument, mode }, storageKe
2431
2394
  function LabFallback({
2432
2395
  title,
2433
2396
  mode,
2397
+ density,
2398
+ theme = interstellarTheme,
2434
2399
  pages,
2435
2400
  path
2436
2401
  }) {
2437
- const resolvedMode = useResolvedMode(mode ?? "auto");
2438
- return /* @__PURE__ */ jsx(ThemeProvider, { theme: interstellarTheme, selection: { mode: resolvedMode }, className: "lk-lab", children: /* @__PURE__ */ jsx(
2439
- LabShell,
2402
+ const resolvedMode = useResolvedColorMode(mode ?? "auto");
2403
+ return /* @__PURE__ */ jsx(
2404
+ ThemeProvider,
2440
2405
  {
2441
- title: title ?? "Labkit",
2442
- mode,
2443
- ...pages ? { pages } : {},
2444
- ...path !== void 0 ? { path } : {},
2445
- children: null
2406
+ theme,
2407
+ selection: { mode: resolvedMode, density: density ?? "comfortable" },
2408
+ className: "lk-lab",
2409
+ children: /* @__PURE__ */ jsx(
2410
+ LabShell,
2411
+ {
2412
+ title: title ?? "Labkit",
2413
+ mode,
2414
+ ...pages ? { pages } : {},
2415
+ ...path !== void 0 ? { path } : {},
2416
+ children: null
2417
+ }
2418
+ )
2446
2419
  }
2447
- ) });
2420
+ );
2448
2421
  }
2449
2422
  var NEBULA_SLOTS = [
2450
2423
  { cx: "18%", cy: "30%", sx: "60%", sy: "80%", stop: "70%" },
@@ -2453,10 +2426,13 @@ var NEBULA_SLOTS = [
2453
2426
  { cx: "12%", cy: "82%", sx: "50%", sy: "70%", stop: "70%" },
2454
2427
  { cx: "85%", cy: "18%", sx: "55%", sy: "80%", stop: "70%" }
2455
2428
  ];
2456
- function buildNebula(colors) {
2457
- const blobs = colors.map((c8, i3) => {
2458
- const p2 = NEBULA_SLOTS[i3 % NEBULA_SLOTS.length];
2459
- return `radial-gradient(ellipse ${p2.sx} ${p2.sy} at ${p2.cx} ${p2.cy}, color-mix(in srgb, ${c8} 22%, transparent), transparent ${p2.stop})`;
2429
+ function buildNebula(list, theme, mode, density) {
2430
+ const ctx = { theme, resolved: resolveTheme(theme, { mode, density }) };
2431
+ const n5 = colorCount(list, ctx) ?? NEBULA_SLOTS.length;
2432
+ const colors = Array.from({ length: n5 }, (_2, i5) => colorAt(list, i5, ctx));
2433
+ const blobs = colors.map((c6, i5) => {
2434
+ const p3 = NEBULA_SLOTS[i5 % NEBULA_SLOTS.length];
2435
+ return `radial-gradient(ellipse ${p3.sx} ${p3.sy} at ${p3.cx} ${p3.cy}, color-mix(in srgb, ${c6} 22%, transparent), transparent ${p3.stop})`;
2460
2436
  });
2461
2437
  blobs.push("radial-gradient(ellipse at center, #0a0a18 0%, #02020a 100%)");
2462
2438
  return blobs.join(", ");
@@ -2476,7 +2452,7 @@ function LabPanes({
2476
2452
  void 0,
2477
2453
  { scope: "lab" }
2478
2454
  );
2479
- const main = contributions.some((c8) => c8.region === "aside") ? /* @__PURE__ */ jsx(
2455
+ const main = contributions.some((c6) => c6.region === "aside") ? /* @__PURE__ */ jsx(
2480
2456
  Split,
2481
2457
  {
2482
2458
  className: "lk-lab__panes",
@@ -2486,15 +2462,15 @@ function LabPanes({
2486
2462
  label: "Lab aside",
2487
2463
  defaultWidth: 320,
2488
2464
  width: asideWidth,
2489
- onWidthChange: (w3) => {
2490
- setAsideWidth(w3);
2465
+ onWidthChange: (w2) => {
2466
+ setAsideWidth(w2);
2491
2467
  surface?.invalidateRects();
2492
2468
  },
2493
2469
  sidebar: /* @__PURE__ */ jsx(LabAsideRegion, { contributions }),
2494
2470
  children
2495
2471
  }
2496
2472
  ) : children;
2497
- if (!contributions.some((c8) => c8.region === "sidebar")) return main;
2473
+ if (!contributions.some((c6) => c6.region === "sidebar")) return main;
2498
2474
  return /* @__PURE__ */ jsx(
2499
2475
  Split,
2500
2476
  {
@@ -2504,8 +2480,8 @@ function LabPanes({
2504
2480
  label: "Lab sidebar",
2505
2481
  defaultWidth: 260,
2506
2482
  width: sidebarWidth,
2507
- onWidthChange: (w3) => {
2508
- setSidebarWidth(w3);
2483
+ onWidthChange: (w2) => {
2484
+ setSidebarWidth(w2);
2509
2485
  surface?.invalidateRects();
2510
2486
  },
2511
2487
  sidebar: /* @__PURE__ */ jsx(LabSidebarRegion, { contributions }),
@@ -2524,13 +2500,25 @@ function Lab(props) {
2524
2500
  );
2525
2501
  if (!opened) {
2526
2502
  if (props.fallback !== void 0) return props.fallback;
2527
- return /* @__PURE__ */ jsx(LabFallback, { title: props.title, mode: props.mode, pages: props.pages, path: props.path });
2503
+ return /* @__PURE__ */ jsx(
2504
+ LabFallback,
2505
+ {
2506
+ title: props.title,
2507
+ mode: props.mode,
2508
+ density: props.density,
2509
+ ...props.theme ? { theme: props.theme } : {},
2510
+ pages: props.pages,
2511
+ path: props.path
2512
+ }
2513
+ );
2528
2514
  }
2529
2515
  return /* @__PURE__ */ jsx(LabRuntime, { ...props, opened });
2530
2516
  }
2531
2517
  function LabRuntime({
2532
2518
  instruments,
2533
2519
  mode,
2520
+ density,
2521
+ theme = interstellarTheme,
2534
2522
  nebula,
2535
2523
  title,
2536
2524
  pages,
@@ -2550,13 +2538,13 @@ function LabRuntime({
2550
2538
  useLayoutEffect(() => {
2551
2539
  store.getState().setInstruments(instruments);
2552
2540
  }, [instruments, store]);
2553
- const trials = useStore(store, (s5) => s5.trials);
2541
+ const trials = useStore(store, (s4) => s4.trials);
2554
2542
  const [focusPick, setFocusPick] = useState(null);
2555
2543
  const focusedTrialId = trials.some((t) => t.id === focusPick) ? focusPick : trials[0]?.id ?? null;
2556
- const savedSnapshots = useStore(store, (s5) => s5.savedSnapshots);
2557
- const modeValue = useStore(store, (s5) => s5.mode);
2558
- const layout = useStore(store, (s5) => s5.layout);
2559
- const undockedPanels = useStore(store, (s5) => s5.undockedPanels);
2544
+ const savedSnapshots = useStore(store, (s4) => s4.savedSnapshots);
2545
+ const modeValue = useStore(store, (s4) => s4.mode);
2546
+ const layout = useStore(store, (s4) => s4.layout);
2547
+ const undockedPanels = useStore(store, (s4) => s4.undockedPanels);
2560
2548
  const panelHostsRef = useRef(null);
2561
2549
  if (panelHostsRef.current === null) panelHostsRef.current = createPanelHostRegistry();
2562
2550
  const outerSurface = useSurfaceOptional();
@@ -2569,17 +2557,17 @@ function LabRuntime({
2569
2557
  const bufferRef = useRef({ w: 0, h: 0 });
2570
2558
  const surfaceRef = useRef(null);
2571
2559
  const onFrame = useCallback((frame) => {
2572
- const canvases = [ownUnderRef.current, ownOverRef.current].filter((c8) => c8 !== null);
2560
+ const canvases = [ownUnderRef.current, ownOverRef.current].filter((c6) => c6 !== null);
2573
2561
  if (canvases.length === 0) return;
2574
- const w3 = Math.round(frame.size.width * frame.dpr);
2575
- const h2 = Math.round(frame.size.height * frame.dpr);
2576
- if (bufferRef.current.w !== w3 || bufferRef.current.h !== h2) {
2577
- bufferRef.current = { w: w3, h: h2 };
2578
- for (const c8 of canvases) {
2579
- c8.width = w3;
2580
- c8.height = h2;
2581
- c8.style.width = `${frame.size.width}px`;
2582
- c8.style.height = `${frame.size.height}px`;
2562
+ const w2 = Math.round(frame.size.width * frame.dpr);
2563
+ const h = Math.round(frame.size.height * frame.dpr);
2564
+ if (bufferRef.current.w !== w2 || bufferRef.current.h !== h) {
2565
+ bufferRef.current = { w: w2, h };
2566
+ for (const c6 of canvases) {
2567
+ c6.width = w2;
2568
+ c6.height = h;
2569
+ c6.style.width = `${frame.size.width}px`;
2570
+ c6.style.height = `${frame.size.height}px`;
2583
2571
  }
2584
2572
  surfaceRef.current?.invalidateAll();
2585
2573
  return;
@@ -2637,14 +2625,14 @@ function LabRuntime({
2637
2625
  })),
2638
2626
  [undockedPanels]
2639
2627
  );
2640
- const resolvedMode = useResolvedMode(modeValue);
2641
- const annotates = instruments.some((i3) => i3.annotations != null);
2628
+ const resolvedMode = useResolvedColorMode(modeValue);
2629
+ const annotates = instruments.some((i5) => i5.annotations != null);
2642
2630
  const labChromeAll = useMemo(
2643
2631
  () => labContributions([...annotates ? ANNOTATION_TOOLS : [], ...tools ?? []], labChrome),
2644
2632
  [annotates, tools, labChrome]
2645
2633
  );
2646
- const hasFooterChrome = labChromeAll.some((c8) => c8.region === "footer");
2647
- const hasPaneChrome = labChromeAll.some((c8) => c8.region === "sidebar" || c8.region === "aside");
2634
+ const hasFooterChrome = labChromeAll.some((c6) => c6.region === "footer");
2635
+ const hasPaneChrome = labChromeAll.some((c6) => c6.region === "sidebar" || c6.region === "aside");
2648
2636
  useEffect(() => {
2649
2637
  if (mode && mode !== store.getState().mode) {
2650
2638
  store.getState().setMode(mode);
@@ -2652,14 +2640,14 @@ function LabRuntime({
2652
2640
  }, [mode, store]);
2653
2641
  const contextValue = useMemo(() => {
2654
2642
  const replaceTrials = (next) => {
2655
- const currentById = new Map(store.getState().trials.map((w3) => [w3.id, w3]));
2656
- const merged = next.map((w3) => currentById.get(w3.id) ?? w3);
2643
+ const currentById = new Map(store.getState().trials.map((w2) => [w2.id, w2]));
2644
+ const merged = next.map((w2) => currentById.get(w2.id) ?? w2);
2657
2645
  store.setState({ trials: merged });
2658
2646
  };
2659
2647
  const replaceAndFocusAdded = (next) => {
2660
- const before = new Set(store.getState().trials.map((w3) => w3.id));
2648
+ const before = new Set(store.getState().trials.map((w2) => w2.id));
2661
2649
  replaceTrials(next);
2662
- const added = next.find((w3) => !before.has(w3.id));
2650
+ const added = next.find((w2) => !before.has(w2.id));
2663
2651
  if (added) setFocusPick(added.id);
2664
2652
  };
2665
2653
  return {
@@ -2684,7 +2672,7 @@ function LabRuntime({
2684
2672
  const current = store.getState();
2685
2673
  const next = swapTrial(current.trials, instruments, id, instrumentName, options);
2686
2674
  if (next === current.trials) return;
2687
- const record = next[current.trials.findIndex((w3) => w3.id === id)];
2675
+ const record = next[current.trials.findIndex((w2) => w2.id === id)];
2688
2676
  const { [id]: extent, ...layoutRest } = current.layout;
2689
2677
  if (extent) current.setLayout({ ...layoutRest, [record.id]: extent });
2690
2678
  replaceTrials(next);
@@ -2694,17 +2682,17 @@ function LabRuntime({
2694
2682
  focusTrial: (id) => setFocusPick(id),
2695
2683
  resetTrial: (id) => {
2696
2684
  const next = resetTrial(store.getState().trials, id, instruments);
2697
- const record = next.find((w3) => w3.id === id);
2685
+ const record = next.find((w2) => w2.id === id);
2698
2686
  if (!record) return;
2699
- store.setState((s5) => ({
2700
- trials: s5.trials.map(
2701
- (w3) => w3.id === id ? { ...w3, config: record.config, state: record.state, view: record.view } : w3
2687
+ store.setState((s4) => ({
2688
+ trials: s4.trials.map(
2689
+ (w2) => w2.id === id ? { ...w2, config: record.config, state: record.state, view: record.view } : w2
2702
2690
  )
2703
2691
  }));
2704
2692
  },
2705
2693
  savedSnapshots,
2706
2694
  saveSnapshot: (trialId, name) => {
2707
- const taken = store.getState().savedSnapshots.filter((s5) => s5.trialId === trialId).length;
2695
+ const taken = store.getState().savedSnapshots.filter((s4) => s4.trialId === trialId).length;
2708
2696
  store.getState().saveSnapshot(trialId, name ?? `Snapshot ${taken + 1}`);
2709
2697
  },
2710
2698
  loadSnapshot: (trialId, snapshotId) => {
@@ -2714,8 +2702,8 @@ function LabRuntime({
2714
2702
  store.getState().deleteSnapshot(snapshotId);
2715
2703
  },
2716
2704
  mode: modeValue,
2717
- setMode: (m2) => {
2718
- store.getState().setMode(m2);
2705
+ setMode: (m3) => {
2706
+ store.getState().setMode(m3);
2719
2707
  },
2720
2708
  configRules,
2721
2709
  controls
@@ -2730,25 +2718,32 @@ function LabRuntime({
2730
2718
  configRules,
2731
2719
  controls
2732
2720
  ]);
2733
- const backdropStyle = resolvedMode === "dark" && nebula && nebula.length > 0 ? { ["--wzl-backdrop"]: buildNebula(nebula) } : void 0;
2721
+ const backdropStyle = resolvedMode === "dark" && nebula && colorCount(nebula) !== 0 ? {
2722
+ ["--wzl-backdrop"]: buildNebula(
2723
+ nebula,
2724
+ theme,
2725
+ resolvedMode,
2726
+ density ?? "comfortable"
2727
+ )
2728
+ } : void 0;
2734
2729
  const workspace = /* @__PURE__ */ jsx(
2735
2730
  Workspace,
2736
2731
  {
2737
2732
  panels: workspacePanels,
2738
- ids: trials.map((w3) => w3.id),
2733
+ ids: trials.map((w2) => w2.id),
2739
2734
  resizable: true,
2740
2735
  reorderable: true,
2741
2736
  onReorder: (ids) => contextValue.reorderTrials(ids),
2742
2737
  layout,
2743
2738
  onLayoutChange: (next) => store.getState().setLayout(next),
2744
- children: trials.map((w3) => /* @__PURE__ */ jsx(Trial, { id: w3.id, chrome, suppress }, w3.id))
2739
+ children: trials.map((w2) => /* @__PURE__ */ jsx(Trial, { id: w2.id, chrome, suppress }, w2.id))
2745
2740
  }
2746
2741
  );
2747
2742
  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(
2748
2743
  ThemeProvider,
2749
2744
  {
2750
- theme: interstellarTheme,
2751
- selection: { mode: resolvedMode },
2745
+ theme,
2746
+ selection: { mode: resolvedMode, density: density ?? "comfortable" },
2752
2747
  className: "lk-lab",
2753
2748
  style: backdropStyle,
2754
2749
  children: /* @__PURE__ */ jsx(
@@ -2810,6 +2805,9 @@ function LabRuntime({
2810
2805
  }
2811
2806
  ) }) }) }) });
2812
2807
  }
2808
+ function LabBoundary({ children }) {
2809
+ return /* @__PURE__ */ jsx(LabStoreContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PersistenceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationPreloadContext.Provider, { value: null, children: /* @__PURE__ */ jsx(LabContext.Provider, { value: null, children: /* @__PURE__ */ jsx(PanelHostContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(SurfaceCanvasContext.Provider, { value: { over: null, under: null }, children: /* @__PURE__ */ jsx(TrialIdContext.Provider, { value: null, children: /* @__PURE__ */ jsx(AnnotationsContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CameraWheelContext.Provider, { value: null, children: /* @__PURE__ */ jsx(CanvasStackContext.Provider, { value: null, children: /* @__PURE__ */ jsx(TrialDragContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ThemeContext.Provider, { value: null, children }) }) }) }) }) }) }) }) }) }) }) }) });
2810
+ }
2813
2811
  var SPECIMEN_SECTIONS = [
2814
2812
  "Buttons & toggles",
2815
2813
  "Fields & pickers",
@@ -2903,32 +2901,32 @@ function ButtonsAndToggles() {
2903
2901
  const [open, setOpen] = useState(true);
2904
2902
  return /* @__PURE__ */ jsxs(Section, { title: "Buttons & toggles", children: [
2905
2903
  /* @__PURE__ */ jsx(Cell, { label: "Button", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2906
- /* @__PURE__ */ jsx(a5, { variant: "primary", children: "Save" }),
2907
- /* @__PURE__ */ jsx(a5, { variant: "secondary", children: "Cancel" }),
2908
- /* @__PURE__ */ jsx(a5, { variant: "ghost", children: "Ghost" }),
2909
- /* @__PURE__ */ jsx(a5, { variant: "secondary", disabled: true, children: "Disabled" }),
2910
- /* @__PURE__ */ jsx(a5, { variant: "secondary", iconOnly: true, ariaLabel: "Add", children: /* @__PURE__ */ jsx(Dot, {}) })
2904
+ /* @__PURE__ */ jsx(c, { variant: "primary", children: "Save" }),
2905
+ /* @__PURE__ */ jsx(c, { variant: "secondary", children: "Cancel" }),
2906
+ /* @__PURE__ */ jsx(c, { variant: "ghost", children: "Ghost" }),
2907
+ /* @__PURE__ */ jsx(c, { variant: "secondary", disabled: true, children: "Disabled" }),
2908
+ /* @__PURE__ */ jsx(c, { variant: "secondary", iconOnly: true, ariaLabel: "Add", children: /* @__PURE__ */ jsx(Dot, {}) })
2911
2909
  ] }) }),
2912
2910
  /* @__PURE__ */ jsx(Cell, { label: "Badge", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2913
- /* @__PURE__ */ jsx(Lt, { shape: "pill", tone: "accent", variant: "outline", size: "sm", children: "ACCENT" }),
2914
- /* @__PURE__ */ jsx(Lt, { tone: "info", variant: "subtle", children: "INFO" }),
2915
- /* @__PURE__ */ jsx(Lt, { tone: "warn", variant: "solid", children: "WARN" }),
2916
- /* @__PURE__ */ jsx(Lt, { tone: "danger", variant: "solid", children: "DANGER" }),
2917
- /* @__PURE__ */ jsx(Lt, { tone: "muted", children: "MUTED" })
2911
+ /* @__PURE__ */ jsx(Ht, { shape: "pill", status: "accent", variant: "outline", size: "sm", children: "ACCENT" }),
2912
+ /* @__PURE__ */ jsx(Ht, { status: "info", variant: "subtle", children: "INFO" }),
2913
+ /* @__PURE__ */ jsx(Ht, { status: "warn", variant: "solid", children: "WARN" }),
2914
+ /* @__PURE__ */ jsx(Ht, { status: "danger", variant: "solid", children: "DANGER" }),
2915
+ /* @__PURE__ */ jsx(Ht, { status: "muted", children: "MUTED" })
2918
2916
  ] }) }),
2919
2917
  /* @__PURE__ */ jsx(Cell, { label: "Checkbox, Switch", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2920
2918
  /* @__PURE__ */ jsx(o2, { isSelected: snap, onChange: setSnap, children: "Snap to grid" }),
2921
2919
  /* @__PURE__ */ jsx(o2, { isIndeterminate: true, children: "Mixed" }),
2922
- /* @__PURE__ */ jsx(a4, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2920
+ /* @__PURE__ */ jsx(a6, { isSelected: wifi, onChange: setWifi, children: "Wifi" })
2923
2921
  ] }) }),
2924
- /* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l3, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
2925
- /* @__PURE__ */ jsx(u3, { value: "off", children: "Off" }),
2926
- /* @__PURE__ */ jsx(u3, { value: "grid", children: "Grid" }),
2927
- /* @__PURE__ */ jsx(u3, { value: "pixel", children: "Pixel" })
2922
+ /* @__PURE__ */ jsx(Cell, { label: "RadioGroup", children: /* @__PURE__ */ jsxs(l5, { label: "Snap mode", orientation: "horizontal", defaultValue: "grid", children: [
2923
+ /* @__PURE__ */ jsx(u5, { value: "off", children: "Off" }),
2924
+ /* @__PURE__ */ jsx(u5, { value: "grid", children: "Grid" }),
2925
+ /* @__PURE__ */ jsx(u5, { value: "pixel", children: "Pixel" })
2928
2926
  ] }) }),
2929
2927
  /* @__PURE__ */ jsxs(Cell, { label: "ToggleBar", children: [
2930
2928
  /* @__PURE__ */ jsx(
2931
- r3,
2929
+ a5,
2932
2930
  {
2933
2931
  ariaLabel: "Align",
2934
2932
  value: align,
@@ -2941,7 +2939,7 @@ function ButtonsAndToggles() {
2941
2939
  }
2942
2940
  ),
2943
2941
  /* @__PURE__ */ jsx(
2944
- r3,
2942
+ a5,
2945
2943
  {
2946
2944
  ariaLabel: "Align, flat",
2947
2945
  variant: "flat",
@@ -2955,9 +2953,9 @@ function ButtonsAndToggles() {
2955
2953
  }
2956
2954
  )
2957
2955
  ] }),
2958
- /* @__PURE__ */ jsx(Cell, { label: "OptionsBar, ActionsBar", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2956
+ /* @__PURE__ */ jsx(Cell, { label: "OptionsBar, ButtonBar", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2959
2957
  /* @__PURE__ */ jsx(
2960
- r7,
2958
+ r3,
2961
2959
  {
2962
2960
  ariaLabel: "Text style",
2963
2961
  items: [
@@ -2967,7 +2965,7 @@ function ButtonsAndToggles() {
2967
2965
  }
2968
2966
  ),
2969
2967
  /* @__PURE__ */ jsx(
2970
- r8,
2968
+ a7,
2971
2969
  {
2972
2970
  items: [
2973
2971
  { value: "undo", label: "Undo", onAction: () => {
@@ -2980,7 +2978,7 @@ function ButtonsAndToggles() {
2980
2978
  ] }) }),
2981
2979
  /* @__PURE__ */ jsx(Cell, { label: "MenuButton, Disclosure", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
2982
2980
  /* @__PURE__ */ jsx(
2983
- l7,
2981
+ d2,
2984
2982
  {
2985
2983
  label: "Add trial\u2026",
2986
2984
  onAction: () => {
@@ -2991,24 +2989,22 @@ function ButtonsAndToggles() {
2991
2989
  ]
2992
2990
  }
2993
2991
  ),
2994
- /* @__PURE__ */ jsx(r6, { open, onToggle: () => setOpen((o5) => !o5), label: "Shapes" }),
2995
- /* @__PURE__ */ jsx(r6, { open: false, onToggle: () => {
2996
- }, label: "Down", direction: "down" })
2992
+ /* @__PURE__ */ jsx(i3, { open, onToggle: () => setOpen((o4) => !o4), label: "Shapes" })
2997
2993
  ] }) }),
2998
- /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o5, { children: [
2999
- /* @__PURE__ */ jsxs(s5, { "aria-label": "Sections", children: [
3000
- /* @__PURE__ */ jsx(c6, { id: "props", children: "Props" }),
3001
- /* @__PURE__ */ jsx(c6, { id: "events", children: "Events" }),
3002
- /* @__PURE__ */ jsx(c6, { id: "snapshot", children: "Snapshot" })
2994
+ /* @__PURE__ */ jsx(Cell, { label: "Tabs", children: /* @__PURE__ */ jsxs(o4, { children: [
2995
+ /* @__PURE__ */ jsxs(s6, { "aria-label": "Sections", children: [
2996
+ /* @__PURE__ */ jsx(c5, { id: "props", children: "Props" }),
2997
+ /* @__PURE__ */ jsx(c5, { id: "events", children: "Events" }),
2998
+ /* @__PURE__ */ jsx(c5, { id: "snapshot", children: "Snapshot" })
3003
2999
  ] }),
3004
- /* @__PURE__ */ jsx(l6, { id: "props", children: "Props panel." }),
3005
- /* @__PURE__ */ jsx(l6, { id: "events", children: "Events panel." }),
3006
- /* @__PURE__ */ jsx(l6, { id: "snapshot", children: "Snapshot panel." })
3000
+ /* @__PURE__ */ jsx(l7, { id: "props", children: "Props panel." }),
3001
+ /* @__PURE__ */ jsx(l7, { id: "events", children: "Events panel." }),
3002
+ /* @__PURE__ */ jsx(l7, { id: "snapshot", children: "Snapshot panel." })
3007
3003
  ] }) }),
3008
3004
  /* @__PURE__ */ jsx(Cell, { label: "Keycaps", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3009
- /* @__PURE__ */ jsx(c3, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
3010
- /* @__PURE__ */ jsx(s3, { label: "K" }),
3011
- /* @__PURE__ */ jsx(s3, { label: "\u2325", variant: "minimal" })
3005
+ /* @__PURE__ */ jsx(p, { keys: [{ label: "\u2318" }, { label: "\u21E7" }, { label: "K" }], separator: "+" }),
3006
+ /* @__PURE__ */ jsx(f2, { label: "K" }),
3007
+ /* @__PURE__ */ jsx(f2, { label: "\u2325", variant: "minimal" })
3012
3008
  ] }) })
3013
3009
  ] });
3014
3010
  }
@@ -3029,9 +3025,9 @@ function FieldsAndPickers() {
3029
3025
  const [paint, setPaint] = useState({ fill: "solid", color: "#b08adb" });
3030
3026
  return /* @__PURE__ */ jsxs(Section, { title: "Fields & pickers", children: [
3031
3027
  /* @__PURE__ */ jsxs(Cell, { label: "Input", children: [
3032
- /* @__PURE__ */ jsx(u2, { label: "Name", placeholder: "e.g. Pico" }),
3028
+ /* @__PURE__ */ jsx(u4, { label: "Name", placeholder: "e.g. Pico" }),
3033
3029
  /* @__PURE__ */ jsx(
3034
- u2,
3030
+ u4,
3035
3031
  {
3036
3032
  label: "Size",
3037
3033
  leadingAdornment: /* @__PURE__ */ jsx("span", { children: "W" }),
@@ -3039,12 +3035,12 @@ function FieldsAndPickers() {
3039
3035
  defaultValue: "120"
3040
3036
  }
3041
3037
  ),
3042
- /* @__PURE__ */ jsx(u2, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3038
+ /* @__PURE__ */ jsx(u4, { label: "Required", isInvalid: true, errorMessage: "Name is required." })
3043
3039
  ] }),
3044
3040
  /* @__PURE__ */ jsxs(Cell, { label: "NumberField, Select, ComboBox", children: [
3045
- /* @__PURE__ */ jsx(g2, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3041
+ /* @__PURE__ */ jsx(g, { label: "Opacity", minValue: 0, maxValue: 100, step: 5, defaultValue: 80 }),
3046
3042
  /* @__PURE__ */ jsx(
3047
- g,
3043
+ T2,
3048
3044
  {
3049
3045
  label: "Color",
3050
3046
  defaultSelectedKey: "g",
@@ -3068,19 +3064,19 @@ function FieldsAndPickers() {
3068
3064
  )
3069
3065
  ] }),
3070
3066
  /* @__PURE__ */ jsxs(Cell, { label: "RangeSlider, Slider", children: [
3071
- /* @__PURE__ */ jsx(l4, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3067
+ /* @__PURE__ */ jsx(l8, { label: "Range", defaultValue: [20, 80], minValue: 0, maxValue: 100 }),
3072
3068
  /* @__PURE__ */ jsx(
3073
- l4,
3069
+ l8,
3074
3070
  {
3075
3071
  label: "Opacity",
3076
3072
  defaultValue: 75,
3077
3073
  minValue: 0,
3078
3074
  maxValue: 100,
3079
- formatOutput: (v2) => `${v2}%`
3075
+ formatOutput: (v) => `${v}%`
3080
3076
  }
3081
3077
  ),
3082
3078
  /* @__PURE__ */ jsx(
3083
- b2,
3079
+ b,
3084
3080
  {
3085
3081
  ariaLabel: "Pair",
3086
3082
  min: 0,
@@ -3095,18 +3091,18 @@ function FieldsAndPickers() {
3095
3091
  ] }),
3096
3092
  /* @__PURE__ */ jsxs(Cell, { label: "DetentSlider, InlineRange", children: [
3097
3093
  /* @__PURE__ */ jsx(
3098
- c7,
3094
+ c6,
3099
3095
  {
3100
3096
  items: [0.25, 0.5, 1, 2, 4],
3101
3097
  value: rate,
3102
3098
  onChange: setRate,
3103
- formatLabel: (r10) => `${r10}\xD7`,
3099
+ formatLabel: (r4) => `${r4}\xD7`,
3104
3100
  labels: "all",
3105
3101
  ariaLabel: "Playback rate"
3106
3102
  }
3107
3103
  ),
3108
3104
  /* @__PURE__ */ jsx(
3109
- r2,
3105
+ i4,
3110
3106
  {
3111
3107
  "aria-label": "Width",
3112
3108
  min: 0,
@@ -3117,8 +3113,8 @@ function FieldsAndPickers() {
3117
3113
  )
3118
3114
  ] }),
3119
3115
  /* @__PURE__ */ jsxs(Cell, { label: "ColorField, GradientEditor", children: [
3120
- /* @__PURE__ */ jsx(l2, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3121
- /* @__PURE__ */ jsx(C2, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3116
+ /* @__PURE__ */ jsx(l4, { value: color, alpha: true, onInput: setColor, onChange: setColor, "aria-label": "Color" }),
3117
+ /* @__PURE__ */ jsx(C, { value: gradient, onInput: setGradient, onChange: setGradient, kindSwitch: true })
3122
3118
  ] }),
3123
3119
  /* @__PURE__ */ jsx(Cell, { label: "PaintInput", children: /* @__PURE__ */ jsx(
3124
3120
  S,
@@ -3150,10 +3146,12 @@ function PanelsAndRows() {
3150
3146
  ]);
3151
3147
  const [panelCollapsed, setPanelCollapsed] = useState(false);
3152
3148
  return /* @__PURE__ */ jsxs(Section, { title: "Panels & property rows", children: [
3153
- /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(O, { title: "Shape", children: /* @__PURE__ */ jsxs(k, { children: [
3149
+ /* @__PURE__ */ jsx(Cell, { label: "PropertyPanel", children: /* @__PURE__ */ jsx(ae, { title: "Shape", children: /* @__PURE__ */ jsxs(oe2, { children: [
3154
3150
  /* @__PURE__ */ jsx(
3155
- F2,
3151
+ B,
3156
3152
  {
3153
+ kind: "number",
3154
+ control: "slider",
3157
3155
  label: "Opacity",
3158
3156
  value: opacity,
3159
3157
  min: 0,
@@ -3163,8 +3161,10 @@ function PanelsAndRows() {
3163
3161
  }
3164
3162
  ),
3165
3163
  /* @__PURE__ */ jsx(
3166
- F2,
3164
+ B,
3167
3165
  {
3166
+ kind: "number",
3167
+ control: "slider",
3168
3168
  label: "Radius",
3169
3169
  value: radius,
3170
3170
  min: 0,
@@ -3174,8 +3174,9 @@ function PanelsAndRows() {
3174
3174
  }
3175
3175
  ),
3176
3176
  /* @__PURE__ */ jsx(
3177
- L3,
3177
+ B,
3178
3178
  {
3179
+ kind: "color",
3179
3180
  label: "Fill",
3180
3181
  value: fill,
3181
3182
  onChange: setFill,
@@ -3183,11 +3184,12 @@ function PanelsAndRows() {
3183
3184
  onAlphaChange: setAlpha
3184
3185
  }
3185
3186
  ),
3186
- /* @__PURE__ */ jsx(L3, { label: "Stroke", value: stroke, onChange: setStroke }),
3187
- /* @__PURE__ */ jsx(V, { label: "Count", value: count, min: 0, max: 100, step: 1, onChange: setCount }),
3187
+ /* @__PURE__ */ jsx(B, { kind: "color", label: "Stroke", value: stroke, onChange: setStroke }),
3188
+ /* @__PURE__ */ jsx(B, { kind: "number", label: "Count", value: count, min: 0, max: 100, step: 1, onChange: setCount }),
3188
3189
  /* @__PURE__ */ jsx(
3189
- H,
3190
+ B,
3190
3191
  {
3192
+ kind: "enum",
3191
3193
  label: "Line cap",
3192
3194
  value: cap,
3193
3195
  onChange: setCap,
@@ -3198,8 +3200,10 @@ function PanelsAndRows() {
3198
3200
  }
3199
3201
  ),
3200
3202
  /* @__PURE__ */ jsx(
3201
- U,
3203
+ B,
3202
3204
  {
3205
+ kind: "enum",
3206
+ control: "toggle",
3203
3207
  label: "Align",
3204
3208
  value: side,
3205
3209
  onChange: setSide,
@@ -3210,9 +3214,9 @@ function PanelsAndRows() {
3210
3214
  ]
3211
3215
  }
3212
3216
  ),
3213
- /* @__PURE__ */ jsx(B, { label: "Label", value: label, onChange: setLabel }),
3214
- /* @__PURE__ */ jsx(R2, { label: "Visible", value: visible, onChange: setVisible }),
3215
- /* @__PURE__ */ jsx(J, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(F2, { label: "Rings", value: 32, min: 4, max: 96, step: 1, onChange: () => {
3217
+ /* @__PURE__ */ jsx(B, { kind: "string", label: "Label", value: label, onChange: setLabel }),
3218
+ /* @__PURE__ */ jsx(B, { kind: "boolean", label: "Visible", value: visible, onChange: setVisible }),
3219
+ /* @__PURE__ */ jsx(b2, { title: "Bevel", defaultCollapsed: true, children: /* @__PURE__ */ jsx(B, { kind: "number", control: "slider", label: "Rings", value: 32, min: 4, max: 96, step: 1, onChange: () => {
3216
3220
  } }) })
3217
3221
  ] }) }) }),
3218
3222
  /* @__PURE__ */ jsx(Cell, { label: "PrefsForm", children: /* @__PURE__ */ jsx(
@@ -3223,23 +3227,23 @@ function PanelsAndRows() {
3223
3227
  onChange: (path, value) => setPrefs((prev) => setAt(prev, path, value))
3224
3228
  }
3225
3229
  ) }),
3226
- /* @__PURE__ */ jsx(Cell, { label: "LayerStack", children: /* @__PURE__ */ jsx(
3227
- c4,
3230
+ /* @__PURE__ */ jsx(Cell, { label: "LayerList", children: /* @__PURE__ */ jsx(
3231
+ D,
3228
3232
  {
3229
3233
  items: layers,
3230
- onReorder: (ids) => setLayers(ids.flatMap((id) => layers.filter((item) => item.id === id))),
3234
+ onReorder: (move) => setLayers(S2(layers, move)),
3231
3235
  renderBody: (item) => /* @__PURE__ */ jsxs("div", { children: [
3232
3236
  "settings for ",
3233
3237
  item.label
3234
3238
  ] })
3235
3239
  }
3236
3240
  ) }),
3237
- /* @__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(
3238
- s4,
3241
+ /* @__PURE__ */ jsx(Cell, { label: "Sidebar, SidebarPanel", children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__box", children: /* @__PURE__ */ jsx(n6, { side: "right", ariaLabel: "Specimen sidebar", children: /* @__PURE__ */ jsx(
3242
+ s5,
3239
3243
  {
3240
3244
  title: "Selection",
3241
3245
  collapsed: panelCollapsed,
3242
- onToggleCollapse: () => setPanelCollapsed((v2) => !v2),
3246
+ onToggleCollapse: () => setPanelCollapsed((v) => !v),
3243
3247
  onHide: () => {
3244
3248
  },
3245
3249
  children: /* @__PURE__ */ jsx("div", { className: "lk-specimen__pad", children: "2 items selected" })
@@ -3251,38 +3255,38 @@ function OverlaysAndFeedback() {
3251
3255
  const calloutAnchor = useRef(null);
3252
3256
  const [calloutOpen, setCalloutOpen] = useState(false);
3253
3257
  const [dialogOpen, setDialogOpen] = useState(false);
3254
- const toasts = useMemo(() => m2(), []);
3258
+ const toasts = useMemo(() => m4(), []);
3255
3259
  return /* @__PURE__ */ jsxs(Section, { title: "Overlays & feedback", children: [
3256
3260
  /* @__PURE__ */ jsx(Cell, { label: "Tooltip, Callout, Dialog, Toast", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__row", children: [
3257
- /* @__PURE__ */ jsxs(c2, { children: [
3261
+ /* @__PURE__ */ jsxs(l2, { children: [
3258
3262
  /* @__PURE__ */ jsx(Focusable, { children: /* @__PURE__ */ jsx("button", { type: "button", children: "Hover me" }) }),
3259
- /* @__PURE__ */ jsx(l, { placement: "bottom", children: "Duplicates the selected layer" })
3263
+ /* @__PURE__ */ jsx(u, { placement: "bottom", children: "Duplicates the selected layer" })
3260
3264
  ] }),
3261
3265
  /* @__PURE__ */ jsx("button", { type: "button", ref: calloutAnchor, onClick: () => setCalloutOpen(true), children: "Callout" }),
3262
3266
  /* @__PURE__ */ jsx(
3263
- g3,
3267
+ g2,
3264
3268
  {
3265
3269
  triggerRef: calloutAnchor,
3266
3270
  isOpen: calloutOpen,
3267
3271
  onOpenChange: setCalloutOpen,
3268
- tone: "info",
3269
- title: "Info",
3272
+ stance: "notice",
3273
+ title: "Notice",
3270
3274
  children: "Neutral guidance."
3271
3275
  }
3272
3276
  ),
3273
- /* @__PURE__ */ jsx(a5, { onClick: () => setDialogOpen(true), children: "Dialog" }),
3277
+ /* @__PURE__ */ jsx(c, { onClick: () => setDialogOpen(true), children: "Dialog" }),
3274
3278
  /* @__PURE__ */ jsx(
3275
- l5,
3279
+ u3,
3276
3280
  {
3277
3281
  isOpen: dialogOpen,
3278
3282
  onOpenChange: setDialogOpen,
3279
3283
  title: "Preferences",
3280
- footer: /* @__PURE__ */ jsx(a5, { variant: "primary", onClick: () => setDialogOpen(false), children: "OK" }),
3284
+ footer: /* @__PURE__ */ jsx(c, { variant: "primary", onClick: () => setDialogOpen(false), children: "OK" }),
3281
3285
  children: /* @__PURE__ */ jsx("p", { children: "Dialog body." })
3282
3286
  }
3283
3287
  ),
3284
3288
  /* @__PURE__ */ jsx(
3285
- a5,
3289
+ c,
3286
3290
  {
3287
3291
  onClick: () => toasts.add("success", "Saved", { description: "All changes stored.", ttlMs: null }),
3288
3292
  children: "Toast"
@@ -3291,29 +3295,29 @@ function OverlaysAndFeedback() {
3291
3295
  /* @__PURE__ */ jsx(S4, { queue: toasts, placement: "bottom-right" })
3292
3296
  ] }) }),
3293
3297
  /* @__PURE__ */ jsx(Cell, { label: "Powerline", children: /* @__PURE__ */ jsx(
3294
- r10,
3298
+ r4,
3295
3299
  {
3296
3300
  variant: "solid",
3297
3301
  size: "sm",
3298
3302
  segments: [
3299
- { text: "main", tone: "accent", endCap: "chevron" },
3300
- { text: "\u2713 12", tone: "info", endCap: "slant" },
3301
- { text: "~/proj", tone: "muted" }
3303
+ { text: "main", status: "accent", endCap: "chevron" },
3304
+ { text: "\u2713 12", status: "info", endCap: "slant" },
3305
+ { text: "~/proj", status: "muted" }
3302
3306
  ]
3303
3307
  }
3304
3308
  ) }),
3305
- /* @__PURE__ */ jsx(Cell, { label: "StatusBar", children: /* @__PURE__ */ jsxs(n6, { ariaLabel: "Editor status", children: [
3306
- /* @__PURE__ */ jsx(r11, { children: "tool: select" }),
3307
- /* @__PURE__ */ jsx(r11, { children: "sel: 3" }),
3309
+ /* @__PURE__ */ jsx(Cell, { label: "StatusBar", children: /* @__PURE__ */ jsxs(n7, { ariaLabel: "Editor status", children: [
3310
+ /* @__PURE__ */ jsx(r5, { children: "tool: select" }),
3311
+ /* @__PURE__ */ jsx(r5, { children: "sel: 3" }),
3308
3312
  /* @__PURE__ */ jsx(i5, {}),
3309
- /* @__PURE__ */ jsx(r11, { muted: true, children: "0.7.0" })
3313
+ /* @__PURE__ */ jsx(r5, { muted: true, children: "0.7.0" })
3310
3314
  ] }) })
3311
3315
  ] });
3312
3316
  }
3313
3317
  function ListsAndData() {
3314
3318
  return /* @__PURE__ */ jsxs(Section, { title: "Lists & data", children: [
3315
3319
  /* @__PURE__ */ jsx(Cell, { label: "ItemList", children: /* @__PURE__ */ jsx(
3316
- i4,
3320
+ p2,
3317
3321
  {
3318
3322
  rows: [
3319
3323
  { id: "a", label: "Draw rect" },
@@ -3324,7 +3328,7 @@ function ListsAndData() {
3324
3328
  }
3325
3329
  ) }),
3326
3330
  /* @__PURE__ */ jsx(Cell, { label: "DataGrid", children: /* @__PURE__ */ jsx(
3327
- s2,
3331
+ f,
3328
3332
  {
3329
3333
  rows: [
3330
3334
  { id: "1", name: "accent", count: 3 },
@@ -3332,8 +3336,8 @@ function ListsAndData() {
3332
3336
  { id: "3", name: "danger", count: 2 }
3333
3337
  ],
3334
3338
  columns: [
3335
- { id: "name", header: "name", accessor: (r10) => r10.name, sortable: true },
3336
- { id: "count", header: "count", accessor: (r10) => r10.count, sortable: true }
3339
+ { id: "name", header: "name", accessor: (r4) => r4.name, sortable: true },
3340
+ { id: "count", header: "count", accessor: (r4) => r4.count, sortable: true }
3337
3341
  ],
3338
3342
  defaultSort: { columnId: "name", direction: "asc" }
3339
3343
  }
@@ -3344,8 +3348,8 @@ function ToolChrome() {
3344
3348
  const [tool, setTool] = useState("select");
3345
3349
  const [paneWidth, setPaneWidth] = useState(160);
3346
3350
  return /* @__PURE__ */ jsxs(Section, { title: "Tool chrome", children: [
3347
- /* @__PURE__ */ jsx(Cell, { label: "ToolGroup, ToolButton", children: /* @__PURE__ */ jsx(n7, { orientation: "horizontal", ariaLabel: "Tools", children: ["select", "rect", "ellipse"].map((id) => /* @__PURE__ */ jsx(
3348
- o4,
3351
+ /* @__PURE__ */ jsx(Cell, { label: "ToolGroup, ToolButton", children: /* @__PURE__ */ jsx(n8, { orientation: "horizontal", ariaLabel: "Tools", children: ["select", "rect", "ellipse"].map((id) => /* @__PURE__ */ jsx(
3352
+ o3,
3349
3353
  {
3350
3354
  icon: /* @__PURE__ */ jsx(Dot, {}),
3351
3355
  label: id,
@@ -3356,14 +3360,14 @@ function ToolChrome() {
3356
3360
  },
3357
3361
  id
3358
3362
  )) }) }),
3359
- /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(r9, { label: "Text", children: [
3360
- /* @__PURE__ */ jsx(a5, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
3361
- /* @__PURE__ */ jsx(a5, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
3363
+ /* @__PURE__ */ jsx(Cell, { label: "ToolOptionsBar", children: /* @__PURE__ */ jsxs(c3, { label: "Text", children: [
3364
+ /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Bold", children: "B" }),
3365
+ /* @__PURE__ */ jsx(c, { size: "sm", variant: "ghost", iconOnly: true, ariaLabel: "Italic", children: "I" })
3362
3366
  ] }) }),
3363
3367
  /* @__PURE__ */ jsx(Cell, { label: "ResizeHandle", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
3364
3368
  /* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "content" }),
3365
3369
  /* @__PURE__ */ jsx(
3366
- c5,
3370
+ c4,
3367
3371
  {
3368
3372
  value: paneWidth,
3369
3373
  min: 100,
@@ -3432,7 +3436,7 @@ function EditorsAndPlots() {
3432
3436
  const [playhead, setPlayhead] = useState(0);
3433
3437
  return /* @__PURE__ */ jsxs(Section, { title: "Editors & plots", children: [
3434
3438
  /* @__PURE__ */ jsx(Cell, { label: "Plot2D", children: /* @__PURE__ */ jsx(
3435
- w2,
3439
+ w,
3436
3440
  {
3437
3441
  width: 260,
3438
3442
  height: 130,
@@ -3443,7 +3447,7 @@ function EditorsAndPlots() {
3443
3447
  }
3444
3448
  ) }),
3445
3449
  /* @__PURE__ */ jsx(Cell, { label: "CurveEditor", children: /* @__PURE__ */ jsx(
3446
- L2,
3450
+ L,
3447
3451
  {
3448
3452
  value: curve,
3449
3453
  onInput: setCurve,
@@ -3458,7 +3462,7 @@ function EditorsAndPlots() {
3458
3462
  }
3459
3463
  ) }),
3460
3464
  /* @__PURE__ */ jsx(Cell, { label: "PointPlotter", children: /* @__PURE__ */ jsx(
3461
- n8,
3465
+ n9,
3462
3466
  {
3463
3467
  value: points,
3464
3468
  onInput: setPoints,
@@ -3472,7 +3476,7 @@ function EditorsAndPlots() {
3472
3476
  }
3473
3477
  ) }),
3474
3478
  /* @__PURE__ */ jsx(Cell, { label: "BandEditor", wide: true, children: /* @__PURE__ */ jsx(
3475
- k2,
3479
+ k,
3476
3480
  {
3477
3481
  min: 1 / 64,
3478
3482
  max: 1 / 2,
@@ -3482,7 +3486,7 @@ function EditorsAndPlots() {
3482
3486
  onChange: setBands,
3483
3487
  selectedIndex: band,
3484
3488
  onSelect: setBand,
3485
- renderBand: (b2) => b2.data.name,
3489
+ renderBand: (b3) => b3.data.name,
3486
3490
  ticks: [1 / 24, 1 / 12, 1 / 6].map((at) => ({ at, label: `1/${Math.round(1 / at)}` }))
3487
3491
  }
3488
3492
  ) }),
@@ -3499,7 +3503,6 @@ function EditorsAndPlots() {
3499
3503
  ] });
3500
3504
  }
3501
3505
  function LabChrome() {
3502
- const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
3503
3506
  const [zoom, setZoom] = useState(1);
3504
3507
  return /* @__PURE__ */ jsxs(Section, { title: "Lab chrome", children: [
3505
3508
  /* @__PURE__ */ jsx(Cell, { label: "Toolbar", wide: true, children: /* @__PURE__ */ jsxs(Toolbar, { "aria-label": "Trial actions", children: [
@@ -3517,18 +3520,6 @@ function LabChrome() {
3517
3520
  /* @__PURE__ */ jsx(StatusBar.Section, { children: "Items: 12" }),
3518
3521
  /* @__PURE__ */ jsx(StatusBar.Section, { children: "Zoom: 100%" })
3519
3522
  ] }) }),
3520
- /* @__PURE__ */ jsx(Cell, { label: "Sidebar", children: /* @__PURE__ */ jsxs("div", { className: "lk-specimen__box", children: [
3521
- /* @__PURE__ */ jsx("div", { className: "lk-specimen__box-main", children: "main" }),
3522
- /* @__PURE__ */ jsx(
3523
- Sidebar,
3524
- {
3525
- title: "Controls",
3526
- collapsed: sidebarCollapsed,
3527
- onToggle: () => setSidebarCollapsed((v2) => !v2),
3528
- children: /* @__PURE__ */ jsx("p", { children: "One slider" })
3529
- }
3530
- )
3531
- ] }) }),
3532
3523
  /* @__PURE__ */ jsxs(Cell, { label: "Legend, JobProgress", children: [
3533
3524
  /* @__PURE__ */ jsx(Legend, { entries: LEGEND }),
3534
3525
  /* @__PURE__ */ jsx(JobProgress, { job: JOB })
@@ -3563,6 +3554,6 @@ function Specimen({ className }) {
3563
3554
  ] });
3564
3555
  }
3565
3556
 
3566
- 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 };
3557
+ export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, AnnotationOverlay, AnnotationTargets, Lab, LabBoundary, 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 };
3567
3558
  //# sourceMappingURL=index.js.map
3568
3559
  //# sourceMappingURL=index.js.map