@weasel-js/ui 1.0.1 → 1.0.3

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 (267) hide show
  1. package/dist/chunks/ActionBar-GThu74LC.js.map +1 -1
  2. package/dist/chunks/{ActionsBar-CAjrj_Pt.js → ActionsBar-9aR5N3lU.js} +10 -17
  3. package/dist/chunks/ActionsBar-9aR5N3lU.js.map +1 -0
  4. package/dist/chunks/Badge-DZQqAV4d.js.map +1 -1
  5. package/dist/chunks/BandEditor-13K91O9M.js +228 -0
  6. package/dist/chunks/BandEditor-13K91O9M.js.map +1 -0
  7. package/dist/chunks/Button-9QNIYugK.js.map +1 -1
  8. package/dist/chunks/{Callout-DlirfLJl.js → Callout-CFqG5xho.js} +1 -1
  9. package/dist/chunks/Callout-CFqG5xho.js.map +1 -0
  10. package/dist/chunks/{Checkbox-B3Z_u7k0.js → Checkbox-KQ5L8APP.js} +1 -1
  11. package/dist/chunks/Checkbox-KQ5L8APP.js.map +1 -0
  12. package/dist/chunks/{ColorField-B4Hd2qqS.js → ColorField-ykpiD3XU.js} +1 -1
  13. package/dist/chunks/ColorField-ykpiD3XU.js.map +1 -0
  14. package/dist/chunks/{ComboBox-tbmgND-F.js → ComboBox-DpxsFVBy.js} +2 -2
  15. package/dist/chunks/ComboBox-DpxsFVBy.js.map +1 -0
  16. package/dist/chunks/{CurveEditor-CSKqAXMp.js → CurveEditor-CqIt_Xph.js} +3 -3
  17. package/dist/chunks/CurveEditor-CqIt_Xph.js.map +1 -0
  18. package/dist/chunks/DataGrid-BQklXGRl.js.map +1 -1
  19. package/dist/chunks/{Dialog-BFuakycR.js → Dialog-3FCd_gYi.js} +1 -1
  20. package/dist/chunks/Dialog-3FCd_gYi.js.map +1 -0
  21. package/dist/chunks/{Field-DPxmJzZz.js → Field-VQwmrIna.js} +1 -1
  22. package/dist/chunks/Field-VQwmrIna.js.map +1 -0
  23. package/dist/chunks/{GradientEditor-3pYXGAPg.js → GradientEditor-DeptQpWX.js} +5 -5
  24. package/dist/chunks/GradientEditor-DeptQpWX.js.map +1 -0
  25. package/dist/chunks/{Input-Dg_CYXg4.js → Input-DpkwYtUY.js} +2 -2
  26. package/dist/chunks/Input-DpkwYtUY.js.map +1 -0
  27. package/dist/chunks/Keycaps-CFX7UAj8.js.map +1 -1
  28. package/dist/chunks/{NumberField-BhxUgi43.js → NumberField-BbzI0GtU.js} +2 -2
  29. package/dist/chunks/NumberField-BbzI0GtU.js.map +1 -0
  30. package/dist/chunks/{OptionsBar-hQN-wfd-.js → OptionsBar-CHvH4n4u.js} +10 -17
  31. package/dist/chunks/OptionsBar-CHvH4n4u.js.map +1 -0
  32. package/dist/chunks/Plot2D-CEnhzodm.js.map +1 -1
  33. package/dist/chunks/{PointPlotter-DCSjvpN0.js → PointPlotter-DD-bWmRc.js} +2 -2
  34. package/dist/chunks/PointPlotter-DD-bWmRc.js.map +1 -0
  35. package/dist/chunks/{Powerline-DkOTPnUV.js → Powerline-Dd9Ukhcl.js} +1 -1
  36. package/dist/chunks/Powerline-Dd9Ukhcl.js.map +1 -0
  37. package/dist/chunks/{Prefs-C4HfuTvm.js → Prefs-lgI4x4jF.js} +10 -10
  38. package/dist/chunks/Prefs-lgI4x4jF.js.map +1 -0
  39. package/dist/chunks/{RadioGroup-Bg3Rqxe2.js → RadioGroup-CIpHr3g6.js} +2 -2
  40. package/dist/chunks/RadioGroup-CIpHr3g6.js.map +1 -0
  41. package/dist/chunks/{RangeSlider-BvM_DGSr.js → RangeSlider-CaDogGTj.js} +1 -1
  42. package/dist/chunks/RangeSlider-CaDogGTj.js.map +1 -0
  43. package/dist/chunks/{ResizeHandle-BUkW2kZC.js → ResizeHandle-BOpmtOOj.js} +2 -2
  44. package/dist/chunks/ResizeHandle-BOpmtOOj.js.map +1 -0
  45. package/dist/chunks/{Select-DC0AjrEe.js → Select-BE3Y1NrH.js} +2 -2
  46. package/dist/chunks/Select-BE3Y1NrH.js.map +1 -0
  47. package/dist/chunks/{SelectionPanel-DoTdisRY.js → SelectionPanel-Zaw8tYQH.js} +6 -6
  48. package/dist/chunks/SelectionPanel-Zaw8tYQH.js.map +1 -0
  49. package/dist/chunks/{Sidebar-B8qig3BQ.js → Sidebar-DP_nyJze.js} +1 -1
  50. package/dist/chunks/Sidebar-DP_nyJze.js.map +1 -0
  51. package/dist/chunks/{SidebarPanel-LOt2c-wb.js → SidebarPanel-BpD0ptyg.js} +1 -1
  52. package/dist/chunks/SidebarPanel-BpD0ptyg.js.map +1 -0
  53. package/dist/chunks/{Slider-Di2kNqVy.js → Slider-CmPeFJ3x.js} +4 -4
  54. package/dist/chunks/Slider-CmPeFJ3x.js.map +1 -0
  55. package/dist/chunks/{StatusBar-Cg2LzdAm.js → StatusBar-DBO0E0Yd.js} +1 -1
  56. package/dist/chunks/StatusBar-DBO0E0Yd.js.map +1 -0
  57. package/dist/chunks/{Switch-I4putUAY.js → Switch-JyVSSAzC.js} +1 -1
  58. package/dist/chunks/{Switch-I4putUAY.js.map → Switch-JyVSSAzC.js.map} +1 -1
  59. package/dist/chunks/{Tabs-irZuG_PN.js → Tabs-Df0sDomx.js} +1 -1
  60. package/dist/chunks/Tabs-Df0sDomx.js.map +1 -0
  61. package/dist/chunks/{Toast-BGYP8Pw0.js → Toast-DFw4IrD_.js} +1 -1
  62. package/dist/chunks/Toast-DFw4IrD_.js.map +1 -0
  63. package/dist/chunks/ToggleBar-BP1zFcvg.js.map +1 -1
  64. package/dist/chunks/{ToolButton-DUeg8fPN.js → ToolButton-DpT-mukU.js} +6 -5
  65. package/dist/chunks/ToolButton-DpT-mukU.js.map +1 -0
  66. package/dist/chunks/{ToolGroup-D0CvyQhQ.js → ToolGroup-BTIwd4U4.js} +1 -1
  67. package/dist/chunks/ToolGroup-BTIwd4U4.js.map +1 -0
  68. package/dist/chunks/{ToolOptionsBar-N_MQcSo4.js → ToolOptionsBar-JvmY7iNe.js} +1 -1
  69. package/dist/chunks/ToolOptionsBar-JvmY7iNe.js.map +1 -0
  70. package/dist/chunks/{ToolPalette-BipoMdZz.js → ToolPalette-DPn0owno.js} +27 -47
  71. package/dist/chunks/ToolPalette-DPn0owno.js.map +1 -0
  72. package/dist/chunks/Tooltip-Clgn4trm.js.map +1 -1
  73. package/dist/chunks/segmentedControl.module-DCyuDbj1.js +11 -0
  74. package/dist/chunks/segmentedControl.module-DCyuDbj1.js.map +1 -0
  75. package/dist/chunks/useRovingTabIndex-DBZtq4IH.js.map +1 -1
  76. package/dist/color/oklch.d.ts +12 -0
  77. package/dist/color/oklch.d.ts.map +1 -1
  78. package/dist/components/ActionBar/ActionBar.d.ts +1 -0
  79. package/dist/components/ActionBar/ActionBar.d.ts.map +1 -1
  80. package/dist/components/ActionsBar/ActionsBar.d.ts +15 -0
  81. package/dist/components/ActionsBar/ActionsBar.d.ts.map +1 -1
  82. package/dist/components/ActionsBar/index.js +1 -1
  83. package/dist/components/Badge/Badge.d.ts +14 -0
  84. package/dist/components/Badge/Badge.d.ts.map +1 -1
  85. package/dist/components/Badge/bases/edgeProfiles.d.ts +8 -0
  86. package/dist/components/Badge/bases/edgeProfiles.d.ts.map +1 -1
  87. package/dist/components/Badge/types.d.ts +11 -0
  88. package/dist/components/Badge/types.d.ts.map +1 -1
  89. package/dist/components/BandEditor/BandEditor.d.ts +56 -0
  90. package/dist/components/BandEditor/BandEditor.d.ts.map +1 -0
  91. package/dist/components/BandEditor/bands.d.ts +45 -0
  92. package/dist/components/BandEditor/bands.d.ts.map +1 -0
  93. package/dist/components/BandEditor/index.d.ts +4 -0
  94. package/dist/components/BandEditor/index.d.ts.map +1 -0
  95. package/dist/components/BandEditor/index.js +2 -0
  96. package/dist/components/BandEditor/scale.d.ts +25 -0
  97. package/dist/components/BandEditor/scale.d.ts.map +1 -0
  98. package/dist/components/Button/Button.d.ts +13 -0
  99. package/dist/components/Button/Button.d.ts.map +1 -1
  100. package/dist/components/Callout/Callout.d.ts +2 -0
  101. package/dist/components/Callout/Callout.d.ts.map +1 -1
  102. package/dist/components/Callout/index.js +1 -1
  103. package/dist/components/Checkbox/Checkbox.d.ts +4 -0
  104. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  105. package/dist/components/Checkbox/index.js +1 -1
  106. package/dist/components/ColorField/ColorField.d.ts +4 -0
  107. package/dist/components/ColorField/ColorField.d.ts.map +1 -1
  108. package/dist/components/ColorField/index.js +1 -1
  109. package/dist/components/ComboBox/ComboBox.d.ts +11 -0
  110. package/dist/components/ComboBox/ComboBox.d.ts.map +1 -1
  111. package/dist/components/ComboBox/index.js +1 -1
  112. package/dist/components/CurveEditor/CurveEditor.d.ts +14 -2
  113. package/dist/components/CurveEditor/CurveEditor.d.ts.map +1 -1
  114. package/dist/components/CurveEditor/LayeredCurveEditor.d.ts +15 -0
  115. package/dist/components/CurveEditor/LayeredCurveEditor.d.ts.map +1 -1
  116. package/dist/components/CurveEditor/createFunctionLayer.d.ts +39 -0
  117. package/dist/components/CurveEditor/createFunctionLayer.d.ts.map +1 -1
  118. package/dist/components/CurveEditor/index.js +1 -1
  119. package/dist/components/CurveEditor/layerTypes.d.ts +5 -0
  120. package/dist/components/CurveEditor/layerTypes.d.ts.map +1 -1
  121. package/dist/components/CurveEditor/setCurveOp.d.ts +4 -0
  122. package/dist/components/CurveEditor/setCurveOp.d.ts.map +1 -1
  123. package/dist/components/DataGrid/DataGrid.d.ts +12 -0
  124. package/dist/components/DataGrid/DataGrid.d.ts.map +1 -1
  125. package/dist/components/Dialog/Dialog.d.ts +1 -0
  126. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  127. package/dist/components/Dialog/index.js +1 -1
  128. package/dist/components/Field/Field.d.ts +9 -0
  129. package/dist/components/Field/Field.d.ts.map +1 -1
  130. package/dist/components/Field/index.js +1 -1
  131. package/dist/components/GradientEditor/GradientEditor.d.ts +4 -0
  132. package/dist/components/GradientEditor/GradientEditor.d.ts.map +1 -1
  133. package/dist/components/GradientEditor/GradientHandles.d.ts +4 -0
  134. package/dist/components/GradientEditor/GradientHandles.d.ts.map +1 -1
  135. package/dist/components/GradientEditor/index.js +1 -1
  136. package/dist/components/Input/Input.d.ts +1 -0
  137. package/dist/components/Input/Input.d.ts.map +1 -1
  138. package/dist/components/Input/index.js +1 -1
  139. package/dist/components/Keycaps/Keycap.d.ts +10 -0
  140. package/dist/components/Keycaps/Keycap.d.ts.map +1 -1
  141. package/dist/components/Keycaps/Keycaps.d.ts +2 -0
  142. package/dist/components/Keycaps/Keycaps.d.ts.map +1 -1
  143. package/dist/components/Keycaps/keySpecsFromMods.d.ts +2 -0
  144. package/dist/components/Keycaps/keySpecsFromMods.d.ts.map +1 -1
  145. package/dist/components/NumberField/NumberField.d.ts +9 -0
  146. package/dist/components/NumberField/NumberField.d.ts.map +1 -1
  147. package/dist/components/NumberField/index.js +1 -1
  148. package/dist/components/OptionsBar/OptionsBar.d.ts +12 -0
  149. package/dist/components/OptionsBar/OptionsBar.d.ts.map +1 -1
  150. package/dist/components/OptionsBar/index.js +1 -1
  151. package/dist/components/Plot2D/Plot2D.d.ts +14 -0
  152. package/dist/components/Plot2D/Plot2D.d.ts.map +1 -1
  153. package/dist/components/Plot2D/geometry.d.ts +10 -0
  154. package/dist/components/Plot2D/geometry.d.ts.map +1 -1
  155. package/dist/components/PointPlotter/PointPlotter.d.ts +3 -2
  156. package/dist/components/PointPlotter/PointPlotter.d.ts.map +1 -1
  157. package/dist/components/PointPlotter/index.js +1 -1
  158. package/dist/components/Powerline/Powerline.d.ts +13 -0
  159. package/dist/components/Powerline/Powerline.d.ts.map +1 -1
  160. package/dist/components/Powerline/index.js +1 -1
  161. package/dist/components/Prefs/PrefsDialog.d.ts +4 -0
  162. package/dist/components/Prefs/PrefsDialog.d.ts.map +1 -1
  163. package/dist/components/Prefs/PrefsForm.d.ts +6 -0
  164. package/dist/components/Prefs/PrefsForm.d.ts.map +1 -1
  165. package/dist/components/Prefs/index.js +1 -1
  166. package/dist/components/Prefs/schema.d.ts +17 -0
  167. package/dist/components/Prefs/schema.d.ts.map +1 -1
  168. package/dist/components/RadioGroup/RadioGroup.d.ts +8 -0
  169. package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  170. package/dist/components/RadioGroup/index.js +1 -1
  171. package/dist/components/RangeSlider/RangeSlider.d.ts +1 -0
  172. package/dist/components/RangeSlider/RangeSlider.d.ts.map +1 -1
  173. package/dist/components/RangeSlider/index.js +1 -1
  174. package/dist/components/ResizeHandle/ResizeHandle.d.ts +7 -3
  175. package/dist/components/ResizeHandle/ResizeHandle.d.ts.map +1 -1
  176. package/dist/components/ResizeHandle/index.js +1 -1
  177. package/dist/components/Select/Select.d.ts +11 -0
  178. package/dist/components/Select/Select.d.ts.map +1 -1
  179. package/dist/components/Select/index.js +1 -1
  180. package/dist/components/SelectionPanel/SelectionPanel.d.ts +6 -0
  181. package/dist/components/SelectionPanel/SelectionPanel.d.ts.map +1 -1
  182. package/dist/components/SelectionPanel/index.js +1 -1
  183. package/dist/components/SelectionPanel/model.d.ts +12 -0
  184. package/dist/components/SelectionPanel/model.d.ts.map +1 -1
  185. package/dist/components/Sidebar/Sidebar.d.ts +1 -0
  186. package/dist/components/Sidebar/Sidebar.d.ts.map +1 -1
  187. package/dist/components/Sidebar/index.js +1 -1
  188. package/dist/components/SidebarPanel/SidebarPanel.d.ts +1 -0
  189. package/dist/components/SidebarPanel/SidebarPanel.d.ts.map +1 -1
  190. package/dist/components/SidebarPanel/index.js +1 -1
  191. package/dist/components/Slider/Slider.d.ts +43 -2
  192. package/dist/components/Slider/Slider.d.ts.map +1 -1
  193. package/dist/components/Slider/index.js +1 -1
  194. package/dist/components/StatusBar/StatusBar.d.ts +2 -0
  195. package/dist/components/StatusBar/StatusBar.d.ts.map +1 -1
  196. package/dist/components/StatusBar/index.js +1 -1
  197. package/dist/components/Switch/Switch.d.ts +11 -0
  198. package/dist/components/Switch/Switch.d.ts.map +1 -1
  199. package/dist/components/Switch/index.js +1 -1
  200. package/dist/components/Tabs/Tabs.d.ts +11 -0
  201. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  202. package/dist/components/Tabs/index.js +1 -1
  203. package/dist/components/Toast/Toast.d.ts +2 -0
  204. package/dist/components/Toast/Toast.d.ts.map +1 -1
  205. package/dist/components/Toast/index.js +1 -1
  206. package/dist/components/Toast/queue.d.ts +7 -0
  207. package/dist/components/Toast/queue.d.ts.map +1 -1
  208. package/dist/components/ToggleBar/ToggleBar.d.ts +16 -0
  209. package/dist/components/ToggleBar/ToggleBar.d.ts.map +1 -1
  210. package/dist/components/ToolButton/ToolButton.d.ts +5 -1
  211. package/dist/components/ToolButton/ToolButton.d.ts.map +1 -1
  212. package/dist/components/ToolButton/index.js +1 -1
  213. package/dist/components/ToolGroup/ToolGroup.d.ts +1 -0
  214. package/dist/components/ToolGroup/ToolGroup.d.ts.map +1 -1
  215. package/dist/components/ToolGroup/index.js +1 -1
  216. package/dist/components/ToolOptionsBar/ToolOptionsBar.d.ts +1 -0
  217. package/dist/components/ToolOptionsBar/ToolOptionsBar.d.ts.map +1 -1
  218. package/dist/components/ToolOptionsBar/index.js +1 -1
  219. package/dist/components/ToolPalette/ToolPalette.d.ts +9 -0
  220. package/dist/components/ToolPalette/ToolPalette.d.ts.map +1 -1
  221. package/dist/components/ToolPalette/index.js +1 -1
  222. package/dist/components/Tooltip/Tooltip.d.ts +5 -0
  223. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  224. package/dist/format/number.d.ts +4 -0
  225. package/dist/format/number.d.ts.map +1 -1
  226. package/dist/index.d.ts +1 -0
  227. package/dist/index.d.ts.map +1 -1
  228. package/dist/index.js +38 -37
  229. package/dist/index.js.map +1 -1
  230. package/dist/paintGradientTrack.d.ts +13 -0
  231. package/dist/paintGradientTrack.d.ts.map +1 -1
  232. package/dist/style.css +1 -1
  233. package/dist/useReorderDragList.d.ts +23 -0
  234. package/dist/useReorderDragList.d.ts.map +1 -1
  235. package/dist/useRovingTabIndex.d.ts +5 -0
  236. package/dist/useRovingTabIndex.d.ts.map +1 -1
  237. package/package.json +2 -2
  238. package/dist/chunks/ActionsBar-CAjrj_Pt.js.map +0 -1
  239. package/dist/chunks/Callout-DlirfLJl.js.map +0 -1
  240. package/dist/chunks/Checkbox-B3Z_u7k0.js.map +0 -1
  241. package/dist/chunks/ColorField-B4Hd2qqS.js.map +0 -1
  242. package/dist/chunks/ComboBox-tbmgND-F.js.map +0 -1
  243. package/dist/chunks/CurveEditor-CSKqAXMp.js.map +0 -1
  244. package/dist/chunks/Dialog-BFuakycR.js.map +0 -1
  245. package/dist/chunks/Field-DPxmJzZz.js.map +0 -1
  246. package/dist/chunks/GradientEditor-3pYXGAPg.js.map +0 -1
  247. package/dist/chunks/Input-Dg_CYXg4.js.map +0 -1
  248. package/dist/chunks/NumberField-BhxUgi43.js.map +0 -1
  249. package/dist/chunks/OptionsBar-hQN-wfd-.js.map +0 -1
  250. package/dist/chunks/PointPlotter-DCSjvpN0.js.map +0 -1
  251. package/dist/chunks/Powerline-DkOTPnUV.js.map +0 -1
  252. package/dist/chunks/Prefs-C4HfuTvm.js.map +0 -1
  253. package/dist/chunks/RadioGroup-Bg3Rqxe2.js.map +0 -1
  254. package/dist/chunks/RangeSlider-BvM_DGSr.js.map +0 -1
  255. package/dist/chunks/ResizeHandle-BUkW2kZC.js.map +0 -1
  256. package/dist/chunks/Select-DC0AjrEe.js.map +0 -1
  257. package/dist/chunks/SelectionPanel-DoTdisRY.js.map +0 -1
  258. package/dist/chunks/Sidebar-B8qig3BQ.js.map +0 -1
  259. package/dist/chunks/SidebarPanel-LOt2c-wb.js.map +0 -1
  260. package/dist/chunks/Slider-Di2kNqVy.js.map +0 -1
  261. package/dist/chunks/StatusBar-Cg2LzdAm.js.map +0 -1
  262. package/dist/chunks/Tabs-irZuG_PN.js.map +0 -1
  263. package/dist/chunks/Toast-BGYP8Pw0.js.map +0 -1
  264. package/dist/chunks/ToolButton-DUeg8fPN.js.map +0 -1
  265. package/dist/chunks/ToolGroup-D0CvyQhQ.js.map +0 -1
  266. package/dist/chunks/ToolOptionsBar-N_MQcSo4.js.map +0 -1
  267. package/dist/chunks/ToolPalette-BipoMdZz.js.map +0 -1
@@ -1,14 +1,7 @@
1
1
  import { t as e } from "./useRovingTabIndex-DBZtq4IH.js";
2
+ import { t } from "./segmentedControl.module-DCyuDbj1.js";
2
3
  import "react";
3
- import { jsx as t } from "react/jsx-runtime";
4
- var n = {
5
- root: "_root_13y7a_6",
6
- segment: "_segment_13y7a_28",
7
- segmentSelected: "_segmentSelected_13y7a_75",
8
- size_sm: "_size_sm_13y7a_133",
9
- variant_minimal: "_variant_minimal_13y7a_146"
10
- };
11
- //#endregion
4
+ import { jsx as n } from "react/jsx-runtime";
12
5
  //#region src/components/OptionsBar/OptionsBar.tsx
13
6
  function r(r) {
14
7
  let { items: i, ariaLabel: a, className: o, height: s, size: c, variant: l } = r, u = (e) => {
@@ -16,23 +9,23 @@ function r(r) {
16
9
  t.disabled || t.onChange(!t.selected);
17
10
  }, d = e({
18
11
  items: i,
19
- itemClassName: n.segment,
12
+ itemClassName: t.segment,
20
13
  onActivate: u
21
14
  }), f = s === void 0 ? void 0 : { "--wzl-tb-height": `${s}px` }, p = [
22
- n.root,
23
- c && n[`size_${c}`],
24
- l && n[`variant_${l}`],
15
+ t.root,
16
+ c && t[`size_${c}`],
17
+ l && t[`variant_${l}`],
25
18
  o
26
19
  ].filter(Boolean).join(" ");
27
- return /* @__PURE__ */ t("div", {
20
+ return /* @__PURE__ */ n("div", {
28
21
  ref: d.rootRef,
29
22
  className: p,
30
23
  role: "group",
31
24
  "aria-label": a,
32
25
  style: f,
33
26
  children: i.map((e, r) => {
34
- let i = `${n.segment}${e.selected ? ` ${n.segmentSelected}` : ""}`;
35
- return /* @__PURE__ */ t("button", {
27
+ let i = `${t.segment}${e.selected ? ` ${t.segmentSelected}` : ""}`;
28
+ return /* @__PURE__ */ n("button", {
36
29
  type: "button",
37
30
  "aria-pressed": e.selected,
38
31
  "aria-label": e.ariaLabel,
@@ -49,4 +42,4 @@ function r(r) {
49
42
  //#endregion
50
43
  export { r as t };
51
44
 
52
- //# sourceMappingURL=OptionsBar-hQN-wfd-.js.map
45
+ //# sourceMappingURL=OptionsBar-CHvH4n4u.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OptionsBar-CHvH4n4u.js","names":[],"sources":["../../src/components/OptionsBar/OptionsBar.tsx"],"sourcesContent":["import { type CSSProperties, type ReactElement, type ReactNode } from 'react';\nimport s from '../segmentedControl.module.css';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\n\n/**\n * One segment of an {@link OptionsBar}. Unlike `ToggleBar`, each item carries\n * its own selected state and its own `onChange`.\n */\nexport type OptionsBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n selected: boolean;\n onChange: (next: boolean) => void;\n};\n\n/** Segment height and type scale for an {@link OptionsBar}. */\nexport type OptionsBarSize = 'sm' | 'md';\n/** Visual treatment of an {@link OptionsBar}. */\nexport type OptionsBarVariant = 'default' | 'minimal';\n\n/** Props for {@link OptionsBar}. */\nexport type OptionsBarProps<V extends string | number = string> = {\n items: readonly OptionsBarItem<V>[];\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: OptionsBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: OptionsBarVariant;\n};\n\n/**\n * Segmented strip of independent on/off options, each owning its own state.\n * Use it when the segments are unrelated booleans; use `ToggleBar` when they\n * are values of one setting.\n */\nexport function OptionsBar<V extends string | number = string>(props: OptionsBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n\n const toggle = (index: number) => {\n const item = items[index];\n if (item.disabled) return;\n item.onChange(!item.selected);\n };\n\n const roving = useRovingTabIndex({ items, itemClassName: s.segment, onActivate: toggle });\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--wzl-tb-height' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={roving.rootRef}\n className={rootCls}\n role=\"group\"\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const cls = `${s.segment}${item.selected ? ` ${s.segmentSelected}` : ''}`;\n return (\n <button\n key={item.value}\n type=\"button\"\n aria-pressed={item.selected}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={roving.tabIndexFor(i)}\n className={cls}\n onClick={() => toggle(i)}\n onKeyDown={roving.onKeyDown(i)}\n >\n {item.label}\n </button>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;AAyCA,SAAgB,EAA+C,GAAyC;CACtG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAY,GAEzD,KAAU,MAAkB;EAChC,IAAM,IAAO,EAAM;AACf,IAAK,YACT,EAAK,SAAS,CAAC,EAAK,SAAS;IAGzB,IAAS,EAAkB;EAAE;EAAO,eAAe,EAAE;EAAS,YAAY;EAAQ,CAAC,EAEnF,IAAmC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,mBAA8B,GAAG,EAAO,KAAK,EAG/C,IAAU;EACd,EAAE;EACF,KAAQ,EAAE,QAAQ;EAClB,KAAW,EAAE,WAAW;EACxB;EACD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;AAE3B,QACE,kBAAC,OAAD;EACE,KAAK,EAAO;EACZ,WAAW;EACX,MAAK;EACL,cAAY;EACL;YAEN,EAAM,KAAK,GAAM,MAAM;GACtB,IAAM,IAAM,GAAG,EAAE,UAAU,EAAK,WAAW,IAAI,EAAE,oBAAoB;AACrE,UACE,kBAAC,UAAD;IAEE,MAAK;IACL,gBAAc,EAAK;IACnB,cAAY,EAAK;IACjB,UAAU,EAAK;IACf,UAAU,EAAO,YAAY,EAAE;IAC/B,WAAW;IACX,eAAe,EAAO,EAAE;IACxB,WAAW,EAAO,UAAU,EAAE;cAE7B,EAAK;IACC,EAXF,EAAK,MAWH;IAEX;EACE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Plot2D-CEnhzodm.js","names":[],"sources":["../../src/dlog.ts","../../src/components/Plot2D/geometry.ts","../../src/components/Plot2D/Plot2D.module.css","../../src/components/Plot2D/Plot2D.tsx"],"sourcesContent":["/**\n * Namespaced, opt-in console tracing. Off by default; production builds\n * may strip the calls entirely depending on the bundler.\n *\n * Enable in the browser:\n *\n * localStorage.setItem('weasel.debug', '*') // all namespaces\n * localStorage.setItem('weasel.debug', 'curve-editor') // just curve editor\n * localStorage.setItem('weasel.debug', 'curve-editor,layer-stack')\n *\n * Each component picks a stable namespace and calls `dlog(namespace, ...)`.\n * Useful for tracing pointer/event flows that are hard to capture\n * post-hoc (drag handlers, gesture sequences, selection mutations).\n *\n * The flag is read once and cached for the page session — reload to\n * pick up changes. Cheap hot-path checks (one nullish-coalesce + Set\n * lookup) so leaving calls in place is fine.\n *\n * Mirrors `src/debug/flag.ts` in the kit. Two impls live here because\n * weasel-ui doesn't depend on the kit, but both read the same\n * localStorage keys so behavior is uniform. See the kit copy for the\n * canonical list of kit-level namespaces.\n *\n * Known weasel-ui namespaces:\n * - plot2d — Plot2D mount / unmount\n * - curve-editor — CurveEditor pointer flow\n */\n\nconst KEYS = ['weasel.debug', 'weaseldraw.debug'] as const;\n\ninterface Cached {\n all: boolean;\n set: Set<string>;\n}\n\nlet cached: Cached | null = null;\n\nfunction read(): Cached {\n const empty: Cached = { all: false, set: new Set() };\n if (typeof localStorage === 'undefined') return empty;\n try {\n for (const k of KEYS) {\n const v = localStorage.getItem(k);\n if (v == null || v === '') continue;\n if (v === '1' || v === 'true' || v === '*') return { all: true, set: new Set() };\n return { all: false, set: new Set(v.split(/[\\s,]+/).filter(Boolean)) };\n }\n return empty;\n } catch {\n return empty;\n }\n}\n\nfunction get(): Cached {\n if (cached === null) cached = read();\n return cached;\n}\n\n/** True when `namespace` (or `*`) is enabled. */\nexport function isDebugEnabled(namespace: string): boolean {\n const c = get();\n return c.all || c.set.has(namespace);\n}\n\n/** Conditional `console.debug` — no-op unless `namespace` (or `*`) is enabled.\n * Each call is prefixed with `[namespace]` so the source is searchable. */\nexport function dlog(namespace: string, ...args: unknown[]): void {\n if (!isDebugEnabled(namespace)) return;\n // eslint-disable-next-line no-console\n console.debug(`[${namespace}]`, ...args);\n}\n","/**\n * Coordinate transforms (model ↔ plot) for Plot2D. Pure / deterministic —\n * no DOM, no React, no state.\n *\n * Model space: caller-defined xRange × yRange. Y axis goes UP.\n * Plot space: 0..width × 0..height in CSS pixels. Y axis goes DOWN (SVG).\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface ModelRange {\n xMin: number;\n xMax: number;\n yMin: number;\n yMax: number;\n}\n\nexport interface PlotSize {\n width: number;\n height: number;\n}\n\nexport function modelToPlot(p: Point, m: ModelRange, plot: PlotSize): Point {\n const xFrac = (p.x - m.xMin) / (m.xMax - m.xMin);\n const yFrac = (p.y - m.yMin) / (m.yMax - m.yMin);\n return {\n x: xFrac * plot.width,\n // Invert y so model y=0 sits at plot bottom (SVG y grows downward).\n y: (1 - yFrac) * plot.height,\n };\n}\n\nexport function plotToModel(p: Point, m: ModelRange, plot: PlotSize): Point {\n const xFrac = p.x / plot.width;\n const yFrac = 1 - p.y / plot.height;\n return {\n x: m.xMin + xFrac * (m.xMax - m.xMin),\n y: m.yMin + yFrac * (m.yMax - m.yMin),\n };\n}\n",".root {\n /* Component-local vars layered over theme tokens. Consumers override\n * either the plot-* var (component scope) or the wzl-* token (app\n * scope). */\n --plot-bg: var(--wzl-surface-sunken);\n --plot-grid: var(--wzl-line);\n /* Axes get full foreground contrast — they're the plot frame, the\n * most prominent structural element after caller-rendered content. */\n --plot-axis: var(--wzl-fg);\n\n display: block;\n /* Caller-rendered marks at the very edge (e.g. CurveEditor anchors)\n * extend past the SVG box by their radius — let them paint over the\n * host page instead of being half-clipped. */\n overflow: visible;\n background: var(--plot-bg);\n user-select: none;\n touch-action: none;\n outline: none;\n}\n\n/* Keyboard-only focus ring. Caller opts in via `tabIndex`. */\n.root:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 2px;\n}\n\n.grid {\n stroke: var(--plot-grid);\n stroke-width: 1;\n fill: none;\n}\n\n.axis {\n stroke: var(--plot-axis);\n stroke-width: var(--wzl-line-width);\n fill: none;\n}\n","import {\n forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\nimport {\n modelToPlot, plotToModel,\n type ModelRange, type Point,\n} from './geometry';\nimport s from './Plot2D.module.css';\nimport { dlog } from '../../dlog';\n\nexport interface GridSettings {\n /** Number of evenly-spaced internal grid lines per axis (excluding\n * the edges). Applied to both x and y. Default 3. */\n divisions?: number;\n /** Stroke color override. When omitted, uses `var(--plot-grid)`. */\n color?: string;\n}\n\nexport interface AxesSettings {\n /** Stroke color override. When omitted, uses `var(--plot-axis)`. */\n color?: string;\n}\n\nexport interface Plot2DCoords {\n plot: Point;\n model: Point;\n}\n\nexport interface Plot2DProps {\n width: number;\n height: number;\n /** Model-space x range. Default [0, 1]. */\n xRange?: readonly [number, number];\n /** Model-space y range. Default [0, 1]. */\n yRange?: readonly [number, number];\n /** Background grid. `false` / `null` / omitted = no grid. Pass `{}`\n * for default (3 divisions per axis) or populated GridSettings. */\n grid?: GridSettings | false | null;\n /** Axis lines. `false` / `null` = no axes. Omitted = default-styled\n * axes (on). Pass AxesSettings to customize. */\n axes?: AxesSettings | false | null;\n /** Forwarded to the underlying svg. Consumer opts into focus this way. */\n tabIndex?: number;\n className?: string;\n style?: CSSProperties;\n /** Pointer down on the SVG. Receives both plot- and model-space coords\n * pre-computed so consumers don't repeat the rect/transform dance. */\n onPointerDown?: (e: ReactPointerEvent<SVGSVGElement>, coords: Plot2DCoords) => void;\n onKeyDown?: (e: ReactKeyboardEvent<SVGSVGElement>) => void;\n children?: ReactNode;\n}\n\nexport interface Plot2DHandle {\n readonly svg: SVGSVGElement | null;\n plotToModel(pt: Point): Point;\n modelToPlot(pt: Point): Point;\n /** Convert a DOM event's clientX/clientY (e.g. from a window-attached\n * pointermove during drag) to plot-space. */\n clientToPlot(e: { clientX: number; clientY: number }): Point;\n /** Convenience: clientToPlot → plotToModel. */\n clientToModel(e: { clientX: number; clientY: number }): Point;\n readonly width: number;\n readonly height: number;\n}\n\nexport const Plot2D = forwardRef<Plot2DHandle, Plot2DProps>(function Plot2D(props, ref) {\n const {\n width, height,\n xRange = [0, 1],\n yRange = [0, 1],\n grid,\n axes,\n tabIndex,\n className,\n style,\n onPointerDown,\n onKeyDown,\n children,\n } = props;\n\n const svgRef = useRef<SVGSVGElement | null>(null);\n\n const modelRange: ModelRange = useMemo(\n () => ({ xMin: xRange[0], xMax: xRange[1], yMin: yRange[0], yMax: yRange[1] }),\n [xRange, yRange],\n );\n\n const plotSize = useMemo(() => ({ width, height }), [width, height]);\n\n const clientToPlot = useCallback((e: { clientX: number; clientY: number }): Point => {\n const rect = svgRef.current?.getBoundingClientRect();\n const left = rect?.left ?? 0;\n const top = rect?.top ?? 0;\n return { x: e.clientX - left, y: e.clientY - top };\n }, []);\n\n useEffect(() => {\n dlog('plot2d', 'mount', { width, height });\n return () => dlog('plot2d', 'unmount');\n }, []);\n useImperativeHandle(ref, () => ({\n get svg() { return svgRef.current; },\n plotToModel: (pt: Point) => plotToModel(pt, modelRange, plotSize),\n modelToPlot: (pt: Point) => modelToPlot(pt, modelRange, plotSize),\n clientToPlot,\n clientToModel: (e) => plotToModel(clientToPlot(e), modelRange, plotSize),\n get width() { return plotSize.width; },\n get height() { return plotSize.height; },\n }), [modelRange, plotSize, clientToPlot]);\n\n const handlePointerDown = useCallback((e: ReactPointerEvent<SVGSVGElement>) => {\n if (!onPointerDown) return;\n const plot = clientToPlot(e);\n const model = plotToModel(plot, modelRange, plotSize);\n onPointerDown(e, { plot, model });\n }, [onPointerDown, clientToPlot, modelRange, plotSize]);\n\n const cls = [s.root, className].filter(Boolean).join(' ');\n\n return (\n <svg\n ref={svgRef}\n className={cls}\n style={style}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n tabIndex={tabIndex}\n onPointerDown={onPointerDown ? handlePointerDown : undefined}\n onKeyDown={onKeyDown}\n >\n {grid && (() => {\n const divisions = grid.divisions ?? 3;\n const stroke = grid.color;\n // Evenly-spaced internal divisions, excluding the edges (which\n // belong to the axes). For divisions=3, fractions are 1/4, 2/4, 3/4.\n const fractions: number[] = [];\n for (let i = 1; i <= divisions; i++) fractions.push(i / (divisions + 1));\n return (\n <g>\n {fractions.map((f) => (\n <line\n key={`gx-${f}`}\n data-plot-element=\"grid\"\n className={s.grid}\n stroke={stroke}\n x1={f * width} x2={f * width}\n y1={0} y2={height}\n />\n ))}\n {fractions.map((f) => (\n <line\n key={`gy-${f}`}\n data-plot-element=\"grid\"\n className={s.grid}\n stroke={stroke}\n x1={0} x2={width}\n y1={f * height} y2={f * height}\n />\n ))}\n </g>\n );\n })()}\n {axes !== false && axes !== null && (() => {\n const stroke = axes?.color;\n return (\n <g>\n <line\n data-plot-element=\"axis\"\n className={s.axis}\n stroke={stroke}\n x1={0} x2={width}\n y1={height} y2={height}\n />\n <line\n data-plot-element=\"axis\"\n className={s.axis}\n stroke={stroke}\n x1={0} x2={0}\n y1={0} y2={height}\n />\n </g>\n );\n })()}\n {children}\n </svg>\n );\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"Plot2D-CEnhzodm.js","names":[],"sources":["../../src/dlog.ts","../../src/components/Plot2D/geometry.ts","../../src/components/Plot2D/Plot2D.module.css","../../src/components/Plot2D/Plot2D.tsx"],"sourcesContent":["/**\n * Namespaced, opt-in console tracing. Off by default; production builds\n * may strip the calls entirely depending on the bundler.\n *\n * Enable in the browser:\n *\n * localStorage.setItem('weasel.debug', '*') // all namespaces\n * localStorage.setItem('weasel.debug', 'curve-editor') // just curve editor\n * localStorage.setItem('weasel.debug', 'curve-editor,layer-stack')\n *\n * Each component picks a stable namespace and calls `dlog(namespace, ...)`.\n * Useful for tracing pointer/event flows that are hard to capture\n * post-hoc (drag handlers, gesture sequences, selection mutations).\n *\n * The flag is read once and cached for the page session — reload to\n * pick up changes. Cheap hot-path checks (one nullish-coalesce + Set\n * lookup) so leaving calls in place is fine.\n *\n * Mirrors `src/debug/flag.ts` in the kit. Two impls live here because\n * weasel-ui doesn't depend on the kit, but both read the same\n * localStorage keys so behavior is uniform. See the kit copy for the\n * canonical list of kit-level namespaces.\n *\n * Known weasel-ui namespaces:\n * - plot2d — Plot2D mount / unmount\n * - curve-editor — CurveEditor pointer flow\n */\n\nconst KEYS = ['weasel.debug', 'weaseldraw.debug'] as const;\n\ninterface Cached {\n all: boolean;\n set: Set<string>;\n}\n\nlet cached: Cached | null = null;\n\nfunction read(): Cached {\n const empty: Cached = { all: false, set: new Set() };\n if (typeof localStorage === 'undefined') return empty;\n try {\n for (const k of KEYS) {\n const v = localStorage.getItem(k);\n if (v == null || v === '') continue;\n if (v === '1' || v === 'true' || v === '*') return { all: true, set: new Set() };\n return { all: false, set: new Set(v.split(/[\\s,]+/).filter(Boolean)) };\n }\n return empty;\n } catch {\n return empty;\n }\n}\n\nfunction get(): Cached {\n if (cached === null) cached = read();\n return cached;\n}\n\n/** True when `namespace` (or `*`) is enabled. */\nexport function isDebugEnabled(namespace: string): boolean {\n const c = get();\n return c.all || c.set.has(namespace);\n}\n\n/** Conditional `console.debug` — no-op unless `namespace` (or `*`) is enabled.\n * Each call is prefixed with `[namespace]` so the source is searchable. */\nexport function dlog(namespace: string, ...args: unknown[]): void {\n if (!isDebugEnabled(namespace)) return;\n // eslint-disable-next-line no-console\n console.debug(`[${namespace}]`, ...args);\n}\n","/**\n * Coordinate transforms (model ↔ plot) for Plot2D. Pure / deterministic —\n * no DOM, no React, no state.\n *\n * Model space: caller-defined xRange × yRange. Y axis goes UP.\n * Plot space: 0..width × 0..height in CSS pixels. Y axis goes DOWN (SVG).\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/**\n * The caller-defined extent of model space, the coordinate system a plot's\n * data lives in.\n */\nexport interface ModelRange {\n xMin: number;\n xMax: number;\n yMin: number;\n yMax: number;\n}\n\n/** The plot's drawing area in CSS pixels. */\nexport interface PlotSize {\n width: number;\n height: number;\n}\n\n/**\n * Maps a model-space point into plot space, flipping the y axis so model y\n * grows upward while SVG y grows downward.\n */\nexport function modelToPlot(p: Point, m: ModelRange, plot: PlotSize): Point {\n const xFrac = (p.x - m.xMin) / (m.xMax - m.xMin);\n const yFrac = (p.y - m.yMin) / (m.yMax - m.yMin);\n return {\n x: xFrac * plot.width,\n // Invert y so model y=0 sits at plot bottom (SVG y grows downward).\n y: (1 - yFrac) * plot.height,\n };\n}\n\n/** The inverse of {@link modelToPlot}. */\nexport function plotToModel(p: Point, m: ModelRange, plot: PlotSize): Point {\n const xFrac = p.x / plot.width;\n const yFrac = 1 - p.y / plot.height;\n return {\n x: m.xMin + xFrac * (m.xMax - m.xMin),\n y: m.yMin + yFrac * (m.yMax - m.yMin),\n };\n}\n",".root {\n /* Component-local vars layered over theme tokens. Consumers override\n * either the plot-* var (component scope) or the wzl-* token (app\n * scope). */\n --plot-bg: var(--wzl-surface-sunken);\n --plot-grid: var(--wzl-line);\n /* Axes get full foreground contrast — they're the plot frame, the\n * most prominent structural element after caller-rendered content. */\n --plot-axis: var(--wzl-fg);\n\n display: block;\n /* Caller-rendered marks at the very edge (e.g. CurveEditor anchors)\n * extend past the SVG box by their radius — let them paint over the\n * host page instead of being half-clipped. */\n overflow: visible;\n background: var(--plot-bg);\n user-select: none;\n touch-action: none;\n outline: none;\n}\n\n/* Keyboard-only focus ring. Caller opts in via `tabIndex`. */\n.root:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 2px;\n}\n\n.grid {\n stroke: var(--plot-grid);\n stroke-width: 1;\n fill: none;\n}\n\n.axis {\n stroke: var(--plot-axis);\n stroke-width: var(--wzl-line-width);\n fill: none;\n}\n","import {\n forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\nimport {\n modelToPlot, plotToModel,\n type ModelRange, type Point,\n} from './geometry';\nimport s from './Plot2D.module.css';\nimport { dlog } from '../../dlog';\n\n/** Background grid configuration for a {@link Plot2D}. */\nexport interface GridSettings {\n /** Number of evenly-spaced internal grid lines per axis (excluding\n * the edges). Applied to both x and y. Default 3. */\n divisions?: number;\n /** Stroke color override. When omitted, uses `var(--plot-grid)`. */\n color?: string;\n}\n\n/** Axis-line configuration for a {@link Plot2D}. */\nexport interface AxesSettings {\n /** Stroke color override. When omitted, uses `var(--plot-axis)`. */\n color?: string;\n}\n\n/** A pointer position given in both of the plot's coordinate systems. */\nexport interface Plot2DCoords {\n plot: Point;\n model: Point;\n}\n\n/** Props for {@link Plot2D}. */\nexport interface Plot2DProps {\n width: number;\n height: number;\n /** Model-space x range. Default [0, 1]. */\n xRange?: readonly [number, number];\n /** Model-space y range. Default [0, 1]. */\n yRange?: readonly [number, number];\n /** Background grid. `false` / `null` / omitted = no grid. Pass `{}`\n * for default (3 divisions per axis) or populated GridSettings. */\n grid?: GridSettings | false | null;\n /** Axis lines. `false` / `null` = no axes. Omitted = default-styled\n * axes (on). Pass AxesSettings to customize. */\n axes?: AxesSettings | false | null;\n /** Forwarded to the underlying svg. Consumer opts into focus this way. */\n tabIndex?: number;\n className?: string;\n style?: CSSProperties;\n /** Pointer down on the SVG. Receives both plot- and model-space coords\n * pre-computed so consumers don't repeat the rect/transform dance. */\n onPointerDown?: (e: ReactPointerEvent<SVGSVGElement>, coords: Plot2DCoords) => void;\n onKeyDown?: (e: ReactKeyboardEvent<SVGSVGElement>) => void;\n children?: ReactNode;\n}\n\n/**\n * Imperative handle on a {@link Plot2D}: the SVG element, its size, and the\n * coordinate conversions, including ones that start from a raw DOM event so a\n * drag tracked on `window` can still map back into the plot.\n */\nexport interface Plot2DHandle {\n readonly svg: SVGSVGElement | null;\n plotToModel(pt: Point): Point;\n modelToPlot(pt: Point): Point;\n /** Convert a DOM event's clientX/clientY (e.g. from a window-attached\n * pointermove during drag) to plot-space. */\n clientToPlot(e: { clientX: number; clientY: number }): Point;\n /** Convenience: clientToPlot → plotToModel. */\n clientToModel(e: { clientX: number; clientY: number }): Point;\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * An SVG plotting surface with an optional grid and axes. It draws the frame\n * and owns the model-space to plot-space mapping; the plotted content is\n * whatever children are passed, positioned in plot space.\n */\nexport const Plot2D = forwardRef<Plot2DHandle, Plot2DProps>(function Plot2D(props, ref) {\n const {\n width, height,\n xRange = [0, 1],\n yRange = [0, 1],\n grid,\n axes,\n tabIndex,\n className,\n style,\n onPointerDown,\n onKeyDown,\n children,\n } = props;\n\n const svgRef = useRef<SVGSVGElement | null>(null);\n\n const modelRange: ModelRange = useMemo(\n () => ({ xMin: xRange[0], xMax: xRange[1], yMin: yRange[0], yMax: yRange[1] }),\n [xRange, yRange],\n );\n\n const plotSize = useMemo(() => ({ width, height }), [width, height]);\n\n const clientToPlot = useCallback((e: { clientX: number; clientY: number }): Point => {\n const rect = svgRef.current?.getBoundingClientRect();\n const left = rect?.left ?? 0;\n const top = rect?.top ?? 0;\n return { x: e.clientX - left, y: e.clientY - top };\n }, []);\n\n useEffect(() => {\n dlog('plot2d', 'mount', { width, height });\n return () => dlog('plot2d', 'unmount');\n }, []);\n useImperativeHandle(ref, () => ({\n get svg() { return svgRef.current; },\n plotToModel: (pt: Point) => plotToModel(pt, modelRange, plotSize),\n modelToPlot: (pt: Point) => modelToPlot(pt, modelRange, plotSize),\n clientToPlot,\n clientToModel: (e) => plotToModel(clientToPlot(e), modelRange, plotSize),\n get width() { return plotSize.width; },\n get height() { return plotSize.height; },\n }), [modelRange, plotSize, clientToPlot]);\n\n const handlePointerDown = useCallback((e: ReactPointerEvent<SVGSVGElement>) => {\n if (!onPointerDown) return;\n const plot = clientToPlot(e);\n const model = plotToModel(plot, modelRange, plotSize);\n onPointerDown(e, { plot, model });\n }, [onPointerDown, clientToPlot, modelRange, plotSize]);\n\n const cls = [s.root, className].filter(Boolean).join(' ');\n\n return (\n <svg\n ref={svgRef}\n className={cls}\n style={style}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n tabIndex={tabIndex}\n onPointerDown={onPointerDown ? handlePointerDown : undefined}\n onKeyDown={onKeyDown}\n >\n {grid && (() => {\n const divisions = grid.divisions ?? 3;\n const stroke = grid.color;\n // Evenly-spaced internal divisions, excluding the edges (which\n // belong to the axes). For divisions=3, fractions are 1/4, 2/4, 3/4.\n const fractions: number[] = [];\n for (let i = 1; i <= divisions; i++) fractions.push(i / (divisions + 1));\n return (\n <g>\n {fractions.map((f) => (\n <line\n key={`gx-${f}`}\n data-plot-element=\"grid\"\n className={s.grid}\n stroke={stroke}\n x1={f * width} x2={f * width}\n y1={0} y2={height}\n />\n ))}\n {fractions.map((f) => (\n <line\n key={`gy-${f}`}\n data-plot-element=\"grid\"\n className={s.grid}\n stroke={stroke}\n x1={0} x2={width}\n y1={f * height} y2={f * height}\n />\n ))}\n </g>\n );\n })()}\n {axes !== false && axes !== null && (() => {\n const stroke = axes?.color;\n return (\n <g>\n <line\n data-plot-element=\"axis\"\n className={s.axis}\n stroke={stroke}\n x1={0} x2={width}\n y1={height} y2={height}\n />\n <line\n data-plot-element=\"axis\"\n className={s.axis}\n stroke={stroke}\n x1={0} x2={0}\n y1={0} y2={height}\n />\n </g>\n );\n })()}\n {children}\n </svg>\n );\n});\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { n as e } from "./CurveEditor-CSKqAXMp.js";
1
+ import { n as e } from "./CurveEditor-CqIt_Xph.js";
2
2
  import { jsx as t } from "react/jsx-runtime";
3
3
  //#region src/components/PointPlotter/PointPlotter.tsx
4
4
  function n(n) {
@@ -13,4 +13,4 @@ function n(n) {
13
13
  //#endregion
14
14
  export { n as t };
15
15
 
16
- //# sourceMappingURL=PointPlotter-DCSjvpN0.js.map
16
+ //# sourceMappingURL=PointPlotter-DD-bWmRc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PointPlotter-DD-bWmRc.js","names":[],"sources":["../../src/components/PointPlotter/PointPlotter.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport {\n CurveEditor,\n type AnchorRenderProps,\n type ControlPoint,\n type CurveEditorProps,\n} from '../CurveEditor';\nimport type { GridSettings, AxesSettings } from '../Plot2D';\n\n/** Props for {@link PointPlotter}. */\nexport interface PointPlotterProps {\n /** Plotted points; caller-owned. */\n value: readonly ControlPoint[];\n /** Fires every frame during drag with the live in-flight value. */\n onInput: (next: ControlPoint[]) => void;\n /** Fires once per discrete user action (drag-end, add, delete) with\n * the new value and the value at gesture start. Wire history here. */\n onChange?: (next: ControlPoint[], prev: readonly ControlPoint[]) => void;\n /** Model-space x range. Default [0, 1]. */\n xRange?: readonly [number, number];\n /** Model-space y range. Default [0, 1]. */\n yRange?: readonly [number, number];\n width: number;\n height: number;\n grid?: GridSettings | false | null;\n axes?: AxesSettings | false | null;\n /** Minimum allowed point count. User-initiated deletion is refused\n * while `value.length <= minPoints`. */\n minPoints?: number;\n /** Maximum allowed point count. User-initiated insertion is refused\n * while `value.length >= maxPoints`. */\n maxPoints?: number;\n /** How new points are added. Default `'click-empty'`. Set to `'never'`\n * to disable insertion entirely. */\n addPointMode?: 'click-empty' | 'never';\n /** Built-in undo/redo via keyboard when the component has focus.\n * Default `true`. See `CurveEditor.history` for details. */\n history?: boolean;\n /** Custom per-anchor renderer. See `CurveEditor.renderAnchor`. */\n renderAnchor?: (info: AnchorRenderProps) => ReactNode;\n /** Extra SVG content beneath the anchors. See `CurveEditor.decorations`. */\n decorations?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * 2D point plotter — a CurveEditor with the curve hidden. Anchors,\n * drag, shift+click delete, right-click delete, and click-empty insert\n * are inherited from CurveEditor verbatim, so the two components share\n * gesture semantics and stay in sync as CurveEditor evolves.\n *\n * Differences from CurveEditor: no curve `<path>` drawn, no fill, no\n * endpoint pinning, no interpolation, default `addPointMode` is\n * `'click-empty'` (CurveEditor defaults to `'click-curve'`, which\n * doesn't make sense without a curve to hit-test against).\n */\nexport function PointPlotter(props: PointPlotterProps) {\n const curveProps: CurveEditorProps = {\n ...props,\n addPointMode: props.addPointMode ?? 'click-empty',\n curve: false,\n fill: false,\n endpoints: 'free',\n };\n return <CurveEditor {...curveProps} />;\n}\n"],"mappings":";;;AAyDA,SAAgB,EAAa,GAA0B;AAQrD,QAAO,kBAAC,GAAD;EANL,GAAG;EACH,cAAc,EAAM,gBAAgB;EACpC,OAAO;EACP,MAAM;EACN,WAAW;EAEyB,CAAA"}
@@ -33,4 +33,4 @@ function r({ segments: r, startCap: i = "flat", size: a, variant: o, depth: s, g
33
33
  //#endregion
34
34
  export { r as t };
35
35
 
36
- //# sourceMappingURL=Powerline-DkOTPnUV.js.map
36
+ //# sourceMappingURL=Powerline-Dd9Ukhcl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Powerline-Dd9Ukhcl.js","names":[],"sources":["../../src/components/Powerline/Powerline.module.css","../../src/components/Powerline/Powerline.tsx"],"sourcesContent":[".row {\n display: inline-flex;\n align-items: stretch;\n gap: var(--powerline-gap, 0.2em);\n}\n\n.matrix {\n display: grid;\n gap: 12px;\n}\n\n/* Reset Badge's opinionated text defaults — Powerline segments should pick up\n * the surrounding text style instead of forcing uppercase / 10px / extra\n * tracking. Consumers can still override via className on Powerline. */\n.segment {\n font-size: inherit;\n text-transform: none;\n letter-spacing: normal;\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport { Badge } from '../Badge/Badge';\nimport type { BadgeSize, BadgeTone, BadgeVariant } from '../Badge/types';\nimport type { EdgeCap } from '../Badge/bases/edgeProfiles';\nimport s from './Powerline.module.css';\n\n/**\n * One segment of a {@link Powerline}. Giving it `onClick` or `href` makes it\n * interactive, the same way it does on a `Badge`.\n */\nexport interface PowerlineSegment {\n text: ReactNode;\n /** Cap on this segment's right edge. Next segment's left edge adopts the same profile. */\n endCap?: EdgeCap;\n tone?: BadgeTone;\n variant?: BadgeVariant;\n size?: BadgeSize;\n onClick?: () => void;\n href?: string;\n 'aria-label'?: string;\n}\n\n/** Props for {@link Powerline}. */\nexport interface PowerlineProps {\n segments: PowerlineSegment[];\n /** Left edge of the first segment. Defaults to 'flat'. */\n startCap?: EdgeCap;\n /** Default size for every segment (per-segment `size` wins). */\n size?: BadgeSize;\n /** Default variant for every segment (per-segment `variant` wins). */\n variant?: BadgeVariant;\n /** Protrusion depth in CSS px, passed through to every segment's base. */\n depth?: number;\n /** Visible gap between adjacent segments. Number → px; string → literal CSS length.\n * Default: `0.2em` (scales with the row's font size). Pass `0` for flush. */\n gap?: number | string;\n className?: string;\n 'aria-label'?: string;\n}\n\n/**\n * A row of chevron-linked badge segments, in the style of a shell powerline\n * prompt. Each segment's `endCap` shapes both its own right edge and the next\n * segment's left edge, so the run reads as one continuous chain.\n *\n * Built for showing a path through a sequence of steps — the inspector uses\n * it to display how input routes from tool to gesture to action to target.\n */\nexport function Powerline({\n segments,\n startCap = 'flat',\n size,\n variant,\n depth,\n gap,\n className,\n ...rest\n}: PowerlineProps) {\n const cls = [s.row, className].filter(Boolean).join(' ');\n const style: CSSProperties | undefined = gap !== undefined\n ? { ['--powerline-gap' as never]: typeof gap === 'number' ? `${gap}px` : gap }\n : undefined;\n return (\n <span className={cls} style={style} aria-label={rest['aria-label']}>\n {segments.map((seg, i) => {\n const leftEdge: EdgeCap = i === 0 ? startCap : (segments[i - 1].endCap ?? 'flat');\n const rightEdge: EdgeCap = seg.endCap ?? 'flat';\n return (\n <Badge\n key={i}\n base=\"powerline\"\n baseParams={{ leftEdge, rightEdge, ...(depth !== undefined && { depth }) }}\n tone={seg.tone}\n variant={seg.variant ?? variant}\n size={seg.size ?? size}\n onClick={seg.onClick}\n href={seg.href}\n aria-label={seg['aria-label']}\n className={s.segment}\n >\n {seg.text}\n </Badge>\n );\n })}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;ACgDA,SAAgB,EAAU,EACxB,aACA,cAAW,QACX,SACA,YACA,UACA,QACA,cACA,GAAG,KACc;AAKjB,QACE,kBAAC,QAAD;EAAM,WALI,CAAC,EAAE,KAAK,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAKjC;EAAY,OAJU,MAAQ,KAAA,IAE7C,KAAA,IADA,EAAG,mBAA6B,OAAO,KAAQ,WAAW,GAAG,EAAI,MAAM,GAAK;EAG1C,cAAY,EAAK;YAClD,EAAS,KAAK,GAAK,MAIhB,kBAAC,GAAD;GAEE,MAAK;GACL,YAAY;IAAE,UANQ,MAAM,IAAI,IAAY,EAAS,IAAI,GAAG,UAAU;IAM9C,WALD,EAAI,UAAU;IAKF,GAAI,MAAU,KAAA,KAAa,EAAE,UAAO;IAAG;GAC1E,MAAM,EAAI;GACV,SAAS,EAAI,WAAW;GACxB,MAAM,EAAI,QAAQ;GAClB,SAAS,EAAI;GACb,MAAM,EAAI;GACV,cAAY,EAAI;GAChB,WAAW,EAAE;aAEZ,EAAI;GACC,EAZD,EAYC,CAEV;EACG,CAAA"}
@@ -1,13 +1,13 @@
1
1
  import { n as e, t } from "./Tooltip-Clgn4trm.js";
2
- import { t as n } from "./Checkbox-B3Z_u7k0.js";
3
- import { t as r } from "./ColorField-B4Hd2qqS.js";
4
- import { t as i } from "./Input-Dg_CYXg4.js";
5
- import { t as a } from "./NumberField-BhxUgi43.js";
6
- import { n as o, t as s } from "./RadioGroup-Bg3Rqxe2.js";
7
- import { t as c } from "./RangeSlider-BvM_DGSr.js";
8
- import { t as l } from "./Select-DC0AjrEe.js";
9
- import { t as u } from "./Switch-I4putUAY.js";
10
- import { t as d } from "./Dialog-BFuakycR.js";
2
+ import { t as n } from "./Checkbox-KQ5L8APP.js";
3
+ import { t as r } from "./ColorField-ykpiD3XU.js";
4
+ import { t as i } from "./Input-DpkwYtUY.js";
5
+ import { t as a } from "./NumberField-BbzI0GtU.js";
6
+ import { n as o, t as s } from "./RadioGroup-CIpHr3g6.js";
7
+ import { t as c } from "./RangeSlider-CaDogGTj.js";
8
+ import { t as l } from "./Select-BE3Y1NrH.js";
9
+ import { t as u } from "./Switch-JyVSSAzC.js";
10
+ import { t as d } from "./Dialog-3FCd_gYi.js";
11
11
  import { useMemo as f } from "react";
12
12
  import { Focusable as p } from "react-aria-components";
13
13
  import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
@@ -235,4 +235,4 @@ function T(e) {
235
235
  //#endregion
236
236
  export { y as a, v as i, x as n, _ as r, T as t };
237
237
 
238
- //# sourceMappingURL=Prefs-C4HfuTvm.js.map
238
+ //# sourceMappingURL=Prefs-lgI4x4jF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prefs-lgI4x4jF.js","names":[],"sources":["../../src/components/Prefs/schema.ts","../../src/components/Prefs/Prefs.module.css","../../src/components/Prefs/PrefsForm.tsx","../../src/components/Prefs/PrefsDialog.tsx"],"sourcesContent":["// Preference-schema vocabulary for PrefsForm / PrefsDialog.\n//\n// Deliberately field-compatible with core's `ToolPref*` family\n// (src/tools/prefs.ts): this schema module deliberately avoids importing\n// @weasel-js/core, so the contract is structural — a `ToolPrefGroup` (and\n// any host-app superset, like WeaselDraw's registry) assigns into\n// `PrefGroup` with no import and no cast. Keep the two in sync\n// field-for-field.\n\n/** Control-presentation hints per kind — visually-equivalent renderings\n * of the same value type. The persisted value is unchanged either way. */\nexport type PrefNumberControl = 'input' | 'slider';\n/** Which control renders a {@link PrefBoolean}. */\nexport type PrefBooleanControl = 'checkbox' | 'switch';\n/** Which control renders a {@link PrefString}. */\nexport type PrefStringControl = 'input' | 'textarea';\n/** Which control renders a {@link PrefEnum}. */\nexport type PrefEnumControl = 'select' | 'radio';\n\ninterface PrefBase<K extends string, Value> {\n kind: K;\n /** Human-readable label, e.g. \"Show grid\". */\n name: string;\n /** Longer help text — surfaces as a tooltip on the row label. */\n description: string;\n /** Fallback when `values` holds nothing at this leaf's path. */\n default: Value;\n /** Omitted from the form unless `showHidden` is set. */\n hidden?: boolean;\n /** Render the control full-width with no label/tooltip row — for\n * controls that supply their own chrome (embedded sub-panel editors).\n * The `description` still applies wherever the renderer surfaces it. */\n block?: boolean;\n /** Row-pairing hint for compact property UIs (`SelectionPanel`):\n * leaves sharing a `pair` id render side-by-side on one row labeled\n * with the `pair` string. Purely presentational. */\n pair?: string;\n}\n\n/** Display-unit conversion for number leaves whose stored value uses a\n * canonical unit the user shouldn't see (radians → degrees). Mirrors\n * core's `ToolPrefNumberUnit`. */\nexport interface PrefNumberUnit {\n toDisplay: (stored: number) => number;\n fromDisplay: (display: number) => number;\n suffix?: string;\n}\n\n/**\n * A numeric preference. `unit` lets the stored value stay in a canonical unit\n * while the user edits a converted one.\n */\nexport interface PrefNumber extends PrefBase<'number', number> {\n min?: number;\n max?: number;\n step?: number;\n control?: PrefNumberControl;\n unit?: PrefNumberUnit;\n}\n/** A boolean preference. */\nexport interface PrefBoolean extends PrefBase<'boolean', boolean> {\n control?: PrefBooleanControl;\n}\n/** A free-text preference. */\nexport interface PrefString extends PrefBase<'string', string> {\n control?: PrefStringControl;\n}\n/** A preference chosen from a fixed set of options. */\nexport interface PrefEnum<T extends string = string> extends PrefBase<'enum', T> {\n options: readonly { value: T; label: string }[];\n control?: PrefEnumControl;\n}\n\n/** A color preference, stored as a hex string. */\nexport interface PrefColor extends PrefBase<'color', string> {\n /** Value is `#rrggbb`, or `#rrggbbaa` when `alpha` is set. */\n alpha?: boolean;\n}\n\n/** The leaf kinds `PrefsForm` renders without a custom renderer. */\nexport type BuiltinPref = PrefNumber | PrefBoolean | PrefString | PrefEnum | PrefColor;\n\n/**\n * Open leaf: any node with a `kind` the form doesn't know renders via the\n * `renderers` map (`renderers[kind]`). App schemas keep their extra fields\n * (e.g. a registry-enum's `source`/`filter`) — renderers receive the node\n * and narrow it themselves. Deliberately NOT index-signatured so concrete\n * app interfaces stay assignable.\n */\nexport interface PrefCustom extends PrefBase<string, unknown> {}\n\n/**\n * Any leaf in a preference schema — a built-in kind, or an app-defined one\n * rendered through `PrefsFormProps.renderers`.\n */\nexport type PrefLeaf = BuiltinPref | PrefCustom;\n\n/** Nestable group: branch nodes in the schema tree. */\nexport interface PrefGroup {\n name: string;\n description?: string;\n children: Record<string, PrefLeaf | PrefGroup>;\n}\n\n/** Distinguishes a leaf from a group while walking a schema tree. */\nexport function isPrefLeaf(node: PrefLeaf | PrefGroup): node is PrefLeaf {\n return 'kind' in node;\n}\n\n/** Get the value at a dotted path inside a nested value tree. Returns\n * `undefined` when a segment is missing or hits a non-object. */\nexport function prefValueAtPath(values: unknown, path: string): unknown {\n let cur: unknown = values;\n for (const seg of path.split('.')) {\n if (cur == null || typeof cur !== 'object') return undefined;\n cur = (cur as Record<string, unknown>)[seg];\n }\n return cur;\n}\n\n/**\n * Recursively drop `hidden` leaves (unless `showHidden`), pruning groups\n * that end up empty. Returns null when the entire subtree is hidden.\n */\nexport function visiblePrefSubtree<T extends PrefLeaf | PrefGroup>(\n node: T,\n showHidden: boolean,\n): T | null {\n if (isPrefLeaf(node)) return node.hidden && !showHidden ? null : node;\n const group = node as PrefGroup;\n const children: Record<string, PrefLeaf | PrefGroup> = {};\n for (const [key, child] of Object.entries(group.children)) {\n const kept = visiblePrefSubtree(child, showHidden);\n if (kept) children[key] = kept;\n }\n if (Object.keys(children).length === 0) return null;\n return { ...node, children };\n}\n","/* Ported from WeaselDraw's wd-prefs-* rules (apps/draw/src/app.css),\n * generalized onto theme tokens. Column width is overridable via\n * --wzl-prefs-column-width at any ancestor scope. */\n\n.columns {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: flex-start;\n gap: 12px;\n overflow-y: auto;\n padding-right: 4px;\n}\n\n.column {\n flex: 0 0 var(--wzl-prefs-column-width, 300px);\n width: var(--wzl-prefs-column-width, 300px);\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n.subpanel {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin-top: 6px;\n padding: 8px 8px 8px 10px;\n background: var(--wzl-surface-sunken);\n border-left: 2px solid var(--wzl-border);\n border-radius: 2px;\n}\n\n.groupHeader {\n display: flex;\n flex-direction: column;\n gap: 2px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.subpanel .groupHeader {\n border-bottom: none;\n padding-bottom: 2px;\n}\n\n.groupTitle {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--wzl-fg);\n letter-spacing: 0.04em;\n text-transform: uppercase;\n}\n\n.subpanel .groupTitle {\n font-size: 11px;\n text-transform: none;\n letter-spacing: 0;\n}\n\n.groupDesc {\n margin: 0;\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n font-size: 12px;\n color: var(--wzl-fg);\n cursor: default;\n}\n\n.rowLabel {\n flex: 1 1 auto;\n min-width: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n\n/* Description affordance — quiet until hovered/focused. */\n.help {\n flex: 0 0 auto;\n padding: 0;\n border: none;\n background: none;\n color: var(--wzl-fg-subtle);\n font-size: 11px;\n line-height: 1;\n cursor: help;\n border-radius: var(--wzl-radius-sm);\n}\n\n.help:hover {\n color: var(--wzl-fg);\n}\n\n.help:focus-visible {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 1px;\n color: var(--wzl-fg);\n}\n\n/* Control slot — fixed width so the label can take the rest of the row.\n * Kit form controls render as block-level flex columns that fill it. */\n.rowControl {\n flex: 0 0 110px;\n min-width: 0;\n display: flex;\n align-items: center;\n}\n\n.textarea {\n width: 100%;\n padding: 4px 8px;\n background: var(--wzl-surface-sunken);\n color: var(--wzl-fg);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n font: inherit;\n font-size: 12px;\n resize: vertical;\n}\n\n.unrenderable {\n font-family: var(--wzl-font-mono);\n font-size: 11px;\n color: var(--wzl-fg-subtle);\n}\n\n/* PrefsDialog header row: title text + optional headerExtra chrome. */\n.titleRow {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n min-width: 0;\n}\n\n.titleRow > span:first-child {\n flex: 1;\n min-width: 0;\n}\n","import { useMemo, type ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Checkbox } from '../Checkbox';\nimport { ColorField } from '../ColorField';\nimport { Input } from '../Input';\nimport { NumberField } from '../NumberField';\nimport { RadioGroup, Radio } from '../RadioGroup';\nimport { RangeSlider } from '../RangeSlider';\nimport { Select } from '../Select';\nimport { Switch } from '../Switch';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport {\n isPrefLeaf,\n prefValueAtPath,\n visiblePrefSubtree,\n type PrefBoolean,\n type PrefColor,\n type PrefEnum,\n type PrefGroup,\n type PrefLeaf,\n type PrefNumber,\n type PrefString,\n} from './schema';\nimport s from './Prefs.module.css';\n\n/** What a {@link PrefRenderer} is given for the leaf it is rendering. */\nexport interface PrefRenderContext {\n /** Dotted path of the leaf within the schema root. */\n path: string;\n /** The schema node. App renderers narrow this to their own kind shape. */\n pref: PrefLeaf;\n /** Current value — `values` at `path`, falling back to `pref.default`. */\n value: unknown;\n setValue: (value: unknown) => void;\n}\n\n/**\n * Renders the control cell for one preference leaf. Returning `null`\n * collapses the row.\n */\nexport type PrefRenderer = (ctx: PrefRenderContext) => ReactNode;\n\n/** Props for {@link PrefsForm}. */\nexport interface PrefsFormProps {\n /** Root of the schema tree. Core `ToolPrefGroup`s assign structurally. */\n schema: PrefGroup;\n /** Nested value tree (shape mirrors the schema). Sparse is fine —\n * missing leaves fall back to their schema `default`. */\n values?: unknown;\n /** Change callback with the leaf's dotted path. Values apply live;\n * there is no dirty/commit state. */\n onChange: (path: string, value: unknown) => void;\n /**\n * Per-kind renderers for app-defined kinds. Entries also override the\n * built-in kinds when keys collide. A renderer owns the control cell\n * (the label/tooltip row chrome stays with the form, unless the leaf\n * sets `block`); returning `null` collapses the row entirely. Unknown\n * kinds with no renderer show a labeled placeholder instead of\n * crashing.\n */\n renderers?: Record<string, PrefRenderer>;\n /** Reveal `hidden` leaves (dev tooling). Default false. */\n showHidden?: boolean;\n className?: string;\n}\n\n/**\n * Schema-driven preferences form. Top-level groups render as columns,\n * nested groups as indented sub-panels, leaves as label + control rows.\n * Storage-agnostic: pair with `PrefsDialog` for the modal composition,\n * and persist however the app likes via `onChange`.\n */\nexport function PrefsForm(props: PrefsFormProps) {\n const { schema, values, onChange, renderers, showHidden = false, className } = props;\n const visibleRoot = useMemo(\n () => visiblePrefSubtree(schema, showHidden),\n [schema, showHidden],\n );\n const ctx: WalkCtx = { values, onChange, renderers };\n return (\n <div className={[s.columns, className].filter(Boolean).join(' ')}>\n {Object.entries(visibleRoot?.children ?? {}).map(([key, child]) => (\n <div key={key} className={s.column}>\n {isPrefLeaf(child) ? (\n // Top-level leaves are unusual but legal — give each its own\n // column for symmetry with grouped siblings.\n <PrefRow ctx={ctx} path={key} pref={child} />\n ) : (\n <GroupBody ctx={ctx} group={child} path={key} depth={0} />\n )}\n </div>\n ))}\n </div>\n );\n}\n\ninterface WalkCtx {\n values: unknown;\n onChange: (path: string, value: unknown) => void;\n renderers?: Record<string, PrefRenderer>;\n}\n\nfunction GroupBody({ ctx, group, path, depth }: {\n ctx: WalkCtx;\n group: PrefGroup;\n path: string;\n depth: number;\n}) {\n return (\n <div className={depth === 0 ? s.panel : s.subpanel}>\n <div className={s.groupHeader}>\n <h3 className={s.groupTitle}>{group.name}</h3>\n {group.description !== undefined && (\n <p className={s.groupDesc}>{group.description}</p>\n )}\n </div>\n <div className={s.rows}>\n {Object.entries(group.children).map(([key, child]) => {\n const childPath = `${path}.${key}`;\n return isPrefLeaf(child) ? (\n <PrefRow key={key} ctx={ctx} path={childPath} pref={child} />\n ) : (\n <GroupBody key={key} ctx={ctx} group={child} path={childPath} depth={depth + 1} />\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction PrefRow({ ctx, path, pref }: { ctx: WalkCtx; path: string; pref: PrefLeaf }) {\n const stored = prefValueAtPath(ctx.values, path);\n const renderCtx: PrefRenderContext = {\n path,\n pref,\n value: stored !== undefined ? stored : pref.default,\n setValue: (v) => ctx.onChange(path, v),\n };\n\n const custom = ctx.renderers?.[pref.kind];\n const control = custom ? custom(renderCtx) : renderBuiltin(renderCtx);\n if (custom && control === null) return null;\n\n // `block` leaves own their chrome (embedded editors with their own\n // header) — no label/tooltip row.\n if (pref.block) return <>{control}</>;\n\n return (\n <label className={s.row}>\n <span className={s.rowLabel}>\n {pref.name}\n {pref.description ? (\n // Help affordance carries the description tooltip. A tooltip\n // trigger must be interactive (keyboard-reachable), so this is\n // a real button — a bare label span would be neither focusable\n // nor announced.\n <TooltipTrigger>\n <Focusable>\n <button type=\"button\" className={s.help} aria-label={`About ${pref.name}`}>\n ⓘ\n </button>\n </Focusable>\n <Tooltip>{pref.description}</Tooltip>\n </TooltipTrigger>\n ) : null}\n </span>\n <span className={s.rowControl}>{control}</span>\n </label>\n );\n}\n\nfunction renderBuiltin(ctx: PrefRenderContext): ReactNode {\n const { pref, value, setValue } = ctx;\n switch (pref.kind) {\n case 'boolean': {\n const p = pref as PrefBoolean;\n const checked = Boolean(value);\n return p.control === 'switch' ? (\n <Switch isSelected={checked} onChange={setValue} aria-label={p.name} />\n ) : (\n <Checkbox isSelected={checked} onChange={setValue} aria-label={p.name} />\n );\n }\n case 'number': {\n const p = pref as PrefNumber;\n const n = typeof value === 'number' && Number.isFinite(value) ? value : 0;\n if (p.control === 'slider') {\n return (\n <RangeSlider\n value={n}\n onChange={(v) => setValue(typeof v === 'number' ? v : v[0])}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n return (\n <NumberField\n value={n}\n onChange={setValue}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n aria-label={p.name}\n />\n );\n }\n case 'string': {\n const p = pref as PrefString;\n const text = typeof value === 'string' ? value : '';\n if (p.control === 'textarea') {\n return (\n <textarea\n className={s.textarea}\n value={text}\n onChange={(e) => setValue(e.target.value)}\n aria-label={p.name}\n rows={3}\n />\n );\n }\n return <Input value={text} onChange={setValue} aria-label={p.name} />;\n }\n case 'enum': {\n const p = pref as PrefEnum;\n const selected = typeof value === 'string' ? value : p.default;\n if (p.control === 'radio') {\n return (\n <RadioGroup\n value={selected}\n onChange={(v) => setValue(v)}\n aria-label={p.name}\n >\n {p.options.map((o) => (\n <Radio key={o.value} value={o.value}>{o.label}</Radio>\n ))}\n </RadioGroup>\n );\n }\n return (\n <Select<string>\n options={p.options.map((o) => ({ value: o.value, label: o.label }))}\n selectedKey={selected}\n onSelectionChange={(v) => setValue(v)}\n aria-label={p.name}\n />\n );\n }\n case 'color': {\n const p = pref as PrefColor;\n const hex = typeof value === 'string' ? value : p.default;\n return (\n <ColorField\n value={hex}\n alpha={p.alpha}\n onChange={setValue}\n aria-label={p.name}\n />\n );\n }\n default:\n // Unknown kind with no renderer entry: labeled placeholder, not a\n // crash — a missing wiring should be visible and recoverable.\n return <span className={s.unrenderable}>({pref.kind}: no renderer)</span>;\n }\n}\n","import type { ReactNode } from 'react';\nimport { Dialog } from '../Dialog';\nimport { PrefsForm, type PrefsFormProps } from './PrefsForm';\nimport s from './Prefs.module.css';\n\n/**\n * Props for {@link PrefsDialog} — everything {@link PrefsForm} takes, plus\n * the dialog's own open state and chrome.\n */\nexport interface PrefsDialogProps extends PrefsFormProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n /** Dialog heading. Defaults to the schema root's `name`. */\n title?: ReactNode;\n /** Extra chrome rendered inline with the title (e.g. a dev-mode\n * \"Show hidden\" switch). */\n headerExtra?: ReactNode;\n /** Class applied to the dialog's modal box. */\n dialogClassName?: string;\n}\n\n/**\n * The kit's preferences dialog: `Dialog` + `PrefsForm`. Changes apply\n * live through `onChange` — there is no OK/Cancel staging. For custom\n * placement (sidebar, popover, inline page), compose `PrefsForm`\n * directly; this wrapper is intentionally thin.\n */\nexport function PrefsDialog(props: PrefsDialogProps) {\n const { isOpen, onOpenChange, title, headerExtra, dialogClassName, ...form } = props;\n return (\n <Dialog\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n aria-label={typeof title === 'string' ? title : form.schema.name}\n className={dialogClassName}\n title={\n headerExtra !== undefined ? (\n <span className={s.titleRow}>\n <span>{title ?? form.schema.name}</span>\n {headerExtra}\n </span>\n ) : (\n title ?? form.schema.name\n )\n }\n >\n <PrefsForm {...form} />\n </Dialog>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { n as e } from "./Field-DPxmJzZz.js";
1
+ import { n as e } from "./Field-VQwmrIna.js";
2
2
  import { FieldError as t, Label as n, Radio as r, RadioGroup as i, Text as a } from "react-aria-components";
3
3
  import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
4
  var c = {
@@ -46,4 +46,4 @@ function u({ children: e, className: t, ...n }) {
46
46
  //#endregion
47
47
  export { l as n, u as t };
48
48
 
49
- //# sourceMappingURL=RadioGroup-Bg3Rqxe2.js.map
49
+ //# sourceMappingURL=RadioGroup-CIpHr3g6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup-CIpHr3g6.js","names":[],"sources":["../../src/components/RadioGroup/RadioGroup.module.css","../../src/components/RadioGroup/RadioGroup.tsx"],"sourcesContent":[".group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n font-family: var(--wzl-font-ui);\n color: var(--wzl-fg);\n}\n\n.group[data-orientation=\"horizontal\"] {\n flex-direction: row;\n gap: 16px;\n}\n\n.legend {\n font-size: 12px;\n font-weight: 500;\n color: var(--wzl-fg);\n}\n\n.radio {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n cursor: pointer;\n font-size: 13px;\n color: var(--wzl-fg);\n user-select: none;\n -webkit-user-select: none;\n}\n\n.radio[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dot {\n position: relative;\n flex: 0 0 auto;\n width: 14px;\n height: 14px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border-strong);\n border-radius: 50%;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.radio[data-focus-visible] .dot {\n box-shadow: 0 0 0 2px var(--wzl-focus-ring);\n}\n\n.radio[data-hovered]:not([data-disabled]) .dot {\n border-color: var(--wzl-fg-muted);\n}\n\n.radio[data-selected] .dot {\n border-color: var(--wzl-accent-strong);\n}\n\n.dot::after {\n content: '';\n position: absolute;\n inset: 3px;\n border-radius: 50%;\n background: var(--wzl-accent-strong);\n transform: scale(0);\n transition: transform var(--wzl-motion-fast);\n}\n\n.radio[data-selected] .dot::after {\n transform: scale(1);\n}\n","import type { ReactNode } from 'react';\nimport {\n RadioGroup as RACRadioGroup,\n Radio as RACRadio,\n Label,\n Text,\n FieldError,\n type RadioGroupProps as RACRadioGroupProps,\n type RadioProps as RACRadioProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './RadioGroup.module.css';\n\n/** Props for {@link RadioGroup}, on top of React Aria's `RadioGroup` props. */\nexport type RadioGroupProps = Omit<RACRadioGroupProps, 'children' | 'className'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n children?: ReactNode;\n className?: string;\n};\n\n/**\n * A set of mutually exclusive choices, wrapping React Aria's RadioGroup and\n * supplying the same label / description / errorMessage slots as `Input`.\n * Holds {@link Radio} children.\n */\nexport function RadioGroup(props: RadioGroupProps) {\n const { label, description, errorMessage, children, className, ...rest } = props;\n return (\n <RACRadioGroup\n {...rest}\n className={[s.group, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={s.legend}>{label}</Label>}\n {children}\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n </RACRadioGroup>\n );\n}\n\n/** Props for {@link Radio}, on top of React Aria's `Radio` props. */\nexport type RadioProps = Omit<RACRadioProps, 'className' | 'children'> & {\n children?: ReactNode;\n className?: string;\n};\n\n/** One choice in a {@link RadioGroup}. The label is passed as children. */\nexport function Radio({ children, className, ...rest }: RadioProps) {\n return (\n <RACRadio {...rest} className={[s.radio, className].filter(Boolean).join(' ')}>\n <span className={s.dot} />\n {children !== undefined && <span>{children}</span>}\n </RACRadio>\n );\n}\n"],"mappings":";;;;;;;;;;;AC4BA,SAAgB,EAAW,GAAwB;CACjD,IAAM,EAAE,UAAO,gBAAa,iBAAc,aAAU,cAAW,GAAG,MAAS;AAC3E,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW;GAAC,EAAE;GAAO,EAAa;GAAM;GAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAF9E;GAIG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAE;cAAS;IAAc,CAAA;GAClE;GACA,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GACxD;;;AAWpB,SAAgB,EAAM,EAAE,aAAU,cAAW,GAAG,KAAoB;AAClE,QACE,kBAAC,GAAD;EAAU,GAAI;EAAM,WAAW,CAAC,EAAE,OAAO,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA7E,CACE,kBAAC,QAAD,EAAM,WAAW,EAAE,KAAO,CAAA,EACzB,MAAa,KAAA,KAAa,kBAAC,QAAD,EAAO,aAAgB,CAAA,CACzC"}
@@ -49,4 +49,4 @@ function l(l) {
49
49
  //#endregion
50
50
  export { l as t };
51
51
 
52
- //# sourceMappingURL=RangeSlider-BvM_DGSr.js.map
52
+ //# sourceMappingURL=RangeSlider-CaDogGTj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RangeSlider-CaDogGTj.js","names":[],"sources":["../../src/components/RangeSlider/RangeSlider.module.css","../../src/components/RangeSlider/RangeSlider.tsx"],"sourcesContent":[".slider {\n display: flex;\n flex-direction: column;\n width: 100%;\n gap: 4px;\n font-family: var(--wzl-font-ui);\n color: var(--wzl-fg);\n}\n\n.slider[data-orientation=\"vertical\"] {\n flex-direction: row;\n align-items: stretch;\n width: 28px;\n height: 160px;\n}\n\n.head {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 8px;\n}\n\n.label {\n font-size: 12px;\n font-weight: 500;\n color: var(--wzl-fg);\n}\n\n.output {\n font-size: 12px;\n color: var(--wzl-fg-subtle);\n font-variant-numeric: tabular-nums;\n}\n\n.track {\n position: relative;\n height: 6px;\n min-width: 80px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: 3px;\n}\n\n.slider[data-orientation=\"vertical\"] .track {\n width: 6px;\n height: 100%;\n}\n\n.fill {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n background: var(--wzl-accent-strong);\n border-radius: 3px;\n}\n\n.thumb {\n width: 14px;\n height: 14px;\n background: var(--wzl-fg-muted);\n border: 1px solid var(--wzl-border-strong);\n border-radius: 50%;\n cursor: ew-resize;\n outline: none;\n transition: box-shadow var(--wzl-motion-fast);\n}\n\n.slider[data-orientation=\"vertical\"] .thumb {\n cursor: ns-resize;\n}\n\n.thumb[data-focus-visible] {\n box-shadow: 0 0 0 2px var(--wzl-focus-ring);\n}\n\n.thumb[data-dragging] {\n background: var(--wzl-accent-strong);\n}\n\n.slider[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n","import type { ReactNode } from 'react';\nimport {\n Slider as RACSlider,\n SliderOutput,\n SliderTrack,\n SliderThumb,\n Label,\n type SliderProps as RACSliderProps,\n} from 'react-aria-components';\nimport s from './RangeSlider.module.css';\n\n/** Props for {@link RangeSlider}, on top of React Aria's `Slider` props. */\nexport type RangeSliderProps = Omit<RACSliderProps, 'children' | 'className'> & {\n label?: ReactNode;\n /** Show the current value next to the label. Defaults to true when a\n * label is supplied. */\n showOutput?: boolean;\n /** Format the rendered value(s). Useful for units (`v => `${v}%``). */\n formatOutput?: (v: number | number[]) => ReactNode;\n className?: string;\n};\n\n/**\n * Linear range slider on React Aria. Single-value by default; pass an array\n * to `value` / `defaultValue` for multi-thumb. Distinct from the kit's\n * canvas-scrub `Slider`, which is shaped for tool-canvas interactions.\n */\nexport function RangeSlider(props: RangeSliderProps) {\n const { label, showOutput, formatOutput, className, ...rest } = props;\n const wantOutput = showOutput ?? label !== undefined;\n return (\n <RACSlider {...rest} className={[s.slider, className].filter(Boolean).join(' ')}>\n {(label !== undefined || wantOutput) && (\n <div className={s.head}>\n {label !== undefined && <Label className={s.label}>{label}</Label>}\n {wantOutput && (\n <SliderOutput className={s.output}>\n {({ state }) => {\n const v = state.values.length === 1 ? state.values[0] : state.values;\n return formatOutput ? formatOutput(v) : Array.isArray(v) ? v.join(' – ') : String(v);\n }}\n </SliderOutput>\n )}\n </div>\n )}\n <SliderTrack className={s.track}>\n {({ state }) => {\n // Single-thumb: fill from start to thumb. Multi-thumb: fill\n // between adjacent thumbs (simplest = between first and last).\n const fillStart = state.values.length > 1 ? state.getThumbPercent(0) * 100 : 0;\n const fillEnd = state.getThumbPercent(state.values.length - 1) * 100;\n return (\n <>\n <div\n className={s.fill}\n style={{ left: `${fillStart}%`, right: `${100 - fillEnd}%` }}\n />\n {state.values.map((_, i) => (\n <SliderThumb key={i} index={i} className={s.thumb} />\n ))}\n </>\n );\n }}\n </SliderTrack>\n </RACSlider>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AC2BA,SAAgB,EAAY,GAAyB;CACnD,IAAM,EAAE,UAAO,eAAY,iBAAc,cAAW,GAAG,MAAS,GAC1D,IAAa,KAAc,MAAU,KAAA;AAC3C,QACE,kBAAC,GAAD;EAAW,GAAI;EAAM,WAAW,CAAC,EAAE,QAAQ,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA/E,EACI,MAAU,KAAA,KAAa,MACvB,kBAAC,OAAD;GAAK,WAAW,EAAE;aAAlB,CACG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAE;cAAQ;IAAc,CAAA,EACjE,KACC,kBAAC,GAAD;IAAc,WAAW,EAAE;eACvB,EAAE,eAAY;KACd,IAAM,IAAI,EAAM,OAAO,WAAW,IAAI,EAAM,OAAO,KAAK,EAAM;AAC9D,YAAO,IAAe,EAAa,EAAE,GAAG,MAAM,QAAQ,EAAE,GAAG,EAAE,KAAK,MAAM,GAAG,OAAO,EAAE;;IAEzE,CAAA,CAEb;MAER,kBAAC,GAAD;GAAa,WAAW,EAAE;cACtB,EAAE,eAAY;IAGd,IAAM,IAAY,EAAM,OAAO,SAAS,IAAI,EAAM,gBAAgB,EAAE,GAAG,MAAM,GACvE,IAAU,EAAM,gBAAgB,EAAM,OAAO,SAAS,EAAE,GAAG;AACjE,WACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;KACE,WAAW,EAAE;KACb,OAAO;MAAE,MAAM,GAAG,EAAU;MAAI,OAAO,GAAG,MAAM,EAAQ;MAAI;KAC5D,CAAA,EACD,EAAM,OAAO,KAAK,GAAG,MACpB,kBAAC,GAAD;KAAqB,OAAO;KAAG,WAAW,EAAE;KAAS,EAAnC,EAAmC,CACrD,CACD,EAAA,CAAA;;GAGK,CAAA,CACJ"}
@@ -9,7 +9,7 @@ function a(e, t, n, r) {
9
9
  return i(Number.isInteger(r) ? a : Number(a.toFixed(10)), t, n);
10
10
  }
11
11
  function o(i) {
12
- let { orientation: o = "vertical", value: s, min: c, max: l, invert: u, onChange: d, onChangeEnd: f, step: p = 1, ariaLabel: m, className: h } = i, g = t(null), _ = e((e) => o === "vertical" ? e.clientX : e.clientY, [o]), v = e((e) => {
12
+ let { orientation: o = "vertical", value: s, min: c, max: l, invert: u, onInput: d, onChange: f, step: p = 1, ariaLabel: m, className: h } = i, g = t(null), _ = e((e) => o === "vertical" ? e.clientX : e.clientY, [o]), v = e((e) => {
13
13
  e.button === 0 && (g.current = {
14
14
  origin: _(e),
15
15
  startValue: s
@@ -78,4 +78,4 @@ function o(i) {
78
78
  //#endregion
79
79
  export { o as t };
80
80
 
81
- //# sourceMappingURL=ResizeHandle-BUkW2kZC.js.map
81
+ //# sourceMappingURL=ResizeHandle-BOpmtOOj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResizeHandle-BOpmtOOj.js","names":[],"sources":["../../src/components/ResizeHandle/ResizeHandle.module.css","../../src/components/ResizeHandle/ResizeHandle.tsx"],"sourcesContent":[".handle {\n flex-shrink: 0;\n width: 4px;\n align-self: stretch;\n cursor: ew-resize;\n background: transparent;\n border-left: 1px solid var(--wzl-border);\n /* The bar is 4px of hit area — thin enough to read as a seam, wide\n enough to grab. `touch-action: none` keeps a touch drag from being\n stolen by the scroll container it usually sits inside. */\n touch-action: none;\n}\n\n.handle.horizontal {\n width: auto;\n height: 4px;\n align-self: auto;\n cursor: ns-resize;\n border-left: none;\n border-top: 1px solid var(--wzl-border);\n}\n\n.handle:hover {\n background: var(--wzl-border);\n}\n\n.handle:focus-visible {\n outline: 2px solid var(--wzl-focus-ring, var(--wzl-accent));\n outline-offset: -1px;\n}\n","import { useCallback, useRef, type KeyboardEvent, type PointerEvent } from 'react';\nimport s from './ResizeHandle.module.css';\n\n/**\n * Props for {@link ResizeHandle}. `onInput` fires throughout the drag and\n * `onChange` once at the end.\n */\nexport interface ResizeHandleProps {\n /**\n * Which way the handle *runs*, matching `aria-orientation` on the\n * separator role: a `vertical` handle is a vertical bar between two\n * side-by-side panes and drags horizontally. `horizontal` is the\n * stacked case (a bar between rows, dragged up and down).\n */\n orientation?: 'vertical' | 'horizontal';\n /** Current size of the pane being resized, in pixels. */\n value: number;\n min: number;\n max: number;\n /**\n * Flip the sign of the drag. Panes docked to the *trailing* edge (a\n * right sidebar, a bottom drawer) grow as the pointer moves toward the\n * start of the axis, so they want `invert`. Leading-edge panes don't.\n */\n invert?: boolean;\n /**\n * Fires continuously while dragging and on each keyboard step, always\n * clamped to [min, max]. Drive the live size from this.\n */\n onInput(next: number): void;\n /**\n * Fires once when a drag ends or a keyboard step settles, with the final\n * size. Persist here rather than in `onInput` — one write per gesture\n * instead of one per pointer sample.\n */\n onChange?(next: number): void;\n /**\n * The granularity of `value`. Arrow keys move by one step (Shift by\n * eight), and pointer drags snap to the same grid — a pointer reports\n * fractional coordinates on a scaled display, and nobody wants\n * `362.9453125` in their persisted layout. Set a fractional step for a\n * pane measured in something finer than whole pixels.\n */\n step?: number;\n ariaLabel?: string;\n className?: string;\n}\n\nconst clamp = (n: number, min: number, max: number): number => Math.min(max, Math.max(min, n));\n\n/**\n * Snap to the step grid, then clamp. Bounds win over the grid: `min`/`max`\n * are hard limits, so a range that isn't a whole number of steps clips to\n * the bound rather than overshooting it.\n */\nfunction settle(n: number, min: number, max: number, step: number): number {\n const snapped = step > 0 ? Math.round(n / step) * step : n;\n // Re-round to kill the float dust `x / 0.1 * 0.1` leaves behind.\n const precise = Number.isInteger(step) ? snapped : Number(snapped.toFixed(10));\n return clamp(precise, min, max);\n}\n\n/**\n * Draggable divider for resizing a pane — the \"window splitter\" pattern.\n * Owns no size of its own: the consumer holds `value` and applies it\n * (typically as a CSS custom property on the pane), which keeps the handle\n * usable for flex, grid, and absolutely-positioned layouts alike.\n *\n * Keyboard-operable as a matter of course: it's focusable, arrows step by\n * `step` (Shift for a coarse step), Home/End jump to the bounds. A splitter\n * that only responds to a pointer drag strands anyone who can't make one.\n */\nexport function ResizeHandle(props: ResizeHandleProps) {\n const {\n orientation = 'vertical', value, min, max, invert, onInput, onChange,\n step = 1, ariaLabel, className,\n } = props;\n\n // Drag origin. Captured on pointerdown so every move is measured against\n // the gesture's start rather than the previous sample — accumulating\n // per-sample deltas drifts once the pointer leaves the clamped range.\n const drag = useRef<{ origin: number; startValue: number } | null>(null);\n\n const axisOf = useCallback(\n (e: PointerEvent<HTMLDivElement>) => (orientation === 'vertical' ? e.clientX : e.clientY),\n [orientation],\n );\n\n const onPointerDown = useCallback((e: PointerEvent<HTMLDivElement>) => {\n if (e.button !== 0) return;\n drag.current = { origin: axisOf(e), startValue: value };\n // jsdom has no pointer capture; the guard keeps tests on the real path.\n e.currentTarget.setPointerCapture?.(e.pointerId);\n e.preventDefault();\n }, [axisOf, value]);\n\n const onPointerMove = useCallback((e: PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n const delta = axisOf(e) - d.origin;\n onInput(settle(d.startValue + (invert ? -delta : delta), min, max, step));\n }, [axisOf, invert, max, min, onInput, step]);\n\n const endDrag = useCallback((e: PointerEvent<HTMLDivElement>) => {\n const d = drag.current;\n if (!d) return;\n drag.current = null;\n e.currentTarget.releasePointerCapture?.(e.pointerId);\n const delta = axisOf(e) - d.origin;\n onChange?.(settle(d.startValue + (invert ? -delta : delta), min, max, step));\n }, [axisOf, invert, max, min, onChange, step]);\n\n const onKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {\n const grow = orientation === 'vertical' ? 'ArrowRight' : 'ArrowDown';\n const shrink = orientation === 'vertical' ? 'ArrowLeft' : 'ArrowUp';\n const amount = step * (e.shiftKey ? 8 : 1) * (invert ? -1 : 1);\n let next: number | undefined;\n if (e.key === grow) next = value + amount;\n else if (e.key === shrink) next = value - amount;\n else if (e.key === 'Home') next = invert ? max : min;\n else if (e.key === 'End') next = invert ? min : max;\n if (next === undefined) return;\n e.preventDefault();\n const settled = settle(next, min, max, step);\n onInput(settled);\n onChange?.(settled);\n }, [invert, max, min, onInput, onChange, orientation, step, value]);\n\n const cls = [s.handle, orientation === 'horizontal' && s.horizontal, className]\n .filter(Boolean).join(' ');\n\n return (\n <div\n className={cls}\n role=\"separator\"\n tabIndex={0}\n aria-label={ariaLabel}\n aria-orientation={orientation}\n aria-valuenow={value}\n aria-valuemin={min}\n aria-valuemax={max}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={onKeyDown}\n />\n );\n}\n"],"mappings":";;;;;GCgDM,KAAS,GAAW,GAAa,MAAwB,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,EAAE,CAAC;AAO9F,SAAS,EAAO,GAAW,GAAa,GAAa,GAAsB;CACzE,IAAM,IAAU,IAAO,IAAI,KAAK,MAAM,IAAI,EAAK,GAAG,IAAO;AAGzD,QAAO,EADS,OAAO,UAAU,EAAK,GAAG,IAAU,OAAO,EAAQ,QAAQ,GAAG,CAAC,EACxD,GAAK,EAAI;;AAajC,SAAgB,EAAa,GAA0B;CACrD,IAAM,EACJ,iBAAc,YAAY,UAAO,QAAK,QAAK,WAAQ,YAAS,aAC5D,UAAO,GAAG,cAAW,iBACnB,GAKE,IAAO,EAAsD,KAAK,EAElE,IAAS,GACZ,MAAqC,MAAgB,aAAa,EAAE,UAAU,EAAE,SACjF,CAAC,EAAY,CACd,EAEK,IAAgB,GAAa,MAAoC;AACjE,IAAE,WAAW,MACjB,EAAK,UAAU;GAAE,QAAQ,EAAO,EAAE;GAAE,YAAY;GAAO,EAEvD,EAAE,cAAc,oBAAoB,EAAE,UAAU,EAChD,EAAE,gBAAgB;IACjB,CAAC,GAAQ,EAAM,CAAC,EAEb,IAAgB,GAAa,MAAoC;EACrE,IAAM,IAAI,EAAK;AACf,MAAI,CAAC,EAAG;EACR,IAAM,IAAQ,EAAO,EAAE,GAAG,EAAE;AAC5B,IAAQ,EAAO,EAAE,cAAc,IAAS,CAAC,IAAQ,IAAQ,GAAK,GAAK,EAAK,CAAC;IACxE;EAAC;EAAQ;EAAQ;EAAK;EAAK;EAAS;EAAK,CAAC,EAEvC,IAAU,GAAa,MAAoC;EAC/D,IAAM,IAAI,EAAK;AACf,MAAI,CAAC,EAAG;AAER,EADA,EAAK,UAAU,MACf,EAAE,cAAc,wBAAwB,EAAE,UAAU;EACpD,IAAM,IAAQ,EAAO,EAAE,GAAG,EAAE;AAC5B,MAAW,EAAO,EAAE,cAAc,IAAS,CAAC,IAAQ,IAAQ,GAAK,GAAK,EAAK,CAAC;IAC3E;EAAC;EAAQ;EAAQ;EAAK;EAAK;EAAU;EAAK,CAAC,EAExC,IAAY,GAAa,MAAqC;EAClE,IAAM,IAAO,MAAgB,aAAa,eAAe,aACnD,IAAS,MAAgB,aAAa,cAAc,WACpD,IAAS,KAAQ,EAAE,WAAW,IAAI,MAAM,IAAS,KAAK,IACxD;AAKJ,MAJI,EAAE,QAAQ,IAAM,IAAO,IAAQ,IAC1B,EAAE,QAAQ,IAAQ,IAAO,IAAQ,IACjC,EAAE,QAAQ,SAAQ,IAAO,IAAS,IAAM,IACxC,EAAE,QAAQ,UAAO,IAAO,IAAS,IAAM,IAC5C,MAAS,KAAA,EAAW;AACxB,IAAE,gBAAgB;EAClB,IAAM,IAAU,EAAO,GAAM,GAAK,GAAK,EAAK;AAE5C,EADA,EAAQ,EAAQ,EAChB,IAAW,EAAQ;IAClB;EAAC;EAAQ;EAAK;EAAK;EAAS;EAAU;EAAa;EAAM;EAAM,CAAC;AAKnE,QACE,kBAAC,OAAD;EACE,WALQ;GAAC,EAAE;GAAQ,MAAgB,gBAAgB,EAAE;GAAY;GAAU,CAC5E,OAAO,QAAQ,CAAC,KAAK,IAIT;EACX,MAAK;EACL,UAAU;EACV,cAAY;EACZ,oBAAkB;EAClB,iBAAe;EACf,iBAAe;EACf,iBAAe;EACA;EACA;EACf,aAAa;EACb,iBAAiB;EACN;EACX,CAAA"}
@@ -1,4 +1,4 @@
1
- import { n as e } from "./Field-DPxmJzZz.js";
1
+ import { n as e } from "./Field-VQwmrIna.js";
2
2
  import { Button as t, FieldError as n, Label as r, ListBox as i, ListBoxItem as a, Popover as o, Select as s, SelectValue as c, Text as l } from "react-aria-components";
3
3
  import { jsx as u, jsxs as d } from "react/jsx-runtime";
4
4
  var f = {
@@ -100,4 +100,4 @@ function h({ children: e, className: t, textValue: n, ...r }) {
100
100
  //#endregion
101
101
  export { h as n, p as t };
102
102
 
103
- //# sourceMappingURL=Select-DC0AjrEe.js.map
103
+ //# sourceMappingURL=Select-BE3Y1NrH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Select-BE3Y1NrH.js","names":[],"sources":["../../src/components/Select/Select.module.css","../../src/components/Select/Select.tsx"],"sourcesContent":[".field {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n gap: 4px;\n}\n\n.trigger {\n display: flex;\n width: 100%;\n align-items: center;\n gap: 6px;\n height: 24px;\n padding: 0 6px 0 10px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n line-height: 1;\n cursor: pointer;\n transition: border-color var(--wzl-motion-fast), box-shadow var(--wzl-motion-fast);\n}\n\n.trigger[data-focus-visible] {\n border-color: var(--wzl-focus-ring);\n box-shadow: 0 0 0 1px var(--wzl-focus-ring);\n}\n\n.field[data-invalid] .trigger {\n border-color: var(--wzl-danger, #ff5b5b);\n}\n\n.trigger[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.value {\n flex: 1;\n min-width: 0;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.value[data-placeholder] {\n color: var(--wzl-fg-subtle);\n}\n\n.chevron {\n width: 10px;\n height: 10px;\n color: var(--wzl-fg-muted);\n flex: 0 0 auto;\n}\n\n.popover {\n min-width: var(--trigger-width);\n max-height: inherit;\n outline: none;\n}\n\n.listbox {\n background: var(--wzl-surface-raised);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-md);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);\n padding: 4px;\n max-height: 280px;\n overflow: auto;\n outline: none;\n font-family: var(--wzl-font-ui);\n font-size: 13px;\n}\n\n.option {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 8px;\n border-radius: 3px;\n cursor: pointer;\n color: var(--wzl-fg);\n outline: none;\n}\n\n.option[data-focused] {\n background: color-mix(in srgb, var(--wzl-fg) 10%, transparent);\n}\n\n.option[data-selected] {\n color: var(--wzl-fg);\n font-weight: 500;\n}\n\n.option[data-disabled] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n\n.check {\n width: 10px;\n height: 10px;\n flex: 0 0 auto;\n opacity: 0;\n}\n\n.option[data-selected] .check {\n opacity: 1;\n}\n","import type { ReactNode } from 'react';\nimport {\n Select as RACSelect,\n Label,\n Button as RACButton,\n SelectValue,\n Popover as RACPopover,\n ListBox as RACListBox,\n ListBoxItem as RACListBoxItem,\n Text,\n FieldError,\n type SelectProps as RACSelectProps,\n type ListBoxItemProps as RACListBoxItemProps,\n type ValidationResult,\n} from 'react-aria-components';\nimport { fieldClasses } from '../Field/Field';\nimport s from './Select.module.css';\n\n/** One option in a {@link Select}'s `options` list. */\nexport type SelectOption = {\n value: string;\n label: ReactNode;\n isDisabled?: boolean;\n /**\n * Plain-text form of `label`, for type-to-select and screen readers.\n * Only needed when `label` isn't a bare string — a label built from\n * elements has no text React Aria can read off it. A string label\n * supplies this itself.\n */\n textValue?: string;\n};\n\ntype Key = string | number;\n\n/**\n * Props for {@link Select}, on top of React Aria's `Select` props, with the\n * selection key narrowed to the option value type.\n */\nexport type SelectProps<T extends Key = string> = Omit<RACSelectProps<object>, 'children' | 'className' | 'selectedKey' | 'defaultSelectedKey' | 'onSelectionChange'> & {\n label?: ReactNode;\n description?: ReactNode;\n errorMessage?: ReactNode | ((v: ValidationResult) => ReactNode);\n placeholder?: string;\n /** Either pass `options` for a quick render, or `children` for full control. */\n options?: ReadonlyArray<SelectOption & { value: T }>;\n children?: ReactNode;\n selectedKey?: T | null;\n defaultSelectedKey?: T;\n onSelectionChange?: (key: T) => void;\n className?: string;\n};\n\n/**\n * Form select wrapping React Aria's Select. Pass either `options` for a\n * quick declarative render or `children` of `<SelectItem>` for control over\n * each row.\n *\n * The selection key type is parameterized so consumers with a string-literal\n * union for `value` (e.g. `'r' | 'g' | 'b'`) get a typed `onSelectionChange`.\n */\nexport function Select<T extends Key = string>(props: SelectProps<T>) {\n const {\n label,\n description,\n errorMessage,\n placeholder,\n options,\n children,\n selectedKey,\n defaultSelectedKey,\n onSelectionChange,\n className,\n ...rest\n } = props;\n\n return (\n <RACSelect\n {...rest}\n selectedKey={selectedKey ?? undefined}\n defaultSelectedKey={defaultSelectedKey}\n onSelectionChange={onSelectionChange ? (k) => onSelectionChange(k as T) : undefined}\n className={[s.field, fieldClasses.root, className].filter(Boolean).join(' ')}\n >\n {label !== undefined && <Label className={fieldClasses.label}>{label}</Label>}\n <RACButton className={s.trigger}>\n <SelectValue className={s.value}>\n {({ defaultChildren, isPlaceholder }) =>\n isPlaceholder ? (placeholder ?? defaultChildren) : defaultChildren\n }\n </SelectValue>\n <svg className={s.chevron} viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M2 4 L5 7 L8 4\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </RACButton>\n {description !== undefined && (\n <Text slot=\"description\" className={fieldClasses.hint}>\n {description}\n </Text>\n )}\n <FieldError className={fieldClasses.error}>{errorMessage}</FieldError>\n {/* `data-weasel-overlay` marks DOM that belongs to this control but\n renders in a portal, outside the subtree the trigger sits in. Any\n consumer reasoning about \"did focus leave my component?\" via\n `closest()` gets the wrong answer without it — a text editor whose\n font menu lives here would end its session the moment the menu is\n clicked. */}\n <RACPopover className={s.popover} data-weasel-overlay=\"\">\n <RACListBox className={s.listbox}>\n {options !== undefined\n ? options.map((o) => (\n <SelectItem\n key={String(o.value)}\n id={o.value}\n isDisabled={o.isDisabled}\n textValue={o.textValue}\n >\n {o.label}\n </SelectItem>\n ))\n : children}\n </RACListBox>\n </RACPopover>\n </RACSelect>\n );\n}\n\n/** Props for {@link SelectItem}, on top of React Aria's `ListBoxItem` props. */\nexport type SelectItemProps = Omit<RACListBoxItemProps, 'className' | 'children'> & {\n children?: ReactNode;\n className?: string;\n};\n\n/**\n * Every row renders a check mark beside its label, so from React Aria's\n * side the children are never plain text and it can't derive the string\n * type-to-select and screen readers need — it warns once per row. A string\n * label already *is* that string, so derive it rather than making every\n * call site restate it; anything richer has to say what it reads as.\n */\nfunction textValueOf(children: ReactNode, explicit: string | undefined): string | undefined {\n if (explicit !== undefined) return explicit;\n return typeof children === 'string' || typeof children === 'number'\n ? String(children)\n : undefined;\n}\n\n/**\n * One row in a {@link Select}'s list, with a leading check mark when\n * selected. A string child supplies its own `textValue`; anything richer must\n * pass one so type-to-select and screen readers have something to read.\n */\nexport function SelectItem({ children, className, textValue, ...rest }: SelectItemProps) {\n return (\n <RACListBoxItem\n {...rest}\n textValue={textValueOf(children, textValue)}\n className={[s.option, className].filter(Boolean).join(' ')}\n >\n <svg className={s.check} viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <polyline points=\"1.5,5 4,7.5 8.5,3\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.6\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n {children}\n </RACListBoxItem>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AC4DA,SAAgB,EAA+B,GAAuB;CACpE,IAAM,EACJ,UACA,gBACA,iBACA,gBACA,YACA,aACA,gBACA,uBACA,sBACA,cACA,GAAG,MACD;AAEJ,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,aAAa,KAAe,KAAA;EACR;EACpB,mBAAmB,KAAqB,MAAM,EAAkB,EAAO,GAAG,KAAA;EAC1E,WAAW;GAAC,EAAE;GAAO,EAAa;GAAM;GAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAL9E;GAOG,MAAU,KAAA,KAAa,kBAAC,GAAD;IAAO,WAAW,EAAa;cAAQ;IAAc,CAAA;GAC7E,kBAAC,GAAD;IAAW,WAAW,EAAE;cAAxB,CACE,kBAAC,GAAD;KAAa,WAAW,EAAE;gBACtB,EAAE,oBAAiB,uBACnB,IAAiB,KAAe,IAAmB;KAEzC,CAAA,EACd,kBAAC,OAAD;KAAK,WAAW,EAAE;KAAS,SAAQ;KAAY,eAAY;eACzD,kBAAC,QAAD;MAAM,GAAE;MAAiB,MAAK;MAAO,QAAO;MAAe,aAAY;MAAM,eAAc;MAAQ,gBAAe;MAAU,CAAA;KACxH,CAAA,CACI;;GACX,MAAgB,KAAA,KACf,kBAAC,GAAD;IAAM,MAAK;IAAc,WAAW,EAAa;cAC9C;IACI,CAAA;GAET,kBAAC,GAAD;IAAY,WAAW,EAAa;cAAQ;IAA0B,CAAA;GAOtE,kBAAC,GAAD;IAAY,WAAW,EAAE;IAAS,uBAAoB;cACpD,kBAAC,GAAD;KAAY,WAAW,EAAE;eACtB,MAAY,KAAA,IAWT,IAVA,EAAQ,KAAK,MACX,kBAAC,GAAD;MAEE,IAAI,EAAE;MACN,YAAY,EAAE;MACd,WAAW,EAAE;gBAEZ,EAAE;MACQ,EANN,OAAO,EAAE,MAAM,CAMT,CACb;KAEK,CAAA;IACF,CAAA;GACH;;;AAiBhB,SAAS,EAAY,GAAqB,GAAkD;AAE1F,QADI,MAAa,KAAA,IACV,OAAO,KAAa,YAAY,OAAO,KAAa,WACvD,OAAO,EAAS,GAChB,KAAA,IAH+B;;AAWrC,SAAgB,EAAW,EAAE,aAAU,cAAW,cAAW,GAAG,KAAyB;AACvF,QACE,kBAAC,GAAD;EACE,GAAI;EACJ,WAAW,EAAY,GAAU,EAAU;EAC3C,WAAW,CAAC,EAAE,QAAQ,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAH5D,CAKE,kBAAC,OAAD;GAAK,WAAW,EAAE;GAAO,SAAQ;GAAY,eAAY;aACvD,kBAAC,YAAD;IAAU,QAAO;IAAoB,MAAK;IAAO,QAAO;IAAe,aAAY;IAAM,eAAc;IAAQ,gBAAe;IAAU,CAAA;GACpI,CAAA,EACL,EACc"}
@@ -1,8 +1,8 @@
1
- import { t as e } from "./ColorField-B4Hd2qqS.js";
2
- import { t } from "./Input-Dg_CYXg4.js";
3
- import { t as n } from "./NumberField-BhxUgi43.js";
4
- import { t as r } from "./Select-DC0AjrEe.js";
5
- import { t as i } from "./Switch-I4putUAY.js";
1
+ import { t as e } from "./ColorField-ykpiD3XU.js";
2
+ import { t } from "./Input-DpkwYtUY.js";
3
+ import { t as n } from "./NumberField-BbzI0GtU.js";
4
+ import { t as r } from "./Select-BE3Y1NrH.js";
5
+ import { t as i } from "./Switch-JyVSSAzC.js";
6
6
  import { Fragment as a, useState as o, useSyncExternalStore as s } from "react";
7
7
  import { MIXED as c, asNodeId as l } from "@weasel-js/core";
8
8
  import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
@@ -300,4 +300,4 @@ function O({ text: e, placeholder: n, ariaLabel: r, onCommit: i }) {
300
300
  //#endregion
301
301
  export { _ as a, y as c, p as i, c as n, x as o, b as r, v as s, w as t };
302
302
 
303
- //# sourceMappingURL=SelectionPanel-DoTdisRY.js.map
303
+ //# sourceMappingURL=SelectionPanel-Zaw8tYQH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SelectionPanel-Zaw8tYQH.js","names":[],"sources":["../../src/components/SelectionPanel/model.ts","../../src/components/SelectionPanel/SelectionPanel.module.css","../../src/components/SelectionPanel/SelectionPanel.tsx"],"sourcesContent":["// Pure selection→panel derivations for SelectionPanel. Kept free of\n// React so intersection/aggregation semantics are unit-testable.\n//\n// Path convention (see core `NodePropertiesEntry`): a leaf's OWN KEY in\n// the schema is its node path — a dotted path of any depth rooted at\n// `pose` or `data` (`pose.x`, `data.fill`, `data.style.fontSize`). Group\n// keys are organizational only.\n\nimport {\n MIXED,\n type Mixed,\n type NodePropertiesEntry,\n type NodeRoutingEntry,\n type SceneNode,\n type ToolPrefGroup,\n type ToolPrefLeaf,\n} from '@weasel-js/core';\n\n// Re-exported under its existing public name here: the kit-wide \"these\n// values disagree\" sentinel (`@weasel-js/core`'s `MIXED`) also covers\n// multi-node aggregation, so this panel doesn't get its own symbol.\nexport { MIXED };\nexport type { Mixed };\n\nexport type AnyNode = SceneNode<unknown, string, unknown>;\n\n/**\n * One editable property in a {@link SelectionPanel}, paired with the dotted\n * node path it reads and writes.\n */\nexport interface PanelLeaf {\n /** Dotted node path — the leaf's key in the schema. */\n path: string;\n leaf: ToolPrefLeaf;\n}\n\n/**\n * One labeled row of a panel section. Holds several leaves when the schema\n * paired them.\n */\nexport interface PanelRow {\n label: string;\n leaves: PanelLeaf[];\n}\n\n/**\n * A titled block of rows, derived from one top-level group of a properties\n * schema. `key` is that group's schema key.\n */\nexport interface PanelSection {\n key: string;\n name: string;\n rows: PanelRow[];\n}\n\n/** Derive a node's kind: containers are `'group'`; leaves classify their\n * `data` through the routing entries (first match wins, `'unknown'`\n * otherwise) — same semantics as core's `NodeRouting.classify`. */\nexport function classifyKind(\n node: AnyNode,\n routing: readonly NodeRoutingEntry[],\n): string {\n if (node.kind === 'container') return 'group';\n for (const entry of routing) {\n if (entry.matches(node.data)) return entry.name;\n }\n return 'unknown';\n}\n\nfunction isGroup(n: ToolPrefLeaf | ToolPrefGroup): n is ToolPrefGroup {\n return !('kind' in n);\n}\n\n/** Flatten a schema to sections of leaves. Nested groups fold into their\n * top-level section; top-level leaves get an untitled leading section. */\nfunction flatten(schema: ToolPrefGroup): PanelSection[] {\n const sections: PanelSection[] = [];\n const untitled: PanelLeaf[] = [];\n\n const collect = (group: ToolPrefGroup, into: PanelLeaf[]): void => {\n for (const [key, child] of Object.entries(group.children)) {\n if (isGroup(child)) collect(child, into);\n else into.push({ path: key, leaf: child });\n }\n };\n\n for (const [key, child] of Object.entries(schema.children)) {\n if (isGroup(child)) {\n const leaves: PanelLeaf[] = [];\n collect(child, leaves);\n sections.push({ key, name: child.name, rows: pairRows(leaves) });\n } else {\n untitled.push({ path: key, leaf: child });\n }\n }\n if (untitled.length > 0) {\n sections.unshift({ key: '', name: '', rows: pairRows(untitled) });\n }\n return sections;\n}\n\n/** Merge consecutive leaves sharing a `pair` id into one labeled row. */\nfunction pairRows(leaves: readonly PanelLeaf[]): PanelRow[] {\n const rows: PanelRow[] = [];\n for (const item of leaves) {\n const pair = item.leaf.pair;\n const prev = rows[rows.length - 1];\n if (pair !== undefined && prev !== undefined && prev.label === pair) {\n prev.leaves.push(item);\n } else {\n rows.push({ label: pair ?? item.leaf.name, leaves: [item] });\n }\n }\n return rows;\n}\n\n/**\n * The schema the panel shows for a set of kinds: one kind → its full\n * schema; several → the intersection by (path, leaf kind), shaped by the\n * first kind's section/row layout. Kinds without a registered schema\n * contribute nothing, so their presence collapses the intersection.\n */\nexport function effectiveSections(\n kinds: readonly string[],\n entries: readonly NodePropertiesEntry[],\n): PanelSection[] {\n const uniq = [...new Set(kinds)];\n if (uniq.length === 0) return [];\n const byName = new Map(entries.map((e) => [e.name, e]));\n const schemas = uniq.map((k) => byName.get(k)?.schema);\n if (schemas.some((s) => s === undefined)) return [];\n const [first, ...rest] = schemas as ToolPrefGroup[];\n\n const flatFirst = flatten(first);\n if (rest.length === 0) return flatFirst;\n\n // '\\0' delimiter: path and kind strings are unconstrained, so a\n // printable separator could collide with real content.\n const leafKey = (l: PanelLeaf): string => `${l.path}\\0${l.leaf.kind}`;\n const restKeys = rest.map(\n (schema) =>\n new Set(\n flatten(schema)\n .flatMap((s) => s.rows)\n .flatMap((r) => r.leaves)\n .map(leafKey),\n ),\n );\n const keep = (l: PanelLeaf): boolean =>\n restKeys.every((set) => set.has(leafKey(l)));\n\n return flatFirst\n .map((section) => ({\n ...section,\n rows: section.rows\n .map((row) => ({ ...row, leaves: row.leaves.filter(keep) }))\n .filter((row) => row.leaves.length > 0),\n }))\n .filter((section) => section.rows.length > 0);\n}\n\n/** Read a node value at a dotted path of any depth (`pose.x`,\n * `data.style.fontSize`, `data.style.fill.color`). Returns `undefined` if\n * the path is dotless (mirrors `commit`'s no-op on a malformed schema\n * key) or if any intermediate segment is missing or not an object. */\nexport function nodeValueAt(node: AnyNode, path: string): unknown {\n const segments = path.split('.');\n if (segments.length < 2) return undefined;\n const head = segments[0];\n let cursor: unknown = head === 'pose' ? node.pose : head === 'data' ? node.data : undefined;\n for (let i = 1; i < segments.length; i++) {\n if (cursor == null || typeof cursor !== 'object') return undefined;\n cursor = (cursor as Record<string, unknown>)[segments[i]];\n }\n return cursor;\n}\n\n/** Immutably set `value` at a dotted path within `root`, cloning each level\n * on the way down so React sees new object identities. Arrays stay arrays\n * (an array intermediate is shallow-copied, not flattened into `{0: ...}`)\n * — this is the write-side twin of `nodeValueAt`, so a schema author who\n * gets a working read gets a working write. */\nexport function setAtPath(root: object, segments: readonly string[], value: unknown): object {\n const [head, ...rest] = segments;\n if (rest.length === 0) {\n return Array.isArray(root)\n ? Object.assign([...root], { [head]: value })\n : { ...root, [head]: value };\n }\n const child = (root as Record<string, unknown>)[head];\n const childObj = Array.isArray(child)\n ? [...child]\n : child != null && typeof child === 'object'\n ? { ...child }\n : {};\n const nested = setAtPath(childObj, rest, value);\n return Array.isArray(root)\n ? Object.assign([...root], { [head]: nested })\n : { ...root, [head]: nested };\n}\n\n/** Aggregate a path across nodes: the shared value, or `MIXED`. */\nexport function aggregateValue(\n nodes: readonly AnyNode[],\n path: string,\n): unknown | Mixed {\n let value: unknown;\n let first = true;\n for (const node of nodes) {\n const v = nodeValueAt(node, path);\n if (first) {\n value = v;\n first = false;\n } else if (!Object.is(v, value)) {\n return MIXED;\n }\n }\n return value;\n}\n\n/** `'rect ×2 · text'` — kinds in first-seen order with counts. */\nexport function kindBreakdown(kinds: readonly string[]): string {\n const counts = new Map<string, number>();\n for (const k of kinds) counts.set(k, (counts.get(k) ?? 0) + 1);\n return [...counts.entries()]\n .map(([k, n]) => (n > 1 ? `${k} ×${n}` : k))\n .join(' · ');\n}\n",".root {\n display: flex;\n flex-direction: column;\n font-size: 12px;\n color: var(--wzl-fg);\n}\n\n.header {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 8px 10px;\n border-block-end: 1px solid var(--wzl-border);\n}\n\n.kind {\n font-weight: 600;\n font-size: 13px;\n}\n\n.breakdown {\n font-size: 11px;\n opacity: 0.6;\n}\n\n.section {\n padding: 6px 10px 8px;\n border-block-end: 1px solid var(--wzl-border);\n}\n\n.section:last-child {\n border-block-end: none;\n}\n\n.sectionTitle {\n margin: 0 0 6px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n opacity: 0.55;\n}\n\n.row {\n display: grid;\n grid-template-columns: 64px 1fr;\n gap: 6px;\n align-items: center;\n margin-block-end: 5px;\n}\n\n.rowLabel {\n opacity: 0.75;\n}\n\n.rowControls {\n display: flex;\n gap: 6px;\n align-items: center;\n min-inline-size: 0;\n}\n\n.rowControls > * {\n flex: 1;\n min-inline-size: 0;\n}\n\n.number :global(input),\n.select {\n font-size: 11px;\n}\n\n.unitSuffix {\n flex: none;\n font-size: 11px;\n opacity: 0.6;\n}\n\n.mixedSwitch {\n opacity: 0.55;\n}\n\n.unrenderable {\n font-size: 11px;\n opacity: 0.5;\n font-style: italic;\n}\n","import { Fragment, useState, useSyncExternalStore, type ReactNode } from 'react';\nimport {\n asNodeId,\n type NodePropertiesEntry,\n type NodeRoutingEntry,\n type Scene,\n type SelectionApi,\n type ToolPrefColor,\n type ToolPrefEnum,\n type ToolPrefLeaf,\n type ToolPrefNumber,\n type ToolPrefPaint,\n} from '@weasel-js/core';\nimport { ColorField } from '../ColorField';\nimport { Input } from '../Input';\nimport { NumberField } from '../NumberField';\nimport { Select } from '../Select';\nimport { Switch } from '../Switch';\nimport {\n MIXED,\n aggregateValue,\n classifyKind,\n effectiveSections,\n kindBreakdown,\n setAtPath,\n type AnyNode,\n type PanelLeaf,\n} from './model';\nimport s from './SelectionPanel.module.css';\n\n/** What a {@link PropertyRenderer} is given for the property it is rendering. */\nexport interface PropertyRenderContext {\n /** Dotted node path of the leaf (`pose.x`, `data.fill`). */\n path: string;\n /** The schema leaf. App renderers narrow it to their own kind shape. */\n pref: ToolPrefLeaf;\n /** Aggregated value across the selection; `undefined` when mixed. */\n value: unknown;\n /** True when selected nodes disagree at this path. */\n mixed: boolean;\n /** Commit a value — fans out to every selected node in one undo step. */\n setValue: (value: unknown) => void;\n}\n\n/**\n * Renders the control for one property across the whole selection.\n * Returning `null` collapses the leaf.\n */\nexport type PropertyRenderer = (ctx: PropertyRenderContext) => ReactNode;\n\n/** Props for {@link SelectionPanel}. */\nexport interface SelectionPanelProps<TData, TLayer extends string, TPose> {\n /** The scene handle (`useScene`). The panel subscribes itself, so it\n * re-renders on scene mutations regardless of parent renders. */\n scene: Scene<TData, TLayer, TPose>;\n /** Selection handle (`useSelection`). Only `current` is read. */\n selection: Pick<SelectionApi, 'current'>;\n /** Properties-trait entries, e.g. core's `defaultNodeProperties` /\n * `inferredNodeProperties` (+ consumer extras). Memoize or hoist. */\n properties: readonly NodePropertiesEntry[];\n /** Routing-trait classifiers used to derive each node's kind — pass\n * the same list the canvas uses. Memoize or hoist. */\n routing: readonly NodeRoutingEntry[];\n /** Control overrides / app-defined kinds (PrefsForm-style). Keys are\n * leaf paths (`data.fill`, checked first) or leaf kinds (`color`).\n * A renderer returning `null` collapses its leaf (and the row, when\n * every leaf in it collapses). */\n renderers?: Record<string, PropertyRenderer>;\n /** Kind → header label. Default: capitalized kind name. */\n kindLabel?: (kind: string) => string;\n /** Rendered when the selection is empty. */\n emptyState?: ReactNode;\n className?: string;\n}\n\nconst defaultKindLabel = (kind: string): string =>\n kind.length === 0 ? kind : kind[0].toUpperCase() + kind.slice(1);\n\n/**\n * Pre-baked selection properties panel. Shows the selected nodes' kind\n * and the properties-trait schema for that kind; multi-selections show\n * the intersection of the kinds' schemas with per-field Mixed state.\n * Edits commit as one labeled `scene.batch` fan-out per gesture.\n */\nexport function SelectionPanel<TData, TLayer extends string, TPose>(\n props: SelectionPanelProps<TData, TLayer, TPose>,\n) {\n const {\n scene,\n selection,\n properties,\n routing,\n renderers,\n kindLabel = defaultKindLabel,\n emptyState = null,\n className,\n } = props;\n\n useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);\n\n const nodes = selection.current\n .map((id) => scene.get(asNodeId(id)))\n .filter((n): n is NonNullable<typeof n> => n != null) as readonly AnyNode[];\n\n const kinds = nodes.map((n) => classifyKind(n, routing));\n const sections = effectiveSections(kinds, properties);\n\n if (nodes.length === 0) {\n return <div className={[s.root, className].filter(Boolean).join(' ')}>{emptyState}</div>;\n }\n\n const commit = (leaf: PanelLeaf, value: unknown): void => {\n const [head, ...rest] = leaf.path.split('.');\n if (rest.length === 0) return;\n const ids = selection.current.map(asNodeId);\n scene.batch(`Edit ${leaf.leaf.name}`, () => {\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n // `setAtPath` spreads plain objects/arrays down the schema path;\n // consumer `pose`/`data` are assumed plain-object-shaped along\n // that path (a class instance's prototype would be dropped by\n // the spread) — the `as TPose`/`as TData` casts below rely on it.\n if (head === 'pose') {\n scene.setPose(id, setAtPath(node.pose as object, rest, value) as TPose);\n } else if (head === 'data') {\n scene.update(id, { data: setAtPath(node.data as object, rest, value) as TData });\n }\n }\n });\n };\n\n return (\n <div className={[s.root, className].filter(Boolean).join(' ')}>\n <header className={s.header}>\n {nodes.length === 1 ? (\n <span className={s.kind}>{kindLabel(kinds[0])}</span>\n ) : (\n <>\n <span className={s.kind}>{nodes.length} selected</span>\n <span className={s.breakdown}>{kindBreakdown(kinds)}</span>\n </>\n )}\n </header>\n {sections.map((section) => {\n // Render controls before emitting row chrome so a null-rendering\n // leaf (custom renderer opting out) collapses its cell — and the\n // whole row / section when nothing survives. PrefsForm precedent.\n const rows = section.rows\n .map((row) => {\n const controls = row.leaves\n .map((panelLeaf) => ({\n panelLeaf,\n content: renderLeafControl(\n panelLeaf,\n row.leaves.length > 1\n ? `${row.label} ${panelLeaf.leaf.name}`\n : panelLeaf.leaf.name,\n nodes,\n renderers,\n commit,\n ),\n }))\n .filter((c) => c.content != null);\n return { row, controls };\n })\n .filter(({ controls }) => controls.length > 0);\n if (rows.length === 0) return null;\n return (\n <section key={section.key} className={s.section}>\n {section.name !== '' && <h3 className={s.sectionTitle}>{section.name}</h3>}\n {rows.map(({ row, controls }) => (\n <div key={row.leaves[0].path} className={s.row}>\n <span className={s.rowLabel} title={row.leaves[0].leaf.description}>\n {row.label}\n </span>\n <span className={s.rowControls}>\n {controls.map(({ panelLeaf, content }) => (\n <Fragment key={panelLeaf.path}>{content}</Fragment>\n ))}\n </span>\n </div>\n ))}\n </section>\n );\n })}\n </div>\n );\n}\n\nfunction renderLeafControl(\n panelLeaf: PanelLeaf,\n ariaLabel: string,\n nodes: readonly AnyNode[],\n renderers: Record<string, PropertyRenderer> | undefined,\n commit: (leaf: PanelLeaf, value: unknown) => void,\n): ReactNode {\n const { path, leaf } = panelLeaf;\n const aggregated = aggregateValue(nodes, path);\n const mixed = aggregated === MIXED;\n const value = mixed ? undefined : aggregated;\n\n const ctx: PropertyRenderContext = {\n path,\n pref: leaf,\n value,\n mixed,\n setValue: (v) => commit(panelLeaf, v),\n };\n\n const custom = renderers?.[path] ?? renderers?.[leaf.kind];\n if (custom) return custom(ctx);\n return renderBuiltin(ctx, ariaLabel);\n}\n\n/** The color of a solid `FillStyle`, or `undefined` for anything else —\n * including a value that isn't a paint at all. `fill` is optional on the\n * solid member of the union, so the tag alone can't decide it. */\nfunction solidColorOf(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null) return undefined;\n const paint = value as { fill?: string; color?: unknown };\n if (paint.fill !== undefined && paint.fill !== 'solid') return undefined;\n return typeof paint.color === 'string' ? paint.color : undefined;\n}\n\nfunction renderBuiltin(ctx: PropertyRenderContext, ariaLabel: string): ReactNode {\n const { pref, value, mixed, setValue } = ctx;\n switch (pref.kind) {\n case 'number': {\n const p = pref as ToolPrefNumber;\n const stored = typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n const display = stored !== undefined ? (p.unit ? p.unit.toDisplay(stored) : stored) : NaN;\n const field = (\n <NumberField\n className={s.number}\n value={mixed || stored === undefined ? NaN : display}\n placeholder={mixed ? 'Mixed' : undefined}\n minValue={p.min}\n maxValue={p.max}\n step={p.step ?? 1}\n hideSteppers\n aria-label={ariaLabel}\n onChange={(n) => {\n if (Number.isNaN(n)) return;\n setValue(p.unit ? p.unit.fromDisplay(n) : n);\n }}\n />\n );\n if (p.unit?.suffix === undefined) return field;\n return (\n <>\n {field}\n <span className={s.unitSuffix} aria-hidden=\"true\">\n {p.unit.suffix}\n </span>\n </>\n );\n }\n case 'string': {\n return (\n <DraftInput\n text={mixed ? undefined : typeof value === 'string' ? value : ''}\n placeholder={mixed ? 'Mixed' : undefined}\n ariaLabel={ariaLabel}\n onCommit={setValue}\n />\n );\n }\n case 'boolean': {\n const control = (\n <Switch isSelected={Boolean(value)} onChange={setValue} aria-label={ariaLabel} />\n );\n // Switch has no indeterminate state; a reduced-opacity wrapper with\n // a title is the cheap honest cue for a mixed selection.\n if (!mixed) return control;\n return (\n <span className={s.mixedSwitch} title=\"Mixed\">\n {control}\n </span>\n );\n }\n case 'enum': {\n const p = pref as ToolPrefEnum;\n return (\n <Select<string>\n className={s.select}\n options={p.options.map((o) => ({ value: o.value, label: o.label }))}\n selectedKey={mixed ? null : typeof value === 'string' ? value : p.default}\n placeholder={mixed ? 'Mixed' : undefined}\n onSelectionChange={setValue}\n aria-label={ariaLabel}\n />\n );\n }\n case 'color': {\n const p = pref as ToolPrefColor;\n return (\n <ColorField\n value={mixed ? undefined : typeof value === 'string' ? value : p.default}\n mixed={mixed}\n alpha={p.alpha}\n onChange={setValue}\n aria-label={ariaLabel}\n />\n );\n }\n case 'paint': {\n // The value is a whole `FillStyle`. A solid one has a color to show; a\n // pattern or gradient does not, and showing the control's default there\n // would claim a color the shape doesn't have. It gets the same\n // indeterminate chip a genuinely mixed selection gets — in both cases\n // the honest statement is \"there is no single color here\".\n const p = pref as ToolPrefPaint;\n const solid = solidColorOf(value) ?? (mixed ? undefined : solidColorOf(p.default));\n return (\n <ColorField\n value={mixed ? undefined : solid}\n mixed={mixed || (value !== undefined && solidColorOf(value) === undefined)}\n alpha={p.alpha}\n // Write the whole union member. Setting a `color` key on the\n // existing paint would leave a `{ fill: 'linear-gradient', stops,\n // color }` hybrid that every structural `'color' in paint` check\n // downstream reads as solid.\n onChange={(color) => setValue({ fill: 'solid', color })}\n aria-label={ariaLabel}\n />\n );\n }\n default:\n return <span className={s.unrenderable}>({pref.kind}: no renderer)</span>;\n }\n}\n\n/** Text input with commit-on-blur/Enter semantics — live-per-keystroke\n * writes would emit one undo step per character. */\nfunction DraftInput({\n text,\n placeholder,\n ariaLabel,\n onCommit,\n}: {\n text: string | undefined;\n placeholder?: string;\n ariaLabel: string;\n onCommit: (v: string) => void;\n}) {\n const [draft, setDraft] = useState<string | null>(null);\n return (\n <Input\n value={draft ?? text ?? ''}\n placeholder={placeholder}\n aria-label={ariaLabel}\n onChange={setDraft}\n onBlur={() => {\n if (draft !== null && draft !== text) onCommit(draft);\n setDraft(null);\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') (e.target as HTMLInputElement).blur();\n }}\n />\n );\n}\n"],"mappings":"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"}
@@ -23,4 +23,4 @@ function n(n) {
23
23
  //#endregion
24
24
  export { n as t };
25
25
 
26
- //# sourceMappingURL=Sidebar-B8qig3BQ.js.map
26
+ //# sourceMappingURL=Sidebar-DP_nyJze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sidebar-DP_nyJze.js","names":[],"sources":["../../src/components/Sidebar/Sidebar.module.css","../../src/components/Sidebar/Sidebar.tsx"],"sourcesContent":[".sidebar {\n display: flex;\n flex-direction: column;\n gap: 4px;\n background: var(--wzl-surface);\n color: var(--wzl-fg);\n}\n\n.sidebar.left {\n border-right: 1px solid var(--wzl-border);\n}\n.sidebar.right {\n border-left: 1px solid var(--wzl-border);\n}\n","import type { CSSProperties, ReactNode } from 'react';\nimport s from './Sidebar.module.css';\n\n/** Props for {@link Sidebar}. */\nexport interface SidebarProps {\n /**\n * Edge the sidebar docks to. Adds a class hook (`s.left` / `s.right`)\n * so consumers can target either edge for borders, shadows, etc.\n * Purely cosmetic — layout is the parent's job.\n */\n side?: 'left' | 'right';\n /**\n * Accessible label — rendered onto the `<aside>`. Without it, screen\n * readers fall back to \"complementary landmark,\" which is fine for\n * apps with a single sidebar but ambiguous when there's both a left\n * and a right.\n */\n ariaLabel?: string;\n children?: ReactNode;\n className?: string;\n /** Inline style — useful for width-as-custom-property handles or any\n * other one-off CSS property the consumer wants to set dynamically. */\n style?: CSSProperties;\n}\n\n/**\n * Generic sidebar shell — `<aside>` with column layout and token-driven\n * surface treatment. Width, sticky positioning, and resize handles stay\n * the consumer's concern (every app has its own layout grid); the kit\n * just provides the chrome.\n *\n * Pair with `<SidebarPanel>` for collapsible sections.\n */\nexport function Sidebar(props: SidebarProps) {\n const { side, ariaLabel, children, className, style } = props;\n const cls = [s.sidebar, side === 'left' && s.left, side === 'right' && s.right, className]\n .filter(Boolean).join(' ');\n return (\n <aside className={cls} aria-label={ariaLabel} style={style}>\n {children}\n </aside>\n );\n}\n"],"mappings":";;;;;;;;ACiCA,SAAgB,EAAQ,GAAqB;CAC3C,IAAM,EAAE,SAAM,cAAW,aAAU,cAAW,aAAU;AAGxD,QACE,kBAAC,SAAD;EAAO,WAHG;GAAC,EAAE;GAAS,MAAS,UAAU,EAAE;GAAM,MAAS,WAAW,EAAE;GAAO;GAAU,CACvF,OAAO,QAAQ,CAAC,KAAK,IAEJ;EAAK,cAAY;EAAkB;EAClD;EACK,CAAA"}
@@ -56,4 +56,4 @@ function o(o) {
56
56
  //#endregion
57
57
  export { o as t };
58
58
 
59
- //# sourceMappingURL=SidebarPanel-LOt2c-wb.js.map
59
+ //# sourceMappingURL=SidebarPanel-BpD0ptyg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarPanel-BpD0ptyg.js","names":[],"sources":["../../src/components/SidebarPanel/SidebarPanel.module.css","../../src/components/SidebarPanel/SidebarPanel.tsx"],"sourcesContent":[".panel {\n padding: 8px;\n background: var(--wzl-surface);\n color: var(--wzl-fg);\n}\n\n.title {\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--wzl-fg-muted);\n}\n\n.titleRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 4px;\n padding: 0;\n}\n\n.titleButton {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex: 1 1 auto;\n background: transparent;\n border: 0;\n padding: 4px 8px;\n cursor: pointer;\n color: inherit;\n font: inherit;\n text-align: left;\n}\n.titleButton:hover {\n color: var(--wzl-fg);\n}\n\n.chevron {\n display: inline-block;\n font-size: 10px;\n line-height: 1;\n color: var(--wzl-fg-muted);\n transition: transform var(--wzl-motion-fast) ease;\n}\n.chevronCollapsed {\n transform: rotate(-90deg);\n}\n\n.hideButton {\n background: transparent;\n border: 0;\n padding: 0 6px;\n font-size: 14px;\n line-height: 1;\n color: var(--wzl-fg-muted);\n cursor: pointer;\n}\n.hideButton:hover {\n color: var(--wzl-fg);\n}\n\n.panel.collapsed {\n padding-bottom: 4px;\n}\n\n.body {\n padding: 0 4px;\n}\n","import type { ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport s from './SidebarPanel.module.css';\n\n/** Props for {@link SidebarPanel}. */\nexport interface SidebarPanelProps {\n /** Title rendered in the panel's header row. */\n title?: ReactNode;\n /**\n * Collapsed state — when true, only the header paints; the body is\n * omitted. Caller owns the state (typically via prefs) and flips it\n * back via `onToggleCollapse`.\n */\n collapsed?: boolean;\n /**\n * Click handler for the title row. When provided, the header renders\n * as a button (chevron + label) and acts as the collapse toggle.\n * When omitted, the title is static text and the panel can't collapse.\n */\n onToggleCollapse?(): void;\n /**\n * Optional close handler — when provided, the header gains a `×`\n * button on the trailing edge. Caller flips its \"hidden\" state and\n * conditionally unmounts the panel from the parent.\n */\n onHide?(): void;\n children?: ReactNode;\n className?: string;\n}\n\n/**\n * Generic collapsible panel section for sidebars. Pure presentation —\n * caller manages `collapsed`/`hidden` state externally (the pattern is\n * to drive it from app prefs so the Preferences modal and inline\n * chevrons toggle the same map).\n *\n * Pair with `<Sidebar>` for the docked column layout.\n */\nexport function SidebarPanel(props: SidebarPanelProps) {\n const { title, collapsed, onToggleCollapse, onHide, children, className } = props;\n const cls = [s.panel, collapsed && s.collapsed, className].filter(Boolean).join(' ');\n const headerInteractive = onToggleCollapse !== undefined;\n return (\n <div className={cls}>\n {title !== undefined && (\n <div className={s.titleRow}>\n {headerInteractive ? (\n <button\n type=\"button\"\n className={s.titleButton}\n onClick={onToggleCollapse}\n aria-expanded={!collapsed}\n >\n <span className={[s.chevron, collapsed && s.chevronCollapsed].filter(Boolean).join(' ')} aria-hidden=\"true\">▾</span>\n <span className={s.title}>{title}</span>\n </button>\n ) : (\n <span className={s.title}>{title}</span>\n )}\n {onHide !== undefined && (\n <TooltipTrigger>\n <Focusable>\n <button\n type=\"button\"\n className={s.hideButton}\n onClick={onHide}\n aria-label=\"Hide panel\"\n >\n ×\n </button>\n </Focusable>\n <Tooltip>Hide panel</Tooltip>\n </TooltipTrigger>\n )}\n </div>\n )}\n {!collapsed && <div className={s.body}>{children}</div>}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;ACuCA,SAAgB,EAAa,GAA0B;CACrD,IAAM,EAAE,UAAO,cAAW,qBAAkB,WAAQ,aAAU,iBAAc,GACtE,IAAM;EAAC,EAAE;EAAO,KAAa,EAAE;EAAW;EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,EAC9E,IAAoB,MAAqB,KAAA;AAC/C,QACE,kBAAC,OAAD;EAAK,WAAW;YAAhB,CACG,MAAU,KAAA,KACT,kBAAC,OAAD;GAAK,WAAW,EAAE;aAAlB,CACG,IACC,kBAAC,UAAD;IACE,MAAK;IACL,WAAW,EAAE;IACb,SAAS;IACT,iBAAe,CAAC;cAJlB,CAME,kBAAC,QAAD;KAAM,WAAW,CAAC,EAAE,SAAS,KAAa,EAAE,iBAAiB,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;KAAE,eAAY;eAAO;KAAQ,CAAA,EACpH,kBAAC,QAAD;KAAM,WAAW,EAAE;eAAQ;KAAa,CAAA,CACjC;QAET,kBAAC,QAAD;IAAM,WAAW,EAAE;cAAQ;IAAa,CAAA,EAEzC,MAAW,KAAA,KACV,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,UAAD;IACE,MAAK;IACL,WAAW,EAAE;IACb,SAAS;IACT,cAAW;cACZ;IAEQ,CAAA,EACC,CAAA,EACZ,kBAAC,GAAD,EAAA,UAAS,cAAoB,CAAA,CACd,EAAA,CAAA,CAEf;MAEP,CAAC,KAAa,kBAAC,OAAD;GAAK,WAAW,EAAE;GAAO;GAAe,CAAA,CACnD"}
@@ -38,7 +38,7 @@ function d(e) {
38
38
  });
39
39
  }
40
40
  function f(a) {
41
- let { thumbs: o, onChange: f, onCommit: p, min: m, max: h, step: g, constraint: _, trackHeight: v, ariaLabel: y, className: b } = a, x = t(null), S = t(null), C = e((e) => h === m ? 0 : c((e - m) / (h - m), 0, 1), [m, h]), w = e((e) => m + c(e, 0, 1) * (h - m), [m, h]), T = e((e) => {
41
+ let { thumbs: o, onInput: f, onChange: p, min: m, max: h, step: g, constraint: _, trackHeight: v, ariaLabel: y, className: b } = a, x = t(null), S = t(null), C = e((e) => h === m ? 0 : c((e - m) / (h - m), 0, 1), [m, h]), w = e((e) => m + c(e, 0, 1) * (h - m), [m, h]), T = e((e) => {
42
42
  S.current = o.map((e) => ({ ...e }));
43
43
  let t = !1, n = (n) => {
44
44
  let r = x.current, i = S.current;
@@ -67,7 +67,7 @@ function f(a) {
67
67
  f(t), p?.(t);
68
68
  return;
69
69
  }
70
- p && p(i.map((e) => ({ ...e })));
70
+ p?.(i.map((e) => ({ ...e })));
71
71
  }
72
72
  };
73
73
  document.addEventListener("pointermove", n), document.addEventListener("pointerup", r);
@@ -100,7 +100,7 @@ function f(a) {
100
100
  }, i = () => {
101
101
  document.removeEventListener("pointermove", r), document.removeEventListener("pointerup", i);
102
102
  let e = S.current;
103
- S.current = null, e && p && p(e.map((e) => ({ ...e })));
103
+ S.current = null, e && p?.(e.map((e) => ({ ...e })));
104
104
  };
105
105
  document.addEventListener("pointermove", r), document.addEventListener("pointerup", i);
106
106
  }, [
@@ -218,4 +218,4 @@ function f(a) {
218
218
  //#endregion
219
219
  export { a as n, o as r, f as t };
220
220
 
221
- //# sourceMappingURL=Slider-Di2kNqVy.js.map
221
+ //# sourceMappingURL=Slider-CmPeFJ3x.js.map