@weasel-js/labkit 1.6.1 → 1.7.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 (162) hide show
  1. package/dist/_dts/{CanvasStackContext-Wo6OwIVM.d.ts → CanvasStackContext-D2jnIwfk.d.ts} +1 -1
  2. package/dist/_dts/{LayerList.d-BoELAMsM.d.ts → LayerList.d-DiuEArKq.d.ts} +2 -2
  3. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +79 -0
  4. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +141 -0
  5. package/dist/_dts/{Select.d-Cr8-zoup.d.ts → Select.d-Bensr_MT.d.ts} +11 -1
  6. package/dist/_dts/{Stage-DWBBi8IU.d.ts → Stage-CCWfQQWM.d.ts} +58 -18
  7. package/dist/_dts/index-B2Yj5aA0.d.ts +274 -0
  8. package/dist/_dts/{index-CKyX0ME_.d.ts → index-CsYqUHD3.d.ts} +2 -2
  9. package/dist/_dts/{types-DTuViBvc.d.ts → types-CRPSGFAp.d.ts} +13 -4
  10. package/dist/_dts/{types-B7yBTTF9.d.ts → types-CSm9jgol.d.ts} +2 -2
  11. package/dist/_dts/{useTrialState-CMaV6UD4.d.ts → useTrialState-CTZPgeZ7.d.ts} +1 -1
  12. package/dist/canvas/index.d.ts +6 -6
  13. package/dist/canvas/index.js +2 -2
  14. package/dist/chrome/index.d.ts +5 -5
  15. package/dist/chrome/index.js +8 -8
  16. package/dist/{chunk-QGMOA2YE.js → chunk-275JRRVD.js} +67 -70
  17. package/dist/chunk-275JRRVD.js.map +1 -0
  18. package/dist/{chunk-KHK5FGER.js → chunk-4LJSC7MB.js} +8 -10
  19. package/dist/chunk-4LJSC7MB.js.map +1 -0
  20. package/dist/{chunk-SLAQPUI4.js → chunk-7BO7HNGF.js} +5 -5
  21. package/dist/{chunk-SLAQPUI4.js.map → chunk-7BO7HNGF.js.map} +1 -1
  22. package/dist/chunk-CZZPXUOU.js +3 -0
  23. package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
  24. package/dist/{chunk-6FLXL3I7.js → chunk-FMK7UQ6V.js} +19 -4
  25. package/dist/chunk-FMK7UQ6V.js.map +1 -0
  26. package/dist/{chunk-O6FFFOHS.js → chunk-FZ7YFQN7.js} +16 -8
  27. package/dist/chunk-FZ7YFQN7.js.map +1 -0
  28. package/dist/{chunk-GHGO52SO.js → chunk-GOZLNM4L.js} +5 -5
  29. package/dist/{chunk-GHGO52SO.js.map → chunk-GOZLNM4L.js.map} +1 -1
  30. package/dist/{chunk-4TT3PNPR.js → chunk-I5DUQ5HM.js} +33 -36
  31. package/dist/chunk-I5DUQ5HM.js.map +1 -0
  32. package/dist/{chunk-NEXR37YJ.js → chunk-J7OWWTCW.js} +4 -5
  33. package/dist/chunk-J7OWWTCW.js.map +1 -0
  34. package/dist/{chunk-IRTGUQ5O.js → chunk-KMJ7RWD3.js} +16 -6
  35. package/dist/chunk-KMJ7RWD3.js.map +1 -0
  36. package/dist/{chunk-S4NCI32V.js → chunk-M7HP3FTK.js} +4 -4
  37. package/dist/{chunk-S4NCI32V.js.map → chunk-M7HP3FTK.js.map} +1 -1
  38. package/dist/chunk-MIM5R4ZT.js +14972 -0
  39. package/dist/chunk-MIM5R4ZT.js.map +1 -0
  40. package/dist/{chunk-ASOK76ZH.js → chunk-T5IBSPAM.js} +59 -26
  41. package/dist/chunk-T5IBSPAM.js.map +1 -0
  42. package/dist/{chunk-DWMSB4CA.js → chunk-UNAZSLWE.js} +82 -16
  43. package/dist/chunk-UNAZSLWE.js.map +1 -0
  44. package/dist/{chunk-TJ77A4A3.js → chunk-Y23G2VZL.js} +5 -9
  45. package/dist/chunk-Y23G2VZL.js.map +1 -0
  46. package/dist/{chunk-HKV7LRHY.js → chunk-YT75VYRD.js} +4 -4
  47. package/dist/{chunk-HKV7LRHY.js.map → chunk-YT75VYRD.js.map} +1 -1
  48. package/dist/{chunk-CGHF6RZV.js → chunk-ZIFPHIWZ.js} +9 -7
  49. package/dist/chunk-ZIFPHIWZ.js.map +1 -0
  50. package/dist/config/index.d.ts +16 -9
  51. package/dist/config/index.js +4 -4
  52. package/dist/controls/index.d.ts +2 -2
  53. package/dist/controls/index.js +5 -5
  54. package/dist/dragdrop/index.d.ts +3 -3
  55. package/dist/index.d.ts +263 -24
  56. package/dist/index.js +376 -237
  57. package/dist/index.js.map +1 -1
  58. package/dist/layers/index.d.ts +4 -4
  59. package/dist/layers/index.js +2 -2
  60. package/dist/loupe/index.d.ts +4 -4
  61. package/dist/loupe/index.js +2 -2
  62. package/dist/overview/index.d.ts +2 -2
  63. package/dist/overview/index.js +9 -8
  64. package/dist/overview/index.js.map +1 -1
  65. package/dist/passthrough/weasel-ui.d.ts +208 -38
  66. package/dist/passthrough/weasel-ui.js +3 -3
  67. package/dist/primitives/index.d.ts +3 -178
  68. package/dist/primitives/index.js +6 -6
  69. package/dist/state/index.d.ts +5 -5
  70. package/dist/state/index.js +4 -4
  71. package/dist/styles.css +91 -83
  72. package/dist/undo/index.d.ts +3 -3
  73. package/package.json +13 -12
  74. package/src/annotations/AnnotationOverlay.tsx +2 -2
  75. package/src/annotations/Annotations.less +0 -10
  76. package/src/annotations/MarkList.tsx +4 -8
  77. package/src/annotations/paint.test.ts +3 -14
  78. package/src/annotations/paint.ts +3 -19
  79. package/src/annotations/svgNodes.test.ts +6 -9
  80. package/src/annotations/svgNodes.ts +3 -3
  81. package/src/canvas/AGENTS.md +1 -0
  82. package/src/canvas/CameraInput.tsx +44 -33
  83. package/src/canvas/CanvasStack.tsx +6 -1
  84. package/src/canvas/LinkedCursor.less +1 -1
  85. package/src/canvas/Stage.test.tsx +33 -4
  86. package/src/canvas/Stage.tsx +6 -1
  87. package/src/canvas/cameraRegistry.test.ts +55 -0
  88. package/src/canvas/cameraRegistry.ts +86 -0
  89. package/src/canvas/cameraZoom.test.ts +46 -0
  90. package/src/canvas/cameraZoom.ts +24 -0
  91. package/src/canvas/index.ts +14 -2
  92. package/src/canvas/sharedScope.test.tsx +94 -0
  93. package/src/chrome/ChromeRegions.stories.tsx +1 -0
  94. package/src/chrome/regions/PaletteRegion.less +0 -7
  95. package/src/chrome/regions/SidebarRegion.less +12 -2
  96. package/src/config/builder.test.ts +2 -1
  97. package/src/config/builder.ts +12 -5
  98. package/src/config/fromConfigField.test.ts +14 -0
  99. package/src/config/fromConfigField.ts +18 -4
  100. package/src/config/path.ts +2 -5
  101. package/src/config/resolve.ts +4 -0
  102. package/src/config/types.ts +13 -9
  103. package/src/controls/ControlPanel.less +1 -1
  104. package/src/controls/ControlPanel.stories.tsx +3 -2
  105. package/src/controls/ControlPanel.test.tsx +64 -11
  106. package/src/controls/ControlPanel.tsx +52 -2
  107. package/src/index.ts +15 -1
  108. package/src/lab/Lab.tsx +83 -72
  109. package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
  110. package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
  111. package/src/lab/LabFullChrome.stories.tsx +1 -0
  112. package/src/lab/LabHeader.test.tsx +24 -14
  113. package/src/lab/LabHeader.tsx +11 -12
  114. package/src/lab/LabShell.less +8 -17
  115. package/src/lab/LabSwitcher.less +6 -6
  116. package/src/lab/LabZoom.test.tsx +223 -0
  117. package/src/lab/LabZoom.tsx +170 -0
  118. package/src/lab/index.ts +1 -0
  119. package/src/loupe/LoupeGestures.tsx +1 -1
  120. package/src/overview/TrialOverview.tsx +7 -5
  121. package/src/passthrough/weasel-ui.test.ts +2 -0
  122. package/src/passthrough/weasel-ui.ts +16 -4
  123. package/src/primitives/FloatingPanel.test.tsx +11 -0
  124. package/src/primitives/FloatingPanel.tsx +2 -5
  125. package/src/primitives/JobProgress.less +1 -1
  126. package/src/primitives/Legend.stories.tsx +1 -0
  127. package/src/primitives/Readout.browser.test.tsx +137 -0
  128. package/src/primitives/Readout.less +12 -0
  129. package/src/primitives/Readout.stories.tsx +58 -0
  130. package/src/primitives/Readout.test.tsx +93 -0
  131. package/src/primitives/Readout.tsx +56 -0
  132. package/src/primitives/index.ts +2 -0
  133. package/src/specimen/Specimen.stories.tsx +1 -0
  134. package/src/specimen/Specimen.tsx +2 -2
  135. package/src/state/Persistence.browser.test.tsx +47 -0
  136. package/src/state/store.test.ts +5 -1
  137. package/src/state/usePersistedState.test.tsx +1 -1
  138. package/src/styles.less +1 -0
  139. package/src/theme/Interstellar.stories.tsx +3 -1
  140. package/src/theme/base.less +21 -47
  141. package/src/theme/interstellar.test.ts +1 -1
  142. package/src/theme/interstellar.theme.json +10 -3
  143. package/src/trial/Trial.less +0 -13
  144. package/src/trial/Trial.tsx +12 -6
  145. package/src/trial/TrialChrome.tsx +21 -3
  146. package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
  147. package/dist/_dts/PropertyField.d-D0ndfIIt.d.ts +0 -404
  148. package/dist/chunk-4TT3PNPR.js.map +0 -1
  149. package/dist/chunk-6FLXL3I7.js.map +0 -1
  150. package/dist/chunk-ASOK76ZH.js.map +0 -1
  151. package/dist/chunk-CGHF6RZV.js.map +0 -1
  152. package/dist/chunk-DWMSB4CA.js.map +0 -1
  153. package/dist/chunk-IRTGUQ5O.js.map +0 -1
  154. package/dist/chunk-KHK5FGER.js.map +0 -1
  155. package/dist/chunk-NEXR37YJ.js.map +0 -1
  156. package/dist/chunk-O6FFFOHS.js.map +0 -1
  157. package/dist/chunk-QGMOA2YE.js.map +0 -1
  158. package/dist/chunk-SBXNQW4G.js +0 -3
  159. package/dist/chunk-TJ77A4A3.js.map +0 -1
  160. package/dist/chunk-TYN6MLXX.js +0 -13864
  161. package/dist/chunk-TYN6MLXX.js.map +0 -1
  162. package/src/state/Persistence.stories.tsx +0 -75
@@ -1,10 +1,10 @@
1
1
  import { useAnnotationsOptional, useAnnotations } from './chunk-3RY6WL5T.js';
2
- import { Toolbar, ZoomControl, ScaleIndicator, FpsMeter, StatusBar, useRovingTabIndex } from './chunk-SLAQPUI4.js';
2
+ import { Toolbar, ZoomControl, ScaleIndicator, FpsMeter, StatusBar, useRovingTabIndex } from './chunk-7BO7HNGF.js';
3
3
  import { usePersistedState } from './chunk-RWNDDKOH.js';
4
- import { ControlPanel } from './chunk-ASOK76ZH.js';
4
+ import { ControlPanel } from './chunk-T5IBSPAM.js';
5
5
  import { useLabContext } from './chunk-Z76KEZAX.js';
6
6
  import { LabStoreContext } from './chunk-2YILQ7Y5.js';
7
- import { b, A, E, C, o, O, h, P, H, g2, u4, F, k, fe, X, U, Z, d2, z, B, Q, V, n8, o4, n3 } from './chunk-TYN6MLXX.js';
7
+ import { b, A, E, C, o, O, h, P, H, _2, a2, u3, F, k, fe, X, U, Z, d3, z, B, Q, V, n8, o4, n3 } from './chunk-MIM5R4ZT.js';
8
8
  import { useState, useId, useContext, useMemo } from 'react';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
10
  import { useStore } from 'zustand/react';
@@ -19,10 +19,10 @@ function fileName(result) {
19
19
  }
20
20
  function download(result) {
21
21
  const url = URL.createObjectURL(result.blob);
22
- const a = document.createElement("a");
23
- a.href = url;
24
- a.download = fileName(result);
25
- a.click();
22
+ const a2 = document.createElement("a");
23
+ a2.href = url;
24
+ a2.download = fileName(result);
25
+ a2.click();
26
26
  setTimeout(() => URL.revokeObjectURL(url), 0);
27
27
  }
28
28
  async function copy(result) {
@@ -71,7 +71,7 @@ function ExportMenu() {
71
71
  }
72
72
  ),
73
73
  /* @__PURE__ */ jsx(
74
- g2,
74
+ _2,
75
75
  {
76
76
  triggerRef: { current: anchor },
77
77
  isOpen: open,
@@ -141,32 +141,29 @@ function MarkList({ meaning, config }) {
141
141
  if (all.length === 0) {
142
142
  return /* @__PURE__ */ jsx("div", { className: "lk-mark-list__empty", children: "No marks yet" });
143
143
  }
144
- return /* @__PURE__ */ jsx("ul", { className: "lk-mark-list", children: all.map((a) => {
145
- const stale = marks.isStale(a, config);
144
+ return /* @__PURE__ */ jsx("ul", { className: "lk-mark-list", children: all.map((a2$1) => {
145
+ const stale = marks.isStale(a2$1, config);
146
146
  return /* @__PURE__ */ jsxs("li", { className: "lk-mark-list__row", children: [
147
147
  /* @__PURE__ */ jsxs("div", { className: "lk-mark-list__head", children: [
148
- /* @__PURE__ */ jsx("span", { className: "lk-mark-list__kind", children: a.kind }),
149
- /* @__PURE__ */ jsx("span", { className: "lk-mark-list__target", children: a.target }),
148
+ /* @__PURE__ */ jsx("span", { className: "lk-mark-list__kind", children: a2$1.kind }),
149
+ /* @__PURE__ */ jsx("span", { className: "lk-mark-list__target", children: a2$1.target }),
150
150
  stale ? /* @__PURE__ */ jsx("span", { className: "lk-mark-list__stale", children: "stale" }) : null,
151
151
  /* @__PURE__ */ jsx(
152
- "button",
152
+ a2,
153
153
  {
154
- type: "button",
155
154
  className: "lk-mark-list__drop",
156
- "aria-label": `Remove ${a.kind} on ${a.target}`,
157
- onClick: () => marks.remove(a.id),
158
- children: "\xD7"
155
+ ariaLabel: `Remove ${a2$1.kind} on ${a2$1.target}`,
156
+ onClick: () => marks.remove(a2$1.id)
159
157
  }
160
158
  )
161
159
  ] }),
162
160
  /* @__PURE__ */ jsx(
163
- u4,
161
+ u3,
164
162
  {
165
- className: "lk-mark-list__title",
166
- "aria-label": `Title of ${a.kind} on ${a.target}`,
167
- value: a.title ?? "",
163
+ "aria-label": `Title of ${a2$1.kind} on ${a2$1.target}`,
164
+ value: a2$1.title ?? "",
168
165
  placeholder: "Untitled",
169
- onChange: (next) => marks.update(a.id, { title: next })
166
+ onChange: (next) => marks.update(a2$1.id, { title: next })
170
167
  }
171
168
  ),
172
169
  statuses.length > 0 ? (
@@ -176,9 +173,9 @@ function MarkList({ meaning, config }) {
176
173
  "select",
177
174
  {
178
175
  className: "lk-mark-list__status",
179
- "aria-label": `Status of ${a.kind} on ${a.target}`,
180
- value: a.status ?? "",
181
- onChange: (e) => marks.update(a.id, { status: e.target.value }),
176
+ "aria-label": `Status of ${a2$1.kind} on ${a2$1.target}`,
177
+ value: a2$1.status ?? "",
178
+ onChange: (e) => marks.update(a2$1.id, { status: e.target.value }),
182
179
  children: [
183
180
  /* @__PURE__ */ jsx("option", { value: "", children: "\u2014" }),
184
181
  statuses.map((s) => /* @__PURE__ */ jsx("option", { value: s.id, children: s.label }, s.id))
@@ -186,7 +183,7 @@ function MarkList({ meaning, config }) {
186
183
  }
187
184
  )
188
185
  ) : null
189
- ] }, a.id);
186
+ ] }, a2$1.id);
190
187
  }) });
191
188
  }
192
189
  var ZOOM_STEP = 1.25;
@@ -342,7 +339,7 @@ function builtinContributions(instrument, ctx, controls) {
342
339
  group: "trial",
343
340
  end: true,
344
341
  render: (c) => /* @__PURE__ */ jsx(
345
- d2,
342
+ d3,
346
343
  {
347
344
  "aria-label": "Load snapshot",
348
345
  label: "Load\u2026",
@@ -548,13 +545,13 @@ function groupsOf(contributions) {
548
545
  groups.push({ key: c.id, end: c.end ?? false, entries: [c] });
549
546
  continue;
550
547
  }
551
- let g2 = byKey.get(c.group);
552
- if (!g2) {
553
- g2 = { key: c.group, end: c.end ?? false, entries: [] };
554
- byKey.set(c.group, g2);
555
- groups.push(g2);
548
+ let g = byKey.get(c.group);
549
+ if (!g) {
550
+ g = { key: c.group, end: c.end ?? false, entries: [] };
551
+ byKey.set(c.group, g);
552
+ groups.push(g);
556
553
  }
557
- g2.entries.push(c);
554
+ g.entries.push(c);
558
555
  }
559
556
  return groups;
560
557
  }
@@ -597,7 +594,7 @@ function ToolbarRegion({
597
594
  }) {
598
595
  if (contributions.length === 0) return null;
599
596
  const groups = groupsOf(contributions);
600
- return /* @__PURE__ */ jsx(Toolbar, { "aria-label": label, children: groups.map((g2) => /* @__PURE__ */ jsx(Toolbar.Group, { end: g2.end, "aria-label": g2.key, children: g2.entries.map((c) => renderEntry(c, ctx, region)) }, g2.key)) });
597
+ return /* @__PURE__ */ jsx(Toolbar, { "aria-label": label, children: groups.map((g) => /* @__PURE__ */ jsx(Toolbar.Group, { end: g.end, "aria-label": g.key, children: g.entries.map((c) => renderEntry(c, ctx, region)) }, g.key)) });
601
598
  }
602
599
  function useLabChromeContext() {
603
600
  const lab = useLabContext();
@@ -779,5 +776,5 @@ function ViewportRegion({ contributions, ctx }) {
779
776
  }
780
777
 
781
778
  export { ANNOTATION_TOOLS, ANNOTATION_WEASEL_TOOLS, ExportMenu, LabAsideRegion, LabFooterRegion, LabHeaderRegion, LabSidebarRegion, MarkList, PaletteRegion, SidebarRegion, StatusRegion, TitleBarRegion, ToolbarRegion, ViewportRegion, annotationToolInfo, builtinContributions, contributionsIn, labAnnotationTools, labContributions, mergeContributions, resolveLabTool, suppressContributions, toolContributions, useLabChromeContext };
782
- //# sourceMappingURL=chunk-4TT3PNPR.js.map
783
- //# sourceMappingURL=chunk-4TT3PNPR.js.map
779
+ //# sourceMappingURL=chunk-I5DUQ5HM.js.map
780
+ //# sourceMappingURL=chunk-I5DUQ5HM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/annotations/ExportMenu.tsx","../src/annotations/MarkList.tsx","../src/chrome/builtins.tsx","../src/annotations/toolMap.ts","../src/tools/labTool.ts","../src/chrome/merge.ts","../src/chrome/regions/SidebarRegion.tsx","../src/chrome/regions/StatusRegion.tsx","../src/chrome/regions/ToolbarRegion.tsx","../src/chrome/LabChrome.tsx","../src/chrome/regions/PaletteRegion.tsx","../src/chrome/regions/TitleBarRegion.tsx","../src/chrome/regions/ViewportRegion.tsx"],"names":["a","_","jsx","jsxs","u","d","n","o","renderEntry"],"mappings":"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","file":"chunk-I5DUQ5HM.js","sourcesContent":["import { ExportIcon } from '@weasel-js/ui';\nimport { useId, useState } from 'react';\nimport { Callout } from '../passthrough/weasel-ui';\nimport { Toolbar } from '../primitives/Toolbar';\nimport { useAnnotationsOptional } from './AnnotationsContext';\nimport type { CaptureResult } from './types';\n\nconst SCALES = [1, 2, 4] as const;\nconst FORMATS = [\n { id: 'png', label: 'PNG' },\n { id: 'svg', label: 'SVG' },\n] as const;\n\ntype Format = (typeof FORMATS)[number]['id'];\n\nfunction fileName(result: CaptureResult): string {\n return `${result.target.replace(/[^a-z0-9._-]+/gi, '-')}.${result.format}`;\n}\n\n/** A blob the person asked for, handed to the browser's own save flow. The\n * object URL is revoked on the next turn — revoking it synchronously races\n * the navigation the click starts. */\nfunction download(result: CaptureResult): void {\n const url = URL.createObjectURL(result.blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = fileName(result);\n a.click();\n setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\n/** PNG goes to the clipboard as an image. SVG goes as text: `image/svg+xml`\n * needs Chromium's `web ` prefix and nothing else reads it, while the markup\n * is what a person pasting a vector export actually wants. */\nasync function copy(result: CaptureResult): Promise<void> {\n if (result.format === 'svg') {\n await navigator.clipboard.writeText(await result.blob.text());\n return;\n }\n await navigator.clipboard.write([new ClipboardItem({ 'image/png': result.blob })]);\n}\n\n/**\n * Export a target's picture with its marks on it.\n *\n * A panel rather than a button because a mark belongs to a target: with more\n * than one pane, \"export\" on its own does not say what.\n *\n * Reads the store through the hook the way `<MarkList>` does — the chrome\n * context carries no instrument state and is not the route to it.\n */\nexport function ExportMenu() {\n const marks = useAnnotationsOptional();\n const [anchor, setAnchor] = useState<HTMLSpanElement | null>(null);\n const [open, setOpen] = useState(false);\n const [target, setTarget] = useState<string | null>(null);\n const [format, setFormat] = useState<Format>('png');\n const [scale, setScale] = useState<number>(2);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const titleId = useId();\n\n if (!marks) return null;\n const targets = marks.targets();\n const chosen = target ?? targets[0]?.id ?? null;\n\n const run = async (then: (r: CaptureResult) => void | Promise<void>): Promise<void> => {\n if (!chosen) return;\n setBusy(true);\n setError(null);\n try {\n await then(await marks.capture(chosen, { format, scale }));\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <span className=\"lk-export\" ref={setAnchor}>\n <Toolbar.Button\n iconOnly\n pressed={open}\n aria-label=\"Export\"\n title=\"Export\"\n onClick={() => setOpen((was) => !was)}\n >\n <ExportIcon size={16} />\n </Toolbar.Button>\n <Callout\n triggerRef={{ current: anchor }}\n isOpen={open}\n onOpenChange={setOpen}\n onDismiss={() => setOpen(false)}\n placement=\"bottom end\"\n aria-labelledby={titleId}\n >\n <div className=\"lk-export__panel\">\n <span className=\"lk-export__title\" id={titleId}>\n Export\n </span>\n\n <label className=\"lk-export__row\">\n <span>Target</span>\n {/* Native controls: role, name and keyboard operability for free,\n and a five-control panel is not the place to rebuild them. */}\n <select\n aria-label=\"Target\"\n value={chosen ?? ''}\n onChange={(e) => setTarget(e.target.value)}\n >\n {targets.map((t) => (\n <option key={t.id} value={t.id}>\n {t.id}\n </option>\n ))}\n </select>\n </label>\n\n {/* A <fieldset>/<legend> cannot do this: a legend is outside its\n fieldset's grid formatting context, so it will not take a grid\n column and every choice row drops below its own label. */}\n <div className=\"lk-export__row\">\n <span>Format</span>\n <span className=\"lk-export__choices\" role=\"radiogroup\" aria-label=\"Format\">\n {FORMATS.map((f) => (\n <label key={f.id}>\n <input\n type=\"radio\"\n name=\"lk-export-format\"\n checked={format === f.id}\n onChange={() => setFormat(f.id)}\n />\n {f.label}\n </label>\n ))}\n </span>\n </div>\n\n <div className=\"lk-export__row\">\n <span>Scale</span>\n <span className=\"lk-export__choices\" role=\"radiogroup\" aria-label=\"Scale\">\n {SCALES.map((s) => (\n <label key={s}>\n <input\n type=\"radio\"\n name=\"lk-export-scale\"\n checked={scale === s}\n onChange={() => setScale(s)}\n />\n {s}×\n </label>\n ))}\n </span>\n </div>\n\n <div className=\"lk-export__actions\">\n <button type=\"button\" disabled={busy || !chosen} onClick={() => run(download)}>\n Download\n </button>\n <button type=\"button\" disabled={busy || !chosen} onClick={() => run(copy)}>\n Copy\n </button>\n </div>\n\n {error ? (\n <p className=\"lk-export__error\" role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n </Callout>\n </span>\n );\n}\n","import { CloseButton, Input } from '../passthrough/weasel-ui';\nimport { useAnnotations } from './AnnotationsContext';\nimport type { AnnotationMeaning } from './types';\n\n/** Props for `<MarkList>`. */\nexport interface MarkListProps {\n /** The instrument's vocabulary. Omitted, rows carry no status control —\n * a host that declared none owns what a mark means. */\n meaning?: AnnotationMeaning;\n /** The live config, for answering staleness. */\n config: unknown;\n}\n\n/** Every mark on this trial's targets: what it says, and whether it still\n * describes the picture under it.\n *\n * Reads the store through the hook, which re-renders on every mutation — so a\n * mark drawn on a pane appears here without anything wiring the two. */\nexport function MarkList({ meaning, config }: MarkListProps) {\n const marks = useAnnotations();\n const all = marks.query();\n const statuses = meaning?.statuses ?? [];\n\n if (all.length === 0) {\n return <div className=\"lk-mark-list__empty\">No marks yet</div>;\n }\n\n return (\n <ul className=\"lk-mark-list\">\n {all.map((a) => {\n const stale = marks.isStale(a, config);\n return (\n <li className=\"lk-mark-list__row\" key={a.id}>\n <div className=\"lk-mark-list__head\">\n <span className=\"lk-mark-list__kind\">{a.kind}</span>\n <span className=\"lk-mark-list__target\">{a.target}</span>\n {stale ? <span className=\"lk-mark-list__stale\">stale</span> : null}\n <CloseButton\n className=\"lk-mark-list__drop\"\n ariaLabel={`Remove ${a.kind} on ${a.target}`}\n onClick={() => marks.remove(a.id)}\n />\n </div>\n <Input\n aria-label={`Title of ${a.kind} on ${a.target}`}\n value={a.title ?? ''}\n placeholder=\"Untitled\"\n onChange={(next) => marks.update(a.id, { title: next })}\n />\n {statuses.length > 0 ? (\n // A native select: it carries role, name and keyboard operability\n // for free, and a sidebar row is not the place to rebuild them.\n <select\n className=\"lk-mark-list__status\"\n aria-label={`Status of ${a.kind} on ${a.target}`}\n value={a.status ?? ''}\n onChange={(e) => marks.update(a.id, { status: e.target.value })}\n >\n <option value=\"\">—</option>\n {statuses.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label}\n </option>\n ))}\n </select>\n ) : null}\n </li>\n );\n })}\n </ul>\n );\n}\n","import {\n CloneIcon,\n CloseIcon,\n FitIcon,\n LoupeIcon,\n RedoIcon,\n ResetIcon,\n SnapshotIcon,\n UndoIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@weasel-js/ui';\nimport { ExportMenu } from '../annotations/ExportMenu';\nimport { MarkList } from '../annotations/MarkList';\nimport type { ControlRenderer } from '../config/types';\nimport { ControlPanel } from '../controls/ControlPanel';\nimport type { Instrument } from '../instrument/types';\nimport { MenuButton } from '../passthrough/weasel-ui';\nimport { FpsMeter } from '../primitives/FpsMeter';\nimport { ScaleIndicator } from '../primitives/ScaleIndicator';\nimport { ZoomControl } from '../primitives/ZoomControl';\nimport type { TrialChromeContext, TrialContribution } from './types';\n\nconst ZOOM_STEP = 1.25;\n\n/** The property groups inside a contribution are folded under keys prefixed\n * with that contribution's id, so a group called `marks` cannot fold the\n * sidebar section of the same name. `ControlPanel` keys by bare label, so the\n * prefix goes on here and comes off again. */\nfunction groupFolds(\n collapsedSections: Readonly<Record<string, boolean>>,\n id: string,\n): Record<string, boolean> {\n const prefix = `${id}/`;\n const out: Record<string, boolean> = {};\n for (const [key, value] of Object.entries(collapsedSections)) {\n if (key.startsWith(prefix)) out[key.slice(prefix.length)] = value;\n }\n return out;\n}\n\n/**\n * The contributions a trial gets from what its instrument declared. This is\n * the whole \"declaring a capability provides the chrome\" rule — it replaces\n * the presence checks that used to be spread across the runtime.\n */\nexport function builtinContributions(\n instrument: Instrument,\n ctx: TrialChromeContext,\n controls?: Record<string, ControlRenderer>,\n): TrialContribution[] {\n const out: TrialContribution[] = [];\n const zoom = ctx.zoom;\n\n // Weasel history is the undo authority for marks, so declaring `annotations`\n // gets the buttons whether or not the instrument also declares `undo`.\n if (instrument.undo != null || instrument.annotations != null) {\n out.push({\n id: 'undo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: UndoIcon,\n label: 'Undo',\n shortcut: 'Mod+Z',\n disabled: !ctx.canUndo,\n onActivate: ctx.undo,\n },\n });\n out.push({\n id: 'redo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: RedoIcon,\n label: 'Redo',\n shortcut: 'Mod+Shift+Z',\n disabled: !ctx.canRedo,\n onActivate: ctx.redo,\n },\n });\n }\n\n // A tool id shares the contribution namespace, so a tool called `close`\n // collides with the built-in close button and throws. Annotation tools are\n // not here: the lab's rail carries them.\n for (const t of instrument.tools?.tools ?? []) {\n out.push({\n id: t.id,\n region: 'palette',\n group: t.group,\n item: { icon: t.icon, label: t.label, shortcut: t.shortcut },\n });\n }\n\n if (instrument.loupe != null) {\n out.push({\n id: 'loupe',\n region: 'toolbar',\n group: 'view',\n item: {\n icon: LoupeIcon,\n label: 'Loupe',\n pressed: ctx.loupeOn,\n onActivate: ctx.toggleLoupe,\n },\n });\n }\n\n // Zoom acts on the view of the trial, so it is a viewport control. A trial\n // holding a non-2D view reports zoom as null and gets none of this.\n if ((instrument.canvas != null || instrument.stage != null) && zoom !== null) {\n out.push({\n id: 'zoom-out',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomOutIcon,\n label: 'Zoom out',\n onActivate: () => ctx.setZoom(zoom / ZOOM_STEP),\n },\n });\n out.push({\n id: 'zoom-in',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomInIcon,\n label: 'Zoom in',\n onActivate: () => ctx.setZoom(zoom * ZOOM_STEP),\n },\n });\n out.push({\n id: 'actual-size',\n region: 'viewport',\n group: 'zoom',\n item: { icon: FitIcon, label: 'Actual size', onActivate: () => ctx.setZoom(1) },\n });\n out.push({\n id: 'zoom-control',\n region: 'viewport',\n group: 'zoom',\n render: (c) => <ZoomControl zoom={c.zoom ?? 1} onZoomChange={c.setZoom} />,\n });\n out.push({\n id: 'scale',\n region: 'status',\n group: 'view',\n render: (c) => <ScaleIndicator zoom={c.zoom ?? 1} />,\n });\n if (instrument.canvas != null) {\n out.push({\n id: 'fps',\n region: 'status',\n group: 'view',\n end: true,\n render: () => <FpsMeter />,\n });\n }\n }\n\n if (instrument.annotations != null) {\n // A popover, so it takes the `render` escape: the panel picks a target,\n // and an icon button cannot ask which one.\n out.push({\n id: 'export',\n region: 'toolbar',\n group: 'trial',\n end: true,\n render: () => <ExportMenu />,\n });\n out.push({\n id: 'marks',\n region: 'sidebar',\n item: {\n title: 'Marks',\n body: <MarkList meaning={instrument.annotations.meaning} config={ctx.config} />,\n },\n });\n }\n\n if (Object.keys(ctx.configSchema.group.children).length > 0) {\n out.push({\n id: 'settings',\n region: 'sidebar',\n item: {\n title: 'Settings',\n body: (\n <ControlPanel\n schema={ctx.configSchema}\n config={ctx.config as Record<string, unknown>}\n auto={ctx.auto}\n setConfig={(key, value) => ctx.setConfig(String(key), value)}\n renderers={controls}\n collapsed={groupFolds(ctx.collapsedSections, 'settings')}\n onCollapse={(label, next) => ctx.setSectionCollapsed(`settings/${label}`, next)}\n />\n ),\n },\n });\n }\n\n if (ctx.savedSnapshots.length > 0) {\n // A menu is not an icon button, so it takes the render escape.\n out.push({\n id: 'snapshot-load',\n region: 'toolbar',\n group: 'trial',\n end: true,\n render: (c) => (\n <MenuButton\n aria-label=\"Load snapshot\"\n label=\"Load…\"\n items={c.savedSnapshots.map((sn) => ({ value: sn.id, label: sn.name }))}\n onAction={(id) => c.loadSnapshot(id)}\n />\n ),\n });\n }\n out.push({\n id: 'clone',\n region: 'titlebar',\n end: true,\n item: { icon: CloneIcon, label: 'Clone trial', onActivate: ctx.clone },\n });\n out.push({\n id: 'reset',\n region: 'titlebar',\n end: true,\n item: { icon: ResetIcon, label: 'Reset trial', onActivate: ctx.reset },\n });\n out.push({\n id: 'snapshot',\n region: 'titlebar',\n end: true,\n item: {\n icon: SnapshotIcon,\n label: 'Save snapshot',\n shortcut: 'Mod+S',\n onActivate: () => ctx.saveSnapshot(),\n },\n });\n out.push({\n id: 'close',\n region: 'titlebar',\n end: true,\n item: {\n icon: CloseIcon,\n label: ctx.isLastTrial ? 'Cannot close the last trial' : 'Close trial',\n danger: true,\n disabled: ctx.isLastTrial,\n onActivate: ctx.close,\n },\n });\n\n return out;\n}\n","import type { BuiltinToolId } from '@weasel-js/core';\nimport {\n ArrowIcon,\n EllipseIcon,\n HandIcon,\n LineIcon,\n PencilIcon,\n RectIcon,\n SelectIcon,\n TextIcon,\n} from '@weasel-js/ui';\nimport type { InstrumentList } from '../instrument/types';\nimport type { TrialTool } from '../tools/types';\nimport type { AnnotationKind } from './types';\n\n/** Which weasel tool an annotation tool drives, and what kind of mark that\n * makes. `select` makes none. */\nexport interface AnnotationToolInfo {\n weaselTool: BuiltinToolId;\n kind?: AnnotationKind;\n}\n\n// `arrow` and `stroke` have no weasel tool of their own, so the kind cannot be\n// read back from the insert — the overlay takes it from the tool id it holds.\nconst TOOLS: Record<string, AnnotationToolInfo> = {\n select: { weaselTool: 'select' },\n stroke: { weaselTool: 'pencil', kind: 'stroke' },\n line: { weaselTool: 'line', kind: 'line' },\n arrow: { weaselTool: 'line', kind: 'arrow' },\n rect: { weaselTool: 'rect', kind: 'rect' },\n ellipse: { weaselTool: 'ellipse', kind: 'ellipse' },\n text: { weaselTool: 'text', kind: 'text' },\n};\n\n/** The tools a lab's rail gets when any instrument declares `annotations`.\n * Ids share the lab's contribution namespace with its own `tools`, and the\n * lab's tool slot holds whichever is active. */\nexport const ANNOTATION_TOOLS: readonly TrialTool[] = [\n // Not in `TOOLS`: an id the map does not carry is what leaves the overlay idle.\n { id: 'pointer', label: 'Interact', icon: HandIcon, group: 'annotate' },\n { id: 'select', label: 'Select', icon: SelectIcon, group: 'annotate' },\n { id: 'stroke', label: 'Freehand', icon: PencilIcon, group: 'annotate' },\n { id: 'line', label: 'Line', icon: LineIcon, group: 'annotate' },\n { id: 'arrow', label: 'Arrow', icon: ArrowIcon, group: 'annotate' },\n { id: 'rect', label: 'Rectangle', icon: RectIcon, group: 'annotate' },\n { id: 'ellipse', label: 'Ellipse', icon: EllipseIcon, group: 'annotate' },\n { id: 'text', label: 'Text', icon: TextIcon, group: 'annotate' },\n];\n\n/** The annotation tools a lab's rail carries for these instruments: none\n * without an annotating instrument, else the union of what each asks for. */\nexport function labAnnotationTools(instruments: InstrumentList): readonly TrialTool[] {\n const wanted = new Set<string>();\n for (const i of instruments) {\n if (i.annotations == null) continue;\n if (i.annotations.tools == null) return ANNOTATION_TOOLS;\n for (const id of i.annotations.tools) wanted.add(id);\n }\n return ANNOTATION_TOOLS.filter((t) => wanted.has(t.id));\n}\n\n/** What `id` drives, or undefined for a tool that is not one of these. */\nexport function annotationToolInfo(id: string | null): AnnotationToolInfo | undefined {\n return id === null ? undefined : TOOLS[id];\n}\n\n/** Every weasel tool the overlay has to mount for this palette to work. */\nexport const ANNOTATION_WEASEL_TOOLS: readonly BuiltinToolId[] = [\n ...new Set(Object.values(TOOLS).map((t) => t.weaselTool)),\n];\n","import { labAnnotationTools } from '../annotations/toolMap';\nimport type { InstrumentList } from '../instrument/types';\n\n/**\n * The tool the lab's slot holds, once its default is applied: a lab with any\n * annotating instrument starts in `pointer`, so a first click reaches the\n * instrument rather than the marks over it, or in the first annotation tool\n * its rail carries when `pointer` is not among them.\n */\nexport function resolveLabTool(slot: string | null, instruments: InstrumentList): string | null {\n if (slot !== null) return slot;\n const tools = labAnnotationTools(instruments);\n if (tools.some((t) => t.id === 'pointer')) return 'pointer';\n return tools[0]?.id ?? null;\n}\n","/**\n * Concatenate contribution bundles into one list, preserving order — order\n * decides how a region lays its contributions out, so it is part of the\n * result, not an accident of it.\n *\n * Throws on a duplicate id rather than dropping one: a contribution silently\n * losing to a later bundle is the failure a registry exists to prevent.\n */\nexport function mergeContributions<T extends { id: string }>(\n ...bundles: readonly (readonly T[])[]\n): T[] {\n const out: T[] = [];\n const seen = new Set<string>();\n for (const bundle of bundles) {\n for (const entry of bundle) {\n if (seen.has(entry.id)) {\n throw new Error(\n `[labkit] mergeContributions: duplicate contribution id \"${entry.id}\". ` +\n 'Two bundles registered the same id; rename one, or suppress the ' +\n 'built-in before adding yours.',\n );\n }\n seen.add(entry.id);\n out.push(entry);\n }\n }\n return out;\n}\n\n/**\n * Drop contributions by id. Throws when an id is not present: a typo that\n * silently suppresses nothing is the same class of bug as a duplicate id\n * silently winning.\n */\nexport function suppressContributions<T extends { id: string }>(\n bundle: readonly T[],\n ids: readonly string[],\n): T[] {\n const present = new Set(bundle.map((c) => c.id));\n for (const id of ids) {\n if (!present.has(id)) {\n throw new Error(\n `[labkit] cannot suppress \"${id}\": no contribution with that id. ` +\n `Present ids: ${[...present].join(', ')}`,\n );\n }\n }\n const drop = new Set(ids);\n return bundle.filter((c) => !drop.has(c.id));\n}\n","import { type StanceProps, useStance } from '@weasel-js/ui';\nimport type { ReactNode } from 'react';\nimport type {\n RegionContribution,\n SidebarSection,\n SidebarSlotContext,\n TrialChromeContext,\n} from '../types';\n\n/** Props for `<SidebarRegion>`. */\nexport interface SidebarRegionProps<TCtx extends SidebarSlotContext = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out. */\n region?: string;\n}\n\nfunction Section({\n title,\n collapsed,\n onCollapsedChange,\n onUndock,\n children,\n stance,\n tone,\n}: StanceProps & {\n title: string;\n collapsed: boolean;\n onCollapsedChange: (collapsed: boolean) => void;\n onUndock?: () => void;\n children: ReactNode;\n}) {\n return (\n <section className=\"lk-sidebar-section\" {...useStance({ stance, tone })}>\n <div className=\"lk-sidebar-section__bar\">\n <button\n type=\"button\"\n className=\"lk-sidebar-section__head\"\n aria-expanded={!collapsed}\n onClick={() => onCollapsedChange(!collapsed)}\n >\n {title}\n </button>\n {onUndock ? (\n <button\n type=\"button\"\n className=\"lk-sidebar-section__undock\"\n aria-label={`Undock ${title}`}\n title={`Undock ${title}`}\n onClick={onUndock}\n >\n ⧉\n </button>\n ) : null}\n </div>\n {collapsed ? null : <div className=\"lk-sidebar-section__body\">{children}</div>}\n </section>\n );\n}\n\n/** Lays `sidebar` contributions out as titled, collapsible sections — a\n * trial's, or the lab's. A section the trial has torn out is not rendered\n * here — `Trial` portals its body into the workspace instead. A context with\n * no `undockPanel` offers no tear-out. */\nexport function SidebarRegion<TCtx extends SidebarSlotContext = TrialChromeContext>({\n contributions,\n ctx,\n region = 'sidebar',\n}: SidebarRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n return (\n <>\n {contributions.map((c) => {\n if (c.render) return <div key={c.id}>{c.render(ctx)}</div>;\n if (c.region !== region || !c.item) return null;\n if (ctx.undockedPanels?.includes(c.id)) return null;\n const item = c.item as SidebarSection;\n return (\n <Section\n key={c.id}\n title={item.title}\n stance={item.stance}\n tone={item.tone}\n collapsed={ctx.collapsedSections[c.id] ?? item.defaultCollapsed ?? false}\n onCollapsedChange={(next) => ctx.setSectionCollapsed(c.id, next)}\n onUndock={\n ctx.undockPanel && item.undockable !== false\n ? () => ctx.undockPanel?.(c.id, item.undockAs ?? 'tile')\n : undefined\n }\n >\n {item.body}\n </Section>\n );\n })}\n </>\n );\n}\n","import { StatusBar } from '../../primitives/StatusBar';\nimport type { RegionContribution, StatusReadout, TrialChromeContext } from '../types';\n\n/** Props for `<StatusRegion>`. */\nexport interface StatusRegionProps<TCtx = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's readouts to lay out; the lab's footer is `footer`. */\n region?: string;\n}\n\n/** Lays a bar's readouts out. */\nexport function StatusRegion<TCtx = TrialChromeContext>({\n contributions,\n ctx,\n region = 'status',\n}: StatusRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n return (\n <StatusBar>\n {contributions.map((c) => {\n if (c.render)\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n {c.render(ctx)}\n </StatusBar.Section>\n );\n if (c.region !== region || !c.item) return null;\n const item = c.item as StatusReadout;\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n <span title={item.title}>{item.text}</span>\n </StatusBar.Section>\n );\n })}\n </StatusBar>\n );\n}\n","import type { ReactNode } from 'react';\nimport { Toolbar } from '../../primitives/Toolbar';\nimport type { RegionContribution, ToolbarItem, TrialChromeContext } from '../types';\n\n/** Props for `<ToolbarRegion>`. */\nexport interface ToolbarRegionProps<TCtx = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out; the lab's action bar is `header`. */\n region?: string;\n /** The bar's accessible name. */\n label?: string;\n}\n\ninterface Group<TCtx> {\n key: string;\n end: boolean;\n entries: RegionContribution<TCtx>[];\n}\n\n/** Bucket by group, preserving first-appearance order. Ungrouped\n * contributions each become their own bucket so they stay in place. */\nfunction groupsOf<TCtx>(contributions: readonly RegionContribution<TCtx>[]): Group<TCtx>[] {\n const groups: Group<TCtx>[] = [];\n const byKey = new Map<string, Group<TCtx>>();\n for (const c of contributions) {\n if (c.group == null) {\n groups.push({ key: c.id, end: c.end ?? false, entries: [c] });\n continue;\n }\n let g = byKey.get(c.group);\n if (!g) {\n g = { key: c.group, end: c.end ?? false, entries: [] };\n byKey.set(c.group, g);\n groups.push(g);\n }\n g.entries.push(c);\n }\n return groups;\n}\n\nfunction renderEntry<TCtx>(c: RegionContribution<TCtx>, ctx: TCtx, region: string): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== region || !c.item) return null;\n const {\n icon: Icon,\n label,\n shortcut,\n disabled,\n danger,\n showLabel,\n pressed,\n onActivate,\n } = c.item as ToolbarItem<TCtx>;\n return (\n <Toolbar.Button\n key={c.id}\n iconOnly={!showLabel}\n variant={danger ? 'danger' : 'default'}\n disabled={disabled}\n pressed={pressed}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={() => onActivate(ctx)}\n >\n <Icon size={16} />\n {showLabel ? <span>{label}</span> : null}\n </Toolbar.Button>\n );\n}\n\n/** Lays a bar's contributions out, grouped by their `group`. */\nexport function ToolbarRegion<TCtx = TrialChromeContext>({\n contributions,\n ctx,\n region = 'toolbar',\n label = 'Trial actions',\n}: ToolbarRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n const groups = groupsOf(contributions);\n return (\n <Toolbar aria-label={label}>\n {groups.map((g) => (\n <Toolbar.Group key={g.key} end={g.end} aria-label={g.key}>\n {g.entries.map((c) => renderEntry(c, ctx, region))}\n </Toolbar.Group>\n ))}\n </Toolbar>\n );\n}\n","import { useContext, useMemo } from 'react';\nimport { useStore } from 'zustand/react';\nimport { useLabContext } from '../lab/LabContext';\nimport { LabStoreContext } from '../state/context';\nimport { usePersistedState } from '../state/usePersistedState';\nimport { resolveLabTool } from '../tools/labTool';\nimport type { TrialTool } from '../tools/types';\nimport type { LabChromeContext, LabContribution, LabRegion } from './labTypes';\nimport { mergeContributions } from './merge';\nimport { SidebarRegion } from './regions/SidebarRegion';\nimport { StatusRegion } from './regions/StatusRegion';\nimport { ToolbarRegion } from './regions/ToolbarRegion';\n\n/** The lab's chrome context: the lab itself, plus the lab's tool slot. Throws\n * outside a `<Lab>`. */\nexport function useLabChromeContext(): LabChromeContext {\n const lab = useLabContext();\n const storeCtx = useContext(LabStoreContext);\n if (!storeCtx) throw new Error('[labkit] lab chrome requires <LabStoreProvider>');\n const slot = useStore(storeCtx.store, (s) => s.activeToolId);\n const storeInstruments = useStore(storeCtx.store, (s) => s.instruments);\n const activeToolId = resolveLabTool(slot, storeInstruments ?? lab.instruments);\n const setLabTool = useStore(storeCtx.store, (s) => s.setLabTool);\n return useMemo(\n () => ({ ...lab, activeToolId, setActiveTool: setLabTool }),\n [lab, activeToolId, setLabTool],\n );\n}\n\n/** The lab's contributions for one region, in declaration order. */\nexport function contributionsIn<TCtx = LabChromeContext>(\n contributions: readonly LabContribution<TCtx>[],\n region: LabRegion,\n): LabContribution<TCtx>[] {\n return contributions.filter((c) => c.region === region);\n}\n\n/** The palette contributions a lab's `tools` stand for. Declaring a tool is\n * shorthand for contributing a palette item that writes the lab's tool\n * slot. */\nexport function toolContributions(tools: readonly TrialTool[]): LabContribution[] {\n return tools.map((t) => ({\n id: t.id,\n region: 'palette' as const,\n ...(t.group === undefined ? {} : { group: t.group }),\n item: {\n icon: t.icon,\n label: t.label,\n ...(t.shortcut === undefined ? {} : { shortcut: t.shortcut }),\n },\n }));\n}\n\n/** Everything the lab's chrome renders, from both of the ways a lab declares\n * it. Tools and contributions share one id namespace, so a tool colliding\n * with a contribution throws here rather than one of them silently losing. */\nexport function labContributions(\n tools: readonly TrialTool[] | undefined,\n chrome: readonly LabContribution[] | undefined,\n): LabContribution[] {\n return mergeContributions<LabContribution>(toolContributions(tools ?? []), [...(chrome ?? [])]);\n}\n\n/** Props shared by the lab's region mounts. Each takes the lab's whole\n * contribution list and lays out the part addressed to it. */\nexport interface LabRegionProps {\n contributions: readonly LabContribution[];\n}\n\n/** The lab's action bar, in the shell header beside the title. */\nexport function LabHeaderRegion({ contributions }: LabRegionProps) {\n const ctx = useLabChromeContext();\n return (\n <ToolbarRegion\n region=\"header\"\n label=\"Lab actions\"\n contributions={contributionsIn(contributions, 'header')}\n ctx={ctx}\n />\n );\n}\n\nfunction LabSections({ contributions, region }: LabRegionProps & { region: 'sidebar' | 'aside' }) {\n const lab = useLabChromeContext();\n const [collapsedSections, setFolds] = usePersistedState<Record<string, boolean>>(\n `lk-lab-${region}-folds`,\n {},\n { scope: 'lab' },\n );\n const ctx = useMemo(\n () => ({\n ...lab,\n collapsedSections,\n setSectionCollapsed: (key: string, collapsed: boolean) =>\n setFolds((f) => ({ ...f, [key]: collapsed })),\n }),\n [lab, collapsedSections, setFolds],\n );\n return (\n <SidebarRegion\n contributions={contributionsIn(contributions, region)}\n ctx={ctx}\n region={region}\n />\n );\n}\n\n/** The lab's sidebar sections. Fold state is a lab-scoped persisted value, so it\n * survives a reload in a stored lab and lasts the session in an unstored one. */\nexport function LabSidebarRegion({ contributions }: LabRegionProps) {\n return <LabSections contributions={contributions} region=\"sidebar\" />;\n}\n\n/** The lab's aside sections, on the far side of the workspace from the sidebar.\n * Fold state persists the way the sidebar's does. */\nexport function LabAsideRegion({ contributions }: LabRegionProps) {\n return <LabSections contributions={contributions} region=\"aside\" />;\n}\n\n/** The lab's readouts, in the shell footer below the workspace. */\nexport function LabFooterRegion({ contributions }: LabRegionProps) {\n const ctx = useLabChromeContext();\n return (\n <StatusRegion\n region=\"footer\"\n contributions={contributionsIn(contributions, 'footer')}\n ctx={ctx}\n />\n );\n}\n","import { ToolButton, ToolGroup } from '../../passthrough/weasel-ui';\nimport { useRovingTabIndex } from '../../primitives/useRovingTabIndex';\nimport type { RegionContribution, ToolItem, ToolSlotContext, TrialChromeContext } from '../types';\n\n/** Props for `<PaletteRegion>`. */\nexport interface PaletteRegionProps<TCtx extends ToolSlotContext = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out. The lab's rail names the same box\n * `palette` too, so this only moves for a chrome that does not. */\n region?: string;\n}\n\n/** A tool strip: a trial's, or the lab's. Selection lives in whichever tool\n * slot the context carries; this region only reflects it. An item carrying\n * `onActivate` is a command instead — it presses, and never latches. */\nexport function PaletteRegion<TCtx extends ToolSlotContext = TrialChromeContext>({\n contributions,\n ctx,\n region = 'palette',\n}: PaletteRegionProps<TCtx>) {\n const { ref, onKeyDown } = useRovingTabIndex<HTMLDivElement>('vertical');\n if (contributions.length === 0) return null;\n return (\n <div\n ref={ref}\n className=\"lk-palette-region\"\n role=\"toolbar\"\n aria-label=\"Tools\"\n aria-orientation=\"vertical\"\n onKeyDown={onKeyDown}\n >\n <ToolGroup orientation=\"vertical\">\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== region || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, onActivate } = c.item as ToolItem<TCtx>;\n return (\n <ToolButton\n key={c.id}\n icon={<Icon size={16} />}\n label={label}\n shortcut={shortcut}\n active={onActivate ? false : ctx.activeToolId === c.id}\n disabled={disabled}\n onClick={onActivate ? () => onActivate(ctx) : () => ctx.setActiveTool(c.id)}\n />\n );\n })}\n </ToolGroup>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Which end of the title bar a `<TitleBarRegion>` lays out: `'lead'` renders\n * the contributions that leave `end` unset, before the title; `'actions'`\n * renders the ones that set it, after everything else. */\nexport type TitleBarPlacement = 'lead' | 'actions';\n\n/** Props for `<TitleBarRegion>`. */\nexport interface TitleBarRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n /** Defaults to `'actions'`, where the built-ins live. */\n placement?: TitleBarPlacement;\n}\n\nfunction renderEntry(c: TrialContribution, ctx: TrialChromeContext): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'titlebar' || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, danger, onActivate } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className={`lk-titlebar-button${danger ? ' lk-titlebar-button--danger' : ''}`}\n disabled={disabled}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={() => onActivate(ctx)}\n // The bar behind these buttons is the window drag surface, so a press\n // that lands here must not also start a drag.\n onPointerDown={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <Icon size={16} />\n </button>\n );\n}\n\n/** Lays a trial's `titlebar` contributions out at one end of the bar. */\nexport function TitleBarRegion({ contributions, ctx, placement = 'actions' }: TitleBarRegionProps) {\n const wanted = placement === 'actions';\n const mine = contributions.filter((c) => (c.end ?? false) === wanted);\n if (mine.length === 0) return null;\n return (\n <span className={wanted ? 'lk-trial__titlebar-actions' : 'lk-trial__titlebar-lead'}>\n {mine.map((c) => renderEntry(c, ctx))}\n </span>\n );\n}\n","import { useRovingTabIndex } from '../../primitives/useRovingTabIndex';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<ViewportRegion>`. */\nexport interface ViewportRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\n/**\n * Controls acting on the view of a trial. Anchored inside the content well\n * rather than in the toolbar, which acts on the trial itself.\n */\nexport function ViewportRegion({ contributions, ctx }: ViewportRegionProps) {\n const { ref, onKeyDown } = useRovingTabIndex<HTMLDivElement>();\n if (contributions.length === 0) return null;\n return (\n <div\n ref={ref}\n className=\"lk-viewport-controls\"\n role=\"toolbar\"\n aria-label=\"View\"\n onKeyDown={onKeyDown}\n >\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'viewport' || !c.item) return null;\n const { icon: Icon, label, disabled, onActivate } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className=\"lk-viewport-controls__button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={() => onActivate(ctx)}\n >\n <Icon size={16} />\n </button>\n );\n })}\n </div>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { usePersistedState } from './chunk-RWNDDKOH.js';
2
- import { openPointerSession } from '@weasel-js/core';
2
+ import { openPointerSession, pastDragThreshold } from '@weasel-js/core';
3
3
  import { useRef, useMemo, useState, useEffect } from 'react';
4
4
  import { floatingStrategy, DEFAULT_INSET, DEFAULT_ANCHOR, FLOATING_DRAG_PREFIX } from 'windease';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -10,7 +10,6 @@ function borderBoxOf(entry) {
10
10
  if (box) return { w: box.inlineSize, h: box.blockSize };
11
11
  return { w: entry.contentRect.width, h: entry.contentRect.height };
12
12
  }
13
- var DRAG_THRESHOLD = 3;
14
13
  function isInteractive(target) {
15
14
  if (!(target instanceof Element)) return false;
16
15
  return target.closest("input, button, a, select, textarea, [data-no-drag]") !== null;
@@ -92,7 +91,7 @@ function FloatingPanel({
92
91
  {
93
92
  onMove: (ev) => {
94
93
  if (!dragging.current) {
95
- if (Math.hypot(ev.clientX - start.x, ev.clientY - start.y) < DRAG_THRESHOLD) return;
94
+ if (!pastDragThreshold({ clientX: start.x, clientY: start.y }, ev)) return;
96
95
  dragging.current = { ...start };
97
96
  setDragging(true);
98
97
  origin.setPointerCapture?.(pointerId);
@@ -140,5 +139,5 @@ function FloatingPanel({
140
139
  }
141
140
 
142
141
  export { FloatingPanel };
143
- //# sourceMappingURL=chunk-NEXR37YJ.js.map
144
- //# sourceMappingURL=chunk-NEXR37YJ.js.map
142
+ //# sourceMappingURL=chunk-J7OWWTCW.js.map
143
+ //# sourceMappingURL=chunk-J7OWWTCW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/primitives/FloatingPanel.tsx"],"names":[],"mappings":"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","file":"chunk-J7OWWTCW.js","sourcesContent":["import { openPointerSession, type PointerSession, pastDragThreshold } from '@weasel-js/core';\nimport type React from 'react';\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n type Corner,\n DEFAULT_ANCHOR,\n DEFAULT_INSET,\n FLOATING_DRAG_PREFIX,\n type FloatingPlacement,\n floatingStrategy,\n} from 'windease';\nimport { usePersistedState } from '../state/usePersistedState';\n\n/** The strategy holds a map keyed by item id; a panel is always a lone item. */\nconst ITEM_ID = 'panel';\n\n/** Props for `<FloatingPanel>`. */\nexport interface FloatingPanelProps {\n children: ReactNode;\n /** Corner it rests in before it has ever been dragged. Default `'bottom-left'`. */\n anchor?: Corner;\n /** Corners that may capture it. Default: all four. */\n snapCorners?: readonly Corner[];\n /** Pixels in from a corner when snapped. Default 12. */\n inset?: number;\n /** Name to remember its position under, through `usePersistedState` — so it\n * is remembered only inside a lab or a `<Persistence>`. Omit to forget on\n * reload. */\n persist?: string;\n className?: string;\n}\n\n/**\n * The panel's footprint is its border box — `contentRect` excludes padding and\n * border, which would place a panel that then overflows its corner by exactly\n * that much.\n */\nfunction borderBoxOf(entry: ResizeObserverEntry): { w: number; h: number } {\n const box = entry.borderBoxSize?.[0];\n if (box) return { w: box.inlineSize, h: box.blockSize };\n return { w: entry.contentRect.width, h: entry.contentRect.height };\n}\n\n/** A pointerdown on one of these is the child's, not a drag. */\nfunction isInteractive(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false;\n return target.closest('input, button, a, select, textarea, [data-no-drag]') !== null;\n}\n\n/**\n * A draggable box that floats over its offset parent and snaps to its corners.\n *\n * Drives windease's `floatingStrategy` as a pure function rather than mounting a\n * windease container: a lab overlay has one item and no zone tree, so the node\n * model would be all cost. Pointer handling is therefore this component's, and\n * windease's own affordance rendering never participates.\n */\nexport function FloatingPanel({\n children,\n anchor = DEFAULT_ANCHOR,\n snapCorners,\n inset = DEFAULT_INSET,\n persist,\n className,\n}: FloatingPanelProps) {\n const ref = useRef<HTMLDivElement>(null);\n const strategy = useMemo(() => floatingStrategy(), []);\n const options = useMemo(() => ({ defaultAnchor: anchor, inset }), [anchor, inset]);\n\n const [container, setContainer] = useState({ w: 0, h: 0 });\n const [size, setSize] = useState({ w: 0, h: 0 });\n const [place, setPlace] = usePersistedState<FloatingPlacement>(persist, () => ({\n x: 0,\n y: 0,\n anchor,\n }));\n\n const item = useMemo(\n () => ({\n id: ITEM_ID,\n meta: { floating: true, ...(snapCorners ? { snapCorners: [...snapCorners] } : {}) },\n natural: size,\n }),\n [size, snapCorners],\n );\n\n useEffect(() => {\n const el = ref.current;\n const parent = el?.offsetParent ?? el?.parentElement;\n if (!el || !parent) return;\n // Sizes come off the entry, not the DOM: jsdom reports 0 for every\n // clientWidth/offsetWidth, and an unmeasured item is withheld from layout.\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === parent) {\n setContainer({ w: entry.contentRect.width, h: entry.contentRect.height });\n } else {\n setSize(borderBoxOf(entry));\n }\n }\n });\n observer.observe(parent);\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const rect = strategy\n .layout({\n items: [item],\n container,\n state: { at: { [ITEM_ID]: place }, inner: undefined },\n options,\n })\n .placements.get(ITEM_ID);\n\n const dragging = useRef<{ x: number; y: number } | null>(null);\n const session = useRef<PointerSession | null>(null);\n const [isDragging, setDragging] = useState(false);\n // A drag outlives the render that started it, so the reducer's inputs are\n // read here and not from that render's closure — a container resized\n // mid-drag would otherwise place the panel against its old box.\n const layout = useRef({ container, options, item });\n layout.current = { container, options, item };\n\n useEffect(() => () => session.current?.cancel(), []);\n\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (isInteractive(e.target)) return;\n // The canvas stack underneath owns pan/zoom on the same pointer events.\n e.stopPropagation();\n const origin = e.currentTarget;\n const pointerId = e.pointerId;\n const start = { x: e.clientX, y: e.clientY };\n\n const end = () => {\n session.current = null;\n if (!dragging.current) return;\n dragging.current = null;\n setDragging(false);\n try {\n origin.releasePointerCapture?.(pointerId);\n } catch {\n // Capture is already gone whenever the session ended by losing it.\n }\n };\n\n // Armed, not capturing. Capture retargets mouseup to this element, and the\n // browser then synthesizes no `click` on the child under the cursor — so\n // capturing on press makes every non-native control in the panel dead to a\n // real mouse, silently. `isInteractive` only exempts the names it lists; a\n // `role=\"button\"` span, a react-aria control or a canvas is not among them.\n session.current = openPointerSession(\n origin,\n e,\n {\n onMove: (ev) => {\n if (!dragging.current) {\n if (!pastDragThreshold({ clientX: start.x, clientY: start.y }, ev)) return;\n dragging.current = { ...start };\n setDragging(true);\n origin.setPointerCapture?.(pointerId);\n }\n const from = dragging.current;\n const dx = ev.clientX - from.x;\n const dy = ev.clientY - from.y;\n if (dx === 0 && dy === 0) return;\n dragging.current = { x: ev.clientX, y: ev.clientY };\n const { container: box, options: opts, item: only } = layout.current;\n setPlace(\n (prev) =>\n strategy.reduce?.(\n { at: { [ITEM_ID]: prev }, inner: undefined },\n {\n affordanceId: `${FLOATING_DRAG_PREFIX}${ITEM_ID}`,\n kind: 'drag',\n payload: { dx, dy },\n },\n { container: box, options: opts, items: [only] },\n ).at[ITEM_ID] ?? prev,\n );\n },\n onEnd: end,\n onCancel: end,\n },\n { capture: false },\n );\n };\n\n return (\n <div\n className={className ? `lk-floating-panel ${className}` : 'lk-floating-panel'}\n data-dragging={isDragging ? 'true' : undefined}\n data-placed={rect ? 'true' : undefined}\n onPointerDown={onPointerDown}\n ref={ref}\n style={\n {\n position: 'absolute',\n left: `${rect?.x ?? 0}px`,\n top: `${rect?.y ?? 0}px`,\n } as CSSProperties\n }\n >\n {children}\n </div>\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { schemaNodeAtPath } from './chunk-TJ77A4A3.js';
1
+ import { schemaNodeAtPath } from './chunk-Y23G2VZL.js';
2
2
 
3
3
  // src/config/fromConfigField.ts
4
4
  function toLeaf(field) {
@@ -41,7 +41,7 @@ function toLeaf(field) {
41
41
  }
42
42
  }
43
43
  function fromConfigFields(fields) {
44
- const children = {};
44
+ const root = { name: "", children: {} };
45
45
  for (const field of fields) {
46
46
  const patch = toLeaf(field);
47
47
  for (const key of Object.keys(patch)) {
@@ -49,10 +49,20 @@ function fromConfigFields(fields) {
49
49
  delete patch[key];
50
50
  }
51
51
  }
52
- children[field.key] = { ...patch, default: field.default };
52
+ const segments = field.key.split(".");
53
+ const leafKey = segments.pop();
54
+ let group = root;
55
+ for (const segment of segments) {
56
+ const existing = group.children[segment];
57
+ if (existing === void 0 || !("children" in existing) || "kind" in existing) {
58
+ group.children[segment] = { name: "", children: {} };
59
+ }
60
+ group = group.children[segment];
61
+ }
62
+ group.children[leafKey] = { ...patch, default: field.default };
53
63
  }
54
64
  return {
55
- group: { name: "", children },
65
+ group: root,
56
66
  sections: [],
57
67
  showIf: /* @__PURE__ */ new Map(),
58
68
  renderers: {},
@@ -69,5 +79,5 @@ function isLeafVisible(resolved, path, config, showHidden = false) {
69
79
  }
70
80
 
71
81
  export { fromConfigFields, isLeafVisible };
72
- //# sourceMappingURL=chunk-IRTGUQ5O.js.map
73
- //# sourceMappingURL=chunk-IRTGUQ5O.js.map
82
+ //# sourceMappingURL=chunk-KMJ7RWD3.js.map
83
+ //# sourceMappingURL=chunk-KMJ7RWD3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/fromConfigField.ts","../src/config/visible.ts"],"names":[],"mappings":"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","file":"chunk-KMJ7RWD3.js","sourcesContent":["import type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\nimport type { ConfigField } from '../controls/types';\nimport type { LeafPatch, ResolvedConfig } from './types';\n\n/** One `ConfigField` as the `Pref*` vocabulary spells it. The two describe the\n * same thing; `ConfigField` just keys on the control where `PrefLeaf`\n * separates the value's kind from how it is presented. */\nfunction toLeaf(field: ConfigField): LeafPatch {\n const base = { name: field.label, description: '' };\n switch (field.type) {\n case 'slider':\n return {\n ...base,\n kind: 'number',\n control: 'slider',\n min: field.min,\n max: field.max,\n step: field.step,\n };\n case 'number':\n return {\n ...base,\n kind: 'number',\n control: 'input',\n min: field.min,\n max: field.max,\n step: field.step,\n };\n case 'checkbox':\n return { ...base, kind: 'boolean', control: 'checkbox' };\n case 'select':\n return { ...base, kind: 'enum', options: field.options };\n case 'text':\n return {\n ...base,\n kind: 'string',\n placeholder: field.placeholder,\n maxLength: field.maxLength,\n debounceMs: field.debounceMs,\n };\n case 'color':\n return { ...base, kind: 'color' };\n default:\n // A schema can arrive from outside TypeScript. Carry the kind through\n // so a lab-supplied renderer can still claim it.\n return { ...base, kind: (field as ConfigField).type };\n }\n}\n\n/**\n * Adapt a legacy `configSchema(): ConfigField[]` into the resolved shape, so\n * both instrument paths reach one renderer.\n *\n * Rules do not run here: a hand-written `ConfigField` already states its label\n * and control, which is everything the rule chain would have inferred.\n *\n * A dotted `key` is a config path, as it is to every read and write, so its\n * leaf is filed under headless groups at that path rather than as one child\n * whose name contains dots — which no path lookup would find.\n */\nexport function fromConfigFields(fields: readonly ConfigField[]): ResolvedConfig {\n const root: PrefGroup = { name: '', children: {} };\n for (const field of fields) {\n const patch = toLeaf(field);\n for (const key of Object.keys(patch)) {\n if ((patch as Record<string, unknown>)[key] === undefined) {\n delete (patch as Record<string, unknown>)[key];\n }\n }\n const segments = field.key.split('.');\n const leafKey = segments.pop() as string;\n let group = root;\n for (const segment of segments) {\n const existing = group.children[segment];\n if (existing === undefined || !('children' in existing) || 'kind' in existing) {\n group.children[segment] = { name: '', children: {} };\n }\n group = group.children[segment] as PrefGroup;\n }\n group.children[leafKey] = { ...patch, default: field.default } as PrefLeaf;\n }\n return {\n group: root,\n sections: [],\n showIf: new Map(),\n renderers: {},\n dialogs: {},\n };\n}\n","import { schemaNodeAtPath } from './path';\nimport type { ResolvedConfig } from './types';\n\n/**\n * Whether the row at a dotted path should be drawn right now. A group answers\n * for its whole subtree — hiding one hides everything under it.\n *\n * `hidden` is the node's own static flag; `showIf` is the schema's predicate\n * over the live config. Both are presentational — a hidden leaf keeps its\n * value and the instrument still reads it.\n */\nexport function isLeafVisible(\n resolved: ResolvedConfig,\n path: string,\n config: Record<string, unknown>,\n showHidden = false,\n): boolean {\n const node = schemaNodeAtPath(resolved.group, path);\n if (node && 'hidden' in node && node.hidden === true && !showHidden) return false;\n const predicate = resolved.showIf.get(path);\n return predicate ? predicate(config) : true;\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { centerOn, zoomAt } from './chunk-JVBYV6TL.js';
2
2
  import { screenToWorld } from './chunk-AWQG7FCC.js';
3
- import { CameraContext, CameraScope } from './chunk-DWMSB4CA.js';
3
+ import { CameraContext, CameraScope } from './chunk-UNAZSLWE.js';
4
4
  import { resolveFrame, DEFAULT_FRAME } from './chunk-24W5VEJW.js';
5
5
  import { CanvasStackContext } from './chunk-CQLQPQ4P.js';
6
6
  import { useVisibleRaf, useActionsRegistry, useGestureDispatcher, normalizeZoom } from '@weasel-js/core';
@@ -243,7 +243,7 @@ function LoupeDispatch({
243
243
  useGestureDispatcher({
244
244
  canvasRef: hostRef,
245
245
  actions: registry,
246
- toolsById: NO_TOOLS,
246
+ entriesById: NO_TOOLS,
247
247
  channels: CHANNELS,
248
248
  enabled: ownDispatcher
249
249
  });
@@ -545,5 +545,5 @@ function resolveLoupe(declared) {
545
545
  }
546
546
 
547
547
  export { CanvasLoupe, DomLoupe, LOUPE_DEFAULTS, LOUPE_MAGNIFY_ID, LOUPE_PEEK_ID, LoupeBubble, LoupeGestures, TrialLoupe, createLoupeActions, drawCanvasLens, lensCamera, lensSourceRect, resolveLoupe, sampleStack, useLoupe };
548
- //# sourceMappingURL=chunk-S4NCI32V.js.map
549
- //# sourceMappingURL=chunk-S4NCI32V.js.map
548
+ //# sourceMappingURL=chunk-M7HP3FTK.js.map
549
+ //# sourceMappingURL=chunk-M7HP3FTK.js.map