@weasel-js/ui 1.5.1 → 1.5.2
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.
- package/dist/chunks/{ActionBar-GZdcfdQL.js → ActionBar-CLwiY3Jg.js} +5 -5
- package/dist/chunks/ActionBar-CLwiY3Jg.js.map +1 -0
- package/dist/chunks/{ActionsBar-Fhx_40iP.js → ActionsBar-D84a4eGy.js} +2 -2
- package/dist/chunks/{ActionsBar-Fhx_40iP.js.map → ActionsBar-D84a4eGy.js.map} +1 -1
- package/dist/chunks/{Badge-Bf8Rd1R6.js → Badge-CW9pBPFl.js} +5 -5
- package/dist/chunks/Badge-CW9pBPFl.js.map +1 -0
- package/dist/chunks/{BandEditor-D8I5Uun-.js → BandEditor-jY-PFKY6.js} +12 -12
- package/dist/chunks/BandEditor-jY-PFKY6.js.map +1 -0
- package/dist/chunks/{Button-CExdkQcU.js → Button-DRSApvnK.js} +15 -15
- package/dist/chunks/Button-DRSApvnK.js.map +1 -0
- package/dist/chunks/{Callout-cx5_CWcW.js → Callout-DrNu-9Qr.js} +12 -12
- package/dist/chunks/Callout-DrNu-9Qr.js.map +1 -0
- package/dist/chunks/{Checkbox-BZZsPaVF.js → Checkbox-BOsDAY2F.js} +5 -5
- package/dist/chunks/Checkbox-BOsDAY2F.js.map +1 -0
- package/dist/chunks/{ColorField-YVf8irfr.js → ColorField-BYzgZM9o.js} +6 -6
- package/dist/chunks/ColorField-BYzgZM9o.js.map +1 -0
- package/dist/chunks/{ComboBox-D57tNYDD.js → ComboBox-Cz3f0Y_8.js} +13 -13
- package/dist/chunks/ComboBox-Cz3f0Y_8.js.map +1 -0
- package/dist/chunks/{CurveEditor-BXiMoN9d.js → CurveEditor-DXwSP-iA.js} +2 -2
- package/dist/chunks/{CurveEditor-BXiMoN9d.js.map → CurveEditor-DXwSP-iA.js.map} +1 -1
- package/dist/chunks/{DataGrid-BVdDMZkQ.js → DataGrid-C8KrYtw7.js} +11 -11
- package/dist/chunks/DataGrid-C8KrYtw7.js.map +1 -0
- package/dist/chunks/{DetentSlider-BWNSv07Z.js → DetentSlider-CAubVX0J.js} +2 -2
- package/dist/chunks/{DetentSlider-BWNSv07Z.js.map → DetentSlider-CAubVX0J.js.map} +1 -1
- package/dist/chunks/{Dialog-DuOzsR2g.js → Dialog-fGqqQ6o_.js} +9 -9
- package/dist/chunks/Dialog-fGqqQ6o_.js.map +1 -0
- package/dist/chunks/{Disclosure-9UgDzc7Z.js → Disclosure-CILDfWsU.js} +6 -6
- package/dist/chunks/Disclosure-CILDfWsU.js.map +1 -0
- package/dist/chunks/{Field-BNqvUJfg.js → Field-DWnV8WZY.js} +6 -6
- package/dist/chunks/Field-DWnV8WZY.js.map +1 -0
- package/dist/chunks/{FontFamilySelect-CO19kyOO.js → FontFamilySelect-DxfgTC3G.js} +2 -2
- package/dist/chunks/{FontFamilySelect-CO19kyOO.js.map → FontFamilySelect-DxfgTC3G.js.map} +1 -1
- package/dist/chunks/{GradientEditor-B_ymIr4Q.js → GradientEditor-rRBmf3G0.js} +7 -7
- package/dist/chunks/GradientEditor-rRBmf3G0.js.map +1 -0
- package/dist/chunks/{Icon-QhLhaGFe.js → Icon-DT0x6HaQ.js} +23 -2
- package/dist/chunks/Icon-DT0x6HaQ.js.map +1 -0
- package/dist/chunks/{Input-B9Vh7ASP.js → Input-DbMKpkXy.js} +5 -5
- package/dist/chunks/Input-DbMKpkXy.js.map +1 -0
- package/dist/chunks/{ItemList-BZJQReXD.js → ItemList-B9zYb0GE.js} +7 -7
- package/dist/chunks/ItemList-B9zYb0GE.js.map +1 -0
- package/dist/chunks/{Jog-BYrxbAQU.js → Jog-DkkTlL3_.js} +8 -8
- package/dist/chunks/Jog-DkkTlL3_.js.map +1 -0
- package/dist/chunks/{Keycaps-CGNQV2Pz.js → Keycaps-DunVpejA.js} +5 -5
- package/dist/chunks/{Keycaps-CGNQV2Pz.js.map → Keycaps-DunVpejA.js.map} +1 -1
- package/dist/chunks/{LayerStack-DOylrQcm.js → LayerStack-CfQ6GsRz.js} +18 -18
- package/dist/chunks/LayerStack-CfQ6GsRz.js.map +1 -0
- package/dist/chunks/{MenuButton-DGE-0DP0.js → MenuButton-C_4nox39.js} +7 -7
- package/dist/chunks/MenuButton-C_4nox39.js.map +1 -0
- package/dist/chunks/{MeshEditor-CHoGQ9K8.js → MeshEditor-Bipz-Ocl.js} +8 -8
- package/dist/chunks/MeshEditor-Bipz-Ocl.js.map +1 -0
- package/dist/chunks/{NumberField-CQzS6TjF.js → NumberField-CCjEDZCg.js} +9 -9
- package/dist/chunks/NumberField-CCjEDZCg.js.map +1 -0
- package/dist/chunks/{OptionsBar-BWaYG_OH.js → OptionsBar-DeQ-vUeZ.js} +2 -2
- package/dist/chunks/{OptionsBar-BWaYG_OH.js.map → OptionsBar-DeQ-vUeZ.js.map} +1 -1
- package/dist/chunks/{PaintField-BVYMu3OI.js → PaintField-jBOJ32rL.js} +8 -8
- package/dist/chunks/PaintField-jBOJ32rL.js.map +1 -0
- package/dist/chunks/{PaintInput-BzAHCKro.js → PaintInput-Qs7Rul5R.js} +10 -10
- package/dist/chunks/PaintInput-Qs7Rul5R.js.map +1 -0
- package/dist/chunks/{PatternPicker-C4OryrYi.js → PatternPicker-BMpXWboq.js} +6 -6
- package/dist/chunks/PatternPicker-BMpXWboq.js.map +1 -0
- package/dist/chunks/{Plot2D-Czvyt_vG.js → Plot2D-CXf_f7QD.js} +1 -1
- package/dist/chunks/{Plot2D-Czvyt_vG.js.map → Plot2D-CXf_f7QD.js.map} +1 -1
- package/dist/chunks/{PointPlotter-Xvb98GwB.js → PointPlotter-S_gz7VYt.js} +2 -2
- package/dist/chunks/{PointPlotter-Xvb98GwB.js.map → PointPlotter-S_gz7VYt.js.map} +1 -1
- package/dist/chunks/{Powerline-B_EH-7Z-.js → Powerline-Ak5AWUlK.js} +5 -5
- package/dist/chunks/Powerline-Ak5AWUlK.js.map +1 -0
- package/dist/chunks/Prefs-CNC8tzyN.js +308 -0
- package/dist/chunks/Prefs-CNC8tzyN.js.map +1 -0
- package/dist/chunks/{Properties-B3KU69NI.js → Properties-Rnb6TAbN.js} +230 -213
- package/dist/chunks/Properties-Rnb6TAbN.js.map +1 -0
- package/dist/chunks/{RadioGroup-C6xpdQNg.js → RadioGroup-CsVp3SEu.js} +6 -6
- package/dist/chunks/RadioGroup-CsVp3SEu.js.map +1 -0
- package/dist/chunks/{RangeSlider-CzgeGLVS.js → RangeSlider-DNr-pJpZ.js} +8 -8
- package/dist/chunks/RangeSlider-DNr-pJpZ.js.map +1 -0
- package/dist/chunks/{ResizeHandle-1Ey8AOij.js → ResizeHandle-RXFf5fXr.js} +1 -1
- package/dist/chunks/{ResizeHandle-1Ey8AOij.js.map → ResizeHandle-RXFf5fXr.js.map} +1 -1
- package/dist/chunks/Select-BEope086.js +190 -0
- package/dist/chunks/Select-BEope086.js.map +1 -0
- package/dist/chunks/SelectionPanel-CEbLS-0D.js +102 -0
- package/dist/chunks/SelectionPanel-CEbLS-0D.js.map +1 -0
- package/dist/chunks/{Sidebar-BlUjn8lD.js → Sidebar-qn_oSCNX.js} +4 -4
- package/dist/chunks/Sidebar-qn_oSCNX.js.map +1 -0
- package/dist/chunks/{SidebarPanel-BqHfz6VK.js → SidebarPanel-Bs6V21hg.js} +12 -12
- package/dist/chunks/SidebarPanel-Bs6V21hg.js.map +1 -0
- package/dist/chunks/{Slider-B2ywUZH6.js → Slider-CIIrqiFS.js} +18 -18
- package/dist/chunks/Slider-CIIrqiFS.js.map +1 -0
- package/dist/chunks/{StatusBar-BFt7Yw5O.js → StatusBar-B4L15DSm.js} +6 -6
- package/dist/chunks/StatusBar-B4L15DSm.js.map +1 -0
- package/dist/chunks/{Switch-Om3t3ASc.js → Switch-DH5POG0T.js} +5 -5
- package/dist/chunks/Switch-DH5POG0T.js.map +1 -0
- package/dist/chunks/{Tabs-EAvYywil.js → Tabs-BFHikpml.js} +5 -5
- package/dist/chunks/Tabs-BFHikpml.js.map +1 -0
- package/dist/chunks/{Timeline-BEyKaBXl.js → Timeline-DNKY_yiK.js} +40 -40
- package/dist/chunks/Timeline-DNKY_yiK.js.map +1 -0
- package/dist/chunks/{Toast-iqLDD_XZ.js → Toast-CI1UDuK6.js} +15 -15
- package/dist/chunks/Toast-CI1UDuK6.js.map +1 -0
- package/dist/chunks/{ToggleBar--9As2PWG.js → ToggleBar-CClus5Cd.js} +8 -8
- package/dist/chunks/ToggleBar-CClus5Cd.js.map +1 -0
- package/dist/chunks/TokenPanel-BPHq24dc.js +634 -0
- package/dist/chunks/TokenPanel-BPHq24dc.js.map +1 -0
- package/dist/chunks/{ToolButton-Dd-1T5aX.js → ToolButton-9QzJCmuM.js} +7 -7
- package/dist/chunks/ToolButton-9QzJCmuM.js.map +1 -0
- package/dist/chunks/{ToolGroup-BBI-W-Gm.js → ToolGroup-BJiDrH_i.js} +3 -3
- package/dist/chunks/ToolGroup-BJiDrH_i.js.map +1 -0
- package/dist/chunks/ToolOptionsBar-CAM6RcUH.js +85 -0
- package/dist/chunks/ToolOptionsBar-CAM6RcUH.js.map +1 -0
- package/dist/chunks/{ToolPalette-BmTDDpmz.js → ToolPalette-DGkKwE7D.js} +8 -8
- package/dist/chunks/ToolPalette-DGkKwE7D.js.map +1 -0
- package/dist/chunks/{Tooltip-BHre_vbI.js → Tooltip-C4YBczLq.js} +3 -3
- package/dist/chunks/Tooltip-C4YBczLq.js.map +1 -0
- package/dist/chunks/{createKeyframeLayer-7j7ukrSx.js → createKeyframeLayer-DKtO0Sw_.js} +3 -3
- package/dist/chunks/{createKeyframeLayer-7j7ukrSx.js.map → createKeyframeLayer-DKtO0Sw_.js.map} +1 -1
- package/dist/chunks/{icons-Btrs-JD7.js → icons-DFLytcui.js} +2 -2
- package/dist/chunks/{icons-Btrs-JD7.js.map → icons-DFLytcui.js.map} +1 -1
- package/dist/chunks/model-13kZ_-mE.js +483 -0
- package/dist/chunks/model-13kZ_-mE.js.map +1 -0
- package/dist/chunks/number-BHz66zQO.js +89 -0
- package/dist/chunks/number-BHz66zQO.js.map +1 -0
- package/dist/chunks/{schema-MCVT1MLv.js → schema-Dft4Cu2p.js} +1 -1
- package/dist/chunks/schema-Dft4Cu2p.js.map +1 -0
- package/dist/chunks/segmentedControl.module-DS72X1ns.js +11 -0
- package/dist/chunks/segmentedControl.module-DS72X1ns.js.map +1 -0
- package/dist/chunks/{snap-B0WQwetQ.js → snap-CEjuWOhN.js} +1 -1
- package/dist/chunks/{snap-B0WQwetQ.js.map → snap-CEjuWOhN.js.map} +1 -1
- package/dist/chunks/useRovingTabIndex-Dkpf_KhN.js.map +1 -1
- package/dist/color/oklch.d.ts +2 -1
- package/dist/color/oklch.d.ts.map +1 -1
- package/dist/components/ActionBar/index.js +1 -1
- package/dist/components/ActionsBar/index.js +1 -1
- package/dist/components/Badge/index.js +1 -1
- package/dist/components/BandEditor/index.js +1 -1
- package/dist/components/Button/index.js +1 -1
- package/dist/components/Callout/index.js +1 -1
- package/dist/components/Checkbox/index.js +1 -1
- package/dist/components/ColorField/index.js +1 -1
- package/dist/components/ComboBox/index.js +1 -1
- package/dist/components/CurveEditor/index.js +3 -3
- package/dist/components/DataGrid/index.js +1 -1
- package/dist/components/DetentSlider/index.js +1 -1
- package/dist/components/Dialog/index.js +1 -1
- package/dist/components/Disclosure/index.js +1 -1
- package/dist/components/Field/index.js +1 -1
- package/dist/components/FontFamilySelect/index.js +1 -1
- package/dist/components/GradientEditor/index.js +1 -1
- package/dist/components/Input/index.js +1 -1
- package/dist/components/ItemList/index.js +1 -1
- package/dist/components/Jog/index.js +1 -1
- package/dist/components/Keycaps/index.js +1 -1
- package/dist/components/LayerStack/index.js +1 -1
- package/dist/components/MenuButton/index.js +1 -1
- package/dist/components/MeshEditor/index.js +1 -1
- package/dist/components/NumberField/UnitField.d.ts +2 -1
- package/dist/components/NumberField/UnitField.d.ts.map +1 -1
- package/dist/components/NumberField/index.js +1 -1
- package/dist/components/OptionsBar/index.js +1 -1
- package/dist/components/PaintField/index.js +1 -1
- package/dist/components/PaintInput/index.js +1 -1
- package/dist/components/PatternPicker/index.js +1 -1
- package/dist/components/Plot2D/index.js +1 -1
- package/dist/components/PointPlotter/index.js +1 -1
- package/dist/components/Powerline/index.js +2 -2
- package/dist/components/Prefs/index.js +2 -2
- package/dist/components/Prefs/schema.d.ts +2 -1
- package/dist/components/Prefs/schema.d.ts.map +1 -1
- package/dist/components/Properties/PropertyGroup.d.ts +7 -1
- package/dist/components/Properties/PropertyGroup.d.ts.map +1 -1
- package/dist/components/Properties/PropertyPanel.d.ts +36 -38
- package/dist/components/Properties/PropertyPanel.d.ts.map +1 -1
- package/dist/components/Properties/index.d.ts +2 -4
- package/dist/components/Properties/index.d.ts.map +1 -1
- package/dist/components/Properties/index.js +2 -2
- package/dist/components/RadioGroup/index.js +1 -1
- package/dist/components/RangeSlider/index.js +1 -1
- package/dist/components/ResizeHandle/index.js +1 -1
- package/dist/components/Select/Select.d.ts +18 -0
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/index.d.ts +1 -1
- package/dist/components/Select/index.d.ts.map +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/SelectionPanel/SelectionPanel.d.ts +3 -50
- package/dist/components/SelectionPanel/SelectionPanel.d.ts.map +1 -1
- package/dist/components/SelectionPanel/index.js +3 -2
- package/dist/components/SelectionPanel/model.d.ts +4 -1
- package/dist/components/SelectionPanel/model.d.ts.map +1 -1
- package/dist/components/SelectionPanel/renderLeaf.d.ts +106 -0
- package/dist/components/SelectionPanel/renderLeaf.d.ts.map +1 -0
- package/dist/components/Sidebar/index.js +1 -1
- package/dist/components/SidebarPanel/index.js +1 -1
- package/dist/components/Slider/index.js +1 -1
- package/dist/components/StatusBar/index.js +1 -1
- package/dist/components/Switch/index.js +1 -1
- package/dist/components/Tabs/index.js +1 -1
- package/dist/components/Timeline/index.js +1 -1
- package/dist/components/Toast/index.js +1 -1
- package/dist/components/ToggleBar/index.js +1 -1
- package/dist/components/TokenPanel/TokenPanel.d.ts +10 -4
- package/dist/components/TokenPanel/TokenPanel.d.ts.map +1 -1
- package/dist/components/TokenPanel/index.d.ts +2 -2
- package/dist/components/TokenPanel/index.d.ts.map +1 -1
- package/dist/components/TokenPanel/index.js +2 -2
- package/dist/components/TokenPanel/tokenTypes.d.ts +24 -0
- package/dist/components/TokenPanel/tokenTypes.d.ts.map +1 -1
- package/dist/components/ToolButton/index.js +1 -1
- package/dist/components/ToolGroup/index.js +1 -1
- package/dist/components/ToolOptionsBar/ToolOptionsBar.d.ts +29 -18
- package/dist/components/ToolOptionsBar/ToolOptionsBar.d.ts.map +1 -1
- package/dist/components/ToolOptionsBar/index.js +1 -1
- package/dist/components/ToolPalette/ToolPalette.d.ts +5 -4
- package/dist/components/ToolPalette/ToolPalette.d.ts.map +1 -1
- package/dist/components/ToolPalette/index.js +1 -1
- package/dist/components/Tooltip/index.js +1 -1
- package/dist/format/number.d.ts +10 -1
- package/dist/format/number.d.ts.map +1 -1
- package/dist/icons/paths.d.ts +9 -1
- package/dist/icons/paths.d.ts.map +1 -1
- package/dist/index.js +69 -75
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/useRovingTabIndex.d.ts +7 -5
- package/dist/useRovingTabIndex.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/chunks/ActionBar-GZdcfdQL.js.map +0 -1
- package/dist/chunks/Badge-Bf8Rd1R6.js.map +0 -1
- package/dist/chunks/BandEditor-D8I5Uun-.js.map +0 -1
- package/dist/chunks/Button-CExdkQcU.js.map +0 -1
- package/dist/chunks/Callout-cx5_CWcW.js.map +0 -1
- package/dist/chunks/Checkbox-BZZsPaVF.js.map +0 -1
- package/dist/chunks/ColorField-YVf8irfr.js.map +0 -1
- package/dist/chunks/ComboBox-D57tNYDD.js.map +0 -1
- package/dist/chunks/DataGrid-BVdDMZkQ.js.map +0 -1
- package/dist/chunks/Dialog-DuOzsR2g.js.map +0 -1
- package/dist/chunks/Disclosure-9UgDzc7Z.js.map +0 -1
- package/dist/chunks/Field-BNqvUJfg.js.map +0 -1
- package/dist/chunks/GradientEditor-B_ymIr4Q.js.map +0 -1
- package/dist/chunks/Icon-QhLhaGFe.js.map +0 -1
- package/dist/chunks/Input-B9Vh7ASP.js.map +0 -1
- package/dist/chunks/ItemList-BZJQReXD.js.map +0 -1
- package/dist/chunks/Jog-BYrxbAQU.js.map +0 -1
- package/dist/chunks/LayerStack-DOylrQcm.js.map +0 -1
- package/dist/chunks/MenuButton-DGE-0DP0.js.map +0 -1
- package/dist/chunks/MeshEditor-CHoGQ9K8.js.map +0 -1
- package/dist/chunks/NumberField-CQzS6TjF.js.map +0 -1
- package/dist/chunks/PaintField-BVYMu3OI.js.map +0 -1
- package/dist/chunks/PaintInput-BzAHCKro.js.map +0 -1
- package/dist/chunks/PatternPicker-C4OryrYi.js.map +0 -1
- package/dist/chunks/Powerline-B_EH-7Z-.js.map +0 -1
- package/dist/chunks/Prefs-FuaJBs3t.js +0 -308
- package/dist/chunks/Prefs-FuaJBs3t.js.map +0 -1
- package/dist/chunks/Properties-B3KU69NI.js.map +0 -1
- package/dist/chunks/RadioGroup-C6xpdQNg.js.map +0 -1
- package/dist/chunks/RangeSlider-CzgeGLVS.js.map +0 -1
- package/dist/chunks/Select-BMYVh10x.js +0 -127
- package/dist/chunks/Select-BMYVh10x.js.map +0 -1
- package/dist/chunks/SelectionPanel-DTpcQidl.js +0 -572
- package/dist/chunks/SelectionPanel-DTpcQidl.js.map +0 -1
- package/dist/chunks/Sidebar-BlUjn8lD.js.map +0 -1
- package/dist/chunks/SidebarPanel-BqHfz6VK.js.map +0 -1
- package/dist/chunks/Slider-B2ywUZH6.js.map +0 -1
- package/dist/chunks/StatusBar-BFt7Yw5O.js.map +0 -1
- package/dist/chunks/Switch-Om3t3ASc.js.map +0 -1
- package/dist/chunks/Tabs-EAvYywil.js.map +0 -1
- package/dist/chunks/Timeline-BEyKaBXl.js.map +0 -1
- package/dist/chunks/Toast-iqLDD_XZ.js.map +0 -1
- package/dist/chunks/ToggleBar--9As2PWG.js.map +0 -1
- package/dist/chunks/TokenPanel-BL9hlq7x.js +0 -374
- package/dist/chunks/TokenPanel-BL9hlq7x.js.map +0 -1
- package/dist/chunks/ToolButton-Dd-1T5aX.js.map +0 -1
- package/dist/chunks/ToolGroup-BBI-W-Gm.js.map +0 -1
- package/dist/chunks/ToolOptionsBar-B2xPWzJf.js +0 -27
- package/dist/chunks/ToolOptionsBar-B2xPWzJf.js.map +0 -1
- package/dist/chunks/ToolPalette-BmTDDpmz.js.map +0 -1
- package/dist/chunks/Tooltip-BHre_vbI.js.map +0 -1
- package/dist/chunks/number-f6PydOZK.js +0 -52
- package/dist/chunks/number-f6PydOZK.js.map +0 -1
- package/dist/chunks/schema-MCVT1MLv.js.map +0 -1
- package/dist/chunks/segmentedControl.module-DmeUMYe3.js +0 -11
- package/dist/chunks/segmentedControl.module-DmeUMYe3.js.map +0 -1
- package/dist/components/Properties/PinDot.d.ts +0 -18
- package/dist/components/Properties/PinDot.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Plot2D-Czvyt_vG.js","names":[],"sources":["../../src/components/Plot2D/geometry.ts","../../src/components/Plot2D/ticks.ts","../../src/components/Plot2D/Plot2D.module.css","../../src/components/Plot2D/Plot2D.tsx"],"sourcesContent":["/**\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","/**\n * Tick placement for a numeric axis. Pure — no DOM, no React.\n */\n\n/** What a tick label formatter knows about the column it is part of. */\nexport interface TickFormatCtx {\n /** Places after the point that every label in the column shares. */\n decimals: number;\n /** Distance between neighboring ticks, or 0 when the ticks were given\n * explicitly and are not evenly spaced. */\n step: number;\n}\n\n/** Turns a tick value into its label. */\nexport type TickFormatter = (value: number, ctx: TickFormatCtx) => string;\n\n/** A column of ticks and the facts its labels share. */\nexport interface TickSet {\n values: number[];\n step: number;\n decimals: number;\n}\n\n/** Options for {@link niceTicks}. */\nexport interface NiceTickOptions {\n /** Smallest gap between neighboring ticks, in px. */\n minSpacing: number;\n /** Ticks closer than this to either end of the axis are dropped, in px.\n * Default 0. */\n inset?: number;\n}\n\nconst MAX_DECIMALS = 20;\n\n/** The smallest of 1, 2 or 5 times a power of ten that is at least `rough`. */\nexport function niceStep(rough: number): number {\n const mag = Math.pow(10, Math.floor(Math.log10(rough)));\n const norm = rough / mag;\n const step = norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10;\n return step * mag;\n}\n\n/** Places after the point a multiple of `step` needs, for a 1/2/5 step. */\nexport function stepDecimals(step: number): number {\n if (!(step > 0) || !Number.isFinite(step)) return 0;\n return Math.min(MAX_DECIMALS, Math.max(0, -Math.floor(Math.log10(step) + 1e-9)));\n}\n\n/** The most places after the point any of `values` needs. */\nexport function tickDecimals(values: readonly number[]): number {\n let most = 0;\n for (const v of values) {\n if (!Number.isFinite(v)) continue;\n let d = 0;\n while (d < MAX_DECIMALS && Math.abs(Number(v.toFixed(d)) - v) > 1e-9 * Math.max(1, Math.abs(v))) d++;\n most = Math.max(most, d);\n }\n return most;\n}\n\n/**\n * Ticks at round values across `range`, drawn `pixels` long: the finest\n * 1/2/5 step that keeps neighbors `minSpacing` px apart, so a taller plot\n * gets more of them.\n */\nexport function niceTicks(\n range: readonly [number, number],\n pixels: number,\n options: NiceTickOptions,\n): TickSet {\n const none: TickSet = { values: [], step: 0, decimals: 0 };\n const lo = Math.min(range[0], range[1]);\n const hi = Math.max(range[0], range[1]);\n const span = hi - lo;\n const { minSpacing, inset = 0 } = options;\n if (!(span > 0) || !Number.isFinite(span) || !(pixels > 0) || !(minSpacing > 0)) return none;\n\n const unitsPerPx = span / pixels;\n const step = niceStep(minSpacing * unitsPerPx);\n const decimals = stepDecimals(step);\n const from = lo + inset * unitsPerPx;\n const to = hi - inset * unitsPerPx;\n // A tolerance in step units, so a tick sitting exactly on a bound survives\n // the float error in `from / step`.\n const first = Math.ceil(from / step - 1e-9);\n const last = Math.floor(to / step + 1e-9);\n const values: number[] = [];\n for (let i = first; i <= last; i++) values.push(Number((i * step).toFixed(decimals)) + 0);\n return { values, step, decimals };\n}\n\n/** The default label: `value` fixed to the column's shared decimals, with\n * no negative zero. */\nexport function formatTick(value: number, ctx: TickFormatCtx): string {\n const text = value.toFixed(ctx.decimals);\n return /^-0(\\.0*)?$/.test(text) ? text.slice(1) : text;\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 --plot-tick: var(--wzl-line-subtle);\n --plot-tick-label: var(--wzl-fg-muted);\n /* Knocks the tick line out from behind an inside label. */\n --plot-tick-label-halo: var(--plot-bg);\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\n.tick {\n stroke: var(--plot-tick);\n stroke-width: 1;\n fill: none;\n}\n\n.tickLabels { pointer-events: none; }\n\n.tickLabel {\n fill: var(--plot-tick-label);\n font-size: var(--wzl-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tickLabel[data-placement='inside'] {\n stroke: var(--plot-tick-label-halo);\n stroke-width: 3px;\n stroke-linejoin: round;\n paint-order: stroke;\n}\n","import {\n forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState,\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 {\n formatTick, niceTicks, tickDecimals,\n type TickFormatCtx, type TickFormatter,\n} from './ticks';\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/**\n * Ticks along one axis of a {@link Plot2D}: a line across the plot at each\n * tick value, and a label naming it. Every label in a column is formatted\n * to the same number of decimal places.\n */\nexport interface TickSettings {\n /** Tick values in model space; any outside the range are skipped.\n * Omitted = round 1/2/5 steps, as many as `minSpacing` allows at the\n * plot's current size. */\n values?: readonly number[];\n /** Smallest gap between generated ticks, in px. Default 24 on y, 64 on x. */\n minSpacing?: number;\n /** A generated tick nearer either end of the axis than this is dropped,\n * so its label stays on the plot, in px. Default 4 on y, 16 on x. */\n inset?: number;\n /** Draw a line across the plot at each tick. Default true. */\n lines?: boolean;\n /** Where labels sit: `'inside'` the plot along its left (y) or bottom (x)\n * edge, `'outside'` it past that edge in space the caller leaves free,\n * or `false` for none. Default `'inside'`. */\n labels?: 'inside' | 'outside' | false;\n /** Space between a label and the plot edge it sits against, in px.\n * Default 4. */\n gap?: number;\n /** Label text for a tick. Default {@link formatTick}. */\n format?: TickFormatter;\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 /** Ticks at x values. `false` / `null` / omitted = none; `{}` = defaults. */\n xTicks?: TickSettings | false | null;\n /** Ticks at y values. `false` / `null` / omitted = none; `{}` = defaults. */\n yTicks?: TickSettings | false | null;\n /** Forwarded to the underlying svg. Consumer opts into focus this way. */\n tabIndex?: number;\n /** Default `'img'`. A plot holding focusable marks must not be an image,\n * whose children are presentational to assistive technology. */\n role?: string;\n 'aria-label'?: string;\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\ntype Axis = 'x' | 'y';\n\nconst TICK_SPACING_PX: Record<Axis, number> = { x: 64, y: 24 };\nconst TICK_INSET_PX: Record<Axis, number> = { x: 16, y: 4 };\nconst LABEL_GAP_PX = 4;\n\ninterface ResolvedTick {\n value: number;\n /** Plot-space position along the axis. */\n at: number;\n label: string;\n}\n\nfunction resolveTicks(\n settings: TickSettings,\n axis: Axis,\n range: readonly [number, number],\n pixels: number,\n toPlot: (v: number) => number,\n): ResolvedTick[] {\n let values: number[];\n let ctx: TickFormatCtx;\n if (settings.values) {\n const lo = Math.min(range[0], range[1]);\n const hi = Math.max(range[0], range[1]);\n const eps = (hi - lo) * 1e-9;\n values = settings.values.filter((v) => v >= lo - eps && v <= hi + eps);\n const gaps = values.slice(1).map((v, i) => v - values[i]);\n const even = gaps.length > 0 && gaps.every((g) => Math.abs(g - gaps[0]) <= Math.abs(gaps[0]) * 1e-9);\n ctx = { decimals: tickDecimals(values), step: even ? gaps[0] : 0 };\n } else {\n const set = niceTicks(range, pixels, {\n minSpacing: settings.minSpacing ?? TICK_SPACING_PX[axis],\n inset: settings.inset ?? TICK_INSET_PX[axis],\n });\n values = set.values;\n ctx = { decimals: set.decimals, step: set.step };\n }\n const format = settings.format ?? formatTick;\n return values.map((value) => ({ value, at: toPlot(value), label: format(value, ctx) }));\n}\n\n/**\n * An SVG plotting surface with an optional grid, axes and ticks. It draws the\n * frame 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 xTicks,\n yTicks,\n tabIndex,\n role = 'img',\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 xTickList = xTicks\n ? resolveTicks(xTicks, 'x', xRange, width, (v) => modelToPlot({ x: v, y: yRange[0] }, modelRange, plotSize).x)\n : [];\n const yTickList = yTicks\n ? resolveTicks(yTicks, 'y', yRange, height, (v) => modelToPlot({ x: xRange[0], y: v }, modelRange, plotSize).y)\n : [];\n\n // An inside y column is right-aligned against its widest label, which only\n // the rendered text can say.\n const yInside = !!yTicks && (yTicks.labels ?? 'inside') === 'inside';\n const yLabelsRef = useRef<SVGGElement | null>(null);\n const [yLabelWidth, setYLabelWidth] = useState(0);\n const yLabelKey = yInside ? yTickList.map((t) => t.label).join('\\n') : '';\n useLayoutEffect(() => {\n if (!yInside) return;\n const measure = (): void => {\n let widest = 0;\n for (const el of yLabelsRef.current?.querySelectorAll('text') ?? []) {\n if (typeof el.getComputedTextLength === 'function') widest = Math.max(widest, el.getComputedTextLength());\n }\n setYLabelWidth((prev) => (prev === widest ? prev : widest));\n };\n measure();\n let live = true;\n // A web font landing after the first measure changes every width.\n document.fonts?.ready.then(() => { if (live) measure(); });\n return () => { live = false; };\n }, [yInside, yLabelKey]);\n\n const cls = [s.root, className].filter(Boolean).join(' ');\n\n const renderTickLines = (axis: Axis, list: ResolvedTick[], settings: TickSettings | false | null | undefined) => {\n if (!settings || settings.lines === false || list.length === 0) return null;\n return (\n <g>\n {list.map((t) => (\n <line\n key={`t${axis}-${t.value}`}\n data-plot-element=\"tick\"\n data-axis={axis}\n className={s.tick}\n {...(axis === 'x'\n ? { x1: t.at, x2: t.at, y1: 0, y2: height }\n : { x1: 0, x2: width, y1: t.at, y2: t.at })}\n />\n ))}\n </g>\n );\n };\n\n const renderTickLabels = (axis: Axis, list: ResolvedTick[], settings: TickSettings | false | null | undefined) => {\n if (!settings || list.length === 0) return null;\n const placement = settings.labels ?? 'inside';\n if (placement === false) return null;\n const outside = placement === 'outside';\n const gap = settings.gap ?? LABEL_GAP_PX;\n let place: { x?: number; y?: number; textAnchor: 'start' | 'middle' | 'end'; dominantBaseline?: 'central' | 'hanging' };\n if (axis === 'y') {\n place = outside\n ? { x: -gap, textAnchor: 'end', dominantBaseline: 'central' }\n : yLabelWidth > 0\n ? { x: gap + yLabelWidth, textAnchor: 'end', dominantBaseline: 'central' }\n : { x: gap, textAnchor: 'start', dominantBaseline: 'central' };\n } else {\n place = outside\n ? { y: height + gap, textAnchor: 'middle', dominantBaseline: 'hanging' }\n : { y: height - gap, textAnchor: 'middle' };\n }\n return (\n <g ref={axis === 'y' ? yLabelsRef : undefined} className={s.tickLabels} aria-hidden=\"true\">\n {list.map((t) => (\n <text\n key={`l${axis}-${t.value}`}\n data-plot-element=\"tick-label\"\n data-axis={axis}\n data-placement={placement}\n className={s.tickLabel}\n x={axis === 'x' ? t.at : place.x}\n y={axis === 'y' ? t.at : place.y}\n textAnchor={place.textAnchor}\n dominantBaseline={place.dominantBaseline}\n >\n {t.label}\n </text>\n ))}\n </g>\n );\n };\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={role}\n aria-label={props['aria-label']}\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 {renderTickLines('x', xTickList, xTicks)}\n {renderTickLines('y', yTickList, yTicks)}\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 {renderTickLabels('x', xTickList, xTicks)}\n {renderTickLabels('y', yTickList, yTicks)}\n {children}\n </svg>\n );\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Plot2D-CXf_f7QD.js","names":[],"sources":["../../src/components/Plot2D/geometry.ts","../../src/components/Plot2D/ticks.ts","../../src/components/Plot2D/Plot2D.module.css","../../src/components/Plot2D/Plot2D.tsx"],"sourcesContent":["/**\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","/**\n * Tick placement for a numeric axis. Pure — no DOM, no React.\n */\n\n/** What a tick label formatter knows about the column it is part of. */\nexport interface TickFormatCtx {\n /** Places after the point that every label in the column shares. */\n decimals: number;\n /** Distance between neighboring ticks, or 0 when the ticks were given\n * explicitly and are not evenly spaced. */\n step: number;\n}\n\n/** Turns a tick value into its label. */\nexport type TickFormatter = (value: number, ctx: TickFormatCtx) => string;\n\n/** A column of ticks and the facts its labels share. */\nexport interface TickSet {\n values: number[];\n step: number;\n decimals: number;\n}\n\n/** Options for {@link niceTicks}. */\nexport interface NiceTickOptions {\n /** Smallest gap between neighboring ticks, in px. */\n minSpacing: number;\n /** Ticks closer than this to either end of the axis are dropped, in px.\n * Default 0. */\n inset?: number;\n}\n\nconst MAX_DECIMALS = 20;\n\n/** The smallest of 1, 2 or 5 times a power of ten that is at least `rough`. */\nexport function niceStep(rough: number): number {\n const mag = Math.pow(10, Math.floor(Math.log10(rough)));\n const norm = rough / mag;\n const step = norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10;\n return step * mag;\n}\n\n/** Places after the point a multiple of `step` needs, for a 1/2/5 step. */\nexport function stepDecimals(step: number): number {\n if (!(step > 0) || !Number.isFinite(step)) return 0;\n return Math.min(MAX_DECIMALS, Math.max(0, -Math.floor(Math.log10(step) + 1e-9)));\n}\n\n/** The most places after the point any of `values` needs. */\nexport function tickDecimals(values: readonly number[]): number {\n let most = 0;\n for (const v of values) {\n if (!Number.isFinite(v)) continue;\n let d = 0;\n while (d < MAX_DECIMALS && Math.abs(Number(v.toFixed(d)) - v) > 1e-9 * Math.max(1, Math.abs(v))) d++;\n most = Math.max(most, d);\n }\n return most;\n}\n\n/**\n * Ticks at round values across `range`, drawn `pixels` long: the finest\n * 1/2/5 step that keeps neighbors `minSpacing` px apart, so a taller plot\n * gets more of them.\n */\nexport function niceTicks(\n range: readonly [number, number],\n pixels: number,\n options: NiceTickOptions,\n): TickSet {\n const none: TickSet = { values: [], step: 0, decimals: 0 };\n const lo = Math.min(range[0], range[1]);\n const hi = Math.max(range[0], range[1]);\n const span = hi - lo;\n const { minSpacing, inset = 0 } = options;\n if (!(span > 0) || !Number.isFinite(span) || !(pixels > 0) || !(minSpacing > 0)) return none;\n\n const unitsPerPx = span / pixels;\n const step = niceStep(minSpacing * unitsPerPx);\n const decimals = stepDecimals(step);\n const from = lo + inset * unitsPerPx;\n const to = hi - inset * unitsPerPx;\n // A tolerance in step units, so a tick sitting exactly on a bound survives\n // the float error in `from / step`.\n const first = Math.ceil(from / step - 1e-9);\n const last = Math.floor(to / step + 1e-9);\n const values: number[] = [];\n for (let i = first; i <= last; i++) values.push(Number((i * step).toFixed(decimals)) + 0);\n return { values, step, decimals };\n}\n\n/** The default label: `value` fixed to the column's shared decimals, with\n * no negative zero. */\nexport function formatTick(value: number, ctx: TickFormatCtx): string {\n const text = value.toFixed(ctx.decimals);\n return /^-0(\\.0*)?$/.test(text) ? text.slice(1) : text;\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 --plot-tick: var(--wzl-line-subtle);\n --plot-tick-label: var(--wzl-fg-muted);\n /* Knocks the tick line out from behind an inside label. */\n --plot-tick-label-halo: var(--plot-bg);\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\n.tick {\n stroke: var(--plot-tick);\n stroke-width: 1;\n fill: none;\n}\n\n.tickLabels { pointer-events: none; }\n\n.tickLabel {\n fill: var(--plot-tick-label);\n font-size: var(--wzl-font-size-xs);\n font-variant-numeric: tabular-nums;\n}\n\n.tickLabel[data-placement='inside'] {\n stroke: var(--plot-tick-label-halo);\n stroke-width: 3px;\n stroke-linejoin: round;\n paint-order: stroke;\n}\n","import {\n forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState,\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 {\n formatTick, niceTicks, tickDecimals,\n type TickFormatCtx, type TickFormatter,\n} from './ticks';\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/**\n * Ticks along one axis of a {@link Plot2D}: a line across the plot at each\n * tick value, and a label naming it. Every label in a column is formatted\n * to the same number of decimal places.\n */\nexport interface TickSettings {\n /** Tick values in model space; any outside the range are skipped.\n * Omitted = round 1/2/5 steps, as many as `minSpacing` allows at the\n * plot's current size. */\n values?: readonly number[];\n /** Smallest gap between generated ticks, in px. Default 24 on y, 64 on x. */\n minSpacing?: number;\n /** A generated tick nearer either end of the axis than this is dropped,\n * so its label stays on the plot, in px. Default 4 on y, 16 on x. */\n inset?: number;\n /** Draw a line across the plot at each tick. Default true. */\n lines?: boolean;\n /** Where labels sit: `'inside'` the plot along its left (y) or bottom (x)\n * edge, `'outside'` it past that edge in space the caller leaves free,\n * or `false` for none. Default `'inside'`. */\n labels?: 'inside' | 'outside' | false;\n /** Space between a label and the plot edge it sits against, in px.\n * Default 4. */\n gap?: number;\n /** Label text for a tick. Default {@link formatTick}. */\n format?: TickFormatter;\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 /** Ticks at x values. `false` / `null` / omitted = none; `{}` = defaults. */\n xTicks?: TickSettings | false | null;\n /** Ticks at y values. `false` / `null` / omitted = none; `{}` = defaults. */\n yTicks?: TickSettings | false | null;\n /** Forwarded to the underlying svg. Consumer opts into focus this way. */\n tabIndex?: number;\n /** Default `'img'`. A plot holding focusable marks must not be an image,\n * whose children are presentational to assistive technology. */\n role?: string;\n 'aria-label'?: string;\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\ntype Axis = 'x' | 'y';\n\nconst TICK_SPACING_PX: Record<Axis, number> = { x: 64, y: 24 };\nconst TICK_INSET_PX: Record<Axis, number> = { x: 16, y: 4 };\nconst LABEL_GAP_PX = 4;\n\ninterface ResolvedTick {\n value: number;\n /** Plot-space position along the axis. */\n at: number;\n label: string;\n}\n\nfunction resolveTicks(\n settings: TickSettings,\n axis: Axis,\n range: readonly [number, number],\n pixels: number,\n toPlot: (v: number) => number,\n): ResolvedTick[] {\n let values: number[];\n let ctx: TickFormatCtx;\n if (settings.values) {\n const lo = Math.min(range[0], range[1]);\n const hi = Math.max(range[0], range[1]);\n const eps = (hi - lo) * 1e-9;\n values = settings.values.filter((v) => v >= lo - eps && v <= hi + eps);\n const gaps = values.slice(1).map((v, i) => v - values[i]);\n const even = gaps.length > 0 && gaps.every((g) => Math.abs(g - gaps[0]) <= Math.abs(gaps[0]) * 1e-9);\n ctx = { decimals: tickDecimals(values), step: even ? gaps[0] : 0 };\n } else {\n const set = niceTicks(range, pixels, {\n minSpacing: settings.minSpacing ?? TICK_SPACING_PX[axis],\n inset: settings.inset ?? TICK_INSET_PX[axis],\n });\n values = set.values;\n ctx = { decimals: set.decimals, step: set.step };\n }\n const format = settings.format ?? formatTick;\n return values.map((value) => ({ value, at: toPlot(value), label: format(value, ctx) }));\n}\n\n/**\n * An SVG plotting surface with an optional grid, axes and ticks. It draws the\n * frame 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 xTicks,\n yTicks,\n tabIndex,\n role = 'img',\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 xTickList = xTicks\n ? resolveTicks(xTicks, 'x', xRange, width, (v) => modelToPlot({ x: v, y: yRange[0] }, modelRange, plotSize).x)\n : [];\n const yTickList = yTicks\n ? resolveTicks(yTicks, 'y', yRange, height, (v) => modelToPlot({ x: xRange[0], y: v }, modelRange, plotSize).y)\n : [];\n\n // An inside y column is right-aligned against its widest label, which only\n // the rendered text can say.\n const yInside = !!yTicks && (yTicks.labels ?? 'inside') === 'inside';\n const yLabelsRef = useRef<SVGGElement | null>(null);\n const [yLabelWidth, setYLabelWidth] = useState(0);\n const yLabelKey = yInside ? yTickList.map((t) => t.label).join('\\n') : '';\n useLayoutEffect(() => {\n if (!yInside) return;\n const measure = (): void => {\n let widest = 0;\n for (const el of yLabelsRef.current?.querySelectorAll('text') ?? []) {\n if (typeof el.getComputedTextLength === 'function') widest = Math.max(widest, el.getComputedTextLength());\n }\n setYLabelWidth((prev) => (prev === widest ? prev : widest));\n };\n measure();\n let live = true;\n // A web font landing after the first measure changes every width.\n document.fonts?.ready.then(() => { if (live) measure(); });\n return () => { live = false; };\n }, [yInside, yLabelKey]);\n\n const cls = [s.root, className].filter(Boolean).join(' ');\n\n const renderTickLines = (axis: Axis, list: ResolvedTick[], settings: TickSettings | false | null | undefined) => {\n if (!settings || settings.lines === false || list.length === 0) return null;\n return (\n <g>\n {list.map((t) => (\n <line\n key={`t${axis}-${t.value}`}\n data-plot-element=\"tick\"\n data-axis={axis}\n className={s.tick}\n {...(axis === 'x'\n ? { x1: t.at, x2: t.at, y1: 0, y2: height }\n : { x1: 0, x2: width, y1: t.at, y2: t.at })}\n />\n ))}\n </g>\n );\n };\n\n const renderTickLabels = (axis: Axis, list: ResolvedTick[], settings: TickSettings | false | null | undefined) => {\n if (!settings || list.length === 0) return null;\n const placement = settings.labels ?? 'inside';\n if (placement === false) return null;\n const outside = placement === 'outside';\n const gap = settings.gap ?? LABEL_GAP_PX;\n let place: { x?: number; y?: number; textAnchor: 'start' | 'middle' | 'end'; dominantBaseline?: 'central' | 'hanging' };\n if (axis === 'y') {\n place = outside\n ? { x: -gap, textAnchor: 'end', dominantBaseline: 'central' }\n : yLabelWidth > 0\n ? { x: gap + yLabelWidth, textAnchor: 'end', dominantBaseline: 'central' }\n : { x: gap, textAnchor: 'start', dominantBaseline: 'central' };\n } else {\n place = outside\n ? { y: height + gap, textAnchor: 'middle', dominantBaseline: 'hanging' }\n : { y: height - gap, textAnchor: 'middle' };\n }\n return (\n <g ref={axis === 'y' ? yLabelsRef : undefined} className={s.tickLabels} aria-hidden=\"true\">\n {list.map((t) => (\n <text\n key={`l${axis}-${t.value}`}\n data-plot-element=\"tick-label\"\n data-axis={axis}\n data-placement={placement}\n className={s.tickLabel}\n x={axis === 'x' ? t.at : place.x}\n y={axis === 'y' ? t.at : place.y}\n textAnchor={place.textAnchor}\n dominantBaseline={place.dominantBaseline}\n >\n {t.label}\n </text>\n ))}\n </g>\n );\n };\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={role}\n aria-label={props['aria-label']}\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 {renderTickLines('x', xTickList, xTicks)}\n {renderTickLines('y', yTickList, yTicks)}\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 {renderTickLabels('x', xTickList, xTicks)}\n {renderTickLabels('y', yTickList, yTicks)}\n {children}\n </svg>\n );\n});\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./CurveEditor-
|
|
1
|
+
import { n as e } from "./CurveEditor-DXwSP-iA.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-
|
|
16
|
+
//# sourceMappingURL=PointPlotter-S_gz7VYt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointPlotter-
|
|
1
|
+
{"version":3,"file":"PointPlotter-S_gz7VYt.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, TickSettings } 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 xTicks?: TickSettings | false | null;\n yTicks?: TickSettings | 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":";;;AA2DA,SAAgB,EAAa,GAA0B;AAQrD,QAAO,kBAAC,GAAD;EANL,GAAG;EACH,cAAc,EAAM,gBAAgB;EACpC,OAAO;EACP,MAAM;EACN,WAAW;EAEyB,CAAA"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { t as e } from "./Badge-
|
|
1
|
+
import { t as e } from "./Badge-CW9pBPFl.js";
|
|
2
2
|
import { jsx as t } from "react/jsx-runtime";
|
|
3
3
|
var n = {
|
|
4
|
-
row: "
|
|
5
|
-
matrix: "
|
|
6
|
-
segment: "
|
|
4
|
+
row: "_row_1a09e_1",
|
|
5
|
+
matrix: "_matrix_1a09e_7",
|
|
6
|
+
segment: "_segment_1a09e_15"
|
|
7
7
|
};
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/components/Powerline/Powerline.tsx
|
|
@@ -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-
|
|
36
|
+
//# sourceMappingURL=Powerline-Ak5AWUlK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Powerline-Ak5AWUlK.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: var(--wzl-space-6);\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,308 @@
|
|
|
1
|
+
import { n as e, t } from "./Tooltip-C4YBczLq.js";
|
|
2
|
+
import { a as n, i as r, n as i, r as a, t as o } from "./schema-Dft4Cu2p.js";
|
|
3
|
+
import { t as s } from "./ColorField-BYzgZM9o.js";
|
|
4
|
+
import { t as c } from "./Select-BEope086.js";
|
|
5
|
+
import { t as l } from "./FontFamilySelect-DxfgTC3G.js";
|
|
6
|
+
import { t as u } from "./Input-DbMKpkXy.js";
|
|
7
|
+
import { n as d, t as f } from "./NumberField-CCjEDZCg.js";
|
|
8
|
+
import { t as p } from "./Switch-DH5POG0T.js";
|
|
9
|
+
import { t as m } from "./PaintField-jBOJ32rL.js";
|
|
10
|
+
import { t as h } from "./Checkbox-BOsDAY2F.js";
|
|
11
|
+
import { n as g, t as _ } from "./RadioGroup-CsVp3SEu.js";
|
|
12
|
+
import { t as v } from "./RangeSlider-DNr-pJpZ.js";
|
|
13
|
+
import { t as y } from "./Dialog-fGqqQ6o_.js";
|
|
14
|
+
import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
15
|
+
import { isBuiltinToolPref as C } from "@weasel-js/core";
|
|
16
|
+
import { useMemo as w } from "react";
|
|
17
|
+
import { Focusable as T } from "react-aria-components";
|
|
18
|
+
//#region src/components/paintValue.ts
|
|
19
|
+
function E(e) {
|
|
20
|
+
if (typeof e != "object" || !e) return !1;
|
|
21
|
+
let t = e;
|
|
22
|
+
return typeof t.fill == "string" || typeof t.color == "string";
|
|
23
|
+
}
|
|
24
|
+
function D(e) {
|
|
25
|
+
if (typeof e != "object" || !e) return;
|
|
26
|
+
let t = e;
|
|
27
|
+
if (!(t.fill !== void 0 && t.fill !== "solid")) return typeof t.color == "string" ? t.color : void 0;
|
|
28
|
+
}
|
|
29
|
+
function O(e) {
|
|
30
|
+
if (!(typeof e != "object" || !e || !("paint" in e))) return D(e.paint);
|
|
31
|
+
}
|
|
32
|
+
var k = {
|
|
33
|
+
columns: "_columns_xgnrh_5",
|
|
34
|
+
column: "_column_xgnrh_5",
|
|
35
|
+
panel: "_panel_xgnrh_23",
|
|
36
|
+
subpanel: "_subpanel_xgnrh_33",
|
|
37
|
+
groupHeader: "_groupHeader_xgnrh_44",
|
|
38
|
+
groupTitle: "_groupTitle_xgnrh_57",
|
|
39
|
+
groupDesc: "_groupDesc_xgnrh_66",
|
|
40
|
+
rows: "_rows_xgnrh_73",
|
|
41
|
+
row: "_row_xgnrh_73",
|
|
42
|
+
rowLabel: "_rowLabel_xgnrh_89",
|
|
43
|
+
help: "_help_xgnrh_104",
|
|
44
|
+
rowControl: "_rowControl_xgnrh_128",
|
|
45
|
+
textarea: "_textarea_xgnrh_135",
|
|
46
|
+
unitSuffix: "_unitSuffix_xgnrh_148",
|
|
47
|
+
unrenderable: "_unrenderable_xgnrh_154",
|
|
48
|
+
titleRow: "_titleRow_xgnrh_161",
|
|
49
|
+
objectLeaf: "_objectLeaf_xgnrh_175",
|
|
50
|
+
objectRow: "_objectRow_xgnrh_182",
|
|
51
|
+
objectLabel: "_objectLabel_xgnrh_189",
|
|
52
|
+
objectGroup: "_objectGroup_xgnrh_196"
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/components/Prefs/PrefsForm.tsx
|
|
56
|
+
function A(e) {
|
|
57
|
+
let { schema: t, values: r, onChange: i, renderers: a, showHidden: s = !1, className: c } = e, l = w(() => n(t, s), [t, s]), u = {
|
|
58
|
+
values: r,
|
|
59
|
+
onChange: i,
|
|
60
|
+
renderers: a
|
|
61
|
+
};
|
|
62
|
+
return /* @__PURE__ */ x("div", {
|
|
63
|
+
className: [k.columns, c].filter(Boolean).join(" "),
|
|
64
|
+
children: Object.entries(l?.children ?? {}).map(([e, t]) => /* @__PURE__ */ x("div", {
|
|
65
|
+
className: k.column,
|
|
66
|
+
children: o(t) ? /* @__PURE__ */ x(M, {
|
|
67
|
+
ctx: u,
|
|
68
|
+
path: e,
|
|
69
|
+
pref: t
|
|
70
|
+
}) : /* @__PURE__ */ x(j, {
|
|
71
|
+
ctx: u,
|
|
72
|
+
group: t,
|
|
73
|
+
path: e,
|
|
74
|
+
depth: 0
|
|
75
|
+
})
|
|
76
|
+
}, e))
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function j({ ctx: e, group: t, path: n, depth: r }) {
|
|
80
|
+
return /* @__PURE__ */ S("div", {
|
|
81
|
+
className: r === 0 ? k.panel : k.subpanel,
|
|
82
|
+
children: [/* @__PURE__ */ S("div", {
|
|
83
|
+
className: k.groupHeader,
|
|
84
|
+
children: [/* @__PURE__ */ x("h3", {
|
|
85
|
+
className: k.groupTitle,
|
|
86
|
+
children: t.name
|
|
87
|
+
}), t.description !== void 0 && /* @__PURE__ */ x("p", {
|
|
88
|
+
className: k.groupDesc,
|
|
89
|
+
children: t.description
|
|
90
|
+
})]
|
|
91
|
+
}), /* @__PURE__ */ x("div", {
|
|
92
|
+
className: k.rows,
|
|
93
|
+
children: Object.entries(t.children).map(([t, i]) => {
|
|
94
|
+
let a = `${n}.${t}`;
|
|
95
|
+
return o(i) ? /* @__PURE__ */ x(M, {
|
|
96
|
+
ctx: e,
|
|
97
|
+
path: a,
|
|
98
|
+
pref: i
|
|
99
|
+
}, t) : /* @__PURE__ */ x(j, {
|
|
100
|
+
ctx: e,
|
|
101
|
+
group: i,
|
|
102
|
+
path: a,
|
|
103
|
+
depth: r + 1
|
|
104
|
+
}, t);
|
|
105
|
+
})
|
|
106
|
+
})]
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function M({ ctx: n, path: i, pref: a }) {
|
|
110
|
+
let o = r(n.values, i), s = {
|
|
111
|
+
path: i,
|
|
112
|
+
pref: a,
|
|
113
|
+
value: o === void 0 ? a.default : o,
|
|
114
|
+
setValue: (e) => n.onChange(i, e),
|
|
115
|
+
auto: !1,
|
|
116
|
+
setAuto: () => {}
|
|
117
|
+
}, c = n.renderers?.[a.kind], l = c ? c(s) : N(s);
|
|
118
|
+
return c && l === null ? null : a.block ? /* @__PURE__ */ x(b, { children: l }) : /* @__PURE__ */ S("label", {
|
|
119
|
+
className: k.row,
|
|
120
|
+
children: [/* @__PURE__ */ S("span", {
|
|
121
|
+
className: k.rowLabel,
|
|
122
|
+
children: [a.name, a.description ? /* @__PURE__ */ S(e, { children: [/* @__PURE__ */ x(T, { children: /* @__PURE__ */ x("button", {
|
|
123
|
+
type: "button",
|
|
124
|
+
className: k.help,
|
|
125
|
+
"aria-label": `About ${a.name}`,
|
|
126
|
+
children: "ⓘ"
|
|
127
|
+
}) }), /* @__PURE__ */ x(t, { children: a.description })] }) : null]
|
|
128
|
+
}), /* @__PURE__ */ x("span", {
|
|
129
|
+
className: k.rowControl,
|
|
130
|
+
children: l
|
|
131
|
+
})]
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function N(e, t) {
|
|
135
|
+
let { pref: n, value: r, setValue: y } = e;
|
|
136
|
+
if (n.kind === "font-family") {
|
|
137
|
+
let e = t?.fontWeight, i = t?.fontStyle;
|
|
138
|
+
return /* @__PURE__ */ x(l, {
|
|
139
|
+
value: typeof r == "string" ? r : void 0,
|
|
140
|
+
onChange: y,
|
|
141
|
+
weight: typeof e == "number" ? e : void 0,
|
|
142
|
+
fontStyle: i === "italic" ? "italic" : void 0,
|
|
143
|
+
"aria-label": n.name
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (!C(n)) return /* @__PURE__ */ S("span", {
|
|
147
|
+
className: k.unrenderable,
|
|
148
|
+
children: [
|
|
149
|
+
"(",
|
|
150
|
+
n.kind,
|
|
151
|
+
": no renderer)"
|
|
152
|
+
]
|
|
153
|
+
});
|
|
154
|
+
switch (n.kind) {
|
|
155
|
+
case "boolean": {
|
|
156
|
+
let e = !!r;
|
|
157
|
+
return n.control === "switch" ? /* @__PURE__ */ x(p, {
|
|
158
|
+
isSelected: e,
|
|
159
|
+
onChange: y,
|
|
160
|
+
"aria-label": n.name
|
|
161
|
+
}) : /* @__PURE__ */ x(h, {
|
|
162
|
+
isSelected: e,
|
|
163
|
+
onChange: y,
|
|
164
|
+
"aria-label": n.name
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
case "number": {
|
|
168
|
+
let e = typeof r == "number" && Number.isFinite(r) ? r : 0, t = n.unit, o = t ? t.toDisplay(e) : e, s = i(n), c = (e) => y(t ? t.fromDisplay(e) : e);
|
|
169
|
+
if (n.control === "slider") return /* @__PURE__ */ x(v, {
|
|
170
|
+
value: o,
|
|
171
|
+
onChange: (e) => c(typeof e == "number" ? e : e[0]),
|
|
172
|
+
minValue: s.min,
|
|
173
|
+
maxValue: s.max,
|
|
174
|
+
step: s.step,
|
|
175
|
+
"aria-label": n.name
|
|
176
|
+
});
|
|
177
|
+
let l = t ? /* @__PURE__ */ x(f, {
|
|
178
|
+
value: o,
|
|
179
|
+
onChange: c,
|
|
180
|
+
minValue: s.min,
|
|
181
|
+
maxValue: s.max,
|
|
182
|
+
step: s.step,
|
|
183
|
+
accepts: a(t),
|
|
184
|
+
"aria-label": n.name
|
|
185
|
+
}) : /* @__PURE__ */ x(d, {
|
|
186
|
+
value: o,
|
|
187
|
+
onChange: c,
|
|
188
|
+
minValue: s.min,
|
|
189
|
+
maxValue: s.max,
|
|
190
|
+
step: s.step,
|
|
191
|
+
"aria-label": n.name
|
|
192
|
+
});
|
|
193
|
+
return t?.suffix === void 0 ? l : /* @__PURE__ */ S(b, { children: [l, /* @__PURE__ */ x("span", {
|
|
194
|
+
className: k.unitSuffix,
|
|
195
|
+
"aria-hidden": "true",
|
|
196
|
+
children: t.suffix
|
|
197
|
+
})] });
|
|
198
|
+
}
|
|
199
|
+
case "string": {
|
|
200
|
+
let e = typeof r == "string" ? r : "";
|
|
201
|
+
return n.control === "textarea" ? /* @__PURE__ */ x("textarea", {
|
|
202
|
+
className: k.textarea,
|
|
203
|
+
value: e,
|
|
204
|
+
onChange: (e) => y(e.target.value),
|
|
205
|
+
"aria-label": n.name,
|
|
206
|
+
rows: 3
|
|
207
|
+
}) : /* @__PURE__ */ x(u, {
|
|
208
|
+
value: e,
|
|
209
|
+
onChange: y,
|
|
210
|
+
"aria-label": n.name
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
case "enum": {
|
|
214
|
+
let e = n.encoding, i = e ? e.read(r, t) : typeof r == "string" ? r : n.default, a = (n) => y(e ? e.write(n, t) : n);
|
|
215
|
+
return n.control === "radio" ? /* @__PURE__ */ x(g, {
|
|
216
|
+
value: i ?? null,
|
|
217
|
+
onChange: a,
|
|
218
|
+
"aria-label": n.name,
|
|
219
|
+
children: n.options.map((e) => /* @__PURE__ */ x(_, {
|
|
220
|
+
value: e.value,
|
|
221
|
+
isDisabled: e.disabled,
|
|
222
|
+
children: e.label
|
|
223
|
+
}, e.value))
|
|
224
|
+
}) : /* @__PURE__ */ x(c, {
|
|
225
|
+
options: n.options.map((e) => ({
|
|
226
|
+
value: e.value,
|
|
227
|
+
label: e.label,
|
|
228
|
+
isDisabled: e.disabled
|
|
229
|
+
})),
|
|
230
|
+
selectedKey: i ?? null,
|
|
231
|
+
onSelectionChange: a,
|
|
232
|
+
"aria-label": n.name
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
case "color": return /* @__PURE__ */ x(s, {
|
|
236
|
+
value: typeof r == "string" ? r : n.default,
|
|
237
|
+
alpha: n.alpha,
|
|
238
|
+
onChange: y,
|
|
239
|
+
"aria-label": n.name
|
|
240
|
+
});
|
|
241
|
+
case "paint": return /* @__PURE__ */ x(m, {
|
|
242
|
+
value: E(r) ? r : E(n.default) ? n.default : null,
|
|
243
|
+
onChange: y,
|
|
244
|
+
"aria-label": n.name
|
|
245
|
+
});
|
|
246
|
+
case "object": {
|
|
247
|
+
let t = n, i = typeof r == "object" && r ? r : void 0, a = (n) => {
|
|
248
|
+
let s = [];
|
|
249
|
+
for (let [c, l] of Object.entries(n)) {
|
|
250
|
+
if (!o(l)) {
|
|
251
|
+
let e = a(l.children);
|
|
252
|
+
if (e.length === 0) continue;
|
|
253
|
+
s.push(/* @__PURE__ */ x("h4", {
|
|
254
|
+
className: k.objectGroup,
|
|
255
|
+
children: l.name
|
|
256
|
+
}, `group:${c}`), ...e);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
s.push(/* @__PURE__ */ S("label", {
|
|
260
|
+
className: k.objectRow,
|
|
261
|
+
children: [/* @__PURE__ */ x("span", {
|
|
262
|
+
className: k.objectLabel,
|
|
263
|
+
children: l.name
|
|
264
|
+
}), N({
|
|
265
|
+
path: `${e.path}.${c}`,
|
|
266
|
+
pref: l,
|
|
267
|
+
value: i?.[c],
|
|
268
|
+
setValue: (e) => {
|
|
269
|
+
y({
|
|
270
|
+
...i ?? t.fromScalar?.(r) ?? {},
|
|
271
|
+
[c]: e
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
auto: e.auto,
|
|
275
|
+
setAuto: e.setAuto
|
|
276
|
+
}, i)]
|
|
277
|
+
}, c));
|
|
278
|
+
}
|
|
279
|
+
return s;
|
|
280
|
+
};
|
|
281
|
+
return /* @__PURE__ */ x("div", {
|
|
282
|
+
className: k.objectLeaf,
|
|
283
|
+
children: a(t.children)
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
default: throw Error(`PrefsForm: no control for built-in pref kind "${n.kind}"`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/components/Prefs/PrefsDialog.tsx
|
|
291
|
+
function P(e) {
|
|
292
|
+
let { isOpen: t, onOpenChange: n, title: r, headerExtra: i, dialogClassName: a, ...o } = e;
|
|
293
|
+
return /* @__PURE__ */ x(y, {
|
|
294
|
+
isOpen: t,
|
|
295
|
+
onOpenChange: n,
|
|
296
|
+
"aria-label": typeof r == "string" ? r : o.schema.name,
|
|
297
|
+
className: a,
|
|
298
|
+
title: i === void 0 ? r ?? o.schema.name : /* @__PURE__ */ S("span", {
|
|
299
|
+
className: k.titleRow,
|
|
300
|
+
children: [/* @__PURE__ */ x("span", { children: r ?? o.schema.name }), i]
|
|
301
|
+
}),
|
|
302
|
+
children: /* @__PURE__ */ x(A, { ...o })
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
306
|
+
export { O as i, A as n, D as r, P as t };
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=Prefs-CNC8tzyN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Prefs-CNC8tzyN.js","names":[],"sources":["../../src/components/paintValue.ts","../../src/components/Prefs/Prefs.module.css","../../src/components/Prefs/PrefsForm.tsx","../../src/components/Prefs/PrefsDialog.tsx"],"sourcesContent":["// Reading and writing the paint objects a property control may be pointed at.\n//\n// `data.fill` is a `FillStyle` and `data.stroke` a `Stroke`, so a control that\n// assumes either is a hex string reads `undefined` off it and writes a bare\n// string back over it. These helpers are what keep a control honest about the\n// shape it is holding.\n\n/** Whether a value is a `FillStyle` at all: an object naming a kind, or one\n * carrying a color, which is the solid member with its optional tag left off.\n * A pref's stored value is `unknown`, so this is what stands between a paint\n * control and a string someone saved there. */\nexport function isPaint(value: unknown): value is { fill?: string; color?: string } {\n if (typeof value !== 'object' || value === null) return false;\n const paint = value as { fill?: unknown; color?: unknown };\n return typeof paint.fill === 'string' || typeof paint.color === 'string';\n}\n\n/** The color of a solid paint, or `undefined` for anything else — including a\n * value that isn't a paint at all. `fill` is optional on the solid member of\n * the union, so the tag alone can't decide it. */\nexport function 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\n/** The single color a stroke shows, or `undefined` when it has none to show —\n * a gradient or pattern stroke, or no stroke at all. */\nexport function strokeColorOf(value: unknown): string | undefined {\n if (typeof value !== 'object' || value === null || !('paint' in value)) return undefined;\n return solidColorOf((value as { paint: unknown }).paint);\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: var(--wzl-space-6);\n overflow-y: auto;\n padding-right: var(--wzl-space-2);\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: var(--wzl-space-4);\n}\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-4);\n padding: var(--wzl-space-5);\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: var(--wzl-space-3);\n margin-top: var(--wzl-space-3);\n padding: var(--wzl-space-4) var(--wzl-space-4) var(--wzl-space-4) var(--wzl-space-5);\n background: var(--wzl-surface-sunken);\n border-left: 2px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n.groupHeader {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-1);\n padding-bottom: var(--wzl-space-2);\n border-bottom: 1px solid var(--wzl-border);\n}\n\n.subpanel .groupHeader {\n border-bottom: none;\n padding-bottom: var(--wzl-space-1);\n}\n\n.groupTitle {\n margin: 0;\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-font-weight-bold);\n color: var(--wzl-fg);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wider));\n text-transform: var(--wzl-params-label-case, uppercase);\n}\n\n.groupDesc {\n margin: 0;\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-subtle);\n line-height: 1.35;\n}\n\n.rows {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n}\n\n.row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--wzl-space-4);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg);\n cursor: default;\n}\n\n.rowLabel {\n /* Not grown: the row's space-between already pushes the control to the end,\n and a growing label would swallow any width the panel gives its track. */\n flex: 0 1 auto;\n inline-size: var(--wzl-params-label-width, auto);\n min-width: 0;\n display: inline-flex;\n align-items: center;\n justify-content: var(--wzl-params-label-align, start);\n gap: var(--wzl-space-2);\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\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: var(--wzl-font-size-sm);\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: var(--wzl-space-2) var(--wzl-space-4);\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: var(--wzl-font-size-sm);\n resize: vertical;\n}\n\n/* Names the unit a number leaf displays in, beside the field showing it. */\n.unitSuffix {\n flex: none;\n font-size: var(--wzl-font-size-sm);\n opacity: 0.6;\n}\n\n.unrenderable {\n font-family: var(--wzl-font-mono);\n font-size: var(--wzl-font-size-sm);\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: var(--wzl-space-6);\n flex: 1;\n min-width: 0;\n}\n\n.titleRow > span:first-child {\n flex: 1;\n min-width: 0;\n}\n\n/* An object leaf renders its fields as its own rows. */\n.objectLeaf {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-3);\n inline-size: 100%;\n}\n\n.objectRow {\n display: grid;\n grid-template-columns: 96px 1fr;\n gap: var(--wzl-space-4);\n align-items: center;\n}\n\n.objectLabel {\n font-size: var(--wzl-font-size-sm);\n opacity: 0.75;\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n}\n\n.objectGroup {\n margin: var(--wzl-space-2) 0 0;\n font-size: var(--wzl-font-size-xs);\n font-weight: var(--wzl-font-weight-bold);\n text-transform: var(--wzl-params-label-case, uppercase);\n letter-spacing: var(--wzl-params-label-tracking, var(--wzl-tracking-wide));\n opacity: 0.55;\n}\n","import { useMemo, type ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Checkbox } from '../Checkbox';\nimport { ColorField } from '../ColorField';\nimport { FontFamilySelect } from '../FontFamilySelect';\nimport { isPaint } from '../paintValue';\nimport { PaintField } from '../PaintField';\nimport { Input } from '../Input';\nimport { NumberField, UnitField } 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 { isBuiltinToolPref, type FillStyle } from '@weasel-js/core';\nimport {\n isPrefLeaf,\n prefDisplayBounds,\n prefUnitAccepts,\n prefValueAtPath,\n visiblePrefSubtree,\n type PrefGroup,\n type PrefLeaf,\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 /** Whether this leaf is currently auto — not pinned, computed by the owner. */\n auto: boolean;\n /** Toggle this leaf's auto state. */\n setAuto: (next: boolean) => 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 // A prefs form pins every leaf: it has no computed state to hand back.\n auto: false,\n setAuto: () => {},\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(\n ctx: PrefRenderContext,\n // The object a nested leaf is a field of — what an enum `encoding` reads\n // and writes against. Undefined for a top-level leaf, which has none.\n siblings?: Record<string, unknown>,\n): ReactNode {\n const { pref, value, setValue } = ctx;\n if (pref.kind === 'font-family') {\n // Not a `ToolPref` kind: its options are the live font registry, which no\n // static schema can carry. Core's own text schema still declares it, so\n // the form ships the control rather than leaving every consumer to.\n //\n // The substitution probe runs at the weight and slant the family is stored\n // beside — fields of the same `TextStyle` object leaf — so the label names\n // the variant that will actually paint.\n const weight = siblings?.fontWeight;\n const slant = siblings?.fontStyle;\n return (\n <FontFamilySelect\n value={typeof value === 'string' ? value : undefined}\n onChange={setValue}\n weight={typeof weight === 'number' ? weight : undefined}\n fontStyle={slant === 'italic' ? 'italic' : undefined}\n aria-label={pref.name}\n />\n );\n }\n if (!isBuiltinToolPref(pref)) {\n // App-defined kind with no `renderers` 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 switch (pref.kind) {\n case 'boolean': {\n const checked = Boolean(value);\n return pref.control === 'switch' ? (\n <Switch isSelected={checked} onChange={setValue} aria-label={pref.name} />\n ) : (\n <Checkbox isSelected={checked} onChange={setValue} aria-label={pref.name} />\n );\n }\n case 'number': {\n const stored = typeof value === 'number' && Number.isFinite(value) ? value : 0;\n const unit = pref.unit;\n const display = unit ? unit.toDisplay(stored) : stored;\n // `min`/`max`/`step` are declared in the stored unit, like the value, so\n // they convert with it — a leaf storing radians and showing degrees was\n // clamping typed degrees against 0..6.28.\n const bounds = prefDisplayBounds(pref);\n const store = (v: number): void => setValue(unit ? unit.fromDisplay(v) : v);\n if (pref.control === 'slider') {\n return (\n <RangeSlider\n value={display}\n onChange={(v) => store(typeof v === 'number' ? v : v[0])}\n minValue={bounds.min}\n maxValue={bounds.max}\n step={bounds.step}\n aria-label={pref.name}\n />\n );\n }\n const field = unit ? (\n <UnitField\n value={display}\n onChange={store}\n minValue={bounds.min}\n maxValue={bounds.max}\n step={bounds.step}\n accepts={prefUnitAccepts(unit)}\n aria-label={pref.name}\n />\n ) : (\n <NumberField\n value={display}\n onChange={store}\n minValue={bounds.min}\n maxValue={bounds.max}\n step={bounds.step}\n aria-label={pref.name}\n />\n );\n if (unit?.suffix === undefined) return field;\n return (\n <>\n {field}\n <span className={s.unitSuffix} aria-hidden=\"true\">{unit.suffix}</span>\n </>\n );\n }\n case 'string': {\n const text = typeof value === 'string' ? value : '';\n if (pref.control === 'textarea') {\n return (\n <textarea\n className={s.textarea}\n value={text}\n onChange={(e) => setValue(e.target.value)}\n aria-label={pref.name}\n rows={3}\n />\n );\n }\n return <Input value={text} onChange={setValue} aria-label={pref.name} />;\n }\n case 'enum': {\n const encoding = pref.encoding;\n // An encoded leaf stores something other than the option string (a dash\n // array), so reading the raw value selects nothing and writing one\n // replaces the stored form with the option string.\n const option = encoding\n ? encoding.read(value, siblings)\n : typeof value === 'string'\n ? value\n : pref.default;\n const choose = (next: string): void =>\n setValue(encoding ? encoding.write(next, siblings) : next);\n if (pref.control === 'radio') {\n return (\n <RadioGroup value={option ?? null} onChange={choose} aria-label={pref.name}>\n {pref.options.map((o) => (\n <Radio key={o.value} value={o.value} isDisabled={o.disabled}>\n {o.label}\n </Radio>\n ))}\n </RadioGroup>\n );\n }\n return (\n <Select<string>\n options={pref.options.map((o) => ({\n value: o.value,\n label: o.label,\n isDisabled: o.disabled,\n }))}\n selectedKey={option ?? null}\n onSelectionChange={choose}\n aria-label={pref.name}\n />\n );\n }\n case 'color': {\n const hex = typeof value === 'string' ? value : pref.default;\n return (\n <ColorField\n value={hex}\n alpha={pref.alpha}\n onChange={setValue}\n aria-label={pref.name}\n />\n );\n }\n case 'paint': {\n // A whole `FillStyle`, edited as one: `PaintField` puts the kind bar and\n // the stop editor in a popover, so the control column holds a swatch and\n // a gradient survives being touched.\n const held = isPaint(value) ? value : isPaint(pref.default) ? pref.default : null;\n return (\n <PaintField\n value={held as FillStyle | null}\n onChange={setValue}\n aria-label={pref.name}\n />\n );\n }\n case 'object': {\n // One value with its fields hanging off it: each child renders its own\n // control and commits the parent object whole.\n const p = pref;\n const held = typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)\n : undefined;\n const objectRows = (children: Record<string, PrefLeaf | PrefGroup>): ReactNode[] => {\n const out: ReactNode[] = [];\n for (const [key, child] of Object.entries(children)) {\n if (!isPrefLeaf(child)) {\n const inner = objectRows(child.children);\n if (inner.length === 0) continue;\n out.push(<h4 key={`group:${key}`} className={s.objectGroup}>{child.name}</h4>, ...inner);\n continue;\n }\n out.push(\n <label key={key} className={s.objectRow}>\n <span className={s.objectLabel}>{child.name}</span>\n {renderBuiltin({\n path: `${ctx.path}.${key}`,\n pref: child,\n value: held?.[key],\n setValue: (v) => {\n const base = held ?? p.fromScalar?.(value) ?? {};\n setValue({ ...base, [key]: v });\n },\n // A field is not pinned on its own — it shares the state of\n // the object leaf it hangs off.\n auto: ctx.auto,\n setAuto: ctx.setAuto,\n }, held)}\n </label>,\n );\n }\n return out;\n };\n return <div className={s.objectLeaf}>{objectRows(p.children)}</div>;\n }\n default: {\n // Not reachable while every built-in kind has an arm — and a new kind\n // that lacks one is a compile error here, never a blank row.\n const _exhaustive: never = pref;\n throw new Error(\n `PrefsForm: no control for built-in pref kind \"${(_exhaustive as { kind: string }).kind}\"`,\n );\n }\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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"}
|