@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,6 +1,6 @@
1
- import { fromConfigFields, isLeafVisible } from './chunk-IRTGUQ5O.js';
2
- import { resolveAutoConfig, schemaNodeAtPath, valueAtPath, auto } from './chunk-TJ77A4A3.js';
3
- import { v3, oe, ae2, b2, s4, L3, s2, B2, V2, m2 } from './chunk-TYN6MLXX.js';
1
+ import { fromConfigFields, isLeafVisible } from './chunk-KMJ7RWD3.js';
2
+ import { resolveAutoConfig, schemaNodeAtPath, valueAtPath, auto } from './chunk-Y23G2VZL.js';
3
+ import { v2, ie2, re2, b2, s3, I, c2, R, c, B, z2, m2 } from './chunk-MIM5R4ZT.js';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
  import { isBuiltinToolPref, toHex8, withAlpha01, getAlpha01 } from '@weasel-js/core';
6
6
  import { useMemo, useState, Fragment as Fragment$1, useRef, useEffect } from 'react';
@@ -16,7 +16,7 @@ function inDialog(body, opts = {}) {
16
16
  const { pref, value, auto: auto2, setAuto } = ctx;
17
17
  const manual = pref.manual === true;
18
18
  return /* @__PURE__ */ jsx(
19
- v3,
19
+ v2,
20
20
  {
21
21
  label: pref.name,
22
22
  description: pref.description,
@@ -39,6 +39,35 @@ function sectionRows(section, rows) {
39
39
  };
40
40
  }
41
41
  var NO_AUTO = /* @__PURE__ */ new Set();
42
+ function leavesUnder(group, at) {
43
+ return Object.entries(group.children).flatMap(([key, child]) => {
44
+ const path = at === "" ? key : `${at}.${key}`;
45
+ return s3(child) ? [[path, child.default]] : leavesUnder(child, path);
46
+ });
47
+ }
48
+ function ResetGroup({
49
+ group,
50
+ path,
51
+ config,
52
+ setConfig
53
+ }) {
54
+ const changed = leavesUnder(group, path).filter(([p, d]) => !Object.is(valueAtPath(config, p), d));
55
+ return /* @__PURE__ */ jsx(
56
+ c,
57
+ {
58
+ iconOnly: true,
59
+ variant: "ghost",
60
+ size: "sm",
61
+ ariaLabel: `Reset ${group.name}`,
62
+ tooltip: `Reset ${group.name} to defaults`,
63
+ disabled: changed.length === 0,
64
+ onClick: () => {
65
+ for (const [p, d] of changed) setConfig(p, d);
66
+ },
67
+ children: /* @__PURE__ */ jsx(B, {})
68
+ }
69
+ );
70
+ }
42
71
  function ControlPanel({
43
72
  schema,
44
73
  fields,
@@ -80,7 +109,7 @@ function ControlPanel({
80
109
  [resolved, config, auto2]
81
110
  );
82
111
  const gridPack = gridOf(pack);
83
- const folds = collapse !== void 0 || collapsed !== void 0 || onCollapse !== void 0 || resolved.sections.some((s3) => s3.collapsed !== void 0);
112
+ const folds = collapse !== void 0 || collapsed !== void 0 || onCollapse !== void 0 || resolved.sections.some((s2) => s2.collapsed !== void 0);
84
113
  const startsFolded = collapse === "closed";
85
114
  const fold = (key, declared, grid = gridPack) => ({
86
115
  pack: grid,
@@ -93,7 +122,7 @@ function ControlPanel({
93
122
  const found = schemaNodeAtPath(resolved.group, path);
94
123
  if (!found) return null;
95
124
  if (!isLeafVisible(resolved, path, config, showHidden)) return null;
96
- if (s4(found)) {
125
+ if (s3(found)) {
97
126
  return /* @__PURE__ */ jsx(
98
127
  ControlRow,
99
128
  {
@@ -119,6 +148,7 @@ function ControlPanel({
119
148
  title: found.name,
120
149
  description: found.description,
121
150
  span: true,
151
+ actions: resolved.resettable?.has(path) ? /* @__PURE__ */ jsx(ResetGroup, { group: found, path, config, setConfig }) : void 0,
122
152
  ...fold(path, void 0, rows.grid),
123
153
  children: body(found, path, rows)
124
154
  },
@@ -127,7 +157,7 @@ function ControlPanel({
127
157
  };
128
158
  const pairable = (path) => {
129
159
  const found = schemaNodeAtPath(resolved.group, path);
130
- if (!found || !s4(found)) return void 0;
160
+ if (!found || !s3(found)) return void 0;
131
161
  const pair = extra(found, "pair");
132
162
  if (pair === void 0) return void 0;
133
163
  if (!isLeafVisible(resolved, path, config, showHidden))
@@ -174,8 +204,8 @@ function ControlPanel({
174
204
  return out;
175
205
  };
176
206
  const body = (group, at, rows) => {
177
- const sections = resolved.sections.filter((s3) => s3.at === at);
178
- const sectioned = new Set(sections.flatMap((s3) => s3.paths));
207
+ const sections = resolved.sections.filter((s2) => s2.at === at);
208
+ const sectioned = new Set(sections.flatMap((s2) => s2.paths));
179
209
  const paths = Object.keys(group.children).map((key) => at === "" ? key : `${at}.${key}`);
180
210
  return /* @__PURE__ */ jsxs(Fragment, { children: [
181
211
  rowsFor(
@@ -197,7 +227,7 @@ function ControlPanel({
197
227
  ] });
198
228
  };
199
229
  const list = /* @__PURE__ */ jsx(
200
- oe,
230
+ ie2,
201
231
  {
202
232
  pack: gridPack,
203
233
  density,
@@ -207,7 +237,7 @@ function ControlPanel({
207
237
  }
208
238
  );
209
239
  if (title === void 0 && stance === void 0 && tone === void 0) return list;
210
- return /* @__PURE__ */ jsx(ae2, { title, stance, tone, density, children: list });
240
+ return /* @__PURE__ */ jsx(re2, { title, stance, tone, density, children: list });
211
241
  }
212
242
  function sectionKey(section) {
213
243
  return section.at === "" ? section.label : `${section.at}.${section.label}`;
@@ -252,7 +282,7 @@ function ControlRow({
252
282
  if (leaf.kind === "list") {
253
283
  const entries = Array.isArray(value) ? value : [];
254
284
  return /* @__PURE__ */ jsx(
255
- v3,
285
+ v2,
256
286
  {
257
287
  label,
258
288
  summary: summarizeValue(entries),
@@ -261,7 +291,7 @@ function ControlRow({
261
291
  description,
262
292
  ...autoProps,
263
293
  children: () => /* @__PURE__ */ jsx(
264
- s2,
294
+ c2,
265
295
  {
266
296
  "aria-label": label,
267
297
  value: entries,
@@ -279,11 +309,11 @@ function ControlRow({
279
309
  case "string":
280
310
  return /* @__PURE__ */ jsx(DebouncedTextRow, { leaf, field, span: wide, ...row });
281
311
  case "number":
282
- return /* @__PURE__ */ jsx(B2, { ...field, ...row, span: field.control === "slider" && wide });
312
+ return /* @__PURE__ */ jsx(R, { ...field, ...row, span: field.control === "slider" && wide });
283
313
  case "enum":
284
- return /* @__PURE__ */ jsx(B2, { ...field, ...row, span: field.control === "radio" && wide });
314
+ return /* @__PURE__ */ jsx(R, { ...field, ...row, span: field.control === "toggle" && wide });
285
315
  default:
286
- return /* @__PURE__ */ jsx(B2, { ...field, ...row });
316
+ return /* @__PURE__ */ jsx(R, { ...field, ...row });
287
317
  }
288
318
  }
289
319
  function labField(leaf, value, write) {
@@ -303,7 +333,10 @@ function labField(leaf, value, write) {
303
333
  control: extra(leaf, "control") === "switch" ? "switch" : "checkbox"
304
334
  };
305
335
  case "enum":
306
- return { ...field, control: extra(leaf, "control") === "radio" ? "radio" : "select" };
336
+ return {
337
+ ...field,
338
+ control: extra(leaf, "control") === "radio" ? "toggle" : "select"
339
+ };
307
340
  case "string":
308
341
  return {
309
342
  ...field,
@@ -319,7 +352,7 @@ function UnwiredRow({
319
352
  kind,
320
353
  description
321
354
  }) {
322
- return /* @__PURE__ */ jsx(L3, { label, description, children: /* @__PURE__ */ jsxs("span", { className: "lk-control-panel__unknown", children: [
355
+ return /* @__PURE__ */ jsx(I, { label, description, children: /* @__PURE__ */ jsxs("span", { className: "lk-control-panel__unknown", children: [
323
356
  "no control for \u201C",
324
357
  kind,
325
358
  "\u201D"
@@ -335,7 +368,7 @@ function DebouncedTextRow({
335
368
  field.onChange,
336
369
  extra(leaf, "debounceMs") ?? 150
337
370
  );
338
- return /* @__PURE__ */ jsx(B2, { ...field, ...row, value: text.local, onChange: text.type });
371
+ return /* @__PURE__ */ jsx(R, { ...field, ...row, value: text.local, onChange: text.type });
339
372
  }
340
373
  function PairedRow({
341
374
  label,
@@ -345,7 +378,7 @@ function PairedRow({
345
378
  layout,
346
379
  span
347
380
  }) {
348
- return /* @__PURE__ */ jsx(L3, { group: true, span, label, layout, children: cells.map(({ path, leaf }) => (
381
+ return /* @__PURE__ */ jsx(I, { group: true, span, label, layout, children: cells.map(({ path, leaf }) => (
349
382
  // The row is named by the pair, so a cell that shares it says which
350
383
  // knob it is — without a caption a paired switch reads only to a
351
384
  // screen reader. A cell whose leaf is deliberately unnamed keeps none.
@@ -376,13 +409,13 @@ function PairCell({
376
409
  if (field === null) return null;
377
410
  switch (field.kind) {
378
411
  case "string":
379
- return /* @__PURE__ */ jsx(V2, { ...field, name: leaf.name, value: text.local, onChange: text.type });
412
+ return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name, value: text.local, onChange: text.type });
380
413
  case "number":
381
- return /* @__PURE__ */ jsx(V2, { ...field, name: leaf.name, control: "input", unit: void 0 });
414
+ return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name, control: "input", unit: void 0 });
382
415
  case "color": {
383
416
  const stored = typeof value === "string" ? toHex8(value) : "#000000";
384
417
  return /* @__PURE__ */ jsx(
385
- V2,
418
+ z2,
386
419
  {
387
420
  ...field,
388
421
  name: leaf.name,
@@ -392,7 +425,7 @@ function PairCell({
392
425
  );
393
426
  }
394
427
  default:
395
- return /* @__PURE__ */ jsx(V2, { ...field, name: leaf.name });
428
+ return /* @__PURE__ */ jsx(z2, { ...field, name: leaf.name });
396
429
  }
397
430
  }
398
431
  function useDebouncedText(value, write, debounceMs) {
@@ -427,5 +460,5 @@ function useDebouncedText(value, write, debounceMs) {
427
460
  }
428
461
 
429
462
  export { ControlPanel, inDialog, summarizeValue };
430
- //# sourceMappingURL=chunk-ASOK76ZH.js.map
431
- //# sourceMappingURL=chunk-ASOK76ZH.js.map
463
+ //# sourceMappingURL=chunk-T5IBSPAM.js.map
464
+ //# sourceMappingURL=chunk-T5IBSPAM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/controls/inDialog.tsx","../src/controls/ControlPanel.tsx"],"names":["auto","v","s","jsx","Fragment","b","ie","re","value","c","m","z"],"mappings":"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","file":"chunk-T5IBSPAM.js","sourcesContent":["import { DialogRow } from '@weasel-js/ui';\nimport type { ControlRenderer, InDialogOptions } from '../config/types';\n\nexport type { InDialogOptions };\n\n/** The one-line summary a dialog row shows when it is given none. */\nexport function summarizeValue(value: unknown): string {\n if (Array.isArray(value)) return value.length === 0 ? 'None' : value.join(', ');\n if (value === undefined || value === null || value === '') return 'None';\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\n}\n\n/**\n * Moves a control into a modal: the row becomes a button showing a summary of\n * the value, and the button opens a dialog whose body is `body`, handed the\n * same context a row renderer gets. For a leaf whose editor will never fit a\n * sidebar row.\n */\nexport function inDialog(body: ControlRenderer, opts: InDialogOptions = {}): ControlRenderer {\n const summary = opts.summary ?? summarizeValue;\n return (ctx) => {\n const { pref, value, auto, setAuto } = ctx;\n const manual = (pref as { manual?: boolean }).manual === true;\n return (\n <DialogRow\n label={pref.name}\n description={pref.description}\n summary={summary(value)}\n title={opts.title}\n readout={auto ? 'auto' : undefined}\n auto={auto}\n onAutoChange={manual ? undefined : setAuto}\n >\n {() => body(ctx)}\n </DialogRow>\n );\n };\n}\n","import { getAlpha01, isBuiltinToolPref, toHex8, withAlpha01 } from '@weasel-js/core';\nimport {\n Button,\n DialogRow,\n isPrefLeaf,\n ListEditor,\n type PrefGroup,\n type PrefLeaf,\n type PropertyAlign,\n PropertyControl,\n type PropertyControlProps,\n type PropertyDensity,\n PropertyField,\n PropertyGroup,\n PropertyList,\n type PropertyListPack,\n PropertyPanel,\n PropertyRow,\n type PropertyRowLayout,\n prefFieldProps,\n ResetIcon,\n type StanceProps,\n} from '@weasel-js/ui';\nimport { Fragment, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport { auto as autoValue } from '../config/auto';\nimport { resolveAutoConfig } from '../config/autoConfig';\nimport { fromConfigFields } from '../config/fromConfigField';\nimport { schemaNodeAtPath, valueAtPath } from '../config/path';\nimport type { ControlRenderer, ResolvedConfig, SectionSpec } from '../config/types';\nimport { isLeafVisible } from '../config/visible';\nimport { inDialog, summarizeValue } from './inDialog';\nimport type { ConfigField } from './types';\n\n/** How a panel packs its rows into the two-column property grid.\n * - `'auto'`: narrow controls (numbers, checkboxes, dropdowns, colors) sit\n * two per row; the ones that need the width — text, sliders, segmented\n * toggles — span it.\n * - `'pairs'`: every row pairs. A control that needs the full width says so\n * itself, with `<PropertyRow span>`.\n * - `'one-up'`: one control per row, colors excepted.\n */\nexport type ControlPack = 'auto' | 'pairs' | 'one-up';\n\n/** How the rows under one heading are laid out: the panel's, or a section's own. */\ninterface Rows {\n pack: ControlPack;\n layout: PropertyRowLayout | undefined;\n grid: PropertyListPack;\n}\n\nconst gridOf = (pack: ControlPack): PropertyListPack =>\n pack === 'one-up' ? 'auto-color' : 'pairs';\n\nfunction sectionRows(section: SectionSpec, rows: Rows): Rows {\n return {\n pack: section.pack ?? rows.pack,\n layout: section.layout ?? rows.layout,\n grid: section.pack ? gridOf(section.pack) : rows.grid,\n };\n}\n\nexport interface ControlPanelProps<TC extends Record<string, unknown>> extends StanceProps {\n /** The instrument's resolved config schema. */\n schema?: ResolvedConfig;\n /** @deprecated Pass `schema`. A field list is adapted into one internally. */\n fields?: ConfigField[];\n config: TC;\n /** Writes one value. The path is dotted for a leaf inside an `f.group`, and\n * the bare key for one at the root. */\n setConfig: (path: string, value: unknown) => void;\n /**\n * Control overrides and app-defined kinds, PrefsForm-style. Keys are config\n * paths (checked first) or leaf kinds. A renderer returning `null` collapses\n * the row; entries override the built-in rows on collision.\n */\n renderers?: Record<string, ControlRenderer>;\n /** How rows pack into the two-column grid. Defaults to `'pairs'`. */\n pack?: ControlPack;\n /**\n * Where a row's label sits relative to its control. Unset takes each row's\n * own orientation — `block` (label above, which is what leaves a paired row\n * room for its value) for most, `inline` for colors and checkboxes.\n */\n layout?: PropertyRowLayout;\n /** Room the rows get. Passed straight to the property list. */\n density?: PropertyDensity;\n /** Cross-axis alignment of an inline row's label and control. */\n align?: PropertyAlign;\n /**\n * Fold each section away behind a twisty, starting `'open'` or `'closed'`.\n * Unset draws the heading alone, as the panel always has — unless a section\n * in the schema declares how it opens, which makes that section foldable on\n * its own and outranks this for that one section.\n */\n collapse?: 'open' | 'closed';\n /**\n * Which sections are folded, keyed as `onCollapse` reports them. Given, the\n * panel keeps no state of its own: every toggle arrives at `onCollapse`\n * instead, which is where a lab that remembers a trial's sections writes\n * them.\n */\n collapsed?: Readonly<Record<string, boolean>>;\n /** A fold moved. The key is a section's label — prefixed by its group's\n * dotted path when the section sits inside one — or a group's own path. */\n onCollapse?: (key: string, collapsed: boolean) => void;\n /** Dotted paths currently unpinned. A row in this set hides its control and\n * reads out `auto`, and clicking its label writes the sentinel back through\n * `setConfig`. Omitted, the panel keeps the set itself: the labels still\n * toggle and the sentinel never reaches `setConfig`, which would otherwise\n * store it as the row's value. */\n auto?: ReadonlySet<string>;\n /** Draw leaves marked `hidden`. */\n showHidden?: boolean;\n /** Heads the panel. With `title`, `stance` or `tone` given, the rows sit in a\n * `<PropertyPanel>` carrying them; with none, they are the bare list. */\n title?: ReactNode;\n className?: string;\n}\n\nconst NO_AUTO: ReadonlySet<string> = new Set();\n\n/** Every leaf beneath a group, as its dotted path and its default. */\nfunction leavesUnder(group: PrefGroup, at: string): [string, unknown][] {\n return Object.entries(group.children).flatMap(([key, child]) => {\n const path = at === '' ? key : `${at}.${key}`;\n return isPrefLeaf(child) ? [[path, child.default] as [string, unknown]] : leavesUnder(child, path);\n });\n}\n\n/** The heading button of a `.resettable()` group: writes each changed leaf's\n * default, and is disabled while nothing has changed. */\nfunction ResetGroup({\n group,\n path,\n config,\n setConfig,\n}: {\n group: PrefGroup;\n path: string;\n config: Record<string, unknown>;\n setConfig: (path: string, value: unknown) => void;\n}) {\n const changed = leavesUnder(group, path).filter(([p, d]) => !Object.is(valueAtPath(config, p), d));\n return (\n <Button\n iconOnly\n variant=\"ghost\"\n size=\"sm\"\n ariaLabel={`Reset ${group.name}`}\n tooltip={`Reset ${group.name} to defaults`}\n disabled={changed.length === 0}\n onClick={() => {\n for (const [p, d] of changed) setConfig(p, d);\n }}\n >\n <ResetIcon />\n </Button>\n );\n}\n\n/** Render an instrument's config schema as a stack of controls, each writing\n * back through `setConfig`. Built on the property rows, so a lab's controls\n * are the same aligned, themed rows the rest of the kit uses. */\nexport function ControlPanel<TC extends Record<string, unknown>>({\n schema,\n fields,\n config,\n setConfig,\n renderers,\n pack = 'pairs',\n layout,\n density,\n align,\n collapse,\n collapsed,\n onCollapse,\n auto: given,\n showHidden = false,\n title,\n stance,\n tone,\n className,\n}: ControlPanelProps<TC>) {\n const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);\n\n // An owner that tracks the set decides what a dot means; one that does not\n // gets a panel that decides for itself, because the alternative is handing it\n // a sentinel it would write into the config as though it were a value.\n const [ownAuto, setOwnAuto] = useState<ReadonlySet<string>>(NO_AUTO);\n const auto = given ?? ownAuto;\n const setRowAuto = (path: string, next: boolean, value: unknown): void => {\n if (given) {\n setConfig(path, next ? autoValue : value);\n return;\n }\n setOwnAuto((prev) => {\n const now = new Set(prev);\n if (next) now.add(path);\n else now.delete(path);\n return now;\n });\n // Pinning keeps whatever the row was showing, the same value the controlled\n // path writes back.\n if (!next) setConfig(path, value);\n };\n\n // What the instrument is reading. A row draws and reports from this rather\n // than calling its own resolver against the raw config, which would disagree\n // with the instrument whenever a resolver depends on another auto path.\n const shown = useMemo(\n () => (auto && auto.size > 0 ? resolveAutoConfig(resolved, config, auto) : config),\n [resolved, config, auto],\n );\n\n const gridPack = gridOf(pack);\n // A section that declares how it opens is foldable whether or not the lab\n // asked for folds — there is nothing else for the declaration to mean.\n const folds =\n collapse !== undefined ||\n collapsed !== undefined ||\n onCollapse !== undefined ||\n resolved.sections.some((s) => s.collapsed !== undefined);\n const startsFolded = collapse === 'closed';\n\n const fold = (key: string, declared?: boolean, grid: PropertyListPack = gridPack) => ({\n pack: grid,\n collapsible: folds,\n defaultCollapsed: declared ?? startsFolded,\n collapsed: collapsed ? (collapsed[key] ?? declared ?? startsFolded) : undefined,\n onCollapsedChange: onCollapse ? (next: boolean) => onCollapse(key, next) : undefined,\n });\n\n /** One node, which is either a group to recurse into or a row to draw. */\n const node = (path: string, rows: Rows): ReactNode => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found) return null;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden)) return null;\n if (isPrefLeaf(found)) {\n return (\n <ControlRow\n key={path}\n path={path}\n leaf={found}\n resolved={resolved}\n config={config}\n shown={shown}\n setConfig={setConfig}\n renderers={renderers}\n pack={rows.pack}\n layout={rows.layout}\n auto={auto}\n setRowAuto={setRowAuto}\n />\n );\n }\n // A group with no name organizes without heading it — core's rule for an\n // empty `PrefGroup.name` — so it contributes its rows and no chrome.\n if (found.name === '') return <Fragment key={path}>{body(found, path, rows)}</Fragment>;\n return (\n <PropertyGroup\n key={path}\n title={found.name}\n description={found.description}\n // A nested group is a block of rows, not a control: half of a\n // two-column grid leaves it laying its own rows out inside a cell,\n // which overlaps them.\n span\n actions={\n resolved.resettable?.has(path) ? (\n <ResetGroup group={found} path={path} config={config as Record<string, unknown>} setConfig={setConfig} />\n ) : undefined\n }\n {...fold(path, undefined, rows.grid)}\n >\n {body(found, path, rows)}\n </PropertyGroup>\n );\n };\n\n /**\n * The leaf at `path` if it may share a row with its neighbours: `pair` is\n * presentational, so a leaf whose control the lab draws itself, or one whose\n * control needs the whole row, keeps its own row instead.\n */\n const pairable = (path: string): { leaf: PrefLeaf; pair: string } | undefined => {\n const found = schemaNodeAtPath(resolved.group, path);\n if (!found || !isPrefLeaf(found)) return undefined;\n const pair = extra<string>(found, 'pair');\n if (pair === undefined) return undefined;\n if (!isLeafVisible(resolved, path, config as Record<string, unknown>, showHidden))\n return undefined;\n if (\n renderers?.[path] ??\n resolved.renderers[path] ??\n resolved.dialogs[path] ??\n renderers?.[found.kind]\n )\n return undefined;\n if (!isBuiltinToolPref(found)) return undefined;\n if (found.kind === 'paint' || found.kind === 'object' || isSliderLeaf(found)) return undefined;\n return { leaf: found, pair };\n };\n\n /** A run of sibling paths as rows, merging each run of adjacent leaves\n * sharing a `pair` id into one row named by the pair. */\n const rowsFor = (paths: readonly string[], rows: Rows): ReactNode[] => {\n const out: ReactNode[] = [];\n for (let i = 0; i < paths.length; ) {\n const head = pairable(paths[i]);\n if (!head) {\n out.push(node(paths[i], rows));\n i += 1;\n continue;\n }\n const { pair } = head;\n const cells = [{ path: paths[i], leaf: head.leaf }];\n let j = i + 1;\n for (; j < paths.length; j += 1) {\n const next = pairable(paths[j]);\n if (!next || next.pair !== pair) break;\n cells.push({ path: paths[j], leaf: next.leaf });\n }\n out.push(\n <PairedRow\n key={paths[i]}\n label={pair}\n cells={cells}\n shown={shown}\n setConfig={setConfig}\n layout={rows.layout}\n // A segmented cell carries every choice at once, so a pair holding\n // one needs the whole row the way a segmented row of its own does.\n span={cells.some(({ leaf }) => extra<string>(leaf, 'control') === 'radio')}\n />,\n );\n i = j;\n }\n return out;\n };\n\n /** One group's children: its loose nodes, then its sections. */\n const body = (group: PrefGroup, at: string, rows: Rows): ReactNode => {\n const sections = resolved.sections.filter((s) => s.at === at);\n const sectioned = new Set(sections.flatMap((s) => s.paths));\n const paths = Object.keys(group.children).map((key) => (at === '' ? key : `${at}.${key}`));\n return (\n <>\n {rowsFor(\n paths.filter((p) => !sectioned.has(p)),\n rows,\n )}\n {sections.map((section) => {\n const inner = sectionRows(section, rows);\n return (\n <PropertyGroup\n key={sectionKey(section)}\n title={section.label}\n {...fold(sectionKey(section), section.collapsed, inner.grid)}\n >\n {rowsFor(section.paths, inner)}\n </PropertyGroup>\n );\n })}\n </>\n );\n };\n\n const list = (\n <PropertyList\n pack={gridPack}\n density={density}\n align={align}\n className={className ? `lk-control-panel ${className}` : 'lk-control-panel'}\n >\n {body(resolved.group, '', { pack, layout, grid: gridPack })}\n </PropertyList>\n );\n if (title === undefined && stance === undefined && tone === undefined) return list;\n return (\n <PropertyPanel title={title} stance={stance} tone={tone} density={density}>\n {list}\n </PropertyPanel>\n );\n}\n\n/** How a section is keyed for folding: its label at the root, and its group's\n * path in front of it anywhere else, so two groups may both have an\n * `Advanced`. */\nfunction sectionKey(section: SectionSpec): string {\n return section.at === '' ? section.label : `${section.at}.${section.label}`;\n}\n\ninterface ControlRowProps<TC extends Record<string, unknown>> {\n path: string;\n leaf: PrefLeaf;\n resolved: ResolvedConfig;\n config: TC;\n /** `config` with every auto path resolved -- what the instrument reads. */\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n renderers?: Record<string, ControlRenderer>;\n pack: ControlPack;\n layout?: PropertyRowLayout;\n auto?: ReadonlySet<string>;\n setRowAuto: (path: string, next: boolean, value: unknown) => void;\n}\n\n/** Whether this leaf draws as a slider, mirroring the condition the `number`\n * arm below branches on. A slider is the one control whose value cannot be\n * read off the control itself. */\nfunction isSliderLeaf(leaf: PrefLeaf): boolean {\n return (\n leaf.kind === 'number' &&\n extra<string>(leaf, 'control') === 'slider' &&\n extra<number>(leaf, 'min') !== undefined &&\n extra<number>(leaf, 'max') !== undefined\n );\n}\n\n/** Reads a labkit-only extra off a leaf. `PrefLeaf` has no field for these,\n * and extra keys survive the resolve pass at runtime. */\nfunction extra<T>(leaf: PrefLeaf, key: string): T | undefined {\n return (leaf as unknown as Record<string, T | undefined>)[key];\n}\n\nfunction ControlRow<TC extends Record<string, unknown>>({\n path,\n leaf,\n resolved,\n config,\n shown,\n setConfig,\n renderers,\n pack,\n layout,\n auto,\n setRowAuto,\n}: ControlRowProps<TC>) {\n const write = (value: unknown): void => setConfig(path, value);\n const fallback = extra<unknown>(leaf, 'default');\n const pinned = valueAtPath(config, path) ?? fallback;\n\n const isAutoRow = auto?.has(path) ?? false;\n const canAuto = !extra<boolean>(leaf, 'manual');\n // Read out of the resolved config rather than re-running this leaf's own\n // resolver, so the row reports the value the instrument actually got — the\n // two diverge as soon as a resolver reads another auto path.\n const resolvedValue = isAutoRow ? valueAtPath(shown, path) : undefined;\n // An auto row draws what the resolver decided, not the value underneath it —\n // a handle sitting at the pinned number while the readout says something else\n // reads as a rendering bug. Pinning then keeps what you were looking at.\n const value = resolvedValue ?? pinned;\n const setAuto = (next: boolean): void => setRowAuto(path, next, value);\n const onAutoChange = canAuto ? setAuto : undefined;\n // An auto row hides its control, so the word is all the row has to say.\n const autoReadout = isAutoRow ? 'auto' : undefined;\n const autoProps = { auto: isAutoRow, onAutoChange };\n\n // Most specific wins, and within a tier the lab's entry beats the\n // instrument's: controls[path] -> node .render/.dialog -> controls[kind] -> built-in.\n const dialog = resolved.dialogs[path];\n const custom =\n renderers?.[path] ??\n resolved.renderers[path] ??\n (dialog ? inDialog(dialog.body, dialog) : undefined) ??\n renderers?.[leaf.kind];\n // A custom row places itself like any other; one that needs the full width\n // says so with `<PropertyRow span>`, which is the same opt-out a built-in has.\n if (custom) return custom({ path, pref: leaf, value, setValue: write, auto: isAutoRow, setAuto });\n\n const label = leaf.name;\n const description = leaf.description;\n // `auto` gives the whole width to the controls that read badly at half of a\n // sidebar's: free text, a slider track, a segmented toggle. `pairs` doesn't.\n const wide = pack === 'auto';\n const row = { label, description, layout, readout: autoReadout, ...autoProps };\n\n if (leaf.kind === 'list') {\n const entries = Array.isArray(value) ? (value as string[]) : [];\n return (\n <DialogRow\n label={label}\n summary={summarizeValue(entries)}\n readout={autoReadout}\n layout={layout}\n description={description}\n {...autoProps}\n >\n {() => (\n <ListEditor\n aria-label={label}\n value={entries}\n onChange={write}\n placeholder={extra<string>(leaf, 'placeholder')}\n />\n )}\n </DialogRow>\n );\n }\n\n const field = labField(leaf, value, write);\n if (field === null)\n return <UnwiredRow label={label} kind={leaf.kind} description={description} />;\n switch (field.kind) {\n case 'string':\n return <DebouncedTextRow leaf={leaf} field={field} span={wide} {...row} />;\n case 'number':\n return <PropertyField {...field} {...row} span={field.control === 'slider' && wide} />;\n case 'enum':\n return <PropertyField {...field} {...row} span={field.control === 'toggle' && wide} />;\n default:\n return <PropertyField {...field} {...row} />;\n }\n}\n\n/**\n * A leaf as the field it draws, with the labkit-only extras `prefFieldProps`\n * knows nothing of. `null` for a kind the panel declines: a paint, which a\n * hex swatch would flatten to a solid, and an object, which a flat row would\n * write one field of. Override with `render` to edit either.\n */\nfunction labField(\n leaf: PrefLeaf,\n value: unknown,\n write: (value: unknown) => void,\n): PropertyControlProps | null {\n if (!isBuiltinToolPref(leaf) || leaf.kind === 'paint' || leaf.kind === 'object') return null;\n const field = prefFieldProps(leaf, { value, setValue: write });\n if (field === null) return null;\n switch (field.kind) {\n case 'number':\n // `prefFieldProps` clamps what it stores, so an instrument is never\n // handed a value outside the range it asked for.\n return {\n ...field,\n control: isSliderLeaf(leaf) ? 'slider' : 'input',\n unit: extra<string>(leaf, 'suffix') ?? field.unit,\n };\n case 'boolean':\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'switch' ? 'switch' : 'checkbox',\n };\n case 'enum':\n // `.radio()` asks for every option at once, as segments.\n return {\n ...field,\n control: extra<string>(leaf, 'control') === 'radio' ? 'toggle' : 'select',\n };\n case 'string':\n return {\n ...field,\n placeholder: extra<string>(leaf, 'placeholder'),\n maxLength: extra<number>(leaf, 'maxLength'),\n };\n default:\n return field;\n }\n}\n\n/** A leaf this panel has no control for is named rather than dropped: a silent\n * gap reads as \"this control does not exist\". */\nfunction UnwiredRow({\n label,\n kind,\n description,\n}: {\n label: string;\n kind: string;\n description?: string;\n}) {\n return (\n <PropertyRow label={label} description={description}>\n <span className=\"lk-control-panel__unknown\">no control for “{kind}”</span>\n </PropertyRow>\n );\n}\n\n/** A text row whose writes are debounced — see {@link useDebouncedText}. */\nfunction DebouncedTextRow({\n leaf,\n field,\n ...row\n}: {\n leaf: PrefLeaf;\n field: PropertyControlProps & { kind: 'string' };\n label: string;\n layout?: PropertyRowLayout;\n span?: boolean;\n description?: string;\n readout?: ReactNode;\n auto?: boolean;\n onAutoChange?: (next: boolean) => void;\n}) {\n const text = useDebouncedText(\n field.value ?? '',\n field.onChange,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n return <PropertyField {...field} {...row} value={text.local} onChange={text.type} />;\n}\n\n/** One cell of a paired row, with its path and the leaf it draws. */\ninterface PairCellSpec {\n path: string;\n leaf: PrefLeaf;\n}\n\n/**\n * Leaves sharing a `pair` id, side by side on one row the pair names — the\n * compact `X` / `Y` idiom `SelectionPanel` draws for the same annotation.\n *\n * The cells are bare controls: a row holds one label column, so each leaf's\n * own name stays with its control as the accessible name and its description\n * as a title. For the same reason the row's label does not toggle auto — it\n * names one path, and this row has several.\n */\nfunction PairedRow<TC extends Record<string, unknown>>({\n label,\n cells,\n shown,\n setConfig,\n layout,\n span,\n}: {\n label: string;\n cells: readonly PairCellSpec[];\n shown: TC;\n setConfig: (path: string, value: unknown) => void;\n layout?: PropertyRowLayout;\n span?: boolean;\n}) {\n return (\n <PropertyRow group span={span} label={label} layout={layout}>\n {cells.map(({ path, leaf }) => (\n // The row is named by the pair, so a cell that shares it says which\n // knob it is — without a caption a paired switch reads only to a\n // screen reader. A cell whose leaf is deliberately unnamed keeps none.\n <span key={path} className=\"lk-pair-cell\" title={leaf.description || undefined}>\n {leaf.name ? <span className=\"lk-pair-label\">{leaf.name}</span> : null}\n <PairCell\n leaf={leaf}\n value={valueAtPath(shown, path) ?? extra<unknown>(leaf, 'default')}\n write={(value) => setConfig(path, value)}\n />\n </span>\n ))}\n </PropertyRow>\n );\n}\n\n/** The control a paired cell holds, without the row chrome a whole row of its\n * own would bring. */\nfunction PairCell({\n leaf,\n value,\n write,\n}: {\n leaf: PrefLeaf;\n value: unknown;\n write: (value: unknown) => void;\n}) {\n const text = useDebouncedText(\n typeof value === 'string' ? value : '',\n write,\n extra<number>(leaf, 'debounceMs') ?? 150,\n );\n const field = labField(leaf, value, write);\n // Unreachable for null: `pairable` admits only kinds with a field.\n if (field === null) return null;\n switch (field.kind) {\n case 'string':\n return (\n <PropertyControl {...field} name={leaf.name} value={text.local} onChange={text.type} />\n );\n case 'number':\n // The pair names the row, so a cell has no room for a unit.\n return <PropertyControl {...field} name={leaf.name} control=\"input\" unit={undefined} />;\n case 'color': {\n // The alpha track needs a row of its own to sit under, so a paired\n // swatch edits the color and carries the stored alpha through untouched.\n const stored = typeof value === 'string' ? toHex8(value) : '#000000';\n return (\n <PropertyControl\n {...field}\n name={leaf.name}\n alpha={undefined}\n onChange={(rgb: string) =>\n write(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb)\n }\n />\n );\n }\n default:\n return <PropertyControl {...field} name={leaf.name} />;\n }\n}\n\n/**\n * Live text held locally between debounced commits, so typing does not re-run\n * the instrument on every keystroke. Locally controlled between commits, which\n * means it has to notice the value changing underneath it.\n */\nfunction useDebouncedText(\n value: string,\n write: (value: string) => void,\n debounceMs: number,\n): { local: string; type: (next: string) => void } {\n const [local, setLocal] = useState(value);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const lastExternal = useRef(value);\n\n useEffect(() => {\n if (value !== lastExternal.current) {\n lastExternal.current = value;\n setLocal(value);\n }\n }, [value]);\n\n useEffect(\n () => () => {\n if (timer.current) clearTimeout(timer.current);\n },\n [],\n );\n\n return {\n local,\n type: (next) => {\n setLocal(next);\n if (timer.current) clearTimeout(timer.current);\n const commit = () => {\n lastExternal.current = next;\n write(next);\n };\n if (debounceMs === 0) commit();\n else timer.current = setTimeout(commit, debounceMs);\n },\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_FRAME } from './chunk-24W5VEJW.js';
2
- import { createContext, useContext, useRef, useMemo, useEffect } from 'react';
3
- import { normalizeZoom, usePointerContext, DepRegistryProvider, ActionsProvider, ActiveToolContextProvider, PointerContextProvider, useActionsRegistry, useDepSource, makeViewportZoomAction, viewportDragPanAction, useGestureDispatcher } from '@weasel-js/core';
2
+ import { createContext, useContext, useEffect, useRef, useMemo } from 'react';
3
+ import { normalizeZoom, useActionsRegistry, usePointerContext, PointerContextProvider, useDepSource, makeViewportZoomAction, viewportDragPanAction, useGestureDispatcher, InputScope } from '@weasel-js/core';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
 
6
6
  var CameraWheelContext = createContext(null);
@@ -23,6 +23,65 @@ function normalize2DView(view) {
23
23
  function withZoom(view, zoom) {
24
24
  return normalize2DView({ zoom, pan: view.pan });
25
25
  }
26
+ function createCameraRegistry() {
27
+ const stacks = /* @__PURE__ */ new Map();
28
+ const listeners = /* @__PURE__ */ new Set();
29
+ const notify = () => {
30
+ for (const l of listeners) l();
31
+ };
32
+ return {
33
+ register(key, camera) {
34
+ const stack = stacks.get(key) ?? [];
35
+ stack.push(camera);
36
+ stacks.set(key, stack);
37
+ notify();
38
+ let released = false;
39
+ return () => {
40
+ if (released) return;
41
+ released = true;
42
+ const cur = stacks.get(key);
43
+ const i = cur?.lastIndexOf(camera) ?? -1;
44
+ if (!cur || i === -1) return;
45
+ cur.splice(i, 1);
46
+ if (cur.length === 0) stacks.delete(key);
47
+ notify();
48
+ };
49
+ },
50
+ get: (key) => stacks.get(key)?.at(-1) ?? null,
51
+ subscribe(listener) {
52
+ listeners.add(listener);
53
+ return () => {
54
+ listeners.delete(listener);
55
+ };
56
+ }
57
+ };
58
+ }
59
+ var CameraRegistryContext = createContext(null);
60
+ var CameraPublishContext = createContext(
61
+ null
62
+ );
63
+ function usePublishCamera(camera) {
64
+ const publish = useContext(CameraPublishContext);
65
+ const actions = useActionsRegistry();
66
+ useEffect(() => {
67
+ if (!publish) return;
68
+ let release = publish(camera);
69
+ if (!actions) return release;
70
+ let was = actions.isActive();
71
+ const off = actions.subscribe(() => {
72
+ const now = actions.isActive();
73
+ if (now && !was) {
74
+ release();
75
+ release = publish(camera);
76
+ }
77
+ was = now;
78
+ });
79
+ return () => {
80
+ off();
81
+ release();
82
+ };
83
+ }, [publish, camera, actions]);
84
+ }
26
85
 
27
86
  // src/canvas/cameraView.ts
28
87
  function toCameraView(view, frame = DEFAULT_FRAME) {
@@ -60,13 +119,12 @@ function clampZoomAbout(prev, next, min, max) {
60
119
  }
61
120
  var STAGE_VIEW_ID = "stage";
62
121
  var CameraContext = createContext(null);
63
- var CameraScopeContext = createContext(false);
64
- function CameraScope({ children }) {
65
- const inScope = useContext(CameraScopeContext);
122
+ function CameraScope({ yoke, children }) {
123
+ const around = useContext(CameraContext);
66
124
  const pointer = usePointerContext();
67
- if (inScope) return /* @__PURE__ */ jsx(Fragment, { children });
68
- const scoped = /* @__PURE__ */ jsx(CameraScopeContext.Provider, { value: true, children });
69
- return /* @__PURE__ */ jsx(DepRegistryProvider, { children: /* @__PURE__ */ jsx(ActionsProvider, { children: /* @__PURE__ */ jsx(ActiveToolContextProvider, { children: pointer ? scoped : /* @__PURE__ */ jsx(PointerContextProvider, { children: scoped }) }) }) });
125
+ if (around) return /* @__PURE__ */ jsx(Fragment, { children });
126
+ const scoped = /* @__PURE__ */ jsx(InputScope, { yoke, children });
127
+ return pointer ? scoped : /* @__PURE__ */ jsx(PointerContextProvider, { children: scoped });
70
128
  }
71
129
  function isPositiveFinite(n) {
72
130
  return Number.isFinite(n) && n > 0;
@@ -102,7 +160,8 @@ function useCameraView({
102
160
  hostSize: () => {
103
161
  const r = hostRef.current?.getBoundingClientRect();
104
162
  return r ? { width: r.width, height: r.height } : null;
105
- }
163
+ },
164
+ zoomRange: () => ({ ...bounds.current })
106
165
  };
107
166
  }, [hostRef]);
108
167
  }
@@ -150,7 +209,8 @@ function CameraDispatch({
150
209
  }
151
210
  };
152
211
  return [
153
- viewportDragPanAction,
212
+ // A trial pans on a plain drag; the kit action binds none of its own.
213
+ { ...viewportDragPanAction, defaultBinding: { kind: "drag" } },
154
214
  { ...zoom, defaultBinding: wheelOnly },
155
215
  tap
156
216
  ];
@@ -175,22 +235,28 @@ function CameraDispatch({
175
235
  useGestureDispatcher({
176
236
  canvasRef: hostRef,
177
237
  actions: registry,
178
- toolsById: NO_TOOLS,
238
+ entriesById: NO_TOOLS,
179
239
  clientToWorld,
180
240
  channels: CHANNELS
181
241
  });
182
242
  usePublishPointer(hostRef, clientToWorld, frame, STAGE_VIEW_ID);
243
+ usePublishCamera(camera);
183
244
  const wheelSlot = useContext(CameraWheelContext);
184
245
  useEffect(() => {
185
246
  if (!wheelSlot) return;
186
247
  const forward = (e) => {
187
248
  hostRef.current?.dispatchEvent(new WheelEvent("wheel", e));
188
249
  };
189
- wheelSlot.current = forward;
250
+ const claim = () => {
251
+ if (registry.isActive()) wheelSlot.current = forward;
252
+ };
253
+ claim();
254
+ const off = registry.subscribe(claim);
190
255
  return () => {
256
+ off();
191
257
  if (wheelSlot.current === forward) wheelSlot.current = null;
192
258
  };
193
- }, [wheelSlot, hostRef]);
259
+ }, [wheelSlot, hostRef, registry]);
194
260
  return null;
195
261
  }
196
262
  function usePublishPointer(hostRef, clientToLocal, frame, viewId) {
@@ -223,6 +289,6 @@ function pointerElsewhere(p, viewId, frame) {
223
289
  return frameLocalToWorld({ x: p.worldX, y: p.worldY }, frame);
224
290
  }
225
291
 
226
- export { CameraContext, CameraInput, CameraScope, CameraScopeContext, CameraWheelContext, DEFAULT_VIEW, STAGE_VIEW_ID, as2DView, clampZoomAbout, frameLocalToWorld, fromCameraView, normalize2DView, pointerElsewhere, toCameraView, useCameraView, usePublishPointer, withZoom };
227
- //# sourceMappingURL=chunk-DWMSB4CA.js.map
228
- //# sourceMappingURL=chunk-DWMSB4CA.js.map
292
+ export { CameraContext, CameraInput, CameraPublishContext, CameraRegistryContext, CameraScope, CameraWheelContext, DEFAULT_VIEW, STAGE_VIEW_ID, as2DView, clampZoomAbout, createCameraRegistry, frameLocalToWorld, fromCameraView, normalize2DView, pointerElsewhere, toCameraView, useCameraView, usePublishCamera, usePublishPointer, withZoom };
293
+ //# sourceMappingURL=chunk-UNAZSLWE.js.map
294
+ //# sourceMappingURL=chunk-UNAZSLWE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/canvas/CameraWheelContext.ts","../src/state/view.ts","../src/canvas/cameraRegistry.ts","../src/canvas/cameraView.ts","../src/canvas/CameraInput.tsx"],"names":["createContext","useContext","useActionsRegistry","useEffect"],"mappings":";;;;;AAWO,IAAM,kBAAA,GAAqB,cAAsC,IAAI;ACJrE,IAAM,YAAA,GAAgC,EAAE,IAAA,EAAM,CAAA,EAAG,GAAA,EAAK,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE;AAInE,SAAS,SAAS,IAAA,EAAuC;AAC9D,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,MAAM,OAAO,IAAA;AACtD,EAAA,MAAM,CAAA,GAAI,IAAA;AACV,EAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACvC,EAAA,IAAI,OAAO,CAAA,CAAE,GAAA,KAAQ,YAAY,CAAA,CAAE,GAAA,KAAQ,MAAM,OAAO,IAAA;AACxD,EAAA,IAAI,OAAO,CAAA,CAAE,GAAA,CAAI,CAAA,KAAM,QAAA,IAAY,OAAO,CAAA,CAAE,GAAA,CAAI,CAAA,KAAM,QAAA,EAAU,OAAO,IAAA;AACvE,EAAA,OAAO,gBAAgB,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,KAAK,EAAE,CAAA,EAAG,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,EAAG,CAAA,CAAE,GAAA,CAAI,CAAA,IAAK,CAAA;AAC1E;AAKO,SAAS,gBAAgB,IAAA,EAAwC;AACtE,EAAA,MAAM,IAAA,GAAO,aAAA,CAAc,IAAA,CAAK,IAAI,CAAA;AACpC,EAAA,MAAM,CAAA,GAAI,OAAO,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAA;AACrD,EAAA,MAAM,CAAA,GAAI,OAAO,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAA;AACrD,EAAA,IAAI,IAAA,KAAS,IAAA,CAAK,IAAA,IAAQ,CAAA,KAAM,IAAA,CAAK,GAAA,CAAI,CAAA,IAAK,CAAA,KAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,IAAA;AACvE,EAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,EAAE,CAAA,EAAG,GAAE,EAAE;AAC/B;AAGO,SAAS,QAAA,CAAS,MAAuB,IAAA,EAA+B;AAC7E,EAAA,OAAO,gBAAgB,EAAE,IAAA,EAAM,GAAA,EAAK,IAAA,CAAK,KAAK,CAAA;AAChD;ACjBO,SAAS,oBAAA,GAAuC;AACrD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAA0B;AAC7C,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAgB;AACtC,EAAA,MAAM,SAAS,MAAY;AACzB,IAAA,KAAA,MAAW,CAAA,IAAK,WAAW,CAAA,EAAE;AAAA,EAC/B,CAAA;AACA,EAAA,OAAO;AAAA,IACL,QAAA,CAAS,KAAK,MAAA,EAAQ;AACpB,MAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,GAAG,KAAK,EAAC;AAClC,MAAA,KAAA,CAAM,KAAK,MAAM,CAAA;AACjB,MAAA,MAAA,CAAO,GAAA,CAAI,KAAK,KAAK,CAAA;AACrB,MAAA,MAAA,EAAO;AACP,MAAA,IAAI,QAAA,GAAW,KAAA;AACf,MAAA,OAAO,MAAM;AACX,QAAA,IAAI,QAAA,EAAU;AACd,QAAA,QAAA,GAAW,IAAA;AACX,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAC1B,QAAA,MAAM,CAAA,GAAI,GAAA,EAAK,WAAA,CAAY,MAAM,CAAA,IAAK,EAAA;AACtC,QAAA,IAAI,CAAC,GAAA,IAAO,CAAA,KAAM,EAAA,EAAI;AACtB,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAC,CAAA;AACf,QAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,MAAA,CAAO,OAAO,GAAG,CAAA;AACvC,QAAA,MAAA,EAAO;AAAA,MACT,CAAA;AAAA,IACF,CAAA;AAAA,IACA,GAAA,EAAK,CAAC,GAAA,KAAQ,MAAA,CAAO,IAAI,GAAG,CAAA,EAAG,EAAA,CAAG,EAAE,CAAA,IAAK,IAAA;AAAA,IACzC,UAAU,QAAA,EAAU;AAClB,MAAA,SAAA,CAAU,IAAI,QAAQ,CAAA;AACtB,MAAA,OAAO,MAAM;AACX,QAAA,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,MAC3B,CAAA;AAAA,IACF;AAAA,GACF;AACF;AAGO,IAAM,qBAAA,GAAwBA,cAAqC,IAAI;AAIvE,IAAM,oBAAA,GAAuBA,aAAAA;AAAA,EAClC;AACF;AAMO,SAAS,iBAAiB,MAAA,EAA0B;AACzD,EAAA,MAAM,OAAA,GAAU,WAAW,oBAAoB,CAAA;AAC/C,EAAA,MAAM,UAAU,kBAAA,EAAmB;AACnC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,IAAI,OAAA,GAAU,QAAQ,MAAM,CAAA;AAC5B,IAAA,IAAI,CAAC,SAAS,OAAO,OAAA;AACrB,IAAA,IAAI,GAAA,GAAM,QAAQ,QAAA,EAAS;AAC3B,IAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,SAAA,CAAU,MAAM;AAClC,MAAA,MAAM,GAAA,GAAM,QAAQ,QAAA,EAAS;AAC7B,MAAA,IAAI,GAAA,IAAO,CAAC,GAAA,EAAK;AACf,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,GAAU,QAAQ,MAAM,CAAA;AAAA,MAC1B;AACA,MAAA,GAAA,GAAM,GAAA;AAAA,IACR,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,EAAI;AACJ,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,MAAA,EAAQ,OAAO,CAAC,CAAA;AAC/B;;;ACtEO,SAAS,YAAA,CAAa,IAAA,EAAqB,KAAA,GAAoB,aAAA,EAAqB;AACzF,EAAA,MAAM,CAAA,GAAI,gBAAgB,IAAI,CAAA;AAC9B,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,EAAE,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,CAAE,IAAA;AAAA,IACrC,CAAA,EAAG,EAAE,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,CAAE,IAAA;AAAA,IACrC,OAAO,EAAE,CAAA,EAAG,EAAE,IAAA,EAAM,CAAA,EAAG,EAAE,IAAA;AAAK,GAChC;AACF;AAGO,SAAS,cAAA,CAAe,IAAA,EAAY,KAAA,GAAoB,aAAA,EAA8B;AAC3F,EAAA,MAAM,IAAA,GAAO,KAAK,KAAA,CAAM,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,KAAK,EAAE,CAAA,EAAG,CAAC,IAAA,CAAK,IAAI,IAAA,GAAO,KAAA,CAAM,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,IAAA,CAAK,IAAI,IAAA,GAAO,KAAA,CAAM,SAAS,CAAA;AAAE,GACpF;AACF;AAIO,SAAS,iBAAA,CAAkB,CAAA,EAAU,KAAA,GAAoB,aAAA,EAAsB;AACpF,EAAA,OAAO,EAAE,GAAG,CAAA,CAAE,CAAA,EAAG,GAAG,CAAA,CAAE,CAAA,GAAI,MAAM,IAAA,EAAK;AACvC;AAOO,SAAS,cAAA,CAAe,IAAA,EAAY,IAAA,EAAY,GAAA,EAAa,GAAA,EAAmB;AACrF,EAAA,MAAM,EAAA,GAAK,KAAK,KAAA,CAAM,CAAA;AACtB,EAAA,MAAM,EAAA,GAAK,KAAK,KAAA,CAAM,CAAA;AACtB,EAAA,MAAM,OAAA,GAAU,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,EAAE,CAAC,CAAA;AAC/C,EAAA,IAAI,OAAA,KAAY,IAAI,OAAO,IAAA;AAC3B,EAAA,IAAI,EAAA,KAAO,EAAA,EAAI,OAAO,EAAE,GAAG,IAAA,EAAM,KAAA,EAAO,EAAE,CAAA,EAAG,OAAA,EAAS,CAAA,EAAG,OAAA,EAAQ,EAAE;AAEnE,EAAA,MAAM,GAAA,GAAM,CAAA,GAAI,EAAA,GAAK,CAAA,GAAI,EAAA;AACzB,EAAA,MAAM,EAAA,GAAA,CAAM,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA,IAAK,GAAA;AAC/B,EAAA,MAAM,EAAA,GAAA,CAAM,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA,IAAK,GAAA;AAE/B,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,EAAA,GAAK,KAAK,EAAA,GAAK,OAAA;AAAA,IAC3B,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,EAAA,GAAK,KAAK,EAAA,GAAK,OAAA;AAAA,IAC3B,KAAA,EAAO,EAAE,CAAA,EAAG,OAAA,EAAS,GAAG,OAAA;AAAQ,GAClC;AACF;ACrBO,IAAM,aAAA,GAAgB;AAkBtB,IAAM,aAAA,GAAgBA,cAAyC,IAAI;AAUnE,SAAS,WAAA,CAAY,EAAE,IAAA,EAAM,QAAA,EAAS,EAAyC;AACpF,EAAA,MAAM,MAAA,GAASC,WAAW,aAAa,CAAA;AACvC,EAAA,MAAM,UAAU,iBAAA,EAAkB;AAClC,EAAA,IAAI,MAAA,EAAQ,uBAAO,GAAA,CAAA,QAAA,EAAA,EAAG,QAAA,EAAS,CAAA;AAC/B,EAAA,MAAM,MAAA,mBAAS,GAAA,CAAC,UAAA,EAAA,EAAW,IAAA,EAAa,QAAA,EAAS,CAAA;AACjD,EAAA,OAAO,OAAA,GAAU,MAAA,mBAAS,GAAA,CAAC,sBAAA,EAAA,EAAwB,QAAA,EAAA,MAAA,EAAO,CAAA;AAC5D;AAuBA,SAAS,iBAAiB,CAAA,EAAoB;AAC5C,EAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,GAAI,CAAA;AACnC;AAOO,SAAS,aAAA,CAAc;AAAA,EAC5B,IAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA,GAAU,GAAA;AAAA,EACV,OAAA,GAAU;AACZ,CAAA,EAAkC;AAChC,EAAA,MAAM,IAAA,GAAO,OAAO,EAAE,IAAA,EAAM,gBAAgB,IAAI,CAAA,EAAG,YAAA,EAAc,KAAA,EAAO,CAAA;AACxE,EAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAM,gBAAgB,IAAI,CAAA,EAAG,cAAc,KAAA,EAAM;AAClE,EAAA,MAAM,WAAA,GAAc,OAAO,gBAAA,CAAiB,IAAA,CAAK,IAAI,CAAA,GAAI,IAAA,CAAK,OAAO,IAAI,CAAA;AACzE,EAAA,MAAM,SAAS,MAAA,CAAO,EAAE,KAAK,OAAA,EAAS,GAAA,EAAK,SAAS,CAAA;AACpD,EAAA,MAAM,UAAU,WAAA,CAAY,OAAA;AAC5B,EAAA,MAAA,CAAO,OAAA,GAAU;AAAA,IACf,KAAK,OAAA,IAAW,IAAA,GAAO,UAAU,IAAA,CAAK,GAAA,CAAI,SAAS,OAAO,CAAA;AAAA,IAC1D,KAAK,OAAA,IAAW,IAAA,GAAO,UAAU,IAAA,CAAK,GAAA,CAAI,SAAS,OAAO;AAAA,GAC5D;AAEA,EAAA,OAAO,QAAoB,MAAM;AAC/B,IAAA,MAAM,GAAA,GAAM,MAAY,YAAA,CAAa,IAAA,CAAK,QAAQ,IAAA,EAAM,IAAA,CAAK,QAAQ,KAAK,CAAA;AAC1E,IAAA,OAAO;AAAA,MACL,GAAA;AAAA,MACA,GAAA,EAAK,CAAC,IAAA,KAAe;AACnB,QAAA,MAAM,EAAE,GAAA,EAAK,GAAA,EAAI,GAAI,MAAA,CAAO,OAAA;AAC5B,QAAA,MAAM,UAAU,cAAA,CAAe,GAAA,EAAI,EAAG,IAAA,EAAM,KAAK,GAAG,CAAA;AACpD,QAAA,MAAM,EAAA,GAAK,cAAA,CAAe,OAAA,EAAS,IAAA,CAAK,QAAQ,KAAK,CAAA;AAGrD,QAAA,IAAA,CAAK,QAAQ,IAAA,GAAO,EAAA;AACpB,QAAA,IAAA,CAAK,OAAA,CAAQ,aAAa,EAAE,CAAA;AAAA,MAC9B,CAAA;AAAA,MACA,UAAU,MAAM;AACd,QAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,OAAA,EAAS,qBAAA,EAAsB;AACjD,QAAA,OAAO,CAAA,GAAI,EAAE,KAAA,EAAO,CAAA,CAAE,OAAO,MAAA,EAAQ,CAAA,CAAE,QAAO,GAAI,IAAA;AAAA,MACpD,CAAA;AAAA,MACA,SAAA,EAAW,OAAO,EAAE,GAAG,OAAO,OAAA,EAAQ;AAAA,KACxC;AAAA,EACF,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AACd;AAEA,IAAM,MAAA,GAAS,YAAA;AACf,IAAM,QAAA,uBAA0C,GAAA,EAAI;AACpD,IAAM,QAAA,GAAW,EAAE,WAAA,EAAa,KAAA,EAAO,QAAQ,KAAA,EAAM;AAmB9C,SAAS,YAAY,KAAA,EAAyB;AACnD,EAAA,MAAM,WAAWC,kBAAAA,EAAmB;AACpC,EAAA,IAAI,CAAC,UAAU,OAAO,IAAA;AACtB,EAAA,uBAAO,GAAA,CAAC,cAAA,EAAA,EAAgB,GAAG,KAAA,EAAO,QAAA,EAAoB,CAAA;AACxD;AAEA,SAAS,cAAA,CAAe;AAAA,EACtB,OAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAAqD;AACnD,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAEnB,EAAA,YAAA,CAAa,MAAA,EAAQ,MAAM,MAAM,CAAA;AACjC,EAAA,YAAA,CAAa,UAAA,EAAY,MAAM,MAAM,CAAA;AAErC,EAAA,MAAM,OAAA,GAAU,QAAkB,MAAM;AAGtC,IAAA,MAAM,OAAO,sBAAA,CAAuB;AAAA,MAClC,KAAA,EAAO,OAAA;AAAA,MACP,GAAA,EAAK,IAAA;AAAA,MACL,KAAK,MAAA,CAAO;AAAA,KACb,CAAA;AAGD,IAAA,MAAM,SAAA,GAAa,KAAK,cAAA,CAAgD,MAAA;AAAA,MACtE,CAAC,MAAM,CAAA,CAAE,IAAA,CAAK,SAAS,OAAA,IAAW,CAAA,CAAE,KAAK,IAAA,KAAS;AAAA,KACpD;AACA,IAAA,MAAM,GAAA,GAAc;AAAA,MAClB,EAAA,EAAI,MAAA;AAAA,MACJ,KAAA,EAAO,gBAAA;AAAA,MACP,cAAA,EAAgB,EAAE,IAAA,EAAM,OAAA,EAAQ;AAAA,MAChC,OAAA,EAAS;AAAA,QACP,MAAA,EAAQ,WAAA;AAAA,QACR,GAAA,EAAK,CAAC,KAAA,EAAO,MAAA,KAAW;AACtB,UAAA,MAAM,CAAA,GAAI,MAAA;AACV,UAAA,IAAI,CAAA,EAAG,MAAA,KAAW,MAAA,IAAa,CAAA,CAAE,WAAW,MAAA,EAAW;AACvD,UAAA,QAAA,CAAS,OAAA,GAAU,iBAAA,CAAkB,EAAE,CAAA,EAAG,CAAA,CAAE,MAAA,EAAQ,CAAA,EAAG,CAAA,CAAE,MAAA,EAAO,EAAG,QAAA,CAAS,OAAO,CAAC,CAAA;AAAA,QACtF;AAAA;AACF,KACF;AACA,IAAA,OAAO;AAAA;AAAA,MAEL,EAAE,GAAG,qBAAA,EAAuB,gBAAgB,EAAE,IAAA,EAAM,QAAO,EAAE;AAAA,MAC7D,EAAE,GAAG,IAAA,EAAM,cAAA,EAAgB,SAAA,EAAsC;AAAA,MACjE;AAAA,KACF;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,IAAA,GAAO,QAAQ,GAAA,CAAI,CAAC,MAAM,QAAA,CAAS,QAAA,CAAS,CAAC,CAAC,CAAA;AACpD,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,MAAW,GAAA,IAAO,MAAM,GAAA,EAAI;AAAA,IAC9B,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,QAAA,EAAU,OAAO,CAAC,CAAA;AAEtB,EAAA,MAAM,aAAA,GAAgB,OAAA;AAAA,IACpB,MAAM,CAAC,EAAA,EAAY,EAAA,KAAe;AAChC,MAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,OAAA,EAAS,qBAAA,EAAsB;AACjD,MAAA,MAAM,CAAA,GAAI,OAAO,GAAA,EAAI;AACrB,MAAA,OAAO;AAAA,QACL,CAAA,EAAA,CAAI,MAAM,CAAA,EAAG,IAAA,IAAQ,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA,CAAE,CAAA;AAAA,QACzC,CAAA,EAAA,CAAI,MAAM,CAAA,EAAG,GAAA,IAAO,MAAM,CAAA,CAAE,KAAA,CAAM,IAAI,CAAA,CAAE;AAAA,OAC1C;AAAA,IACF,CAAA;AAAA,IACA,CAAC,SAAS,MAAM;AAAA,GAClB;AAEA,EAAA,oBAAA,CAAqB;AAAA,IACnB,SAAA,EAAW,OAAA;AAAA,IACX,OAAA,EAAS,QAAA;AAAA,IACT,WAAA,EAAa,QAAA;AAAA,IACb,aAAA;AAAA,IACA,QAAA,EAAU;AAAA,GACX,CAAA;AAED,EAAA,iBAAA,CAAkB,OAAA,EAAS,aAAA,EAAe,KAAA,EAAO,aAAa,CAAA;AAC9D,EAAA,gBAAA,CAAiB,MAAM,CAAA;AAKvB,EAAA,MAAM,SAAA,GAAYF,WAAW,kBAAkB,CAAA;AAC/C,EAAAE,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAwB;AACvC,MAAA,OAAA,CAAQ,SAAS,aAAA,CAAc,IAAI,UAAA,CAAW,OAAA,EAAS,CAAC,CAAC,CAAA;AAAA,IAC3D,CAAA;AACA,IAAA,MAAM,QAAQ,MAAY;AACxB,MAAA,IAAI,QAAA,CAAS,QAAA,EAAS,EAAG,SAAA,CAAU,OAAA,GAAU,OAAA;AAAA,IAC/C,CAAA;AACA,IAAA,KAAA,EAAM;AACN,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,SAAA,CAAU,KAAK,CAAA;AACpC,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,EAAI;AACJ,MAAA,IAAI,SAAA,CAAU,OAAA,KAAY,OAAA,EAAS,SAAA,CAAU,OAAA,GAAU,IAAA;AAAA,IACzD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,SAAA,EAAW,OAAA,EAAS,QAAQ,CAAC,CAAA;AAEjC,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,iBAAA,CACd,OAAA,EACA,aAAA,EACA,KAAA,EACA,MAAA,EACM;AACN,EAAA,MAAM,QAAQ,iBAAA,EAAkB;AAChC,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,EAAA,MAAM,OAAA,GAAU,OAAO,aAAa,CAAA;AACpC,EAAA,OAAA,CAAQ,OAAA,GAAU,aAAA;AAClB,EAAAA,UAAU,MAAM;AACd,IAAA,MAAM,KAAK,OAAA,CAAQ,OAAA;AACnB,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,KAAA,EAAO;AACnB,IAAA,MAAM,MAAA,GAAS,CAAC,CAAA,KAA0B;AACxC,MAAA,MAAM,CAAA,GAAI,iBAAA,CAAkB,OAAA,CAAQ,OAAA,CAAQ,CAAA,CAAE,SAAS,CAAA,CAAE,OAAO,CAAA,EAAG,QAAA,CAAS,OAAO,CAAA;AACnF,MAAA,KAAA,CAAM,GAAA,CAAI,EAAE,MAAA,EAAQ,CAAA,CAAE,GAAG,MAAA,EAAQ,CAAA,CAAE,CAAA,EAAG,MAAA,EAAQ,CAAA;AAAA,IAChD,CAAA;AACA,IAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAA0B;AACzC,MAAA,IAAI,CAAA,CAAE,YAAY,CAAA,EAAG;AACrB,MAAA,IAAI,MAAM,GAAA,EAAI,EAAG,WAAW,MAAA,EAAQ,KAAA,CAAM,IAAI,IAAI,CAAA;AAAA,IACpD,CAAA;AACA,IAAA,EAAA,CAAG,gBAAA,CAAiB,eAAe,MAAM,CAAA;AACzC,IAAA,EAAA,CAAG,gBAAA,CAAiB,gBAAgB,OAAO,CAAA;AAC3C,IAAA,OAAO,MAAM;AACX,MAAA,EAAA,CAAG,mBAAA,CAAoB,eAAe,MAAM,CAAA;AAC5C,MAAA,EAAA,CAAG,mBAAA,CAAoB,gBAAgB,OAAO,CAAA;AAAA,IAChD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,KAAA,EAAO,MAAM,CAAC,CAAA;AAC7B;AAIO,SAAS,gBAAA,CACd,CAAA,EACA,MAAA,EACA,KAAA,EACc;AACd,EAAA,IAAI,CAAC,CAAA,IAAK,CAAA,CAAE,MAAA,KAAW,QAAQ,OAAO,IAAA;AACtC,EAAA,OAAO,iBAAA,CAAkB,EAAE,CAAA,EAAG,CAAA,CAAE,QAAQ,CAAA,EAAG,CAAA,CAAE,MAAA,EAAO,EAAG,KAAK,CAAA;AAC9D","file":"chunk-UNAZSLWE.js","sourcesContent":["import { createContext } from 'react';\n\n/** Where a trial's camera takes a wheel event from outside its own element. */\nexport type CameraWheelSlot = { current: ((e: WheelEvent) => void) | null };\n\n/**\n * The trial's camera, for input that lands outside it. An annotation target's\n * input box is portalled into the surface container, so a wheel over a mark\n * never bubbles through the stage or canvas stack it sits on; the box hands\n * the event here instead.\n */\nexport const CameraWheelContext = createContext<CameraWheelSlot | null>(null);\n","import { normalizeZoom } from '@weasel-js/core';\nimport type { ViewTransform } from '../instrument/types';\n\n/** The 2D view labkit has always shipped, and what a trial gets when it names no\n * other. Re-exported under its own name so a consumer can say which it means. */\nexport type ViewTransform2D = ViewTransform;\n\nexport const DEFAULT_VIEW: ViewTransform2D = { zoom: 1, pan: { x: 0, y: 0 } };\n\n/** A trial's view is opaque to labkit, so anything that needs the 2D shape — the\n * zoom chrome, `CanvasStack` — asks for it and handles not getting it. */\nexport function as2DView(view: unknown): ViewTransform2D | null {\n if (typeof view !== 'object' || view === null) return null;\n const v = view as Partial<ViewTransform2D>;\n if (typeof v.zoom !== 'number') return null;\n if (typeof v.pan !== 'object' || v.pan === null) return null;\n if (typeof v.pan.x !== 'number' || typeof v.pan.y !== 'number') return null;\n return normalize2DView({ zoom: v.zoom, pan: { x: v.pan.x, y: v.pan.y } });\n}\n\n/** `view` inside the invariant every view holds: a zoom that is not a finite\n * number of at least `ZOOM_FLOOR` becomes the floor, and a non-finite pan\n * becomes 0. Returns `view` itself when it already holds. */\nexport function normalize2DView(view: ViewTransform2D): ViewTransform2D {\n const zoom = normalizeZoom(view.zoom);\n const x = Number.isFinite(view.pan.x) ? view.pan.x : 0;\n const y = Number.isFinite(view.pan.y) ? view.pan.y : 0;\n if (zoom === view.zoom && x === view.pan.x && y === view.pan.y) return view;\n return { zoom, pan: { x, y } };\n}\n\n/** `view` at a new zoom, through the same rule. */\nexport function withZoom(view: ViewTransform2D, zoom: number): ViewTransform2D {\n return normalize2DView({ zoom, pan: view.pan });\n}\n","import { useActionsRegistry } from '@weasel-js/core';\nimport { createContext, useContext, useEffect } from 'react';\nimport type { CameraView } from './CameraInput';\n\n/**\n * Cameras by key, for chrome that acts on a camera it does not contain — the\n * lab's zoom controls, which drive whichever trial has the focus.\n */\nexport interface CameraRegistry {\n /** Publish `camera` under `key` and return its release. Registrants for one\n * key stack, newest live. */\n register(key: string, camera: CameraView): () => void;\n get(key: string): CameraView | null;\n /** Fires after any register or release. Shaped for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n}\n\nexport function createCameraRegistry(): CameraRegistry {\n const stacks = new Map<string, CameraView[]>();\n const listeners = new Set<() => void>();\n const notify = (): void => {\n for (const l of listeners) l();\n };\n return {\n register(key, camera) {\n const stack = stacks.get(key) ?? [];\n stack.push(camera);\n stacks.set(key, stack);\n notify();\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const cur = stacks.get(key);\n const i = cur?.lastIndexOf(camera) ?? -1;\n if (!cur || i === -1) return;\n cur.splice(i, 1);\n if (cur.length === 0) stacks.delete(key);\n notify();\n };\n },\n get: (key) => stacks.get(key)?.at(-1) ?? null,\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n\n/** The registry a lab keeps its trials' cameras in. */\nexport const CameraRegistryContext = createContext<CameraRegistry | null>(null);\n\n/** Where a camera publishes itself. The host binds the key — a trial provides\n * one that registers under its own id — so the camera needs no name. */\nexport const CameraPublishContext = createContext<((camera: CameraView) => () => void) | null>(\n null,\n);\n\n/** Publish `camera` to the host in scope for as long as the caller is mounted,\n * and again each time its input scope becomes the active one — a registry\n * key stacks newest-live, so the camera last used is the one chrome reaches.\n * Call it inside the camera's scope. */\nexport function usePublishCamera(camera: CameraView): void {\n const publish = useContext(CameraPublishContext);\n const actions = useActionsRegistry();\n useEffect(() => {\n if (!publish) return;\n let release = publish(camera);\n if (!actions) return release;\n let was = actions.isActive();\n const off = actions.subscribe(() => {\n const now = actions.isActive();\n if (now && !was) {\n release();\n release = publish(camera);\n }\n was = now;\n });\n return () => {\n off();\n release();\n };\n }, [publish, camera, actions]);\n}\n","/**\n * labkit's camera as a weasel `View`, so core's viewport actions drive it.\n *\n * labkit places a world point on screen at\n * `originPx + pan + zoom * (x, yDir * y)`. A weasel `View` places one at\n * `(p - (x, y)) * scale`. Over *frame-local* coordinates — the world with `y`\n * multiplied by `yDir` — the two are the same affine map, which is all a pan\n * or a zoom about a screen point needs.\n */\nimport type { View } from '@weasel-js/core';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { DEFAULT_FRAME, type WorldFrame } from './worldSpec';\n\n/** The weasel `View` equal to `view` under `frame`. */\nexport function toCameraView(view: ViewTransform, frame: WorldFrame = DEFAULT_FRAME): View {\n const v = normalize2DView(view);\n return {\n x: -(frame.originPx.x + v.pan.x) / v.zoom,\n y: -(frame.originPx.y + v.pan.y) / v.zoom,\n scale: { x: v.zoom, y: v.zoom },\n };\n}\n\n/** The labkit camera equal to weasel `view` under `frame`. */\nexport function fromCameraView(view: View, frame: WorldFrame = DEFAULT_FRAME): ViewTransform {\n const zoom = view.scale.x;\n return {\n zoom,\n pan: { x: -view.x * zoom - frame.originPx.x, y: -view.y * zoom - frame.originPx.y },\n };\n}\n\n/** A frame-local point in the instrument's world, and back — the map is its\n * own inverse. */\nexport function frameLocalToWorld(p: Point, frame: WorldFrame = DEFAULT_FRAME): Point {\n return { x: p.x, y: p.y * frame.yDir };\n}\n\n/**\n * `next` with its zoom held to [`min`, `max`], about the screen point the step\n * from `prev` was anchored on, so a zoom that hits a bound stays anchored where\n * the pointer is. A pan (equal scales) passes through.\n */\nexport function clampZoomAbout(prev: View, next: View, min: number, max: number): View {\n const s0 = prev.scale.x;\n const s1 = next.scale.x;\n const clamped = Math.min(max, Math.max(min, s1));\n if (clamped === s1) return next;\n if (s0 === s1) return { ...next, scale: { x: clamped, y: clamped } };\n // The screen point both views agree on: p / s0 + x0 = p / s1 + x1.\n const inv = 1 / s0 - 1 / s1;\n const px = (next.x - prev.x) / inv;\n const py = (next.y - prev.y) / inv;\n // The same point under the clamped scale.\n return {\n x: prev.x + px / s0 - px / clamped,\n y: prev.y + py / s0 - py / clamped,\n scale: { x: clamped, y: clamped },\n };\n}\n","/**\n * A labkit camera driven by weasel's dispatcher: drag pans, the wheel zooms\n * about the pointer, a tap reports the world point, and the pointer is\n * published into the store in scope. What `usePanZoom` used to hand-roll.\n */\nimport {\n type Action,\n type ActionsRegistry,\n InputScope,\n makeViewportZoomAction,\n PointerContextProvider,\n type PointerWorldPos,\n type Tool,\n useActionsRegistry,\n useDepSource,\n useGestureDispatcher,\n usePointerContext,\n type View,\n type ViewApi,\n viewportDragPanAction,\n type Yoke,\n} from '@weasel-js/core';\nimport {\n createContext,\n type ReactNode,\n type RefObject,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type { Point, ViewTransform } from '../instrument/types';\nimport { normalize2DView } from '../state/view';\nimport { CameraWheelContext } from './CameraWheelContext';\nimport { usePublishCamera } from './cameraRegistry';\nimport { clampZoomAbout, frameLocalToWorld, fromCameraView, toCameraView } from './cameraView';\nimport type { ViewportSize, WorldFrame } from './worldSpec';\n\n/** The view id the stage publishes its pointer under. */\nexport const STAGE_VIEW_ID = 'stage';\n\n/**\n * A camera, as the things that sit beside it read it: an overview, a loupe, a\n * linked cursor. Points are *frame-local* — the world with `y` multiplied by\n * `frame.yDir` — which is the space `view` works in.\n */\nexport interface CameraContextValue {\n /** The camera as a weasel `ViewApi`, clamped to its zoom range. */\n view: ViewApi;\n frame: WorldFrame;\n /** The element the camera's dispatcher listens on. */\n element: () => HTMLElement | null;\n /** The content's own rect, frame-local, when it has one — a `<Stage>`'s. */\n content?: { x: number; y: number; width: number; height: number };\n}\n\n/** The camera around the caller, or `null` outside one. */\nexport const CameraContext = createContext<CameraContextValue | null>(null);\n\n/**\n * The input scope a camera routes through. Inside another camera — a loupe or\n * an overlay laid over a canvas stack — it joins that camera's scope, so its\n * actions reach the dispatcher already listening there. Anywhere else it\n * mounts a scope of its own, which keeps its own tool unless it joins `yoke`:\n * a camera beside another never takes that one's gestures. The pointer store is the exception — one\n * already in scope is kept, since sharing it is the point.\n */\nexport function CameraScope({ yoke, children }: { yoke?: Yoke; children: ReactNode }) {\n const around = useContext(CameraContext);\n const pointer = usePointerContext();\n if (around) return <>{children}</>;\n const scoped = <InputScope yoke={yoke}>{children}</InputScope>;\n return pointer ? scoped : <PointerContextProvider>{scoped}</PointerContextProvider>;\n}\n\n/** Options for {@link useCameraView}. */\nexport interface CameraViewOptions {\n view: ViewTransform;\n onViewChange: (v: ViewTransform) => void;\n frame: WorldFrame;\n hostRef: RefObject<HTMLElement | null>;\n minZoom?: number;\n maxZoom?: number;\n}\n\n/** A camera's zoom limits, after widening to admit its opening zoom. */\nexport interface ZoomRange {\n min: number;\n max: number;\n}\n\n/** A labkit camera: a weasel `ViewApi` that also says how far it zooms. */\nexport interface CameraView extends ViewApi {\n zoomRange(): ZoomRange;\n}\n\nfunction isPositiveFinite(n: number): boolean {\n return Number.isFinite(n) && n > 0;\n}\n\n/**\n * A labkit camera as a stable `ViewApi`. Its zoom range is widened to keep the\n * opening zoom reachable — captured once, so a zoom-out cannot shrink the\n * range and strand the opening view behind it.\n */\nexport function useCameraView({\n view,\n onViewChange,\n frame,\n hostRef,\n minZoom = 0.1,\n maxZoom = 32,\n}: CameraViewOptions): CameraView {\n const live = useRef({ view: normalize2DView(view), onViewChange, frame });\n live.current = { view: normalize2DView(view), onViewChange, frame };\n const initialZoom = useRef(isPositiveFinite(view.zoom) ? view.zoom : null);\n const bounds = useRef({ min: minZoom, max: maxZoom });\n const opening = initialZoom.current;\n bounds.current = {\n min: opening == null ? minZoom : Math.min(minZoom, opening),\n max: opening == null ? maxZoom : Math.max(maxZoom, opening),\n };\n\n return useMemo<CameraView>(() => {\n const get = (): View => toCameraView(live.current.view, live.current.frame);\n return {\n get,\n set: (next: View) => {\n const { min, max } = bounds.current;\n const clamped = clampZoomAbout(get(), next, min, max);\n const vt = fromCameraView(clamped, live.current.frame);\n // Written ahead of the render, so a second event inside one commit\n // steps from this one.\n live.current.view = vt;\n live.current.onViewChange(vt);\n },\n hostSize: () => {\n const r = hostRef.current?.getBoundingClientRect();\n return r ? { width: r.width, height: r.height } : null;\n },\n zoomRange: () => ({ ...bounds.current }),\n };\n }, [hostRef]);\n}\n\nconst TAP_ID = 'camera.tap';\nconst NO_TOOLS: ReadonlyMap<string, Tool> = new Map();\nconst CHANNELS = { contextMenu: false, ingest: false } as const;\n\n/** Props for `<CameraInput>`. */\nexport interface CameraInputProps {\n hostRef: RefObject<HTMLElement | null>;\n /** Published to the host's camera registry while its scope is the active\n * one, so chrome acting on \"the camera\" acts on the one last used. */\n camera: CameraView;\n frame: WorldFrame;\n /** A primary-button press released without crossing the drag threshold, at\n * the world point it landed on. */\n onTap?: (world: Point) => void;\n}\n\n/**\n * Mounts the dispatcher on `hostRef` and routes the camera's gestures through\n * it. Render it inside a `<CameraScope>`; with no actions registry in scope it\n * renders nothing.\n */\nexport function CameraInput(props: CameraInputProps) {\n const registry = useActionsRegistry();\n if (!registry) return null;\n return <CameraDispatch {...props} registry={registry} />;\n}\n\nfunction CameraDispatch({\n hostRef,\n camera,\n frame,\n onTap,\n registry,\n}: CameraInputProps & { registry: ActionsRegistry }) {\n const frameRef = useRef(frame);\n frameRef.current = frame;\n const onTapRef = useRef(onTap);\n onTapRef.current = onTap;\n\n useDepSource('view', () => camera);\n useDepSource('rootView', () => camera);\n\n const actions = useMemo<Action[]>(() => {\n // Unclamped here: `camera.set` clamps, to a range widened around the\n // opening zoom, and anchors the clamp where the wheel was.\n const zoom = makeViewportZoomAction({\n wheel: 'plain',\n min: 1e-9,\n max: Number.POSITIVE_INFINITY,\n });\n // The wheel and the trackpad's two pinch forms only: the zoom keys listen\n // on the window, and every trial on a page would take them at once.\n const wheelOnly = (zoom.defaultBinding as { spec: { kind: string } }[]).filter(\n (b) => b.spec.kind === 'wheel' || b.spec.kind === 'pinch',\n );\n const tap: Action = {\n id: TAP_ID,\n label: 'Tap the canvas',\n defaultBinding: { kind: 'click' },\n invoker: {\n timing: 'immediate',\n run: (_deps, params) => {\n const p = params as { worldX?: number; worldY?: number } | undefined;\n if (p?.worldX === undefined || p.worldY === undefined) return;\n onTapRef.current?.(frameLocalToWorld({ x: p.worldX, y: p.worldY }, frameRef.current));\n },\n },\n };\n return [\n // A trial pans on a plain drag; the kit action binds none of its own.\n { ...viewportDragPanAction, defaultBinding: { kind: 'drag' } },\n { ...zoom, defaultBinding: wheelOnly as Action['defaultBinding'] },\n tap,\n ];\n }, []);\n\n useEffect(() => {\n const offs = actions.map((a) => registry.register(a));\n return () => {\n for (const off of offs) off();\n };\n }, [registry, actions]);\n\n const clientToWorld = useMemo(\n () => (cx: number, cy: number) => {\n const r = hostRef.current?.getBoundingClientRect();\n const v = camera.get();\n return {\n x: (cx - (r?.left ?? 0)) / v.scale.x + v.x,\n y: (cy - (r?.top ?? 0)) / v.scale.y + v.y,\n };\n },\n [hostRef, camera],\n );\n\n useGestureDispatcher({\n canvasRef: hostRef,\n actions: registry,\n entriesById: NO_TOOLS,\n clientToWorld,\n channels: CHANNELS,\n });\n\n usePublishPointer(hostRef, clientToWorld, frame, STAGE_VIEW_ID);\n usePublishCamera(camera);\n\n // Input that lands outside the camera's element — an annotation target's\n // box, portalled into the surface — reaches the active camera's dispatcher\n // through here.\n const wheelSlot = useContext(CameraWheelContext);\n useEffect(() => {\n if (!wheelSlot) return;\n const forward = (e: WheelEvent): void => {\n hostRef.current?.dispatchEvent(new WheelEvent('wheel', e));\n };\n const claim = (): void => {\n if (registry.isActive()) wheelSlot.current = forward;\n };\n claim();\n const off = registry.subscribe(claim);\n return () => {\n off();\n if (wheelSlot.current === forward) wheelSlot.current = null;\n };\n }, [wheelSlot, hostRef, registry]);\n\n return null;\n}\n\n/**\n * Publish the pointer over `hostRef` into the store in scope, in the\n * instrument's world, as `viewId`; clear it when the pointer leaves with no\n * button held.\n */\nexport function usePublishPointer(\n hostRef: RefObject<HTMLElement | null>,\n clientToLocal: (cx: number, cy: number) => Point,\n frame: WorldFrame,\n viewId: string,\n): void {\n const store = usePointerContext();\n const frameRef = useRef(frame);\n frameRef.current = frame;\n const toLocal = useRef(clientToLocal);\n toLocal.current = clientToLocal;\n useEffect(() => {\n const el = hostRef.current;\n if (!el || !store) return;\n const onMove = (e: PointerEvent): void => {\n const w = frameLocalToWorld(toLocal.current(e.clientX, e.clientY), frameRef.current);\n store.set({ worldX: w.x, worldY: w.y, viewId });\n };\n const onLeave = (e: PointerEvent): void => {\n if (e.buttons !== 0) return;\n if (store.get()?.viewId === viewId) store.set(null);\n };\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerleave', onLeave);\n return () => {\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerleave', onLeave);\n };\n }, [hostRef, store, viewId]);\n}\n\n/** The pointer as a frame-local point, or `null` when there is none or it is\n * over `viewId` itself. */\nexport function pointerElsewhere(\n p: PointerWorldPos,\n viewId: string,\n frame: WorldFrame,\n): Point | null {\n if (!p || p.viewId === viewId) return null;\n return frameLocalToWorld({ x: p.worldX, y: p.worldY }, frame);\n}\n\nexport type { ViewportSize };\n"]}
@@ -1,15 +1,11 @@
1
+ import { isPlainObject } from '@weasel-js/core';
2
+
1
3
  // src/config/auto.ts
2
4
  var auto = /* @__PURE__ */ Symbol("weasel.auto");
3
5
  function isAuto(value) {
4
6
  return value === auto;
5
7
  }
6
-
7
- // src/config/path.ts
8
- function isRecord(value) {
9
- if (typeof value !== "object" || value === null) return false;
10
- const proto = Object.getPrototypeOf(value);
11
- return proto === Object.prototype || proto === null;
12
- }
8
+ var isRecord = isPlainObject;
13
9
  function valueAtPath(config, path) {
14
10
  let cur = config;
15
11
  for (const segment of path.split(".")) {
@@ -144,5 +140,5 @@ function applyConfigWrite(config, autoPaths, path, value) {
144
140
  }
145
141
 
146
142
  export { applyConfigWrite, auto, autoPathsOf, fillConfigDefaults, hasConfigPath, isAuto, isRecord, resolveAutoConfig, schemaNodeAtPath, valueAtPath, withValueAtPath };
147
- //# sourceMappingURL=chunk-TJ77A4A3.js.map
148
- //# sourceMappingURL=chunk-TJ77A4A3.js.map
143
+ //# sourceMappingURL=chunk-Y23G2VZL.js.map
144
+ //# sourceMappingURL=chunk-Y23G2VZL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/auto.ts","../src/config/path.ts","../src/config/autoConfig.ts"],"names":[],"mappings":"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","file":"chunk-Y23G2VZL.js","sourcesContent":["/**\n * Written at a config path to mean \"do not pin this — let the instrument\n * decide\". Accepted by `setConfig`, by a trial's `configSeed`, and by\n * `.initial()` in a schema. It is normalized into the trial's set of unpinned\n * paths on the way into the store and is never itself stored, so a serialized\n * trial contains no sentinel and the last pinned value survives.\n */\nexport const auto: unique symbol = Symbol('weasel.auto');\n\n/** The type of the `auto` sentinel, for widening a value parameter. */\nexport type Auto = typeof auto;\n\nexport function isAuto(value: unknown): value is Auto {\n return value === auto;\n}\n","import { isPlainObject } from '@weasel-js/core';\nimport type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\n\n/**\n * Reading and writing a config tree by dotted path. A schema's leaves address\n * their values this way, so a leaf nested under `f.group` and a flat one are\n * reached by exactly the same call.\n */\n\n/** A plain object a config tree can be walked into. An array, a `Date`, a\n * `Map` or a class instance is a leaf value: a walk that descended into one\n * would rebuild it as a bare `{}`. */\nexport const isRecord = isPlainObject;\n\n/** The value at a dotted path. `undefined` when a segment is missing or the\n * walk hits something that is not a record. */\nexport function valueAtPath(config: unknown, path: string): unknown {\n let cur = config;\n for (const segment of path.split('.')) {\n if (!isRecord(cur)) return undefined;\n cur = cur[segment];\n }\n return cur;\n}\n\n/** Whether a dotted path is actually present, which a `undefined` value is\n * not enough to tell you. */\nexport function hasConfigPath(config: unknown, path: string): boolean {\n let cur = config;\n for (const segment of path.split('.')) {\n if (!isRecord(cur) || !(segment in cur)) return false;\n cur = cur[segment];\n }\n return true;\n}\n\nfunction writeIn(node: unknown, segments: readonly string[], value: unknown): unknown {\n const [head, ...rest] = segments;\n if (head === undefined) return value;\n const base = isRecord(node) ? node : {};\n return { ...base, [head]: rest.length === 0 ? value : writeIn(base[head], rest, value) };\n}\n\n/** A copy of `config` with `value` written at a dotted path. Every record on\n * the way down is copied and the input is left alone; a missing — or\n * non-record — intermediate is replaced with the branch the path implies. */\nexport function withValueAtPath<T>(config: T, path: string, value: unknown): T {\n return writeIn(config, path.split('.'), value) as T;\n}\n\n/**\n * `stored` with every gap filled from `defaults`, down the whole tree.\n *\n * This is how a config written before its schema grew a branch still loads:\n * the branch arrives at its defaults instead of `undefined`, and a key the\n * defaults no longer mention is kept rather than dropped, so nothing is lost\n * to a schema change the author has not finished making.\n */\nexport function fillConfigDefaults<T>(stored: unknown, defaults: T): T {\n if (!isRecord(defaults)) return (stored === undefined ? defaults : stored) as T;\n const base = isRecord(stored) ? stored : {};\n const out: Record<string, unknown> = { ...base };\n for (const [key, value] of Object.entries(defaults)) {\n out[key] = fillConfigDefaults(base[key], value);\n }\n return out as T;\n}\n\n/** A node in a resolved schema tree, by dotted path. Structural rather than\n * `isPrefLeaf` so this stays free of a runtime import. */\nexport function schemaNodeAtPath(group: PrefGroup, path: string): PrefLeaf | PrefGroup | undefined {\n let node: PrefLeaf | PrefGroup | undefined = group;\n for (const segment of path.split('.')) {\n if (node === undefined || !('children' in node)) return undefined;\n node = node.children[segment];\n }\n return node;\n}\n","import type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\nimport { isAuto } from './auto';\nimport { isRecord, withValueAtPath } from './path';\nimport type { ResolvedConfig } from './types';\n\ntype Resolver = (config: Record<string, unknown>) => unknown;\n\n/** Reads a labkit-only extra off a resolved leaf. `PrefLeaf` has no field for\n * these; they ride as extra keys and survive the resolve walk. */\nfunction extra<T>(leaf: PrefLeaf, key: string): T | undefined {\n return (leaf as unknown as Record<string, T | undefined>)[key];\n}\n\n/** Every leaf in a resolved schema, in schema order, with its dotted path. */\nfunction* leaves(group: PrefGroup, at = ''): Generator<[string, PrefLeaf]> {\n for (const [key, child] of Object.entries(group.children)) {\n const path = at === '' ? key : `${at}.${key}`;\n if ('kind' in child) yield [path, child];\n else yield* leaves(child, path);\n }\n}\n\n/** The dotted paths a schema declares as starting auto — every leaf that said\n * `.initial(auto)`. This is what seeds a new trial's unpinned set. */\nexport function autoPathsOf(resolved: ResolvedConfig): string[] {\n const out: string[] = [];\n for (const [path, leaf] of leaves(resolved.group)) {\n if (extra<boolean>(leaf, 'unpinned')) out.push(path);\n }\n return out;\n}\n\n/**\n * The config an instrument reads: the stored one, with every unpinned path\n * either computed by its resolver or removed.\n *\n * Resolution is demand-driven — a resolver reading another unpinned path\n * forces that one first, whatever order the schema declared them in — so a\n * cycle is a real cycle and not an ordering accident.\n */\nexport function resolveAutoConfig<TC>(\n resolved: ResolvedConfig,\n config: TC,\n autoPaths: ReadonlySet<string>,\n): TC {\n if (autoPaths.size === 0) return config;\n\n const resolvers = new Map<string, Resolver | undefined>();\n for (const [path, leaf] of leaves(resolved.group)) {\n if (autoPaths.has(path)) resolvers.set(path, extra<Resolver>(leaf, 'autoResolve'));\n }\n if (resolvers.size === 0) return config;\n\n // Drop first, so a resolver reading a still-unresolved auto path sees\n // `undefined` rather than a stale pinned value it would silently believe.\n let out = config as unknown as Record<string, unknown>;\n for (const path of resolvers.keys()) out = dropAtPath(out, path);\n\n const inFlight = new Set<string>();\n const done = new Set<string>();\n\n const need = (path: string): void => {\n if (done.has(path)) return;\n if (inFlight.has(path)) {\n throw new Error(`[labkit] auto resolver cycle at \"${path}\"`);\n }\n const resolve = resolvers.get(path);\n if (!resolve) {\n done.add(path);\n return;\n }\n inFlight.add(path);\n try {\n // Read `out` only after the resolver has run: it forces its own\n // dependencies, and each of those replaced `out`.\n const value = resolve(demand(() => out, resolvers, need));\n out = withValueAtPath(out, path, value);\n } finally {\n inFlight.delete(path);\n }\n done.add(path);\n };\n\n for (const path of resolvers.keys()) need(path);\n return out as unknown as TC;\n}\n\n/**\n * The config a resolver reads. A top-level key that is itself unpinned is\n * forced before it is handed back, which is what makes declaration order\n * irrelevant and turns a genuine loop into a named error.\n *\n * Only top-level keys are trapped: a resolver reaching `c.grid.size` gets the\n * already-dropped branch, and a nested auto path it depends on resolves by\n * schema order alone.\n */\nfunction demand(\n read: () => Record<string, unknown>,\n resolvers: ReadonlyMap<string, Resolver | undefined>,\n need: (path: string) => void,\n): Record<string, unknown> {\n return new Proxy(read(), {\n get(_target, key) {\n if (typeof key === 'string' && resolvers.has(key)) need(key);\n return Reflect.get(read(), key);\n },\n has(_target, key) {\n return Reflect.has(read(), key);\n },\n ownKeys() {\n return Reflect.ownKeys(read());\n },\n getOwnPropertyDescriptor(_target, key) {\n return Reflect.getOwnPropertyDescriptor(read(), key);\n },\n });\n}\n\n/** A copy of `config` with the dotted path removed, copying every record on\n * the way down. A path that is not there comes back unchanged. */\nfunction dropAtPath(config: Record<string, unknown>, path: string): Record<string, unknown> {\n const [head, ...rest] = path.split('.');\n if (head === undefined || !(head in config)) return config;\n if (rest.length === 0) {\n const { [head]: _dropped, ...kept } = config;\n return kept;\n }\n const child = config[head];\n if (!isRecord(child)) return config;\n return { ...config, [head]: dropAtPath(child, rest.join('.')) };\n}\n\n/**\n * What writing `value` at `path` makes of a trial's raw config and its set of\n * unpinned paths. `auto` pins nothing and joins the set; any other value is\n * written and leaves it. Both the store and the chrome go through this, so\n * they cannot disagree about what a write meant.\n */\nexport function applyConfigWrite<TC>(\n config: TC,\n autoPaths: readonly string[],\n path: string,\n value: unknown,\n): { config: TC; autoPaths: readonly string[] } {\n if (isAuto(value)) {\n if (autoPaths.includes(path)) return { config, autoPaths };\n return { config, autoPaths: [...autoPaths, path] };\n }\n return {\n config: withValueAtPath(config, path, value),\n autoPaths: autoPaths.includes(path) ? autoPaths.filter((p) => p !== path) : autoPaths,\n };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { newId, emptyUndoStack, deserializeTrials, openRecords, labPrefix, documentOfRecords, recordsOfDocument, trialRecord, trialValuesPrefix, saveRecord, LAYOUT_RECORD, UNDOCK_RECORD, META_RECORD, parseRecordName, compareTrialOrder, serializeTrials, labStorageKey } from './chunk-RWNDDKOH.js';
2
- import { resolveConfigSchema, useResolvedConfig } from './chunk-O6FFFOHS.js';
3
- import { applyConfigWrite, fillConfigDefaults } from './chunk-TJ77A4A3.js';
2
+ import { resolveConfigSchema, useResolvedConfig } from './chunk-FZ7YFQN7.js';
3
+ import { applyConfigWrite, fillConfigDefaults } from './chunk-Y23G2VZL.js';
4
4
  import { LabStoreContext, TrialIdContext } from './chunk-2YILQ7Y5.js';
5
5
  import { createStore } from 'zustand/vanilla';
6
6
  import { useContext } from 'react';
@@ -733,5 +733,5 @@ function useTrialState() {
733
733
  }
734
734
 
735
735
  export { CURRENT_DOCUMENT_VERSION, createLabStore, dockPanel, labDocumentKey, openLabStore, panelKey, quarantineKey, undockPanel, unruledConfigSchema, useTrialState };
736
- //# sourceMappingURL=chunk-HKV7LRHY.js.map
737
- //# sourceMappingURL=chunk-HKV7LRHY.js.map
736
+ //# sourceMappingURL=chunk-YT75VYRD.js.map
737
+ //# sourceMappingURL=chunk-YT75VYRD.js.map