@weasel-js/ui 1.2.0 → 1.3.0-pre.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/dist/chunks/{ActionBar-BvPEd_GW.js → ActionBar-BTev_ZZl.js} +21 -21
  2. package/dist/chunks/ActionBar-BTev_ZZl.js.map +1 -0
  3. package/dist/chunks/{ActionsBar-9aR5N3lU.js → ActionsBar-gTuCtkv8.js} +4 -4
  4. package/dist/chunks/{ActionsBar-9aR5N3lU.js.map → ActionsBar-gTuCtkv8.js.map} +1 -1
  5. package/dist/chunks/{Badge-dQzbkk-C.js → Badge-9dPfvYOk.js} +672 -670
  6. package/dist/chunks/Badge-9dPfvYOk.js.map +1 -0
  7. package/dist/chunks/{BandEditor-D3i6l299.js → BandEditor-DKbcHG2_.js} +46 -46
  8. package/dist/chunks/BandEditor-DKbcHG2_.js.map +1 -0
  9. package/dist/chunks/{Button-9QNIYugK.js → Button-CIu40Epu.js} +28 -28
  10. package/dist/chunks/Button-CIu40Epu.js.map +1 -0
  11. package/dist/chunks/{Callout-cJHJ4kIN.js → Callout-CHs98djt.js} +35 -35
  12. package/dist/chunks/Callout-CHs98djt.js.map +1 -0
  13. package/dist/chunks/Checkbox-BLEw-wEb.js +47 -0
  14. package/dist/chunks/Checkbox-BLEw-wEb.js.map +1 -0
  15. package/dist/chunks/ColorField-D1t-BdSa.js +60 -0
  16. package/dist/chunks/ColorField-D1t-BdSa.js.map +1 -0
  17. package/dist/chunks/{ComboBox-ONQISwtI.js → ComboBox-cvdKolWv.js} +28 -28
  18. package/dist/chunks/ComboBox-cvdKolWv.js.map +1 -0
  19. package/dist/chunks/{CurveEditor-SmwwvrsA.js → CurveEditor-BaA-PabB.js} +116 -116
  20. package/dist/chunks/{CurveEditor-SmwwvrsA.js.map → CurveEditor-BaA-PabB.js.map} +1 -1
  21. package/dist/chunks/DataGrid-D15I779H.js +210 -0
  22. package/dist/chunks/DataGrid-D15I779H.js.map +1 -0
  23. package/dist/chunks/Dialog-DC1x46Sq.js +59 -0
  24. package/dist/chunks/Dialog-DC1x46Sq.js.map +1 -0
  25. package/dist/chunks/{Field-VQwmrIna.js → Field-BjFl_yng.js} +6 -6
  26. package/dist/chunks/Field-BjFl_yng.js.map +1 -0
  27. package/dist/chunks/GradientEditor-BJRD0n1g.js +308 -0
  28. package/dist/chunks/GradientEditor-BJRD0n1g.js.map +1 -0
  29. package/dist/chunks/InlineRange-C6UYKxLD.js +24 -0
  30. package/dist/chunks/InlineRange-C6UYKxLD.js.map +1 -0
  31. package/dist/chunks/Input-DhWBgpRx.js +55 -0
  32. package/dist/chunks/Input-DhWBgpRx.js.map +1 -0
  33. package/dist/chunks/{Keycaps-CFX7UAj8.js → Keycaps-BhCKdyws.js} +15 -15
  34. package/dist/chunks/Keycaps-BhCKdyws.js.map +1 -0
  35. package/dist/chunks/NumberField-ZdVa4bpJ.js +59 -0
  36. package/dist/chunks/NumberField-ZdVa4bpJ.js.map +1 -0
  37. package/dist/chunks/{OptionsBar-CHvH4n4u.js → OptionsBar-DahCI4Aq.js} +4 -4
  38. package/dist/chunks/{OptionsBar-CHvH4n4u.js.map → OptionsBar-DahCI4Aq.js.map} +1 -1
  39. package/dist/chunks/PaintInput-Cggm9OIl.js +205 -0
  40. package/dist/chunks/PaintInput-Cggm9OIl.js.map +1 -0
  41. package/dist/chunks/PatternPicker-B63SlDoF.js +93 -0
  42. package/dist/chunks/PatternPicker-B63SlDoF.js.map +1 -0
  43. package/dist/chunks/{Plot2D-CEnhzodm.js → Plot2D-sPXTw_-l.js} +27 -27
  44. package/dist/chunks/{Plot2D-CEnhzodm.js.map → Plot2D-sPXTw_-l.js.map} +1 -1
  45. package/dist/chunks/{PointPlotter-BUIse9c4.js → PointPlotter-CLd9u5Bq.js} +2 -2
  46. package/dist/chunks/{PointPlotter-BUIse9c4.js.map → PointPlotter-CLd9u5Bq.js.map} +1 -1
  47. package/dist/chunks/{Powerline-BYWdK8QH.js → Powerline-DhQJYaUg.js} +2 -2
  48. package/dist/chunks/{Powerline-BYWdK8QH.js.map → Powerline-DhQJYaUg.js.map} +1 -1
  49. package/dist/chunks/Prefs-BSJ0lMmJ.js +300 -0
  50. package/dist/chunks/Prefs-BSJ0lMmJ.js.map +1 -0
  51. package/dist/chunks/RadioGroup-vtwjRiUm.js +49 -0
  52. package/dist/chunks/RadioGroup-vtwjRiUm.js.map +1 -0
  53. package/dist/chunks/RangeSlider-B-n_7AgJ.js +52 -0
  54. package/dist/chunks/RangeSlider-B-n_7AgJ.js.map +1 -0
  55. package/dist/chunks/{ResizeHandle-BOpmtOOj.js → ResizeHandle--ZExnMfa.js} +8 -8
  56. package/dist/chunks/{ResizeHandle-BOpmtOOj.js.map → ResizeHandle--ZExnMfa.js.map} +1 -1
  57. package/dist/chunks/{Select-CHsuQCp0.js → Select--BVTi-j0.js} +32 -32
  58. package/dist/chunks/Select--BVTi-j0.js.map +1 -0
  59. package/dist/chunks/SelectionPanel-C7kygTFE.js +446 -0
  60. package/dist/chunks/SelectionPanel-C7kygTFE.js.map +1 -0
  61. package/dist/chunks/{Sidebar-DP_nyJze.js → Sidebar-CtwBdr4n.js} +1 -1
  62. package/dist/chunks/{Sidebar-DP_nyJze.js.map → Sidebar-CtwBdr4n.js.map} +1 -1
  63. package/dist/chunks/SidebarPanel-AeSc7wNR.js +59 -0
  64. package/dist/chunks/SidebarPanel-AeSc7wNR.js.map +1 -0
  65. package/dist/chunks/{Slider-tGbqoAZH.js → Slider-cxWR47gi.js} +39 -39
  66. package/dist/chunks/Slider-cxWR47gi.js.map +1 -0
  67. package/dist/chunks/{StatusBar-DBO0E0Yd.js → StatusBar-D_wu-SZh.js} +6 -6
  68. package/dist/chunks/StatusBar-D_wu-SZh.js.map +1 -0
  69. package/dist/chunks/Switch-CtZwp5zm.js +27 -0
  70. package/dist/chunks/Switch-CtZwp5zm.js.map +1 -0
  71. package/dist/chunks/Tabs-lB0IB4TX.js +41 -0
  72. package/dist/chunks/Tabs-lB0IB4TX.js.map +1 -0
  73. package/dist/chunks/{Toast-DFw4IrD_.js → Toast-hr9BYsho.js} +31 -31
  74. package/dist/chunks/{Toast-DFw4IrD_.js.map → Toast-hr9BYsho.js.map} +1 -1
  75. package/dist/chunks/{ToggleBar-BP1zFcvg.js → ToggleBar-BxgWq-wO.js} +11 -10
  76. package/dist/chunks/ToggleBar-BxgWq-wO.js.map +1 -0
  77. package/dist/chunks/{ToolButton-ClPz5L6j.js → ToolButton-CJrPjbsj.js} +16 -16
  78. package/dist/chunks/ToolButton-CJrPjbsj.js.map +1 -0
  79. package/dist/chunks/{ToolGroup-BTIwd4U4.js → ToolGroup-D_lDzkvU.js} +1 -1
  80. package/dist/chunks/{ToolGroup-BTIwd4U4.js.map → ToolGroup-D_lDzkvU.js.map} +1 -1
  81. package/dist/chunks/{ToolOptionsBar-JvmY7iNe.js → ToolOptionsBar-BA6Sb3U2.js} +4 -4
  82. package/dist/chunks/ToolOptionsBar-BA6Sb3U2.js.map +1 -0
  83. package/dist/chunks/{ToolPalette-DAiVhdtV.js → ToolPalette-TMvkaJwr.js} +24 -24
  84. package/dist/chunks/ToolPalette-TMvkaJwr.js.map +1 -0
  85. package/dist/chunks/Tooltip-Di7vxbFa.js +40 -0
  86. package/dist/chunks/Tooltip-Di7vxbFa.js.map +1 -0
  87. package/dist/chunks/{keyGlyph-BDH5fqkO.js → keyGlyph-DNpLxF8u.js} +1 -1
  88. package/dist/chunks/{keyGlyph-BDH5fqkO.js.map → keyGlyph-DNpLxF8u.js.map} +1 -1
  89. package/dist/chunks/segmentedControl.module-D4b7x19O.js +11 -0
  90. package/dist/chunks/segmentedControl.module-D4b7x19O.js.map +1 -0
  91. package/dist/chunks/{useRovingTabIndex-DBZtq4IH.js → useRovingTabIndex-CQz8EiKh.js} +1 -1
  92. package/dist/chunks/{useRovingTabIndex-DBZtq4IH.js.map → useRovingTabIndex-CQz8EiKh.js.map} +1 -1
  93. package/dist/components/ActionBar/index.js +1 -1
  94. package/dist/components/ActionsBar/index.js +1 -1
  95. package/dist/components/Badge/Badge.d.ts.map +1 -1
  96. package/dist/components/Badge/index.js +1 -1
  97. package/dist/components/BandEditor/index.js +1 -1
  98. package/dist/components/Button/index.js +1 -1
  99. package/dist/components/Callout/index.js +1 -1
  100. package/dist/components/Checkbox/Checkbox.d.ts +1 -1
  101. package/dist/components/Checkbox/index.js +1 -1
  102. package/dist/components/ColorField/ColorField.d.ts.map +1 -1
  103. package/dist/components/ColorField/index.js +1 -1
  104. package/dist/components/ComboBox/index.js +1 -1
  105. package/dist/components/CurveEditor/index.js +1 -1
  106. package/dist/components/DataGrid/index.js +1 -1
  107. package/dist/components/Dialog/index.js +1 -1
  108. package/dist/components/Field/index.js +1 -1
  109. package/dist/components/GradientEditor/SceneGradientHandles.d.ts +41 -0
  110. package/dist/components/GradientEditor/SceneGradientHandles.d.ts.map +1 -0
  111. package/dist/components/GradientEditor/index.d.ts +1 -0
  112. package/dist/components/GradientEditor/index.d.ts.map +1 -1
  113. package/dist/components/GradientEditor/index.js +2 -2
  114. package/dist/components/InlineRange/InlineRange.d.ts +17 -0
  115. package/dist/components/InlineRange/InlineRange.d.ts.map +1 -0
  116. package/dist/components/InlineRange/index.d.ts +2 -0
  117. package/dist/components/InlineRange/index.d.ts.map +1 -0
  118. package/dist/components/InlineRange/index.js +2 -0
  119. package/dist/components/Input/Input.d.ts +1 -1
  120. package/dist/components/Input/index.js +1 -1
  121. package/dist/components/Keycaps/index.js +2 -2
  122. package/dist/components/NumberField/NumberField.d.ts +1 -1
  123. package/dist/components/NumberField/index.js +1 -1
  124. package/dist/components/OptionsBar/index.js +1 -1
  125. package/dist/components/PaintInput/PaintInput.d.ts +40 -0
  126. package/dist/components/PaintInput/PaintInput.d.ts.map +1 -0
  127. package/dist/components/PaintInput/index.d.ts +2 -0
  128. package/dist/components/PaintInput/index.d.ts.map +1 -0
  129. package/dist/components/PaintInput/index.js +2 -0
  130. package/dist/components/PatternPicker/PatternPicker.d.ts +31 -0
  131. package/dist/components/PatternPicker/PatternPicker.d.ts.map +1 -0
  132. package/dist/components/PatternPicker/index.d.ts +2 -0
  133. package/dist/components/PatternPicker/index.d.ts.map +1 -0
  134. package/dist/components/PatternPicker/index.js +2 -0
  135. package/dist/components/Plot2D/index.js +1 -1
  136. package/dist/components/PointPlotter/index.js +1 -1
  137. package/dist/components/Powerline/index.js +2 -2
  138. package/dist/components/Prefs/PrefsForm.d.ts.map +1 -1
  139. package/dist/components/Prefs/index.d.ts +1 -1
  140. package/dist/components/Prefs/index.d.ts.map +1 -1
  141. package/dist/components/Prefs/index.js +1 -1
  142. package/dist/components/Prefs/schema.d.ts +4 -92
  143. package/dist/components/Prefs/schema.d.ts.map +1 -1
  144. package/dist/components/RadioGroup/index.js +1 -1
  145. package/dist/components/RangeSlider/index.js +1 -1
  146. package/dist/components/ResizeHandle/index.js +1 -1
  147. package/dist/components/Select/index.js +1 -1
  148. package/dist/components/SelectionPanel/SelectionPanel.d.ts +32 -1
  149. package/dist/components/SelectionPanel/SelectionPanel.d.ts.map +1 -1
  150. package/dist/components/SelectionPanel/index.js +1 -1
  151. package/dist/components/Sidebar/index.js +1 -1
  152. package/dist/components/SidebarPanel/index.js +1 -1
  153. package/dist/components/Slider/index.js +1 -1
  154. package/dist/components/StatusBar/index.js +1 -1
  155. package/dist/components/Switch/Switch.d.ts +1 -1
  156. package/dist/components/Switch/index.js +1 -1
  157. package/dist/components/Tabs/index.js +1 -1
  158. package/dist/components/Toast/index.js +1 -1
  159. package/dist/components/ToggleBar/ToggleBar.d.ts +1 -1
  160. package/dist/components/ToggleBar/ToggleBar.d.ts.map +1 -1
  161. package/dist/components/ToggleBar/index.js +1 -1
  162. package/dist/components/ToolButton/index.js +1 -1
  163. package/dist/components/ToolGroup/index.js +1 -1
  164. package/dist/components/ToolOptionsBar/index.js +1 -1
  165. package/dist/components/ToolPalette/index.js +1 -1
  166. package/dist/components/Tooltip/index.js +1 -1
  167. package/dist/components/paintValue.d.ts +8 -0
  168. package/dist/components/paintValue.d.ts.map +1 -0
  169. package/dist/icons/Icon.d.ts +17 -0
  170. package/dist/icons/Icon.d.ts.map +1 -0
  171. package/dist/icons/index.d.ts +50 -0
  172. package/dist/icons/index.d.ts.map +1 -0
  173. package/dist/icons/paths.d.ts +71 -0
  174. package/dist/icons/paths.d.ts.map +1 -0
  175. package/dist/index.d.ts +5 -0
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +184 -48
  178. package/dist/index.js.map +1 -1
  179. package/dist/style.css +1 -1
  180. package/package.json +4 -3
  181. package/dist/chunks/ActionBar-BvPEd_GW.js.map +0 -1
  182. package/dist/chunks/Badge-dQzbkk-C.js.map +0 -1
  183. package/dist/chunks/BandEditor-D3i6l299.js.map +0 -1
  184. package/dist/chunks/Button-9QNIYugK.js.map +0 -1
  185. package/dist/chunks/Callout-cJHJ4kIN.js.map +0 -1
  186. package/dist/chunks/Checkbox-KQ5L8APP.js +0 -47
  187. package/dist/chunks/Checkbox-KQ5L8APP.js.map +0 -1
  188. package/dist/chunks/ColorField-ykpiD3XU.js +0 -60
  189. package/dist/chunks/ColorField-ykpiD3XU.js.map +0 -1
  190. package/dist/chunks/ComboBox-ONQISwtI.js.map +0 -1
  191. package/dist/chunks/DataGrid-DZQ4Chbd.js +0 -210
  192. package/dist/chunks/DataGrid-DZQ4Chbd.js.map +0 -1
  193. package/dist/chunks/Dialog-CqwdJv_t.js +0 -59
  194. package/dist/chunks/Dialog-CqwdJv_t.js.map +0 -1
  195. package/dist/chunks/Field-VQwmrIna.js.map +0 -1
  196. package/dist/chunks/GradientEditor-Bg6SX64V.js +0 -280
  197. package/dist/chunks/GradientEditor-Bg6SX64V.js.map +0 -1
  198. package/dist/chunks/Input-DpkwYtUY.js +0 -55
  199. package/dist/chunks/Input-DpkwYtUY.js.map +0 -1
  200. package/dist/chunks/Keycaps-CFX7UAj8.js.map +0 -1
  201. package/dist/chunks/NumberField-BbzI0GtU.js +0 -59
  202. package/dist/chunks/NumberField-BbzI0GtU.js.map +0 -1
  203. package/dist/chunks/Prefs-BMR9wMiZ.js +0 -238
  204. package/dist/chunks/Prefs-BMR9wMiZ.js.map +0 -1
  205. package/dist/chunks/RadioGroup-CIpHr3g6.js +0 -49
  206. package/dist/chunks/RadioGroup-CIpHr3g6.js.map +0 -1
  207. package/dist/chunks/RangeSlider-CaDogGTj.js +0 -52
  208. package/dist/chunks/RangeSlider-CaDogGTj.js.map +0 -1
  209. package/dist/chunks/Select-CHsuQCp0.js.map +0 -1
  210. package/dist/chunks/SelectionPanel-D_wk_8ZN.js +0 -303
  211. package/dist/chunks/SelectionPanel-D_wk_8ZN.js.map +0 -1
  212. package/dist/chunks/SidebarPanel-BVTQ1ZyM.js +0 -59
  213. package/dist/chunks/SidebarPanel-BVTQ1ZyM.js.map +0 -1
  214. package/dist/chunks/Slider-tGbqoAZH.js.map +0 -1
  215. package/dist/chunks/StatusBar-DBO0E0Yd.js.map +0 -1
  216. package/dist/chunks/Switch-JyVSSAzC.js +0 -27
  217. package/dist/chunks/Switch-JyVSSAzC.js.map +0 -1
  218. package/dist/chunks/Tabs-Df0sDomx.js +0 -41
  219. package/dist/chunks/Tabs-Df0sDomx.js.map +0 -1
  220. package/dist/chunks/ToggleBar-BP1zFcvg.js.map +0 -1
  221. package/dist/chunks/ToolButton-ClPz5L6j.js.map +0 -1
  222. package/dist/chunks/ToolOptionsBar-JvmY7iNe.js.map +0 -1
  223. package/dist/chunks/ToolPalette-DAiVhdtV.js.map +0 -1
  224. package/dist/chunks/Tooltip-DXJbdR5B.js +0 -40
  225. package/dist/chunks/Tooltip-DXJbdR5B.js.map +0 -1
  226. package/dist/chunks/segmentedControl.module-DCyuDbj1.js +0 -11
  227. package/dist/chunks/segmentedControl.module-DCyuDbj1.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PatternPicker-B63SlDoF.js","names":[],"sources":["../../src/components/PatternPicker/PatternPicker.module.css","../../src/components/PatternPicker/PatternPicker.tsx"],"sourcesContent":["/* Tile grid over the size switch. */\n.root {\n display: flex;\n flex-direction: column;\n gap: 6px;\n min-inline-size: 0;\n}\n\n.grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(var(--wzl-swatch-size, 28px), 1fr));\n gap: 0;\n}\n\n/* The swatch's whole face is its own tile, so it must not carry a flat\n background — and the tile repeats at its own scale, not the swatch's. */\n.swatch {\n width: 100%;\n aspect-ratio: 1 / 1;\n min-width: 0;\n padding: 0;\n border: 0.5px solid var(--wzl-border);\n border-radius: 0;\n cursor: pointer;\n background-color: var(--wzl-surface-sunken);\n background-image: var(--tile-preview);\n background-repeat: repeat;\n background-size: 16px 16px;\n background-clip: padding-box;\n}\n\n.swatch:hover {\n border-color: var(--wzl-fg-muted);\n}\n\n.swatchActive {\n border-color: var(--wzl-accent);\n box-shadow: 0 0 0 1px var(--wzl-accent);\n}\n","import type { ReactElement } from 'react';\nimport type { CSSProperties } from 'react';\nimport type { FillStyle, TilePatternSpec } from '@weasel-js/core';\nimport { tilePreviewCssUrl } from '@weasel-js/svg';\nimport { ToggleBar } from '../ToggleBar';\nimport s from './PatternPicker.module.css';\n\n/** The `pattern` member of the paint union. */\nexport type PatternFill = Extract<FillStyle, { fill: 'pattern' }>;\n\nconst TILES: readonly TilePatternSpec['tile'][] = ['hatch', 'crosshatch', 'dots', 'chunks'];\n\n/** Tile sizes the picker offers, coarse enough that each reads as a\n * distinct texture rather than a nudge. */\nconst TILE_SIZES: readonly { value: number; label: string }[] = [\n { value: 4, label: 'S' },\n { value: 8, label: 'M' },\n { value: 16, label: 'L' },\n { value: 32, label: 'XL' },\n];\n\nconst DEFAULT_TILE_SIZE = 8;\n\n/** Every swatch previews at one size so the grid compares tiles, not scales. */\nconst PREVIEW_SIZE = 16;\n\n/** The spec a pattern paint carries, if it carries one. A consumer-built\n * `TextureHandle` has no spec, so the picker shows no tile selected and\n * replaces it wholesale on the next click. */\nfunction specOf(fill: PatternFill): TilePatternSpec | null {\n return 'tile' in fill.pattern ? fill.pattern : null;\n}\n\n/**\n * A pattern seeded from a color. `units: 'bounds'` anchors the tile to the\n * node's box, so the texture travels with the shape.\n */\nexport function seedPattern(\n tile: TilePatternSpec['tile'],\n from: string,\n size: number = DEFAULT_TILE_SIZE,\n): PatternFill {\n const spec: TilePatternSpec = { tile, color: from, size };\n // `chunks` is a scatter over a ground rather than a line texture; without a\n // background it reads as loose specks on whatever sits beneath.\n if (tile === 'chunks') spec.bg = '#00000000';\n return { fill: 'pattern', pattern: spec, units: 'bounds' };\n}\n\n/** Props for {@link PatternPicker}. */\nexport interface PatternPickerProps {\n /** The pattern paint being edited. */\n value: PatternFill;\n /** The color new tiles are seeded with — the paint's own, normally. */\n color: string;\n /** Committed value: one call per click. A tile pick and a size change are\n * each a complete gesture, so there is no `onInput`. */\n onChange: (next: PatternFill) => void;\n className?: string;\n}\n\n/**\n * Grid of tile swatches over a size switch, each swatch previewing the real\n * tile at the current color.\n *\n * The preview shares its shape mapper with what the renderer paints, so a\n * swatch cannot drift from the texture it selects.\n */\nexport function PatternPicker(props: PatternPickerProps): ReactElement {\n const { value, color, onChange, className } = props;\n const spec = specOf(value);\n const size = spec?.size ?? DEFAULT_TILE_SIZE;\n\n const pick = (tile: TilePatternSpec['tile']): void => {\n onChange(seedPattern(tile, color, size));\n };\n\n const resize = (nextSize: number): void => {\n if (!spec) return;\n onChange({ ...value, pattern: { ...spec, size: nextSize } });\n };\n\n return (\n <div className={[s.root, className].filter(Boolean).join(' ')}>\n <div className={s.grid}>\n {TILES.map((tile) => {\n const preview: TilePatternSpec = { tile, color, size: PREVIEW_SIZE };\n if (tile === 'chunks') preview.bg = '#00000000';\n const selected = spec?.tile === tile;\n return (\n <button\n key={tile}\n type=\"button\"\n className={[s.swatch, selected && s.swatchActive].filter(Boolean).join(' ')}\n style={{ ['--tile-preview' as string]: tilePreviewCssUrl(preview) } as CSSProperties}\n title={tile}\n aria-label={tile}\n aria-pressed={selected}\n onClick={() => pick(tile)}\n />\n );\n })}\n </div>\n <ToggleBar<number>\n items={TILE_SIZES}\n value={size}\n size=\"sm\"\n ariaLabel=\"Tile size\"\n onChange={(v) => v != null && resize(v)}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;GCUM,IAA4C;CAAC;CAAS;CAAc;CAAQ;CAAS,EAIrF,IAA0D;CAC9D;EAAE,OAAO;EAAG,OAAO;EAAK;CACxB;EAAE,OAAO;EAAG,OAAO;EAAK;CACxB;EAAE,OAAO;EAAI,OAAO;EAAK;CACzB;EAAE,OAAO;EAAI,OAAO;EAAM;CAC3B,EAEK,IAAoB,GAGpB,IAAe;AAKrB,SAAS,EAAO,GAA2C;AACzD,QAAO,UAAU,EAAK,UAAU,EAAK,UAAU;;AAOjD,SAAgB,EACd,GACA,GACA,IAAe,GACF;CACb,IAAM,IAAwB;EAAE;EAAM,OAAO;EAAM;EAAM;AAIzD,QADI,MAAS,aAAU,EAAK,KAAK,cAC1B;EAAE,MAAM;EAAW,SAAS;EAAM,OAAO;EAAU;;AAsB5D,SAAgB,EAAc,GAAyC;CACrE,IAAM,EAAE,UAAO,UAAO,aAAU,iBAAc,GACxC,IAAO,EAAO,EAAM,EACpB,IAAO,GAAM,QAAQ,GAErB,KAAQ,MAAwC;AACpD,IAAS,EAAY,GAAM,GAAO,EAAK,CAAC;IAGpC,KAAU,MAA2B;AACpC,OACL,EAAS;GAAE,GAAG;GAAO,SAAS;IAAE,GAAG;IAAM,MAAM;IAAU;GAAE,CAAC;;AAG9D,QACE,kBAAC,OAAD;EAAK,WAAW,CAAC,EAAE,MAAM,EAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;YAA7D,CACE,kBAAC,OAAD;GAAK,WAAW,EAAE;aACf,EAAM,KAAK,MAAS;IACnB,IAAM,IAA2B;KAAE;KAAM;KAAO,MAAM;KAAc;AACpE,IAAI,MAAS,aAAU,EAAQ,KAAK;IACpC,IAAM,IAAW,GAAM,SAAS;AAChC,WACE,kBAAC,UAAD;KAEE,MAAK;KACL,WAAW,CAAC,EAAE,QAAQ,KAAY,EAAE,aAAa,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;KAC3E,OAAO,EAAG,kBAA6B,EAAkB,EAAQ,EAAE;KACnE,OAAO;KACP,cAAY;KACZ,gBAAc;KACd,eAAe,EAAK,EAAK;KACzB,EARK,EAQL;KAEJ;GACE,CAAA,EACN,kBAAC,GAAD;GACE,OAAO;GACP,OAAO;GACP,MAAK;GACL,WAAU;GACV,WAAW,MAAM,KAAK,QAAQ,EAAO,EAAE;GACvC,CAAA,CACE"}
@@ -1,5 +1,5 @@
1
- import { forwardRef as e, useCallback as t, useEffect as n, useImperativeHandle as r, useMemo as i, useRef as a } from "react";
2
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
1
+ import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
+ import { forwardRef as n, useCallback as r, useEffect as i, useImperativeHandle as a, useMemo as o, useRef as s } from "react";
3
3
  //#region src/dlog.ts
4
4
  var c = ["weasel.debug", "weaseldraw.debug"], l = null;
5
5
  function u() {
@@ -54,26 +54,26 @@ var g = {
54
54
  root: "_root_1djm7_1",
55
55
  grid: "_grid_1djm7_28",
56
56
  axis: "_axis_1djm7_34"
57
- }, _ = e(function(e, c) {
58
- let { width: l, height: u, xRange: d = [0, 1], yRange: f = [0, 1], grid: _, axes: v, tabIndex: y, className: b, style: x, onPointerDown: S, onKeyDown: C, children: w } = e, T = a(null), E = i(() => ({
57
+ }, _ = n(function(n, c) {
58
+ let { width: l, height: u, xRange: d = [0, 1], yRange: f = [0, 1], grid: _, axes: v, tabIndex: y, className: b, style: x, onPointerDown: S, onKeyDown: C, children: w } = n, T = s(null), E = o(() => ({
59
59
  xMin: d[0],
60
60
  xMax: d[1],
61
61
  yMin: f[0],
62
62
  yMax: f[1]
63
- }), [d, f]), D = i(() => ({
63
+ }), [d, f]), D = o(() => ({
64
64
  width: l,
65
65
  height: u
66
- }), [l, u]), O = t((e) => {
66
+ }), [l, u]), O = r((e) => {
67
67
  let t = T.current?.getBoundingClientRect(), n = t?.left ?? 0, r = t?.top ?? 0;
68
68
  return {
69
69
  x: e.clientX - n,
70
70
  y: e.clientY - r
71
71
  };
72
72
  }, []);
73
- n(() => (p("plot2d", "mount", {
73
+ i(() => (p("plot2d", "mount", {
74
74
  width: l,
75
75
  height: u
76
- }), () => p("plot2d", "unmount")), []), r(c, () => ({
76
+ }), () => p("plot2d", "unmount")), []), a(c, () => ({
77
77
  get svg() {
78
78
  return T.current;
79
79
  },
@@ -92,7 +92,7 @@ var g = {
92
92
  D,
93
93
  O
94
94
  ]);
95
- let k = t((e) => {
95
+ let k = r((e) => {
96
96
  if (!S) return;
97
97
  let t = O(e);
98
98
  S(e, {
@@ -105,7 +105,7 @@ var g = {
105
105
  E,
106
106
  D
107
107
  ]);
108
- return /* @__PURE__ */ s("svg", {
108
+ return /* @__PURE__ */ t("svg", {
109
109
  ref: T,
110
110
  className: [g.root, b].filter(Boolean).join(" "),
111
111
  style: x,
@@ -118,40 +118,40 @@ var g = {
118
118
  onKeyDown: C,
119
119
  children: [
120
120
  _ && (() => {
121
- let e = _.divisions ?? 3, t = _.color, n = [];
122
- for (let t = 1; t <= e; t++) n.push(t / (e + 1));
123
- return /* @__PURE__ */ s("g", { children: [n.map((e) => /* @__PURE__ */ o("line", {
121
+ let n = _.divisions ?? 3, r = _.color, i = [];
122
+ for (let e = 1; e <= n; e++) i.push(e / (n + 1));
123
+ return /* @__PURE__ */ t("g", { children: [i.map((t) => /* @__PURE__ */ e("line", {
124
124
  "data-plot-element": "grid",
125
125
  className: g.grid,
126
- stroke: t,
127
- x1: e * l,
128
- x2: e * l,
126
+ stroke: r,
127
+ x1: t * l,
128
+ x2: t * l,
129
129
  y1: 0,
130
130
  y2: u
131
- }, `gx-${e}`)), n.map((e) => /* @__PURE__ */ o("line", {
131
+ }, `gx-${t}`)), i.map((t) => /* @__PURE__ */ e("line", {
132
132
  "data-plot-element": "grid",
133
133
  className: g.grid,
134
- stroke: t,
134
+ stroke: r,
135
135
  x1: 0,
136
136
  x2: l,
137
- y1: e * u,
138
- y2: e * u
139
- }, `gy-${e}`))] });
137
+ y1: t * u,
138
+ y2: t * u
139
+ }, `gy-${t}`))] });
140
140
  })(),
141
141
  v !== !1 && v !== null && (() => {
142
- let e = v?.color;
143
- return /* @__PURE__ */ s("g", { children: [/* @__PURE__ */ o("line", {
142
+ let n = v?.color;
143
+ return /* @__PURE__ */ t("g", { children: [/* @__PURE__ */ e("line", {
144
144
  "data-plot-element": "axis",
145
145
  className: g.axis,
146
- stroke: e,
146
+ stroke: n,
147
147
  x1: 0,
148
148
  x2: l,
149
149
  y1: u,
150
150
  y2: u
151
- }), /* @__PURE__ */ o("line", {
151
+ }), /* @__PURE__ */ e("line", {
152
152
  "data-plot-element": "axis",
153
153
  className: g.axis,
154
- stroke: e,
154
+ stroke: n,
155
155
  x1: 0,
156
156
  x2: 0,
157
157
  y1: 0,
@@ -165,4 +165,4 @@ var g = {
165
165
  //#endregion
166
166
  export { f as a, p as i, m as n, h as r, _ as t };
167
167
 
168
- //# sourceMappingURL=Plot2D-CEnhzodm.js.map
168
+ //# sourceMappingURL=Plot2D-sPXTw_-l.js.map
@@ -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\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 // Mount/unmount trace: re-running on a resize would log a spurious mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\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-sPXTw_-l.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 // Mount/unmount trace: re-running on a resize would log a spurious mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\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-SmwwvrsA.js";
1
+ import { n as e } from "./CurveEditor-BaA-PabB.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-BUIse9c4.js.map
16
+ //# sourceMappingURL=PointPlotter-CLd9u5Bq.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PointPlotter-BUIse9c4.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"}
1
+ {"version":3,"file":"PointPlotter-CLd9u5Bq.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"}
@@ -1,4 +1,4 @@
1
- import { t as e } from "./Badge-dQzbkk-C.js";
1
+ import { t as e } from "./Badge-9dPfvYOk.js";
2
2
  import { jsx as t } from "react/jsx-runtime";
3
3
  var n = {
4
4
  row: "_row_q3wun_1",
@@ -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-BYWdK8QH.js.map
36
+ //# sourceMappingURL=Powerline-DhQJYaUg.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Powerline-BYWdK8QH.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
+ {"version":3,"file":"Powerline-DhQJYaUg.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"}
@@ -0,0 +1,300 @@
1
+ import { n as e, t } from "./Tooltip-Di7vxbFa.js";
2
+ import { t as n } from "./ColorField-D1t-BdSa.js";
3
+ import { t as r } from "./Checkbox-BLEw-wEb.js";
4
+ import { t as i } from "./Input-DhWBgpRx.js";
5
+ import { t as a } from "./NumberField-ZdVa4bpJ.js";
6
+ import { n as o, t as s } from "./RadioGroup-vtwjRiUm.js";
7
+ import { t as c } from "./RangeSlider-B-n_7AgJ.js";
8
+ import { t as l } from "./Select--BVTi-j0.js";
9
+ import { t as u } from "./Switch-CtZwp5zm.js";
10
+ import { t as d } from "./Dialog-DC1x46Sq.js";
11
+ import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
12
+ import { isBuiltinToolPref as h } from "@weasel-js/core";
13
+ import { useMemo as g } from "react";
14
+ import { Focusable as _ } from "react-aria-components";
15
+ //#region src/components/paintValue.ts
16
+ function v(e) {
17
+ if (typeof e != "object" || !e) return;
18
+ let t = e;
19
+ if (!(t.fill !== void 0 && t.fill !== "solid")) return typeof t.color == "string" ? t.color : void 0;
20
+ }
21
+ function y(e) {
22
+ if (!(typeof e != "object" || !e || !("paint" in e))) return v(e.paint);
23
+ }
24
+ //#endregion
25
+ //#region src/components/Prefs/schema.ts
26
+ function b(e) {
27
+ return "kind" in e;
28
+ }
29
+ function x(e, t) {
30
+ let n = e;
31
+ for (let e of t.split(".")) {
32
+ if (typeof n != "object" || !n) return;
33
+ n = n[e];
34
+ }
35
+ return n;
36
+ }
37
+ function S(e, t) {
38
+ if (b(e)) return e.hidden && !t ? null : e;
39
+ let n = e, r = {};
40
+ for (let [e, i] of Object.entries(n.children)) {
41
+ let n = S(i, t);
42
+ n && (r[e] = n);
43
+ }
44
+ return Object.keys(r).length === 0 ? null : {
45
+ ...e,
46
+ children: r
47
+ };
48
+ }
49
+ var C = {
50
+ columns: "_columns_i4hcs_5",
51
+ column: "_column_i4hcs_5",
52
+ panel: "_panel_i4hcs_23",
53
+ subpanel: "_subpanel_i4hcs_33",
54
+ groupHeader: "_groupHeader_i4hcs_44",
55
+ groupTitle: "_groupTitle_i4hcs_57",
56
+ groupDesc: "_groupDesc_i4hcs_72",
57
+ rows: "_rows_i4hcs_79",
58
+ row: "_row_i4hcs_79",
59
+ rowLabel: "_rowLabel_i4hcs_95",
60
+ help: "_help_i4hcs_104",
61
+ rowControl: "_rowControl_i4hcs_128",
62
+ textarea: "_textarea_i4hcs_135",
63
+ unrenderable: "_unrenderable_i4hcs_147",
64
+ titleRow: "_titleRow_i4hcs_154",
65
+ objectLeaf: "_objectLeaf_i4hcs_168",
66
+ objectRow: "_objectRow_i4hcs_175",
67
+ objectLabel: "_objectLabel_i4hcs_182",
68
+ objectGroup: "_objectGroup_i4hcs_187"
69
+ };
70
+ //#endregion
71
+ //#region src/components/Prefs/PrefsForm.tsx
72
+ function w(e) {
73
+ let { schema: t, values: n, onChange: r, renderers: i, showHidden: a = !1, className: o } = e, s = g(() => S(t, a), [t, a]), c = {
74
+ values: n,
75
+ onChange: r,
76
+ renderers: i
77
+ };
78
+ return /* @__PURE__ */ p("div", {
79
+ className: [C.columns, o].filter(Boolean).join(" "),
80
+ children: Object.entries(s?.children ?? {}).map(([e, t]) => /* @__PURE__ */ p("div", {
81
+ className: C.column,
82
+ children: b(t) ? /* @__PURE__ */ p(E, {
83
+ ctx: c,
84
+ path: e,
85
+ pref: t
86
+ }) : /* @__PURE__ */ p(T, {
87
+ ctx: c,
88
+ group: t,
89
+ path: e,
90
+ depth: 0
91
+ })
92
+ }, e))
93
+ });
94
+ }
95
+ function T({ ctx: e, group: t, path: n, depth: r }) {
96
+ return /* @__PURE__ */ m("div", {
97
+ className: r === 0 ? C.panel : C.subpanel,
98
+ children: [/* @__PURE__ */ m("div", {
99
+ className: C.groupHeader,
100
+ children: [/* @__PURE__ */ p("h3", {
101
+ className: C.groupTitle,
102
+ children: t.name
103
+ }), t.description !== void 0 && /* @__PURE__ */ p("p", {
104
+ className: C.groupDesc,
105
+ children: t.description
106
+ })]
107
+ }), /* @__PURE__ */ p("div", {
108
+ className: C.rows,
109
+ children: Object.entries(t.children).map(([t, i]) => {
110
+ let a = `${n}.${t}`;
111
+ return b(i) ? /* @__PURE__ */ p(E, {
112
+ ctx: e,
113
+ path: a,
114
+ pref: i
115
+ }, t) : /* @__PURE__ */ p(T, {
116
+ ctx: e,
117
+ group: i,
118
+ path: a,
119
+ depth: r + 1
120
+ }, t);
121
+ })
122
+ })]
123
+ });
124
+ }
125
+ function E({ ctx: n, path: r, pref: i }) {
126
+ let a = x(n.values, r), o = {
127
+ path: r,
128
+ pref: i,
129
+ value: a === void 0 ? i.default : a,
130
+ setValue: (e) => n.onChange(r, e)
131
+ }, s = n.renderers?.[i.kind], c = s ? s(o) : D(o);
132
+ return s && c === null ? null : i.block ? /* @__PURE__ */ p(f, { children: c }) : /* @__PURE__ */ m("label", {
133
+ className: C.row,
134
+ children: [/* @__PURE__ */ m("span", {
135
+ className: C.rowLabel,
136
+ children: [i.name, i.description ? /* @__PURE__ */ m(e, { children: [/* @__PURE__ */ p(_, { children: /* @__PURE__ */ p("button", {
137
+ type: "button",
138
+ className: C.help,
139
+ "aria-label": `About ${i.name}`,
140
+ children: "ⓘ"
141
+ }) }), /* @__PURE__ */ p(t, { children: i.description })] }) : null]
142
+ }), /* @__PURE__ */ p("span", {
143
+ className: C.rowControl,
144
+ children: c
145
+ })]
146
+ });
147
+ }
148
+ function D(e, t) {
149
+ let { pref: d, value: f, setValue: g } = e;
150
+ if (!h(d)) return /* @__PURE__ */ m("span", {
151
+ className: C.unrenderable,
152
+ children: [
153
+ "(",
154
+ d.kind,
155
+ ": no renderer)"
156
+ ]
157
+ });
158
+ switch (d.kind) {
159
+ case "boolean": {
160
+ let e = !!f;
161
+ return d.control === "switch" ? /* @__PURE__ */ p(u, {
162
+ isSelected: e,
163
+ onChange: g,
164
+ "aria-label": d.name
165
+ }) : /* @__PURE__ */ p(r, {
166
+ isSelected: e,
167
+ onChange: g,
168
+ "aria-label": d.name
169
+ });
170
+ }
171
+ case "number": {
172
+ let e = typeof f == "number" && Number.isFinite(f) ? f : 0;
173
+ return d.control === "slider" ? /* @__PURE__ */ p(c, {
174
+ value: e,
175
+ onChange: (e) => g(typeof e == "number" ? e : e[0]),
176
+ minValue: d.min,
177
+ maxValue: d.max,
178
+ step: d.step ?? 1,
179
+ "aria-label": d.name
180
+ }) : /* @__PURE__ */ p(a, {
181
+ value: e,
182
+ onChange: g,
183
+ minValue: d.min,
184
+ maxValue: d.max,
185
+ step: d.step ?? 1,
186
+ "aria-label": d.name
187
+ });
188
+ }
189
+ case "string": {
190
+ let e = typeof f == "string" ? f : "";
191
+ return d.control === "textarea" ? /* @__PURE__ */ p("textarea", {
192
+ className: C.textarea,
193
+ value: e,
194
+ onChange: (e) => g(e.target.value),
195
+ "aria-label": d.name,
196
+ rows: 3
197
+ }) : /* @__PURE__ */ p(i, {
198
+ value: e,
199
+ onChange: g,
200
+ "aria-label": d.name
201
+ });
202
+ }
203
+ case "enum": {
204
+ let e = d.encoding, n = e ? e.read(f, t) : typeof f == "string" ? f : d.default, r = (n) => g(e ? e.write(n, t) : n);
205
+ return d.control === "radio" ? /* @__PURE__ */ p(o, {
206
+ value: n ?? null,
207
+ onChange: r,
208
+ "aria-label": d.name,
209
+ children: d.options.map((e) => /* @__PURE__ */ p(s, {
210
+ value: e.value,
211
+ isDisabled: e.disabled,
212
+ children: e.label
213
+ }, e.value))
214
+ }) : /* @__PURE__ */ p(l, {
215
+ options: d.options.map((e) => ({
216
+ value: e.value,
217
+ label: e.label,
218
+ isDisabled: e.disabled
219
+ })),
220
+ selectedKey: n ?? null,
221
+ onSelectionChange: r,
222
+ "aria-label": d.name
223
+ });
224
+ }
225
+ case "color": return /* @__PURE__ */ p(n, {
226
+ value: typeof f == "string" ? f : d.default,
227
+ alpha: d.alpha,
228
+ onChange: g,
229
+ "aria-label": d.name
230
+ });
231
+ case "paint": return /* @__PURE__ */ p(n, {
232
+ value: v(f) ?? v(d.default),
233
+ alpha: d.alpha,
234
+ onChange: (e) => g({
235
+ fill: "solid",
236
+ color: e
237
+ }),
238
+ "aria-label": d.name
239
+ });
240
+ case "object": {
241
+ let t = d, n = typeof f == "object" && f ? f : void 0, r = (i) => {
242
+ let a = [];
243
+ for (let [o, s] of Object.entries(i)) {
244
+ if (!b(s)) {
245
+ let e = r(s.children);
246
+ if (e.length === 0) continue;
247
+ a.push(/* @__PURE__ */ p("h4", {
248
+ className: C.objectGroup,
249
+ children: s.name
250
+ }, `group:${o}`), ...e);
251
+ continue;
252
+ }
253
+ a.push(/* @__PURE__ */ m("label", {
254
+ className: C.objectRow,
255
+ children: [/* @__PURE__ */ p("span", {
256
+ className: C.objectLabel,
257
+ children: s.name
258
+ }), D({
259
+ path: `${e.path}.${o}`,
260
+ pref: s,
261
+ value: n?.[o],
262
+ setValue: (e) => {
263
+ g({
264
+ ...n ?? t.fromScalar?.(f) ?? {},
265
+ [o]: e
266
+ });
267
+ }
268
+ }, n)]
269
+ }, o));
270
+ }
271
+ return a;
272
+ };
273
+ return /* @__PURE__ */ p("div", {
274
+ className: C.objectLeaf,
275
+ children: r(t.children)
276
+ });
277
+ }
278
+ default: throw Error(`PrefsForm: no control for built-in pref kind "${d.kind}"`);
279
+ }
280
+ }
281
+ //#endregion
282
+ //#region src/components/Prefs/PrefsDialog.tsx
283
+ function O(e) {
284
+ let { isOpen: t, onOpenChange: n, title: r, headerExtra: i, dialogClassName: a, ...o } = e;
285
+ return /* @__PURE__ */ p(d, {
286
+ isOpen: t,
287
+ onOpenChange: n,
288
+ "aria-label": typeof r == "string" ? r : o.schema.name,
289
+ className: a,
290
+ title: i === void 0 ? r ?? o.schema.name : /* @__PURE__ */ m("span", {
291
+ className: C.titleRow,
292
+ children: [/* @__PURE__ */ p("span", { children: r ?? o.schema.name }), i]
293
+ }),
294
+ children: /* @__PURE__ */ p(w, { ...o })
295
+ });
296
+ }
297
+ //#endregion
298
+ export { S as a, x as i, w as n, v as o, b as r, y as s, O as t };
299
+
300
+ //# sourceMappingURL=Prefs-BSJ0lMmJ.js.map