@weasel-js/labkit 1.4.4 → 1.5.1

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 (278) hide show
  1. package/README.md +54 -6
  2. package/dist/_dts/{CanvasStackContext-kTEZvEgE.d.ts → CanvasStackContext-CJNMS6mz.d.ts} +1 -1
  3. package/dist/_dts/{PrefsForm.d-DDHFANkc.d.ts → PrefsForm.d-DPy9I8It.d.ts} +4 -0
  4. package/dist/_dts/Select.d-Gwr8fLpK.d.ts +453 -0
  5. package/dist/_dts/{frac-z7ker2Vx.d.ts → frac-B4okC2lX.d.ts} +291 -31
  6. package/dist/_dts/{index-Blv9uQzu.d.ts → index-BNdz-tNd.d.ts} +105 -17
  7. package/dist/_dts/index-CSJoj4LC.d.ts +248 -0
  8. package/dist/_dts/{types-B9_zrHmb.d.ts → types-DzoNY1pO.d.ts} +91 -4
  9. package/dist/_dts/usePanZoom-Pzf9f2jh.d.ts +160 -0
  10. package/dist/_dts/useTrialState-uLlmaccn.d.ts +212 -0
  11. package/dist/canvas/index.d.ts +18 -129
  12. package/dist/canvas/index.js +4 -2
  13. package/dist/chrome/index.d.ts +5 -93
  14. package/dist/chrome/index.js +10 -6
  15. package/dist/chunk-7PFH3CNM.js +150 -0
  16. package/dist/chunk-7PFH3CNM.js.map +1 -0
  17. package/dist/{chunk-I6JCVE24.js → chunk-CEIUBPPW.js} +143 -17
  18. package/dist/chunk-CEIUBPPW.js.map +1 -0
  19. package/dist/chunk-EH7UEQV7.js +590 -0
  20. package/dist/chunk-EH7UEQV7.js.map +1 -0
  21. package/dist/{chunk-MOM3GOVY.js → chunk-EHGVROVV.js} +125 -27
  22. package/dist/chunk-EHGVROVV.js.map +1 -0
  23. package/dist/{chunk-TJ7QY3OC.js → chunk-ERFMC6WU.js} +160 -78
  24. package/dist/chunk-ERFMC6WU.js.map +1 -0
  25. package/dist/{chunk-CTRKTLYZ.js → chunk-H6ZAOWNE.js} +11 -11
  26. package/dist/chunk-H6ZAOWNE.js.map +1 -0
  27. package/dist/{chunk-64ZCN3DA.js → chunk-IHUVQ3TX.js} +250 -160
  28. package/dist/chunk-IHUVQ3TX.js.map +1 -0
  29. package/dist/{chunk-FQMJUVHJ.js → chunk-IJJUK4FU.js} +53 -46
  30. package/dist/chunk-IJJUK4FU.js.map +1 -0
  31. package/dist/chunk-IXTQI7JX.js +737 -0
  32. package/dist/chunk-IXTQI7JX.js.map +1 -0
  33. package/dist/{chunk-BKFVHKJH.js → chunk-MDVTK5U3.js} +4 -4
  34. package/dist/{chunk-BKFVHKJH.js.map → chunk-MDVTK5U3.js.map} +1 -1
  35. package/dist/chunk-PHK4W562.js +72 -0
  36. package/dist/chunk-PHK4W562.js.map +1 -0
  37. package/dist/chunk-PJ7WEQBJ.js +18 -0
  38. package/dist/chunk-PJ7WEQBJ.js.map +1 -0
  39. package/dist/chunk-RWNDDKOH.js +682 -0
  40. package/dist/chunk-RWNDDKOH.js.map +1 -0
  41. package/dist/chunk-T3EC2DXD.js +12628 -0
  42. package/dist/chunk-T3EC2DXD.js.map +1 -0
  43. package/dist/{chunk-SMHP6XZ4.js → chunk-UN4U4P63.js} +10 -8
  44. package/dist/chunk-UN4U4P63.js.map +1 -0
  45. package/dist/chunk-WIG6XHJ7.js +35 -0
  46. package/dist/chunk-WIG6XHJ7.js.map +1 -0
  47. package/dist/chunk-Z76KEZAX.js +15 -0
  48. package/dist/chunk-Z76KEZAX.js.map +1 -0
  49. package/dist/chunk-ZDHY47EV.js +363 -0
  50. package/dist/chunk-ZDHY47EV.js.map +1 -0
  51. package/dist/config/index.d.ts +276 -0
  52. package/dist/config/index.js +8 -0
  53. package/dist/config/index.js.map +1 -0
  54. package/dist/controls/index.d.ts +3 -4
  55. package/dist/controls/index.js +4 -3
  56. package/dist/dragdrop/index.d.ts +3 -5
  57. package/dist/index.d.ts +266 -413
  58. package/dist/index.js +1775 -2251
  59. package/dist/index.js.map +1 -1
  60. package/dist/layers/index.d.ts +4 -6
  61. package/dist/layers/index.js +2 -2
  62. package/dist/loupe/index.d.ts +69 -20
  63. package/dist/loupe/index.js +2 -2
  64. package/dist/passthrough/weasel-ui.d.ts +175 -309
  65. package/dist/passthrough/weasel-ui.js +1 -1
  66. package/dist/primitives/index.d.ts +55 -6
  67. package/dist/primitives/index.js +6 -4
  68. package/dist/state/index.d.ts +13 -8
  69. package/dist/state/index.js +18 -13
  70. package/dist/state/index.js.map +1 -1
  71. package/dist/styles.css +223 -76
  72. package/dist/surface/index.d.ts +44 -7
  73. package/dist/surface/index.js +2 -1
  74. package/dist/ui/layers/index.js +1 -1
  75. package/dist/undo/index.d.ts +3 -5
  76. package/package.json +15 -8
  77. package/src/annotations/AnnotationOverlay.tsx +56 -5
  78. package/src/annotations/Annotations.less +4 -0
  79. package/src/annotations/Annotations.overlay.test.tsx +105 -6
  80. package/src/annotations/drawOne.test.ts +1 -1
  81. package/src/annotations/drawOne.ts +2 -2
  82. package/src/annotations/paint.test.ts +2 -2
  83. package/src/annotations/paint.ts +1 -1
  84. package/src/annotations/preload.ts +6 -0
  85. package/src/annotations/store.test.ts +18 -0
  86. package/src/annotations/store.ts +5 -4
  87. package/src/annotations/svgNodes.test.ts +2 -2
  88. package/src/annotations/svgNodes.ts +1 -0
  89. package/src/annotations/toolMap.test.ts +9 -5
  90. package/src/annotations/toolMap.ts +6 -3
  91. package/src/annotations/types.ts +6 -3
  92. package/src/canvas/CameraWheelContext.ts +12 -0
  93. package/src/canvas/CanvasStack.stories.tsx +1 -1
  94. package/src/canvas/CanvasStack.test.tsx +25 -0
  95. package/src/canvas/CanvasStack.tsx +31 -4
  96. package/src/canvas/Stage.less +18 -0
  97. package/src/canvas/Stage.test.tsx +186 -0
  98. package/src/canvas/Stage.tsx +134 -0
  99. package/src/canvas/camera.test.ts +17 -2
  100. package/src/canvas/camera.ts +9 -9
  101. package/src/canvas/index.ts +4 -0
  102. package/src/canvas/usePanZoom.test.ts +28 -0
  103. package/src/canvas/usePanZoom.ts +21 -9
  104. package/src/chrome/ChromeRegions.stories.tsx +1 -4
  105. package/src/chrome/LabChrome.tsx +130 -0
  106. package/src/chrome/builtins.test.ts +1 -0
  107. package/src/chrome/builtins.tsx +21 -31
  108. package/src/chrome/index.ts +16 -0
  109. package/src/chrome/labRegions.test.tsx +208 -0
  110. package/src/chrome/labTypes.ts +50 -0
  111. package/src/chrome/merge.ts +7 -9
  112. package/src/chrome/regions/PaletteRegion.test.tsx +6 -4
  113. package/src/chrome/regions/PaletteRegion.tsx +16 -9
  114. package/src/chrome/regions/SidebarRegion.stories.tsx +44 -0
  115. package/src/chrome/regions/SidebarRegion.tsx +25 -13
  116. package/src/chrome/regions/StatusRegion.tsx +15 -8
  117. package/src/chrome/regions/ToolbarRegion.tsx +34 -16
  118. package/src/chrome/types.ts +50 -20
  119. package/src/config/auto.test.ts +12 -0
  120. package/src/config/auto.ts +15 -0
  121. package/src/config/autoConfig.test.ts +107 -0
  122. package/src/config/autoConfig.ts +153 -0
  123. package/src/config/builder.test.ts +42 -0
  124. package/src/config/builder.ts +68 -17
  125. package/src/config/declarationEmit.fixture.ts +11 -0
  126. package/src/config/declarationEmit.test.ts +51 -0
  127. package/src/config/entry.test.ts +46 -0
  128. package/src/config/index.ts +16 -1
  129. package/src/config/nodeClasses.test.ts +18 -0
  130. package/src/config/path.ts +7 -2
  131. package/src/config/resolve.test.ts +25 -0
  132. package/src/config/resolve.ts +17 -1
  133. package/src/config/types.ts +34 -2
  134. package/src/config/useResolvedConfig.ts +26 -0
  135. package/src/controls/AutoControls.stories.tsx +88 -0
  136. package/src/controls/ControlPanel.stories.tsx +42 -1
  137. package/src/controls/ControlPanel.test.tsx +530 -4
  138. package/src/controls/ControlPanel.tsx +562 -82
  139. package/src/fake-indexeddb-auto.d.ts +5 -0
  140. package/src/index.test.ts +7 -0
  141. package/src/index.ts +66 -5
  142. package/src/instrument/serializers.test.ts +22 -0
  143. package/src/instrument/serializers.ts +40 -1
  144. package/src/instrument/types.ts +25 -1
  145. package/src/lab/Lab.chrome.test.tsx +16 -0
  146. package/src/lab/Lab.less +4 -13
  147. package/src/lab/Lab.persist.test.tsx +147 -0
  148. package/src/lab/Lab.stories.tsx +1 -3
  149. package/src/lab/Lab.surface.test.tsx +71 -3
  150. package/src/lab/Lab.test.tsx +168 -16
  151. package/src/lab/Lab.tsx +434 -129
  152. package/src/lab/LabContext.ts +8 -0
  153. package/src/lab/LabFit.stories.less +18 -0
  154. package/src/lab/LabFit.stories.tsx +219 -0
  155. package/src/lab/LabFullChrome.stories.tsx +1 -4
  156. package/src/lab/LabHeader.test.tsx +40 -9
  157. package/src/lab/LabHeader.tsx +7 -14
  158. package/src/lab/LabPalette.tsx +13 -26
  159. package/src/lab/LabRoot.test.tsx +56 -0
  160. package/src/lab/LabRoot.tsx +47 -0
  161. package/src/lab/LabShell.less +73 -15
  162. package/src/lab/LabShell.stories.tsx +50 -1
  163. package/src/lab/LabShell.tsx +18 -27
  164. package/src/lab/LabSwitcher.less +18 -11
  165. package/src/lab/LabSwitcher.test.tsx +14 -9
  166. package/src/lab/LabSwitcher.tsx +8 -4
  167. package/src/lab/Workspace.less +1 -1
  168. package/src/lab/Workspace.stories.tsx +1 -1
  169. package/src/lab/Workspace.surface.test.tsx +1 -0
  170. package/src/lab/fitCheck.test.ts +57 -0
  171. package/src/lab/fitCheck.ts +125 -0
  172. package/src/lab/index.ts +2 -0
  173. package/src/layers/LayerList.stories.tsx +1 -1
  174. package/src/loupe/AGENTS.md +17 -5
  175. package/src/loupe/Loupe.less +1 -1
  176. package/src/loupe/LoupeGestures.tsx +67 -0
  177. package/src/loupe/TrialLoupe.tsx +43 -28
  178. package/src/loupe/canvasLens.ts +1 -1
  179. package/src/loupe/index.ts +4 -0
  180. package/src/loupe/loupeActions.ts +98 -0
  181. package/src/loupe/types.ts +1 -1
  182. package/src/loupe/useLoupe.test.tsx +60 -3
  183. package/src/loupe/useLoupe.ts +29 -49
  184. package/src/passthrough/weasel-ui.ts +9 -0
  185. package/src/primitives/FloatingPanel.stories.tsx +14 -2
  186. package/src/primitives/FloatingPanel.test.tsx +47 -16
  187. package/src/primitives/FloatingPanel.tsx +11 -25
  188. package/src/primitives/FpsMeter.stories.tsx +1 -1
  189. package/src/primitives/JobProgress.stories.tsx +1 -1
  190. package/src/primitives/Legend.stories.tsx +1 -1
  191. package/src/primitives/ScaleIndicator.stories.tsx +1 -1
  192. package/src/primitives/Sidebar.less +7 -0
  193. package/src/primitives/Sidebar.stories.tsx +1 -1
  194. package/src/primitives/Split.less +14 -0
  195. package/src/primitives/Split.test.tsx +133 -0
  196. package/src/primitives/Split.tsx +175 -0
  197. package/src/primitives/StatusBar.stories.tsx +1 -1
  198. package/src/primitives/Toolbar.stories.tsx +1 -1
  199. package/src/primitives/ZoomControl.tsx +5 -2
  200. package/src/primitives/index.ts +2 -0
  201. package/src/specimen/Specimen.less +95 -0
  202. package/src/specimen/Specimen.stories.tsx +13 -0
  203. package/src/specimen/Specimen.test.tsx +13 -0
  204. package/src/specimen/Specimen.tsx +888 -0
  205. package/src/state/Persistence.stories.tsx +75 -0
  206. package/src/state/Persistence.tsx +33 -0
  207. package/src/state/SingletonExperiment.test.tsx +47 -53
  208. package/src/state/SingletonExperiment.tsx +24 -13
  209. package/src/state/adapterContract.ts +116 -0
  210. package/src/state/adapters.test.ts +113 -61
  211. package/src/state/adapters.ts +328 -69
  212. package/src/state/document.test.ts +71 -96
  213. package/src/state/document.ts +66 -52
  214. package/src/state/helpers.test.ts +1 -1
  215. package/src/state/index.ts +8 -0
  216. package/src/state/labRecords.test.ts +105 -0
  217. package/src/state/labRecords.ts +160 -0
  218. package/src/state/openLabStore.test.ts +658 -0
  219. package/src/state/openLabStore.ts +403 -0
  220. package/src/state/records.test.ts +234 -0
  221. package/src/state/records.ts +219 -0
  222. package/src/state/store.test.ts +169 -635
  223. package/src/state/store.ts +146 -163
  224. package/src/state/toolSlot.test.ts +1 -1
  225. package/src/state/types.ts +65 -17
  226. package/src/state/useOpenOnce.ts +68 -0
  227. package/src/state/usePersistedState.test.tsx +125 -0
  228. package/src/state/usePersistedState.ts +66 -0
  229. package/src/state/useTrialState.test.tsx +87 -3
  230. package/src/state/useTrialState.ts +9 -1
  231. package/src/state/view.test.ts +49 -15
  232. package/src/state/view.ts +18 -1
  233. package/src/styles.less +3 -0
  234. package/src/surface/AGENTS.md +39 -7
  235. package/src/surface/SurfaceContext.ts +26 -3
  236. package/src/surface/index.ts +2 -0
  237. package/src/surface/useSurfaceTile.test.tsx +1 -0
  238. package/src/surface/useSurfaceTile.ts +6 -5
  239. package/src/surface/useTiledSurface.test.tsx +231 -1
  240. package/src/surface/useTiledSurface.ts +76 -15
  241. package/src/theme/Interstellar.stories.tsx +9 -9
  242. package/src/theme/interstellar.test.ts +17 -6
  243. package/src/theme/interstellar.theme.json +180 -0
  244. package/src/theme/interstellar.ts +8 -5
  245. package/src/tools/labTool.ts +11 -0
  246. package/src/trial/Trial.annotations.persist.test.tsx +100 -58
  247. package/src/trial/Trial.annotations.test.tsx +59 -7
  248. package/src/trial/Trial.canvas.test.tsx +32 -0
  249. package/src/trial/Trial.config.test.tsx +75 -2
  250. package/src/trial/Trial.job.test.tsx +3 -3
  251. package/src/trial/Trial.less +5 -26
  252. package/src/trial/Trial.stories.tsx +5 -3
  253. package/src/trial/Trial.test.tsx +31 -4
  254. package/src/trial/Trial.trialId.test.tsx +23 -1
  255. package/src/trial/Trial.tsx +139 -52
  256. package/src/trial/TrialBody.tsx +17 -141
  257. package/src/trial/TrialChrome.tsx +24 -7
  258. package/src/trial/trialOps.test.ts +101 -1
  259. package/src/trial/trialOps.ts +67 -7
  260. package/dist/_dts/types-BP2OCcpg.d.ts +0 -155
  261. package/dist/_dts/types-x92Kfeme.d.ts +0 -62
  262. package/dist/_dts/useTrialState-D6Vb3T-g.d.ts +0 -99
  263. package/dist/chunk-2P6PP5N4.js +0 -553
  264. package/dist/chunk-2P6PP5N4.js.map +0 -1
  265. package/dist/chunk-64ZCN3DA.js.map +0 -1
  266. package/dist/chunk-CTRKTLYZ.js.map +0 -1
  267. package/dist/chunk-E44SU6XS.js +0 -50
  268. package/dist/chunk-E44SU6XS.js.map +0 -1
  269. package/dist/chunk-FQMJUVHJ.js.map +0 -1
  270. package/dist/chunk-I6JCVE24.js.map +0 -1
  271. package/dist/chunk-MOM3GOVY.js.map +0 -1
  272. package/dist/chunk-SMHP6XZ4.js.map +0 -1
  273. package/dist/chunk-TJ7QY3OC.js.map +0 -1
  274. package/dist/chunk-U3IYHIAE.js +0 -343
  275. package/dist/chunk-U3IYHIAE.js.map +0 -1
  276. package/dist/chunk-W3ECWC2K.js +0 -7335
  277. package/dist/chunk-W3ECWC2K.js.map +0 -1
  278. package/src/theme/interstellar.tokens.json +0 -61
@@ -1,343 +0,0 @@
1
- import { schemaNodeAtPath, valueAtPath } from './chunk-E44SU6XS.js';
2
- import { T2, H, t2, M2, L2, I, N2, A2, F, D, P2 } from './chunk-W3ECWC2K.js';
3
- import { isBuiltinToolPref } from '@weasel-js/core';
4
- import { useMemo, Fragment as Fragment$1, useState, useRef, useEffect } from 'react';
5
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
-
7
- // src/config/fromConfigField.ts
8
- function toLeaf(field) {
9
- const base = { name: field.label, description: "" };
10
- switch (field.type) {
11
- case "slider":
12
- return {
13
- ...base,
14
- kind: "number",
15
- control: "slider",
16
- min: field.min,
17
- max: field.max,
18
- step: field.step
19
- };
20
- case "number":
21
- return {
22
- ...base,
23
- kind: "number",
24
- control: "input",
25
- min: field.min,
26
- max: field.max,
27
- step: field.step
28
- };
29
- case "checkbox":
30
- return { ...base, kind: "boolean", control: "checkbox" };
31
- case "select":
32
- return { ...base, kind: "enum", options: field.options };
33
- case "text":
34
- return {
35
- ...base,
36
- kind: "string",
37
- placeholder: field.placeholder,
38
- maxLength: field.maxLength,
39
- debounceMs: field.debounceMs
40
- };
41
- case "color":
42
- return { ...base, kind: "color" };
43
- default:
44
- return { ...base, kind: field.type };
45
- }
46
- }
47
- function fromConfigFields(fields) {
48
- const children = {};
49
- for (const field of fields) {
50
- const patch = toLeaf(field);
51
- for (const key of Object.keys(patch)) {
52
- if (patch[key] === void 0) {
53
- delete patch[key];
54
- }
55
- }
56
- children[field.key] = { ...patch, default: field.default };
57
- }
58
- return {
59
- group: { name: "", children },
60
- sections: [],
61
- showIf: /* @__PURE__ */ new Map(),
62
- renderers: {}
63
- };
64
- }
65
-
66
- // src/config/visible.ts
67
- function isLeafVisible(resolved, path, config, showHidden = false) {
68
- const node = schemaNodeAtPath(resolved.group, path);
69
- if (node && "hidden" in node && node.hidden === true && !showHidden) return false;
70
- const predicate = resolved.showIf.get(path);
71
- return predicate ? predicate(config) : true;
72
- }
73
- function ControlPanel({
74
- schema,
75
- fields,
76
- config,
77
- setConfig,
78
- renderers,
79
- pack = "pairs",
80
- layout,
81
- density,
82
- align,
83
- collapse,
84
- collapsed,
85
- onCollapse,
86
- showHidden = false,
87
- className
88
- }) {
89
- const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);
90
- const gridPack = pack === "one-up" ? "auto-color" : "pairs";
91
- const folds = collapse !== void 0 || collapsed !== void 0 || onCollapse !== void 0 || resolved.sections.some((s) => s.collapsed !== void 0);
92
- const startsFolded = collapse === "closed";
93
- const fold = (key, declared) => ({
94
- pack: gridPack,
95
- collapsible: folds,
96
- defaultCollapsed: declared ?? startsFolded,
97
- collapsed: collapsed ? collapsed[key] ?? declared ?? startsFolded : void 0,
98
- onCollapsedChange: onCollapse ? (next) => onCollapse(key, next) : void 0
99
- });
100
- const node = (path) => {
101
- const found = schemaNodeAtPath(resolved.group, path);
102
- if (!found) return null;
103
- if (!isLeafVisible(resolved, path, config, showHidden)) return null;
104
- if (t2(found)) {
105
- return /* @__PURE__ */ jsx(
106
- ControlRow,
107
- {
108
- path,
109
- leaf: found,
110
- resolved,
111
- config,
112
- setConfig,
113
- renderers,
114
- pack,
115
- layout
116
- },
117
- path
118
- );
119
- }
120
- if (found.name === "") return /* @__PURE__ */ jsx(Fragment$1, { children: body(found, path) }, path);
121
- return /* @__PURE__ */ jsx(H, { title: found.name, ...fold(path), children: body(found, path) }, path);
122
- };
123
- const body = (group, at) => {
124
- const sections = resolved.sections.filter((s) => s.at === at);
125
- const sectioned = new Set(sections.flatMap((s) => s.paths));
126
- const paths = Object.keys(group.children).map((key) => at === "" ? key : `${at}.${key}`);
127
- return /* @__PURE__ */ jsxs(Fragment, { children: [
128
- paths.filter((p) => !sectioned.has(p)).map(node),
129
- sections.map((section) => /* @__PURE__ */ jsx(
130
- H,
131
- {
132
- title: section.label,
133
- ...fold(sectionKey(section), section.collapsed),
134
- children: section.paths.map(node)
135
- },
136
- sectionKey(section)
137
- ))
138
- ] });
139
- };
140
- return /* @__PURE__ */ jsx(
141
- T2,
142
- {
143
- pack: gridPack,
144
- density,
145
- align,
146
- className: className ? `lk-control-panel ${className}` : "lk-control-panel",
147
- children: body(resolved.group, "")
148
- }
149
- );
150
- }
151
- function sectionKey(section) {
152
- return section.at === "" ? section.label : `${section.at}.${section.label}`;
153
- }
154
- function extra(leaf, key) {
155
- return leaf[key];
156
- }
157
- function ControlRow({
158
- path,
159
- leaf,
160
- resolved,
161
- config,
162
- setConfig,
163
- renderers,
164
- pack,
165
- layout
166
- }) {
167
- const write = (value2) => setConfig(path, value2);
168
- const fallback = extra(leaf, "default");
169
- const value = valueAtPath(config, path) ?? fallback;
170
- const custom = renderers?.[path] ?? resolved.renderers[path] ?? renderers?.[leaf.kind];
171
- if (custom) return custom({ path, pref: leaf, value, setValue: write });
172
- const label = leaf.name;
173
- const description = leaf.description;
174
- const read = () => value;
175
- const wide = pack === "auto";
176
- if (!isBuiltinToolPref(leaf))
177
- return /* @__PURE__ */ jsx(UnwiredRow, { label, kind: leaf.kind, description });
178
- switch (leaf.kind) {
179
- case "number": {
180
- const min = extra(leaf, "min");
181
- const max = extra(leaf, "max");
182
- const step = extra(leaf, "step");
183
- const suffix = extra(leaf, "suffix");
184
- if (extra(leaf, "control") === "slider" && min !== void 0 && max !== void 0) {
185
- return /* @__PURE__ */ jsx(
186
- A2,
187
- {
188
- label,
189
- value: read(),
190
- min,
191
- max,
192
- step,
193
- unit: suffix,
194
- onChange: write,
195
- layout,
196
- span: wide,
197
- description
198
- }
199
- );
200
- }
201
- const lo = min ?? Number.NEGATIVE_INFINITY;
202
- const hi = max ?? Number.POSITIVE_INFINITY;
203
- return /* @__PURE__ */ jsx(
204
- F,
205
- {
206
- label,
207
- value: read(),
208
- min,
209
- max,
210
- step,
211
- unit: suffix,
212
- onChange: (n) => write(Math.min(hi, Math.max(lo, n))),
213
- layout,
214
- description
215
- }
216
- );
217
- }
218
- case "boolean":
219
- return /* @__PURE__ */ jsx(
220
- N2,
221
- {
222
- label,
223
- value: read(),
224
- onChange: write,
225
- layout,
226
- description
227
- }
228
- );
229
- case "enum": {
230
- const options = extra(leaf, "options") ?? [];
231
- const segmented = extra(leaf, "control") === "radio";
232
- const Row = segmented ? L2 : I;
233
- return /* @__PURE__ */ jsx(
234
- Row,
235
- {
236
- label,
237
- value: read(),
238
- options,
239
- onChange: write,
240
- layout,
241
- span: segmented && wide,
242
- description
243
- }
244
- );
245
- }
246
- case "string":
247
- return /* @__PURE__ */ jsx(
248
- DebouncedTextRow,
249
- {
250
- leaf,
251
- label,
252
- value: read(),
253
- write,
254
- layout,
255
- span: wide,
256
- description
257
- }
258
- );
259
- case "color":
260
- return /* @__PURE__ */ jsx(
261
- M2,
262
- {
263
- label,
264
- value: read(),
265
- onChange: write,
266
- layout,
267
- description
268
- }
269
- );
270
- case "paint":
271
- case "object":
272
- return /* @__PURE__ */ jsx(UnwiredRow, { label, kind: leaf.kind, description });
273
- default: {
274
- const _exhaustive = leaf;
275
- throw new Error(
276
- `ControlPanel: no control for built-in pref kind "${_exhaustive.kind}"`
277
- );
278
- }
279
- }
280
- }
281
- function UnwiredRow({
282
- label,
283
- kind,
284
- description
285
- }) {
286
- return /* @__PURE__ */ jsx(D, { label, description, children: /* @__PURE__ */ jsxs("span", { className: "lk-control-panel__unknown", children: [
287
- "no control for \u201C",
288
- kind,
289
- "\u201D"
290
- ] }) });
291
- }
292
- function DebouncedTextRow({
293
- leaf,
294
- label,
295
- value,
296
- write,
297
- layout,
298
- span,
299
- description
300
- }) {
301
- const debounceMs = extra(leaf, "debounceMs") ?? 150;
302
- const [local, setLocal] = useState(value);
303
- const timer = useRef(null);
304
- const lastExternal = useRef(value);
305
- useEffect(() => {
306
- if (value !== lastExternal.current) {
307
- lastExternal.current = value;
308
- setLocal(value);
309
- }
310
- }, [value]);
311
- useEffect(
312
- () => () => {
313
- if (timer.current) clearTimeout(timer.current);
314
- },
315
- []
316
- );
317
- return /* @__PURE__ */ jsx(
318
- P2,
319
- {
320
- label,
321
- layout,
322
- span,
323
- description,
324
- value: local,
325
- placeholder: extra(leaf, "placeholder"),
326
- maxLength: extra(leaf, "maxLength"),
327
- onChange: (next) => {
328
- setLocal(next);
329
- if (timer.current) clearTimeout(timer.current);
330
- const commit = () => {
331
- lastExternal.current = next;
332
- write(next);
333
- };
334
- if (debounceMs === 0) commit();
335
- else timer.current = setTimeout(commit, debounceMs);
336
- }
337
- }
338
- );
339
- }
340
-
341
- export { ControlPanel, fromConfigFields, isLeafVisible };
342
- //# sourceMappingURL=chunk-U3IYHIAE.js.map
343
- //# sourceMappingURL=chunk-U3IYHIAE.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/fromConfigField.ts","../src/config/visible.ts","../src/controls/ControlPanel.tsx"],"names":["t","Fragment","T","value","A","N","L","M","P"],"mappings":"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","file":"chunk-U3IYHIAE.js","sourcesContent":["import type { PrefLeaf } from '@weasel-js/ui';\nimport type { ConfigField } from '../controls/types';\nimport type { LeafPatch, ResolvedConfig } from './types';\n\n/** One `ConfigField` as the `Pref*` vocabulary spells it. The two describe the\n * same thing; `ConfigField` just keys on the control where `PrefLeaf`\n * separates the value's kind from how it is presented. */\nfunction toLeaf(field: ConfigField): LeafPatch {\n const base = { name: field.label, description: '' };\n switch (field.type) {\n case 'slider':\n return {\n ...base,\n kind: 'number',\n control: 'slider',\n min: field.min,\n max: field.max,\n step: field.step,\n };\n case 'number':\n return {\n ...base,\n kind: 'number',\n control: 'input',\n min: field.min,\n max: field.max,\n step: field.step,\n };\n case 'checkbox':\n return { ...base, kind: 'boolean', control: 'checkbox' };\n case 'select':\n return { ...base, kind: 'enum', options: field.options };\n case 'text':\n return {\n ...base,\n kind: 'string',\n placeholder: field.placeholder,\n maxLength: field.maxLength,\n debounceMs: field.debounceMs,\n };\n case 'color':\n return { ...base, kind: 'color' };\n default:\n // A schema can arrive from outside TypeScript. Carry the kind through\n // so a lab-supplied renderer can still claim it.\n return { ...base, kind: (field as ConfigField).type };\n }\n}\n\n/**\n * Adapt a legacy `configSchema(): ConfigField[]` into the resolved shape, so\n * both instrument paths reach one renderer.\n *\n * Rules do not run here: a hand-written `ConfigField` already states its label\n * and control, which is everything the rule chain would have inferred.\n */\nexport function fromConfigFields(fields: readonly ConfigField[]): ResolvedConfig {\n const children: Record<string, PrefLeaf> = {};\n for (const field of fields) {\n const patch = toLeaf(field);\n for (const key of Object.keys(patch)) {\n if ((patch as Record<string, unknown>)[key] === undefined) {\n delete (patch as Record<string, unknown>)[key];\n }\n }\n children[field.key] = { ...patch, default: field.default } as PrefLeaf;\n }\n return {\n group: { name: '', children },\n sections: [],\n showIf: new Map(),\n renderers: {},\n };\n}\n","import { schemaNodeAtPath } from './path';\nimport type { ResolvedConfig } from './types';\n\n/**\n * Whether the row at a dotted path should be drawn right now. A group answers\n * for its whole subtree — hiding one hides everything under it.\n *\n * `hidden` is the node's own static flag; `showIf` is the schema's predicate\n * over the live config. Both are presentational — a hidden leaf keeps its\n * value and the instrument still reads it.\n */\nexport function isLeafVisible(\n resolved: ResolvedConfig,\n path: string,\n config: Record<string, unknown>,\n showHidden = false,\n): boolean {\n const node = schemaNodeAtPath(resolved.group, path);\n if (node && 'hidden' in node && node.hidden === true && !showHidden) return false;\n const predicate = resolved.showIf.get(path);\n return predicate ? predicate(config) : true;\n}\n","import { isBuiltinToolPref } from '@weasel-js/core';\nimport {\n CheckboxRow,\n ColorRow,\n isPrefLeaf,\n NumberRow,\n type PrefGroup,\n type PrefLeaf,\n type PropertyAlign,\n type PropertyDensity,\n PropertyGroup,\n PropertyList,\n type PropertyListPack,\n PropertyRow,\n type PropertyRowLayout,\n SelectRow,\n SliderRow,\n TextRow,\n ToggleRow,\n} from '@weasel-js/ui';\nimport { Fragment, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\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 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, colours) 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, colours excepted.\n */\nexport type ControlPack = 'auto' | 'pairs' | 'one-up';\n\nexport interface ControlPanelProps<TC extends Record<string, unknown>> {\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 /** Draw leaves marked `hidden`. */\n showHidden?: boolean;\n className?: string;\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 showHidden = false,\n className,\n}: ControlPanelProps<TC>) {\n const resolved = useMemo(() => schema ?? fromConfigFields(fields ?? []), [schema, fields]);\n\n const gridPack: PropertyListPack = pack === 'one-up' ? 'auto-color' : 'pairs';\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) => ({\n pack: gridPack,\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): 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 setConfig={setConfig}\n renderers={renderers}\n pack={pack}\n layout={layout}\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)}</Fragment>;\n return (\n <PropertyGroup key={path} title={found.name} {...fold(path)}>\n {body(found, path)}\n </PropertyGroup>\n );\n };\n\n /** One group's children: its loose nodes, then its sections. */\n const body = (group: PrefGroup, at: string): 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 {paths.filter((p) => !sectioned.has(p)).map(node)}\n {sections.map((section) => (\n <PropertyGroup\n key={sectionKey(section)}\n title={section.label}\n {...fold(sectionKey(section), section.collapsed)}\n >\n {section.paths.map(node)}\n </PropertyGroup>\n ))}\n </>\n );\n };\n\n return (\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, '')}\n </PropertyList>\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 setConfig: (path: string, value: unknown) => void;\n renderers?: Record<string, ControlRenderer>;\n pack: ControlPack;\n layout?: PropertyRowLayout;\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 setConfig,\n renderers,\n pack,\n layout,\n}: ControlRowProps<TC>) {\n const write = (value: unknown): void => setConfig(path, value);\n const fallback = extra<unknown>(leaf, 'default');\n const value = valueAtPath(config, path) ?? fallback;\n\n // Most specific wins, and within a tier the lab's entry beats the\n // instrument's: controls[path] -> node .render -> controls[kind] -> built-in.\n const custom = renderers?.[path] ?? resolved.renderers[path] ?? 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 });\n\n const label = leaf.name;\n const description = leaf.description;\n const read = <T,>(): T => value as T;\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\n if (!isBuiltinToolPref(leaf))\n return <UnwiredRow label={label} kind={leaf.kind} description={description} />;\n\n switch (leaf.kind) {\n case 'number': {\n const min = extra<number>(leaf, 'min');\n const max = extra<number>(leaf, 'max');\n const step = extra<number>(leaf, 'step');\n const suffix = extra<string>(leaf, 'suffix');\n if (extra<string>(leaf, 'control') === 'slider' && min !== undefined && max !== undefined) {\n return (\n <SliderRow\n label={label}\n value={read<number>()}\n min={min}\n max={max}\n step={step}\n unit={suffix}\n onChange={write}\n layout={layout}\n span={wide}\n description={description}\n />\n );\n }\n // NumberRow commits every keystroke and does not clamp, so the bounds a\n // schema declares are enforced here — an instrument should never be\n // handed a config value outside the range it asked for.\n const lo = min ?? Number.NEGATIVE_INFINITY;\n const hi = max ?? Number.POSITIVE_INFINITY;\n return (\n <NumberRow\n label={label}\n value={read<number>()}\n min={min}\n max={max}\n step={step}\n unit={suffix}\n onChange={(n) => write(Math.min(hi, Math.max(lo, n)))}\n layout={layout}\n description={description}\n />\n );\n }\n case 'boolean':\n return (\n <CheckboxRow\n label={label}\n value={read<boolean>()}\n onChange={write}\n layout={layout}\n description={description}\n />\n );\n case 'enum': {\n const options = extra<readonly { value: string; label: string }[]>(leaf, 'options') ?? [];\n const segmented = extra<string>(leaf, 'control') === 'radio';\n const Row = segmented ? ToggleRow : SelectRow;\n return (\n <Row\n label={label}\n value={read<string>()}\n options={options}\n onChange={write}\n layout={layout}\n span={segmented && wide}\n description={description}\n />\n );\n }\n case 'string':\n return (\n <DebouncedTextRow\n leaf={leaf}\n label={label}\n value={read<string>()}\n write={write}\n layout={layout}\n span={wide}\n description={description}\n />\n );\n case 'color':\n return (\n <ColorRow\n label={label}\n value={read<string>()}\n onChange={write}\n layout={layout}\n description={description}\n />\n );\n case 'paint':\n case 'object':\n // Declined: a hex swatch would write a solid over a gradient, and a flat\n // row would write one field into a half-built object. Override with\n // `render` to edit either.\n return <UnwiredRow label={label} kind={leaf.kind} description={description} />;\n default: {\n // Not reachable while every built-in kind has an arm — and a new kind\n // that lacks one is a compile error here, never a blank row.\n const _exhaustive: never = leaf;\n throw new Error(\n `ControlPanel: no control for built-in pref kind \"${(_exhaustive as { kind: string }).kind}\"`,\n );\n }\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/** Text writes are debounced so typing does not re-run the instrument on every\n * keystroke, which means the row is locally controlled between commits and has\n * to notice when the config changes underneath it. */\nfunction DebouncedTextRow({\n leaf,\n label,\n value,\n write,\n layout,\n span,\n description,\n}: {\n leaf: PrefLeaf;\n label: string;\n value: string;\n write: (value: unknown) => void;\n layout?: PropertyRowLayout;\n span?: boolean;\n description?: string;\n}) {\n const debounceMs = extra<number>(leaf, 'debounceMs') ?? 150;\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 <TextRow\n label={label}\n layout={layout}\n span={span}\n description={description}\n value={local}\n placeholder={extra<string>(leaf, 'placeholder')}\n maxLength={extra<number>(leaf, 'maxLength')}\n onChange={(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}\n"]}