@weasel-js/labkit 1.6.0 → 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 (222) hide show
  1. package/dist/_dts/{CanvasStackContext-DQgcH1ny.d.ts → CanvasStackContext-D2jnIwfk.d.ts} +1 -1
  2. package/dist/_dts/FloatingPanel-7j0IcXwz.d.ts +30 -0
  3. package/dist/_dts/{LayerList.d-2c9yup5Y.d.ts → LayerList.d-DiuEArKq.d.ts} +4 -4
  4. package/dist/_dts/PrefsRow.d-TOZ7BgD9.d.ts +79 -0
  5. package/dist/_dts/PropertyPanel.d-D-1paCbE.d.ts +141 -0
  6. package/dist/_dts/{Select.d-BchGMC2Y.d.ts → Select.d-Bensr_MT.d.ts} +15 -6
  7. package/dist/_dts/Stage-CCWfQQWM.d.ts +202 -0
  8. package/dist/_dts/index-B2Yj5aA0.d.ts +274 -0
  9. package/dist/_dts/{index-B0--8PEM.d.ts → index-CsYqUHD3.d.ts} +12 -13
  10. package/dist/_dts/{types-B7y8hX1D.d.ts → types-CRPSGFAp.d.ts} +33 -5
  11. package/dist/_dts/{frac-DTRq7Xpb.d.ts → types-CSm9jgol.d.ts} +700 -650
  12. package/dist/_dts/{useTrialState-CP4jfuKl.d.ts → useTrialState-CTZPgeZ7.d.ts} +2 -3
  13. package/dist/canvas/index.d.ts +40 -8
  14. package/dist/canvas/index.js +5 -3
  15. package/dist/chrome/index.d.ts +5 -6
  16. package/dist/chrome/index.js +9 -7
  17. package/dist/chunk-24W5VEJW.js +18 -0
  18. package/dist/chunk-24W5VEJW.js.map +1 -0
  19. package/dist/chunk-275JRRVD.js +728 -0
  20. package/dist/chunk-275JRRVD.js.map +1 -0
  21. package/dist/chunk-3RY6WL5T.js +38 -0
  22. package/dist/chunk-3RY6WL5T.js.map +1 -0
  23. package/dist/chunk-4LJSC7MB.js +143 -0
  24. package/dist/chunk-4LJSC7MB.js.map +1 -0
  25. package/dist/{chunk-3FI7Y4R4.js → chunk-7BO7HNGF.js} +5 -5
  26. package/dist/{chunk-3FI7Y4R4.js.map → chunk-7BO7HNGF.js.map} +1 -1
  27. package/dist/chunk-AWQG7FCC.js +19 -0
  28. package/dist/chunk-AWQG7FCC.js.map +1 -0
  29. package/dist/chunk-CZZPXUOU.js +3 -0
  30. package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
  31. package/dist/{chunk-ZORVNOKX.js → chunk-FMK7UQ6V.js} +24 -145
  32. package/dist/chunk-FMK7UQ6V.js.map +1 -0
  33. package/dist/{chunk-BVL7Y574.js → chunk-FZ7YFQN7.js} +26 -10
  34. package/dist/chunk-FZ7YFQN7.js.map +1 -0
  35. package/dist/{chunk-USO6TERP.js → chunk-GOZLNM4L.js} +11 -9
  36. package/dist/chunk-GOZLNM4L.js.map +1 -0
  37. package/dist/{chunk-H5VIV7MQ.js → chunk-I5DUQ5HM.js} +88 -82
  38. package/dist/chunk-I5DUQ5HM.js.map +1 -0
  39. package/dist/chunk-J7OWWTCW.js +143 -0
  40. package/dist/chunk-J7OWWTCW.js.map +1 -0
  41. package/dist/{chunk-H6ZAOWNE.js → chunk-JVBYV6TL.js} +3 -3
  42. package/dist/{chunk-H6ZAOWNE.js.map → chunk-JVBYV6TL.js.map} +1 -1
  43. package/dist/{chunk-VQ47KWD5.js → chunk-KMJ7RWD3.js} +18 -7
  44. package/dist/chunk-KMJ7RWD3.js.map +1 -0
  45. package/dist/{chunk-ERFMC6WU.js → chunk-M7HP3FTK.js} +20 -11
  46. package/dist/chunk-M7HP3FTK.js.map +1 -0
  47. package/dist/chunk-MIM5R4ZT.js +14972 -0
  48. package/dist/chunk-MIM5R4ZT.js.map +1 -0
  49. package/dist/{chunk-HFRE4QQV.js → chunk-T5IBSPAM.js} +96 -32
  50. package/dist/chunk-T5IBSPAM.js.map +1 -0
  51. package/dist/chunk-UNAZSLWE.js +294 -0
  52. package/dist/chunk-UNAZSLWE.js.map +1 -0
  53. package/dist/{chunk-RS3HRQWU.js → chunk-WPLAANH4.js} +4 -3
  54. package/dist/chunk-WPLAANH4.js.map +1 -0
  55. package/dist/{chunk-AWH3SRPW.js → chunk-Y23G2VZL.js} +5 -37
  56. package/dist/chunk-Y23G2VZL.js.map +1 -0
  57. package/dist/{chunk-MOLIUNVH.js → chunk-YT75VYRD.js} +4 -4
  58. package/dist/{chunk-MOLIUNVH.js.map → chunk-YT75VYRD.js.map} +1 -1
  59. package/dist/chunk-ZIFPHIWZ.js +302 -0
  60. package/dist/chunk-ZIFPHIWZ.js.map +1 -0
  61. package/dist/config/index.d.ts +48 -40
  62. package/dist/config/index.js +4 -5
  63. package/dist/controls/index.d.ts +91 -7
  64. package/dist/controls/index.js +5 -4
  65. package/dist/dragdrop/index.d.ts +9 -7
  66. package/dist/dragdrop/index.js +3 -2
  67. package/dist/index.d.ts +294 -82
  68. package/dist/index.js +425 -402
  69. package/dist/index.js.map +1 -1
  70. package/dist/layers/index.d.ts +4 -5
  71. package/dist/layers/index.js +2 -1
  72. package/dist/loupe/index.d.ts +20 -17
  73. package/dist/loupe/index.js +5 -3
  74. package/dist/overview/index.d.ts +56 -0
  75. package/dist/overview/index.js +289 -0
  76. package/dist/overview/index.js.map +1 -0
  77. package/dist/passthrough/weasel-ui.d.ts +239 -69
  78. package/dist/passthrough/weasel-ui.js +3 -2
  79. package/dist/primitives/index.d.ts +5 -204
  80. package/dist/primitives/index.js +6 -4
  81. package/dist/state/index.d.ts +8 -8
  82. package/dist/state/index.js +4 -5
  83. package/dist/state/index.js.map +1 -1
  84. package/dist/styles.css +152 -82
  85. package/dist/undo/index.d.ts +4 -4
  86. package/package.json +17 -12
  87. package/src/annotations/AnnotationOverlay.tsx +2 -2
  88. package/src/annotations/Annotations.less +0 -10
  89. package/src/annotations/MarkList.tsx +4 -8
  90. package/src/annotations/index.ts +1 -0
  91. package/src/annotations/paint.test.ts +3 -14
  92. package/src/annotations/paint.ts +3 -19
  93. package/src/annotations/store.test.ts +26 -0
  94. package/src/annotations/store.ts +25 -6
  95. package/src/annotations/svgNodes.test.ts +6 -9
  96. package/src/annotations/svgNodes.ts +3 -3
  97. package/src/annotations/toolMap.test.ts +37 -2
  98. package/src/annotations/toolMap.ts +13 -0
  99. package/src/annotations/types.ts +27 -0
  100. package/src/canvas/AGENTS.md +9 -10
  101. package/src/canvas/CameraInput.test.tsx +136 -0
  102. package/src/canvas/CameraInput.tsx +322 -0
  103. package/src/canvas/CanvasStack.tsx +47 -58
  104. package/src/canvas/LinkedCursor.less +16 -0
  105. package/src/canvas/LinkedCursor.tsx +54 -0
  106. package/src/canvas/Stage.test.tsx +33 -4
  107. package/src/canvas/Stage.tsx +47 -37
  108. package/src/canvas/cameraRegistry.test.ts +55 -0
  109. package/src/canvas/cameraRegistry.ts +86 -0
  110. package/src/canvas/cameraView.test.ts +60 -0
  111. package/src/canvas/cameraView.ts +61 -0
  112. package/src/canvas/cameraZoom.test.ts +46 -0
  113. package/src/canvas/cameraZoom.ts +24 -0
  114. package/src/canvas/index.ts +23 -2
  115. package/src/canvas/sharedScope.test.tsx +94 -0
  116. package/src/chrome/ChromeRegions.stories.tsx +1 -0
  117. package/src/chrome/regions/PaletteRegion.less +0 -7
  118. package/src/chrome/regions/SidebarRegion.less +12 -2
  119. package/src/chrome/regions/SidebarRegion.test.tsx +9 -2
  120. package/src/config/builder.test.ts +2 -1
  121. package/src/config/builder.ts +15 -8
  122. package/src/config/entry.test.ts +3 -1
  123. package/src/config/fromConfigField.test.ts +14 -0
  124. package/src/config/fromConfigField.ts +19 -4
  125. package/src/config/index.ts +4 -1
  126. package/src/config/path.ts +2 -5
  127. package/src/config/resolve.ts +15 -1
  128. package/src/config/sectionTree.test.ts +12 -6
  129. package/src/config/sectionTree.ts +15 -5
  130. package/src/config/types.ts +34 -9
  131. package/src/controls/ControlPanel.less +1 -1
  132. package/src/controls/ControlPanel.stories.tsx +3 -2
  133. package/src/controls/ControlPanel.test.tsx +76 -13
  134. package/src/controls/ControlPanel.tsx +80 -11
  135. package/src/controls/inDialog.test.tsx +18 -0
  136. package/src/controls/inDialog.tsx +2 -10
  137. package/src/index.test.ts +1 -1
  138. package/src/index.ts +23 -5
  139. package/src/instrument/SineWave.smoke.test.tsx +2 -0
  140. package/src/instrument/types.ts +10 -1
  141. package/src/lab/Lab.nebula.test.tsx +11 -2
  142. package/src/lab/Lab.test.tsx +3 -1
  143. package/src/lab/Lab.tsx +87 -76
  144. package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
  145. package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
  146. package/src/lab/LabFullChrome.stories.tsx +1 -0
  147. package/src/lab/LabHeader.test.tsx +24 -14
  148. package/src/lab/LabHeader.tsx +11 -12
  149. package/src/lab/LabShell.less +8 -17
  150. package/src/lab/LabSwitcher.less +6 -6
  151. package/src/lab/LabZoom.test.tsx +223 -0
  152. package/src/lab/LabZoom.tsx +170 -0
  153. package/src/lab/index.ts +1 -0
  154. package/src/loupe/AGENTS.md +7 -6
  155. package/src/loupe/LoupeGestures.tsx +15 -10
  156. package/src/loupe/TrialLoupe.tsx +5 -5
  157. package/src/loupe/index.ts +1 -0
  158. package/src/loupe/loupeActions.ts +6 -2
  159. package/src/overview/AGENTS.md +38 -0
  160. package/src/overview/OverviewMarks.test.tsx +100 -0
  161. package/src/overview/OverviewMarks.tsx +93 -0
  162. package/src/overview/TrialOverview.less +53 -0
  163. package/src/overview/TrialOverview.stories.tsx +50 -0
  164. package/src/overview/TrialOverview.test.tsx +116 -0
  165. package/src/overview/TrialOverview.tsx +376 -0
  166. package/src/overview/index.ts +2 -0
  167. package/src/passthrough/weasel-ui.test.ts +2 -0
  168. package/src/passthrough/weasel-ui.ts +23 -4
  169. package/src/primitives/FloatingPanel.test.tsx +11 -0
  170. package/src/primitives/FloatingPanel.tsx +2 -5
  171. package/src/primitives/JobProgress.less +1 -1
  172. package/src/primitives/Legend.stories.tsx +1 -0
  173. package/src/primitives/Readout.browser.test.tsx +137 -0
  174. package/src/primitives/Readout.less +12 -0
  175. package/src/primitives/Readout.stories.tsx +58 -0
  176. package/src/primitives/Readout.test.tsx +93 -0
  177. package/src/primitives/Readout.tsx +56 -0
  178. package/src/primitives/index.ts +2 -0
  179. package/src/specimen/Specimen.stories.tsx +1 -0
  180. package/src/specimen/Specimen.tsx +21 -4
  181. package/src/state/Persistence.browser.test.tsx +47 -0
  182. package/src/state/labRecords.test.ts +4 -1
  183. package/src/state/store.test.ts +9 -5
  184. package/src/state/usePersistedState.test.tsx +1 -1
  185. package/src/state/useTrialState.test.tsx +1 -1
  186. package/src/styles.less +3 -0
  187. package/src/theme/Interstellar.stories.tsx +4 -6
  188. package/src/theme/base.less +21 -47
  189. package/src/theme/interstellar.test.ts +1 -1
  190. package/src/theme/interstellar.theme.json +10 -3
  191. package/src/tools/labTool.ts +6 -2
  192. package/src/trial/Trial.annotations.test.tsx +16 -0
  193. package/src/trial/Trial.less +0 -13
  194. package/src/trial/Trial.loupe.test.tsx +73 -1
  195. package/src/trial/Trial.stories.tsx +2 -0
  196. package/src/trial/Trial.tsx +23 -1
  197. package/src/trial/TrialChrome.tsx +21 -3
  198. package/src/trial/trialOps.test.ts +4 -4
  199. package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
  200. package/dist/_dts/inDialog-D5ZKGjiD.d.ts +0 -23
  201. package/dist/_dts/index-DINmCuLA.d.ts +0 -453
  202. package/dist/_dts/number.d-OeQYQoUO.d.ts +0 -28
  203. package/dist/_dts/usePanZoom-Bq73pwFe.d.ts +0 -117
  204. package/dist/chunk-2AYGEN57.js +0 -32
  205. package/dist/chunk-2AYGEN57.js.map +0 -1
  206. package/dist/chunk-AWH3SRPW.js.map +0 -1
  207. package/dist/chunk-BVL7Y574.js.map +0 -1
  208. package/dist/chunk-ERFMC6WU.js.map +0 -1
  209. package/dist/chunk-H5VIV7MQ.js.map +0 -1
  210. package/dist/chunk-HFRE4QQV.js.map +0 -1
  211. package/dist/chunk-RS3HRQWU.js.map +0 -1
  212. package/dist/chunk-SBXNQW4G.js +0 -3
  213. package/dist/chunk-TT5C5S6R.js +0 -368
  214. package/dist/chunk-TT5C5S6R.js.map +0 -1
  215. package/dist/chunk-USO6TERP.js.map +0 -1
  216. package/dist/chunk-VQ47KWD5.js.map +0 -1
  217. package/dist/chunk-WUJXJC5O.js +0 -14568
  218. package/dist/chunk-WUJXJC5O.js.map +0 -1
  219. package/dist/chunk-ZORVNOKX.js.map +0 -1
  220. package/src/canvas/usePanZoom.test.ts +0 -244
  221. package/src/canvas/usePanZoom.ts +0 -147
  222. package/src/state/Persistence.stories.tsx +0 -75
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/auto.ts","../src/config/path.ts","../src/config/autoConfig.ts","../src/controls/inDialog.tsx"],"names":["auto","v"],"mappings":";;;;AAOO,IAAM,IAAA,0BAA6B,aAAa;AAKhD,SAAS,OAAO,KAAA,EAA+B;AACpD,EAAA,OAAO,KAAA,KAAU,IAAA;AACnB;;;ACHO,SAAS,SAAS,KAAA,EAAkD;AACzE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,KAAA;AACxD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,cAAA,CAAe,KAAK,CAAA;AACzC,EAAA,OAAO,KAAA,KAAU,MAAA,CAAO,SAAA,IAAa,KAAA,KAAU,IAAA;AACjD;AAIO,SAAS,WAAA,CAAY,QAAiB,IAAA,EAAuB;AAClE,EAAA,IAAI,GAAA,GAAM,MAAA;AACV,EAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,MAAA;AAC3B,IAAA,GAAA,GAAM,IAAI,OAAO,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,GAAA;AACT;AAIO,SAAS,aAAA,CAAc,QAAiB,IAAA,EAAuB;AACpE,EAAA,IAAI,GAAA,GAAM,MAAA;AACV,EAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,IAAA,IAAI,CAAC,QAAA,CAAS,GAAG,KAAK,EAAE,OAAA,IAAW,MAAM,OAAO,KAAA;AAChD,IAAA,GAAA,GAAM,IAAI,OAAO,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,OAAA,CAAQ,IAAA,EAAe,QAAA,EAA6B,KAAA,EAAyB;AACpF,EAAA,MAAM,CAAC,IAAA,EAAM,GAAG,IAAI,CAAA,GAAI,QAAA;AACxB,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,KAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,IAAI,CAAA,GAAI,OAAO,EAAC;AACtC,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,CAAC,IAAI,GAAG,IAAA,CAAK,MAAA,KAAW,CAAA,GAAI,KAAA,GAAQ,QAAQ,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,EAAM,KAAK,CAAA,EAAE;AACzF;AAKO,SAAS,eAAA,CAAmB,MAAA,EAAW,IAAA,EAAc,KAAA,EAAmB;AAC7E,EAAA,OAAO,QAAQ,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,GAAG,KAAK,CAAA;AAC/C;AAUO,SAAS,kBAAA,CAAsB,QAAiB,QAAA,EAAgB;AACrE,EAAA,IAAI,CAAC,QAAA,CAAS,QAAQ,GAAG,OAAQ,MAAA,KAAW,SAAY,QAAA,GAAW,MAAA;AACnE,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,MAAM,CAAA,GAAI,SAAS,EAAC;AAC1C,EAAA,MAAM,GAAA,GAA+B,EAAE,GAAG,IAAA,EAAK;AAC/C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACnD,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,kBAAA,CAAmB,IAAA,CAAK,GAAG,GAAG,KAAK,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,GAAA;AACT;AAIO,SAAS,gBAAA,CAAiB,OAAkB,IAAA,EAAgD;AACjG,EAAA,IAAI,IAAA,GAAyC,KAAA;AAC7C,EAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,EAAG;AACrC,IAAA,IAAI,IAAA,KAAS,MAAA,IAAa,EAAE,UAAA,IAAc,OAAO,OAAO,MAAA;AACxD,IAAA,IAAA,GAAO,IAAA,CAAK,SAAS,OAAO,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,IAAA;AACT;;;ACvEA,SAAS,KAAA,CAAS,MAAgB,GAAA,EAA4B;AAC5D,EAAA,OAAQ,KAAkD,GAAG,CAAA;AAC/D;AAGA,UAAU,MAAA,CAAO,KAAA,EAAkB,EAAA,GAAK,EAAA,EAAmC;AACzE,EAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,KAAA,CAAM,QAAQ,CAAA,EAAG;AACzD,IAAA,MAAM,OAAO,EAAA,KAAO,EAAA,GAAK,MAAM,CAAA,EAAG,EAAE,IAAI,GAAG,CAAA,CAAA;AAC3C,IAAA,IAAI,MAAA,IAAU,KAAA,EAAO,MAAM,CAAC,MAAM,KAAK,CAAA;AAAA,SAClC,OAAO,MAAA,CAAO,KAAA,EAAO,IAAI,CAAA;AAAA,EAChC;AACF;AAIO,SAAS,YAAY,QAAA,EAAoC;AAC9D,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AACjD,IAAA,IAAI,MAAe,IAAA,EAAM,UAAU,CAAA,EAAG,GAAA,CAAI,KAAK,IAAI,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,GAAA;AACT;AAUO,SAAS,iBAAA,CACd,QAAA,EACA,MAAA,EACA,SAAA,EACI;AACJ,EAAA,IAAI,SAAA,CAAU,IAAA,KAAS,CAAA,EAAG,OAAO,MAAA;AAEjC,EAAA,MAAM,SAAA,uBAAgB,GAAA,EAAkC;AACxD,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AACjD,IAAA,IAAI,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA,EAAG,SAAA,CAAU,IAAI,IAAA,EAAM,KAAA,CAAgB,IAAA,EAAM,aAAa,CAAC,CAAA;AAAA,EACnF;AACA,EAAA,IAAI,SAAA,CAAU,IAAA,KAAS,CAAA,EAAG,OAAO,MAAA;AAIjC,EAAA,IAAI,GAAA,GAAM,MAAA;AACV,EAAA,KAAA,MAAW,QAAQ,SAAA,CAAU,IAAA,IAAQ,GAAA,GAAM,UAAA,CAAW,KAAK,IAAI,CAAA;AAE/D,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAE7B,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAAuB;AACnC,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG;AACpB,IAAA,IAAI,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACtB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,IAC7D;AACA,IAAA,MAAM,OAAA,GAAU,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA;AAClC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AACb,MAAA;AAAA,IACF;AACA,IAAA,QAAA,CAAS,IAAI,IAAI,CAAA;AACjB,IAAA,IAAI;AAGF,MAAA,MAAM,QAAQ,OAAA,CAAQ,MAAA,CAAO,MAAM,GAAA,EAAK,SAAA,EAAW,IAAI,CAAC,CAAA;AACxD,MAAA,GAAA,GAAM,eAAA,CAAgB,GAAA,EAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IACxC,CAAA,SAAE;AACA,MAAA,QAAA,CAAS,OAAO,IAAI,CAAA;AAAA,IACtB;AACA,IAAA,IAAA,CAAK,IAAI,IAAI,CAAA;AAAA,EACf,CAAA;AAEA,EAAA,KAAA,MAAW,IAAA,IAAQ,SAAA,CAAU,IAAA,EAAK,OAAQ,IAAI,CAAA;AAC9C,EAAA,OAAO,GAAA;AACT;AAWA,SAAS,MAAA,CACP,IAAA,EACA,SAAA,EACA,IAAA,EACyB;AACzB,EAAA,OAAO,IAAI,KAAA,CAAM,IAAA,EAAK,EAAG;AAAA,IACvB,GAAA,CAAI,SAAS,GAAA,EAAK;AAChB,MAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,SAAA,CAAU,IAAI,GAAG,CAAA,OAAQ,GAAG,CAAA;AAC3D,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAK,EAAG,GAAG,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,GAAA,CAAI,SAAS,GAAA,EAAK;AAChB,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAK,EAAG,GAAG,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,IAAA,EAAM,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,wBAAA,CAAyB,SAAS,GAAA,EAAK;AACrC,MAAA,OAAO,OAAA,CAAQ,wBAAA,CAAyB,IAAA,EAAK,EAAG,GAAG,CAAA;AAAA,IACrD;AAAA,GACD,CAAA;AACH;AAIA,SAAS,UAAA,CAAW,QAAiC,IAAA,EAAuC;AAC1F,EAAA,MAAM,CAAC,IAAA,EAAM,GAAG,IAAI,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AACtC,EAAA,IAAI,IAAA,KAAS,MAAA,IAAa,EAAE,IAAA,IAAQ,SAAS,OAAO,MAAA;AACpD,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,IAAA,MAAM,EAAE,CAAC,IAAI,GAAG,QAAA,EAAU,GAAG,MAAK,GAAI,MAAA;AACtC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAI,CAAA;AACzB,EAAA,IAAI,CAAC,QAAA,CAAS,KAAK,CAAA,EAAG,OAAO,MAAA;AAC7B,EAAA,OAAO,EAAE,GAAG,MAAA,EAAQ,CAAC,IAAI,GAAG,UAAA,CAAW,KAAA,EAAO,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAE;AAChE;AAQO,SAAS,gBAAA,CACd,MAAA,EACA,SAAA,EACA,IAAA,EACA,KAAA,EAC8C;AAC9C,EAAA,IAAI,MAAA,CAAO,KAAK,CAAA,EAAG;AACjB,IAAA,IAAI,UAAU,QAAA,CAAS,IAAI,GAAG,OAAO,EAAE,QAAQ,SAAA,EAAU;AACzD,IAAA,OAAO,EAAE,MAAA,EAAQ,SAAA,EAAW,CAAC,GAAG,SAAA,EAAW,IAAI,CAAA,EAAE;AAAA,EACnD;AACA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,eAAA,CAAgB,MAAA,EAAQ,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C,SAAA,EAAW,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA,GAAI,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,KAAM,IAAI,CAAA,GAAI;AAAA,GAC9E;AACF;AC1IO,SAAS,eAAe,KAAA,EAAwB;AACrD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,KAAA,CAAM,MAAA,KAAW,CAAA,GAAI,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAC9E,EAAA,IAAI,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,IAAI,OAAO,MAAA;AAClE,EAAA,OAAO,OAAO,UAAU,QAAA,GAAW,IAAA,CAAK,UAAU,KAAK,CAAA,GAAI,OAAO,KAAK,CAAA;AACzE;AAQO,SAAS,QAAA,CAAS,IAAA,EAAuB,IAAA,GAAwB,EAAC,EAAoB;AAC3F,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,cAAA;AAChC,EAAA,OAAO,CAAC,GAAA,KAAQ;AACd,IAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAO,IAAA,EAAAA,KAAAA,EAAM,SAAQ,GAAI,GAAA;AACvC,IAAA,MAAM,MAAA,GAAU,KAA8B,MAAA,KAAW,IAAA;AACzD,IAAA,uBACE,GAAA;AAAA,MAACC,EAAA;AAAA,MAAA;AAAA,QACC,OAAO,IAAA,CAAK,IAAA;AAAA,QACZ,aAAa,IAAA,CAAK,WAAA;AAAA,QAClB,OAAA,EAAS,QAAQ,KAAK,CAAA;AAAA,QACtB,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ,OAAA,EAASD,QAAO,MAAA,GAAS,MAAA;AAAA,QACzB,IAAA,EAAMA,KAAAA;AAAA,QACN,YAAA,EAAc,SAAS,MAAA,GAAY,OAAA;AAAA,QAElC,QAAA,EAAA,MAAM,KAAK,GAAG;AAAA;AAAA,KACjB;AAAA,EAEJ,CAAA;AACF","file":"chunk-AWH3SRPW.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 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 function isRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\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","import { DialogRow } from '@weasel-js/ui';\nimport type { ReactNode } from 'react';\nimport type { ControlRenderer } from '../config/types';\n\n/** Options for {@link inDialog}. */\nexport interface InDialogOptions {\n /** What the row's button shows of the value. Defaults to a list joined with\n * commas, or the value itself. */\n summary?: (value: unknown) => ReactNode;\n /** The dialog's heading. Defaults to the row's label. */\n title?: ReactNode;\n}\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"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/builder.ts","../src/config/rules.ts","../src/config/resolve.ts","../src/config/useResolvedConfig.ts"],"names":[],"mappings":"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","file":"chunk-BVL7Y574.js","sourcesContent":["import type { PrefLeaf, PrefNumberFormat, PrefNumberUnit } from '@weasel-js/ui';\nimport { type InDialogOptions, inDialog } from '../controls/inDialog';\nimport { type Auto, isAuto } from './auto';\nimport type {\n Annotations,\n BranchAnnotations,\n BranchOptions,\n ConfigBranch,\n ConfigEntry,\n ConfigNode,\n ConfigOption,\n ConfigSchema,\n ConfigShape,\n ControlRenderer,\n InferConfig,\n NodeOptions,\n SectionOption,\n} from './types';\n\n/** Whether a schema entry is a branch rather than a leaf. */\nexport function isConfigBranch(entry: ConfigEntry): entry is ConfigBranch {\n return 'children' in entry;\n}\n\n/** Shared chaining surface. Every method clones, so a node can be reused as a\n * base for several leaves without one bleeding into the next. */\nexport abstract class BaseNode<T> implements ConfigNode<T> {\n abstract readonly kind: string | null;\n\n // `default` is a reserved word in a parameter position, so the field is\n // declared rather than taken as a parameter property.\n readonly default: T;\n\n constructor(\n defaultValue: T,\n readonly annotations: Readonly<Annotations> = {},\n readonly options: Readonly<NodeOptions> = {},\n ) {\n this.default = defaultValue;\n }\n\n /** Clone into the same subclass. Subclasses with extra constructor\n * arguments override this. */\n protected with(annotations: Annotations, options: NodeOptions): this {\n const Ctor = this.constructor as new (d: T, a: Annotations, o: NodeOptions) => this;\n return new Ctor(this.default, annotations, options);\n }\n\n protected ann(patch: Annotations): this {\n return this.with({ ...this.annotations, ...patch }, this.options);\n }\n\n protected opt(patch: NodeOptions): this {\n return this.with(this.annotations, { ...this.options, ...patch });\n }\n\n /** Human-readable label. Defaults to the key, title-cased. */\n label(name: string): this {\n return this.ann({ name });\n }\n\n /** Longer help text, surfaced as a tooltip on the row label. */\n describe(description: string): this {\n return this.ann({ description });\n }\n\n /** Omit from the panel unless it is asked to show hidden leaves. */\n hidden(): this {\n return this.ann({ hidden: true });\n }\n\n /** Pair with a sibling sharing this id, side-by-side on one row. */\n pair(pair: string): this {\n return this.ann({ pair });\n }\n\n /** Render under a named section heading. `collapsed` opens the section\n * folded, and `layout` and `pack` lay out its rows — say each on any one of\n * the section's leaves. */\n section(label: string, opts: Omit<SectionOption, 'label'> = {}): this {\n return this.opt({ section: { label, ...opts } });\n }\n\n /** Show this row only while the predicate holds. Presentational — the value\n * stays in config and the instrument still reads it. */\n showIf(predicate: (config: Record<string, unknown>) => boolean): this {\n return this.opt({ showIf: predicate });\n }\n\n /** Draw this one row yourself, keeping the kind, default and validation. */\n render(renderer: ControlRenderer): this {\n return this.opt({ render: renderer });\n }\n\n /** Draw this row as a button that opens a dialog, with `body` as the\n * dialog's content — for an editor too big for the row. */\n dialog(body: ControlRenderer, opts?: InDialogOptions): this {\n return this.render(inDialog(body, opts));\n }\n\n /**\n * Compute this leaf's value while it is auto, instead of leaving it\n * `undefined`. The resolver is given the config with every other auto path\n * already resolved.\n */\n auto(resolve: (config: Record<string, unknown>) => T): this {\n return this.opt({ autoResolve: resolve as (c: Record<string, unknown>) => unknown });\n }\n\n /**\n * Start this leaf auto rather than pinned at its default. Takes `auto` and\n * nothing else — the constructor argument already declares the value, and a\n * second way to say it would fight with the first.\n */\n initial(value: Auto): this {\n if (!isAuto(value)) throw new Error('[labkit] .initial() takes `auto` and nothing else');\n return this.opt({ unpinned: true });\n }\n\n /** Never auto. The row's label does not toggle. */\n manual(): this {\n return this.opt({ manual: true });\n }\n}\n\nexport class NumberNode extends BaseNode<number> {\n readonly kind = 'number';\n\n /** Bound the value. A number with both bounds renders as a slider. */\n range(min: number, max: number): this {\n return this.ann({ min, max });\n }\n\n step(step: number): this {\n return this.ann({ step });\n }\n\n /** A display suffix for the value — `'px'`, `'ms'`, `'°'`. Presentation only:\n * it is never parsed, and the stored value stays a plain number. */\n suffix(suffix: string): this {\n return this.ann({ suffix });\n }\n\n /** Show the value in a named format — `'compact'` reads `2.00M`. Presentation\n * only: the stored value stays a plain number, and a typed `2.5m` reads back. */\n format(format: PrefNumberFormat): this {\n return this.ann({ format });\n }\n\n /**\n * Store the value in one unit and edit it in another — radians stored,\n * degrees typed. `min`, `max` and `step` are declared in the stored unit\n * alongside the value, and convert with it. `prefUnit` builds one from a\n * `UnitSystem`.\n */\n unit(unit: PrefNumberUnit): this {\n return this.ann({ unit });\n }\n\n /** Force a slider even without both bounds. */\n slider(): this {\n return this.ann({ control: 'slider' });\n }\n\n /** Force a typed input even when both bounds are set. */\n input(): this {\n return this.ann({ control: 'input' });\n }\n}\n\nexport class BooleanNode extends BaseNode<boolean> {\n readonly kind = 'boolean';\n\n /** Ask for a switch rather than a checkbox. */\n toggle(): this {\n return this.ann({ control: 'switch' });\n }\n}\n\nexport class StringNode extends BaseNode<string> {\n readonly kind = 'string';\n\n placeholder(placeholder: string): this {\n return this.ann({ placeholder });\n }\n\n maxLength(maxLength: number): this {\n return this.ann({ maxLength });\n }\n\n /** Milliseconds to debounce live writes. 0 commits every keystroke. */\n debounce(debounceMs: number): this {\n return this.ann({ debounceMs });\n }\n}\n\nexport class ListNode extends BaseNode<string[]> {\n readonly kind = 'list';\n\n /** Shown in an empty entry. */\n placeholder(placeholder: string): this {\n return this.ann({ placeholder });\n }\n}\n\nexport class ColorNode extends BaseNode<string> {\n readonly kind = 'color';\n\n /** The value carries alpha as `#rrggbbaa`, and the row gets an opacity\n * track beside the swatch. */\n alpha(): this {\n return this.ann({ alpha: true });\n }\n}\n\nexport class EnumNode<T extends string> extends BaseNode<T> {\n readonly kind = 'enum';\n\n /** Render as a segmented control rather than a select. */\n radio(): this {\n return this.ann({ control: 'radio' });\n }\n\n /** Relabel the choices. Named `labels` rather than `options` because\n * `options` is the node's own extras bag. */\n labels(options: readonly ConfigOption[]): this {\n return this.ann({ options });\n }\n}\n\n/** A leaf whose kind the rule chain decides. */\nexport class ValueNode<T> extends BaseNode<T> {\n readonly kind = null;\n}\n\n/** A leaf of a kind labkit does not ship a row for. */\nexport class CustomNode<T> extends BaseNode<T> {\n constructor(\n readonly kind: string,\n defaultValue: T,\n annotations: Readonly<Annotations> = {},\n options: Readonly<NodeOptions> = {},\n ) {\n super(defaultValue, annotations, options);\n }\n\n protected override with(annotations: Annotations, options: NodeOptions): this {\n return new CustomNode(this.kind, this.default, annotations, options) as this;\n }\n}\n\n/**\n * A branch of the schema: its children nest under its key, so a leaf inside\n * one is read and written at a dotted path. Distinct from `.section()`, which\n * puts a heading over sibling leaves and leaves their paths alone.\n */\nexport class GroupNode<S extends ConfigShape> implements ConfigBranch<S> {\n constructor(\n readonly children: S,\n readonly annotations: Readonly<BranchAnnotations> = {},\n readonly options: Readonly<BranchOptions> = {},\n ) {}\n\n private with(annotations: BranchAnnotations, options: BranchOptions): GroupNode<S> {\n return new GroupNode(this.children, annotations, options);\n }\n\n /** Heading for the group's rows. Defaults to the key, title-cased. */\n label(name: string): GroupNode<S> {\n return this.with({ ...this.annotations, name }, this.options);\n }\n\n /** Longer help text. Carried on the resolved `PrefGroup`; both weasel-ui's\n * `PrefsForm` and `ControlPanel` draw it under the heading. */\n describe(description: string): GroupNode<S> {\n return this.with({ ...this.annotations, description }, this.options);\n }\n\n /** Render this whole group under a named section heading. */\n section(label: string, opts: Omit<SectionOption, 'label'> = {}): GroupNode<S> {\n return this.with(this.annotations, { ...this.options, section: { label, ...opts } });\n }\n\n /** Show this group only while the predicate holds. Presentational — every\n * value beneath it stays in config and the instrument still reads it. */\n showIf(predicate: (config: Record<string, unknown>) => boolean): GroupNode<S> {\n return this.with(this.annotations, { ...this.options, showIf: predicate });\n }\n}\n\n/** Every default in a shape, nested the way the shape is. */\nfunction shapeDefaults(shape: ConfigShape): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(shape)) {\n out[key] = isConfigBranch(entry) ? shapeDefaults(entry.children) : entry.default;\n }\n return out;\n}\n\nconst expand = <T extends string>(\n options: readonly T[] | readonly ConfigOption[],\n): readonly ConfigOption[] =>\n options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));\n\n/**\n * Builds an instrument's config: the values, their types, and how each is\n * edited, in one declaration.\n *\n * ```ts\n * const config = f.schema({\n * showGrid: f.boolean(true),\n * cellSize: f.number(20).range(5, 80).step(5).label('Grid spacing'),\n * // Nested: read and written at `grid.color`.\n * grid: f.group({ color: f.color('#ffffff') }),\n * })\n * ```\n */\nexport const f = {\n number: (def: number): NumberNode => new NumberNode(def),\n boolean: (def: boolean): BooleanNode => new BooleanNode(def),\n string: (def: string): StringNode => new StringNode(def),\n color: (def: string): ColorNode => new ColorNode(def),\n /** A list of strings. Its row summarizes the list, and opens a dialog to\n * edit it one entry per field. */\n list: (def: readonly string[]): ListNode => new ListNode([...def]),\n\n /** A fixed set of choices. The default's literal type flows into the config\n * type, so `f.enum('fast', ['fast', 'accurate'])` gives\n * `'fast' | 'accurate'` with no `as const`. */\n enum: <const T extends string>(\n def: T,\n options: readonly T[] | readonly ConfigOption[],\n ): EnumNode<T> => new EnumNode<T>(def, { options: expand(options) }),\n\n /** A leaf with no declared kind: the rule chain decides, which is how a lab\n * states a convention like \"every `*Color` key is a color picker\". */\n value: <T>(def: T): ValueNode<T> => new ValueNode(def),\n\n /** A branch: its children nest under this key, so `grid: f.group({ size })`\n * puts the value at `config.grid.size` and addresses it as `'grid.size'`.\n * Groups nest as deeply as the schema wants. */\n group: <const S extends ConfigShape>(children: S): GroupNode<S> => new GroupNode(children),\n\n /** A leaf of a kind a lab supplies the control for, through `controls`. */\n custom: <T>(\n kind: string,\n def: T,\n validate?: (leaf: PrefLeaf, config: Record<string, unknown>) => string[],\n ): CustomNode<T> => new CustomNode(kind, def, {}, validate ? { validate } : {}),\n\n /** Collect leaves and groups into an instrument's config. */\n schema<S extends ConfigShape>(nodes: S): ConfigSchema<InferConfig<S>> {\n return { nodes, defaults: () => shapeDefaults(nodes) as InferConfig<S> };\n },\n};\n","import type { ConfigRule, ConfigRuleContext, LeafPatch } from './types';\n\n/** `cellSize` -> `Cell size`. Splits camelCase without shattering acronyms. */\nexport function titleCase(key: string): string {\n const words = key\n .replace(/[_-]+/g, ' ')\n .split(/(?<=[a-z0-9])(?=[A-Z])/)\n .join(' ')\n .trim()\n .toLowerCase();\n return words.length === 0 ? words : words[0].toUpperCase() + words.slice(1);\n}\n\n/** An `f.value` leaf takes its kind from the shape of its default. */\nconst kindFromValue: ConfigRule = (ctx) => {\n const t = typeof ctx.default;\n if (t === 'boolean' || t === 'number' || t === 'string') return { kind: t };\n const d = ctx.default;\n if (Array.isArray(d) && d.every((v) => typeof v === 'string')) return { kind: 'list' };\n return null;\n};\n\nconst labelFromKey: ConfigRule = (ctx) => ({ name: titleCase(ctx.key) });\n\n/** A number bounded on both sides is a slider; one bound or none is an input. */\nconst sliderWhenBounded: ConfigRule = (ctx) => {\n if (ctx.leaf.kind !== 'number') return null;\n const bounded = ctx.leaf.min !== undefined && ctx.leaf.max !== undefined;\n return bounded ? { control: 'slider' } : null;\n};\n\n/** `PrefBase.description` is required, so every leaf must end up with one. */\nconst descriptionDefault: ConfigRule = () => ({ description: '' });\n\n/**\n * labkit's own inference, expressed in the same vocabulary a consumer\n * extends. Runs after the consumer's rules, so a lab always wins.\n *\n * If one of these ever needs something a `ConfigRule` cannot express, the\n * seam is too weak — that is the point of writing them this way.\n */\nexport const builtinRules: readonly ConfigRule[] = [\n kindFromValue,\n labelFromKey,\n sliderWhenBounded,\n descriptionDefault,\n];\n\n/**\n * Fold a rule chain into one leaf patch. Gap-filling: a property already\n * settled is never overwritten, so the accumulator seeded with the author's\n * annotations beats every rule, and earlier rules beat later ones.\n */\nexport function applyRules(\n seed: LeafPatch,\n ctx: Omit<ConfigRuleContext, 'leaf'>,\n rules: readonly ConfigRule[],\n): LeafPatch {\n const acc: LeafPatch = { ...seed };\n for (const rule of rules) {\n const patch = rule({ ...ctx, leaf: acc });\n if (patch === null) continue;\n for (const [k, v] of Object.entries(patch)) {\n if (v !== undefined && acc[k as keyof LeafPatch] === undefined) {\n (acc as Record<string, unknown>)[k] = v;\n }\n }\n }\n return acc;\n}\n","import type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\nimport { isConfigBranch } from './builder';\nimport { applyRules, builtinRules, titleCase } from './rules';\nimport type {\n ConfigEntry,\n ConfigRule,\n ConfigSchema,\n ConfigShape,\n ControlRenderer,\n LeafPatch,\n ResolvedConfig,\n SectionSpec,\n} from './types';\n\n/** Drop keys whose value is undefined, so an unset annotation stays a gap the\n * rule chain can fill rather than a settled `undefined`. */\nfunction defined(annotations: Record<string, unknown>): LeafPatch {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(annotations)) if (v !== undefined) out[k] = v;\n return out as LeafPatch;\n}\n\n/** What the walk collects on the side of the `PrefGroup` tree. */\ninterface Sink {\n sections: SectionSpec[];\n showIf: Map<string, (config: Record<string, unknown>) => boolean>;\n renderers: Record<string, ControlRenderer>;\n chain: readonly ConfigRule[];\n}\n\n/**\n * Resolve a schema into the vocabulary weasel-ui renders, running each leaf\n * through the consumer's rules and then labkit's own.\n *\n * The group mirrors the schema's own nesting: an `f.group` becomes a nested\n * `PrefGroup`, so a leaf's dotted path within the tree is the path its value\n * is written at, and both `ControlPanel` and `PrefsForm` address it\n * identically.\n */\nexport function resolveConfigSchema<TC>(\n schema: ConfigSchema<TC>,\n rules: readonly ConfigRule[] = [],\n): ResolvedConfig {\n const sink: Sink = {\n sections: [],\n showIf: new Map(),\n renderers: {},\n chain: [...rules, ...builtinRules],\n };\n const group = resolveShape(schema.nodes, '', '', sink);\n return { group, sections: sink.sections, showIf: sink.showIf, renderers: sink.renderers };\n}\n\n/** A section while it is still being filled. */\ntype OpenSection = Omit<SectionSpec, 'paths'> & { paths: string[] };\n\nfunction resolveShape(shape: ConfigShape, at: string, name: string, sink: Sink): PrefGroup {\n const children: Record<string, PrefLeaf | PrefGroup> = {};\n const sections = new Map<string, OpenSection>();\n\n for (const [key, entry] of Object.entries(shape)) {\n const path = at === '' ? key : `${at}.${key}`;\n children[key] = resolveEntry(entry, key, path, sink);\n\n const { section, showIf: predicate } = entry.options;\n if (section !== undefined) {\n let spec = sections.get(section.label);\n if (!spec) {\n spec = { at, label: section.label, paths: [] };\n sections.set(section.label, spec);\n sink.sections.push(spec);\n }\n spec.paths.push(path);\n // One node saying `collapsed` settles the section, so a schema does not\n // have to repeat it on every node under the heading.\n if (section.collapsed !== undefined) {\n spec.collapsed = (spec.collapsed ?? false) || section.collapsed;\n }\n if (section.layout !== undefined && spec.layout === undefined) spec.layout = section.layout;\n if (section.pack !== undefined && spec.pack === undefined) spec.pack = section.pack;\n }\n if (predicate) sink.showIf.set(path, predicate);\n if (!isConfigBranch(entry) && entry.options.render) sink.renderers[path] = entry.options.render;\n }\n\n return { name, children };\n}\n\nfunction resolveEntry(\n entry: ConfigEntry,\n key: string,\n path: string,\n sink: Sink,\n): PrefLeaf | PrefGroup {\n if (isConfigBranch(entry)) {\n const group = resolveShape(\n entry.children,\n path,\n entry.annotations.name ?? titleCase(key),\n sink,\n );\n return entry.annotations.description === undefined\n ? group\n : { ...group, description: entry.annotations.description };\n }\n if (entry.options.manual && entry.options.unpinned) {\n throw new Error(\n `[labkit] \"${path}\" is both .manual() and .initial(auto) — a field that can never be auto cannot start auto`,\n );\n }\n const seed: LeafPatch = defined({\n ...entry.annotations,\n ...(entry.kind === null ? {} : { kind: entry.kind }),\n });\n const patch = applyRules(seed, { key, path, default: entry.default }, sink.chain);\n const { autoResolve, unpinned, manual } = entry.options;\n return {\n ...patch,\n default: entry.default,\n // Extra keys survive onto the leaf at runtime; `ControlPanel` reads them\n // back with its `extra<T>` helper, the same as `min`, `step` and the rest.\n ...(autoResolve === undefined ? {} : { autoResolve }),\n ...(unpinned === undefined ? {} : { unpinned }),\n ...(manual === undefined ? {} : { manual }),\n } as PrefLeaf;\n}\n","import { useMemo } from 'react';\nimport { resolveAutoConfig } from './autoConfig';\nimport type { ResolvedConfig } from './types';\n\nconst NONE: ReadonlySet<string> = new Set();\n\n/**\n * The config an instrument reads: the stored one with every unpinned path\n * resolved. The single place resolution happens, so `Trial` and\n * `useTrialState` cannot disagree about what an instrument is looking at.\n */\nexport function useResolvedConfig<TC>(\n schema: ResolvedConfig | undefined,\n config: TC,\n autoPaths: readonly string[] | undefined,\n): { config: TC; auto: ReadonlySet<string> } {\n const auto = useMemo(\n () => (autoPaths && autoPaths.length > 0 ? new Set(autoPaths) : NONE),\n [autoPaths],\n );\n const resolvedConfig = useMemo(\n () => (schema ? resolveAutoConfig(schema, config, auto) : config),\n [schema, config, auto],\n );\n return { config: resolvedConfig, auto };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/loupe/canvasLens.ts","../src/loupe/CanvasLoupe.tsx","../src/loupe/DomLoupe.tsx","../src/loupe/LoupeBubble.tsx","../src/loupe/loupeActions.ts","../src/loupe/LoupeGestures.tsx","../src/loupe/useHostSize.ts","../../loupe/src/geometry.ts","../../loupe/src/model.ts","../src/loupe/useLoupe.ts","../src/loupe/TrialLoupe.tsx","../src/loupe/types.ts"],"names":["jsx","useEffect","useRef","useMemo"],"mappings":"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","file":"chunk-ERFMC6WU.js","sourcesContent":["import type { LoupePoint } from '@weasel-js/loupe';\nimport { centerOn } from '../canvas/camera';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport type { CanvasLayerDescriptor } from '../canvas/useLayerScheduler';\nimport { DEFAULT_FRAME, resolveFrame, type WorldFrame, type WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\n\n/** The camera a round lens of `diameter` shows a magnified region through, and\n * the coordinate system it is read in — the instrument's own `WorldSpec`,\n * resolved against the lens rather than the stack. */\nexport interface LensCamera {\n view: ViewTransform;\n frame: WorldFrame;\n}\n\n/**\n * What a lens aimed at `aim` renders the stack's layers through.\n *\n * The lens is its own viewport, so the world spec resolves against its box: an\n * instrument centred on its viewport is centred in the lens too.\n */\nexport function lensCamera(\n aim: LoupePoint,\n outer: ViewTransform,\n outerFrame: WorldFrame,\n factor: number,\n diameter: number,\n worldSpec?: WorldSpec,\n): LensCamera {\n const size = { width: diameter, height: diameter };\n const frame = resolveFrame(worldSpec, size);\n const world = screenToWorld(aim, outer, outerFrame);\n return { view: centerOn(world, outer.zoom * factor, size, frame), frame };\n}\n\n/** A rectangle in a backing store's own device pixels. */\nexport interface SourceRect {\n sx: number;\n sy: number;\n sw: number;\n sh: number;\n}\n\n/**\n * The region a pixel-mode lens copies out of a presented canvas: the `diameter\n * / factor` CSS px around `aim`, in that canvas' backing-store pixels.\n */\nexport function lensSourceRect(\n aim: LoupePoint,\n factor: number,\n diameter: number,\n dpr: number,\n): SourceRect {\n const span = diameter / factor;\n return {\n sx: (aim.x - span / 2) * dpr,\n sy: (aim.y - span / 2) * dpr,\n sw: span * dpr,\n sh: span * dpr,\n };\n}\n\n/**\n * The color a stack presents at a point: the topmost visible layer with\n * anything opaque there, or `null` when every layer is transparent — which is\n * the honest answer for a point showing nothing but the workspace behind.\n */\nexport function sampleStack(\n layers: readonly CanvasLayerDescriptor[],\n canvases: Map<string, HTMLCanvasElement>,\n p: LoupePoint,\n dpr: number,\n): string | null {\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i];\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas) continue;\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) continue;\n const x = Math.floor(p.x * dpr);\n const y = Math.floor(p.y * dpr);\n if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) continue;\n const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;\n if (a === 0) continue;\n return `#${[r, g, b].map((c) => c.toString(16).padStart(2, '0')).join('')}`;\n }\n return null;\n}\n\n/** Redraw the stack into a lens' own canvas. `mode` decides whether the layers\n * are re-run at the lens camera or their presented pixels are enlarged. */\nexport function drawCanvasLens(\n ctx: CanvasRenderingContext2D,\n opts: {\n aim: LoupePoint;\n factor: number;\n diameter: number;\n dpr: number;\n mode: 'vector' | 'pixel';\n outer: ViewTransform;\n outerFrame?: WorldFrame;\n worldSpec?: WorldSpec;\n layers: readonly CanvasLayerDescriptor[];\n canvases: Map<string, HTMLCanvasElement>;\n },\n): void {\n const { aim, factor, diameter, dpr, mode, outer, layers, canvases } = opts;\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, diameter, diameter);\n\n if (mode === 'pixel') {\n const { sx, sy, sw, sh } = lensSourceRect(aim, factor, diameter, dpr);\n ctx.imageSmoothingEnabled = false;\n for (const layer of layers) {\n if (!layer.visible) continue;\n const canvas = canvases.get(layer.id);\n if (!canvas || canvas.width === 0 || canvas.height === 0) continue;\n ctx.drawImage(canvas, sx, sy, sw, sh, 0, 0, diameter, diameter);\n }\n ctx.restore();\n return;\n }\n\n const lens = lensCamera(\n aim,\n outer,\n opts.outerFrame ?? DEFAULT_FRAME,\n factor,\n diameter,\n opts.worldSpec,\n );\n for (const layer of layers) {\n if (!layer.visible) continue;\n ctx.save();\n layer.render(ctx, lens.view, lens.frame);\n ctx.restore();\n }\n ctx.restore();\n}\n","import { useVisibleRaf } from '@weasel-js/core';\nimport type { LoupeMode, LoupePoint } from '@weasel-js/loupe';\nimport { useEffect, useRef } from 'react';\nimport type { CanvasStackSurface } from '../canvas/CanvasStackContext';\nimport type { WorldFrame, WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport { drawCanvasLens } from './canvasLens';\n\n/** Props for `<CanvasLoupe>`. */\nexport interface CanvasLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n diameter: number;\n /** The stack being magnified: its layers, its pixels, and its measured box. */\n surface: CanvasStackSurface;\n view: ViewTransform;\n frame: WorldFrame;\n worldSpec?: WorldSpec;\n}\n\n/**\n * Paints a lens over a `<CanvasStack>` by re-drawing the stack's layers through\n * a zoomed camera — so the magnified content is as sharp as the original, at\n * any factor. `pixel` mode enlarges what the stack presented instead.\n */\nexport function CanvasLoupe({\n aim,\n factor,\n mode,\n diameter,\n surface,\n view,\n frame,\n worldSpec,\n}: CanvasLoupeProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const dpr = surface.size.dpr;\n\n // Whatever the stack redraws every frame, the lens has to redraw too — an\n // instrument that animates from its own loop never re-renders this component.\n const args = { aim, factor, mode, diameter, dpr, view, frame, worldSpec, surface };\n const argsRef = useRef(args);\n argsRef.current = args;\n\n const loop = useVisibleRaf(\n () => {\n loop.request();\n const canvas = canvasRef.current;\n const ctx = canvas?.getContext('2d');\n const canvases = argsRef.current.surface.canvases.current;\n if (!ctx || !canvases) return;\n const a = argsRef.current;\n drawCanvasLens(ctx, {\n aim: a.aim,\n factor: a.factor,\n diameter: a.diameter,\n dpr: a.dpr,\n mode: a.mode,\n outer: a.view,\n outerFrame: a.frame,\n worldSpec: a.worldSpec,\n layers: a.surface.layers,\n canvases,\n });\n },\n { target: canvasRef },\n );\n\n useEffect(() => {\n loop.request();\n return () => loop.cancel();\n }, [loop]);\n\n return (\n <canvas\n ref={canvasRef}\n className=\"lk-loupe__canvas\"\n width={Math.max(1, Math.round(diameter * dpr))}\n height={Math.max(1, Math.round(diameter * dpr))}\n />\n );\n}\n","import type { LoupeMode, LoupePoint } from '@weasel-js/loupe';\nimport type { CSSProperties } from 'react';\nimport { zoomAt } from '../canvas/camera';\nimport type { ViewportSize, WorldFrame } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport type { LoupeRenderArgs } from './types';\n\n/** Props for `<DomLoupe>`. */\nexport interface DomLoupeProps {\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n diameter: number;\n /** The host the instrument draws into, which the stage reproduces. */\n size: ViewportSize;\n /** The trial's own camera. */\n view: ViewTransform;\n frame?: WorldFrame;\n state: unknown;\n config: unknown;\n render: (args: LoupeRenderArgs) => React.ReactNode;\n}\n\n/**\n * Paints a lens over DOM content by asking the instrument to draw itself again\n * at a magnified camera.\n *\n * The stage is a full copy of the host, so the instrument's own layout still\n * holds; the camera is composed about the aimed point, which keeps that point\n * where it already was, and the stage is then slid by `diameter / 2 - aim` to\n * bring it to the middle of the lens.\n */\nexport function DomLoupe({\n aim,\n factor,\n mode,\n diameter,\n size,\n view,\n frame,\n state,\n config,\n render,\n}: DomLoupeProps) {\n const style: CSSProperties = {\n width: `${size.width}px`,\n height: `${size.height}px`,\n transform: `translate(${diameter / 2 - aim.x}px, ${diameter / 2 - aim.y}px)`,\n };\n return (\n <div className=\"lk-loupe__stage\" style={style}>\n {render({\n state,\n config,\n view: zoomAt(view, factor, aim, { frame }),\n factor,\n mode,\n size,\n })}\n </div>\n );\n}\n","import type { LoupePoint } from '@weasel-js/loupe';\nimport type { CSSProperties, ReactNode, RefObject } from 'react';\n\n/** Props for `<LoupeBubble>`. */\nexport interface LoupeBubbleProps {\n /** Where the lens is aimed, in its container's own pixels. */\n aim: LoupePoint;\n diameter: number;\n hostRef?: RefObject<HTMLDivElement | null>;\n children: ReactNode;\n}\n\n/**\n * The lens itself: a circle centred on the aimed point, clipping whatever a\n * painter draws into it.\n *\n * It takes no pointer events, so the pan, the wheel and anything underneath\n * keep working while it is up — and it is `aria-hidden`, since it magnifies\n * content already on the page rather than adding any.\n */\nexport function LoupeBubble({ aim, diameter, hostRef, children }: LoupeBubbleProps) {\n const style: CSSProperties = {\n width: `${diameter}px`,\n height: `${diameter}px`,\n transform: `translate(${aim.x - diameter / 2}px, ${aim.y - diameter / 2}px)`,\n };\n return (\n <div ref={hostRef} className=\"lk-loupe\" style={style} aria-hidden=\"true\">\n {children}\n </div>\n );\n}\n","/**\n * The loupe's two bindable interactions, as `Action` descriptors the gesture\n * dispatcher routes: hold a key to peek, and walk the magnification with the\n * wheel.\n *\n * Free of React so the routing can be tested without a DOM.\n */\nimport type { Action } from '@weasel-js/core';\n\n/** Canonical id of the hold-to-peek action. */\nexport const LOUPE_PEEK_ID = 'loupe.peek';\n/** Canonical id of the wheel-magnify action. */\nexport const LOUPE_MAGNIFY_ID = 'loupe.magnify';\n\n/** How fast the wheel walks the magnification. Gentler than the pan-zoom\n * wheel: the lens' whole range is one order of magnitude. */\nexport const WHEEL_RATE = 0.002;\n\n/** What the actions do to a live loupe. Every member is read through the\n * object on each invocation, so one stable instance serves the life of the\n * registration. */\nexport interface LoupeInputApi {\n /** Whether the lens is up. The wheel belongs to the loupe only while it is;\n * otherwise `loupe.magnify` declines and the dispatcher leaves the event\n * unhandled, which is what hands it back to the lab's own pan/zoom. */\n shown: () => boolean;\n /** Raise or drop the hold-to-peek flag. */\n setPeeking: (on: boolean) => void;\n /** Multiply the magnification by one wheel notch of `deltaY`. */\n magnifyBy: (deltaY: number) => void;\n}\n\n/**\n * Build the loupe's actions. `peekKey` is a `KeyboardEvent.key`; passing\n * `null` omits `loupe.peek` entirely rather than registering a binding no key\n * can match.\n */\nexport function createLoupeActions(\n input: LoupeInputApi,\n peekKey: string | null,\n): readonly Action[] {\n const magnify: Action = {\n id: LOUPE_MAGNIFY_ID,\n label: 'Magnify (loupe)',\n group: 'loupe',\n // Every modifier optional: the lens claims the wheel whenever it is up,\n // which is what the hand-rolled capture-phase listener did. A bare spec\n // would forbid modifiers and hand Cmd+wheel back to the lab mid-peek.\n defaultBinding: [\n {\n spec: {\n kind: 'wheel',\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n enabled: () => (input.shown() ? true : 'not-applicable'),\n invoker: {\n timing: 'immediate',\n run(_deps, params) {\n input.magnifyBy((params?.deltaY as number | undefined) ?? 0);\n },\n },\n };\n\n if (peekKey === null) return [magnify];\n\n const peek: Action = {\n id: LOUPE_PEEK_ID,\n label: 'Peek (loupe)',\n group: 'loupe',\n // Hotkey scope: peeking must beat whatever the lab's active tool binds to\n // the same key, the way every other held-key trigger does.\n scope: 'hotkey',\n // Every modifier optional because the peek key may BE one: the keydown\n // that carries `Alt` — the default — also reports `altKey: true`, and the\n // matcher forbids any modifier a spec does not name.\n defaultBinding: [\n {\n spec: {\n kind: 'key-held',\n key: peekKey,\n mods: { alt: 'optional', ctrl: 'optional', meta: 'optional', shift: 'optional' },\n },\n opts: {},\n },\n ],\n invoker: {\n timing: 'ongoing',\n start() {\n input.setPeeking(true);\n return { onEnd: () => input.setPeeking(false) };\n },\n },\n };\n return [peek, magnify];\n}\n","/**\n * Mounts the gesture dispatcher on a loupe's host and registers the loupe's\n * actions on it, so the peek key and the wheel route the way every other\n * weasel binding does.\n *\n * Three of the dispatcher's four element channels are off. Only `wheel` is\n * wanted here; `contextMenu` suppresses the native menu unconditionally and\n * `ingest` makes the host a file-drop target, neither of which a lab asked\n * for by turning a magnifier on.\n */\nimport {\n type ActionsRegistry,\n type Tool,\n useActionsRegistry,\n useGestureDispatcher,\n} from '@weasel-js/core';\nimport { type RefObject, useEffect, useMemo } from 'react';\nimport { createLoupeActions, type LoupeInputApi } from './loupeActions';\n\n/** Props for `<LoupeGestures>`. */\nexport interface LoupeGesturesProps {\n /** The element the dispatcher listens on — the same one the lens tracks. */\n hostRef: RefObject<HTMLElement | null>;\n input: LoupeInputApi;\n /** `KeyboardEvent.key` for hold-to-peek, or `null` for no peek binding. */\n peekKey: string | null;\n}\n\nconst NO_TOOLS: ReadonlyMap<string, Tool> = new Map();\n\nconst CHANNELS = { pointer: false, contextMenu: false, ingest: false } as const;\n\nfunction LoupeDispatch({\n hostRef,\n input,\n peekKey,\n registry,\n}: LoupeGesturesProps & { registry: ActionsRegistry }) {\n const actions = useMemo(() => createLoupeActions(input, peekKey), [input, peekKey]);\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 useGestureDispatcher({\n canvasRef: hostRef,\n actions: registry,\n toolsById: NO_TOOLS,\n channels: CHANNELS,\n });\n\n return null;\n}\n\n/**\n * The loupe's input, routed. Render it inside a `<WeaselProvider isolate>` —\n * with no registry in scope it renders nothing rather than registering\n * actions that could never fire.\n */\nexport function LoupeGestures(props: LoupeGesturesProps) {\n const registry = useActionsRegistry();\n if (!registry) return null;\n return <LoupeDispatch {...props} registry={registry} />;\n}\n","import { type RefObject, useEffect, useState } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\n\nconst ZERO: ViewportSize = { width: 0, height: 0 };\n\n/** An element's CSS-pixel box, kept current. `{0, 0}` until it is measured, and\n * wherever `ResizeObserver` is absent. */\nexport function useHostSize(ref: RefObject<HTMLElement | null>): ViewportSize {\n const [size, setSize] = useState<ViewportSize>(ZERO);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const update = (): void => {\n const rect = el.getBoundingClientRect();\n setSize((prev) =>\n prev.width === rect.width && prev.height === rect.height\n ? prev\n : { width: rect.width, height: rect.height },\n );\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, [ref]);\n\n return size;\n}\n","import type { View } from '@weasel-js/core';\n\n/** A point on the magnified surface, in its own CSS pixels. */\nexport interface LoupePoint {\n x: number;\n y: number;\n}\n\n/** The lens' rectangle on that surface. */\nexport interface LoupeRect extends LoupePoint {\n w: number;\n h: number;\n}\n\n/**\n * The inner `View` a loupe renders its content through: the outer view's\n * magnification times `factor`, positioned so `target` sits at the center of\n * a viewport the size of `rect`.\n */\nexport function loupeInnerView(\n target: LoupePoint,\n outer: View,\n rect: LoupeRect,\n factor: number,\n): View {\n const scale = { x: outer.scale.x * factor, y: outer.scale.y * factor };\n return {\n x: target.x - rect.w / 2 / scale.x,\n y: target.y - rect.h / 2 / scale.y,\n scale,\n };\n}\n\n/**\n * Where on the outer surface a point inside the lens is looking, in\n * screen-space CSS px.\n *\n * The inverse of {@link loupeInnerView}: the lens centers `aim` in `rect` and\n * magnifies by `factor`, and the outer view's own scale cancels out of the\n * round trip — so this needs no `View`.\n */\nexport function loupeSourcePoint(\n p: LoupePoint,\n rect: LoupeRect,\n aim: LoupePoint,\n factor: number,\n): LoupePoint {\n return {\n x: aim.x + (p.x - (rect.x + rect.w / 2)) / factor,\n y: aim.y + (p.y - (rect.y + rect.h / 2)) / factor,\n };\n}\n","import { normalizeZoom } from '@weasel-js/core';\nimport { type LoupePoint, type LoupeRect, loupeSourcePoint } from './geometry';\n\n/** How a loupe magnifies. `'vector'` re-renders the source through a zoomed-in\n * view, so content stays sharp at any factor; `'pixel'` blows up the actual\n * pixels the surface presented. */\nexport type LoupeMode = 'vector' | 'pixel';\n\n/**\n * What a loupe needs from the surface it magnifies. A painter implements it,\n * and the model asks nothing about how the lens is drawn — only where it is,\n * what colour is under a point, and whether anyone can still see it.\n */\nexport interface LoupeSurface {\n /** The lens' rectangle, or `null` while it has none. */\n lens(): LoupeRect | null;\n /**\n * Does the lens itself cover this point? A stationary lens does over its own\n * frame, which is what the freeze rule below is for; a lens that follows the\n * pointer never covers it and answers `false`.\n */\n covers(p: LoupePoint): boolean;\n /** Hex colour at a surface point, or `null` when the surface cannot say. */\n sample(p: LoupePoint): string | null;\n /** Is the lens off screen? Aims are ignored while it is. */\n hidden(): boolean;\n /** Is the lens gone for good? The model tears itself down when it is. */\n gone(): boolean;\n /** Something the painter must redraw for has changed. */\n changed(): void;\n /**\n * Run `fn` after each frame the surface lands; returns an unsubscribe.\n * Implement it when `sample` reads pixels that only show an aim once a\n * frame has painted — a framebuffer read back. The model then samples the\n * aim on the next landed frame, so `color` settles a frame after the aim.\n * Omit it when `sample` can answer for a fresh aim right away.\n */\n subscribeFrame?(fn: () => void): () => void;\n}\n\n/** Options for {@link createLoupeModel}. */\nexport interface LoupeModelOptions {\n surface: LoupeSurface;\n mode?: LoupeMode;\n /** Magnification. Default 8. Always positive and finite: a factor that is\n * not becomes `ZOOM_FLOOR`, the same rule a view's zoom follows. */\n factor?: number;\n /** Bounds `setFactor` clamps to. Unset means bounded only by that rule. */\n minFactor?: number;\n maxFactor?: number;\n /** Called with the hex colour under the aim point whenever it changes. */\n onColorChange?: (hex: string) => void;\n /** Called when a pick lands — an eyedropper on the magnified surface. Where\n * the colour goes is the consumer's business. */\n onPick?: (hex: string) => void;\n /** Called when the model tears itself down because the surface reported the\n * lens gone, so the painter can drop what it was holding. */\n onDispose?: () => void;\n}\n\n/** Where a loupe is aimed, how far it magnifies, and what colour it is over. */\nexport interface LoupeModel {\n readonly mode: LoupeMode;\n readonly factor: number;\n /** Last aimed point, in the surface's CSS px. */\n readonly aim: LoupePoint;\n /** Hex colour under the aim point. `null` until something answers. */\n readonly color: string | null;\n setMode(mode: LoupeMode): void;\n setFactor(factor: number): void;\n /** Aim at a surface point. Ignored while the lens covers it, is hidden, or\n * the model is disposed. */\n aimAt(p: LoupePoint): void;\n /** Sample what the lens shows at `p`, a point inside it, and report that to\n * `onPick`. Omit `p` to pick at the aim point. Leaves the aim, and `color`,\n * alone. */\n pick(p?: LoupePoint): string | null;\n dispose(): void;\n}\n\n/**\n * Build the loupe's model over a surface. It holds the state a magnifier has —\n * aim, factor, mode, colour — and none of the drawing.\n */\nexport function createLoupeModel(opts: LoupeModelOptions): LoupeModel {\n const { surface } = opts;\n let mode: LoupeMode = opts.mode ?? 'vector';\n let factor = normalizeZoom(opts.factor ?? 8);\n let aim: LoupePoint = { x: 0, y: 0 };\n let color: string | null = null;\n let disposed = false;\n let aimUnsampled = false;\n\n const clamp = (n: number): number =>\n normalizeZoom(Math.min(opts.maxFactor ?? Number.POSITIVE_INFINITY,\n Math.max(opts.minFactor ?? Number.NEGATIVE_INFINITY, n)));\n\n const sampleColor = () => {\n const hex = surface.sample(aim);\n if (hex === null || hex === color) return;\n color = hex;\n opts.onColorChange?.(hex);\n };\n\n const unsubscribeFrame = surface.subscribeFrame?.(() => {\n if (!aimUnsampled) return;\n aimUnsampled = false;\n sampleColor();\n });\n\n const teardown = () => {\n if (disposed) return;\n disposed = true;\n unsubscribeFrame?.();\n opts.onDispose?.();\n };\n\n return {\n get mode() { return mode; },\n get factor() { return factor; },\n get aim() { return aim; },\n get color() { return color; },\n\n setMode(next) {\n if (disposed || next === mode) return;\n mode = next;\n surface.changed();\n },\n\n setFactor(next) {\n if (disposed) return;\n factor = clamp(next);\n surface.changed();\n },\n\n aimAt(p) {\n if (disposed) return;\n // A lens can be taken away by whatever owns it, without coming back\n // through `dispose`. Follow it down rather than keep sampling for a\n // magnifier nobody can see.\n if (surface.gone()) { teardown(); return; }\n if (surface.hidden()) return;\n if (surface.covers(p)) return;\n aim = p;\n if (unsubscribeFrame) aimUnsampled = true;\n else sampleColor();\n surface.changed();\n },\n\n pick(p) {\n if (disposed) return null;\n let at = aim;\n if (p) {\n const rect = surface.lens();\n if (!rect) return null;\n at = loupeSourcePoint(p, rect, aim, factor);\n // The lens is part of the picture the surface presents. A point near\n // its frame maps back underneath it, and sampling there reports the\n // lens' own chrome as artwork.\n if (surface.covers(at)) return null;\n }\n const hex = surface.sample(at);\n if (hex !== null) opts.onPick?.(hex);\n return hex;\n },\n\n dispose: teardown,\n };\n}\n","import {\n createLoupeModel,\n type LoupeMode,\n type LoupeModel,\n type LoupePoint,\n} from '@weasel-js/loupe';\nimport { type RefObject, useCallback, useEffect, useReducer, useRef } from 'react';\nimport type { LoupeInputApi } from './loupeActions';\nimport { WHEEL_RATE } from './loupeActions';\nimport type { ResolvedLoupe } from './types';\n\n/** Options for {@link useLoupe}. */\nexport interface UseLoupeOptions {\n capability: ResolvedLoupe;\n /** The element the lens tracks the pointer across. */\n hostRef: RefObject<HTMLElement | null>;\n /** Whether the loupe is turned on. Hold-to-peek shows it regardless. */\n enabled: boolean;\n /** Hex color at a host point. Omitted, the loupe reports no color — which\n * is the honest answer for a surface with no pixels to read. */\n sample?: (p: LoupePoint) => string | null;\n}\n\n/** A loupe as a React view reads it. */\nexport interface LoupeState {\n /** Whether the lens should be drawn. */\n visible: boolean;\n /** Where it is aimed, in the host's own pixels. */\n aim: LoupePoint;\n factor: number;\n mode: LoupeMode;\n color: string | null;\n setMode: (mode: LoupeMode) => void;\n setFactor: (factor: number) => void;\n /** Sample what the lens shows at a point inside it. */\n pick: (p?: LoupePoint) => string | null;\n /** What `<LoupeGestures>` drives the lens through. Stable for the life of\n * the hook, so registering the actions on it does not churn. */\n input: LoupeInputApi;\n}\n\n/**\n * Binds `@weasel-js/loupe`'s model to a host element and tracks the pointer\n * across it.\n *\n * The peek key and the wheel are not here: they are `loupe.peek` and\n * `loupe.magnify`, routed through the gesture dispatcher that\n * `<LoupeGestures>` mounts on the same host. Aiming stays a plain listener\n * because a hover is not a gesture the grammar names — `GESTURE_DESCRIPTORS`\n * has no continuous-motion entry, and inventing one to carry the lens' aim\n * would be an input taxonomy change, not a loupe change.\n */\nexport function useLoupe({ capability, hostRef, enabled, sample }: UseLoupeOptions): LoupeState {\n const [, bump] = useReducer((n: number) => n + 1, 0);\n\n const overRef = useRef(false);\n const peekingRef = useRef(false);\n const enabledRef = useRef(enabled);\n enabledRef.current = enabled;\n const sampleRef = useRef(sample);\n sampleRef.current = sample;\n const onColorChangeRef = useRef(capability.onColorChange);\n onColorChangeRef.current = capability.onColorChange;\n\n // Reads nothing but refs, so it is stable and an effect may depend on it.\n const shown = useCallback(\n (): boolean => overRef.current && (enabledRef.current || peekingRef.current),\n [],\n );\n\n const modelRef = useRef<LoupeModel | null>(null);\n if (modelRef.current === null) {\n modelRef.current = createLoupeModel({\n mode: capability.mode,\n factor: capability.factor,\n minFactor: capability.minFactor,\n maxFactor: capability.maxFactor,\n onColorChange: (hex) => onColorChangeRef.current?.(hex),\n surface: {\n lens: () => {\n const d = diameterRef.current;\n const { x, y } = modelRef.current?.aim ?? { x: 0, y: 0 };\n return { x: x - d / 2, y: y - d / 2, w: d, h: d };\n },\n // The lens follows the pointer and is painted over the host rather than\n // into it, so it is never part of the picture being magnified.\n covers: () => false,\n sample: (p) => sampleRef.current?.(p) ?? null,\n hidden: () => !shown(),\n gone: () => goneRef.current,\n changed: bump,\n },\n });\n }\n const model = modelRef.current;\n\n const diameterRef = useRef(capability.diameter);\n diameterRef.current = capability.diameter;\n const goneRef = useRef(false);\n\n // The model holds no resources, and `dispose` is one-way — so unmounting only\n // reports the lens gone. Disposing here instead leaves React's mount / unmount\n // / remount in StrictMode with a permanently dead model that silently ignores\n // every aim.\n useEffect(() => {\n goneRef.current = false;\n return () => {\n goneRef.current = true;\n };\n }, []);\n\n // Turning the loupe off with the pointer still inside must put the lens away,\n // and the model only reconsiders on an aim.\n useEffect(() => {\n if (!enabled && !peekingRef.current) bump();\n }, [enabled]);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n\n const onPointerMove = (e: PointerEvent): void => {\n overRef.current = true;\n const rect = host.getBoundingClientRect();\n model.aimAt({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n if (!shown()) return;\n bump();\n };\n const onPointerLeave = (): void => {\n overRef.current = false;\n bump();\n };\n\n host.addEventListener('pointermove', onPointerMove);\n host.addEventListener('pointerleave', onPointerLeave);\n return () => {\n host.removeEventListener('pointermove', onPointerMove);\n host.removeEventListener('pointerleave', onPointerLeave);\n };\n }, [hostRef, model, shown]);\n\n const inputRef = useRef<LoupeInputApi | null>(null);\n if (inputRef.current === null) {\n inputRef.current = {\n shown,\n setPeeking: (on) => {\n if (peekingRef.current === on) return;\n peekingRef.current = on;\n bump();\n },\n magnifyBy: (deltaY) => {\n const m = modelRef.current;\n if (m) m.setFactor(m.factor * Math.exp(-deltaY * WHEEL_RATE));\n },\n };\n }\n\n return {\n visible: shown(),\n aim: model.aim,\n factor: model.factor,\n mode: model.mode,\n color: model.color,\n setMode: model.setMode,\n setFactor: model.setFactor,\n pick: model.pick,\n input: inputRef.current,\n };\n}\n","import { WeaselProvider } from '@weasel-js/core';\nimport { type RefObject, useContext, useMemo } from 'react';\nimport { CanvasStackContext } from '../canvas/CanvasStackContext';\nimport type { WorldSpec } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\nimport { CanvasLoupe } from './CanvasLoupe';\nimport { sampleStack } from './canvasLens';\nimport { DomLoupe } from './DomLoupe';\nimport { LoupeBubble } from './LoupeBubble';\nimport { LoupeGestures } from './LoupeGestures';\nimport type { ResolvedLoupe } from './types';\nimport { useHostSize } from './useHostSize';\nimport { useLoupe } from './useLoupe';\n\n/** Props for `<TrialLoupe>`. */\nexport interface TrialLoupeProps {\n capability: ResolvedLoupe;\n /** Whether the trial's loupe is turned on. Hold-to-peek shows it anyway. */\n enabled: boolean;\n state: unknown;\n config: unknown;\n /** The trial's own camera. */\n view: ViewTransform;\n worldSpec?: WorldSpec;\n /** The element the lens tracks. A loupe mounted inside a `<CanvasStack>`\n * takes the stack's own element instead, and this goes unused. */\n hostRef?: RefObject<HTMLElement | null>;\n}\n\n/** Stable stand-in, so a loupe with nothing to track does not re-bind its\n * listeners on every render. */\nconst NO_HOST: RefObject<HTMLElement | null> = { current: null };\n\n/**\n * A trial's loupe, painted by whichever painter suits its content: the canvas\n * stack it is mounted inside, or the instrument's own `render` at a magnified\n * camera.\n */\nexport function TrialLoupe({\n capability,\n enabled,\n state,\n config,\n view,\n worldSpec,\n hostRef,\n}: TrialLoupeProps) {\n const stack = useContext(CanvasStackContext);\n const surface = capability.render ? undefined : stack?.surface;\n const host = surface?.element ?? hostRef ?? NO_HOST;\n\n const sample = useMemo(() => {\n if (!surface) return undefined;\n return (p: { x: number; y: number }): string | null => {\n const canvases = surface.canvases.current;\n return canvases ? sampleStack(surface.layers, canvases, p, surface.size.dpr) : null;\n };\n }, [surface]);\n\n const loupe = useLoupe({ capability, hostRef: host, enabled, sample });\n const measured = useHostSize(host);\n const size = surface?.size ?? measured;\n\n // The gestures mount outside the visibility gate: hold-to-peek is what\n // raises a lens that is down, so its binding has to be live while it is.\n // One isolated scope per loupe, for the reason `<AnnotationOverlay>` gives\n // — an actions registry holds one dispatcher.\n const gestures = (\n <WeaselProvider isolate>\n <LoupeGestures hostRef={host} input={loupe.input} peekKey={capability.peekKey ?? null} />\n </WeaselProvider>\n );\n\n if (!loupe.visible) return gestures;\n\n return (\n <>\n {gestures}\n <LoupeBubble aim={loupe.aim} diameter={capability.diameter}>\n {capability.render ? (\n <DomLoupe\n aim={loupe.aim}\n factor={loupe.factor}\n mode={loupe.mode}\n diameter={capability.diameter}\n size={size}\n view={view}\n frame={stack?.frame}\n state={state}\n config={config}\n render={capability.render}\n />\n ) : surface && stack ? (\n <CanvasLoupe\n aim={loupe.aim}\n factor={loupe.factor}\n mode={loupe.mode}\n diameter={capability.diameter}\n surface={surface}\n view={stack.view}\n frame={stack.frame}\n worldSpec={worldSpec}\n />\n ) : null}\n </LoupeBubble>\n </>\n );\n}\n","import type { LoupeMode } from '@weasel-js/loupe';\nimport type { ReactNode } from 'react';\nimport type { ViewportSize } from '../canvas/worldSpec';\nimport type { ViewTransform } from '../instrument/types';\n\n/** What a DOM instrument's loupe `render` is handed: the same data its own\n * `render` gets, and the camera to draw it through. */\nexport interface LoupeRenderArgs<TS = unknown, TC = unknown> {\n state: TS;\n config: TC;\n /** The trial's own camera composed with the magnification, about the aimed\n * point — so drawing the same content through it magnifies in place. */\n view: ViewTransform;\n /** The magnification on its own, for whatever must not scale with the\n * camera. */\n factor: number;\n mode: LoupeMode;\n /** The size of the viewport `view` is written for: the trial's content well,\n * not the lens. The lens shows a circle cut out of it. */\n size: ViewportSize;\n}\n\n/**\n * Declares that an instrument can be magnified.\n *\n * With no `render`, the loupe re-draws the instrument's canvas layers through a\n * zoomed camera, so it stays sharp at any factor. An instrument whose content is\n * DOM supplies `render` instead: given a camera, draw me again.\n */\nexport interface LoupeCapability<TS = unknown, TC = unknown> {\n render?: (args: LoupeRenderArgs<TS, TC>) => ReactNode;\n /** Opening magnification, clamped to the bounds below. Default 6. */\n factor?: number;\n /** What the wheel clamps to. Defaults 2 and 32. */\n minFactor?: number;\n maxFactor?: number;\n /** `'vector'` (default) re-renders the content magnified; `'pixel'` blows up\n * the pixels the instrument presented. A `render` loupe is always vector —\n * DOM has no framebuffer to enlarge. */\n mode?: LoupeMode;\n /** Lens diameter in CSS px. Default 200. */\n diameter?: number;\n /** Held for a momentary peek while the loupe is off. Default `'Alt'`; `null`\n * turns hold-to-peek off. Matched against `KeyboardEvent.key`. */\n peekKey?: string | null;\n /** Called with the color under the aim, wherever the surface can say. The\n * canvas painter reads it back; a DOM loupe has no pixels to sample. */\n onColorChange?: (hex: string) => void;\n}\n\n/** An instrument's loupe declaration. `true` takes every default. */\nexport type LoupeDeclaration<TS = unknown, TC = unknown> = true | LoupeCapability<TS, TC>;\n\n/** A {@link LoupeCapability} with every default filled in. */\nexport interface ResolvedLoupe<TS = unknown, TC = unknown> {\n render?: (args: LoupeRenderArgs<TS, TC>) => ReactNode;\n onColorChange?: (hex: string) => void;\n factor: number;\n minFactor: number;\n maxFactor: number;\n mode: LoupeMode;\n diameter: number;\n peekKey: string | null;\n}\n\nexport const LOUPE_DEFAULTS = {\n factor: 6,\n minFactor: 2,\n maxFactor: 32,\n mode: 'vector',\n diameter: 200,\n peekKey: 'Alt',\n} as const satisfies Omit<ResolvedLoupe, 'render' | 'onColorChange'>;\n\nexport function resolveLoupe<TS, TC>(declared: LoupeDeclaration<TS, TC>): ResolvedLoupe<TS, TC> {\n const cap = declared === true ? {} : declared;\n const minFactor = cap.minFactor ?? LOUPE_DEFAULTS.minFactor;\n const maxFactor = cap.maxFactor ?? LOUPE_DEFAULTS.maxFactor;\n return {\n render: cap.render,\n onColorChange: cap.onColorChange,\n minFactor,\n maxFactor,\n factor: Math.min(maxFactor, Math.max(minFactor, cap.factor ?? LOUPE_DEFAULTS.factor)),\n diameter: cap.diameter ?? LOUPE_DEFAULTS.diameter,\n peekKey: cap.peekKey === undefined ? LOUPE_DEFAULTS.peekKey : cap.peekKey,\n // A DOM loupe has no framebuffer, so `pixel` would have nothing to enlarge.\n mode: cap.render ? 'vector' : (cap.mode ?? LOUPE_DEFAULTS.mode),\n };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/annotations/AnnotationsContext.ts","../src/annotations/ExportMenu.tsx","../src/annotations/MarkList.tsx","../src/chrome/builtins.tsx","../src/tools/labTool.ts","../src/chrome/merge.ts","../src/chrome/regions/SidebarRegion.tsx","../src/chrome/regions/StatusRegion.tsx","../src/chrome/regions/ToolbarRegion.tsx","../src/chrome/LabChrome.tsx","../src/chrome/regions/PaletteRegion.tsx","../src/chrome/regions/TitleBarRegion.tsx","../src/chrome/regions/ViewportRegion.tsx"],"names":["g","jsx","jsxs","u","d","n","useContext","o","renderEntry"],"mappings":"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","file":"chunk-H5VIV7MQ.js","sourcesContent":["import { createContext, useCallback, useContext, useRef, useSyncExternalStore } from 'react';\nimport type { AnnotationsApi } from './types';\n\n/** Null in a trial whose instrument declares no `annotations`. */\nexport const AnnotationsContext = createContext<AnnotationsApi | null>(null);\n\n/** Re-render the caller whenever any of the store's scenes changes.\n *\n * The API is a stable facade over mutable scenes, so nothing about its\n * identity says a mark was added — a component reading `query()` without this\n * renders one answer and never revises it. */\nfunction useMarkVersion(api: AnnotationsApi | null): void {\n const version = useRef(0);\n useSyncExternalStore(\n useCallback(\n (fn: () => void) =>\n api?.subscribe(() => {\n version.current += 1;\n fn();\n }) ?? (() => {}),\n [api],\n ),\n useCallback(() => version.current, []),\n () => 0,\n );\n}\n\n/** The marks on this trial's targets. Reached through a hook rather than the\n * chrome context, which carries no instrument state — a sidebar panel listing\n * marks pulls it the way `useTrialState()` does. Throws outside a trial whose\n * instrument declares the capability. */\nexport function useAnnotations(): AnnotationsApi {\n const api = useContext(AnnotationsContext);\n useMarkVersion(api);\n if (!api) {\n throw new Error(\n '[labkit] useAnnotations requires an instrument that declares the `annotations` capability',\n );\n }\n return api;\n}\n\n/** The marks on this trial's targets, or null. For chrome that renders in\n * every trial and does something else where there are none. */\nexport function useAnnotationsOptional(): AnnotationsApi | null {\n const api = useContext(AnnotationsContext);\n useMarkVersion(api);\n return api;\n}\n","import { ExportIcon } from '@weasel-js/ui';\nimport { useId, useState } from 'react';\nimport { Callout } from '../passthrough/weasel-ui';\nimport { Toolbar } from '../primitives/Toolbar';\nimport { useAnnotationsOptional } from './AnnotationsContext';\nimport type { CaptureResult } from './types';\n\nconst SCALES = [1, 2, 4] as const;\nconst FORMATS = [\n { id: 'png', label: 'PNG' },\n { id: 'svg', label: 'SVG' },\n] as const;\n\ntype Format = (typeof FORMATS)[number]['id'];\n\nfunction fileName(result: CaptureResult): string {\n return `${result.target.replace(/[^a-z0-9._-]+/gi, '-')}.${result.format}`;\n}\n\n/** A blob the person asked for, handed to the browser's own save flow. The\n * object URL is revoked on the next turn — revoking it synchronously races\n * the navigation the click starts. */\nfunction download(result: CaptureResult): void {\n const url = URL.createObjectURL(result.blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = fileName(result);\n a.click();\n setTimeout(() => URL.revokeObjectURL(url), 0);\n}\n\n/** PNG goes to the clipboard as an image. SVG goes as text: `image/svg+xml`\n * needs Chromium's `web ` prefix and nothing else reads it, while the markup\n * is what a person pasting a vector export actually wants. */\nasync function copy(result: CaptureResult): Promise<void> {\n if (result.format === 'svg') {\n await navigator.clipboard.writeText(await result.blob.text());\n return;\n }\n await navigator.clipboard.write([new ClipboardItem({ 'image/png': result.blob })]);\n}\n\n/**\n * Export a target's picture with its marks on it.\n *\n * A panel rather than a button because a mark belongs to a target: with more\n * than one pane, \"export\" on its own does not say what.\n *\n * Reads the store through the hook the way `<MarkList>` does — the chrome\n * context carries no instrument state and is not the route to it.\n */\nexport function ExportMenu() {\n const marks = useAnnotationsOptional();\n const [anchor, setAnchor] = useState<HTMLSpanElement | null>(null);\n const [open, setOpen] = useState(false);\n const [target, setTarget] = useState<string | null>(null);\n const [format, setFormat] = useState<Format>('png');\n const [scale, setScale] = useState<number>(2);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const titleId = useId();\n\n if (!marks) return null;\n const targets = marks.targets();\n const chosen = target ?? targets[0]?.id ?? null;\n\n const run = async (then: (r: CaptureResult) => void | Promise<void>): Promise<void> => {\n if (!chosen) return;\n setBusy(true);\n setError(null);\n try {\n await then(await marks.capture(chosen, { format, scale }));\n setOpen(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <span className=\"lk-export\" ref={setAnchor}>\n <Toolbar.Button\n iconOnly\n pressed={open}\n aria-label=\"Export\"\n title=\"Export\"\n onClick={() => setOpen((was) => !was)}\n >\n <ExportIcon size={16} />\n </Toolbar.Button>\n <Callout\n triggerRef={{ current: anchor }}\n isOpen={open}\n onOpenChange={setOpen}\n onDismiss={() => setOpen(false)}\n placement=\"bottom end\"\n aria-labelledby={titleId}\n >\n <div className=\"lk-export__panel\">\n <span className=\"lk-export__title\" id={titleId}>\n Export\n </span>\n\n <label className=\"lk-export__row\">\n <span>Target</span>\n {/* Native controls: role, name and keyboard operability for free,\n and a five-control panel is not the place to rebuild them. */}\n <select\n aria-label=\"Target\"\n value={chosen ?? ''}\n onChange={(e) => setTarget(e.target.value)}\n >\n {targets.map((t) => (\n <option key={t.id} value={t.id}>\n {t.id}\n </option>\n ))}\n </select>\n </label>\n\n {/* A <fieldset>/<legend> cannot do this: a legend is outside its\n fieldset's grid formatting context, so it will not take a grid\n column and every choice row drops below its own label. */}\n <div className=\"lk-export__row\">\n <span>Format</span>\n <span className=\"lk-export__choices\" role=\"radiogroup\" aria-label=\"Format\">\n {FORMATS.map((f) => (\n <label key={f.id}>\n <input\n type=\"radio\"\n name=\"lk-export-format\"\n checked={format === f.id}\n onChange={() => setFormat(f.id)}\n />\n {f.label}\n </label>\n ))}\n </span>\n </div>\n\n <div className=\"lk-export__row\">\n <span>Scale</span>\n <span className=\"lk-export__choices\" role=\"radiogroup\" aria-label=\"Scale\">\n {SCALES.map((s) => (\n <label key={s}>\n <input\n type=\"radio\"\n name=\"lk-export-scale\"\n checked={scale === s}\n onChange={() => setScale(s)}\n />\n {s}×\n </label>\n ))}\n </span>\n </div>\n\n <div className=\"lk-export__actions\">\n <button type=\"button\" disabled={busy || !chosen} onClick={() => run(download)}>\n Download\n </button>\n <button type=\"button\" disabled={busy || !chosen} onClick={() => run(copy)}>\n Copy\n </button>\n </div>\n\n {error ? (\n <p className=\"lk-export__error\" role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n </Callout>\n </span>\n );\n}\n","import { Input } from '../passthrough/weasel-ui';\nimport { useAnnotations } from './AnnotationsContext';\nimport type { AnnotationMeaning } from './types';\n\n/** Props for `<MarkList>`. */\nexport interface MarkListProps {\n /** The instrument's vocabulary. Omitted, rows carry no status control —\n * a host that declared none owns what a mark means. */\n meaning?: AnnotationMeaning;\n /** The live config, for answering staleness. */\n config: unknown;\n}\n\n/** Every mark on this trial's targets: what it says, and whether it still\n * describes the picture under it.\n *\n * Reads the store through the hook, which re-renders on every mutation — so a\n * mark drawn on a pane appears here without anything wiring the two. */\nexport function MarkList({ meaning, config }: MarkListProps) {\n const marks = useAnnotations();\n const all = marks.query();\n const statuses = meaning?.statuses ?? [];\n\n if (all.length === 0) {\n return <div className=\"lk-mark-list__empty\">No marks yet</div>;\n }\n\n return (\n <ul className=\"lk-mark-list\">\n {all.map((a) => {\n const stale = marks.isStale(a, config);\n return (\n <li className=\"lk-mark-list__row\" key={a.id}>\n <div className=\"lk-mark-list__head\">\n <span className=\"lk-mark-list__kind\">{a.kind}</span>\n <span className=\"lk-mark-list__target\">{a.target}</span>\n {stale ? <span className=\"lk-mark-list__stale\">stale</span> : null}\n <button\n type=\"button\"\n className=\"lk-mark-list__drop\"\n aria-label={`Remove ${a.kind} on ${a.target}`}\n onClick={() => marks.remove(a.id)}\n >\n ×\n </button>\n </div>\n <Input\n className=\"lk-mark-list__title\"\n aria-label={`Title of ${a.kind} on ${a.target}`}\n value={a.title ?? ''}\n placeholder=\"Untitled\"\n onChange={(next) => marks.update(a.id, { title: next })}\n />\n {statuses.length > 0 ? (\n // A native select: it carries role, name and keyboard operability\n // for free, and a sidebar row is not the place to rebuild them.\n <select\n className=\"lk-mark-list__status\"\n aria-label={`Status of ${a.kind} on ${a.target}`}\n value={a.status ?? ''}\n onChange={(e) => marks.update(a.id, { status: e.target.value })}\n >\n <option value=\"\">—</option>\n {statuses.map((s) => (\n <option key={s.id} value={s.id}>\n {s.label}\n </option>\n ))}\n </select>\n ) : null}\n </li>\n );\n })}\n </ul>\n );\n}\n","import {\n CloneIcon,\n CloseIcon,\n FitIcon,\n LoupeIcon,\n RedoIcon,\n ResetIcon,\n SnapshotIcon,\n UndoIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@weasel-js/ui';\nimport { ExportMenu } from '../annotations/ExportMenu';\nimport { MarkList } from '../annotations/MarkList';\nimport type { ControlRenderer } from '../config/types';\nimport { ControlPanel } from '../controls/ControlPanel';\nimport type { Instrument } from '../instrument/types';\nimport { MenuButton } from '../passthrough/weasel-ui';\nimport { FpsMeter } from '../primitives/FpsMeter';\nimport { ScaleIndicator } from '../primitives/ScaleIndicator';\nimport { ZoomControl } from '../primitives/ZoomControl';\nimport type { TrialChromeContext, TrialContribution } from './types';\n\nconst ZOOM_STEP = 1.25;\n\n/** The property groups inside a contribution are folded under keys prefixed\n * with that contribution's id, so a group called `marks` cannot fold the\n * sidebar section of the same name. `ControlPanel` keys by bare label, so the\n * prefix goes on here and comes off again. */\nfunction groupFolds(\n collapsedSections: Readonly<Record<string, boolean>>,\n id: string,\n): Record<string, boolean> {\n const prefix = `${id}/`;\n const out: Record<string, boolean> = {};\n for (const [key, value] of Object.entries(collapsedSections)) {\n if (key.startsWith(prefix)) out[key.slice(prefix.length)] = value;\n }\n return out;\n}\n\n/**\n * The contributions a trial gets from what its instrument declared. This is\n * the whole \"declaring a capability provides the chrome\" rule — it replaces\n * the presence checks that used to be spread across the runtime.\n */\nexport function builtinContributions(\n instrument: Instrument,\n ctx: TrialChromeContext,\n controls?: Record<string, ControlRenderer>,\n): TrialContribution[] {\n const out: TrialContribution[] = [];\n const zoom = ctx.zoom;\n\n // Weasel history is the undo authority for marks, so declaring `annotations`\n // gets the buttons whether or not the instrument also declares `undo`.\n if (instrument.undo != null || instrument.annotations != null) {\n out.push({\n id: 'undo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: UndoIcon,\n label: 'Undo',\n shortcut: 'Mod+Z',\n disabled: !ctx.canUndo,\n onActivate: ctx.undo,\n },\n });\n out.push({\n id: 'redo',\n region: 'toolbar',\n group: 'history',\n item: {\n icon: RedoIcon,\n label: 'Redo',\n shortcut: 'Mod+Shift+Z',\n disabled: !ctx.canRedo,\n onActivate: ctx.redo,\n },\n });\n }\n\n // A tool id shares the contribution namespace, so a tool called `close`\n // collides with the built-in close button and throws. Annotation tools are\n // not here: the lab's rail carries them.\n for (const t of instrument.tools?.tools ?? []) {\n out.push({\n id: t.id,\n region: 'palette',\n group: t.group,\n item: { icon: t.icon, label: t.label, shortcut: t.shortcut },\n });\n }\n\n if (instrument.loupe != null) {\n out.push({\n id: 'loupe',\n region: 'toolbar',\n group: 'view',\n item: {\n icon: LoupeIcon,\n label: 'Loupe',\n pressed: ctx.loupeOn,\n onActivate: ctx.toggleLoupe,\n },\n });\n }\n\n // Zoom acts on the view of the trial, so it is a viewport control. A trial\n // holding a non-2D view reports zoom as null and gets none of this.\n if ((instrument.canvas != null || instrument.stage != null) && zoom !== null) {\n out.push({\n id: 'zoom-out',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomOutIcon,\n label: 'Zoom out',\n onActivate: () => ctx.setZoom(zoom / ZOOM_STEP),\n },\n });\n out.push({\n id: 'zoom-in',\n region: 'viewport',\n group: 'zoom',\n item: {\n icon: ZoomInIcon,\n label: 'Zoom in',\n onActivate: () => ctx.setZoom(zoom * ZOOM_STEP),\n },\n });\n out.push({\n id: 'actual-size',\n region: 'viewport',\n group: 'zoom',\n item: { icon: FitIcon, label: 'Actual size', onActivate: () => ctx.setZoom(1) },\n });\n out.push({\n id: 'zoom-control',\n region: 'viewport',\n group: 'zoom',\n render: (c) => <ZoomControl zoom={c.zoom ?? 1} onZoomChange={c.setZoom} />,\n });\n out.push({\n id: 'scale',\n region: 'status',\n group: 'view',\n render: (c) => <ScaleIndicator zoom={c.zoom ?? 1} />,\n });\n if (instrument.canvas != null) {\n out.push({\n id: 'fps',\n region: 'status',\n group: 'view',\n end: true,\n render: () => <FpsMeter />,\n });\n }\n }\n\n if (instrument.annotations != null) {\n // A popover, so it takes the `render` escape: the panel picks a target,\n // and an icon button cannot ask which one.\n out.push({\n id: 'export',\n region: 'toolbar',\n group: 'trial',\n end: true,\n render: () => <ExportMenu />,\n });\n out.push({\n id: 'marks',\n region: 'sidebar',\n item: {\n title: 'Marks',\n body: <MarkList meaning={instrument.annotations.meaning} config={ctx.config} />,\n },\n });\n }\n\n if (Object.keys(ctx.configSchema.group.children).length > 0) {\n out.push({\n id: 'settings',\n region: 'sidebar',\n item: {\n title: 'Settings',\n body: (\n <ControlPanel\n schema={ctx.configSchema}\n config={ctx.config as Record<string, unknown>}\n auto={ctx.auto}\n setConfig={(key, value) => ctx.setConfig(String(key), value)}\n renderers={controls}\n collapsed={groupFolds(ctx.collapsedSections, 'settings')}\n onCollapse={(label, next) => ctx.setSectionCollapsed(`settings/${label}`, next)}\n />\n ),\n },\n });\n }\n\n if (ctx.savedSnapshots.length > 0) {\n // A menu is not an icon button, so it takes the render escape.\n out.push({\n id: 'snapshot-load',\n region: 'toolbar',\n group: 'trial',\n end: true,\n render: (c) => (\n <MenuButton\n aria-label=\"Load snapshot\"\n label=\"Load…\"\n items={c.savedSnapshots.map((sn) => ({ value: sn.id, label: sn.name }))}\n onAction={(id) => c.loadSnapshot(id)}\n />\n ),\n });\n }\n out.push({\n id: 'clone',\n region: 'titlebar',\n end: true,\n item: { icon: CloneIcon, label: 'Clone trial', onActivate: ctx.clone },\n });\n out.push({\n id: 'reset',\n region: 'titlebar',\n end: true,\n item: { icon: ResetIcon, label: 'Reset trial', onActivate: ctx.reset },\n });\n out.push({\n id: 'snapshot',\n region: 'titlebar',\n end: true,\n item: {\n icon: SnapshotIcon,\n label: 'Save snapshot',\n shortcut: 'Mod+S',\n onActivate: () => ctx.saveSnapshot(),\n },\n });\n out.push({\n id: 'close',\n region: 'titlebar',\n end: true,\n item: {\n icon: CloseIcon,\n label: ctx.isLastTrial ? 'Cannot close the last trial' : 'Close trial',\n danger: true,\n disabled: ctx.isLastTrial,\n onActivate: ctx.close,\n },\n });\n\n return out;\n}\n","import type { InstrumentList } from '../instrument/types';\n\n/**\n * The tool the lab's slot holds, once its default is applied: a lab with any\n * annotating instrument starts in `pointer`, so a first click reaches the\n * instrument rather than the marks over it.\n */\nexport function resolveLabTool(slot: string | null, instruments: InstrumentList): string | null {\n if (slot !== null) return slot;\n return instruments.some((i) => i.annotations != null) ? 'pointer' : null;\n}\n","/**\n * Concatenate contribution bundles into one list, preserving order — order\n * decides how a region lays its contributions out, so it is part of the\n * result, not an accident of it.\n *\n * Throws on a duplicate id rather than dropping one: a contribution silently\n * losing to a later bundle is the failure a registry exists to prevent.\n */\nexport function mergeContributions<T extends { id: string }>(\n ...bundles: readonly (readonly T[])[]\n): T[] {\n const out: T[] = [];\n const seen = new Set<string>();\n for (const bundle of bundles) {\n for (const entry of bundle) {\n if (seen.has(entry.id)) {\n throw new Error(\n `[labkit] mergeContributions: duplicate contribution id \"${entry.id}\". ` +\n 'Two bundles registered the same id; rename one, or suppress the ' +\n 'built-in before adding yours.',\n );\n }\n seen.add(entry.id);\n out.push(entry);\n }\n }\n return out;\n}\n\n/**\n * Drop contributions by id. Throws when an id is not present: a typo that\n * silently suppresses nothing is the same class of bug as a duplicate id\n * silently winning.\n */\nexport function suppressContributions<T extends { id: string }>(\n bundle: readonly T[],\n ids: readonly string[],\n): T[] {\n const present = new Set(bundle.map((c) => c.id));\n for (const id of ids) {\n if (!present.has(id)) {\n throw new Error(\n `[labkit] cannot suppress \"${id}\": no contribution with that id. ` +\n `Present ids: ${[...present].join(', ')}`,\n );\n }\n }\n const drop = new Set(ids);\n return bundle.filter((c) => !drop.has(c.id));\n}\n","import { type StanceProps, useStance } from '@weasel-js/ui';\nimport type { ReactNode } from 'react';\nimport type {\n RegionContribution,\n SidebarSection,\n SidebarSlotContext,\n TrialChromeContext,\n} from '../types';\n\n/** Props for `<SidebarRegion>`. */\nexport interface SidebarRegionProps<TCtx extends SidebarSlotContext = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out. */\n region?: string;\n}\n\nfunction Section({\n title,\n collapsed,\n onCollapsedChange,\n onUndock,\n children,\n stance,\n tone,\n}: StanceProps & {\n title: string;\n collapsed: boolean;\n onCollapsedChange: (collapsed: boolean) => void;\n onUndock?: () => void;\n children: ReactNode;\n}) {\n return (\n <section className=\"lk-sidebar-section\" {...useStance({ stance, tone })}>\n <div className=\"lk-sidebar-section__bar\">\n <button\n type=\"button\"\n className=\"lk-sidebar-section__head\"\n aria-expanded={!collapsed}\n onClick={() => onCollapsedChange(!collapsed)}\n >\n {title}\n </button>\n {onUndock ? (\n <button\n type=\"button\"\n className=\"lk-sidebar-section__undock\"\n aria-label={`Undock ${title}`}\n title={`Undock ${title}`}\n onClick={onUndock}\n >\n ⧉\n </button>\n ) : null}\n </div>\n {collapsed ? null : <div className=\"lk-sidebar-section__body\">{children}</div>}\n </section>\n );\n}\n\n/** Lays `sidebar` contributions out as titled, collapsible sections — a\n * trial's, or the lab's. A section the trial has torn out is not rendered\n * here — `Trial` portals its body into the workspace instead. A context with\n * no `undockPanel` offers no tear-out. */\nexport function SidebarRegion<TCtx extends SidebarSlotContext = TrialChromeContext>({\n contributions,\n ctx,\n region = 'sidebar',\n}: SidebarRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n return (\n <>\n {contributions.map((c) => {\n if (c.render) return <div key={c.id}>{c.render(ctx)}</div>;\n if (c.region !== region || !c.item) return null;\n if (ctx.undockedPanels?.includes(c.id)) return null;\n const item = c.item as SidebarSection;\n return (\n <Section\n key={c.id}\n title={item.title}\n stance={item.stance}\n tone={item.tone}\n collapsed={ctx.collapsedSections[c.id] ?? item.defaultCollapsed ?? false}\n onCollapsedChange={(next) => ctx.setSectionCollapsed(c.id, next)}\n onUndock={\n ctx.undockPanel && item.undockable !== false\n ? () => ctx.undockPanel?.(c.id, item.undockAs ?? 'tile')\n : undefined\n }\n >\n {item.body}\n </Section>\n );\n })}\n </>\n );\n}\n","import { StatusBar } from '../../primitives/StatusBar';\nimport type { RegionContribution, StatusReadout, TrialChromeContext } from '../types';\n\n/** Props for `<StatusRegion>`. */\nexport interface StatusRegionProps<TCtx = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's readouts to lay out; the lab's footer is `footer`. */\n region?: string;\n}\n\n/** Lays a bar's readouts out. */\nexport function StatusRegion<TCtx = TrialChromeContext>({\n contributions,\n ctx,\n region = 'status',\n}: StatusRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n return (\n <StatusBar>\n {contributions.map((c) => {\n if (c.render)\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n {c.render(ctx)}\n </StatusBar.Section>\n );\n if (c.region !== region || !c.item) return null;\n const item = c.item as StatusReadout;\n return (\n <StatusBar.Section key={c.id} end={c.end}>\n <span title={item.title}>{item.text}</span>\n </StatusBar.Section>\n );\n })}\n </StatusBar>\n );\n}\n","import type { ReactNode } from 'react';\nimport { Toolbar } from '../../primitives/Toolbar';\nimport type { RegionContribution, ToolbarItem, TrialChromeContext } from '../types';\n\n/** Props for `<ToolbarRegion>`. */\nexport interface ToolbarRegionProps<TCtx = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out; the lab's action bar is `header`. */\n region?: string;\n /** The bar's accessible name. */\n label?: string;\n}\n\ninterface Group<TCtx> {\n key: string;\n end: boolean;\n entries: RegionContribution<TCtx>[];\n}\n\n/** Bucket by group, preserving first-appearance order. Ungrouped\n * contributions each become their own bucket so they stay in place. */\nfunction groupsOf<TCtx>(contributions: readonly RegionContribution<TCtx>[]): Group<TCtx>[] {\n const groups: Group<TCtx>[] = [];\n const byKey = new Map<string, Group<TCtx>>();\n for (const c of contributions) {\n if (c.group == null) {\n groups.push({ key: c.id, end: c.end ?? false, entries: [c] });\n continue;\n }\n let g = byKey.get(c.group);\n if (!g) {\n g = { key: c.group, end: c.end ?? false, entries: [] };\n byKey.set(c.group, g);\n groups.push(g);\n }\n g.entries.push(c);\n }\n return groups;\n}\n\nfunction renderEntry<TCtx>(c: RegionContribution<TCtx>, ctx: TCtx, region: string): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== region || !c.item) return null;\n const {\n icon: Icon,\n label,\n shortcut,\n disabled,\n danger,\n showLabel,\n pressed,\n onActivate,\n } = c.item as ToolbarItem<TCtx>;\n return (\n <Toolbar.Button\n key={c.id}\n iconOnly={!showLabel}\n variant={danger ? 'danger' : 'default'}\n disabled={disabled}\n pressed={pressed}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={() => onActivate(ctx)}\n >\n <Icon size={16} />\n {showLabel ? <span>{label}</span> : null}\n </Toolbar.Button>\n );\n}\n\n/** Lays a bar's contributions out, grouped by their `group`. */\nexport function ToolbarRegion<TCtx = TrialChromeContext>({\n contributions,\n ctx,\n region = 'toolbar',\n label = 'Trial actions',\n}: ToolbarRegionProps<TCtx>) {\n if (contributions.length === 0) return null;\n const groups = groupsOf(contributions);\n return (\n <Toolbar aria-label={label}>\n {groups.map((g) => (\n <Toolbar.Group key={g.key} end={g.end} aria-label={g.key}>\n {g.entries.map((c) => renderEntry(c, ctx, region))}\n </Toolbar.Group>\n ))}\n </Toolbar>\n );\n}\n","import { useContext, useMemo } from 'react';\nimport { useStore } from 'zustand/react';\nimport { useLabContext } from '../lab/LabContext';\nimport { LabStoreContext } from '../state/context';\nimport { usePersistedState } from '../state/usePersistedState';\nimport { resolveLabTool } from '../tools/labTool';\nimport type { TrialTool } from '../tools/types';\nimport type { LabChromeContext, LabContribution, LabRegion } from './labTypes';\nimport { mergeContributions } from './merge';\nimport { SidebarRegion } from './regions/SidebarRegion';\nimport { StatusRegion } from './regions/StatusRegion';\nimport { ToolbarRegion } from './regions/ToolbarRegion';\n\n/** The lab's chrome context: the lab itself, plus the lab's tool slot. Throws\n * outside a `<Lab>`. */\nexport function useLabChromeContext(): LabChromeContext {\n const lab = useLabContext();\n const storeCtx = useContext(LabStoreContext);\n if (!storeCtx) throw new Error('[labkit] lab chrome requires <LabStoreProvider>');\n const slot = useStore(storeCtx.store, (s) => s.activeToolId);\n const storeInstruments = useStore(storeCtx.store, (s) => s.instruments);\n const activeToolId = resolveLabTool(slot, storeInstruments ?? lab.instruments);\n const setLabTool = useStore(storeCtx.store, (s) => s.setLabTool);\n return useMemo(\n () => ({ ...lab, activeToolId, setActiveTool: setLabTool }),\n [lab, activeToolId, setLabTool],\n );\n}\n\n/** The lab's contributions for one region, in declaration order. */\nexport function contributionsIn<TCtx = LabChromeContext>(\n contributions: readonly LabContribution<TCtx>[],\n region: LabRegion,\n): LabContribution<TCtx>[] {\n return contributions.filter((c) => c.region === region);\n}\n\n/** The palette contributions a lab's `tools` stand for. Declaring a tool is\n * shorthand for contributing a palette item that writes the lab's tool\n * slot. */\nexport function toolContributions(tools: readonly TrialTool[]): LabContribution[] {\n return tools.map((t) => ({\n id: t.id,\n region: 'palette' as const,\n ...(t.group === undefined ? {} : { group: t.group }),\n item: {\n icon: t.icon,\n label: t.label,\n ...(t.shortcut === undefined ? {} : { shortcut: t.shortcut }),\n },\n }));\n}\n\n/** Everything the lab's chrome renders, from both of the ways a lab declares\n * it. Tools and contributions share one id namespace, so a tool colliding\n * with a contribution throws here rather than one of them silently losing. */\nexport function labContributions(\n tools: readonly TrialTool[] | undefined,\n chrome: readonly LabContribution[] | undefined,\n): LabContribution[] {\n return mergeContributions<LabContribution>(toolContributions(tools ?? []), [...(chrome ?? [])]);\n}\n\n/** Props shared by the lab's region mounts. Each takes the lab's whole\n * contribution list and lays out the part addressed to it. */\nexport interface LabRegionProps {\n contributions: readonly LabContribution[];\n}\n\n/** The lab's action bar, in the shell header beside the title. */\nexport function LabHeaderRegion({ contributions }: LabRegionProps) {\n const ctx = useLabChromeContext();\n return (\n <ToolbarRegion\n region=\"header\"\n label=\"Lab actions\"\n contributions={contributionsIn(contributions, 'header')}\n ctx={ctx}\n />\n );\n}\n\nfunction LabSections({ contributions, region }: LabRegionProps & { region: 'sidebar' | 'aside' }) {\n const lab = useLabChromeContext();\n const [collapsedSections, setFolds] = usePersistedState<Record<string, boolean>>(\n `lk-lab-${region}-folds`,\n {},\n { scope: 'lab' },\n );\n const ctx = useMemo(\n () => ({\n ...lab,\n collapsedSections,\n setSectionCollapsed: (key: string, collapsed: boolean) =>\n setFolds((f) => ({ ...f, [key]: collapsed })),\n }),\n [lab, collapsedSections, setFolds],\n );\n return (\n <SidebarRegion\n contributions={contributionsIn(contributions, region)}\n ctx={ctx}\n region={region}\n />\n );\n}\n\n/** The lab's sidebar sections. Fold state is a lab-scoped persisted value, so it\n * survives a reload in a stored lab and lasts the session in an unstored one. */\nexport function LabSidebarRegion({ contributions }: LabRegionProps) {\n return <LabSections contributions={contributions} region=\"sidebar\" />;\n}\n\n/** The lab's aside sections, on the far side of the workspace from the sidebar.\n * Fold state persists the way the sidebar's does. */\nexport function LabAsideRegion({ contributions }: LabRegionProps) {\n return <LabSections contributions={contributions} region=\"aside\" />;\n}\n\n/** The lab's readouts, in the shell footer below the workspace. */\nexport function LabFooterRegion({ contributions }: LabRegionProps) {\n const ctx = useLabChromeContext();\n return (\n <StatusRegion\n region=\"footer\"\n contributions={contributionsIn(contributions, 'footer')}\n ctx={ctx}\n />\n );\n}\n","import { ToolButton, ToolGroup } from '../../passthrough/weasel-ui';\nimport { useRovingTabIndex } from '../../primitives/useRovingTabIndex';\nimport type { RegionContribution, ToolItem, ToolSlotContext, TrialChromeContext } from '../types';\n\n/** Props for `<PaletteRegion>`. */\nexport interface PaletteRegionProps<TCtx extends ToolSlotContext = TrialChromeContext> {\n contributions: readonly RegionContribution<NoInfer<TCtx>>[];\n ctx: TCtx;\n /** Which region's items to lay out. The lab's rail names the same box\n * `palette` too, so this only moves for a chrome that does not. */\n region?: string;\n}\n\n/** A tool strip: a trial's, or the lab's. Selection lives in whichever tool\n * slot the context carries; this region only reflects it. An item carrying\n * `onActivate` is a command instead — it presses, and never latches. */\nexport function PaletteRegion<TCtx extends ToolSlotContext = TrialChromeContext>({\n contributions,\n ctx,\n region = 'palette',\n}: PaletteRegionProps<TCtx>) {\n const { ref, onKeyDown } = useRovingTabIndex<HTMLDivElement>('vertical');\n if (contributions.length === 0) return null;\n return (\n <div\n ref={ref}\n className=\"lk-palette-region\"\n role=\"toolbar\"\n aria-label=\"Tools\"\n aria-orientation=\"vertical\"\n onKeyDown={onKeyDown}\n >\n <ToolGroup orientation=\"vertical\">\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== region || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, onActivate } = c.item as ToolItem<TCtx>;\n return (\n <ToolButton\n key={c.id}\n icon={<Icon size={16} />}\n label={label}\n shortcut={shortcut}\n active={onActivate ? false : ctx.activeToolId === c.id}\n disabled={disabled}\n onClick={onActivate ? () => onActivate(ctx) : () => ctx.setActiveTool(c.id)}\n />\n );\n })}\n </ToolGroup>\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Which end of the title bar a `<TitleBarRegion>` lays out: `'lead'` renders\n * the contributions that leave `end` unset, before the title; `'actions'`\n * renders the ones that set it, after everything else. */\nexport type TitleBarPlacement = 'lead' | 'actions';\n\n/** Props for `<TitleBarRegion>`. */\nexport interface TitleBarRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n /** Defaults to `'actions'`, where the built-ins live. */\n placement?: TitleBarPlacement;\n}\n\nfunction renderEntry(c: TrialContribution, ctx: TrialChromeContext): ReactNode {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'titlebar' || !c.item) return null;\n const { icon: Icon, label, shortcut, disabled, danger, onActivate } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className={`lk-titlebar-button${danger ? ' lk-titlebar-button--danger' : ''}`}\n disabled={disabled}\n aria-label={label}\n title={shortcut ? `${label} (${shortcut})` : label}\n onClick={() => onActivate(ctx)}\n // The bar behind these buttons is the window drag surface, so a press\n // that lands here must not also start a drag.\n onPointerDown={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n >\n <Icon size={16} />\n </button>\n );\n}\n\n/** Lays a trial's `titlebar` contributions out at one end of the bar. */\nexport function TitleBarRegion({ contributions, ctx, placement = 'actions' }: TitleBarRegionProps) {\n const wanted = placement === 'actions';\n const mine = contributions.filter((c) => (c.end ?? false) === wanted);\n if (mine.length === 0) return null;\n return (\n <span className={wanted ? 'lk-trial__titlebar-actions' : 'lk-trial__titlebar-lead'}>\n {mine.map((c) => renderEntry(c, ctx))}\n </span>\n );\n}\n","import { useRovingTabIndex } from '../../primitives/useRovingTabIndex';\nimport type { TrialChromeContext, TrialContribution } from '../types';\n\n/** Props for `<ViewportRegion>`. */\nexport interface ViewportRegionProps {\n contributions: readonly TrialContribution[];\n ctx: TrialChromeContext;\n}\n\n/**\n * Controls acting on the view of a trial. Anchored inside the content well\n * rather than in the toolbar, which acts on the trial itself.\n */\nexport function ViewportRegion({ contributions, ctx }: ViewportRegionProps) {\n const { ref, onKeyDown } = useRovingTabIndex<HTMLDivElement>();\n if (contributions.length === 0) return null;\n return (\n <div\n ref={ref}\n className=\"lk-viewport-controls\"\n role=\"toolbar\"\n aria-label=\"View\"\n onKeyDown={onKeyDown}\n >\n {contributions.map((c) => {\n if (c.render) return <span key={c.id}>{c.render(ctx)}</span>;\n if (c.region !== 'viewport' || !c.item) return null;\n const { icon: Icon, label, disabled, onActivate } = c.item;\n return (\n <button\n key={c.id}\n type=\"button\"\n className=\"lk-viewport-controls__button\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={() => onActivate(ctx)}\n >\n <Icon size={16} />\n </button>\n );\n })}\n </div>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/controls/ControlPanel.tsx"],"names":["auto","s","Fragment","b","oe","value","v","m","L"],"mappings":"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","file":"chunk-HFRE4QQV.js","sourcesContent":["import { getAlpha01, isBuiltinToolPref, toHex8, withAlpha01 } from '@weasel-js/core';\nimport {\n DialogRow,\n isPrefLeaf,\n ListEditor,\n type PrefGroup,\n type PrefLeaf,\n type PropertyAlign,\n type PropertyControlProps,\n PropertyControl,\n type PropertyDensity,\n PropertyField,\n PropertyGroup,\n PropertyList,\n type PropertyListPack,\n PropertyPanel,\n PropertyRow,\n type PropertyRowLayout,\n prefFieldProps,\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 { 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/** 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 {...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 (renderers?.[path] ?? resolved.renderers[path] ?? renderers?.[found.kind]) 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 -> 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, 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) 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 === 'radio' && 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 { ...field, control: extra<string>(leaf, 'control') === 'switch' ? 'switch' : 'checkbox' };\n case 'enum':\n return { ...field, control: extra<string>(leaf, 'control') === 'radio' ? 'radio' : 'select' };\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 <PropertyControl {...field} name={leaf.name} value={text.local} onChange={text.type} />;\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) => write(field.alpha ? withAlpha01(rgb, getAlpha01(stored)) : rgb)}\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 +0,0 @@
1
- {"version":3,"sources":["../src/dragdrop/DragGhost.tsx","../src/dragdrop/DragDropRuntime.tsx","../src/dragdrop/Palette.tsx"],"names":["useState","useEffect","jsx"],"mappings":";;;;;;AASO,SAAS,SAAA,CAAU,EAAE,IAAA,EAAM,SAAA,EAAU,EAAuC;AACjF,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,SAAA,CAAU,MAAM,UAAA,CAAW,IAAI,CAAA,EAAG,EAAE,CAAA;AACpC,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,QAAA,KAAa,aAAa,OAAO,IAAA;AACxD,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,IAAA,EAAM,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,EAAE,CAAA,EAAA,CAAA;AAAA,IACzB,GAAA,EAAK,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,EAAE,CAAA,EAAA;AAAA,GAC1B;AACA,EAAA,OAAO,YAAA;AAAA,oBACL,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EAAgB,KAAA,EAC7B,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sBAAA,EAAwB,QAAA,EAAA,IAAA,CAAK,KAAA,EAAM,CAAA,EACrD,CAAA;AAAA,IACA,QAAA,CAAS;AAAA,GACX;AACF;ACqBO,SAAS,WAAA,CAAoB;AAAA,EAClC,UAAA;AAAA,EACA,kBAAA;AAAA,EACA,IAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAA+C;AAC7C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,SAA2B,IAAI,CAAA;AACvD,EAAA,MAAM,OAAA,GAAU,OAAyB,IAAI,CAAA;AAC7C,EAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAGlB,EAAA,MAAM,UAAA,GAAa,OAAqB,IAAI,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAa,OAA8B,IAAI,CAAA;AAIrD,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,EAAE,UAAA,EAAY,KAAA,EAAO,QAAQ,QAAA,EAAU,IAAA,EAAM,IAAA,EAAM,SAAA,EAAW,CAAA;AACrF,EAAA,OAAA,CAAQ,OAAA,GAAU,EAAE,UAAA,EAAY,KAAA,EAAO,QAAQ,QAAA,EAAU,IAAA,EAAM,MAAM,SAAA,EAAU;AAE/E,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,CAAC,SAAA,KAA8B;AAC7B,MAAA,MAAM,KAAK,kBAAA,CAAmB,OAAA;AAC9B,MAAA,IAAI,CAAC,IAAI,OAAO,KAAA;AAChB,MAAA,MAAM,CAAA,GAAI,GAAG,qBAAA,EAAsB;AACnC,MAAA,OACE,SAAA,CAAU,CAAA,IAAK,CAAA,CAAE,IAAA,IACjB,UAAU,CAAA,IAAK,CAAA,CAAE,KAAA,IACjB,SAAA,CAAU,CAAA,IAAK,CAAA,CAAE,GAAA,IACjB,SAAA,CAAU,KAAK,CAAA,CAAE,MAAA;AAAA,IAErB,CAAA;AAAA,IACA,CAAC,kBAAkB;AAAA,GACrB;AAEA,EAAA,MAAM,0BAAA,GAA6B,WAAA;AAAA,IACjC,CAAC,SAAA,KAAmC;AAClC,MAAA,MAAM,KAAK,kBAAA,CAAmB,OAAA;AAC9B,MAAA,IAAI,CAAC,IAAI,OAAO,IAAA;AAChB,MAAA,MAAM,CAAA,GAAI,GAAG,qBAAA,EAAsB;AACnC,MAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA;AAC1F,MAAA,OAAO,aAAA;AAAA,QACL,EAAE,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,CAAA,CAAE,MAAM,CAAA,EAAG,SAAA,CAAU,CAAA,GAAI,CAAA,CAAE,GAAA,EAAI;AAAA,QAClD,QAAQ,OAAA,CAAQ,IAAA;AAAA,QAChB;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,kBAAkB;AAAA,GACrB;AAEA,EAAA,MAAM,SAAA,GAAY,cAAc,MAAM;AACpC,IAAA,MAAM,YAAY,UAAA,CAAW,OAAA;AAC7B,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,MAAM,SAAS,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAI,CAAC,MAAA,IAAU,CAAC,SAAA,EAAW;AAC3B,IAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,IAAA,IAAI,QAAA,GAAgC,IAAA;AACpC,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,UAAA,IAAc,YAAA,CAAa,SAAS,CAAA,EAAG;AACzD,MAAA,MAAM,KAAA,GAAQ,2BAA2B,SAAS,CAAA;AAClD,MAAA,IAAI,KAAA,EAAO,QAAA,GAAW,IAAA,CAAK,UAAA,CAAW,UAAA,CAAW,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,MAAM,CAAA;AAAA,IAC9F;AACA,IAAA,OAAA,CAAQ,EAAE,GAAG,MAAA,EAAQ,SAAA,EAAW,UAAU,CAAA;AAAA,EAC5C,CAAC,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,SAAA,CAAU,MAAA,EAAO;AACjB,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAClB,IAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,EACd,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,SAAA,GAAY,WAAA;AAAA,IAChB,CAAC,MAAmB,CAAA,KAAyB;AAC3C,MAAA,IAAI,WAAW,OAAA,EAAS;AACxB,MAAA,MAAM,IAAA,GAAkB,EAAE,IAAA,EAAM,SAAA,EAAW,EAAE,CAAA,EAAG,CAAA,CAAE,OAAA,EAAS,CAAA,EAAG,CAAA,CAAE,OAAA,EAAQ,EAAG,UAAU,IAAA,EAAK;AAC1F,MAAA,OAAA,CAAQ,OAAA,GAAU,IAAA;AAClB,MAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,MAAA,UAAA,CAAW,OAAA,GAAU,kBAAA,CAAmB,CAAA,CAAE,aAAA,EAAe,CAAA,EAAG;AAAA,QAC1D,MAAA,EAAQ,CAAC,EAAA,KAAO;AACd,UAAA,MAAM,YAAY,EAAE,CAAA,EAAG,GAAG,OAAA,EAAS,CAAA,EAAG,GAAG,OAAA,EAAQ;AACjD,UAAA,MAAM,UAAU,OAAA,CAAQ,OAAA;AACxB,UAAA,IAAI,CAAC,OAAA,EAAS;AACd,UAAA,IAAI,UAAA,CAAW,YAAY,IAAA,EAAM;AAG/B,YAAA,UAAA,CAAW,OAAA,GAAU,SAAA;AACrB,YAAA,OAAA,CAAQ,OAAA,GAAU,EAAE,GAAG,OAAA,EAAS,SAAA,EAAU;AAC1C,YAAA,OAAA,CAAQ,QAAQ,OAAO,CAAA;AACvB,YAAA;AAAA,UACF;AACA,UAAA,UAAA,CAAW,OAAA,GAAU,SAAA;AACrB,UAAA,SAAA,CAAU,OAAA,EAAQ;AAAA,QACpB,CAAA;AAAA,QACA,KAAA,EAAO,CAAC,EAAA,KAAO;AACb,UAAA,MAAM,YAAY,EAAE,CAAA,EAAG,GAAG,OAAA,EAAS,CAAA,EAAG,GAAG,OAAA,EAAQ;AACjD,UAAA,MAAM,SAAS,OAAA,CAAQ,OAAA;AACvB,UAAA,SAAA,EAAU;AACV,UAAA,IAAI,CAAC,MAAA,IAAU,CAAC,YAAA,CAAa,SAAS,CAAA,EAAG;AACzC,UAAA,MAAM,KAAA,GAAQ,2BAA2B,SAAS,CAAA;AAClD,UAAA,IAAI,CAAC,KAAA,EAAO;AACZ,UAAA,MAAM,OAAO,OAAA,CAAQ,OAAA;AACrB,UAAA,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,UAAA,CAAW,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACjF,UAAA,IAAA,CAAK,KAAK,kBAAkB,CAAA;AAAA,QAC9B,CAAA;AAAA;AAAA,QAEA,QAAA,EAAU;AAAA,OACX,CAAA;AAAA,IACH,CAAA;AAAA,IACA,CAAC,SAAA,EAAW,SAAA,EAAW,YAAA,EAAc,0BAA0B;AAAA,GACjE;AAEA,EAAAC,SAAAA,CAAU,MAAM,MAAM,UAAA,CAAW,SAAS,MAAA,EAAO,EAAG,EAAE,CAAA;AAEtD,EAAA,OAAO,EAAE,MAAM,SAAA,EAAU;AAC3B;AAMO,SAAS,WAAA,CAAY,EAAE,IAAA,EAAK,EAAqB;AACtD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,uBAAOC,IAAC,SAAA,EAAA,EAAU,IAAA,EAAM,KAAK,IAAA,EAAM,SAAA,EAAW,KAAK,SAAA,EAAW,CAAA;AAChE;AClKO,SAAS,OAAA,CAAQ,EAAE,KAAA,EAAO,WAAA,EAAa,WAAU,EAAiB;AACvE,EAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,SAAA,GAAY,CAAA,WAAA,EAAc,SAAS,CAAA,CAAA,GAAK,YAAA,EACrD,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,yBACVA,GAAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MAEL,SAAA,EAAU,kBAAA;AAAA,MACV,aAAA,EAAe,CAAC,CAAA,KAAM;AACpB,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,MACrB,CAAA;AAAA,MAEA,0BAAAA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAA,EAAqB,eAAK,KAAA,EAAM;AAAA,KAAA;AAAA,IAP3C,IAAA,CAAK;AAAA,GASb,CAAA,EACH,CAAA;AAEJ","file":"chunk-RS3HRQWU.js","sourcesContent":["import { type ReactPortal, useEffect, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PaletteItem, Point } from '../instrument/types';\n\nexport interface DragGhostProps {\n item: PaletteItem;\n screenPos: Point;\n}\n\nexport function DragGhost({ item, screenPos }: DragGhostProps): ReactPortal | null {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n if (!mounted || typeof document === 'undefined') return null;\n const style = {\n left: `${screenPos.x + 12}px`,\n top: `${screenPos.y + 12}px`,\n };\n return createPortal(\n <div className=\"lk-drag-ghost\" style={style}>\n <span className=\"lk-drag-ghost__label\">{item.label}</span>\n </div>,\n document.body,\n );\n}\n","import { openPointerSession, type PointerSession, useVisibleRaf } from '@weasel-js/core';\nimport {\n type PointerEvent as ReactPointerEvent,\n type RefObject,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { screenToWorld } from '../canvas/canvasCoords';\nimport { resolveFrame, type WorldSpec } from '../canvas/worldSpec';\nimport type {\n DragDropCapability,\n DragFeedback,\n PaletteItem,\n Point,\n ViewTransform,\n} from '../instrument/types';\nimport { DragGhost } from './DragGhost';\n\nexport interface DragState {\n item: PaletteItem;\n screenPos: Point;\n feedback: DragFeedback | null;\n}\n\nexport interface UseDragDropArgs<TS, TC> {\n capability: DragDropCapability<TS, TC>;\n canvasContainerRef: RefObject<HTMLElement | null>;\n view: ViewTransform;\n /** The instrument's coordinate system, resolved against the container each\n * time a screen point is converted — the container is what knows its size. */\n worldSpec?: WorldSpec;\n state: TS;\n config: TC;\n setState: (next: TS | ((prev: TS) => TS)) => void;\n emit: (event: string) => void;\n}\n\nexport interface UseDragDropResult {\n drag: DragState | null;\n startDrag: (item: PaletteItem, e: ReactPointerEvent) => void;\n}\n\nexport function useDragDrop<TS, TC>({\n capability,\n canvasContainerRef,\n view,\n state,\n config,\n setState,\n emit,\n worldSpec,\n}: UseDragDropArgs<TS, TC>): UseDragDropResult {\n const [drag, setDrag] = useState<DragState | null>(null);\n const dragRef = useRef<DragState | null>(null);\n dragRef.current = drag;\n /** The move the next frame will resolve. Doubles as the throttle's flag:\n * non-null means a frame is already queued. */\n const pendingPos = useRef<Point | null>(null);\n const sessionRef = useRef<PointerSession | null>(null);\n\n /** A session keeps the closure it was opened with, so everything the drop\n * reads has to come from here rather than from that closure. */\n const liveRef = useRef({ capability, state, config, setState, emit, view, worldSpec });\n liveRef.current = { capability, state, config, setState, emit, view, worldSpec };\n\n const isOverCanvas = useCallback(\n (screenPos: Point): boolean => {\n const el = canvasContainerRef.current;\n if (!el) return false;\n const r = el.getBoundingClientRect();\n return (\n screenPos.x >= r.left &&\n screenPos.x <= r.right &&\n screenPos.y >= r.top &&\n screenPos.y <= r.bottom\n );\n },\n [canvasContainerRef],\n );\n\n const screenToWorldFromContainer = useCallback(\n (screenPos: Point): Point | null => {\n const el = canvasContainerRef.current;\n if (!el) return null;\n const r = el.getBoundingClientRect();\n const frame = resolveFrame(liveRef.current.worldSpec, { width: r.width, height: r.height });\n return screenToWorld(\n { x: screenPos.x - r.left, y: screenPos.y - r.top },\n liveRef.current.view,\n frame,\n );\n },\n [canvasContainerRef],\n );\n\n const frameLoop = useVisibleRaf(() => {\n const screenPos = pendingPos.current;\n pendingPos.current = null;\n const active = dragRef.current;\n if (!active || !screenPos) return;\n const live = liveRef.current;\n let feedback: DragFeedback | null = null;\n if (live.capability.onDragOver && isOverCanvas(screenPos)) {\n const world = screenToWorldFromContainer(screenPos);\n if (world) feedback = live.capability.onDragOver(world, active.item, live.state, live.config);\n }\n setDrag({ ...active, screenPos, feedback });\n });\n\n const clearDrag = useCallback(() => {\n pendingPos.current = null;\n frameLoop.cancel();\n sessionRef.current = null;\n dragRef.current = null;\n setDrag(null);\n }, [frameLoop]);\n\n const startDrag = useCallback(\n (item: PaletteItem, e: ReactPointerEvent) => {\n if (sessionRef.current) return;\n const next: DragState = { item, screenPos: { x: e.clientX, y: e.clientY }, feedback: null };\n dragRef.current = next;\n setDrag(next);\n sessionRef.current = openPointerSession(e.currentTarget, e, {\n onMove: (ev) => {\n const screenPos = { x: ev.clientX, y: ev.clientY };\n const current = dragRef.current;\n if (!current) return;\n if (pendingPos.current !== null) {\n // A frame is already queued: keep the ghost under the cursor and\n // let that frame probe the drop target from the newest position.\n pendingPos.current = screenPos;\n dragRef.current = { ...current, screenPos };\n setDrag(dragRef.current);\n return;\n }\n pendingPos.current = screenPos;\n frameLoop.request();\n },\n onEnd: (ev) => {\n const screenPos = { x: ev.clientX, y: ev.clientY };\n const active = dragRef.current;\n clearDrag();\n if (!active || !isOverCanvas(screenPos)) return;\n const world = screenToWorldFromContainer(screenPos);\n if (!world) return;\n const live = liveRef.current;\n live.setState(live.capability.onDrop(world, active.item, live.state, live.config));\n live.emit('canvas.itemAdded');\n },\n // An interrupted gesture never named a destination, so it drops nothing.\n onCancel: clearDrag,\n });\n },\n [clearDrag, frameLoop, isOverCanvas, screenToWorldFromContainer],\n );\n\n useEffect(() => () => sessionRef.current?.cancel(), []);\n\n return { drag, startDrag };\n}\n\nexport interface DragOverlayProps {\n drag: DragState | null;\n}\n\nexport function DragOverlay({ drag }: DragOverlayProps) {\n if (!drag) return null;\n return <DragGhost item={drag.item} screenPos={drag.screenPos} />;\n}\n","import type { PointerEvent as ReactPointerEvent } from 'react';\nimport type { PaletteItem } from '../instrument/types';\n\nexport interface PaletteProps {\n items: PaletteItem[];\n onDragStart: (item: PaletteItem, e: ReactPointerEvent) => void;\n className?: string;\n}\n\nexport function Palette({ items, onDragStart, className }: PaletteProps) {\n return (\n <div className={className ? `lk-palette ${className}` : 'lk-palette'}>\n {items.map((item) => (\n <button\n type=\"button\"\n key={item.id}\n className=\"lk-palette__item\"\n onPointerDown={(e) => {\n e.preventDefault();\n onDragStart(item, e);\n }}\n >\n <span className=\"lk-palette__label\">{item.label}</span>\n </button>\n ))}\n </div>\n );\n}\n"]}
@@ -1,3 +0,0 @@
1
-
2
- //# sourceMappingURL=chunk-SBXNQW4G.js.map
3
- //# sourceMappingURL=chunk-SBXNQW4G.js.map