@weasel-js/ui 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/Badge-CTc9Lkwn.js +14 -0
- package/dist/chunks/Badge-CTc9Lkwn.js.map +1 -0
- package/dist/chunks/{Badge-CyAIZSDo.js → Badge-D2aD7xVL.js} +277 -228
- package/dist/chunks/Badge-D2aD7xVL.js.map +1 -0
- package/dist/chunks/BandEditor-Dd0egAgE.js +292 -0
- package/dist/chunks/BandEditor-Dd0egAgE.js.map +1 -0
- package/dist/chunks/{ButtonBar-D5Vi0aj_.js → ButtonBar-DIQTe5GQ.js} +2 -2
- package/dist/chunks/{ButtonBar-D5Vi0aj_.js.map → ButtonBar-DIQTe5GQ.js.map} +1 -1
- package/dist/chunks/Callout-ndW5_Bqx.js +116 -0
- package/dist/chunks/Callout-ndW5_Bqx.js.map +1 -0
- package/dist/chunks/CloseButton-C2J7wVfo.js +26 -0
- package/dist/chunks/CloseButton-C2J7wVfo.js.map +1 -0
- package/dist/chunks/ColorField-Yz_BkcCT.js +69 -0
- package/dist/chunks/ColorField-Yz_BkcCT.js.map +1 -0
- package/dist/chunks/{ColorModeControl-ke5PXbBa.js → ColorModeControl-BewxA0rX.js} +3 -3
- package/dist/chunks/{ColorModeControl-ke5PXbBa.js.map → ColorModeControl-BewxA0rX.js.map} +1 -1
- package/dist/chunks/{ComboBox-DpT8lc3p.js → ComboBox-B34H76CW.js} +12 -12
- package/dist/chunks/ComboBox-B34H76CW.js.map +1 -0
- package/dist/chunks/{CurveEditor-BDJXjEvK.js → CurveEditor-DUVjd25R.js} +2 -2
- package/dist/chunks/{CurveEditor-BDJXjEvK.js.map → CurveEditor-DUVjd25R.js.map} +1 -1
- package/dist/chunks/{DataGrid-D-dZj1BD.js → DataGrid-LZ2JgY2Y.js} +17 -17
- package/dist/chunks/DataGrid-LZ2JgY2Y.js.map +1 -0
- package/dist/chunks/DetailList-BKomDzg5.js +52 -0
- package/dist/chunks/DetailList-BKomDzg5.js.map +1 -0
- package/dist/chunks/{DetentSlider-CL8TlX3S.js → DetentSlider-5uQPFucv.js} +2 -2
- package/dist/chunks/{DetentSlider-CL8TlX3S.js.map → DetentSlider-5uQPFucv.js.map} +1 -1
- package/dist/chunks/Dialog-DGFutQ--.js +63 -0
- package/dist/chunks/Dialog-DGFutQ--.js.map +1 -0
- package/dist/chunks/{Disclosure-0G0uh2fa.js → Disclosure-Ch2KxYuB.js} +7 -7
- package/dist/chunks/Disclosure-Ch2KxYuB.js.map +1 -0
- package/dist/chunks/{DragHandleGlyph-Dr7Fgo0I.js → DragGrip-AoIZXfZb.js} +2 -2
- package/dist/chunks/DragGrip-AoIZXfZb.js.map +1 -0
- package/dist/chunks/FallthroughDiagram-BEHiM5IS.js +284 -0
- package/dist/chunks/FallthroughDiagram-BEHiM5IS.js.map +1 -0
- package/dist/chunks/{FontFamilySelect-DXlMKWfK.js → FontFamilySelect-DkRgNtag.js} +2 -2
- package/dist/chunks/{FontFamilySelect-DXlMKWfK.js.map → FontFamilySelect-DkRgNtag.js.map} +1 -1
- package/dist/chunks/GestureRoute-C_YGl7bJ.js +82 -0
- package/dist/chunks/GestureRoute-C_YGl7bJ.js.map +1 -0
- package/dist/chunks/GradientEditor-b7v4Ph3i.js +363 -0
- package/dist/chunks/GradientEditor-b7v4Ph3i.js.map +1 -0
- package/dist/chunks/{Icon-Cgzy8VgC.js → Icon-CcVjdq2C.js} +31 -1
- package/dist/chunks/Icon-CcVjdq2C.js.map +1 -0
- package/dist/chunks/{InlineRange-eOj6JpJl.js → InlineRange-P01ABSzo.js} +3 -3
- package/dist/chunks/InlineRange-P01ABSzo.js.map +1 -0
- package/dist/chunks/{Jog-DESxZ44P.js → Jog-DRmfrkCg.js} +3 -3
- package/dist/chunks/{Jog-DESxZ44P.js.map → Jog-DRmfrkCg.js.map} +1 -1
- package/dist/chunks/{Keycaps-C0H_v2gO.js → Keycaps-C-FJyG8k.js} +14 -14
- package/dist/chunks/Keycaps-C-FJyG8k.js.map +1 -0
- package/dist/chunks/{LayerList-nz-QYvTF.js → LayerList-wCI1EueM.js} +148 -152
- package/dist/chunks/LayerList-wCI1EueM.js.map +1 -0
- package/dist/chunks/ListEditor-BeA60TAA.js +71 -0
- package/dist/chunks/ListEditor-BeA60TAA.js.map +1 -0
- package/dist/chunks/{MenuButton-DtaGenKf.js → MenuButton-BSqEChJE.js} +7 -7
- package/dist/chunks/MenuButton-BSqEChJE.js.map +1 -0
- package/dist/chunks/{MeshEditor-qqGc6hlD.js → MeshEditor-D1HLZcAh.js} +3 -3
- package/dist/chunks/{MeshEditor-qqGc6hlD.js.map → MeshEditor-D1HLZcAh.js.map} +1 -1
- package/dist/chunks/NumberField-BnJxcazc.js +206 -0
- package/dist/chunks/NumberField-BnJxcazc.js.map +1 -0
- package/dist/chunks/{OptionsBar-DbzAgIln.js → OptionsBar-ujxYidhj.js} +2 -2
- package/dist/chunks/{OptionsBar-DbzAgIln.js.map → OptionsBar-ujxYidhj.js.map} +1 -1
- package/dist/chunks/{PaintField-DaJukRc6.js → PaintField-DadOELMg.js} +2 -2
- package/dist/chunks/{PaintField-DaJukRc6.js.map → PaintField-DadOELMg.js.map} +1 -1
- package/dist/chunks/PaintInput-v8Y7MDbH.js +121 -0
- package/dist/chunks/PaintInput-v8Y7MDbH.js.map +1 -0
- package/dist/chunks/{PatternPicker-B-cUt-JT.js → PatternPicker-R_EQtw2Q.js} +2 -2
- package/dist/chunks/{PatternPicker-B-cUt-JT.js.map → PatternPicker-R_EQtw2Q.js.map} +1 -1
- package/dist/chunks/{PointPlotter-Bxo6haKe.js → PointPlotter-ldI4RrU1.js} +2 -2
- package/dist/chunks/{PointPlotter-Bxo6haKe.js.map → PointPlotter-ldI4RrU1.js.map} +1 -1
- package/dist/chunks/{Powerline-ExO5GwEr.js → Powerline-DNyH885r.js} +2 -2
- package/dist/chunks/{Powerline-ExO5GwEr.js.map → Powerline-DNyH885r.js.map} +1 -1
- package/dist/chunks/{Prefs-DpqFKiwY.js → Prefs-ByA-x51i.js} +46 -34
- package/dist/chunks/Prefs-ByA-x51i.js.map +1 -0
- package/dist/chunks/{Properties-D_KzDN9K.js → Properties-DmAeQ3mk.js} +35 -29
- package/dist/chunks/Properties-DmAeQ3mk.js.map +1 -0
- package/dist/chunks/PropertyField-DfIJJ5GS.js +673 -0
- package/dist/chunks/PropertyField-DfIJJ5GS.js.map +1 -0
- package/dist/chunks/{RangeSlider-BKRRTPTZ.js → RangeSlider-SEGE-7VF.js} +8 -8
- package/dist/chunks/RangeSlider-SEGE-7VF.js.map +1 -0
- package/dist/chunks/{ResizeHandle-BKT0XYpx.js → ResizeHandle-rKVWyeTG.js} +3 -3
- package/dist/chunks/ResizeHandle-rKVWyeTG.js.map +1 -0
- package/dist/chunks/Select-ClmKtyWg.js +229 -0
- package/dist/chunks/Select-ClmKtyWg.js.map +1 -0
- package/dist/chunks/SelectionPanel-BaQnX4Bs.js +106 -0
- package/dist/chunks/SelectionPanel-BaQnX4Bs.js.map +1 -0
- package/dist/chunks/SidebarPanel-BblDEz4G.js +53 -0
- package/dist/chunks/SidebarPanel-BblDEz4G.js.map +1 -0
- package/dist/chunks/Slider-YofwGOI4.js +389 -0
- package/dist/chunks/Slider-YofwGOI4.js.map +1 -0
- package/dist/chunks/{StatusBar-DzoPDY4k.js → StatusBar-Ca9Dvhhq.js} +6 -6
- package/dist/chunks/StatusBar-Ca9Dvhhq.js.map +1 -0
- package/dist/chunks/{SwatchGrid-BARC3rnF.js → SwatchGrid-BYvA8Bmh.js} +3 -3
- package/dist/chunks/SwatchGrid-BYvA8Bmh.js.map +1 -0
- package/dist/chunks/ThemeSwitcher-BlsInAmR.js +38 -0
- package/dist/chunks/ThemeSwitcher-BlsInAmR.js.map +1 -0
- package/dist/chunks/{Timeline--58F7MED.js → Timeline-B39cwfMB.js} +207 -203
- package/dist/chunks/Timeline-B39cwfMB.js.map +1 -0
- package/dist/chunks/{Toast-DNBb-24H.js → Toast-BF9GE0HC.js} +25 -27
- package/dist/chunks/Toast-BF9GE0HC.js.map +1 -0
- package/dist/chunks/{ToggleBar-DTjGeS0Q.js → ToggleBar-BTYkBXU9.js} +8 -8
- package/dist/chunks/ToggleBar-BTYkBXU9.js.map +1 -0
- package/dist/chunks/{TokenPanel-CMq7uydV.js → TokenPanel-CMDAOfYH.js} +5 -5
- package/dist/chunks/{TokenPanel-CMq7uydV.js.map → TokenPanel-CMDAOfYH.js.map} +1 -1
- package/dist/chunks/{ToolButton-CR4sQlxF.js → ToolButton-CAHBa08P.js} +6 -6
- package/dist/chunks/ToolButton-CAHBa08P.js.map +1 -0
- package/dist/chunks/{ToolOptionsBar-CtzTlaN2.js → ToolOptionsBar-D_GCrBAN.js} +8 -7
- package/dist/chunks/ToolOptionsBar-D_GCrBAN.js.map +1 -0
- package/dist/chunks/{ToolPalette-CKG9qY6P.js → ToolPalette-OOWN51Xx.js} +3 -3
- package/dist/chunks/ToolPalette-OOWN51Xx.js.map +1 -0
- package/dist/chunks/{Tree-DVOtc9R5.js → Tree-Cc8lIzgM.js} +2 -2
- package/dist/chunks/{Tree-DVOtc9R5.js.map → Tree-Cc8lIzgM.js.map} +1 -1
- package/dist/chunks/{createKeyframeLayer-Czj6Y235.js → createKeyframeLayer-DVl321_l.js} +15 -16
- package/dist/chunks/createKeyframeLayer-DVl321_l.js.map +1 -0
- package/dist/chunks/{icons-Dk8SRS8g.js → icons-BhcR1l64.js} +2 -2
- package/dist/chunks/icons-BhcR1l64.js.map +1 -0
- package/dist/chunks/{model-Du7Lta4C.js → model-BaF65rnX.js} +95 -90
- package/dist/chunks/model-BaF65rnX.js.map +1 -0
- package/dist/chunks/{prefField-Dnl7nmjQ.js → prefField-BopW9bjx.js} +17 -13
- package/dist/chunks/prefField-BopW9bjx.js.map +1 -0
- package/dist/chunks/segmentedControl.module-D6SzYJD7.js +11 -0
- package/dist/chunks/segmentedControl.module-D6SzYJD7.js.map +1 -0
- package/dist/chunks/{useReorderDragList-B_-5L5Gu.js → useReorderDragList-FCMoFIzH.js} +2 -2
- package/dist/chunks/useReorderDragList-FCMoFIzH.js.map +1 -0
- package/dist/components/Badge/bases/Powerline.d.ts.map +1 -1
- package/dist/components/Badge/bases/edgeProfiles.d.ts +31 -4
- package/dist/components/Badge/bases/edgeProfiles.d.ts.map +1 -1
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Badge/index.d.ts.map +1 -1
- package/dist/components/Badge/index.js +3 -2
- package/dist/components/Badge/statusIcons.d.ts +5 -0
- package/dist/components/Badge/statusIcons.d.ts.map +1 -0
- package/dist/components/BandEditor/BandEditor.d.ts +16 -7
- package/dist/components/BandEditor/BandEditor.d.ts.map +1 -1
- package/dist/components/BandEditor/bands.d.ts +5 -2
- package/dist/components/BandEditor/bands.d.ts.map +1 -1
- package/dist/components/BandEditor/index.js +1 -1
- package/dist/components/ButtonBar/index.js +1 -1
- package/dist/components/Callout/Callout.d.ts +2 -2
- package/dist/components/Callout/Callout.d.ts.map +1 -1
- package/dist/components/Callout/index.js +1 -1
- package/dist/components/CloseButton/CloseButton.d.ts +21 -0
- package/dist/components/CloseButton/CloseButton.d.ts.map +1 -0
- package/dist/components/CloseButton/index.d.ts +3 -0
- package/dist/components/CloseButton/index.d.ts.map +1 -0
- package/dist/components/CloseButton/index.js +2 -0
- package/dist/components/ColorField/ColorField.d.ts +5 -1
- package/dist/components/ColorField/ColorField.d.ts.map +1 -1
- package/dist/components/ColorField/index.js +1 -1
- package/dist/components/ColorModeControl/index.js +1 -1
- package/dist/components/ComboBox/index.js +1 -1
- package/dist/components/CurveEditor/index.js +2 -2
- package/dist/components/DataGrid/index.js +1 -1
- package/dist/components/DetailList/DetailList.d.ts +31 -5
- package/dist/components/DetailList/DetailList.d.ts.map +1 -1
- package/dist/components/DetailList/index.d.ts +1 -1
- package/dist/components/DetailList/index.d.ts.map +1 -1
- package/dist/components/DetailList/index.js +1 -1
- package/dist/components/DetentSlider/index.js +1 -1
- package/dist/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog/index.js +1 -1
- package/dist/components/Disclosure/Disclosure.d.ts +1 -1
- package/dist/components/Disclosure/index.js +1 -1
- package/dist/components/{DragHandleGlyph/DragHandleGlyph.d.ts → DragGrip/DragGrip.d.ts} +4 -4
- package/dist/components/DragGrip/DragGrip.d.ts.map +1 -0
- package/dist/components/DragGrip/index.d.ts +3 -0
- package/dist/components/DragGrip/index.d.ts.map +1 -0
- package/dist/components/DragGrip/index.js +2 -0
- package/dist/components/FallthroughDiagram/FallthroughDiagram.d.ts +14 -0
- package/dist/components/FallthroughDiagram/FallthroughDiagram.d.ts.map +1 -0
- package/dist/components/FallthroughDiagram/fixtures.d.ts +17 -0
- package/dist/components/FallthroughDiagram/fixtures.d.ts.map +1 -0
- package/dist/components/FallthroughDiagram/index.d.ts +3 -0
- package/dist/components/FallthroughDiagram/index.d.ts.map +1 -0
- package/dist/components/FallthroughDiagram/index.js +2 -0
- package/dist/components/FontFamilySelect/index.js +1 -1
- package/dist/components/GestureRoute/GestureRoute.d.ts +19 -0
- package/dist/components/GestureRoute/GestureRoute.d.ts.map +1 -0
- package/dist/components/GestureRoute/index.d.ts +3 -0
- package/dist/components/GestureRoute/index.d.ts.map +1 -0
- package/dist/components/GestureRoute/index.js +2 -0
- package/dist/components/GradientEditor/GradientEditor.d.ts +22 -8
- package/dist/components/GradientEditor/GradientEditor.d.ts.map +1 -1
- package/dist/components/GradientEditor/index.js +1 -1
- package/dist/components/InlineRange/index.js +1 -1
- package/dist/components/Jog/index.js +1 -1
- package/dist/components/Keycaps/Keycaps.d.ts +11 -5
- package/dist/components/Keycaps/Keycaps.d.ts.map +1 -1
- package/dist/components/Keycaps/index.d.ts +1 -1
- package/dist/components/Keycaps/index.d.ts.map +1 -1
- package/dist/components/Keycaps/index.js +1 -1
- package/dist/components/LayerList/LayerList.d.ts +1 -1
- package/dist/components/LayerList/LayerList.d.ts.map +1 -1
- package/dist/components/LayerList/index.js +1 -1
- package/dist/components/ListEditor/ListEditor.d.ts.map +1 -1
- package/dist/components/ListEditor/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 +20 -7
- 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/PaintInput.d.ts.map +1 -1
- package/dist/components/PaintInput/index.js +1 -1
- package/dist/components/PatternPicker/index.js +1 -1
- package/dist/components/PointPlotter/index.js +1 -1
- package/dist/components/Powerline/index.d.ts +1 -1
- package/dist/components/Powerline/index.d.ts.map +1 -1
- package/dist/components/Powerline/index.js +2 -2
- package/dist/components/Prefs/PrefsRow.d.ts.map +1 -1
- package/dist/components/Prefs/index.d.ts +1 -1
- package/dist/components/Prefs/index.d.ts.map +1 -1
- package/dist/components/Prefs/index.js +2 -2
- package/dist/components/Prefs/prefField.d.ts.map +1 -1
- package/dist/components/Prefs/schema.d.ts +2 -2
- package/dist/components/Prefs/schema.d.ts.map +1 -1
- package/dist/components/Properties/PropertyField.d.ts +22 -30
- package/dist/components/Properties/PropertyField.d.ts.map +1 -1
- package/dist/components/Properties/PropertyGroup.d.ts.map +1 -1
- package/dist/components/Properties/PropertyPanel.d.ts +1 -8
- package/dist/components/Properties/PropertyPanel.d.ts.map +1 -1
- package/dist/components/Properties/index.d.ts +1 -1
- package/dist/components/Properties/index.d.ts.map +1 -1
- package/dist/components/Properties/index.js +2 -2
- package/dist/components/RangeSlider/index.js +1 -1
- package/dist/components/ResizeHandle/index.js +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/index.js +1 -1
- package/dist/components/SelectionPanel/SelectionPanel.d.ts.map +1 -1
- package/dist/components/SelectionPanel/index.js +2 -2
- package/dist/components/SelectionPanel/renderLeaf.d.ts +7 -0
- package/dist/components/SelectionPanel/renderLeaf.d.ts.map +1 -1
- package/dist/components/SidebarPanel/SidebarPanel.d.ts +1 -1
- package/dist/components/SidebarPanel/SidebarPanel.d.ts.map +1 -1
- package/dist/components/SidebarPanel/index.js +1 -1
- package/dist/components/Slider/Slider.d.ts +19 -2
- package/dist/components/Slider/Slider.d.ts.map +1 -1
- package/dist/components/Slider/index.js +1 -1
- package/dist/components/StatusBar/index.js +1 -1
- package/dist/components/SwatchGrid/index.js +1 -1
- package/dist/components/ThemeSwitcher/ThemeSwitcher.d.ts +38 -0
- package/dist/components/ThemeSwitcher/ThemeSwitcher.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher/index.d.ts +3 -0
- package/dist/components/ThemeSwitcher/index.d.ts.map +1 -0
- package/dist/components/ThemeSwitcher/index.js +2 -0
- package/dist/components/Timeline/Transport.d.ts.map +1 -1
- package/dist/components/Timeline/index.js +1 -1
- package/dist/components/Toast/Toast.d.ts.map +1 -1
- package/dist/components/Toast/index.js +1 -1
- package/dist/components/ToggleBar/index.js +1 -1
- package/dist/components/TokenPanel/index.js +1 -1
- package/dist/components/ToolButton/index.js +1 -1
- package/dist/components/ToolOptionsBar/index.js +1 -1
- package/dist/components/ToolPalette/ToolPalette.d.ts +2 -1
- package/dist/components/ToolPalette/ToolPalette.d.ts.map +1 -1
- package/dist/components/ToolPalette/index.js +1 -1
- package/dist/components/Tree/index.js +1 -1
- package/dist/components/spin.d.ts +16 -0
- package/dist/components/spin.d.ts.map +1 -0
- package/dist/components/stanceSurfaces.d.ts.map +1 -1
- package/dist/icons/index.d.ts +0 -2
- package/dist/icons/index.d.ts.map +1 -1
- package/dist/icons/paths.d.ts +10 -0
- package/dist/icons/paths.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -99
- package/dist/index.js.map +1 -1
- package/dist/paintGradientTrack.d.ts +5 -2
- package/dist/paintGradientTrack.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/useReorderDragList.d.ts +1 -1
- package/dist/useReorderDragList.d.ts.map +1 -1
- package/package.json +9 -8
- package/dist/chunks/Badge-CyAIZSDo.js.map +0 -1
- package/dist/chunks/BandEditor-Dhm_Xrlr.js +0 -248
- package/dist/chunks/BandEditor-Dhm_Xrlr.js.map +0 -1
- package/dist/chunks/Callout-yEn9iPlh.js +0 -119
- package/dist/chunks/Callout-yEn9iPlh.js.map +0 -1
- package/dist/chunks/ColorField-BcMcW8Sa.js +0 -60
- package/dist/chunks/ColorField-BcMcW8Sa.js.map +0 -1
- package/dist/chunks/ComboBox-DpT8lc3p.js.map +0 -1
- package/dist/chunks/DataGrid-D-dZj1BD.js.map +0 -1
- package/dist/chunks/DetailList-BMER1LUZ.js +0 -43
- package/dist/chunks/DetailList-BMER1LUZ.js.map +0 -1
- package/dist/chunks/Dialog-BWyNMgpf.js +0 -66
- package/dist/chunks/Dialog-BWyNMgpf.js.map +0 -1
- package/dist/chunks/Disclosure-0G0uh2fa.js.map +0 -1
- package/dist/chunks/DragHandleGlyph-Dr7Fgo0I.js.map +0 -1
- package/dist/chunks/GradientEditor-B3a-MsVJ.js +0 -335
- package/dist/chunks/GradientEditor-B3a-MsVJ.js.map +0 -1
- package/dist/chunks/Icon-Cgzy8VgC.js.map +0 -1
- package/dist/chunks/InlineRange-eOj6JpJl.js.map +0 -1
- package/dist/chunks/Keycaps-C0H_v2gO.js.map +0 -1
- package/dist/chunks/LayerList-nz-QYvTF.js.map +0 -1
- package/dist/chunks/ListEditor-BQ6AV3Ac.js +0 -74
- package/dist/chunks/ListEditor-BQ6AV3Ac.js.map +0 -1
- package/dist/chunks/MenuButton-DtaGenKf.js.map +0 -1
- package/dist/chunks/NumberField-CwJOMmQR.js +0 -117
- package/dist/chunks/NumberField-CwJOMmQR.js.map +0 -1
- package/dist/chunks/PaintInput-Byhna3H-.js +0 -131
- package/dist/chunks/PaintInput-Byhna3H-.js.map +0 -1
- package/dist/chunks/Prefs-DpqFKiwY.js.map +0 -1
- package/dist/chunks/Properties-D_KzDN9K.js.map +0 -1
- package/dist/chunks/PropertyField-DGCecAnV.js +0 -758
- package/dist/chunks/PropertyField-DGCecAnV.js.map +0 -1
- package/dist/chunks/RangeSlider-BKRRTPTZ.js.map +0 -1
- package/dist/chunks/ResizeHandle-BKT0XYpx.js.map +0 -1
- package/dist/chunks/Select-CzyfaXzp.js +0 -225
- package/dist/chunks/Select-CzyfaXzp.js.map +0 -1
- package/dist/chunks/SelectionPanel-BgUM1h03.js +0 -103
- package/dist/chunks/SelectionPanel-BgUM1h03.js.map +0 -1
- package/dist/chunks/SidebarPanel-aoIqxbtq.js +0 -55
- package/dist/chunks/SidebarPanel-aoIqxbtq.js.map +0 -1
- package/dist/chunks/Slider-CFwQYQ10.js +0 -383
- package/dist/chunks/Slider-CFwQYQ10.js.map +0 -1
- package/dist/chunks/StatusBar-DzoPDY4k.js.map +0 -1
- package/dist/chunks/SwatchGrid-BARC3rnF.js.map +0 -1
- package/dist/chunks/Timeline--58F7MED.js.map +0 -1
- package/dist/chunks/Toast-DNBb-24H.js.map +0 -1
- package/dist/chunks/ToggleBar-DTjGeS0Q.js.map +0 -1
- package/dist/chunks/ToolButton-CR4sQlxF.js.map +0 -1
- package/dist/chunks/ToolOptionsBar-CtzTlaN2.js.map +0 -1
- package/dist/chunks/ToolPalette-CKG9qY6P.js.map +0 -1
- package/dist/chunks/createKeyframeLayer-Czj6Y235.js.map +0 -1
- package/dist/chunks/icons-Dk8SRS8g.js.map +0 -1
- package/dist/chunks/model-Du7Lta4C.js.map +0 -1
- package/dist/chunks/number-D3NEx_8r.js +0 -89
- package/dist/chunks/number-D3NEx_8r.js.map +0 -1
- package/dist/chunks/prefField-Dnl7nmjQ.js.map +0 -1
- package/dist/chunks/segmentedControl.module-Bv7DEg8f.js +0 -11
- package/dist/chunks/segmentedControl.module-Bv7DEg8f.js.map +0 -1
- package/dist/chunks/useReorderDragList-B_-5L5Gu.js.map +0 -1
- package/dist/components/DragHandleGlyph/DragHandleGlyph.d.ts.map +0 -1
- package/dist/components/DragHandleGlyph/index.d.ts +0 -3
- package/dist/components/DragHandleGlyph/index.d.ts.map +0 -1
- package/dist/components/DragHandleGlyph/index.js +0 -2
- package/dist/format/number.d.ts +0 -56
- package/dist/format/number.d.ts.map +0 -1
- package/dist/icons/ShapeKindIcon.d.ts +0 -10
- package/dist/icons/ShapeKindIcon.d.ts.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Timeline--58F7MED.js","names":["easingLabel","s","KEY_STEP_MS","s","s","_Fragment","s","s","st","s","PauseIcon","PlayIcon","createKeyframeLayer","applyKeyframeDrag","snapToNearest","DetentSlider","Timeline_module_default","bezierOf","spec","easingBezier","easingLabel","b","name","fn","EASINGS","sampleEasing","resolveEasing","out","count","last","i","EASING_NAMES","PREVIEW_SAMPLES","BEZIER_OF","DEFAULT_BEZIER","EasingPicker","props","bezier","value","label","named","selectValue","points","v","onChange","n","MIN_SPAN_MS","createTimeScale","span","window","perMs","widthPx","perPx","ms","px","toFraction","toPercent","spanFraction","spanPercent","clampWindow","w","bounds","from","zoomWindow","maxSpan","nextSpan","factor","frac","atMs","panWindow","byMs","tickTimes","step","niceStep","minSpacingPx","V_INSET_PCT","KEY_STEP_MS$1","valueRange","values","keys","k","lo","pad","LaneGraph","win","hostRef","useRef","size","setSize","useState","el","update","r","prev","ro","layer","useMemo","t","snapTimes","offset","committed","selection","selectedSegment","live","setLive","state","stateRef","layers","onLayerChange","next","raw","onSelect","onSelectSegment","applied","onKeysInput","onLayerCommit","rawPrev","onKeysCommit","yLo","yHi","ticks","LayeredCurveEditor","KEY_STEP_MS","entryTimes","row","Lane","trackRef","sessionRef","drag","setDrag","pct","msAt","rect","clientX","snapPxToMs","width","scale","graph","mode","sampledKeys","onKeyPointerDown","e","at","ev","times","end","openPointerSession","onKeyInput","onKeyCommit","onKeyDown","expanded","onToggleExpand","DisclosureMark","onInsert","Fragment","idx","ZOOM_STEP","formatMs","Ruler","setWidth","widthOf","onPointerDown","onScrub","onWheel","playhead","RATES","seconds","Transport","looping","loop","rates","rate","a","paused","onPlay","onPause","jsx","onLoopChange","onRateChange","duration","isNumeric","track","buildLanes","walk","nextPath","path","key","depth","tracks","trackAtPath","list","found","samePath","withKeys","withEvents","replaceAtPath","rest","parent","tt","moveKey","sel","toMs","st","moved","keyIndex","et","events","insertKey","trackPath","sampleTrack","deleteKey","setKeyEasing","_drop","easing","setKeys","setKeyValue","Timeline","setExpanded","ownWindow","setOwnWindow","ownSelection","setOwnSelection","segmentSelection","setSegmentSelection","setWindow","setSelection","rows","toggle","onRootKeyDown","selectedTrack","selectedKey","segmentTrack","segmentKey","className","onInput","renderKeyEditor","AnimatedTimeline","bump","useReducer","handle","rafRef","raf","useVisibleRaf","useEffect","useCallback"],"sources":["../../src/components/Timeline/Timeline.module.css","../../src/components/Timeline/easingSpec.ts","../../src/components/Timeline/EasingPicker.tsx","../../src/components/Timeline/timeScale.ts","../../src/components/Timeline/LaneGraph.tsx","../../src/components/Timeline/Lane.tsx","../../src/components/Timeline/Ruler.tsx","../../src/components/Timeline/Transport.tsx","../../src/components/Timeline/lanes.ts","../../src/components/Timeline/keys.ts","../../src/components/Timeline/Timeline.tsx","../../src/components/Timeline/AnimatedTimeline.tsx"],"sourcesContent":[".ruler {\n position: relative;\n height: var(--wzl-control-h, 24px);\n border-bottom: 1px solid var(--wzl-border);\n background: var(--wzl-surface-raised);\n cursor: ew-resize;\n user-select: none;\n overflow: hidden;\n}\n\n.tick {\n position: absolute;\n top: 0;\n transform: translateX(2px);\n color: var(--wzl-fg-muted);\n pointer-events: none;\n white-space: nowrap;\n}\n\n.tick::before {\n content: '';\n position: absolute;\n left: -2px;\n top: 0;\n bottom: 0;\n border-left: 1px solid var(--wzl-border);\n}\n\n.playhead {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--wzl-accent-strong);\n pointer-events: none;\n}\n\n.lane {\n display: flex;\n align-items: stretch;\n min-height: var(--wzl-control-h-sm);\n border-bottom: 1px solid var(--wzl-line-subtle);\n}\n\n.laneLabel {\n /* Must match `.gutter`'s width exactly, or every key sits off the ruler. */\n box-sizing: border-box;\n flex: 0 0 var(--wzl-timeline-label-w, 120px);\n display: flex;\n align-items: center;\n gap: var(--wzl-space-2);\n padding-inline: var(--wzl-space-3);\n padding-inline-start: calc(var(--wzl-space-3) + var(--depth, 0) * var(--wzl-space-6));\n font-size: var(--wzl-font-size);\n color: var(--wzl-fg);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.lane[data-depth='1'] .laneLabel { --depth: 1; }\n.lane[data-depth='2'] .laneLabel { --depth: 2; }\n.lane[data-depth='3'] .laneLabel { --depth: 3; }\n\n.disclosure { display: inline-flex; flex: none; cursor: pointer; }\n\n.laneTrack {\n position: relative;\n flex: 1 1 auto;\n min-width: 0;\n background: var(--wzl-surface);\n}\n\n.key, .eventMark {\n position: absolute;\n top: 50%;\n width: var(--wzl-handle-size);\n height: var(--wzl-handle-size);\n margin-left: calc(var(--wzl-handle-size) / -2);\n background: var(--wzl-fg-muted);\n cursor: ew-resize;\n}\n\n.key { transform: translateY(-50%) rotate(45deg); }\n.eventMark { transform: translateY(-50%); border-radius: 50%; }\n\n.key[aria-current='true'], .eventMark[aria-current='true'] { background: var(--wzl-accent-strong); }\n.key:focus-visible, .eventMark:focus-visible { outline: 2px solid var(--wzl-focus-ring); outline-offset: 1px; }\n\n/* The key stays drawn where it was committed while its ghost tracks the\n pointer, so the drag reads as a move from somewhere to somewhere. */\n.key[data-dragging='true'], .eventMark[data-dragging='true'] { opacity: 0.4; }\n\n.keyGhost, .eventGhost {\n position: absolute;\n top: 50%;\n width: var(--wzl-handle-size);\n height: var(--wzl-handle-size);\n margin-left: calc(var(--wzl-handle-size) / -2);\n background: var(--wzl-accent-soft);\n border: 1px dashed var(--wzl-accent-strong);\n pointer-events: none;\n}\n\n.keyGhost { transform: translateY(-50%) rotate(45deg); }\n.eventGhost { transform: translateY(-50%); border-radius: 50%; }\n\n.lane[data-mode='graph'] { min-height: 72px; }\n\n/* A numeric lane in graph mode is a curve editor filling the track. */\n.graphHost {\n position: absolute;\n inset: 0;\n}\n\n/* Out-specifies the editor's own defaults: the lane keeps the track's ground\n and the timeline's accent line rather than a plot's. */\n.graphHost .graph {\n --plot-bg: transparent;\n --curve-line: var(--wzl-accent-strong);\n --curve-line-width: 1px;\n}\n\n/* A graph lane's value labels hang off the track's start edge into the label\n column, so the lane's own label ellipsizes before it reaches them. */\n.lane[data-graph='true'] .laneLabel {\n padding-inline-end: calc(var(--wzl-space-3) + var(--wzl-timeline-value-axis-w, 32px));\n}\n\n.nestedBar {\n position: absolute;\n top: 4px;\n bottom: 4px;\n background: var(--wzl-surface-sunken);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n.transport {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n padding: var(--wzl-space-2) var(--wzl-space-3);\n border-bottom: 1px solid var(--wzl-border);\n background: var(--wzl-surface-raised);\n}\n\n.transportButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--wzl-icon-button-size);\n padding: var(--wzl-space-1) var(--wzl-space-3);\n /* Sits on `--wzl-surface-raised`, so a transparent fill and a border that\n close in value leave it reading as text rather than as a control. */\n background: var(--wzl-surface);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n cursor: pointer;\n}\n\n.transportButton:hover { border-color: var(--wzl-fg-muted); }\n\n.transportButton[aria-checked='true'] {\n background: var(--wzl-accent-soft);\n border-color: var(--wzl-accent-strong);\n color: var(--wzl-accent-fg);\n}\n\n/* The bar's chrome lives on the row, so controls beside `<Transport>` sit\n inside it rather than hanging off the panel's corner. `.transport` keeps its\n own chrome for standalone use. */\n.transportRow {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n padding-inline-end: var(--wzl-space-3);\n border-bottom: 1px solid var(--wzl-border);\n background: var(--wzl-surface-raised);\n}\n\n.transportRow > .transport {\n flex: 1 1 auto;\n border-bottom: 0;\n background: transparent;\n}\n\n/* Last in the row, and growing leftward into the slack `margin-inline-start`\n leaves it: the playhead rewrites this every frame and gains a digit at 10s,\n so anything laid out after it would vibrate. */\n.time {\n margin-inline-start: auto;\n text-align: end;\n font-variant-numeric: tabular-nums;\n color: var(--wzl-fg-muted);\n}\n.rate { display: inline-flex; align-items: center; gap: var(--wzl-space-3); color: var(--wzl-fg-muted); }\n.rateSlider { width: 88px; }\n\n/* The detents carry no labels in a bar this dense, so the chosen rate is said\n once, here, in a fixed-width cell so the controls beside it never shift. */\n.rateReadout {\n min-width: 3ch;\n font-variant-numeric: tabular-nums;\n color: var(--wzl-fg);\n}\n\n.root {\n display: flex;\n flex-direction: column;\n min-height: 0;\n background: var(--wzl-surface);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n /* `--wzl-font-ui` is condensed, so it reads a size smaller than it measures.\n Everything below inherits this; override per rule only to go up. */\n font-family: var(--wzl-font-ui);\n font-size: var(--wzl-font-size-sm);\n line-height: var(--wzl-leading-snug);\n}\n\n.label { padding: var(--wzl-space-2) var(--wzl-space-3); color: var(--wzl-fg-muted); }\n\n.body { display: flex; align-items: stretch; }\n.gutter { box-sizing: border-box; flex: 0 0 var(--wzl-timeline-label-w, 120px); border-right: 1px solid var(--wzl-border); }\n.rulerWrap { flex: 1 1 auto; min-width: 0; }\n\n.lanes {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\n.inspector {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n padding: var(--wzl-space-2) var(--wzl-space-3);\n border-top: 1px solid var(--wzl-border);\n background: var(--wzl-surface-raised);\n}\n\n.segment {\n position: absolute;\n top: 0;\n bottom: 0;\n cursor: pointer;\n}\n\n.segment[aria-current='true'] { background: var(--wzl-accent-soft); }\n.segment:focus-visible { outline: 2px solid var(--wzl-focus-ring); outline-offset: -2px; }\n\n.easingPicker { display: inline-flex; align-items: center; gap: var(--wzl-space-3); }\n.easingLabel { font-variant-numeric: tabular-nums; color: var(--wzl-fg-muted); }\n\n.easingPreview {\n width: 32px;\n height: 32px;\n fill: none;\n stroke: var(--wzl-accent-strong);\n stroke-width: 1;\n border: 1px solid var(--wzl-border);\n}\n\n","import { EASINGS, resolveEasing, type EasingName, type EasingSpec } from '@weasel-js/core';\n\nfunction bezierOf(spec: EasingSpec): readonly [number, number, number, number] | null {\n if (typeof spec === 'object' && spec !== null && 'bezier' in spec) return spec.bezier;\n return null;\n}\n\n/** Control points, for the graph view's draggable handles. `null` means this\n * spec has no handles to drag — the view offers to convert it to a bezier. */\nexport function easingBezier(spec?: EasingSpec): readonly [number, number, number, number] | null {\n if (spec === undefined) return null;\n return bezierOf(spec);\n}\n\n/** What the picker shows for a spec.\n *\n * A function is matched against the built-ins by reference so a consumer that\n * passed `easeOutBack` directly still reads back as `'easeOutBack'`. A wrapped\n * or hand-written function cannot be named and reads as `'custom'` — which is\n * why an editor writes names and control points rather than functions. */\nexport function easingLabel(spec?: EasingSpec): string {\n if (spec === undefined) return 'linear';\n if (typeof spec === 'string') return spec;\n const b = bezierOf(spec);\n if (b) return `cubic-bezier(${b.join(', ')})`;\n for (const [name, fn] of Object.entries(EASINGS)) {\n if (fn === spec) return name;\n }\n return 'custom';\n}\n\n/** `count` evenly spaced samples of the curve over 0..1, for drawing it. */\nexport function sampleEasing(spec: EasingSpec | undefined, count: number): number[] {\n const fn = resolveEasing(spec);\n const out = new Array<number>(count);\n const last = count - 1;\n for (let i = 0; i < count; i++) out[i] = fn(last === 0 ? 0 : i / last);\n return out;\n}\n\n/** Every built-in name, for the picker's list. */\nexport const EASING_NAMES = Object.keys(EASINGS) as EasingName[];\n","import type { ReactElement } from 'react';\nimport type { EasingSpec } from '@weasel-js/core';\nimport s from './Timeline.module.css';\nimport { EASING_NAMES, easingBezier, easingLabel, sampleEasing } from './easingSpec';\n\n/** Samples drawn in the inline curve preview. */\nconst PREVIEW_SAMPLES = 24;\n\n/** Control points for the named curves the picker can convert. A name the table\n * does not cover converts to the CSS default rather than refusing. */\nconst BEZIER_OF: Partial<Record<string, readonly [number, number, number, number]>> = {\n linear: [0, 0, 1, 1],\n easeInQuad: [0.11, 0, 0.5, 0],\n easeOutQuad: [0.5, 1, 0.89, 1],\n easeInOutQuad: [0.45, 0, 0.55, 1],\n easeInCubic: [0.32, 0, 0.67, 0],\n easeOutCubic: [0.33, 1, 0.68, 1],\n easeInOutCubic: [0.65, 0, 0.35, 1],\n easeInSine: [0.12, 0, 0.39, 0],\n easeOutSine: [0.61, 1, 0.88, 1],\n easeInOutSine: [0.37, 0, 0.63, 1],\n};\n\nconst DEFAULT_BEZIER: readonly [number, number, number, number] = [0.25, 0.1, 0.25, 1];\n\nexport interface EasingPickerProps {\n value: EasingSpec | undefined;\n onChange: (next: EasingSpec | undefined) => void;\n}\n\nexport function EasingPicker(props: EasingPickerProps): ReactElement {\n const { value, onChange } = props;\n const bezier = easingBezier(value);\n const label = easingLabel(value);\n const named = bezier === null && (EASING_NAMES as string[]).includes(label);\n const selectValue = bezier !== null ? 'custom' : named ? label : 'linear';\n\n const points = sampleEasing(value, PREVIEW_SAMPLES)\n .map((v, i) => `${(i / (PREVIEW_SAMPLES - 1)) * 100},${100 - v * 100}`)\n .join(' ');\n\n return (\n <div className={s.easingPicker}>\n <label>\n Easing\n <select\n value={selectValue}\n onChange={(e) => onChange(e.target.value === 'linear' ? undefined : e.target.value as EasingSpec)}\n >\n <option value=\"linear\">linear</option>\n {EASING_NAMES.filter((n) => n !== 'linear').map((n) => <option key={n} value={n}>{n}</option>)}\n {bezier !== null ? <option value=\"custom\">custom</option> : null}\n </select>\n </label>\n\n {bezier !== null ? <span className={s.easingLabel}>{label}</span> : (\n <button\n type=\"button\"\n className={s.transportButton}\n onClick={() => onChange({ bezier: BEZIER_OF[selectValue] ?? DEFAULT_BEZIER })}\n >\n Convert to bezier\n </button>\n )}\n\n <svg className={s.easingPreview} data-testid=\"easing-preview\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\">\n <polyline points={points} vectorEffect=\"non-scaling-stroke\" />\n </svg>\n </div>\n );\n}\n","import { niceStep } from '../Plot2D/ticks';\n\n/** A visible span of timeline time, in ms. */\nexport interface TimeWindow {\n from: number;\n to: number;\n}\n\nexport interface TimeScale {\n window: TimeWindow;\n widthPx: number;\n toPx(ms: number): number;\n toMs(px: number): number;\n}\n\n/** Narrowest window the user can zoom to, in ms. Below this the playhead and\n * the keys it sits between stop being separable at any sane track width. */\nconst MIN_SPAN_MS = 1;\n\nexport function createTimeScale(window: TimeWindow, widthPx: number): TimeScale {\n const span = window.to - window.from;\n const perMs = span === 0 ? 0 : widthPx / span;\n const perPx = widthPx === 0 ? 0 : span / widthPx;\n return {\n window,\n widthPx,\n toPx: (ms) => (ms - window.from) * perMs,\n toMs: (px) => window.from + px * perPx,\n };\n}\n\n/** Where `ms` sits in the window, as a fraction. The width-free half of\n * `createTimeScale` — a CSS `left: %` needs no pixel width, and asking for one\n * is what drove three copies of this arithmetic into the lane and the ruler. */\nexport function toFraction(window: TimeWindow, ms: number): number {\n const span = window.to - window.from;\n return span === 0 ? 0 : (ms - window.from) / span;\n}\n\n/** `toFraction` as a CSS percentage. */\nexport function toPercent(window: TimeWindow, ms: number): string {\n return `${toFraction(window, ms) * 100}%`;\n}\n\n/** A duration as a fraction of the window. Distinct from `toFraction`, which\n * measures a position and so subtracts `window.from`. */\nexport function spanFraction(window: TimeWindow, ms: number): number {\n const span = window.to - window.from;\n return span === 0 ? 0 : ms / span;\n}\n\n/** A duration as a CSS percentage, for a width. */\nexport function spanPercent(window: TimeWindow, ms: number): string {\n return `${spanFraction(window, ms) * 100}%`;\n}\n\nfunction clampWindow(w: TimeWindow, bounds: TimeWindow): TimeWindow {\n const span = Math.min(w.to - w.from, bounds.to - bounds.from);\n let from = w.from;\n if (from < bounds.from) from = bounds.from;\n if (from + span > bounds.to) from = bounds.to - span;\n return { from, to: from + span };\n}\n\n/** Scale the window by `factor` about `atMs`, which stays at the same fraction\n * of the track. `factor < 1` zooms in. */\nexport function zoomWindow(\n w: TimeWindow, atMs: number, factor: number, bounds: TimeWindow,\n): TimeWindow {\n const span = w.to - w.from;\n const maxSpan = bounds.to - bounds.from;\n const nextSpan = Math.min(maxSpan, Math.max(MIN_SPAN_MS, span * factor));\n const frac = span === 0 ? 0.5 : (atMs - w.from) / span;\n return clampWindow({ from: atMs - frac * nextSpan, to: atMs + (1 - frac) * nextSpan }, bounds);\n}\n\n/** Shift the window by `byMs`, preserving its span. */\nexport function panWindow(w: TimeWindow, byMs: number, bounds: TimeWindow): TimeWindow {\n return clampWindow({ from: w.from + byMs, to: w.to + byMs }, bounds);\n}\n\n/** Minimum gap between time ticks, in px — the ruler's and the graph grid's. */\nexport const TICK_SPACING_PX = 64;\n\n/** Ruler tick times inside `w`, spaced at least `minSpacingPx` apart. */\nexport function tickTimes(w: TimeWindow, widthPx: number, minSpacingPx: number): number[] {\n const span = w.to - w.from;\n if (widthPx <= 0 || span <= 0) return [];\n const step = niceStep((minSpacingPx / widthPx) * span);\n const out: number[] = [];\n for (let t = Math.ceil(w.from / step) * step; t <= w.to + 1e-9; t += step) {\n out.push(Math.round(t / step) * step);\n }\n return out;\n}\n","import { useLayoutEffect, useMemo, useRef, useState, type ReactElement } from 'react';\nimport type { Keyframe } from '@weasel-js/core';\nimport { LayeredCurveEditor } from '../CurveEditor/LayeredCurveEditor';\nimport {\n applyKeyframeDrag, createKeyframeLayer, type KeyframeLayerState,\n} from '../CurveEditor/createKeyframeLayer';\nimport s from './Timeline.module.css';\nimport { TICK_SPACING_PX, tickTimes, type TimeWindow } from './timeScale';\n\n/** Keeps the extreme keys inside the lane: at the very edge a key centers on\n * the lane's border and hangs half into its neighbor. As a percentage of\n * the lane's height, applied top and bottom. */\nconst V_INSET_PCT = 8;\n\n/** One arrow-key step, in ms; shift multiplies by ten. */\nconst KEY_STEP_MS = 10;\n\nexport interface LaneGraphProps {\n keys: readonly Keyframe<number>[];\n label: string;\n window: TimeWindow;\n /** Ruler time of this track's zero. */\n offset: number;\n /** Ruler times a dragged key snaps to. */\n snapTimes: readonly number[];\n selection: number | null;\n selectedSegment: number | null;\n onSelect: (keyIndex: number) => void;\n onSelectSegment?: (keyIndex: number) => void;\n /** Live during a key drag. */\n onKeysInput?: (keys: readonly Keyframe<number>[]) => void;\n /** Once per edit: a drag's end, a handle's release, a key press. */\n onKeysCommit: (keys: readonly Keyframe<number>[]) => void;\n}\n\n/** The value range a lane plots: its keys' extent, padded so no key sits on\n * the border. A flat track gets a unit span so it still has a middle. */\nfunction valueRange(keys: readonly Keyframe<number>[]): [number, number] {\n const values = keys.map((k) => k.value);\n const lo = Math.min(...values);\n const hi = Math.max(...values);\n const span = hi - lo || 1;\n const pad = (span * V_INSET_PCT) / (100 - 2 * V_INSET_PCT);\n return [lo - pad, lo + span + pad];\n}\n\n/** A numeric lane's graph: one keyframe layer on a curve editor, sized to the\n * lane and windowed to the ruler. */\nexport function LaneGraph(props: LaneGraphProps): ReactElement {\n const {\n keys, label, window: win, offset, snapTimes, selection, selectedSegment,\n onSelect, onSelectSegment, onKeysInput, onKeysCommit,\n } = props;\n\n const hostRef = useRef<HTMLDivElement | null>(null);\n const [size, setSize] = useState({ width: 0, height: 0 });\n useLayoutEffect(() => {\n const el = hostRef.current;\n if (!el) return;\n const update = (): void => {\n const r = el.getBoundingClientRect();\n setSize((prev) => (prev.width === r.width && prev.height === r.height ? prev : { width: r.width, height: r.height }));\n };\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const layer = useMemo(() => createKeyframeLayer({\n id: 'keys',\n label,\n formatX: (t) => `${Math.round(t)} ms`,\n // The layer works in track time; the snap candidates are ruler times.\n snapX: snapTimes.map((t) => t - offset),\n xClamp: [0, Infinity],\n step: { x: KEY_STEP_MS },\n }), [label, snapTimes, offset]);\n\n const committed = useMemo<KeyframeLayerState>(\n () => ({ keys, selectedKey: selection, selectedSegment, drag: null }),\n [keys, selection, selectedSegment],\n );\n // Held only while a gesture is in flight, so a consumer echoing live input\n // back through `keys` cannot move the keys out from under the drag.\n const [live, setLive] = useState<KeyframeLayerState | null>(null);\n const state = live ?? committed;\n const stateRef = useRef(state);\n stateRef.current = state;\n\n const layers = useMemo(() => [{ layer, state: state as unknown }], [layer, state]);\n\n const onLayerChange = (_id: string, raw: unknown): void => {\n const next = raw as KeyframeLayerState;\n const prev = stateRef.current;\n if (next.selectedKey !== null && next.selectedKey !== prev.selectedKey) onSelect(next.selectedKey);\n if (next.selectedSegment !== null && next.selectedSegment !== prev.selectedSegment) onSelectSegment?.(next.selectedSegment);\n if (!next.drag) { setLive(null); return; }\n setLive(next);\n // A handle drag writes a fresh easing spec per move; publishing those\n // would grow the consumer's easing cache by one entry per pixel.\n if (next.drag.kind !== 'key') return;\n const applied = applyKeyframeDrag(next).keys;\n if (applied !== next.keys) onKeysInput?.(applied);\n };\n\n const onLayerCommit = (_id: string, raw: unknown, rawPrev: unknown): void => {\n setLive(null);\n const next = raw as KeyframeLayerState;\n if (next.keys !== (rawPrev as KeyframeLayerState).keys) onKeysCommit(next.keys);\n };\n\n const [yLo, yHi] = valueRange(state.keys);\n const ticks = size.width > 0 ? tickTimes(win, size.width, TICK_SPACING_PX) : [];\n\n return (\n <div ref={hostRef} className={s.graphHost}>\n {size.width > 0 && size.height > 0 ? (\n <LayeredCurveEditor\n className={s.graph}\n aria-label={`${label} graph`}\n layers={layers}\n onLayerChange={onLayerChange}\n onLayerCommit={onLayerCommit}\n width={size.width}\n height={size.height}\n xRange={[win.from - offset, win.to - offset]}\n yRange={[yLo, yHi]}\n grid={false}\n axes={false}\n // The ruler's ticks, carried into track time.\n xTicks={{ values: ticks.map((t) => t - offset), labels: false }}\n // Clears a key at the track's start edge, which hangs into the gutter.\n yTicks={{ labels: 'outside', gap: 10 }}\n history={false}\n />\n ) : null}\n </div>\n );\n}\n","import { useEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type PointerEvent as ReactPointerEvent, type ReactElement } from 'react';\nimport { openPointerSession, type EventTrack, type Keyframe, type PointerSession, type SampledTrack, type TimelineTrack } from '@weasel-js/core';\nimport { DisclosureMark } from '../Disclosure';\nimport s from './Timeline.module.css';\nimport { createTimeScale, spanPercent, toPercent, type TimeWindow } from './timeScale';\nimport { SNAP_RADIUS_PX, snapToNearest } from '../../snap';\nimport { LaneGraph } from './LaneGraph';\nimport type { LaneRow } from './lanes';\n\n/** One arrow-key step, in ms; shift multiplies by ten. */\nconst KEY_STEP_MS = 10;\n\nexport interface LaneProps {\n row: LaneRow;\n window: TimeWindow;\n mode: 'dope' | 'graph';\n /** Index of the selected key on THIS row, or null. */\n selection: number | null;\n onSelect: (keyIndex: number) => void;\n /** Live during a dope-sheet drag. */\n onKeyInput: (keyIndex: number, toMs: number) => void;\n /** Once, at the end of a dope-sheet gesture. */\n onKeyCommit: (keyIndex: number, toMs: number) => void;\n /** Live during a graph-mode key drag: the row's whole key list. */\n onKeysInput?: (keys: readonly Keyframe<number>[]) => void;\n /** Once per graph-mode edit: the row's whole key list. */\n onKeysCommit?: (keys: readonly Keyframe<number>[]) => void;\n onInsert: (atMs: number) => void;\n onToggleExpand: () => void;\n expanded: boolean;\n /** Times a dragged key snaps to. */\n snapTimes: readonly number[];\n /** Index of the key a selected segment runs INTO, or null. */\n selectedSegment?: number | null;\n onSelectSegment?: (keyIndex: number) => void;\n}\n\nfunction entryTimes(row: LaneRow): number[] {\n if (row.kind === 'sampled') return (row.track as SampledTrack<unknown>).keys.map((k) => k.t);\n if (row.kind === 'event') return (row.track as EventTrack).events.map((e) => e.t);\n return [];\n}\n\nexport function Lane(props: LaneProps): ReactElement {\n const {\n row, window: win, mode, selection, onSelect, onKeyInput, onKeyCommit, onInsert, onToggleExpand, expanded, snapTimes,\n selectedSegment = null, onSelectSegment, onKeysInput, onKeysCommit,\n } = props;\n const trackRef = useRef<HTMLDivElement | null>(null);\n const sessionRef = useRef<PointerSession | null>(null);\n useEffect(() => () => { sessionRef.current?.cancel(); }, []);\n\n // Where the dragged key would land. Owned here rather than derived from the\n // tracks prop, so a drag previews whether or not the consumer wires\n // `onKeyInput` — the committed key stays put underneath as the origin.\n const [drag, setDrag] = useState<{ keyIndex: number; t: number } | null>(null);\n\n const pct = (ms: number): string => toPercent(win, ms + row.offset);\n\n const msAt = (clientX: number): number => {\n const rect = trackRef.current?.getBoundingClientRect();\n if (!rect) return win.from;\n return createTimeScale(win, rect.width).toMs(clientX - rect.left) - row.offset;\n };\n\n const snapPxToMs = (): number => {\n const width = trackRef.current?.getBoundingClientRect().width ?? 0;\n const scale = createTimeScale(win, width);\n return scale.toMs(SNAP_RADIUS_PX) - scale.toMs(0);\n };\n\n // Only a numeric sampled row has an honest value axis to graph.\n const graph = mode === 'graph' && row.numeric;\n const sampledKeys = row.kind === 'sampled' ? (row.track as SampledTrack<number>).keys : [];\n\n const onKeyPointerDown = (i: number) => (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n e.stopPropagation();\n onSelect(i);\n\n // `snapTimes` are ruler times and `msAt` is track-local, so a nested row\n // has to cross into ruler space to snap and back out to commit.\n const at = (ev: { clientX: number; altKey: boolean }): number => {\n const raw = Math.max(0, msAt(ev.clientX));\n return ev.altKey ? raw : snapToNearest(raw + row.offset, snapTimes, snapPxToMs()) - row.offset;\n };\n\n setDrag({ keyIndex: i, t: times[i] });\n\n const end = (): void => {\n setDrag(null);\n sessionRef.current = null;\n };\n // No pointer capture — see `Ruler`, same idiom across the timeline.\n sessionRef.current?.cancel();\n sessionRef.current = openPointerSession(e.currentTarget, e, {\n onMove: (ev) => {\n setDrag({ keyIndex: i, t: at(ev) });\n onKeyInput(i, at(ev));\n },\n onEnd: (ev) => {\n onKeyCommit(i, at(ev));\n end();\n },\n onCancel: end,\n }, { capture: false });\n };\n\n const onKeyDown = (i: number, t: number) => (e: ReactKeyboardEvent<HTMLDivElement>): void => {\n const step = KEY_STEP_MS * (e.shiftKey ? 10 : 1);\n if (e.key === 'ArrowRight') { e.preventDefault(); onKeyCommit(i, t + step); }\n if (e.key === 'ArrowLeft') { e.preventDefault(); onKeyCommit(i, Math.max(0, t - step)); }\n };\n\n const times = entryTimes(row);\n\n return (\n <div className={s.lane} data-depth={row.depth} data-mode={mode} data-graph={graph ? 'true' : undefined}>\n <div className={s.laneLabel}>\n {row.kind === 'timeline' ? (\n <span\n role=\"button\"\n tabIndex={0}\n aria-expanded={expanded}\n data-testid=\"timeline-disclosure\"\n className={s.disclosure}\n onClick={onToggleExpand}\n onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onToggleExpand(); } }}\n >\n <DisclosureMark open={expanded} />\n </span>\n ) : null}\n {row.label}\n </div>\n <div\n className={s.laneTrack}\n ref={trackRef}\n data-testid=\"timeline-lane-track\"\n onDoubleClick={(e) => { if (row.kind === 'sampled') onInsert(Math.max(0, msAt(e.clientX))); }}\n >\n {graph ? (\n <LaneGraph\n keys={sampledKeys}\n label={row.label}\n window={win}\n offset={row.offset}\n snapTimes={snapTimes}\n selection={selection}\n selectedSegment={selectedSegment}\n onSelect={onSelect}\n onSelectSegment={onSelectSegment}\n onKeysInput={onKeysInput}\n onKeysCommit={(keys) => onKeysCommit?.(keys)}\n />\n ) : (\n <>\n {row.kind === 'timeline' ? (\n <div\n className={s.nestedBar}\n data-testid=\"timeline-nested\"\n style={{ left: pct(0), width: spanPercent(win, (row.track as TimelineTrack).timeline.duration ?? 0) }}\n />\n ) : null}\n {row.kind === 'sampled' ? sampledKeys.slice(1).map((k, idx) => {\n const i = idx + 1;\n return (\n <div\n key={`seg-${i}`}\n role=\"button\"\n tabIndex={0}\n aria-label={`${row.label} segment into ${Math.round(k.t)} ms`}\n aria-current={selectedSegment === i ? 'true' : undefined}\n data-testid=\"timeline-segment\"\n className={s.segment}\n style={{ left: pct(sampledKeys[i - 1].t), width: spanPercent(win, k.t - sampledKeys[i - 1].t) }}\n onClick={() => onSelectSegment?.(i)}\n onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelectSegment?.(i); } }}\n />\n );\n }) : null}\n {times.map((t, i) => (\n <div\n key={i}\n role=\"button\"\n tabIndex={0}\n aria-label={`${row.label} key at ${Math.round(t)} ms`}\n aria-current={selection === i ? 'true' : undefined}\n data-testid={row.kind === 'event' ? 'timeline-event' : 'timeline-key'}\n data-dragging={drag?.keyIndex === i ? 'true' : undefined}\n className={row.kind === 'event' ? s.eventMark : s.key}\n style={{ left: pct(t) }}\n onPointerDown={onKeyPointerDown(i)}\n onKeyDown={onKeyDown(i, t)}\n />\n ))}\n {drag ? (\n <div\n aria-hidden=\"true\"\n data-testid=\"timeline-key-ghost\"\n className={row.kind === 'event' ? s.eventGhost : s.keyGhost}\n style={{ left: pct(drag.t) }}\n />\n ) : null}\n </>\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useLayoutEffect, useRef, useState, type PointerEvent as ReactPointerEvent, type ReactElement, type WheelEvent as ReactWheelEvent } from 'react';\nimport { openPointerSession, type PointerSession } from '@weasel-js/core';\nimport s from './Timeline.module.css';\nimport { createTimeScale, panWindow, TICK_SPACING_PX, tickTimes, toPercent, zoomWindow, type TimeWindow } from './timeScale';\n\n/** One wheel notch's zoom factor. */\nconst ZOOM_STEP = 0.0015;\n\nexport interface RulerProps {\n window: TimeWindow;\n /** The full extent the window may cover — normally `{ from: 0, to: duration }`. */\n bounds: TimeWindow;\n playhead: number;\n onScrub: (t: number) => void;\n onWindowChange: (w: TimeWindow) => void;\n}\n\nfunction formatMs(ms: number): string {\n if (ms >= 1000) return `${(ms / 1000).toFixed(ms % 1000 === 0 ? 0 : 2)}s`;\n return `${Math.round(ms)}ms`;\n}\n\nexport function Ruler(props: RulerProps): ReactElement {\n const { window: win, bounds, playhead, onScrub, onWindowChange } = props;\n const trackRef = useRef<HTMLDivElement | null>(null);\n const sessionRef = useRef<PointerSession | null>(null);\n useEffect(() => () => { sessionRef.current?.cancel(); }, []);\n\n // Re-render once the track is mounted so ticks lay out against its real\n // width — `trackRef.current` is null on the render that first attaches it.\n const [width, setWidth] = useState(0);\n useLayoutEffect(() => {\n const el = trackRef.current;\n if (!el) return;\n const update = (): void => setWidth(el.getBoundingClientRect().width);\n update();\n if (typeof ResizeObserver === 'undefined') return;\n const ro = new ResizeObserver(update);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n const widthOf = (): number => trackRef.current?.getBoundingClientRect().width ?? 0;\n const msAt = (clientX: number): number => {\n const rect = trackRef.current?.getBoundingClientRect();\n if (!rect) return win.from;\n const scale = createTimeScale(win, rect.width);\n const raw = scale.toMs(clientX - rect.left);\n return Math.min(win.to, Math.max(win.from, raw));\n };\n\n // `capture: false`: the session tracks the pointer off the ruler on its own,\n // and capture would retarget pointerup and kill the click on non-native\n // children of the scrubbed track.\n const onPointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (e.button !== 0) return;\n onScrub(msAt(e.clientX));\n\n sessionRef.current?.cancel();\n const end = (): void => { sessionRef.current = null; };\n sessionRef.current = openPointerSession(e.currentTarget, e, {\n onMove: (ev) => { onScrub(msAt(ev.clientX)); },\n onEnd: end,\n onCancel: end,\n }, { capture: false });\n };\n\n const onWheel = (e: ReactWheelEvent<HTMLDivElement>): void => {\n if (e.ctrlKey) {\n onWindowChange(zoomWindow(win, msAt(e.clientX), Math.exp(e.deltaY * ZOOM_STEP), bounds));\n } else {\n const width = widthOf();\n const perPx = width === 0 ? 0 : (win.to - win.from) / width;\n onWindowChange(panWindow(win, e.deltaY * perPx, bounds));\n }\n };\n\n const ticks = tickTimes(win, width, TICK_SPACING_PX);\n const pct = (ms: number): string => toPercent(win, ms);\n\n return (\n <div\n className={s.ruler}\n ref={trackRef}\n data-testid=\"timeline-ruler\"\n onPointerDown={onPointerDown}\n onWheel={onWheel}\n >\n {ticks.map((t) => (\n <span\n key={t}\n className={s.tick}\n data-testid=\"timeline-tick\"\n style={{ left: pct(t) }}\n >\n {formatMs(t)}\n </span>\n ))}\n <div\n className={s.playhead}\n data-testid=\"timeline-playhead\"\n style={{ left: pct(playhead) }}\n />\n </div>\n );\n}\n","import type { ReactElement } from 'react';\nimport { DetentSlider } from '../DetentSlider';\nimport { PauseIcon, PlayIcon } from '../../icons';\nimport s from './Timeline.module.css';\n\n/** Playback rates the transport offers. */\nconst RATES = [0.25, 0.5, 1, 2, 4] as const;\n\nexport interface TransportProps {\n paused: boolean;\n loop: boolean | number;\n rate: number;\n playhead: number;\n duration: number;\n onPlay: () => void;\n onPause: () => void;\n onLoopChange: (loop: boolean | number) => void;\n onRateChange: (rate: number) => void;\n}\n\nconst seconds = (ms: number): string => `${(ms / 1000).toFixed(2)}s`;\n\nexport function Transport(props: TransportProps): ReactElement {\n const { paused, loop, rate, playhead, duration, onPlay, onPause, onLoopChange, onRateChange } = props;\n const looping = loop !== false && loop !== 0;\n // The handle's scale is whatever anything holding it set, so an off-list rate\n // gets its own detent — `DetentSlider` would otherwise round it to the\n // nearest and label the thumb with a rate the timeline is not running at.\n const rates = RATES.includes(rate as typeof RATES[number])\n ? (RATES as readonly number[])\n : [...RATES, rate].sort((a, b) => a - b);\n\n return (\n <div className={s.transport}>\n <button\n type=\"button\"\n className={s.transportButton}\n aria-label={paused ? 'Play' : 'Pause'}\n onClick={paused ? onPlay : onPause}\n >\n {paused ? <PlayIcon size={14} /> : <PauseIcon size={14} />}\n </button>\n\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={looping}\n aria-label=\"Loop\"\n className={s.transportButton}\n onClick={() => onLoopChange(!looping)}\n >\n ⟲\n </button>\n\n <div className={s.rate}>\n Rate\n <DetentSlider\n ariaLabel=\"Rate\"\n items={rates}\n value={rate}\n onChange={onRateChange}\n formatLabel={(r) => `${r}x`}\n labels=\"none\"\n className={s.rateSlider}\n />\n <span className={s.rateReadout}>{rate}x</span>\n </div>\n\n <span className={s.time} data-testid=\"timeline-time\">\n {seconds(playhead)} / {seconds(duration)}\n </span>\n </div>\n );\n}\n","import type { SampledTrack, Track } from '@weasel-js/core';\n\nexport interface LaneRow {\n /** Stable across re-renders and edits: the dotted index path. */\n key: string;\n /** Index path into the track tree, outermost first. */\n path: number[];\n track: Track;\n label: string;\n /** Nesting depth; 0 for a top-level track. */\n depth: number;\n /** Accumulated `at` from every nested parent, in ms. A key drawn on this row\n * sits at `offset + key.t` on the ruler. */\n offset: number;\n kind: Track['kind'];\n /** True only for a sampled track whose every key value is a number — the\n * sole case where a value axis has an honest meaning. */\n numeric: boolean;\n}\n\nfunction isNumeric(track: Track): boolean {\n if (track.kind !== 'sampled') return false;\n const keys = (track as SampledTrack<unknown>).keys;\n return keys.length > 0 && keys.every((k) => typeof k.value === 'number');\n}\n\n/** Flatten the track tree to rows, descending only into expanded nested\n * timelines. `expanded` holds the `key` of each open nested row. */\nexport function buildLanes(\n tracks: readonly Track[],\n expanded: ReadonlySet<string>,\n): LaneRow[] {\n const out: LaneRow[] = [];\n const walk = (list: readonly Track[], path: number[], depth: number, offset: number): void => {\n list.forEach((track, i) => {\n const nextPath = [...path, i];\n const key = nextPath.join('.');\n out.push({\n key,\n path: nextPath,\n track,\n label: track.label ?? `${track.kind} ${i}`,\n depth,\n offset,\n kind: track.kind,\n numeric: isNumeric(track),\n });\n if (track.kind === 'timeline' && expanded.has(key)) {\n walk(track.timeline.tracks, nextPath, depth + 1, offset + track.at);\n }\n });\n };\n walk(tracks, [], 0, 0);\n return out;\n}\n\n/** The track at an index path, or `undefined` when the path leaves the tree. */\nexport function trackAtPath(tracks: readonly Track[], path: readonly number[]): Track | undefined {\n let list: readonly Track[] = tracks;\n let found: Track | undefined;\n for (const i of path) {\n found = list[i];\n if (!found) return undefined;\n list = found.kind === 'timeline' ? found.timeline.tracks : [];\n }\n return found;\n}\n","import { sampleTrack, type EasingSpec, type EventTrack, type Keyframe, type SampledTrack, type TimelineTrack, type Track } from '@weasel-js/core';\nimport { trackAtPath } from './lanes';\n\nexport interface KeySelection {\n /** Index path into the track tree, outermost first — a `LaneRow.path`. A\n * top-level track is `[i]`; a track inside the nested timeline at `i` is\n * `[i, j]`. */\n trackPath: readonly number[];\n keyIndex: number;\n}\n\nexport interface KeyEdit {\n tracks: Track[];\n selection: KeySelection | null;\n}\n\n/** True when two index paths address the same track. */\nexport function samePath(a: readonly number[], b: readonly number[]): boolean {\n return a.length === b.length && a.every((n, i) => n === b[i]);\n}\n\n/** Shallow-clone one track, replacing only its key list. `onTick`, `fire`,\n * `interpolate` and `interpolator` survive as references, which is what lets a\n * running timeline take an edited track without rewiring. */\nfunction withKeys(track: Track, keys: Keyframe<unknown>[]): Track {\n return { ...(track as SampledTrack<unknown>), keys } as Track;\n}\n\nfunction withEvents(track: Track, events: EventTrack['events']): Track {\n return { ...(track as EventTrack), events } as Track;\n}\n\n/** Replace the track at `path`, cloning the timeline tracks along the way so\n * the caller's tree is untouched at every level, not just the top. */\nfunction replaceAtPath(tracks: readonly Track[], path: readonly number[], next: Track): Track[] {\n const out = tracks.slice();\n const [i, ...rest] = path;\n if (rest.length === 0) {\n out[i] = next;\n return out;\n }\n const parent = out[i];\n if (parent?.kind !== 'timeline') return out;\n const tt = parent as TimelineTrack;\n out[i] = {\n ...tt,\n timeline: { ...tt.timeline, tracks: replaceAtPath(tt.timeline.tracks, rest, next) },\n };\n return out;\n}\n\n/** Move a key or an event crossing to `toMs`, clamped at zero. `toMs` is in the\n * addressed track's own time, not the ruler's — a nested track's keys are\n * measured from its parent's `at`.\n *\n * Re-sorts, and reports the moved entry's new index. `sampleTrack` binary-\n * searches without sorting first, so a drag past a neighbour that left the list\n * unsorted would sample the wrong segment and raise nothing. */\nexport function moveKey(\n tracks: readonly Track[], sel: KeySelection, toMs: number,\n): KeyEdit {\n const track = trackAtPath(tracks, sel.trackPath);\n const t = Math.max(0, toMs);\n\n if (track?.kind === 'sampled') {\n const st = track as SampledTrack<unknown>;\n const moved = { ...st.keys[sel.keyIndex], t };\n const keys = st.keys.filter((_, i) => i !== sel.keyIndex);\n const at = keys.findIndex((k) => k.t > t);\n const keyIndex = at === -1 ? keys.length : at;\n keys.splice(keyIndex, 0, moved);\n return {\n tracks: replaceAtPath(tracks, sel.trackPath, withKeys(track, keys)),\n selection: { trackPath: sel.trackPath, keyIndex },\n };\n }\n\n if (track?.kind === 'event') {\n const et = track as EventTrack;\n const moved = { ...et.events[sel.keyIndex], t };\n const events = et.events.filter((_, i) => i !== sel.keyIndex);\n const at = events.findIndex((e) => e.t > t);\n const keyIndex = at === -1 ? events.length : at;\n events.splice(keyIndex, 0, moved);\n return {\n tracks: replaceAtPath(tracks, sel.trackPath, withEvents(track, events)),\n selection: { trackPath: sel.trackPath, keyIndex },\n };\n }\n\n return { tracks: tracks.slice(), selection: sel };\n}\n\n/** Insert a key at `atMs`, seeded with whatever the track already reads there\n * so inserting alone never changes the motion. */\nexport function insertKey(\n tracks: readonly Track[], trackPath: readonly number[], atMs: number,\n): KeyEdit {\n const track = trackAtPath(tracks, trackPath);\n if (track?.kind !== 'sampled') return { tracks: tracks.slice(), selection: null };\n\n const st = track as SampledTrack<unknown>;\n const t = Math.max(0, atMs);\n const value = st.keys.length === 0 ? 0 : sampleTrack(st, t);\n const keys = st.keys.slice();\n const at = keys.findIndex((k) => k.t > t);\n const keyIndex = at === -1 ? keys.length : at;\n keys.splice(keyIndex, 0, { t, value });\n return {\n tracks: replaceAtPath(tracks, trackPath, withKeys(track, keys)),\n selection: { trackPath, keyIndex },\n };\n}\n\n/** Remove a key, selecting the one before it. */\nexport function deleteKey(tracks: readonly Track[], sel: KeySelection): KeyEdit {\n const track = trackAtPath(tracks, sel.trackPath);\n if (track?.kind !== 'sampled') return { tracks: tracks.slice(), selection: sel };\n\n const st = track as SampledTrack<unknown>;\n const keys = st.keys.filter((_, i) => i !== sel.keyIndex);\n return {\n tracks: replaceAtPath(tracks, sel.trackPath, withKeys(track, keys)),\n selection: keys.length === 0\n ? null\n : { trackPath: sel.trackPath, keyIndex: Math.max(0, sel.keyIndex - 1) },\n };\n}\n\n/** Set the easing shaping the approach INTO the selected key. */\nexport function setKeyEasing(\n tracks: readonly Track[], sel: KeySelection, easing: EasingSpec | undefined,\n): Track[] {\n const track = trackAtPath(tracks, sel.trackPath);\n if (track?.kind !== 'sampled') return tracks.slice();\n\n const st = track as SampledTrack<unknown>;\n const keys = st.keys.slice();\n const { easing: _drop, ...rest } = keys[sel.keyIndex];\n keys[sel.keyIndex] = easing === undefined ? rest : { ...rest, easing };\n return replaceAtPath(tracks, sel.trackPath, withKeys(track, keys));\n}\n\n/** Replace a sampled track's whole key list, keeping its callbacks. */\nexport function setKeys(\n tracks: readonly Track[], trackPath: readonly number[], keys: readonly Keyframe<unknown>[],\n): Track[] {\n const track = trackAtPath(tracks, trackPath);\n if (track?.kind !== 'sampled') return tracks.slice();\n return replaceAtPath(tracks, trackPath, withKeys(track, keys.slice()));\n}\n\n/** Set the selected key's value, leaving its time alone. */\nexport function setKeyValue(\n tracks: readonly Track[], sel: KeySelection, value: unknown,\n): Track[] {\n const track = trackAtPath(tracks, sel.trackPath);\n if (track?.kind !== 'sampled') return tracks.slice();\n\n const st = track as SampledTrack<unknown>;\n const keys = st.keys.slice();\n keys[sel.keyIndex] = { ...keys[sel.keyIndex], value };\n return replaceAtPath(tracks, sel.trackPath, withKeys(track, keys));\n}\n\nexport { snapToNearest as snapTime } from '../../snap';\n","import { useMemo, useState, type KeyboardEvent as ReactKeyboardEvent, type ReactElement, type ReactNode } from 'react';\nimport type { EasingSpec, Keyframe, SampledTrack, Track } from '@weasel-js/core';\nimport s from './Timeline.module.css';\nimport { EasingPicker } from './EasingPicker';\nimport { Lane } from './Lane';\nimport { Ruler } from './Ruler';\nimport { Transport, type TransportProps } from './Transport';\nimport { buildLanes, trackAtPath } from './lanes';\nimport { deleteKey, insertKey, moveKey, samePath, setKeyEasing, setKeys, setKeyValue, type KeySelection } from './keys';\nimport type { TimeWindow } from './timeScale';\n\nexport type { KeySelection } from './keys';\nexport type { TimeWindow } from './timeScale';\n\nexport interface KeyEditorCtx<T = unknown> {\n key: Keyframe<T>;\n track: SampledTrack<T>;\n selection: KeySelection;\n /** Replace the selected key; routed through this component's `onChange`. */\n commit: (next: Keyframe<T>) => void;\n /** Set the easing shaping the approach into this key. */\n setEasing: (easing: EasingSpec | undefined) => void;\n}\n\nexport interface TimelineProps {\n tracks: readonly Track[];\n duration: number;\n playhead: number;\n\n mode?: 'dope' | 'graph';\n onModeChange?: (mode: 'dope' | 'graph') => void;\n\n /** Live during a drag — wire for preview, do not write to history. */\n onInput?: (next: Track[]) => void;\n /** Committed at gesture end: one call per gesture. */\n onChange: (next: Track[]) => void;\n onScrub: (t: number) => void;\n\n /** `false` hides the transport. */\n transport?: Omit<TransportProps, 'playhead' | 'duration'> | false;\n selection?: KeySelection | null;\n onSelect?: (sel: KeySelection | null) => void;\n renderKeyEditor?: (ctx: KeyEditorCtx) => ReactNode;\n\n window?: TimeWindow;\n onWindowChange?: (w: TimeWindow) => void;\n\n label?: ReactNode;\n className?: string;\n}\n\nexport function Timeline(props: TimelineProps): ReactElement {\n const {\n tracks, duration, playhead,\n onInput, onChange, onScrub,\n renderKeyEditor, label, className,\n } = props;\n\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(() => new Set());\n const [ownWindow, setOwnWindow] = useState<TimeWindow>({ from: 0, to: duration });\n const [ownSelection, setOwnSelection] = useState<KeySelection | null>(null);\n const [segmentSelection, setSegmentSelection] = useState<KeySelection | null>(null);\n\n const win = props.window ?? ownWindow;\n const setWindow = props.onWindowChange ?? setOwnWindow;\n const selection = props.selection !== undefined ? props.selection : ownSelection;\n const setSelection = props.onSelect ?? setOwnSelection;\n\n const bounds: TimeWindow = { from: 0, to: duration };\n const rows = useMemo(() => buildLanes(tracks, expanded), [tracks, expanded]);\n\n /** Every key time on every row — what a dragged key snaps to. */\n const snapTimes = useMemo(() => {\n const out = new Set<number>([0, duration]);\n for (const row of rows) {\n if (row.kind === 'sampled') for (const k of (row.track as SampledTrack<unknown>).keys) out.add(k.t + row.offset);\n }\n return [...out];\n }, [rows, duration]);\n\n const toggle = (key: string): void => {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(key)) next.delete(key); else next.add(key);\n return next;\n });\n };\n\n const onRootKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>): void => {\n if ((e.key === 'Delete' || e.key === 'Backspace') && selection) {\n e.preventDefault();\n const r = deleteKey(tracks, selection);\n onChange(r.tracks);\n setSelection(r.selection);\n }\n };\n\n const selectedTrack = selection ? trackAtPath(tracks, selection.trackPath) : undefined;\n const selectedKey = selectedTrack?.kind === 'sampled'\n ? (selectedTrack as SampledTrack<unknown>).keys[selection!.keyIndex]\n : undefined;\n\n const segmentTrack = segmentSelection ? trackAtPath(tracks, segmentSelection.trackPath) : undefined;\n const segmentKey = segmentTrack?.kind === 'sampled'\n ? (segmentTrack as SampledTrack<unknown>).keys[segmentSelection!.keyIndex]\n : undefined;\n\n return (\n <div\n className={[s.root, className].filter(Boolean).join(' ')}\n data-testid=\"timeline-root\"\n tabIndex={-1}\n onKeyDown={onRootKeyDown}\n >\n {label ? <div className={s.label}>{label}</div> : null}\n\n {props.transport === false ? null : (\n <div className={s.transportRow}>\n <Transport\n {...(props.transport ?? {\n paused: true, loop: false, rate: 1,\n onPlay: () => {}, onPause: () => {},\n onLoopChange: () => {}, onRateChange: () => {},\n })}\n playhead={playhead}\n duration={duration}\n />\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={(props.mode ?? 'dope') === 'graph'}\n aria-label=\"Graph mode\"\n className={s.transportButton}\n onClick={() => props.onModeChange?.((props.mode ?? 'dope') === 'graph' ? 'dope' : 'graph')}\n >\n Graph\n </button>\n </div>\n )}\n\n <div className={s.body}>\n <div className={s.gutter} />\n <div className={s.rulerWrap}>\n <Ruler\n window={win}\n bounds={bounds}\n playhead={playhead}\n onScrub={onScrub}\n onWindowChange={setWindow}\n />\n </div>\n </div>\n\n <div className={s.lanes}>\n {rows.map((row) => {\n const trackPath = row.path;\n return (\n <Lane\n key={row.key}\n row={row}\n window={win}\n mode={props.mode ?? 'dope'}\n selection={selection && samePath(selection.trackPath, trackPath) ? selection.keyIndex : null}\n expanded={expanded.has(row.key)}\n snapTimes={snapTimes}\n onToggleExpand={() => toggle(row.key)}\n onSelect={(keyIndex) => setSelection({ trackPath, keyIndex })}\n onKeyInput={(keyIndex, toMs) => {\n onInput?.(moveKey(tracks, { trackPath, keyIndex }, toMs).tracks);\n }}\n onKeyCommit={(keyIndex, toMs) => {\n const r = moveKey(tracks, { trackPath, keyIndex }, toMs);\n onChange(r.tracks);\n setSelection(r.selection);\n }}\n onKeysInput={(keys) => onInput?.(setKeys(tracks, trackPath, keys))}\n onKeysCommit={(keys) => onChange(setKeys(tracks, trackPath, keys))}\n onInsert={(atMs) => {\n const r = insertKey(tracks, trackPath, atMs);\n onChange(r.tracks);\n setSelection(r.selection);\n }}\n selectedSegment={segmentSelection && samePath(segmentSelection.trackPath, trackPath) ? segmentSelection.keyIndex : null}\n onSelectSegment={(keyIndex) => setSegmentSelection({ trackPath, keyIndex })}\n />\n );\n })}\n </div>\n\n {renderKeyEditor && selection && selectedKey && selectedTrack?.kind === 'sampled' ? (\n <div className={s.inspector}>\n {renderKeyEditor({\n key: selectedKey,\n track: selectedTrack as SampledTrack<unknown>,\n selection,\n commit: (next) => onChange(setKeyValue(tracks, selection, next.value)),\n setEasing: (easing) => onChange(setKeyEasing(tracks, selection, easing)),\n })}\n </div>\n ) : null}\n\n {segmentSelection && segmentKey ? (\n <div className={s.inspector}>\n <EasingPicker\n value={segmentKey.easing}\n onChange={(next) => onChange(setKeyEasing(tracks, segmentSelection, next))}\n />\n </div>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useEffect, useReducer, useRef, type ReactElement } from 'react';\nimport { useVisibleRaf, type TimelineHandle, type Track } from '@weasel-js/core';\nimport { Timeline, type TimelineProps } from './Timeline';\n\nexport interface AnimatedTimelineProps\n extends Omit<TimelineProps, 'tracks' | 'duration' | 'playhead' | 'onChange' | 'onScrub' | 'transport'> {\n handle: TimelineHandle;\n /** `false` hides the transport, as on `<Timeline>`. */\n transport?: false;\n}\n\n/** Binds `<Timeline>` to a live handle.\n *\n * `handle.tracks()` returns the timeline's own array, not a copy, so an edit\n * splices it in place inside `edit()`. Assigning a replacement array would\n * update nothing and raise nothing. */\nexport function AnimatedTimeline(props: AnimatedTimelineProps): ReactElement {\n const { handle, ...rest } = props;\n const [, bump] = useReducer((n: number) => n + 1, 0);\n\n // `subscribe` fires on `edit` only, so the playhead comes from the frame loop.\n useEffect(() => handle.subscribe(bump), [handle]);\n\n // `useVisibleRaf` returns a controller; a continuous loop re-requests from\n // inside its own frame, and nothing runs until something calls `request`.\n // No `onResume` here: this loop measures no elapsed time of its own, it only\n // reads the playhead the animator already advanced.\n const rafRef = useRef<{ request(): void } | null>(null);\n const raf = useVisibleRaf(() => {\n bump();\n if (!handle.isPaused()) rafRef.current?.request();\n });\n rafRef.current = raf;\n useEffect(() => {\n if (!handle.isPaused()) raf.request();\n return () => raf.cancel();\n }, [handle, raf]);\n\n const onChange = useCallback((next: Track[]) => {\n handle.edit(() => {\n const live = handle.tracks() as Track[];\n live.splice(0, live.length, ...next);\n });\n }, [handle]);\n\n const playhead = handle.time();\n const duration = handle.duration();\n\n return (\n <Timeline\n {...rest}\n tracks={handle.tracks()}\n duration={duration}\n playhead={playhead}\n onChange={onChange}\n onScrub={handle.seek}\n transport={props.transport === false ? false : {\n paused: handle.isPaused(),\n loop: handle.loop(),\n rate: handle.timeScale(),\n onPlay: () => {\n // `rearm` declines to revive a timeline at its duration, so resume\n // alone would do nothing. Play-at-end rewinds first.\n if (handle.time() >= duration) handle.seek(0);\n handle.resume();\n raf.request();\n bump();\n },\n onPause: () => { handle.pause(); bump(); },\n onLoopChange: (next) => { handle.setLoop(next); bump(); },\n onRateChange: (next) => { handle.setTimeScale(next); bump(); },\n }}\n />\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Toast-DNBb-24H.js","names":["toast","s","RACToastRegion","RACToast","RACToastContent","DEFAULT_TTL_MS","activeToastTransitions","viewTransitionWrapUpdate","reduceMotion","root","vt","flushSync","fn","RAC_QUEUES","ToastQueue","UNSTABLE_ToastQueue","options","rac","id","existing","key","racOptions","ttlMs","createToastQueue","racQueueOf","queue","defaultToastQueue","tonedAdd","tone","title","toast$1","Toast_module_default","placementClass","toneClass","ToastRegion","props","UNSTABLE_ToastRegion","placement","className","t","UNSTABLE_Toast","UNSTABLE_ToastContent","Text","Button"],"sources":["../../src/components/Toast/queue.ts","../../src/components/Toast/Toast.module.css","../../src/components/Toast/Toast.tsx"],"sourcesContent":["import { UNSTABLE_ToastQueue } from 'react-aria-components';\nimport { flushSync } from 'react-dom';\n\n/** Severity of a toast, driving its accent color and icon. */\nexport type ToastTone = 'info' | 'success' | 'warning' | 'error';\n\n/** Kit-owned payload rendered inside each toast. */\nexport interface ToastContent {\n title: string;\n description?: string;\n tone: ToastTone;\n}\n\n/** Options for a single toast. */\nexport interface ToastOptions {\n description?: string;\n /**\n * Auto-dismiss delay in ms. Default 8000. `null` — sticky until dismissed.\n * Must be > 0; RAC treats 0 as no timer (sticky).\n */\n ttlMs?: number | null;\n /** Stable identity: re-adding with the same id replaces the earlier toast. */\n id?: string;\n}\n\nconst DEFAULT_TTL_MS = 8000;\n\n// Tracks overlapping toast-triggered view transitions so the `:root`\n// marker class survives until the *last* one settles.\nlet activeToastTransitions = 0;\n\n/**\n * RAC's sanctioned toast-animation hook: wrap every queue mutation in a\n * view transition so entry, exit, and the surviving stack's reflow all\n * animate (choreography lives in `toastViewTransitions.css`). Falls back\n * to a plain synchronous update when the browser lacks the API or the\n * user prefers reduced motion — i.e. exactly the pre-animation behavior.\n * The jsdom test environment always takes the fallback path.\n */\nfunction viewTransitionWrapUpdate(fn: () => void): void {\n const reduceMotion =\n typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (typeof document === 'undefined' || !('startViewTransition' in document) || reduceMotion) {\n fn();\n return;\n }\n // The marker class scopes the CSS that un-names `:root` (keeps the rest\n // of the page live and interactive during the transition) to\n // toast-owned transitions only.\n const root = document.documentElement;\n activeToastTransitions++;\n root.classList.add('wzl-toast-vt');\n // flushSync: the DOM must reflect the queue change inside the\n // transition callback, before the browser snapshots the new state.\n const vt = document.startViewTransition(() => flushSync(fn));\n // `ready` rejects when the browser skips the transition — routine under\n // a rapid burst of toasts, where each new transition supersedes the\n // in-flight one. The DOM update has still applied by then, but an\n // untouched `ready` surfaces the rejection as a console error, so\n // consume it.\n vt.ready.catch(() => {});\n void vt.finished.finally(() => {\n if (--activeToastTransitions === 0) root.classList.remove('wzl-toast-vt');\n });\n}\n\n// The wrapped RAC queue lives in a module-scoped WeakMap so the public\n// class surface carries no RAC (UNSTABLE_) types — see the design spec's\n// containment rule. `racQueueOf` below is the folder-internal accessor.\nconst RAC_QUEUES = new WeakMap<ToastQueue, UNSTABLE_ToastQueue<ToastContent>>();\n\n/**\n * Kit-owned toast queue. Create isolated instances with\n * `createToastQueue()` (tests, secondary roots); most apps use the\n * module-level `defaultToastQueue` via `toast()`.\n *\n * At most 5 toasts are visible at once; adding a 6th shows immediately\n * and hides the oldest (it returns when a slot frees, with its ttl\n * restarted).\n */\nexport class ToastQueue {\n private keysById = new Map<string, string>();\n\n constructor() {\n RAC_QUEUES.set(\n this,\n new UNSTABLE_ToastQueue<ToastContent>({\n maxVisibleToasts: 5,\n wrapUpdate: viewTransitionWrapUpdate,\n }),\n );\n }\n\n add(tone: ToastTone, title: string, options: ToastOptions = {}): void {\n const { description, ttlMs = DEFAULT_TTL_MS, id } = options;\n const rac = RAC_QUEUES.get(this)!;\n if (id !== undefined) {\n const existing = this.keysById.get(id);\n if (existing !== undefined) rac.close(existing);\n }\n let key: string;\n const racOptions: { timeout?: number; onClose?: () => void } =\n ttlMs === null ? {} : { timeout: ttlMs };\n if (id !== undefined) {\n racOptions.onClose = () => {\n if (this.keysById.get(id) === key) this.keysById.delete(id);\n };\n }\n key = rac.add({ title, description, tone }, racOptions);\n if (id !== undefined) this.keysById.set(id, key);\n }\n\n /** Dismiss the toast previously added with this `id`. No-op if none is live. */\n dismiss(id: string): void {\n const key = this.keysById.get(id);\n if (key !== undefined) RAC_QUEUES.get(this)!.close(key);\n }\n\n /** Dismiss every queued toast. */\n clear(): void {\n RAC_QUEUES.get(this)!.clear();\n this.keysById.clear();\n }\n}\n\n/**\n * Creates an independent toast queue. Most apps use the module-level\n * `defaultToastQueue` that `toast()` writes to; make your own when a surface\n * needs its own stack, and pass it to `ToastRegion`.\n */\nexport function createToastQueue(): ToastQueue {\n return new ToastQueue();\n}\n\n/**\n * Folder-internal bridge to the wrapped RAC queue for `ToastRegion`.\n * Deliberately NOT exported from the Toast folder's `index.ts` — the\n * RAC toast surface is unstable and must not leak past this folder.\n */\nexport function racQueueOf(queue: ToastQueue): UNSTABLE_ToastQueue<ToastContent> {\n return RAC_QUEUES.get(queue)!;\n}\n\n/** Module-level default queue used by `toast()` and `<ToastRegion>`. */\nexport const defaultToastQueue = createToastQueue();\n\ntype ToastFn = {\n (title: string, options?: ToastOptions): void;\n info(title: string, options?: ToastOptions): void;\n success(title: string, options?: ToastOptions): void;\n warning(title: string, options?: ToastOptions): void;\n error(title: string, options?: ToastOptions): void;\n};\n\nfunction tonedAdd(tone: ToastTone) {\n return (title: string, options?: ToastOptions) => defaultToastQueue.add(tone, title, options);\n}\n\n/** Imperative convenience over `defaultToastQueue`. Bare `toast(...)` is `info`. */\nexport const toast: ToastFn = Object.assign(tonedAdd('info'), {\n info: tonedAdd('info'),\n success: tonedAdd('success'),\n warning: tonedAdd('warning'),\n error: tonedAdd('error'),\n});\n",".region {\n position: fixed;\n z-index: 1100;\n display: flex;\n /* RAC unshifts new toasts to the front of the DOM (newest-first), and the\n * ol/li wrappers are display:contents, so the flex direction alone\n * decides which end of the stack the newest toast lands on. Base\n * (bottom corners): column-reverse puts DOM-first (newest) at the\n * bottom, hugging the corner. Top corners override back to column so\n * DOM-first still hugs the top edge. */\n flex-direction: column-reverse;\n gap: var(--wzl-space-4);\n max-width: 360px;\n outline: none;\n}\n\n.bottomRight { bottom: 16px; right: 16px; }\n.bottomLeft { bottom: 16px; left: 16px; }\n.topRight { top: 16px; right: 16px; flex-direction: column; }\n.topLeft { top: 16px; left: 16px; flex-direction: column; }\n\n.toast {\n --toast-accent: var(--wzl-accent-strong);\n /* Groups every toast under one ident so toastViewTransitions.css can\n * target `::view-transition-new/old(.wzl-toast)` without knowing the\n * per-toast view-transition-name (set inline in Toast.tsx). */\n view-transition-class: wzl-toast;\n display: flex;\n align-items: flex-start;\n gap: var(--wzl-space-4);\n background: var(--wzl-surface);\n border: 1px solid var(--wzl-border);\n border-left: 3px solid var(--toast-accent);\n border-radius: var(--wzl-radius-md);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);\n color: var(--wzl-fg);\n font-family: var(--wzl-font-ui);\n padding: var(--wzl-space-5) var(--wzl-space-6);\n outline: none;\n}\n\n.region[data-focus-visible],\n.toast[data-focus-visible] {\n outline: 2px solid var(--wzl-focus-ring);\n outline-offset: 1px;\n}\n\n.toneInfo { /* default accent — uses --toast-accent fallback */ }\n.toneSuccess { --toast-accent: var(--wzl-success, #2ec27e); }\n.toneWarning { --toast-accent: var(--wzl-warning, #d99a3f); }\n.toneError { --toast-accent: var(--wzl-danger); }\n\n.content {\n flex: 1;\n min-width: 0;\n}\n\n.title {\n display: block;\n font-size: var(--wzl-font-size);\n font-weight: var(--wzl-font-weight-bold);\n}\n\n.description {\n display: block;\n margin-top: var(--wzl-space-1);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-muted);\n}\n\n.close {\n flex: 0 0 auto;\n background: none;\n border: none;\n color: var(--wzl-fg-muted);\n font-size: var(--wzl-font-size-lg);\n line-height: 1;\n padding: var(--wzl-space-1) var(--wzl-space-2);\n cursor: pointer;\n border-radius: var(--wzl-radius-sm);\n}\n\n.close:hover {\n color: var(--wzl-fg);\n}\n","import {\n UNSTABLE_ToastRegion as RACToastRegion,\n UNSTABLE_Toast as RACToast,\n UNSTABLE_ToastContent as RACToastContent,\n Text,\n Button,\n} from 'react-aria-components';\nimport { defaultToastQueue, racQueueOf, type ToastQueue, type ToastTone } from './queue';\nimport s from './Toast.module.css';\nimport './toastViewTransitions.css';\n\n/** Screen corner a toast stack anchors to. */\nexport type ToastPlacement = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';\n\n/** Props for {@link ToastRegion}. */\nexport interface ToastRegionProps {\n /** Queue to render. Defaults to the module-level `defaultToastQueue`. */\n queue?: ToastQueue;\n /** Screen corner for the stack. Default `bottom-right`. */\n placement?: ToastPlacement;\n className?: string;\n}\n\nconst placementClass: Record<ToastPlacement, string> = {\n 'bottom-right': s.bottomRight,\n 'bottom-left': s.bottomLeft,\n 'top-right': s.topRight,\n 'top-left': s.topLeft,\n};\n\nconst toneClass: Record<ToastTone, string> = {\n info: s.toneInfo,\n success: s.toneSuccess,\n warning: s.toneWarning,\n error: s.toneError,\n};\n\n/**\n * Renders the toast stack for a queue. Mount once, near the app root.\n * From the underlying React Aria region: landmark semantics (keyboard /\n * F6 reachable), screen-reader announcements, and hover pausing the\n * auto-dismiss timers.\n */\nexport function ToastRegion(props: ToastRegionProps) {\n const { queue = defaultToastQueue, placement = 'bottom-right', className } = props;\n return (\n <RACToastRegion\n queue={racQueueOf(queue)}\n aria-label=\"Notifications\"\n className={[s.region, placementClass[placement], className].filter(Boolean).join(' ')}\n >\n {({ toast: t }) => (\n <RACToast\n toast={t}\n className={[s.toast, toneClass[t.content.tone]].filter(Boolean).join(' ')}\n // Inline style is the one sanctioned exception here: each toast\n // needs a *unique* view-transition-name (so enter/exit/reflow\n // track per-toast), and a class can't mint unique idents. The\n // prefix keeps the ident valid (RAC keys can start with digits).\n style={{ viewTransitionName: `wzl-toast-${t.key.replace(/[^a-zA-Z0-9_-]/g, '_')}` }}\n >\n <RACToastContent className={s.content}>\n <Text slot=\"title\" className={s.title}>{t.content.title}</Text>\n {t.content.description !== undefined && (\n <Text slot=\"description\" className={s.description}>{t.content.description}</Text>\n )}\n </RACToastContent>\n <Button slot=\"close\" className={s.close} aria-label=\"Dismiss notification\">\n ×\n </Button>\n </RACToast>\n )}\n </RACToastRegion>\n );\n}\n"],"mappings":";;;;AAyBA,IAAMK,IAAiB,KAInBC,IAAyB;AAU7B,SAASC,EAAyB,GAAsB;CACtD,IAAMC,IACJ,OAAO,cAAe,cAAc,WAAW,kCAAkC,CAAC,CAAC;CACrF,IAAI,OAAO,WAAa,OAAe,EAAE,yBAAyB,aAAaA,GAAc;EAC3F,EAAG;EACH;CACF;CAIA,IAAMC,IAAO,SAAS;CAEtB,AADA,KACAA,EAAK,UAAU,IAAI,cAAc;CAGjC,IAAMC,IAAK,SAAS,0BAA0BC,EAAUC,CAAE,CAAC;CAO3D,AADAF,EAAG,MAAM,YAAY,CAAC,CAAC,GACvBA,EAAQ,SAAS,cAAc;EAC7B,AAAI,EAAEJ,MAA2B,KAAGG,EAAK,UAAU,OAAO,cAAc;CAC1E,CAAC;AACH;AAKA,IAAMI,oBAAa,IAAI,QAAuD,GAWjEC,IAAb,MAAwB;CACtB,2BAAmB,IAAI,IAAoB;CAE3C,cAAc;EACZ,EAAW,IACT,MACA,IAAIC,EAAkC;GACpC,kBAAkB;GAClB,YAAYR;EACd,CAAC,CACH;CACF;CAEA,IAAI,GAAiB,GAAe,IAAwB,CAAC,GAAS;EACpE,IAAM,EAAE,gBAAa,WAAQF,GAAgB,UAAOW,GAC9CC,IAAMJ,EAAW,IAAI,IAAI;EAC/B,IAAIK,MAAO,KAAA,GAAW;GACpB,IAAMC,IAAW,KAAK,SAAS,IAAID,CAAE;GACrC,AAAIC,MAAa,KAAA,KAAWF,EAAI,MAAME,CAAQ;EAChD;EACA,IAAIC,GACEC,IACJC,MAAU,OAAO,CAAC,IAAI,EAAE,SAASA,EAAM;EAOzC,AANIJ,MAAO,KAAA,MACT,EAAW,gBAAgB;GACzB,AAAI,KAAK,SAAS,IAAIA,CAAE,MAAME,KAAK,KAAK,SAAS,OAAOF,CAAE;EAC5D,IAEF,IAAMD,EAAI,IAAI;GAAE;GAAO;GAAa;EAAK,GAAGI,CAAU,GAClDH,MAAO,KAAA,KAAW,KAAK,SAAS,IAAIA,GAAIE,CAAG;CACjD;CAGA,QAAQ,GAAkB;EACxB,IAAMA,IAAM,KAAK,SAAS,IAAIF,CAAE;EAChC,AAAIE,MAAQ,KAAA,KAAWP,EAAW,IAAI,IAAI,CAAC,CAAE,MAAMO,CAAG;CACxD;CAGA,QAAc;EAEZ,AADAP,EAAW,IAAI,IAAI,CAAC,CAAE,MAAM,GAC5B,KAAK,SAAS,MAAM;CACtB;AACF;AAOA,SAAgBU,IAA+B;CAC7C,OAAO,IAAIT,EAAW;AACxB;AAOA,SAAgBU,EAAW,GAAsD;CAC/E,OAAOX,EAAW,IAAIY,CAAK;AAC7B;AAGA,IAAaC,IAAoBH,EAAiB;AAUlD,SAASI,EAAS,GAAiB;CACjC,QAAQ,GAAe,MAA2BD,EAAkB,IAAIE,GAAMC,GAAOb,CAAO;AAC9F;AAGA,IAAahB,IAAiB,OAAO,OAAO2B,EAAS,MAAM,GAAG;CAC5D,MAAMA,EAAS,MAAM;CACrB,SAASA,EAAS,SAAS;CAC3B,SAASA,EAAS,SAAS;CAC3B,OAAOA,EAAS,OAAO;AACzB,CAAC;;;;;;;;;;;;;;;GE7IKK,IAAiD;CACrD,gBAAgB/B,EAAE;CAClB,eAAeA,EAAE;CACjB,aAAaA,EAAE;CACf,YAAYA,EAAE;AAChB,GAEMgC,IAAuC;CAC3C,MAAMhC,EAAE;CACR,SAASA,EAAE;CACX,SAASA,EAAE;CACX,OAAOA,EAAE;AACX;AAQA,SAAgBiC,EAAY,GAAyB;CACnD,IAAM,EAAE,WAAQR,GAAmB,eAAY,gBAAgB,iBAAcS;CAC7E,OACE,kBAACjC,GAAD;EACE,OAAOsB,EAAWC,CAAK;EACvB,cAAW;EACX,WAAW;GAACxB,EAAE;GAAQ+B,EAAeK;GAAYC;EAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAElF,WAAA,EAAE,OAAOC,QACT,kBAACpC,GAAD;GACE,OAAOoC;GACP,WAAW,CAACtC,EAAE,OAAOgC,EAAUM,EAAE,QAAQ,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;GAKxE,OAAO,EAAE,oBAAoB,aAAaA,EAAE,IAAI,QAAQ,mBAAmB,GAAG,IAAI;GAPpF,UAAA,CASE,kBAACnC,GAAD;IAAiB,WAAWH,EAAE;IAA9B,UAAA,CACE,kBAACyC,GAAD;KAAM,MAAK;KAAQ,WAAWzC,EAAE;KAAQ,UAAAsC,EAAE,QAAQ;IAAY,CAAA,GAC7DA,EAAE,QAAQ,gBAAgB,KAAA,KACzB,kBAACG,GAAD;KAAM,MAAK;KAAc,WAAWzC,EAAE;KAAc,UAAAsC,EAAE,QAAQ;IAAkB,CAAA,CAEnE;GACjB,CAAA,GAAA,kBAACI,GAAD;IAAQ,MAAK;IAAQ,WAAW1C,EAAE;IAAO,cAAW;IAAuB,UAAA;GAEnE,CAAA,CACA;;CAEE,CAAA;AAEpB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ToggleBar-DTjGeS0Q.js","names":["s","segmentTooltipContent","useRovingTabIndex","ToggleBar_module_default","ToggleBar","props","mode","isSelected","value","isMixed","mixed","handleClick","item","items","index","current","next","v","selectedIndex","it","roving","style","height","rootCls","size","variant","className","ariaLabel","selected","cls","SegmentTooltip","i"],"sources":["../../src/components/ToggleBar/ToggleBar.module.css","../../src/components/ToggleBar/ToggleBar.tsx"],"sourcesContent":["/* Aqua-glass segmented control. The track is a pill-shaped well; the\n selected segment becomes a tinted glass cylinder that reads as the same\n \"lozenge\" family as the standalone Button. Visual params come from the\n `--btn-*` custom properties (see Button.module.css) so the Button Lab\n can tune both surfaces with one set of sliders. */\n.root {\n display: inline-flex;\n height: var(--tb-h, var(--wzl-control-h, 24px));\n padding: var(--wzl-space-1);\n background: linear-gradient(\n 180deg,\n rgba(0, 0, 0, 0.18) 0%,\n rgba(0, 0, 0, 0.05) 100%\n );\n border-radius: var(--wzl-radius-pill);\n /* Clip segments to the track outline so interior corners read crisp and\n the selected segment's glass treatment doesn't paint over the rounded\n outer pixels. */\n overflow: hidden;\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.4),\n 0 1px 0 rgba(255, 255, 255, 0.06);\n user-select: none;\n -webkit-user-select: none;\n touch-action: none;\n}\n\n.segment {\n position: relative;\n flex: 1 1 0;\n min-width: 0;\n /* The track's stretch sizes a segment; without this, labkit's :where(button) height wins and overflows a small bar. */\n height: auto;\n padding: 0 var(--wzl-space-6);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n margin: 0;\n font-family: var(--wzl-font-ui);\n font-weight: var(--wzl-font-weight-normal);\n font-size: var(--btn-fontsize, var(--wzl-font-size));\n line-height: 1;\n color: var(--wzl-fg-muted);\n cursor: pointer;\n /* Only round the outer corners of the bar — middle segments stay square\n so the seams between them don't render as facing parentheses. */\n border-radius: 0;\n isolation: isolate;\n overflow: hidden;\n transition: color var(--wzl-motion-fast);\n}\n\n/* A glyph label is a fixed box, not text that can reflow: without this it is\n the only thing in the segment flex can take width from, and three bars in\n one property row squeeze it to nothing. The side padding drops with it —\n 8px around a 14px glyph is most of a segment. */\n.segment > svg {\n flex: none;\n}\n\n.segment:has(> svg) {\n padding: 0 5px;\n}\n\n.segment:first-child {\n border-radius: var(--wzl-radius-pill) 0 0 var(--wzl-radius-pill);\n}\n\n.segment:last-child {\n border-radius: 0 var(--wzl-radius-pill) var(--wzl-radius-pill) 0;\n}\n\n.segment:only-child {\n border-radius: var(--wzl-radius-pill);\n}\n\n.segment:focus-visible {\n outline: 2px solid var(--wzl-accent);\n outline-offset: -2px;\n}\n\n.segment:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n}\n\n/* Selected segment — full Aqua glass cylinder. Mirrors Button.variant_primary. */\n.segmentSelected {\n background: linear-gradient(\n 180deg,\n color-mix(in srgb, var(--wzl-accent) var(--btn-top-alpha, 45%), transparent) 0%,\n color-mix(in srgb, var(--wzl-accent) var(--btn-upper-alpha, 70%), transparent) calc(var(--btn-equator, 52%) - var(--btn-equator-spread, 12%)),\n color-mix(in srgb, var(--wzl-accent) var(--btn-equator-tint, 95%), white) var(--btn-equator, 52%),\n var(--wzl-accent) calc(var(--btn-equator, 52%) + var(--btn-equator-spread, 12%) * 1.6),\n color-mix(in srgb, var(--wzl-accent) var(--btn-base-tint, 70%), black) 100%\n );\n backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n -webkit-backdrop-filter: blur(var(--btn-blur, 6px)) saturate(var(--btn-saturate, 1.3));\n color: var(--wzl-fg-on-accent);\n text-shadow:\n 0 1px 0 rgba(0, 0, 0, var(--btn-text-shadow, 0.35)),\n var(--btn-text-inset-x, 0px) var(--btn-text-inset-y, 1px) 0 rgba(0, 0, 0, var(--btn-text-inset, 0.55)),\n 0 0 6px rgba(0, 0, 0, calc(var(--btn-text-shadow, 0.35) * 0.5));\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, var(--btn-inset-hi, 0.42)),\n inset 0 -1px 2px rgba(0, 0, 0, var(--btn-inset-lo, 0.3)),\n 0 0 0 1px rgba(0, 0, 0, var(--btn-rim, 0.22)),\n 0 1px 2px rgba(0, 0, 0, var(--btn-drop-near, 0.3)),\n 0 2px 4px rgba(0, 0, 0, calc(var(--btn-drop-far, 0.18) * 0.8));\n}\n\n/* Specular gloss on the selected segment. Top corners inherit the\n segment's radius so they hug the upper edge cleanly; bottom corners\n are flattened so the gloss ends in a straight line at the equator\n instead of two little curves that read as `)(` brackets. */\n.segmentSelected::before {\n content: '';\n position: absolute;\n inset: 1px 1px var(--btn-gloss-bottom, 50%) 1px;\n border-radius: inherit;\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n background: linear-gradient(\n 180deg,\n rgba(255, 255, 255, var(--btn-gloss-top, 0.42)) 0%,\n rgba(255, 255, 255, var(--btn-gloss-mid, 0.12)) 60%,\n rgba(255, 255, 255, 0) 100%\n );\n pointer-events: none;\n z-index: 1;\n}\n\n.segmentSelected > * {\n position: relative;\n z-index: 2;\n}\n\n/* Mixed segment (`aria-pressed=\"mixed\"`) — the sources disagree. Reads as a\n deliberate third state rather than a dimmed \"on\": a flat accent wash with\n none of the selected segment's gloss/cylinder treatment, so it can't be\n mistaken for the glass lozenge at a glance. */\n.segmentMixed {\n background: color-mix(in srgb, var(--wzl-accent) 22%, transparent);\n color: var(--wzl-fg);\n box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--wzl-accent) 45%, transparent);\n}\n\n.segmentMixed:hover:not(:disabled) {\n background: color-mix(in srgb, var(--wzl-accent) 32%, transparent);\n}\n\n.variant_minimal .segmentMixed {\n background: color-mix(in srgb, var(--wzl-accent) 18%, transparent);\n box-shadow: none;\n color: var(--wzl-fg);\n}\n\n/* Small variant — ~60% of the default height, with proportionally reduced\n padding and font. Sized for dense surfaces (lab control panels, inline\n filters, etc.). */\n.size_sm {\n height: 17px;\n padding: 1px;\n}\n\n.size_sm .segment {\n padding: 0 var(--wzl-space-4);\n font-size: var(--wzl-font-size-sm);\n}\n\n/* `.size_sm .segment` outranks the glyph rule above on specificity, so a\n small bar's glyph segments need the tight padding restated to stay\n near-square rather than reading as wide plates. */\n.size_sm .segment:has(> svg) {\n padding: 0 3px;\n}\n\n/* Minimal variant — strips the pill track, glass selected state, inset\n shadows, and outer padding. Used in dense diagnostic surfaces (dispatch\n trace, lab inspectors) where the bar must read as plain text controls. */\n.variant_minimal {\n height: auto;\n padding: 0;\n background: none;\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n box-shadow: none;\n gap: 0;\n}\n\n.variant_minimal .segment {\n padding: 0 var(--wzl-space-3);\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-font-weight-medium);\n line-height: 1.4;\n border-radius: 0;\n color: var(--wzl-fg-muted);\n transition: none;\n}\n\n/* Dividers between segments make the mutual-exclusion grouping visible\n without a heavy track. Only the inner edges get a rule — the outer\n border on `.variant_minimal` handles the perimeter. */\n.variant_minimal .segment + .segment {\n border-left: 1px solid var(--wzl-border);\n}\n\n.variant_minimal .segment:first-child,\n.variant_minimal .segment:last-child,\n.variant_minimal .segment:only-child {\n border-radius: 0;\n}\n\n.variant_minimal .segment:hover:not(:disabled):not(.segmentSelected) {\n color: var(--wzl-fg);\n background: var(--wzl-surface-hover);\n}\n\n.variant_minimal .segmentSelected {\n background: none;\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n color: var(--wzl-accent-fg, var(--wzl-accent));\n text-shadow: none;\n box-shadow: none;\n font-weight: var(--wzl-font-weight-medium);\n}\n\n.variant_minimal .segmentSelected::before {\n content: none;\n}\n\n/* Flat variant — no track, no glass, no pill: each segment is its own\n outlined cell. For property panels, where a bar sits in a row beside\n inputs and the glass cylinder makes it the loudest thing on the surface. */\n.variant_flat {\n padding: 0;\n background: none;\n border-radius: var(--wzl-radius-sm);\n box-shadow: none;\n overflow: visible;\n}\n\n.variant_flat .segment {\n border: 1px solid var(--wzl-border-strong);\n border-radius: 0;\n /* Sunken, so an unselected cell sits below the panel and the selected one\n reads as raised without needing the glass treatment back. */\n background: var(--wzl-surface-sunken);\n color: var(--wzl-fg-muted);\n}\n\n/* Adjacent cells share one rule rather than stacking two. */\n.variant_flat .segment + .segment {\n margin-inline-start: -1px;\n}\n\n.variant_flat .segment:first-child {\n border-start-start-radius: var(--wzl-radius-sm);\n border-end-start-radius: var(--wzl-radius-sm);\n}\n\n.variant_flat .segment:last-child {\n border-start-end-radius: var(--wzl-radius-sm);\n border-end-end-radius: var(--wzl-radius-sm);\n}\n\n.variant_flat .segment:hover:not(:disabled):not(.segmentSelected) {\n background: var(--wzl-surface-hover);\n color: var(--wzl-fg);\n}\n\n.variant_flat .segmentSelected {\n background: var(--wzl-accent);\n border-color: var(--wzl-accent);\n color: var(--wzl-fg-on-accent);\n backdrop-filter: none;\n -webkit-backdrop-filter: none;\n text-shadow: none;\n box-shadow: none;\n /* Its own border rather than the neighbour's overlapping edge. */\n z-index: 1;\n}\n\n.variant_flat .segmentSelected::before {\n content: none;\n}\n","import { type CSSProperties, type ReactElement, type ReactNode } from 'react';\nimport s from './ToggleBar.module.css';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\nimport { SegmentTooltip, segmentTooltipContent, type SegmentTooltipFields } from '../segmentTooltip';\n\n/** One segment of a {@link ToggleBar}, identified by its `value`. */\nexport type ToggleBarItem<V extends string | number = string> = {\n value: V;\n label?: ReactNode;\n ariaLabel?: string;\n disabled?: boolean;\n} & SegmentTooltipFields;\n\n/** Segment height and type scale for a {@link ToggleBar}. */\nexport type ToggleBarSize = 'sm' | 'md';\n/** Visual treatment of a {@link ToggleBar}. */\nexport type ToggleBarVariant = 'default' | 'minimal' | 'flat';\n\ntype CommonProps = {\n ariaLabel?: string;\n className?: string;\n height?: number;\n /** Size variant. `sm` is ~60% of the default height with reduced padding\n * and font size — sized for dense surfaces like lab control panels. */\n size?: ToggleBarSize;\n /** Visual variant. `minimal` strips the pill track and glass treatment;\n * selection becomes a flat accent. For dense diagnostic surfaces. */\n variant?: ToggleBarVariant;\n};\n\n/**\n * Props for {@link ToggleBar}, discriminated on `mode`. Single mode is\n * controlled by one value or `null`; multiple mode by an array, and only it\n * accepts `mixedValues`.\n */\nexport type ToggleBarProps<V extends string | number = string> =\n | (CommonProps & {\n mode?: 'single';\n items: readonly ToggleBarItem<V>[];\n value: V | null;\n onChange: (next: V | null) => void;\n allowDeselect?: boolean;\n })\n | (CommonProps & {\n mode: 'multiple';\n items: readonly ToggleBarItem<V>[];\n value: readonly V[];\n /**\n * Values that are neither on nor off — the sources this bar\n * aggregates disagree (a text range that is bold in part of it, a\n * multi-selection whose nodes differ). Rendered `aria-pressed=\"mixed\"`,\n * the ARIA tri-state a toggle button actually has, rather than\n * `SelectionPanel`'s reduced-opacity-plus-`title` workaround for\n * `Switch`, which has no indeterminate state to render.\n *\n * `value` wins where the two lists overlap, so a caller that can't\n * cheaply keep them disjoint doesn't get an ambiguous segment.\n *\n * Clicking a mixed segment turns it fully **on**, matching the\n * everywhere-else convention (and `toggleFlagInRange`'s rule for a\n * partially-styled text range) that a mixed toggle resolves toward\n * the affirmative rather than clearing.\n */\n mixedValues?: readonly V[];\n onChange: (next: V[]) => void;\n });\n\n/**\n * Segmented control for choosing among a fixed set of values — one of them\n * (`mode: 'single'`, the default) or any number (`mode: 'multiple'`).\n *\n * Single mode ignores a click on the already-selected segment unless\n * `allowDeselect` is set. Arrow keys move focus without changing the value;\n * Space and Enter commit.\n */\nexport function ToggleBar<V extends string | number = string>(props: ToggleBarProps<V>): ReactElement {\n const { items, ariaLabel, className, height, size, variant } = props;\n const mode = props.mode ?? 'single';\n\n const isSelected = (value: V): boolean => {\n if (mode === 'multiple') return (props.value as readonly V[]).includes(value);\n return (props.value as V | null) === value;\n };\n\n /** Mixed only in multiple mode, and only where `value` doesn't already\n * claim the segment. Single mode has nothing to be mixed about — its\n * aggregate is one value or none. */\n const isMixed = (value: V): boolean => {\n if (mode !== 'multiple') return false;\n const mixed = (props as { mixedValues?: readonly V[] }).mixedValues;\n return mixed !== undefined && mixed.includes(value) && !isSelected(value);\n };\n\n const handleClick = (index: number) => () => {\n const item = items[index];\n if (item.disabled) return;\n if (mode === 'multiple') {\n const current = props.value as readonly V[];\n const next = current.includes(item.value)\n ? current.filter(v => v !== item.value)\n : [...current, item.value];\n (props.onChange as (n: V[]) => void)(next);\n } else {\n const current = props.value as V | null;\n if (current === item.value) {\n if ((props as { allowDeselect?: boolean }).allowDeselect) {\n (props.onChange as (n: V | null) => void)(null);\n }\n return;\n }\n (props.onChange as (n: V | null) => void)(item.value);\n }\n };\n\n const selectedIndex = mode === 'single'\n ? items.findIndex(it => it.value === (props.value as V | null))\n : -1;\n\n const roving = useRovingTabIndex({\n items,\n itemClassName: s.segment,\n // Single mode is a radiogroup: the tab stop is the current value, and\n // arrow keys move the selection with the focus. Multiple mode is a set of\n // independent toggles — focus alone moves, and Space/Enter flips.\n tabStopIndex: selectedIndex >= 0 && !items[selectedIndex].disabled ? selectedIndex : undefined,\n onNavigate: mode === 'single'\n ? (index) => (props.onChange as (n: V | null) => void)(items[index].value)\n : undefined,\n onActivate: mode === 'multiple' ? (index) => handleClick(index)() : undefined,\n });\n\n const style: CSSProperties | undefined = height !== undefined\n ? ({ ['--tb-h' as string]: `${height}px` } as CSSProperties)\n : undefined;\n\n const rootCls = [\n s.root,\n size && s[`size_${size}`],\n variant && s[`variant_${variant}`],\n className,\n ].filter(Boolean).join(' ');\n\n return (\n <div\n ref={roving.rootRef}\n className={rootCls}\n role={mode === 'multiple' ? 'group' : 'radiogroup'}\n aria-label={ariaLabel}\n style={style}\n >\n {items.map((item, i) => {\n const selected = isSelected(item.value);\n const mixed = isMixed(item.value);\n const cls = [s.segment, selected && s.segmentSelected, mixed && s.segmentMixed]\n .filter(Boolean)\n .join(' ');\n return (\n <SegmentTooltip key={item.value} content={segmentTooltipContent(item)} disabled={item.disabled}>\n <button\n type=\"button\"\n role={mode === 'multiple' ? undefined : 'radio'}\n aria-checked={mode === 'multiple' ? undefined : selected}\n aria-pressed={mode === 'multiple' ? (mixed ? 'mixed' : selected) : undefined}\n aria-label={item.ariaLabel}\n disabled={item.disabled}\n tabIndex={roving.tabIndexFor(i)}\n className={cls}\n onClick={handleClick(i)}\n onKeyDown={roving.onKeyDown(i)}\n >\n {item.label}\n </button>\n </SegmentTooltip>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AC2EA,SAAgBI,EAA8C,GAAwC;CACpG,IAAM,EAAE,UAAO,cAAW,cAAW,WAAQ,SAAM,eAAYC,GACzDC,IAAOD,EAAM,QAAQ,UAErBE,KAAc,MACdD,MAAS,aAAoBD,EAAM,MAAuB,SAASG,CAAK,IACpEH,EAAM,UAAuBG,GAMjCC,KAAW,MAAsB;EACrC,IAAIH,MAAS,YAAY,OAAO;EAChC,IAAMI,IAASL,EAAyC;EACxD,OAAOK,MAAU,KAAA,KAAaA,EAAM,SAASF,CAAK,KAAK,CAACD,EAAWC,CAAK;CAC1E,GAEMG,KAAe,YAAwB;EAC3C,IAAMC,IAAOC,EAAMC;EACnB,IAAI,GAAK,UACT;OAAIR,MAAS,YAAY;IACvB,IAAMS,IAAUV,EAAM,OAChBW,IAAOD,EAAQ,SAASH,EAAK,KAAK,IACpCG,EAAQ,QAAO,MAAKE,MAAML,EAAK,KAAK,IACpC,CAAC,GAAGG,GAASH,EAAK,KAAK;IAC3B,EAAO,SAA8BI,CAAI;GAC3C,OAAO;IAEL,IADgBX,EAAM,UACNO,EAAK,OAAO;KAC1B,AAAKP,EAAsC,iBACzCA,EAAO,SAAmC,IAAI;KAEhD;IACF;IACA,EAAO,SAAmCO,EAAK,KAAK;GACtD;;CACF,GAEMM,IAAgBZ,MAAS,WAC3BO,EAAM,WAAU,MAAMM,EAAG,UAAWd,EAAM,KAAkB,IAC5D,IAEEe,IAASlB,EAAkB;EAC/B;EACA,eAAeF,EAAE;EAIjB,cAAckB,KAAiB,KAAK,CAACL,EAAMK,EAAc,CAAC,WAAWA,IAAgB,KAAA;EACrF,YAAYZ,MAAS,YAChB,MAAWD,EAAM,SAAmCQ,EAAMC,EAAM,CAAC,KAAK,IACvE,KAAA;EACJ,YAAYR,MAAS,cAAc,MAAUK,EAAYG,CAAK,CAAC,CAAC,IAAI,KAAA;CACtE,CAAC,GAEKO,IAAmCC,MAAW,KAAA,IAEhD,KAAA,IADC,EAAG,UAAqB,GAAGA,EAAO,IAAI,GAGrCC,IAAU;EACdvB,EAAE;EACFwB,KAAQxB,EAAE,QAAQwB;EAClBC,KAAWzB,EAAE,WAAWyB;EACxBC;CACF,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAE1B,OACE,kBAAC,OAAD;EACE,KAAKN,EAAO;EACZ,WAAWG;EACX,MAAMjB,MAAS,aAAa,UAAU;EACtC,cAAYqB;EACL;EAEN,UAAAd,EAAM,KAAK,GAAM,MAAM;GACtB,IAAMe,IAAWrB,EAAWK,EAAK,KAAK,GAChCF,IAAQD,EAAQG,EAAK,KAAK,GAC1BiB,IAAM;IAAC7B,EAAE;IAAS4B,KAAY5B,EAAE;IAAiBU,KAASV,EAAE;GAAY,CAAC,CAC5E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;GACX,OACE,kBAAC8B,GAAD;IAAiC,SAAS7B,EAAsBW,CAAI;IAAG,UAAUA,EAAK;IACpF,UAAA,kBAAC,UAAD;KACE,MAAK;KACL,MAAMN,MAAS,aAAa,KAAA,IAAY;KACxC,gBAAcA,MAAS,aAAa,KAAA,IAAYsB;KAChD,gBAActB,MAAS,aAAcI,IAAQ,UAAUkB,IAAY,KAAA;KACnE,cAAYhB,EAAK;KACjB,UAAUA,EAAK;KACf,UAAUQ,EAAO,YAAYW,CAAC;KAC9B,WAAWF;KACX,SAASlB,EAAYoB,CAAC;KACtB,WAAWX,EAAO,UAAUW,CAAC;KAE5B,UAAAnB,EAAK;IACA,CAAA;GACM,GAfKA,EAAK,KAeV;EAEpB,CAAC;CACE,CAAA;AAET"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ToolButton-CR4sQlxF.js","names":["s","TooltipTrigger","Tooltip","Tooltip$1","TooltipTrigger$1","ToolButton_module_default","ToolButton","props","resolvedTitle","title","shortcut","label","cls","active","className","disabled","Focusable","tabbable","ariaDisabled","icon"],"sources":["../../src/components/ToolButton/ToolButton.module.css","../../src/components/ToolButton/ToolButton.tsx"],"sourcesContent":[".button {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--wzl-space-1);\n min-width: 44px;\n padding: var(--wzl-space-3) var(--wzl-space-2);\n background: transparent;\n border: 1px solid transparent;\n border-radius: var(--wzl-radius-sm);\n color: var(--wzl-fg);\n cursor: default;\n font-family: inherit;\n font-size: var(--wzl-font-size-xs);\n line-height: 1.1;\n}\n.button:hover:not([disabled]) {\n background: var(--wzl-surface-hover);\n color: var(--wzl-fg);\n}\n.button:focus-visible {\n outline: 2px solid var(--wzl-accent);\n outline-offset: -2px;\n}\n.button.active {\n background: var(--wzl-surface-pressed);\n border-color: var(--wzl-accent);\n color: var(--wzl-fg);\n}\n.button[disabled] {\n opacity: 0.4;\n}\n\n.icon { display: block; }\n.icon > svg { display: block; }\n.label { font-size: var(--wzl-font-size-xs); }\n.shortcut {\n color: var(--wzl-fg-muted);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: var(--wzl-font-size-2xs);\n}\n","import type { KeyboardEvent, ReactNode } from 'react';\nimport { Focusable } from 'react-aria-components';\nimport { Tooltip, TooltipTrigger } from '../Tooltip';\nimport s from './ToolButton.module.css';\n\n/** Props for {@link ToolButton}. */\nexport interface ToolButtonProps {\n /** Icon node (typically an SVG component). */\n icon: ReactNode;\n /** Human-readable label shown under the icon. */\n label: string;\n /** Optional shortcut hint (e.g. \"V\" or \"⌘Z\"). */\n shortcut?: string;\n /** Selected/active state — toggles the active visual treatment. */\n active?: boolean;\n /** Disabled state — passes through to the underlying button. */\n disabled?: boolean;\n /**\n * When true, sets `aria-disabled=\"true\"` on the button without using the\n * native `disabled` attribute. This keeps the button focusable and reachable\n * by keyboard (roving-tabindex still applies) while marking it as ineligible\n * to screen readers. The caller is responsible for making `onClick` a no-op.\n */\n ariaDisabled?: boolean;\n /**\n * Whether this button is the currently tabbable member of its toolbar.\n * Toolbars use roving tabindex: exactly one button has `tabIndex=0` at\n * a time; the rest are `-1`. Caller manages which.\n */\n tabbable?: boolean;\n /** Click handler. */\n onClick(): void;\n /** Key handler for the underlying button — a toolbar's roving-tabindex\n * navigation attaches here. */\n onKeyDown?(e: KeyboardEvent<HTMLElement>): void;\n /**\n * Tooltip content. Defaults to `label` (plus `shortcut` if provided).\n */\n title?: string;\n /** Additional class for the root button. */\n className?: string;\n}\n\n/**\n * Generic icon-+-label toolbar button — building block for `ToolPalette`\n * and similar surfaces. Headless about layout direction (parent group\n * supplies flex direction via `ToolGroup`). Theme via `--wzl-*` tokens.\n */\nexport function ToolButton(props: ToolButtonProps) {\n const {\n icon, label, shortcut, active, disabled, ariaDisabled, tabbable,\n onClick, onKeyDown, title, className,\n } = props;\n const resolvedTitle = title ?? (shortcut ? `${label} (${shortcut})` : label);\n const cls = [s.button, active && s.active, className].filter(Boolean).join(' ');\n return (\n <TooltipTrigger isDisabled={disabled}>\n <Focusable isDisabled={disabled}>\n <button\n type=\"button\"\n tabIndex={tabbable ? 0 : -1}\n className={cls}\n aria-current={active ? 'true' : undefined}\n aria-disabled={ariaDisabled ? 'true' : undefined}\n disabled={disabled}\n onClick={onClick}\n onKeyDown={onKeyDown}\n >\n <span className={s.icon} aria-hidden=\"true\">{icon}</span>\n <span className={s.label}>{label}</span>\n {shortcut && <span className={s.shortcut}>{shortcut}</span>}\n </button>\n </Focusable>\n <Tooltip>{resolvedTitle}</Tooltip>\n </TooltipTrigger>\n );\n}\n"],"mappings":";;;;;;;;;;;;ACgDA,SAAgBM,EAAW,GAAwB;CACjD,IAAM,EACJ,SAAM,UAAO,aAAU,WAAQ,aAAU,iBAAc,aACvD,YAAS,cAAW,UAAO,iBACzBC,GACEC,IAAgBC,MAAUC,IAAW,GAAGC,EAAM,IAAID,EAAS,KAAKC,IAChEC,IAAM;EAACZ,EAAE;EAAQa,KAAUb,EAAE;EAAQc;CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC9E,OACE,kBAACb,GAAD;EAAgB,YAAYc;EAA5B,UAAA,CACE,kBAACC,GAAD;GAAW,YAAYD;GACrB,UAAA,kBAAC,UAAD;IACE,MAAK;IACL,UAAUE,IAAW,IAAI;IACzB,WAAWL;IACX,gBAAcC,IAAS,SAAS,KAAA;IAChC,iBAAeK,IAAe,SAAS,KAAA;IAC7B;IACD;IACE;IARb,UAAA;KAUE,kBAAC,QAAD;MAAM,WAAWlB,EAAE;MAAM,eAAY;MAAQ,UAAAmB;KAAW,CAAA;KACxD,kBAAC,QAAD;MAAM,WAAWnB,EAAE;MAAQ,UAAAW;KAAY,CAAA;KACtCD,KAAY,kBAAC,QAAD;MAAM,WAAWV,EAAE;MAAW,UAAAU;KAAe,CAAA;IACpD;;EACC,CAAA,GACX,kBAACR,GAAD,EAAA,UAAUM,EAAuB,CAAA,CACnB;;AAEpB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ToolOptionsBar-CtzTlaN2.js","names":["s","_Fragment","isGroup","pairRows","renderCells","renderBuiltin","ToolOptionsBar_module_default","ToolOptionsBar","props","cls","className","label","schema","barRows","BarRow","row","children","leaves","collect","key","child","group","path","prefix","cells","barCell","panelLeaf","values","mixed","renderers","onChange","Fragment","needsLabel","cell","leaf","isMixed","ctx","v","p","custom","ariaLabel"],"sources":["../../src/components/ToolOptionsBar/ToolOptionsBar.module.css","../../src/components/ToolOptionsBar/ToolOptionsBar.tsx"],"sourcesContent":["/* Horizontal strip reserved above the workspace for contextual tool\n options. Fixed height so mounting/unmounting content never resizes\n the workspace beneath it — that's the whole reason this row exists\n as permanent chrome rather than an on-demand overlay.\n\n Overflow: when controls exceed the available width, `.controls`\n scrolls horizontally rather than wrapping (which would grow the row\n and defeat the fixed-height guarantee above) or clipping (which\n would hide controls with no way to reach them). A flyout/long-press\n affordance was considered and rejected — grouped, directly visible\n layouts are preferred in this repo. */\n\n.root {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-4);\n height: var(--wzl-tb-height, 28px);\n padding: 0 var(--wzl-space-4);\n background: var(--wzl-surface);\n border-bottom: 1px solid var(--wzl-border);\n color: var(--wzl-fg);\n overflow: hidden;\n}\n\n.label {\n flex: 0 0 auto;\n font-size: var(--wzl-font-size-sm);\n font-weight: var(--wzl-font-weight-bold);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--wzl-fg-muted);\n white-space: nowrap;\n}\n\n.controls {\n display: flex;\n align-items: center;\n gap: var(--wzl-space-3);\n flex: 1 1 auto;\n min-width: 0;\n height: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: thin;\n}\n\n/* Firefox gets a thin scrollbar for free via `scrollbar-width` above.\n * Chromium/WebKit need it spelled out — on a classic (non-overlay)\n * scrollbar theme (default on Windows Chrome/Edge), an unstyled\n * horizontal scrollbar is ~15-17px tall and renders *inside* this box,\n * clipping/off-centering the row's controls. That would reintroduce the\n * exact height instability the scroll-over-wrap overflow choice above\n * exists to avoid — just at the row's inner edge instead of its outer\n * one. Pin it thin and out of the way instead. */\n.controls::-webkit-scrollbar {\n height: 4px;\n}\n.controls::-webkit-scrollbar-track {\n background: transparent;\n}\n.controls::-webkit-scrollbar-thumb {\n background: var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n}\n\n/* A schema-drawn control sits on the line as-is; the cell exists only to keep\n it from being squeezed by the row's flex context. */\n.cell {\n display: flex;\n align-items: center;\n flex: none;\n}\n\n.cellLabel {\n flex: none;\n margin-right: var(--wzl-space-2);\n font-size: var(--wzl-font-size-sm);\n color: var(--wzl-fg-muted);\n white-space: nowrap;\n}\n\n/* Fields are read beside their label on one line, so they carry only the\n digits they need rather than the panel's column width. */\n.controls {\n --wzl-number-field-width: 5ch;\n}\n\n/* The strip decides how much room a control gets, because its budget is one\n line rather than a column: a field carries the digits it needs and an\n opacity track stops short of pushing its neighbours off the end. Both are\n the panel's widths otherwise, which are sized for a two-column grid. */\n.cell input[type='text'] {\n inline-size: var(--wzl-number-field-width, 5ch);\n}\n\n.cell input[type='range'] {\n inline-size: 64px;\n flex: none;\n}\n","import type { ReactNode } from 'react';\nimport type { ToolPrefGroup, ToolPrefLeaf } from '@weasel-js/core';\nimport {\n renderBuiltin,\n renderCells,\n type LeafCell,\n type PropertyRenderContext,\n type PropertyRenderer,\n} from '../SelectionPanel/renderLeaf';\nimport { isGroup, pairRows, type PanelLeaf, type PanelRow } from '../SelectionPanel/model';\nimport s from './ToolOptionsBar.module.css';\n\n/** Props for {@link ToolOptionsBar}. */\nexport interface ToolOptionsBarProps {\n /**\n * Context label for the row — e.g. the active tool's name. Rendered\n * before the children and doubles as the toolbar's `aria-label`. Omit\n * it and the row still renders (it's a permanently reserved slot), just\n * without an accessible name.\n *\n * Using `label` for both the visible text and `aria-label` means a\n * screen reader announces it twice when landing on the toolbar (\"Text,\n * toolbar\", then \"Text\" again when browsing into the visible span).\n * `aria-labelledby` would avoid the echo at the cost of id plumbing and\n * an awkward no-`id`-to-point-at case when `label` is omitted. The\n * double-announcement is common enough for labeled landmark regions\n * that it's left as-is — considered, not missed.\n */\n label?: string;\n /**\n * The active tool's options. Leaves draw through the same leaf → control\n * mapping `SelectionPanel` uses, so a kind gets its control decided in one\n * place; groups organize without drawing, since the bar is one line.\n */\n schema?: ToolPrefGroup;\n /** Each leaf's value, keyed by dotted path. A path with no entry is unset. */\n values?: Readonly<Record<string, unknown>>;\n /** A leaf edit, as the dotted path it was declared at and its new value. */\n onChange?: (path: string, value: unknown) => void;\n /** Paths whose sources disagree — drawn as the control's mixed state. */\n mixed?: ReadonlySet<string>;\n /** Control overrides, by dotted path or by leaf kind, as the panel takes. */\n renderers?: Record<string, PropertyRenderer>;\n children?: ReactNode;\n className?: string;\n}\n\n/**\n * Horizontal strip reserved above the workspace for contextual tool options.\n * Given a `schema` it draws the active tool's options itself; the children\n * slot stays open for a tenant that is not a tool's options at all, such as\n * loupe controls.\n *\n * The row always renders, even empty, because the app reserves its height\n * permanently rather than mounting it on demand — mounting mid-edit would\n * resize the workspace under a canvas that's sized to the page.\n *\n * `role=\"toolbar\"` without roving tabindex: the ARIA authoring practices\n * expect arrow-key roving focus across a toolbar's items, but a bar of\n * compound controls (`NumberField`, `Select`, `ColorField`) must leave the\n * arrow keys to them — they edit their own value with them. That is true of\n * schema-drawn controls as much as of arbitrary children, so the bar keeps\n * plain DOM tab order and `useRovingTabIndex` documents this as its opt-out.\n */\nexport function ToolOptionsBar(props: ToolOptionsBarProps) {\n const { label, schema, values, onChange, mixed, renderers, children, className } = props;\n const cls = [s.root, className].filter(Boolean).join(' ');\n return (\n <div className={cls} role=\"toolbar\" aria-label={label}>\n {label !== undefined && <span className={s.label}>{label}</span>}\n <div className={s.controls}>\n {schema !== undefined &&\n barRows(schema).map((row) => (\n <BarRow\n key={row.leaves[0]!.path}\n row={row}\n values={values}\n mixed={mixed}\n renderers={renderers}\n onChange={onChange}\n />\n ))}\n {children}\n </div>\n </div>\n );\n}\n\n/**\n * The schema's visible leaves as rows, addressed by dotted path. Groups are\n * organizational here — a bar is one line, so a nested group contributes its\n * leaves and no chrome — but its path segment still names them, so a leaf\n * reads back at the path the tool declared it at.\n */\nfunction barRows(schema: ToolPrefGroup): PanelRow[] {\n const leaves: PanelLeaf[] = [];\n const collect = (group: ToolPrefGroup, prefix: string): void => {\n for (const [key, child] of Object.entries(group.children)) {\n const path = prefix === '' ? key : `${prefix}.${key}`;\n if (isGroup(child)) collect(child, path);\n else if (child.hidden !== true) leaves.push({ path, leaf: child });\n }\n };\n collect(schema, '');\n return pairRows(leaves);\n}\n\n/** One row of the bar: a single control, or a run of flags as one bar. */\nfunction BarRow({\n row,\n values,\n mixed,\n renderers,\n onChange,\n}: {\n row: PanelRow;\n values: Readonly<Record<string, unknown>> | undefined;\n mixed: ReadonlySet<string> | undefined;\n renderers: Record<string, PropertyRenderer> | undefined;\n onChange: ((path: string, value: unknown) => void) | undefined;\n}) {\n // The bar draws no row label, so a control carries its own name rather than\n // the panel's qualified \"<pair> <leaf>\" — the run's bar carries the pair.\n const cells = row.leaves.map((panelLeaf) =>\n barCell(panelLeaf, panelLeaf.leaf.name, values, mixed, renderers, onChange),\n );\n return (\n <>\n {renderCells(cells, renderers).map((cell) => (\n <span key={cell.key} className={s.cell}>\n {needsLabel(cell.leaf) && (\n <span className={s.cellLabel} aria-hidden=\"true\">\n {cell.leaf.short ?? cell.leaf.name}\n </span>\n )}\n {cell.content}\n </span>\n ))}\n </>\n );\n}\n\n/**\n * Whether a control needs telling from its neighbours in words.\n *\n * Only a bare value box does: a number or a string is a box of characters,\n * and two of them side by side are indistinguishable. Everything else shows\n * what it is — a swatch is a color, a font picker names the family, a flag\n * run and a segmented control label their own segments — so a word in front\n * would repeat what the control already says. `name` stays the accessible\n * name either way, so this costs a screen reader nothing.\n */\nfunction needsLabel(leaf: ToolPrefLeaf): boolean {\n return leaf.kind === 'number' || leaf.kind === 'string';\n}\n\nfunction barCell(\n panelLeaf: PanelLeaf,\n ariaLabel: string,\n values: Readonly<Record<string, unknown>> | undefined,\n mixed: ReadonlySet<string> | undefined,\n renderers: Record<string, PropertyRenderer> | undefined,\n onChange: ((path: string, value: unknown) => void) | undefined,\n): LeafCell {\n const { path, leaf } = panelLeaf;\n const isMixed = mixed?.has(path) === true;\n const ctx: PropertyRenderContext = {\n path,\n pref: leaf,\n value: isMixed ? undefined : values?.[path],\n mixed: isMixed,\n unset: !isMixed && values?.[path] === undefined,\n setValue: (v) => onChange?.(path, v),\n valueAt: (p) => ({ value: values?.[p], mixed: mixed?.has(p) === true }),\n };\n return {\n key: path,\n leaf: leaf as ToolPrefLeaf,\n ctx,\n ariaLabel,\n render: () => {\n const custom = renderers?.[path] ?? renderers?.[leaf.kind];\n return custom ? custom(ctx) : renderBuiltin(ctx, ariaLabel, renderers, path);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;ACgEA,SAAgBO,EAAe,GAA4B;CACzD,IAAM,EAAE,UAAO,WAAQ,WAAQ,aAAU,UAAO,cAAW,aAAU,iBAAcC,GAC7EC,IAAM,CAACT,EAAE,MAAMU,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CACxD,OACE,kBAAC,OAAD;EAAK,WAAWD;EAAK,MAAK;EAAU,cAAYE;EAAhD,UAAA,CACGA,MAAU,KAAA,KAAa,kBAAC,QAAD;GAAM,WAAWX,EAAE;GAAQ,UAAAW;EAAY,CAAA,GAC/D,kBAAC,OAAD;GAAK,WAAWX,EAAE;GAAlB,UAAA,CACGY,MAAW,KAAA,KACVC,EAAQD,CAAM,CAAC,CAAC,KAAK,MACnB,kBAACE,GAAD;IAEO;IACG;IACD;IACI;IACD;GACX,GANMC,EAAI,OAAO,EAAE,CAAE,IAMrB,CACF,GACFC,CACE;EACF,CAAA,CAAA;;AAET;AAQA,SAASH,EAAQ,GAAmC;CAClD,IAAMI,IAAsB,CAAC,GACvBC,KAAW,GAAsB,MAAyB;EAC9D,KAAK,IAAM,CAACC,GAAKC,MAAU,OAAO,QAAQC,EAAM,QAAQ,GAAG;GACzD,IAAMC,IAAOC,MAAW,KAAKJ,IAAM,GAAGI,EAAO,GAAGJ;GAChD,AAAIjB,EAAQkB,CAAK,IAAGF,EAAQE,GAAOE,CAAI,IAC9BF,EAAM,WAAW,MAAMH,EAAO,KAAK;IAAE;IAAM,MAAMG;GAAM,CAAC;EACnE;CACF;CAEA,OADAF,EAAQN,GAAQ,EAAE,GACXT,EAASc,CAAM;AACxB;AAGA,SAASH,EAAO,EACd,QACA,WACA,UACA,cACA,eAOC;CAGD,IAAMU,IAAQT,EAAI,OAAO,KAAK,MAC5BU,EAAQC,GAAWA,EAAU,KAAK,MAAMC,GAAQC,GAAOC,GAAWC,CAAQ,CAC5E;CACA,OACE,kBAAA7B,GAAA,EAAA,UACGG,EAAYoB,GAAOK,CAAS,CAAC,CAAC,KAAK,MAClC,kBAAC,QAAD;EAAqB,WAAW7B,EAAE;EAAlC,UAAA,CACGgC,EAAWC,EAAK,IAAI,KACnB,kBAAC,QAAD;GAAM,WAAWjC,EAAE;GAAW,eAAY;GACvC,UAAAiC,EAAK,KAAK,SAASA,EAAK,KAAK;EAC1B,CAAA,GAEPA,EAAK,OACF;CAPK,GAAAA,EAAK,GAOV,CACP,EACD,CAAA;AAEN;AAYA,SAASD,EAAW,GAA6B;CAC/C,OAAOE,EAAK,SAAS,YAAYA,EAAK,SAAS;AACjD;AAEA,SAAST,EACP,GACA,GACA,GACA,GACA,GACA,GACU;CACV,IAAM,EAAE,SAAM,YAASC,GACjBS,IAAUP,GAAO,IAAIN,CAAI,MAAM,IAC/Bc,IAA6B;EACjC;EACA,MAAMF;EACN,OAAOC,IAAU,KAAA,IAAYR,IAASL;EACtC,OAAOa;EACP,OAAO,CAACA,KAAWR,IAASL,OAAU,KAAA;EACtC,WAAW,MAAMQ,IAAWR,GAAMe,CAAC;EACnC,UAAU,OAAO;GAAE,OAAOV,IAASW;GAAI,OAAOV,GAAO,IAAIU,CAAC,MAAM;EAAK;CACvE;CACA,OAAO;EACL,KAAKhB;EACC;EACN;EACA;EACA,cAAc;GACZ,IAAMiB,IAASV,IAAYP,MAASO,IAAYK,EAAK;GACrD,OAAOK,IAASA,EAAOH,CAAG,IAAI/B,EAAc+B,GAAKI,GAAWX,GAAWP,CAAI;EAC7E;CACF;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ToolPalette-CKG9qY6P.js","names":["s","Fragment","formatShortcut","ToolButton","ToolGroup","Fragment$1","ToolPalette_module_default","DEFAULT_GROUP_ORDER","MISC","partitionByGroup","groups","tool","list","g","bucket","orderedGroupKeys","seen","ordered","known","groupOrder","key","resolveIcon","rawIcon","UnknownIcon","ToolPalette","props","tools","groupKeys","cls","orientation","className","k","eligibility","eligibleContribution","modeRegistry","activeIndex","t","roving","useRovingTabIndex","enabled","index","i","label","shortcut","lookupShortcut","modeName","resolvedTitle"],"sources":["../../src/components/ToolPalette/ToolPalette.module.css","../../src/components/ToolPalette/ToolPalette.tsx"],"sourcesContent":[".palette {\n display: flex;\n flex-direction: column;\n gap: var(--wzl-space-2);\n background: var(--wzl-surface);\n border: 1px solid var(--wzl-border);\n border-radius: var(--wzl-radius-sm);\n padding: var(--wzl-space-2);\n user-select: none;\n}\n.palette.horizontal {\n flex-direction: row;\n}\n\n/* Marker only — `useRovingTabIndex` finds the palette's buttons by this class.\n Carries no styles; deleting it breaks keyboard navigation. */\n.paletteBtn {}\n\n/* Applied to ineligible tool buttons in the active mode. */\n.ineligibleBtn {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.separator {\n background: var(--wzl-border);\n}\n.palette:not(.horizontal) .separator {\n height: 1px;\n margin: var(--wzl-space-1) 0;\n}\n.palette.horizontal .separator {\n width: 1px;\n margin: 0 var(--wzl-space-1);\n}\n","import { Fragment, type ReactNode } from 'react';\nimport { UnknownIcon } from '@weasel-js/core';\nimport type { AnyTool, ToolsApi } from '@weasel-js/core';\nimport { eligibleContribution, type ModeRegistry } from '@weasel-js/modes';\nimport { ToolButton } from '../ToolButton';\nimport { ToolGroup } from '../ToolGroup';\nimport { useRovingTabIndex } from '../../useRovingTabIndex';\nimport s from './ToolPalette.module.css';\nimport { formatShortcut, type ShortcutInput } from './formatShortcut';\n\nconst DEFAULT_GROUP_ORDER = ['select', 'shape', 'draw', 'type', 'view'] as const;\nconst MISC = 'misc';\n\nfunction partitionByGroup(list: AnyTool[]): Map<string, AnyTool[]> {\n const groups = new Map<string, AnyTool[]>();\n for (const tool of list) {\n const g = tool.presentation?.group ?? MISC;\n const bucket = groups.get(g) ?? [];\n bucket.push(tool);\n groups.set(g, bucket);\n }\n return groups;\n}\n\nfunction orderedGroupKeys(\n groups: Map<string, AnyTool[]>,\n groupOrder: readonly string[],\n): string[] {\n const seen = new Set(groups.keys());\n const ordered: string[] = [];\n for (const known of groupOrder) {\n if (seen.has(known)) {\n ordered.push(known);\n seen.delete(known);\n }\n }\n // Unknown groups in insertion order (Map preserves it), misc last.\n for (const key of groups.keys()) {\n if (seen.has(key) && key !== MISC) {\n ordered.push(key);\n seen.delete(key);\n }\n }\n if (seen.has(MISC)) ordered.push(MISC);\n return ordered;\n}\n\nfunction resolveIcon(tool: AnyTool): ReactNode {\n const rawIcon = tool.presentation?.icon;\n if (rawIcon == null) return <UnknownIcon />;\n if (typeof rawIcon === 'function') return rawIcon(undefined);\n return rawIcon;\n}\n\n/** Props for {@link ToolPalette}. */\nexport interface ToolPaletteProps {\n tools: ToolsApi;\n orientation?: 'vertical' | 'horizontal';\n className?: string;\n /** Derive the keyboard shortcut for a tool button from the action registry.\n * Called with the tool's id; return `undefined` to suppress a chip. When\n * omitted, falls back to `tool.keybinding` (legacy path). */\n lookupShortcut?: (toolId: string) => ShortcutInput | undefined;\n /**\n * Optional mode registry. When provided, tools whose\n * `eligibility.capabilities` do not match the current mode are rendered\n * greyed-out, aria-disabled, and their onClick is suppressed. When omitted,\n * all tools are treated as eligible (preserves existing behavior in\n * consumers that haven't wired a registry).\n */\n modeRegistry?: ModeRegistry;\n /**\n * Presentation-group display order. Groups not listed keep their registry\n * insertion order after the listed ones; `misc` always renders last.\n * Defaults to `['select', 'shape', 'draw', 'type', 'view']`.\n */\n groupOrder?: readonly string[];\n}\n\n/**\n * Toolbar of the registered tools, split into separator-divided groups by\n * each tool's presentation group and navigable by arrow keys. Clicking a\n * button makes that tool active.\n *\n * Given a `modeRegistry`, tools whose capabilities the current mode does not\n * allow render greyed out and inert rather than disappearing.\n */\nexport function ToolPalette(props: ToolPaletteProps) {\n const {\n tools, orientation = 'vertical', className, lookupShortcut, modeRegistry,\n groupOrder = DEFAULT_GROUP_ORDER,\n } = props;\n const list = Object.values(tools.registry);\n const groups = partitionByGroup(list);\n const groupKeys = orderedGroupKeys(groups, groupOrder);\n const cls = [s.palette, orientation === 'horizontal' && s.horizontal, className]\n .filter(Boolean).join(' ');\n\n // Flat, in DOM order — the roving-tabindex hook indexes by this order.\n const ordered = groupKeys.flatMap((k) => groups.get(k)!);\n const eligibility = ordered.map(\n (tool) => (modeRegistry ? eligibleContribution(modeRegistry, tool) : true),\n );\n const activeIndex = ordered.findIndex((t) => t.id === tools.active);\n const roving = useRovingTabIndex({\n items: eligibility.map((enabled) => ({ disabled: !enabled })),\n itemClassName: s.paletteBtn,\n // An ineligible active tool can't hold the tab stop; fall back to the\n // hook's first-enabled default.\n ...(activeIndex >= 0 && eligibility[activeIndex] ? { tabStopIndex: activeIndex } : {}),\n });\n let index = -1;\n\n return (\n <div\n ref={roving.rootRef}\n className={cls}\n role=\"toolbar\"\n aria-label=\"Tools\"\n >\n {groupKeys.map((key, i) => (\n <Fragment key={key}>\n {i > 0 && (\n <div\n className={s.separator}\n role=\"separator\"\n aria-orientation={orientation === 'horizontal' ? 'vertical' : 'horizontal'}\n />\n )}\n <ToolGroup orientation={orientation} groupKey={key}>\n {groups.get(key)!.map((tool) => {\n const i = ++index;\n const label = tool.presentation?.label ?? tool.id;\n const shortcut = tool.presentation?.shortcut\n ?? formatShortcut(lookupShortcut ? lookupShortcut(tool.id) : tool.keybinding);\n const enabled = eligibility[i];\n const modeName = modeRegistry ? modeRegistry.current().id : undefined;\n const resolvedTitle = !enabled && modeName\n ? `${label}${shortcut ? ` (${shortcut})` : ''} — disabled in ${modeName} mode`\n : undefined;\n return (\n <ToolButton\n key={tool.id}\n icon={resolveIcon(tool)}\n label={label}\n shortcut={shortcut}\n active={tools.active === tool.id}\n tabbable={roving.tabIndexFor(i) === 0}\n ariaDisabled={!enabled}\n className={[s.paletteBtn, !enabled && s.ineligibleBtn].filter(Boolean).join(' ')}\n title={resolvedTitle}\n onClick={enabled ? () => tools.setActive(tool.id) : () => {}}\n onKeyDown={roving.onKeyDown(i)}\n />\n );\n })}\n </ToolGroup>\n </Fragment>\n ))}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"createKeyframeLayer-Czj6Y235.js","names":["s","_Fragment","s","dlog","plotToModel","modelToPlot","Plot2D","snapToNearest","hitTestAnchor","r2","radius","best","i","anchors","dx","pointer","dy","d2","hitTestCurve","segIdx","segments","samples","last","a","b","abx","aby","apx","apy","ab2","u","cx","cy","t","HANDLE_SIZE_TOKENS","handleSize","tokenPx","token","resolved","handleHalf","CurveEditor_module_default","NO_MODIFIERS","readModifiers","LayeredCurveEditor","props","historyEnabled","modelRange","useMemo","xRange","yRange","plotSize","width","height","layersRef","useRef","layers","modelRangeRef","plotSizeRef","plotRef","makeCtx","useCallback","mr","ps","p","activeRef","activeLayerId","setActiveLayerId","useState","pastRef","futureRef","snapshot","m","restore","current","prev","snap","onLayerChange","undo","past","redo","future","next","onGestureMoveRef","onGestureEndRef","onGestureCancelRef","sessionRef","cleanupGesture","findLayerState","id","h","model","ctx","finalState","onLayerCommit","restored","installGesture","startStates","startSelfState","layerId","openPointerSession","down","onSvgPointerDown","modifiers","e","ls","nativeEvent","coords","preEventSnapshot","hit","prevState","committed","gesture","pendingCommit","onSvgKeyDown","k","renderCtxBase","cls","className","children","SAMPLES_PER_SEGMENT","KEY_HIT_PX","HANDLE_HIT_PX","CURVE_HIT_PX","KEY_HALF","HANDLE_RADIUS","SHIFT_MULTIPLIER","HANDLE_STEP","keyframeLayerState","clampTo","range","v","bezierOf","key","moveKeyTo","moved","keys","index","rest","at","selectedKey","applyKeyframeDrag","state","drag","createKeyframeLayer","cfg","label","formatX","x","snapRadiusPx","easingInto","d","seg","cubicBezierEasing","resolveEasing","segmentSamples","out","ease","pts","j","activeBezier","handlePoints","xf","yf","bezier","path","render","shown","curve","dragIndex","Fragment","x0","x1","h1","h2","hitTest","plot","c","keyGesture","perPx","handleGesture","segment","handle","onPointerDown","extra","onKeyDown","target","activate","mult","keyEl","stepX","stepY","value","segEl","handleEl"],"sources":["../../src/components/CurveEditor/hitTest.ts","../../src/handles.ts","../../src/components/CurveEditor/CurveEditor.module.css","../../src/components/CurveEditor/LayeredCurveEditor.tsx","../../src/components/CurveEditor/createKeyframeLayer.tsx"],"sourcesContent":["/**\n * Curve-specific hit tests. Generic coord transforms live in\n * `../Plot2D/geometry`; what's here is curve-only (anchor / polyline\n * proximity).\n */\nimport type { Point } from '../Plot2D/geometry';\n\n/**\n * Nearest-anchor hit test. Anchors are already in plot/screen coords.\n * Returns the index of the nearest anchor whose squared distance to\n * the pointer is ≤ radius². Null if no anchor is within radius.\n */\nexport function hitTestAnchor(\n anchors: readonly Point[],\n pointer: Point,\n radius: number,\n): { index: number } | null {\n const r2 = radius * radius;\n let best: { index: number; d2: number } | null = null;\n for (let i = 0; i < anchors.length; i++) {\n const a = anchors[i];\n const dx = a.x - pointer.x;\n const dy = a.y - pointer.y;\n const d2 = dx * dx + dy * dy;\n if (d2 > r2) continue;\n if (best === null || d2 < best.d2) best = { index: i, d2 };\n }\n return best ? { index: best.index } : null;\n}\n\n/**\n * Hit test against a per-segment sampled polyline. Each entry in\n * `segments` is the sample list for one segment (inclusive of\n * endpoints). Returns segment index + t (∈ [0, 1]) of the closest\n * point on the polyline within radius. Null if nothing is in range.\n *\n * Distance is measured to the line-segment chords between adjacent\n * samples, not just to the samples themselves — so sparse sampling\n * still produces accurate hits along the chord.\n */\nexport function hitTestCurve(\n segments: readonly (readonly Point[])[],\n pointer: Point,\n radius: number,\n): { segIdx: number; t: number } | null {\n const r2 = radius * radius;\n let best: { segIdx: number; t: number; d2: number } | null = null;\n for (let segIdx = 0; segIdx < segments.length; segIdx++) {\n const samples = segments[segIdx];\n if (samples.length < 2) continue;\n const last = samples.length - 1;\n for (let i = 0; i < last; i++) {\n const a = samples[i];\n const b = samples[i + 1];\n const abx = b.x - a.x;\n const aby = b.y - a.y;\n const apx = pointer.x - a.x;\n const apy = pointer.y - a.y;\n const ab2 = abx * abx + aby * aby;\n let u = ab2 > 0 ? (apx * abx + apy * aby) / ab2 : 0;\n if (u < 0) u = 0;\n else if (u > 1) u = 1;\n const cx = a.x + u * abx;\n const cy = a.y + u * aby;\n const dx = cx - pointer.x;\n const dy = cy - pointer.y;\n const d2 = dx * dx + dy * dy;\n if (d2 > r2) continue;\n const t = (i + u) / last;\n if (best === null || d2 < best.d2) best = { segIdx, t, d2 };\n }\n }\n return best ? { segIdx: best.segIdx, t: best.t } : null;\n}\n","import { tokenPx } from '@weasel-js/theme';\nimport type { ResolvedTheme } from '@weasel-js/theme';\n\n/**\n * The handle sizes the theme publishes: the default rank, the inert one a\n * locked or pinned point wears, and the emphasized one for a handle that is\n * its own category.\n */\nexport const HANDLE_SIZE_TOKENS = [\n '--wzl-handle-size', '--wzl-handle-size-sm', '--wzl-handle-size-lg',\n] as const;\n\n/** One of {@link HANDLE_SIZE_TOKENS}. */\nexport type HandleSizeToken = (typeof HANDLE_SIZE_TOKENS)[number];\n\n/**\n * A handle's edge in px, for code that draws a handle instead of styling one.\n *\n * CSS reaches `--wzl-handle-*` directly; SVG geometry attributes and canvas\n * cannot, so they come through here and the number stays written once, in the\n * theme definition.\n */\nexport function handleSize(token: HandleSizeToken, resolved?: ResolvedTheme): number {\n return tokenPx(token, resolved);\n}\n\n/** Half a handle's edge — what an SVG rect centered on a point offsets by. */\nexport function handleHalf(token: HandleSizeToken, resolved?: ResolvedTheme): number {\n return handleSize(token, resolved) / 2;\n}\n",".root {\n /* Component-local vars layered over the theme tokens. Each var resolves\n * to a semantic token from @weasel-js/theme; consumers override\n * either the curve-* var (component scope) or the wzl-* token (app\n * scope) without touching this file.\n *\n * Background / grid / axis tokens live on Plot2D now (this component\n * composes Plot2D, which paints the background and chrome). */\n --curve-line: var(--wzl-curve-color);\n --curve-line-width: var(--wzl-curve-width);\n --curve-fill: color-mix(in srgb, var(--curve-line) 30%, transparent);\n --curve-anchor-fill: var(--wzl-surface);\n --curve-anchor-stroke: var(--curve-line);\n --curve-anchor-active-fill: var(--curve-line);\n --curve-pinned-fill: var(--wzl-fg-subtle);\n}\n\n.fill {\n fill: var(--curve-fill);\n stroke: none;\n pointer-events: none;\n}\n\n.curve {\n stroke: var(--curve-line);\n stroke-width: var(--curve-line-width);\n fill: none;\n pointer-events: stroke;\n}\n\n.anchor {\n fill: var(--curve-anchor-fill);\n stroke: var(--curve-anchor-stroke);\n stroke-width: 1.5;\n cursor: grab;\n}\n\n.anchor:hover {\n fill: var(--curve-anchor-active-fill);\n}\n\n.anchor.active {\n fill: var(--curve-anchor-active-fill);\n cursor: grabbing;\n}\n\n.anchor.pinned {\n fill: var(--curve-pinned-fill);\n cursor: default;\n}\n\n/* Caller-set locked anchors share the gray pinned fill but signal\n * \"not interactive at all\" via the not-allowed cursor. */\n.anchor.locked {\n cursor: not-allowed;\n}\n\n/* Endpoint vertices render as diamonds (rotated squares) instead of\n * circles, so they read as a different category of handle. The shape\n * is enforced inline via SVG <rect transform>; this class only adds\n * the hover/active styling. */\n.endpoint {\n /* No fill / stroke overrides — endpoint visuals reuse .anchor /\n * .anchor.pinned / .anchor.active styling. The class exists as a\n * marker for future per-endpoint styling needs. */\n}\n\n/* When the consumer opts into hiding non-interactive handles, pinned\n * endpoints disappear entirely. */\n.hidden {\n display: none;\n}\n\n/* Focus is drawn on the mark itself: an outline on an SVG shape rings its\n bounding box, which the nearest scroll container clips. */\n.anchor:focus-visible {\n outline: none;\n stroke: var(--wzl-focus-ring);\n stroke-width: 2;\n}\n\n/* ── keyframe layer ─────────────────────────────────────────────────── */\n\n.keyframe {\n fill: var(--curve-key-fill, var(--wzl-fg-muted));\n cursor: grab;\n}\n\n.keyframe[aria-current='true'] { fill: var(--curve-selected, var(--wzl-accent-strong)); }\n.keyframe:focus-visible,\n.handle:focus-visible {\n outline: none;\n stroke: var(--wzl-focus-ring);\n stroke-width: 2;\n}\n\n.segmentTarget:focus-visible {\n outline: none;\n stroke: var(--wzl-focus-ring);\n stroke-opacity: 0.5;\n}\n\n/* The committed key holds while its ghost tracks the pointer, so a drag\n reads as a move from somewhere to somewhere. */\n.keyframe[data-dragging='true'] { opacity: 0.4; }\n\n.keyframeGhost {\n fill: var(--curve-selected-soft, var(--wzl-accent-soft));\n stroke: var(--curve-selected, var(--wzl-accent-strong));\n stroke-width: 1;\n stroke-dasharray: 2 2;\n pointer-events: none;\n}\n\n.segmentBand {\n fill: var(--curve-selected-soft, var(--wzl-accent-soft));\n pointer-events: none;\n}\n\n/* Carries focus and a name for each segment; hit testing is geometric. */\n.segmentTarget {\n fill: none;\n stroke: transparent;\n stroke-width: 8;\n pointer-events: none;\n}\n\n.handle {\n fill: var(--wzl-surface);\n stroke: var(--curve-selected, var(--wzl-accent-strong));\n stroke-width: 1;\n cursor: grab;\n}\n\n.handleStem {\n stroke: var(--curve-selected, var(--wzl-accent-strong));\n stroke-width: 1;\n pointer-events: none;\n}\n","import {\n useCallback, useEffect, useMemo, useRef, useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\nimport { openPointerSession, type PointerSession } from '@weasel-js/core';\nimport {\n Plot2D,\n type Plot2DHandle,\n type GridSettings,\n type AxesSettings,\n type TickSettings,\n} from '../Plot2D';\nimport {\n modelToPlot, plotToModel,\n type ModelRange,\n} from '../Plot2D/geometry';\nimport { dlog } from '../../dlog';\nimport s from './CurveEditor.module.css';\nimport type {\n CurveLayer, LayerCtx, LayerGesture, LayerModifiers, ModelPoint, PlotPoint,\n} from './layerTypes';\n\n/**\n * A layer paired with the state the consumer holds for it. The editor never\n * stores layer state itself.\n */\nexport interface LayerBinding<S = unknown> {\n layer: CurveLayer<S>;\n state: S;\n}\n\n/** Props for {@link LayeredCurveEditor}. */\nexport interface LayeredCurveEditorProps {\n /** Bottom-to-top render order: `layers[0]` paints first, `layers[N-1]`\n * paints on top. Hit-testing runs in reverse (topmost claim wins). */\n layers: ReadonlyArray<LayerBinding<unknown>>;\n\n /** Fires every frame during a gesture with the live in-flight state\n * for the layer that owns the gesture. */\n onLayerChange(id: string, next: unknown): void;\n\n /** Fires once per discrete user action (drag-end, one-shot insert,\n * delete) for the layer that produced the change. `prev` is the\n * layer's state at gesture start. */\n onLayerCommit?(id: string, next: unknown, prev: unknown): void;\n\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 grid?: GridSettings | false | null;\n axes?: AxesSettings | false | null;\n /** Ticks at x values. See `Plot2D.xTicks`. */\n xTicks?: TickSettings | false | null;\n /** Ticks at y values. See `Plot2D.yTicks`. */\n yTicks?: TickSettings | false | null;\n\n /** Built-in undo/redo via Cmd/Ctrl+Z (Shift+Z or Y for redo) on the\n * focused SVG. Snapshots every layer's state on each commit; undo\n * fires `onLayerChange(id, prevState)` for each layer whose state\n * changed. Default `true`. */\n history?: boolean;\n\n /** Accessible name for the plot, which is exposed as a group so the\n * focusable marks layers render inside it stay reachable. */\n 'aria-label'?: string;\n className?: string;\n style?: CSSProperties;\n\n /** Extra SVG content rendered behind all layers (under the lowest\n * layer but above grid/axes). Use this for static chrome that isn't\n * worth modeling as a layer. */\n children?: ReactNode;\n}\n\ninterface ActiveGesture {\n layerId: string;\n gesture: LayerGesture<unknown>;\n startStates: Map<string, unknown>;\n startSelfState: unknown;\n}\n\n/** A cancel carries no event, so a layer's `onCancel` sees no modifiers held. */\nconst NO_MODIFIERS: LayerModifiers = { shift: false, alt: false, meta: false, ctrl: false };\n\nfunction readModifiers(e: PointerEvent | ReactPointerEvent | KeyboardEvent | ReactKeyboardEvent): LayerModifiers {\n return {\n shift: e.shiftKey,\n alt: e.altKey,\n meta: e.metaKey,\n ctrl: e.ctrlKey,\n };\n}\n\n/**\n * A `Plot2D` that hosts a stack of composable curve layers. It owns the\n * pointer gestures and the coordinate mapping; each layer supplies its own\n * drawing, hit testing and gesture behavior.\n *\n * Layer state stays with the consumer: the editor reports changes through\n * `onLayerChange` during a gesture and `onLayerCommit` at its end, and reads\n * the state back from props each frame. That is what lets one layer's drag\n * update another layer's state mid-gesture.\n */\nexport function LayeredCurveEditor(props: LayeredCurveEditorProps) {\n const {\n layers, onLayerChange, onLayerCommit,\n width, height,\n xRange = [0, 1], yRange = [0, 1],\n grid, axes, xTicks, yTicks,\n className, style, children,\n } = props;\n\n const historyEnabled = props.history !== false;\n\n const modelRange: ModelRange = useMemo(\n () => ({ xMin: xRange[0], xMax: xRange[1], yMin: yRange[0], yMax: yRange[1] }),\n [xRange, yRange],\n );\n const plotSize = useMemo(() => ({ width, height }), [width, height]);\n\n // Refs that always hold the latest props — gesture handlers and\n // window listeners close over these refs, never over render-time\n // values, so mid-drag re-renders (including cross-layer state\n // updates) are visible to the next pointermove tick.\n const layersRef = useRef(layers);\n layersRef.current = layers;\n const modelRangeRef = useRef(modelRange);\n modelRangeRef.current = modelRange;\n const plotSizeRef = useRef(plotSize);\n plotSizeRef.current = plotSize;\n\n const plotRef = useRef<Plot2DHandle | null>(null);\n\n // ── Coord helpers ──────────────────────────────────────────────────\n const makeCtx = useCallback((modifiers: LayerModifiers): LayerCtx => {\n const mr = modelRangeRef.current;\n const ps = plotSizeRef.current;\n return {\n modelRange: mr,\n plotSize: ps,\n toPlot: (p) => modelToPlot(p, mr, ps),\n toModel: (p) => plotToModel(p, mr, ps),\n modifiers,\n };\n }, []);\n\n // ── Gesture routing ────────────────────────────────────────────────\n const activeRef = useRef(null as ActiveGesture | null);\n const [activeLayerId, setActiveLayerId] = useState<string | null>(null);\n\n // ── History (whole-state snapshots) ────────────────────────────────\n const pastRef = useRef<Map<string, unknown>[]>([]);\n const futureRef = useRef<Map<string, unknown>[]>([]);\n\n const snapshot = useCallback((): Map<string, unknown> => {\n const m = new Map<string, unknown>();\n for (const b of layersRef.current) m.set(b.layer.id, b.state);\n return m;\n }, []);\n\n const restore = useCallback((snap: Map<string, unknown>) => {\n const current = layersRef.current;\n for (const b of current) {\n const prev = snap.get(b.layer.id);\n if (prev !== undefined && prev !== b.state) {\n onLayerChange(b.layer.id, prev);\n }\n }\n }, [onLayerChange]);\n\n const undo = useCallback(() => {\n if (!historyEnabled) return;\n const past = pastRef.current;\n if (past.length === 0) return;\n const prev = past.pop()!;\n futureRef.current.push(snapshot());\n restore(prev);\n }, [historyEnabled, snapshot, restore]);\n\n const redo = useCallback(() => {\n if (!historyEnabled) return;\n const future = futureRef.current;\n if (future.length === 0) return;\n const next = future.pop()!;\n pastRef.current.push(snapshot());\n restore(next);\n }, [historyEnabled, snapshot, restore]);\n\n // ── Pointer routing during an active gesture ───────────────────────\n // The session's callbacks are fixed at gesture start, so they delegate\n // through refs holding the latest per-render impl — a mid-drag re-render\n // must reach the next pointermove tick.\n const onGestureMoveRef = useRef<(e: PointerEvent) => void>(() => {});\n const onGestureEndRef = useRef<(e: PointerEvent) => void>(() => {});\n const onGestureCancelRef = useRef<() => void>(() => {});\n\n const sessionRef = useRef<PointerSession | null>(null);\n\n const cleanupGesture = useCallback(() => {\n sessionRef.current = null;\n activeRef.current = null;\n setActiveLayerId(null);\n }, []);\n\n const findLayerState = useCallback((id: string): unknown | undefined => {\n for (const b of layersRef.current) if (b.layer.id === id) return b.state;\n return undefined;\n }, []);\n\n onGestureMoveRef.current = (e: PointerEvent) => {\n const a = activeRef.current;\n if (!a) return;\n const h = plotRef.current;\n if (!h) return;\n const model = h.clientToModel(e);\n const current = findLayerState(a.layerId);\n if (current === undefined) return;\n const ctx = makeCtx(readModifiers(e));\n const next = a.gesture.onMove(current, model, e, ctx);\n if (next !== current) onLayerChange(a.layerId, next);\n };\n\n onGestureEndRef.current = (e: PointerEvent) => {\n const a = activeRef.current;\n if (!a) return;\n const current = findLayerState(a.layerId);\n if (current === undefined) { cleanupGesture(); return; }\n const ctx = makeCtx(readModifiers(e));\n const finalState = a.gesture.onCommit ? a.gesture.onCommit(current, ctx) : current;\n if (finalState !== current) onLayerChange(a.layerId, finalState);\n if (historyEnabled) {\n pastRef.current.push(a.startStates);\n futureRef.current = [];\n }\n if (onLayerCommit) onLayerCommit(a.layerId, finalState, a.startSelfState);\n cleanupGesture();\n };\n\n onGestureCancelRef.current = () => {\n const a = activeRef.current;\n if (!a) return;\n const current = findLayerState(a.layerId);\n if (current === undefined) { cleanupGesture(); return; }\n const ctx = makeCtx(NO_MODIFIERS);\n const restored = a.gesture.onCancel ? a.gesture.onCancel(current, ctx) : a.startSelfState;\n if (restored !== current) onLayerChange(a.layerId, restored);\n cleanupGesture();\n };\n\n // No pointer capture: consumers render their own SVG chrome into the plot\n // through `children`, and capture would retarget pointerup away from it.\n const installGesture = useCallback((\n layerId: string,\n down: ReactPointerEvent<SVGSVGElement>,\n gesture: LayerGesture<unknown>,\n ) => {\n const startStates = snapshot();\n const startSelfState = startStates.get(layerId);\n activeRef.current = {\n layerId, gesture,\n startStates,\n startSelfState,\n };\n setActiveLayerId(layerId);\n sessionRef.current = openPointerSession(down.currentTarget, down, {\n onMove: (e) => onGestureMoveRef.current(e),\n onEnd: (e) => onGestureEndRef.current(e),\n onCancel: () => onGestureCancelRef.current(),\n }, { capture: false });\n }, [snapshot]);\n\n // ── pointerdown dispatch ───────────────────────────────────────────\n const onSvgPointerDown = useCallback((\n e: ReactPointerEvent<SVGSVGElement>,\n coords: { plot: PlotPoint; model: ModelPoint },\n ) => {\n if (activeRef.current) return; // ignore secondary touches mid-gesture\n const modifiers = readModifiers(e);\n const ctx = makeCtx(modifiers);\n const ls = layersRef.current;\n const nativeEvent = e.nativeEvent;\n\n dlog('layered-curve-editor', 'pointerdown', { plot: coords.plot, model: coords.model, layers: ls.length });\n\n // Capture the pre-event snapshot once; reuse for history if any\n // path produces a commit (gesture-start commit or one-shot).\n const preEventSnapshot = snapshot();\n\n // Top-to-bottom hit test.\n for (let i = ls.length - 1; i >= 0; i--) {\n const b = ls[i];\n const hit = b.layer.hitTest?.(b.state, coords.plot, ctx);\n if (!hit) continue;\n // Found a claim. onPointerDown may start a gesture, absorb the\n // click, or commit a one-shot edit via extra.commit.\n const prevState = b.state;\n let committed: unknown = undefined;\n const gesture = b.layer.onPointerDown?.(\n prevState, hit, nativeEvent, ctx,\n {\n plot: coords.plot,\n model: coords.model,\n commit(next) { committed = next; onLayerChange(b.layer.id, next); },\n },\n );\n e.stopPropagation();\n if (gesture) {\n installGesture(b.layer.id, e, gesture);\n return;\n }\n if (committed !== undefined) {\n if (historyEnabled) {\n pastRef.current.push(preEventSnapshot);\n futureRef.current = [];\n }\n onLayerCommit?.(b.layer.id, committed, prevState);\n }\n return;\n }\n\n // No hit — empty space dispatch, top-to-bottom.\n let pendingCommit: { id: string; next: unknown; prev: unknown } | null = null;\n for (let i = ls.length - 1; i >= 0; i--) {\n const b = ls[i];\n if (!b.layer.onEmptyPointerDown) continue;\n const prevState = b.state;\n let committed: unknown = undefined;\n const gesture = b.layer.onEmptyPointerDown(\n prevState, coords.model, nativeEvent, ctx,\n {\n plot: coords.plot,\n model: coords.model,\n commit(next) {\n committed = next;\n onLayerChange(b.layer.id, next);\n },\n },\n );\n if (gesture) {\n // If onEmptyPointerDown also published a commit (e.g. click-curve\n // insert publishes the new point then drags it), the gesture's\n // startStates already capture the post-insert state; the commit\n // for history is the *pre*-event snapshot, written when the\n // gesture eventually finishes via the gesture-commit path. We\n // override the gesture's startStates so undo restores correctly.\n installGesture(b.layer.id, e, gesture);\n if (committed !== undefined && activeRef.current !== null) {\n (activeRef.current as ActiveGesture).startStates = preEventSnapshot;\n (activeRef.current as ActiveGesture).startSelfState = preEventSnapshot.get(b.layer.id);\n }\n return;\n }\n if (committed !== undefined) {\n pendingCommit = { id: b.layer.id, next: committed, prev: prevState };\n break;\n }\n }\n if (pendingCommit) {\n if (historyEnabled) {\n pastRef.current.push(preEventSnapshot);\n futureRef.current = [];\n }\n onLayerCommit?.(pendingCommit.id, pendingCommit.next, pendingCommit.prev);\n }\n }, [makeCtx, installGesture, onLayerChange, onLayerCommit, historyEnabled, snapshot]);\n\n // ── keyboard ───────────────────────────────────────────────────────\n const onSvgKeyDown = useCallback((e: ReactKeyboardEvent<SVGSVGElement>) => {\n const modifiers = readModifiers(e);\n const ctx = makeCtx(modifiers);\n const ls = layersRef.current;\n // History first.\n if (historyEnabled && (e.metaKey || e.ctrlKey)) {\n const k = e.key.toLowerCase();\n if (k === 'z') {\n if (e.shiftKey) redo();\n else undo();\n e.preventDefault();\n return;\n }\n if (k === 'y') { redo(); e.preventDefault(); return; }\n }\n // Then layers (top-to-bottom).\n for (let i = ls.length - 1; i >= 0; i--) {\n const b = ls[i];\n if (!b.layer.onKeyDown) continue;\n const preEventSnapshot = snapshot();\n let committed: unknown = undefined;\n b.layer.onKeyDown(b.state, e.nativeEvent, ctx, {\n commit(next) { committed = next; onLayerChange(b.layer.id, next); },\n });\n if (committed !== undefined) {\n if (historyEnabled) {\n pastRef.current.push(preEventSnapshot);\n futureRef.current = [];\n }\n onLayerCommit?.(b.layer.id, committed, b.state);\n }\n // The layer prevents default on the native event, which the synthetic\n // event's `isDefaultPrevented` does not observe.\n if (e.nativeEvent.defaultPrevented) return;\n }\n }, [historyEnabled, undo, redo, makeCtx, snapshot, onLayerChange, onLayerCommit]);\n\n useEffect(() => () => { sessionRef.current?.cancel(); }, []);\n\n // ── render ─────────────────────────────────────────────────────────\n const renderCtxBase: Omit<LayerCtx, 'modifiers'> = useMemo(() => ({\n modelRange,\n plotSize,\n toPlot: (p) => modelToPlot(p, modelRange, plotSize),\n toModel: (p) => plotToModel(p, modelRange, plotSize),\n }), [modelRange, plotSize]);\n\n const cls = [s.root, className].filter(Boolean).join(' ');\n\n return (\n <Plot2D\n ref={plotRef}\n className={cls}\n style={style}\n width={width}\n height={height}\n xRange={xRange}\n yRange={yRange}\n grid={grid}\n axes={axes}\n xTicks={xTicks}\n yTicks={yTicks}\n tabIndex={historyEnabled ? 0 : undefined}\n role=\"group\"\n aria-label={props['aria-label']}\n onPointerDown={onSvgPointerDown}\n onKeyDown={onSvgKeyDown}\n >\n {children}\n {layers.map((b) => {\n const ctx = {\n ...renderCtxBase,\n modifiers: { shift: false, alt: false, meta: false, ctrl: false },\n isActive: activeLayerId === b.layer.id,\n };\n return (\n <g key={b.layer.id} data-layer-id={b.layer.id}>\n {b.layer.render(b.state, ctx)}\n </g>\n );\n })}\n </Plot2D>\n );\n}\n","/**\n * Keyframe layer for LayeredCurveEditor: a value-over-time curve whose shape\n * between two keys is the easing on the later one, with draggable keys and\n * draggable cubic-bezier handles on the selected segment.\n *\n * Distinct from `createFunctionLayer`, which interpolates a spline through\n * its anchors. Here the keys are exact and the easing approximates between\n * them, so the two do not share curve maths.\n */\nimport type { ReactNode } from 'react';\nimport { cubicBezierEasing, resolveEasing, type EasingFn, type Keyframe } from '@weasel-js/core';\nimport { hitTestAnchor, hitTestCurve } from './hitTest';\nimport { handleHalf } from '../../handles';\nimport { SNAP_RADIUS_PX, snapToNearest } from '../../snap';\nimport s from './CurveEditor.module.css';\nimport type {\n CurveLayer, EmptyDownArgs, KeyDownArgs, LayerCtx, LayerGesture, LayerHit, LayerRenderCtx, PlotPoint,\n} from './layerTypes';\n\ntype Bezier = readonly [number, number, number, number];\n\n/** A gesture in flight. The committed keys hold still underneath it. */\nexport type KeyframeDrag =\n | { kind: 'key'; index: number; t: number; value: number }\n | { kind: 'handle'; segment: number; bezier: Bezier };\n\n/**\n * The state a keyframe layer owns, held by the consumer and round-tripped\n * through `LayeredCurveEditor`'s `onLayerChange`.\n */\nexport interface KeyframeLayerState {\n /** Sorted ascending by `t`. */\n keys: readonly Keyframe<number>[];\n selectedKey: number | null;\n /** Index of the key the selected segment runs into. Its bezier handles show. */\n selectedSegment: number | null;\n drag: KeyframeDrag | null;\n}\n\n/** Configuration for {@link createKeyframeLayer}. */\nexport interface KeyframeLayerConfig {\n /** Layer id; default `'keyframes'`. */\n id?: string;\n /** Names the curve in each mark's accessible name. Default `'Curve'`. */\n label?: string;\n /** Formats a key time for accessible names. Default: rounded number. */\n formatX?: (x: number) => string;\n /** Times a dragged key snaps to. Holding alt defeats the snap. */\n snapX?: readonly number[];\n /** Snap reach, in plot pixels. Default 6. */\n snapRadiusPx?: number;\n /** Bounds for a key's time. Default: unbounded. */\n xClamp?: readonly [number, number];\n /** Bounds for a key's value. Default: unbounded. */\n yClamp?: readonly [number, number];\n /** One arrow-key step in model units; shift takes ten. Default: 1% of the\n * plot's range on that axis. */\n step?: { x?: number; y?: number };\n}\n\nconst SAMPLES_PER_SEGMENT = 16;\nconst KEY_HIT_PX = 8;\nconst HANDLE_HIT_PX = 8;\nconst CURVE_HIT_PX = 6;\nconst KEY_HALF = handleHalf('--wzl-handle-size');\nconst HANDLE_RADIUS = 3.5;\nconst SHIFT_MULTIPLIER = 10;\nconst HANDLE_STEP = 0.01;\n\n/** A keyframe layer state with nothing selected and no gesture in flight. */\nexport function keyframeLayerState(keys: readonly Keyframe<number>[]): KeyframeLayerState {\n return { keys, selectedKey: null, selectedSegment: null, drag: null };\n}\n\nfunction clampTo(v: number, range?: readonly [number, number]): number {\n return range ? Math.min(range[1], Math.max(range[0], v)) : v;\n}\n\nfunction bezierOf(key: Keyframe<number> | undefined): Bezier | null {\n const e = key?.easing;\n return typeof e === 'object' && e !== null && 'bezier' in e ? e.bezier : null;\n}\n\nfunction moveKeyTo(\n keys: readonly Keyframe<number>[], index: number, t: number, value: number,\n): { keys: Keyframe<number>[]; selectedKey: number } {\n const moved = { ...keys[index], t, value };\n const rest = keys.filter((_, i) => i !== index);\n const at = rest.findIndex((k) => k.t > t);\n const selectedKey = at === -1 ? rest.length : at;\n rest.splice(selectedKey, 0, moved);\n return { keys: rest, selectedKey };\n}\n\n/**\n * The keys a state's drag would leave behind: a dragged key re-sorted into\n * place, or a dragged handle's control points written onto the key its\n * segment runs into. `selectedKey` follows a moved key to its new index; a\n * key dropped where it started returns the same `keys` array.\n */\nexport function applyKeyframeDrag(\n state: KeyframeLayerState,\n): { keys: readonly Keyframe<number>[]; selectedKey: number | null } {\n const { drag, keys } = state;\n if (!drag) return { keys, selectedKey: state.selectedKey };\n if (drag.kind === 'key') {\n const k = keys[drag.index];\n if (k && k.t === drag.t && k.value === drag.value) return { keys, selectedKey: drag.index };\n return moveKeyTo(keys, drag.index, drag.t, drag.value);\n }\n const next = keys.slice();\n next[drag.segment] = { ...keys[drag.segment], easing: { bezier: drag.bezier } };\n return { keys: next, selectedKey: state.selectedKey };\n}\n\n/**\n * Builds a keyframe layer for `LayeredCurveEditor`. Model x is time and model\n * y is value; each segment is drawn through the easing on the key it runs\n * into. Every key, segment and handle is focusable and named, and the arrow\n * keys move whichever one has focus.\n */\nexport function createKeyframeLayer(cfg: KeyframeLayerConfig = {}): CurveLayer<KeyframeLayerState> {\n const id = cfg.id ?? 'keyframes';\n const label = cfg.label ?? 'Curve';\n const formatX = cfg.formatX ?? ((x: number) => String(Math.round(x)));\n const snapRadiusPx = cfg.snapRadiusPx ?? SNAP_RADIUS_PX;\n\n // A live handle drag is previewed straight from its control points: a\n // fresh spec per pointermove through `resolveEasing` would leave one\n // permanent cache entry per pixel of drag.\n function easingInto(state: KeyframeLayerState, keys: readonly Keyframe<number>[], seg: number): EasingFn {\n const d = state.drag;\n if (d?.kind === 'handle' && d.segment === seg) return cubicBezierEasing(...d.bezier);\n return resolveEasing(keys[seg].easing);\n }\n\n function segmentSamples(state: KeyframeLayerState, keys: readonly Keyframe<number>[], ctx: LayerCtx): PlotPoint[][] {\n const out: PlotPoint[][] = [];\n for (let i = 1; i < keys.length; i++) {\n const a = keys[i - 1];\n const b = keys[i];\n const ease = easingInto(state, keys, i);\n const pts: PlotPoint[] = [];\n for (let j = 0; j <= SAMPLES_PER_SEGMENT; j++) {\n const u = j / SAMPLES_PER_SEGMENT;\n pts.push(ctx.toPlot({ x: a.t + (b.t - a.t) * u, y: a.value + (b.value - a.value) * ease(u) }));\n }\n out.push(pts);\n }\n return out;\n }\n\n function activeBezier(state: KeyframeLayerState): Bezier | null {\n const seg = state.selectedSegment;\n if (seg === null || seg < 1 || seg >= state.keys.length) return null;\n const d = state.drag;\n if (d?.kind === 'handle' && d.segment === seg) return d.bezier;\n return bezierOf(state.keys[seg]);\n }\n\n function handlePoints(state: KeyframeLayerState, bezier: Bezier, ctx: LayerCtx): [PlotPoint, PlotPoint] {\n const a = state.keys[state.selectedSegment! - 1];\n const b = state.keys[state.selectedSegment!];\n const at = (xf: number, yf: number) =>\n ctx.toPlot({ x: a.t + xf * (b.t - a.t), y: a.value + yf * (b.value - a.value) });\n return [at(bezier[0], bezier[1]), at(bezier[2], bezier[3])];\n }\n\n const path = (pts: readonly PlotPoint[]): string =>\n pts.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x.toFixed(2)},${p.y.toFixed(2)}`).join('');\n\n // ── render ──────────────────────────────────────────────────────────\n function render(state: KeyframeLayerState, ctx: LayerRenderCtx): ReactNode {\n const shown = state.drag?.kind === 'key' ? applyKeyframeDrag(state).keys : state.keys;\n const segments = segmentSamples(state, shown, ctx);\n const curve = segments.flatMap((pts, i) => (i === 0 ? pts : pts.slice(1)));\n const seg = state.selectedSegment;\n const bezier = activeBezier(state);\n const dragIndex = state.drag?.kind === 'key' ? state.drag.index : null;\n\n return (\n <>\n {seg !== null && seg >= 1 && seg < shown.length ? (() => {\n const x0 = ctx.toPlot({ x: shown[seg - 1].t, y: 0 }).x;\n const x1 = ctx.toPlot({ x: shown[seg].t, y: 0 }).x;\n return (\n <rect\n className={s.segmentBand}\n x={Math.min(x0, x1)}\n y={0}\n width={Math.abs(x1 - x0)}\n height={ctx.plotSize.height}\n />\n );\n })() : null}\n {curve.length > 1 ? <path data-curve-element=\"curve\" className={s.curve} d={path(curve)} /> : null}\n {segments.map((pts, i) => (\n <path\n key={`seg-${i + 1}`}\n className={s.segmentTarget}\n d={path(pts)}\n role=\"button\"\n tabIndex={0}\n aria-label={`${label} segment into ${formatX(shown[i + 1].t)}`}\n aria-current={seg === i + 1 ? 'true' : undefined}\n data-segment-index={i + 1}\n />\n ))}\n {bezier ? (() => {\n const [h1, h2] = handlePoints(state, bezier, ctx);\n const a = ctx.toPlot({ x: state.keys[seg! - 1].t, y: state.keys[seg! - 1].value });\n const b = ctx.toPlot({ x: state.keys[seg!].t, y: state.keys[seg!].value });\n return (\n <>\n <line className={s.handleStem} x1={a.x} y1={a.y} x2={h1.x} y2={h1.y} />\n <line className={s.handleStem} x1={b.x} y1={b.y} x2={h2.x} y2={h2.y} />\n {[h1, h2].map((h, i) => (\n <circle\n key={`handle-${i}`}\n className={s.handle}\n cx={h.x}\n cy={h.y}\n r={HANDLE_RADIUS}\n role=\"button\"\n tabIndex={0}\n aria-label={`${label} bezier handle ${i + 1}`}\n data-handle-index={i}\n />\n ))}\n </>\n );\n })() : null}\n {state.keys.map((k, i) => {\n const p = ctx.toPlot({ x: k.t, y: k.value });\n return (\n <rect\n key={`key-${i}`}\n className={s.keyframe}\n x={p.x - KEY_HALF}\n y={p.y - KEY_HALF}\n width={KEY_HALF * 2}\n height={KEY_HALF * 2}\n transform={`rotate(45 ${p.x} ${p.y})`}\n role=\"button\"\n tabIndex={0}\n aria-label={`${label} key at ${formatX(k.t)}`}\n aria-current={state.selectedKey === i ? 'true' : undefined}\n data-keyframe-index={i}\n data-dragging={dragIndex === i ? 'true' : undefined}\n />\n );\n })}\n {state.drag?.kind === 'key' ? (() => {\n const p = ctx.toPlot({ x: state.drag.t, y: state.drag.value });\n return (\n <rect\n aria-hidden=\"true\"\n className={s.keyframeGhost}\n x={p.x - KEY_HALF}\n y={p.y - KEY_HALF}\n width={KEY_HALF * 2}\n height={KEY_HALF * 2}\n transform={`rotate(45 ${p.x} ${p.y})`}\n data-keyframe-ghost=\"\"\n />\n );\n })() : null}\n </>\n );\n }\n\n // ── hit test ────────────────────────────────────────────────────────\n function hitTest(state: KeyframeLayerState, plot: PlotPoint, ctx: LayerCtx): LayerHit | null {\n const bezier = activeBezier(state);\n if (bezier) {\n const h = hitTestAnchor(handlePoints(state, bezier, ctx), plot, HANDLE_HIT_PX);\n if (h) return { kind: 'handle', payload: { handle: h.index } };\n }\n const k = hitTestAnchor(state.keys.map((key) => ctx.toPlot({ x: key.t, y: key.value })), plot, KEY_HIT_PX);\n if (k) return { kind: 'key', payload: { index: k.index } };\n const c = hitTestCurve(segmentSamples(state, state.keys, ctx), plot, CURVE_HIT_PX);\n if (c) return { kind: 'segment', payload: { segment: c.segIdx + 1 } };\n return null;\n }\n\n // ── gestures ────────────────────────────────────────────────────────\n function keyGesture(index: number): LayerGesture<KeyframeLayerState> {\n return {\n onMove(state, model, e, ctx) {\n let t = clampTo(model.x, cfg.xClamp);\n if (cfg.snapX && !e.altKey) {\n const perPx = (ctx.modelRange.xMax - ctx.modelRange.xMin) / ctx.plotSize.width;\n t = clampTo(snapToNearest(t, cfg.snapX, Math.abs(perPx) * snapRadiusPx), cfg.xClamp);\n }\n return { ...state, drag: { kind: 'key', index, t, value: clampTo(model.y, cfg.yClamp) } };\n },\n onCommit(state) { return { ...state, ...applyKeyframeDrag(state), drag: null }; },\n onCancel(state) { return { ...state, drag: null }; },\n };\n }\n\n function handleGesture(segment: number, handle: 0 | 1): LayerGesture<KeyframeLayerState> {\n return {\n onMove(state, model) {\n const a = state.keys[segment - 1];\n const b = state.keys[segment];\n const d = state.drag;\n if (!a || !b || d?.kind !== 'handle') return state;\n const xf = b.t === a.t ? 0 : Math.min(1, Math.max(0, (model.x - a.t) / (b.t - a.t)));\n const yf = b.value === a.value ? 0 : (model.y - a.value) / (b.value - a.value);\n const bezier = [...d.bezier] as [number, number, number, number];\n bezier[handle * 2] = xf;\n bezier[handle * 2 + 1] = yf;\n return { ...state, drag: { kind: 'handle', segment, bezier } };\n },\n onCommit(state) { return { ...state, ...applyKeyframeDrag(state), drag: null }; },\n onCancel(state) { return { ...state, drag: null }; },\n };\n }\n\n function onPointerDown(\n state: KeyframeLayerState,\n hit: LayerHit,\n e: PointerEvent,\n _ctx: LayerCtx,\n extra: EmptyDownArgs<KeyframeLayerState>,\n ): LayerGesture<KeyframeLayerState> | void {\n if (e.button !== 0) return;\n if (hit.kind === 'handle') {\n const bezier = activeBezier(state);\n const segment = state.selectedSegment;\n if (!bezier || segment === null) return;\n const { handle } = hit.payload as { handle: 0 | 1 };\n extra.commit({ ...state, drag: { kind: 'handle', segment, bezier } });\n return handleGesture(segment, handle);\n }\n if (hit.kind === 'key') {\n const { index } = hit.payload as { index: number };\n const k = state.keys[index];\n extra.commit({ ...state, selectedKey: index, drag: { kind: 'key', index, t: k.t, value: k.value } });\n return keyGesture(index);\n }\n if (hit.kind === 'segment') {\n const { segment } = hit.payload as { segment: number };\n extra.commit({ ...state, selectedSegment: segment });\n }\n }\n\n // ── keyboard ────────────────────────────────────────────────────────\n function onKeyDown(\n state: KeyframeLayerState,\n e: KeyboardEvent,\n ctx: LayerCtx,\n extra: KeyDownArgs<KeyframeLayerState>,\n ): void {\n const target = e.target as Element | null;\n if (target?.closest?.('[data-layer-id]')?.getAttribute('data-layer-id') !== id) return;\n const activate = e.key === 'Enter' || e.key === ' ';\n const dx = e.key === 'ArrowRight' ? 1 : e.key === 'ArrowLeft' ? -1 : 0;\n const dy = e.key === 'ArrowUp' ? 1 : e.key === 'ArrowDown' ? -1 : 0;\n const mult = e.shiftKey ? SHIFT_MULTIPLIER : 1;\n\n const keyEl = target.closest('[data-keyframe-index]');\n if (keyEl) {\n const index = Number(keyEl.getAttribute('data-keyframe-index'));\n const k = state.keys[index];\n if (!k) return;\n if (activate) {\n e.preventDefault();\n extra.commit({ ...state, selectedKey: index });\n return;\n }\n if (dx === 0 && dy === 0) return;\n e.preventDefault();\n const m = ctx.modelRange;\n const stepX = (cfg.step?.x ?? Math.abs(m.xMax - m.xMin) / 100) * mult;\n const stepY = (cfg.step?.y ?? Math.abs(m.yMax - m.yMin) / 100) * mult;\n const t = clampTo(k.t + dx * stepX, cfg.xClamp);\n const value = clampTo(k.value + dy * stepY, cfg.yClamp);\n if (t === k.t && value === k.value) return;\n extra.commit({ ...state, ...moveKeyTo(state.keys, index, t, value), drag: null });\n return;\n }\n\n const segEl = target.closest('[data-segment-index]');\n if (segEl && activate) {\n e.preventDefault();\n extra.commit({ ...state, selectedSegment: Number(segEl.getAttribute('data-segment-index')) });\n return;\n }\n\n const handleEl = target.closest('[data-handle-index]');\n const bezier = activeBezier(state);\n if (handleEl && bezier && state.selectedSegment !== null && (dx !== 0 || dy !== 0)) {\n e.preventDefault();\n const h = Number(handleEl.getAttribute('data-handle-index'));\n const next = [...bezier] as [number, number, number, number];\n next[h * 2] = Math.min(1, Math.max(0, next[h * 2] + dx * HANDLE_STEP * mult));\n next[h * 2 + 1] += dy * HANDLE_STEP * mult;\n const drag: KeyframeDrag = { kind: 'handle', segment: state.selectedSegment, bezier: next };\n extra.commit({ ...state, ...applyKeyframeDrag({ ...state, drag }), drag: null });\n }\n }\n\n return { id, render, hitTest, onPointerDown, onKeyDown };\n}\n"],"mappings":";;;;;;;;AAYA,SAAgBQ,EACd,GACA,GACA,GAC0B;CAC1B,IAAMC,IAAKC,IAASA,GAChBC,IAA6C;CACjD,KAAK,IAAIC,IAAI,GAAGA,IAAIC,EAAQ,QAAQ,KAAK;EACvC,IAAM,IAAIA,EAAQD,IACZE,IAAK,EAAE,IAAIC,EAAQ,GACnBC,IAAK,EAAE,IAAID,EAAQ,GACnBE,IAAKH,IAAKA,IAAKE,IAAKA;EAC1B,AAAIC,IAAKR,MACLE,MAAS,QAAQM,IAAKN,EAAK,QAAI,IAAO;GAAE,OAAOC;GAAG;EAAG;CAC3D;CACA,OAAOD,IAAO,EAAE,OAAOA,EAAK,MAAM,IAAI;AACxC;AAYA,SAAgBO,EACd,GACA,GACA,GACsC;CACtC,IAAMT,IAAKC,IAASA,GAChBC,IAAyD;CAC7D,KAAK,IAAIQ,IAAS,GAAGA,IAASC,EAAS,QAAQ,KAAU;EACvD,IAAMC,IAAUD,EAASD;EACzB,IAAIE,EAAQ,SAAS,GAAG;EACxB,IAAMC,IAAOD,EAAQ,SAAS;EAC9B,KAAK,IAAIT,IAAI,GAAGA,IAAIU,GAAM,KAAK;GAC7B,IAAMC,IAAIF,EAAQT,IACZY,IAAIH,EAAQT,IAAI,IAChBa,IAAMD,EAAE,IAAID,EAAE,GACdG,IAAMF,EAAE,IAAID,EAAE,GACdI,IAAMZ,EAAQ,IAAIQ,EAAE,GACpBK,IAAMb,EAAQ,IAAIQ,EAAE,GACpBM,IAAMJ,IAAMA,IAAMC,IAAMA,GAC1BI,IAAID,IAAM,KAAKF,IAAMF,IAAMG,IAAMF,KAAOG,IAAM;GAClD,AAAIC,IAAI,IAAG,IAAI,IACNA,IAAI,MAAG,IAAI;GACpB,IAAMC,IAAKR,EAAE,IAAIO,IAAIL,GACfO,IAAKT,EAAE,IAAIO,IAAIJ,GACfZ,IAAKiB,IAAKhB,EAAQ,GAClBC,IAAKgB,IAAKjB,EAAQ,GAClBE,IAAKH,IAAKA,IAAKE,IAAKA;GAC1B,IAAIC,IAAKR,GAAI;GACb,IAAMwB,KAAKrB,IAAIkB,KAAKR;GACpB,CAAIX,MAAS,QAAQM,IAAKN,EAAK,QAAI,IAAO;IAAE;IAAQ;IAAG;GAAG;EAC5D;CACF;CACA,OAAOA,IAAO;EAAE,QAAQA,EAAK;EAAQ,GAAGA,EAAK;CAAE,IAAI;AACrD;;;ACjEA,IAAauB,IAAqB;CAChC;CAAqB;CAAwB;AAC/C;AAYA,SAAgBC,EAAW,GAAwB,GAAkC;CACnF,OAAOC,EAAQC,GAAOC,CAAQ;AAChC;AAGA,SAAgBC,EAAW,GAAwB,GAAkC;CACnF,OAAOJ,EAAWE,GAAOC,CAAQ,IAAI;AACvC;;;;;;;;;;;;;;;;;GE2DMG,IAA+B;CAAE,OAAO;CAAO,KAAK;CAAO,MAAM;CAAO,MAAM;AAAM;AAE1F,SAASC,EAAc,GAA0F;CAC/G,OAAO;EACL,OAAO,EAAE;EACT,KAAK,EAAE;EACP,MAAM,EAAE;EACR,MAAM,EAAE;CACV;AACF;AAYA,SAAgBC,EAAmB,GAAgC;CACjE,IAAM,EACJ,WAAQ,kBAAe,kBACvB,UAAO,WACP,YAAS,CAAC,GAAG,CAAC,GAAG,YAAS,CAAC,GAAG,CAAC,GAC/B,SAAM,SAAM,WAAQ,WACpB,cAAW,UAAO,gBAChBC,GAEEC,IAAiBD,EAAM,YAAY,IAEnCE,IAAyBC,SACtB;EAAE,MAAMC,EAAO;EAAI,MAAMA,EAAO;EAAI,MAAMC,EAAO;EAAI,MAAMA,EAAO;CAAG,IAC5E,CAACD,GAAQC,CAAM,CACjB,GACMC,IAAWH,SAAe;EAAE;EAAO;CAAO,IAAI,CAACI,GAAOC,CAAM,CAAC,GAM7DC,IAAYC,EAAOC,CAAM;CAC/B,EAAU,UAAUA;CACpB,IAAMC,IAAgBF,EAAOR,CAAU;CACvC,EAAc,UAAUA;CACxB,IAAMW,IAAcH,EAAOJ,CAAQ;CACnC,EAAY,UAAUA;CAEtB,IAAMQ,IAAUJ,EAA4B,IAAI,GAG1CK,IAAUC,GAAa,MAAwC;EACnE,IAAMC,IAAKL,EAAc,SACnBM,IAAKL,EAAY;EACvB,OAAO;GACL,YAAYI;GACZ,UAAUC;GACV,SAAS,MAAMzD,EAAY0D,GAAGF,GAAIC,CAAE;GACpC,UAAU,MAAM1D,EAAY2D,GAAGF,GAAIC,CAAE;GACrC;EACF;CACF,GAAG,CAAC,CAAC,GAGCE,IAAYV,EAAO,IAA4B,GAC/C,CAACW,GAAeC,KAAoBC,EAAwB,IAAI,GAGhEC,IAAUd,EAA+B,CAAC,CAAC,GAC3Ce,IAAYf,EAA+B,CAAC,CAAC,GAE7CgB,IAAWV,QAAwC;EACvD,IAAMW,oBAAI,IAAI,IAAqB;EACnC,KAAK,IAAM/C,KAAK6B,EAAU,SAAS,EAAE,IAAI7B,EAAE,MAAM,IAAIA,EAAE,KAAK;EAC5D,OAAO+C;CACT,GAAG,CAAC,CAAC,GAECC,IAAUZ,GAAa,MAA+B;EAC1D,IAAMa,IAAUpB,EAAU;EAC1B,KAAK,IAAM7B,KAAKiD,GAAS;GACvB,IAAMC,IAAOC,EAAK,IAAInD,EAAE,MAAM,EAAE;GAChC,AAAIkD,MAAS,KAAA,KAAaA,MAASlD,EAAE,SACnCoD,EAAcpD,EAAE,MAAM,IAAIkD,CAAI;EAElC;CACF,GAAG,CAACE,CAAa,CAAC,GAEZC,IAAOjB,QAAkB;EAC7B,IAAI,CAACf,GAAgB;EACrB,IAAMiC,IAAOV,EAAQ;EACrB,IAAIU,EAAK,WAAW,GAAG;EACvB,IAAMJ,IAAOI,EAAK,IAAI;EAEtB,AADAT,EAAU,QAAQ,KAAKC,EAAS,CAAC,GACjCE,EAAQE,CAAI;CACd,GAAG;EAAC7B;EAAgByB;EAAUE;CAAO,CAAC,GAEhCO,IAAOnB,QAAkB;EAC7B,IAAI,CAACf,GAAgB;EACrB,IAAMmC,IAASX,EAAU;EACzB,IAAIW,EAAO,WAAW,GAAG;EACzB,IAAMC,IAAOD,EAAO,IAAI;EAExB,AADAZ,EAAQ,QAAQ,KAAKE,EAAS,CAAC,GAC/BE,EAAQS,CAAI;CACd,GAAG;EAACpC;EAAgByB;EAAUE;CAAO,CAAC,GAMhCU,IAAmB5B,QAAwC,CAAC,CAAC,GAC7D6B,IAAkB7B,QAAwC,CAAC,CAAC,GAC5D8B,IAAqB9B,QAAyB,CAAC,CAAC,GAEhD+B,IAAa/B,EAA8B,IAAI,GAE/CgC,IAAiB1B,QAAkB;EAGvC,AAFA,EAAW,UAAU,MACrB,EAAU,UAAU,MACpBM,EAAiB,IAAI;CACvB,GAAG,CAAC,CAAC,GAECqB,IAAiB3B,GAAa,MAAoC;EACtE,KAAK,IAAMpC,KAAK6B,EAAU,SAAS,IAAI7B,EAAE,MAAM,OAAOgE,GAAI,OAAOhE,EAAE;CAErE,GAAG,CAAC,CAAC;CA+BL,AA7BA,EAAiB,WAAW,MAAoB;EAC9C,IAAMD,IAAIyC,EAAU;EACpB,IAAI,CAACzC,GAAG;EACR,IAAMkE,IAAI/B,EAAQ;EAClB,IAAI,CAAC+B,GAAG;EACR,IAAMC,IAAQD,EAAE,cAAc,CAAC,GACzBhB,IAAUc,EAAehE,EAAE,OAAO;EACxC,IAAIkD,MAAY,KAAA,GAAW;EAC3B,IAAMkB,IAAMhC,EAAQjB,EAAc,CAAC,CAAC,GAC9BuC,IAAO1D,EAAE,QAAQ,OAAOkD,GAASiB,GAAO,GAAGC,CAAG;EACpD,AAAIV,MAASR,KAASG,EAAcrD,EAAE,SAAS0D,CAAI;CACrD,GAEA,EAAgB,WAAW,MAAoB;EAC7C,IAAM1D,IAAIyC,EAAU;EACpB,IAAI,CAACzC,GAAG;EACR,IAAMkD,IAAUc,EAAehE,EAAE,OAAO;EACxC,IAAIkD,MAAY,KAAA,GAAW;GAAE,EAAe;GAAG;EAAQ;EACvD,IAAMkB,IAAMhC,EAAQjB,EAAc,CAAC,CAAC,GAC9BkD,IAAarE,EAAE,QAAQ,WAAWA,EAAE,QAAQ,SAASkD,GAASkB,CAAG,IAAIlB;EAO3E,AANImB,MAAenB,KAASG,EAAcrD,EAAE,SAASqE,CAAU,GAC3D/C,MACFuB,EAAQ,QAAQ,KAAK7C,EAAE,WAAW,GAClC,EAAU,UAAU,CAAC,IAEnBsE,KAAeA,EAActE,EAAE,SAASqE,GAAYrE,EAAE,cAAc,GACxE+D,EAAe;CACjB,GAEA,EAAmB,gBAAgB;EACjC,IAAM/D,IAAIyC,EAAU;EACpB,IAAI,CAACzC,GAAG;EACR,IAAMkD,IAAUc,EAAehE,EAAE,OAAO;EACxC,IAAIkD,MAAY,KAAA,GAAW;GAAE,EAAe;GAAG;EAAQ;EACvD,IAAMkB,IAAMhC,EAAQlB,CAAY,GAC1BqD,IAAWvE,EAAE,QAAQ,WAAWA,EAAE,QAAQ,SAASkD,GAASkB,CAAG,IAAIpE,EAAE;EAE3E,AADIuE,MAAarB,KAASG,EAAcrD,EAAE,SAASuE,CAAQ,GAC3DR,EAAe;CACjB;CAIA,IAAMS,IAAiBnC,GACrB,GACA,GACA,MACG;EACH,IAAMoC,IAAc1B,EAAS,GACvB2B,IAAiBD,EAAY,IAAIE,CAAO;EAO9C,AANA,EAAU,UAAU;GAClB;GAAS;GACT;GACA;EACF,GACAhC,EAAiBgC,CAAO,GACxB,EAAW,UAAUC,EAAmBC,EAAK,eAAeA,GAAM;GAChE,SAAS,MAAMlB,EAAiB,QAAQ,CAAC;GACzC,QAAQ,MAAMC,EAAgB,QAAQ,CAAC;GACvC,gBAAgBC,EAAmB,QAAQ;EAC7C,GAAG,EAAE,SAAS,GAAM,CAAC;CACvB,GAAG,CAACd,CAAQ,CAAC,GAGP+B,KAAmBzC,GACvB,GACA,MACG;EACH,IAAII,EAAU,SAAS;EACvB,IAAMsC,IAAY5D,EAAc6D,CAAC,GAC3BZ,IAAMhC,EAAQ2C,CAAS,GACvBE,IAAKnD,EAAU,SACfoD,IAAcF,EAAE;EAEtB,EAAK,wBAAwB,eAAe;GAAE,MAAMG,EAAO;GAAM,OAAOA,EAAO;GAAO,QAAQF,EAAG;EAAO,CAAC;EAIzG,IAAMG,IAAmBrC,EAAS;EAGlC,KAAK,IAAI1D,IAAI4F,EAAG,SAAS,GAAG5F,KAAK,GAAG,KAAK;GACvC,IAAMY,IAAIgF,EAAG5F,IACPgG,IAAMpF,EAAE,MAAM,UAAUA,EAAE,OAAOkF,EAAO,MAAMf,CAAG;GACvD,IAAI,CAACiB,GAAK;GAGV,IAAMC,IAAYrF,EAAE,OAChBsF,GACEC,IAAUvF,EAAE,MAAM,gBACtBqF,GAAWD,GAAKH,GAAad,GAC7B;IACE,MAAMe,EAAO;IACb,OAAOA,EAAO;IACd,OAAO,GAAM;KAAoB,AAAlB,IAAYzB,GAAML,EAAcpD,EAAE,MAAM,IAAIyD,CAAI;IAAG;GACpE,CACF;GAEA,IADAsB,EAAE,gBAAgB,GACdQ,GAAS;IACX,EAAevF,EAAE,MAAM,IAAI+E,GAAGQ,CAAO;IACrC;GACF;GACA,AAAID,MAAc,KAAA,MACZjE,MACFuB,EAAQ,QAAQ,KAAKuC,CAAgB,GACrC,EAAU,UAAU,CAAC,IAEvBd,IAAgBrE,EAAE,MAAM,IAAIsF,GAAWD,CAAS;GAElD;EACF;EAGA,IAAIG,IAAqE;EACzE,KAAK,IAAIpG,IAAI4F,EAAG,SAAS,GAAG5F,KAAK,GAAG,KAAK;GACvC,IAAMY,IAAIgF,EAAG5F;GACb,IAAI,CAACY,EAAE,MAAM,oBAAoB;GACjC,IAAMqF,IAAYrF,EAAE,OAChBsF,GACEC,IAAUvF,EAAE,MAAM,mBACtBqF,GAAWH,EAAO,OAAOD,GAAad,GACtC;IACE,MAAMe,EAAO;IACb,OAAOA,EAAO;IACd,OAAO,GAAM;KAEX,AADA,IAAYzB,GACZL,EAAcpD,EAAE,MAAM,IAAIyD,CAAI;IAChC;GACF,CACF;GACA,IAAI8B,GAAS;IAQX,AADAhB,EAAevE,EAAE,MAAM,IAAI+E,GAAGQ,CAAO,GACjCD,MAAc,KAAA,KAAa9C,EAAU,YAAY,SACnD,EAAW,QAA0B,cAAc2C,GACnD,EAAW,QAA0B,iBAAiBA,EAAiB,IAAInF,EAAE,MAAM,EAAE;IAEvF;GACF;GACA,IAAIsF,MAAc,KAAA,GAAW;IAC3B,IAAgB;KAAE,IAAItF,EAAE,MAAM;KAAI,MAAMsF;KAAW,MAAMD;IAAU;IACnE;GACF;EACF;EACA,AAAIG,MACEnE,MACFuB,EAAQ,QAAQ,KAAKuC,CAAgB,GACrC,EAAU,UAAU,CAAC,IAEvBd,IAAgBmB,EAAc,IAAIA,EAAc,MAAMA,EAAc,IAAI;CAE5E,GAAG;EAACrD;EAASoC;EAAgBnB;EAAeiB;EAAehD;EAAgByB;CAAQ,CAAC,GAG9E2C,KAAerD,GAAa,MAAyC;EACzE,IAAM0C,IAAY5D,EAAc,CAAC,GAC3BiD,IAAMhC,EAAQ2C,CAAS,GACvBE,IAAKnD,EAAU;EAErB,IAAIR,MAAmB,EAAE,WAAW,EAAE,UAAU;GAC9C,IAAMqE,IAAI,EAAE,IAAI,YAAY;GAC5B,IAAIA,MAAM,KAAK;IAGb,AAFI,EAAE,WAAUnC,EAAK,IAChBF,EAAK,GACV,EAAE,eAAe;IACjB;GACF;GACA,IAAIqC,MAAM,KAAK;IAAU,AAARnC,EAAK,GAAG,EAAE,eAAe;IAAG;GAAQ;EACvD;EAEA,KAAK,IAAInE,IAAI4F,EAAG,SAAS,GAAG5F,KAAK,GAAG,KAAK;GACvC,IAAMY,IAAIgF,EAAG5F;GACb,IAAI,CAACY,EAAE,MAAM,WAAW;GACxB,IAAMmF,IAAmBrC,EAAS,GAC9BwC;GAaJ,IAZAtF,EAAE,MAAM,UAAUA,EAAE,OAAO,EAAE,aAAamE,GAAK,EAC7C,OAAO,GAAM;IAAoB,AAAlB,IAAYV,GAAML,EAAcpD,EAAE,MAAM,IAAIyD,CAAI;GAAG,EACpE,CAAC,GACG6B,MAAc,KAAA,MACZjE,MACFuB,EAAQ,QAAQ,KAAKuC,CAAgB,GACrC,EAAU,UAAU,CAAC,IAEvBd,IAAgBrE,EAAE,MAAM,IAAIsF,GAAWtF,EAAE,KAAK,IAI5C,EAAE,YAAY,kBAAkB;EACtC;CACF,GAAG;EAACqB;EAAgBgC;EAAME;EAAMpB;EAASW;EAAUM;EAAeiB;CAAa,CAAC;CAEhF,cAAsB;EAAE,EAAW,SAAS,OAAO;CAAG,GAAG,CAAC,CAAC;CAG3D,IAAMsB,KAA6CpE,SAAe;EAChE;EACA;EACA,SAAS,MAAM1C,EAAY0D,GAAGjB,GAAYI,CAAQ;EAClD,UAAU,MAAM9C,EAAY2D,GAAGjB,GAAYI,CAAQ;CACrD,IAAI,CAACJ,GAAYI,CAAQ,CAAC,GAEpBkE,KAAM,CAACpH,EAAE,MAAMqH,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAExD,OACE,kBAAC/G,GAAD;EACE,KAAKoD;EACL,WAAW0D;EACJ;EACA;EACC;EACA;EACA;EACF;EACA;EACE;EACA;EACR,UAAUvE,IAAiB,IAAI,KAAA;EAC/B,MAAK;EACL,cAAYD,EAAM;EAClB,eAAeyD;EACf,WAAWY;EAhBb,UAAA,CAkBGK,GACA/D,EAAO,KAAK,MAAM;GACjB,IAAMoC,IAAM;IACV,GAAGwB;IACH,WAAW;KAAE,OAAO;KAAO,KAAK;KAAO,MAAM;KAAO,MAAM;IAAM;IAChE,UAAUlD,MAAkBzC,EAAE,MAAM;GACtC;GACA,OACE,kBAAC,KAAD;IAAoB,iBAAeA,EAAE,MAAM;IACxC,UAAAA,EAAE,MAAM,OAAOA,EAAE,OAAOmE,CAAG;GAC3B,GAFKnE,EAAE,MAAM,EAEb;EAEP,CAAC,CACK;;AAEZ;;;AC5YA,IAAM+F,IAAsB,IACtBC,IAAa,GACbC,IAAgB,GAChBC,IAAe,GACfC,IAAWpF,EAAW,mBAAmB,GACzCqF,IAAgB,KAChBC,IAAmB,IACnBC,IAAc;AAGpB,SAAgBC,EAAmB,GAAuD;CACxF,OAAO;EAAE;EAAM,aAAa;EAAM,iBAAiB;EAAM,MAAM;CAAK;AACtE;AAEA,SAASC,EAAQ,GAAW,GAA2C;CACrE,OAAOC,IAAQ,KAAK,IAAIA,EAAM,IAAI,KAAK,IAAIA,EAAM,IAAIC,CAAC,CAAC,IAAIA;AAC7D;AAEA,SAASC,EAAS,GAAkD;CAClE,IAAM5B,IAAI6B,GAAK;CACf,OAAO,OAAO7B,KAAM,YAAYA,KAAc,YAAYA,IAAIA,EAAE,SAAS;AAC3E;AAEA,SAAS8B,EACP,GAAmC,GAAe,GAAW,GACV;CACnD,IAAMC,IAAQ;EAAE,GAAGC,EAAKC;EAAQ;EAAG;CAAM,GACnCC,IAAOF,EAAK,QAAQ,GAAG,MAAM3H,MAAM4H,CAAK,GACxCE,IAAKD,EAAK,WAAW,MAAMvB,EAAE,IAAIjF,CAAC,GAClC0G,IAAcD,MAAO,KAAKD,EAAK,SAASC;CAE9C,OADAD,EAAK,OAAOE,GAAa,GAAGL,CAAK,GAC1B;EAAE,MAAMG;EAAM;CAAY;AACnC;AAQA,SAAgBG,EACd,GACmE;CACnE,IAAM,EAAE,SAAM,YAASC;CACvB,IAAI,CAACC,GAAM,OAAO;EAAE;EAAM,aAAaD,EAAM;CAAY;CACzD,IAAIC,EAAK,SAAS,OAAO;EACvB,IAAM5B,IAAIqB,EAAKO,EAAK;EAEpB,OADI5B,KAAKA,EAAE,MAAM4B,EAAK,KAAK5B,EAAE,UAAU4B,EAAK,QAAc;GAAE;GAAM,aAAaA,EAAK;EAAM,IACnFT,EAAUE,GAAMO,EAAK,OAAOA,EAAK,GAAGA,EAAK,KAAK;CACvD;CACA,IAAM7D,IAAOsD,EAAK,MAAM;CAExB,OADA,EAAKO,EAAK,WAAW;EAAE,GAAGP,EAAKO,EAAK;EAAU,QAAQ,EAAE,QAAQA,EAAK,OAAO;CAAE,GACvE;EAAE,MAAM7D;EAAM,aAAa4D,EAAM;CAAY;AACtD;AAQA,SAAgBE,EAAoB,IAA2B,CAAC,GAAmC;CACjG,IAAMvD,IAAKwD,EAAI,MAAM,aACfC,IAAQD,EAAI,SAAS,SACrBE,IAAUF,EAAI,aAAa,MAAc,OAAO,KAAK,MAAMG,CAAC,CAAC,IAC7DC,IAAeJ,EAAI,gBAAA;CAKzB,SAASK,EAAW,GAA2B,GAAmC,GAAuB;EACvG,IAAMC,IAAIT,EAAM;EAEhB,OADIS,GAAG,SAAS,YAAYA,EAAE,YAAYC,IAAYC,EAAkB,GAAGF,EAAE,MAAM,IAC5EG,EAAclB,EAAKgB,EAAI,CAAC,MAAM;CACvC;CAEA,SAASG,EAAe,GAA2B,GAAmC,GAA8B;EAClH,IAAMC,IAAqB,CAAC;EAC5B,KAAK,IAAI,IAAI,GAAG,IAAIpB,EAAK,QAAQ,KAAK;GACpC,IAAM,IAAIA,EAAK,IAAI,IACb/G,IAAI+G,EAAK,IACTqB,IAAOP,EAAWR,GAAON,GAAM,CAAC,GAChCsB,IAAmB,CAAC;GAC1B,KAAK,IAAIC,IAAI,GAAGA,KAAKvC,GAAqB,KAAK;IAC7C,IAAMzF,IAAIgI,IAAIvC;IACd,EAAI,KAAK5B,EAAI,OAAO;KAAE,GAAG,EAAE,KAAKnE,EAAE,IAAI,EAAE,KAAKM;KAAG,GAAG,EAAE,SAASN,EAAE,QAAQ,EAAE,SAASoI,EAAK9H,CAAC;IAAE,CAAC,CAAC;GAC/F;GACA,EAAI,KAAK+H,CAAG;EACd;EACA,OAAOF;CACT;CAEA,SAASI,EAAa,GAA0C;EAC9D,IAAMR,IAAMV,EAAM;EAClB,IAAIU,MAAQ,QAAQA,IAAM,KAAKA,KAAOV,EAAM,KAAK,QAAQ,OAAO;EAChE,IAAMS,IAAIT,EAAM;EAEhB,OADIS,GAAG,SAAS,YAAYA,EAAE,YAAYC,IAAYD,EAAE,SACjDnB,EAASU,EAAM,KAAKU,EAAI;CACjC;CAEA,SAASS,EAAa,GAA2B,GAAgB,GAAuC;EACtG,IAAMzI,IAAIsH,EAAM,KAAKA,EAAM,kBAAmB,IACxCrH,IAAIqH,EAAM,KAAKA,EAAM,kBACrBH,KAAM,GAAY,MACtB/C,EAAI,OAAO;GAAE,GAAGpE,EAAE,IAAI0I,KAAMzI,EAAE,IAAID,EAAE;GAAI,GAAGA,EAAE,QAAQ2I,KAAM1I,EAAE,QAAQD,EAAE;EAAO,CAAC;EACjF,OAAO,CAACmH,EAAGyB,EAAO,IAAIA,EAAO,EAAE,GAAGzB,EAAGyB,EAAO,IAAIA,EAAO,EAAE,CAAC;CAC5D;CAEA,IAAMC,KAAQ,MACZP,EAAI,KAAK,GAAG,MAAM,GAAGjJ,MAAM,IAAI,MAAM,MAAMmD,EAAE,EAAE,QAAQ,CAAC,EAAE,GAAGA,EAAE,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE;CAGxF,SAASsG,EAAO,GAA2B,GAAgC;EACzE,IAAMC,IAAQzB,EAAM,MAAM,SAAS,QAAQD,EAAkBC,CAAK,CAAC,CAAC,OAAOA,EAAM,MAC3EzH,IAAWsI,EAAeb,GAAOyB,GAAO3E,CAAG,GAC3C4E,IAAQnJ,EAAS,SAAS,GAAK,MAAOR,MAAM,IAAIiJ,IAAMA,EAAI,MAAM,CAAC,CAAE,GACnEN,IAAMV,EAAM,iBACZsB,IAASJ,EAAalB,CAAK,GAC3B2B,IAAY3B,EAAM,MAAM,SAAS,QAAQA,EAAM,KAAK,QAAQ;EAElE,OACE,kBAAA5I,GAAA,EAAA,UAAA;GACGsJ,MAAQ,QAAQA,KAAO,KAAKA,IAAMe,EAAM,gBAAgB;IACvD,IAAMI,IAAK/E,EAAI,OAAO;KAAE,GAAG2E,EAAMf,IAAM,EAAE,CAAC;KAAG,GAAG;IAAE,CAAC,CAAC,CAAC,GAC/CoB,IAAKhF,EAAI,OAAO;KAAE,GAAG2E,EAAMf,EAAI,CAAC;KAAG,GAAG;IAAE,CAAC,CAAC,CAAC;IACjD,OACE,kBAAC,QAAD;KACE,WAAWrJ,EAAE;KACb,GAAG,KAAK,IAAIwK,GAAIC,CAAE;KAClB,GAAG;KACH,OAAO,KAAK,IAAIA,IAAKD,CAAE;KACvB,QAAQ/E,EAAI,SAAS;IACtB,CAAA;GAEL,EAAA,CAAG,IAAI;GACN4E,EAAM,SAAS,IAAI,kBAAC,QAAD;IAAM,sBAAmB;IAAQ,WAAWrK,EAAE;IAAO,GAAGkK,EAAKG,CAAK;GAAI,CAAA,IAAI;GAC7FnJ,EAAS,KAAK,GAAK,MAClB,kBAAC,QAAD;IAEE,WAAWlB,EAAE;IACb,GAAGkK,EAAKP,CAAG;IACX,MAAK;IACL,UAAU;IACV,cAAY,GAAGZ,EAAM,gBAAgBC,EAAQoB,EAAM1J,IAAI,EAAE,CAAC,CAAC;IAC3D,gBAAc2I,MAAQ3I,IAAI,IAAI,SAAS,KAAA;IACvC,sBAAoBA,IAAI;GACzB,GARM,OAAOA,IAAI,GAQjB,CACF;GACAuJ,WAAgB;IACf,IAAM,CAACS,GAAIC,KAAMb,EAAanB,GAAOsB,GAAQxE,CAAG,GAC1C,IAAIA,EAAI,OAAO;KAAE,GAAGkD,EAAM,KAAKU,IAAO,EAAE,CAAC;KAAG,GAAGV,EAAM,KAAKU,IAAO,EAAE,CAAC;IAAM,CAAC,GAC3E/H,IAAImE,EAAI,OAAO;KAAE,GAAGkD,EAAM,KAAKU,EAAK,CAAC;KAAG,GAAGV,EAAM,KAAKU,EAAK,CAAC;IAAM,CAAC;IACzE,OACE,kBAAAtJ,GAAA,EAAA,UAAA;KACE,kBAAC,QAAD;MAAM,WAAWC,EAAE;MAAY,IAAI,EAAE;MAAG,IAAI,EAAE;MAAG,IAAI0K,EAAG;MAAG,IAAIA,EAAG;KAAI,CAAA;KACtE,kBAAC,QAAD;MAAM,WAAW1K,EAAE;MAAY,IAAIsB,EAAE;MAAG,IAAIA,EAAE;MAAG,IAAIqJ,EAAG;MAAG,IAAIA,EAAG;KAAI,CAAA;KACrE,CAACD,GAAIC,CAAE,CAAC,CAAC,KAAK,GAAG,MAChB,kBAAC,UAAD;MAEE,WAAW3K,EAAE;MACb,IAAIuF,EAAE;MACN,IAAIA,EAAE;MACN,GAAGmC;MACH,MAAK;MACL,UAAU;MACV,cAAY,GAAGqB,EAAM,iBAAiBrI,IAAI;MAC1C,qBAAmBA;KACpB,GATM,UAAUA,GAShB,CACF;IACD,EAAA,CAAA;GAEN,EAAA,CAAG,IAAI;GACNiI,EAAM,KAAK,KAAK,GAAG,MAAM;IACxB,IAAM9E,IAAI4B,EAAI,OAAO;KAAE,GAAGuB,EAAE;KAAG,GAAGA,EAAE;IAAM,CAAC;IAC3C,OACE,kBAAC,QAAD;KAEE,WAAWhH,EAAE;KACb,GAAG6D,EAAE,IAAI4D;KACT,GAAG5D,EAAE,IAAI4D;KACT,OAAOA,IAAW;KAClB,QAAQA,IAAW;KACnB,WAAW,aAAa5D,EAAE,EAAE,GAAGA,EAAE,EAAE;KACnC,MAAK;KACL,UAAU;KACV,cAAY,GAAGkF,EAAM,UAAUC,EAAQhC,EAAE,CAAC;KAC1C,gBAAc2B,EAAM,gBAAgBjI,IAAI,SAAS,KAAA;KACjD,uBAAqBA;KACrB,iBAAe4J,MAAc5J,IAAI,SAAS,KAAA;IAC3C,GAbM,OAAOA,GAab;GAEL,CAAC;GACAiI,EAAM,MAAM,SAAS,eAAe;IACnC,IAAM9E,IAAI4B,EAAI,OAAO;KAAE,GAAGkD,EAAM,KAAK;KAAG,GAAGA,EAAM,KAAK;IAAM,CAAC;IAC7D,OACE,kBAAC,QAAD;KACE,eAAY;KACZ,WAAW3I,EAAE;KACb,GAAG6D,EAAE,IAAI4D;KACT,GAAG5D,EAAE,IAAI4D;KACT,OAAOA,IAAW;KAClB,QAAQA,IAAW;KACnB,WAAW,aAAa5D,EAAE,EAAE,GAAGA,EAAE,EAAE;KACnC,uBAAoB;IACrB,CAAA;GAEL,EAAA,CAAG,IAAI;EACP,EAAA,CAAA;CAEN;CAGA,SAAS+G,EAAQ,GAA2B,GAAiB,GAAgC;EAC3F,IAAMX,IAASJ,EAAalB,CAAK;EACjC,IAAIsB,GAAQ;GACV,IAAM1E,IAAIjF,EAAcwJ,EAAanB,GAAOsB,GAAQxE,CAAG,GAAGoF,GAAMtD,CAAa;GAC7E,IAAIhC,GAAG,OAAO;IAAE,MAAM;IAAU,SAAS,EAAE,QAAQA,EAAE,MAAM;GAAE;EAC/D;EACA,IAAMyB,IAAI1G,EAAcqI,EAAM,KAAK,KAAK,MAAQlD,EAAI,OAAO;GAAE,GAAGyC,EAAI;GAAG,GAAGA,EAAI;EAAM,CAAC,CAAC,GAAG2C,GAAMvD,CAAU;EACzG,IAAIN,GAAG,OAAO;GAAE,MAAM;GAAO,SAAS,EAAE,OAAOA,EAAE,MAAM;EAAE;EACzD,IAAM8D,IAAI9J,EAAawI,EAAeb,GAAOA,EAAM,MAAMlD,CAAG,GAAGoF,GAAMrD,CAAY;EAEjF,OADIsD,IAAU;GAAE,MAAM;GAAW,SAAS,EAAE,SAASA,EAAE,SAAS,EAAE;EAAE,IAC7D;CACT;CAGA,SAASC,EAAW,GAAiD;EACnE,OAAO;GACL,OAAO,GAAO,GAAO,GAAG,GAAK;IAC3B,IAAIhJ,IAAI+F,EAAQtC,EAAM,GAAGsD,EAAI,MAAM;IACnC,IAAIA,EAAI,SAAS,CAACzC,EAAE,QAAQ;KAC1B,IAAM2E,KAASvF,EAAI,WAAW,OAAOA,EAAI,WAAW,QAAQA,EAAI,SAAS;KACzE,IAAIqC,EAAQzH,EAAc0B,GAAG+G,EAAI,OAAO,KAAK,IAAIkC,CAAK,IAAI9B,CAAY,GAAGJ,EAAI,MAAM;IACrF;IACA,OAAO;KAAE,GAAGH;KAAO,MAAM;MAAE,MAAM;MAAO;MAAO;MAAG,OAAOb,EAAQtC,EAAM,GAAGsD,EAAI,MAAM;KAAE;IAAE;GAC1F;GACA,SAAS,GAAO;IAAE,OAAO;KAAE,GAAGH;KAAO,GAAGD,EAAkBC,CAAK;KAAG,MAAM;IAAK;GAAG;GAChF,SAAS,GAAO;IAAE,OAAO;KAAE,GAAGA;KAAO,MAAM;IAAK;GAAG;EACrD;CACF;CAEA,SAASsC,EAAc,GAAiB,GAAiD;EACvF,OAAO;GACL,OAAO,GAAO,GAAO;IACnB,IAAM5J,IAAIsH,EAAM,KAAKuC,IAAU,IACzB5J,IAAIqH,EAAM,KAAKuC,IACf9B,IAAIT,EAAM;IAChB,IAAI,CAACtH,KAAK,CAACC,KAAK8H,GAAG,SAAS,UAAU,OAAOT;IAC7C,IAAMoB,IAAKzI,EAAE,MAAMD,EAAE,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,IAAImE,EAAM,IAAInE,EAAE,MAAMC,EAAE,IAAID,EAAE,EAAE,CAAC,GAC7E2I,IAAK1I,EAAE,UAAUD,EAAE,QAAQ,KAAKmE,EAAM,IAAInE,EAAE,UAAUC,EAAE,QAAQD,EAAE,QAClE4I,IAAS,CAAC,GAAGb,EAAE,MAAM;IAG3B,OAFA,EAAO+B,IAAS,KAAKpB,GACrB,EAAOoB,IAAS,IAAI,KAAKnB,GAClB;KAAE,GAAGrB;KAAO,MAAM;MAAE,MAAM;MAAU;MAAS;KAAO;IAAE;GAC/D;GACA,SAAS,GAAO;IAAE,OAAO;KAAE,GAAGA;KAAO,GAAGD,EAAkBC,CAAK;KAAG,MAAM;IAAK;GAAG;GAChF,SAAS,GAAO;IAAE,OAAO;KAAE,GAAGA;KAAO,MAAM;IAAK;GAAG;EACrD;CACF;CAEA,SAASyC,EACP,GACA,GACA,GACA,GACA,GACyC;EACzC,IAAI/E,EAAE,WAAW,GACjB;OAAIK,EAAI,SAAS,UAAU;IACzB,IAAMuD,IAASJ,EAAalB,CAAK,GAC3BuC,IAAUvC,EAAM;IACtB,IAAI,CAACsB,KAAUiB,MAAY,MAAM;IACjC,IAAM,EAAE,cAAWxE,EAAI;IAEvB,OADA2E,EAAM,OAAO;KAAE,GAAG1C;KAAO,MAAM;MAAE,MAAM;MAAU;MAAS;KAAO;IAAE,CAAC,GAC7DsC,EAAcC,GAASC,CAAM;GACtC;GACA,IAAIzE,EAAI,SAAS,OAAO;IACtB,IAAM,EAAE,aAAUA,EAAI,SAChBM,IAAI2B,EAAM,KAAKL;IAErB,OADA+C,EAAM,OAAO;KAAE,GAAG1C;KAAO,aAAaL;KAAO,MAAM;MAAE,MAAM;MAAO;MAAO,GAAGtB,EAAE;MAAG,OAAOA,EAAE;KAAM;IAAE,CAAC,GAC5F+D,EAAWzC,CAAK;GACzB;GACA,IAAI5B,EAAI,SAAS,WAAW;IAC1B,IAAM,EAAE,eAAYA,EAAI;IACxB,EAAM,OAAO;KAAE,GAAGiC;KAAO,iBAAiBuC;IAAQ,CAAC;GACrD;EAVA;CAWF;CAGA,SAASI,EACP,GACA,GACA,GACA,GACM;EACN,IAAMC,IAASlF,EAAE;EACjB,IAAIkF,GAAQ,UAAU,iBAAiB,CAAC,EAAE,aAAa,eAAe,MAAMjG,GAAI;EAChF,IAAMkG,IAAWnF,EAAE,QAAQ,WAAWA,EAAE,QAAQ,KAC1CzF,IAAKyF,EAAE,QAAQ,eAAe,IAAIA,EAAE,QAAQ,cAAc,KAAK,GAC/DvF,IAAKuF,EAAE,QAAQ,YAAY,IAAIA,EAAE,QAAQ,cAAc,KAAK,GAC5DoF,IAAOpF,EAAE,WAAWsB,IAAmB,GAEvC+D,IAAQH,EAAO,QAAQ,uBAAuB;EACpD,IAAIG,GAAO;GACT,IAAMpD,IAAQ,OAAOoD,EAAM,aAAa,qBAAqB,CAAC,GACxD1E,IAAI2B,EAAM,KAAKL;GACrB,IAAI,CAACtB,GAAG;GACR,IAAIwE,GAAU;IAEZ,AADAnF,EAAE,eAAe,GACjBgF,EAAM,OAAO;KAAE,GAAG1C;KAAO,aAAaL;IAAM,CAAC;IAC7C;GACF;GACA,IAAI1H,MAAO,KAAKE,MAAO,GAAG;GAC1B,EAAE,eAAe;GACjB,IAAMuD,IAAIoB,EAAI,YACRkG,KAAS7C,EAAI,MAAM,KAAK,KAAK,IAAIzE,EAAE,OAAOA,EAAE,IAAI,IAAI,OAAOoH,GAC3DG,KAAS9C,EAAI,MAAM,KAAK,KAAK,IAAIzE,EAAE,OAAOA,EAAE,IAAI,IAAI,OAAOoH,GAC3D1J,IAAI+F,EAAQd,EAAE,IAAIpG,IAAK+K,GAAO7C,EAAI,MAAM,GACxC+C,IAAQ/D,EAAQd,EAAE,QAAQlG,IAAK8K,GAAO9C,EAAI,MAAM;GACtD,IAAI/G,MAAMiF,EAAE,KAAK6E,MAAU7E,EAAE,OAAO;GACpC,EAAM,OAAO;IAAE,GAAG2B;IAAO,GAAGR,EAAUQ,EAAM,MAAML,GAAOvG,GAAG8J,CAAK;IAAG,MAAM;GAAK,CAAC;GAChF;EACF;EAEA,IAAMC,IAAQP,EAAO,QAAQ,sBAAsB;EACnD,IAAIO,KAASN,GAAU;GAErB,AADAnF,EAAE,eAAe,GACjBgF,EAAM,OAAO;IAAE,GAAG1C;IAAO,iBAAiB,OAAOmD,EAAM,aAAa,oBAAoB,CAAC;GAAE,CAAC;GAC5F;EACF;EAEA,IAAMC,IAAWR,EAAO,QAAQ,qBAAqB,GAC/CtB,IAASJ,EAAalB,CAAK;EACjC,IAAIoD,KAAY9B,KAAUtB,EAAM,oBAAoB,SAAS/H,MAAO,KAAKE,MAAO,IAAI;GAClF,EAAE,eAAe;GACjB,IAAMyE,IAAI,OAAOwG,EAAS,aAAa,mBAAmB,CAAC,GACrDhH,IAAO,CAAC,GAAGkF,CAAM;GAEvB,AADA,EAAK1E,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,GAAGR,EAAKQ,IAAI,KAAK3E,IAAKgH,IAAc6D,CAAI,CAAC,GAC5E,EAAKlG,IAAI,IAAI,MAAMzE,IAAK8G,IAAc6D;GACtC,IAAM7C,IAAqB;IAAE,MAAM;IAAU,SAASD,EAAM;IAAiB,QAAQ5D;GAAK;GAC1F,EAAM,OAAO;IAAE,GAAG4D;IAAO,GAAGD,EAAkB;KAAE,GAAGC;KAAO;IAAK,CAAC;IAAG,MAAM;GAAK,CAAC;EACjF;CACF;CAEA,OAAO;EAAE;EAAI;EAAQ;EAAS;EAAe;CAAU;AACzD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"icons-Dk8SRS8g.js","names":["Icon","EllipseIcon$1","ImageIcon$1","LassoIcon$1","LineIcon$1","PenIcon$1","PencilIcon$1","PolygonIcon$1","RectIcon$1","StarIcon$1","TextIcon$1","UnknownIcon$1","CloneIcon","p","ResetIcon","CloseIcon","ExportIcon","ZoomInIcon","PanIcon","AddIcon","ModeLightIcon","ModeDarkIcon","ModeAutoIcon","RemoveIcon","SortIcon","ZoomOutIcon","FitIcon","SnapshotIcon","PlayIcon","PauseIcon","StopIcon","StepBackIcon","StepForwardIcon","StepIcon","CrosshairIcon","FullscreenIcon","CompareIcon","FilterIcon","SearchIcon","LoupeIcon","LayersIcon","PageIcon","LockIcon","UnlockIcon","VisibleIcon","HiddenIcon","PinIcon","LinkIcon","CollapseIcon","ExpandIcon","ChevronIcon","TuneIcon","GridIcon","SnapIcon","MeasureIcon","RandomizeIcon","RefreshIcon","InfoIcon","WarningIcon","ErrorIcon","BusyIcon","CheckIcon","LayoutRowsIcon","LayoutColumnsIcon","LayoutGridIcon","UngroupIcon","DistributeVerticalIcon","GroupIcon","HandIcon","FlipXIcon","FlipYIcon","DistributeHorizontalIcon","SendBackwardIcon","AlignLeftIcon","CutIcon","ArrowIcon","RedoIcon","SelectIcon","AlignCenterYIcon","EyedropperIcon","UndoIcon","BringForwardIcon","AlignBottomIcon","PasteIcon","AlignRightIcon","AlignCenterXIcon","AlignTopIcon","BringToFrontIcon","CopyIcon","SendToBackIcon","DuplicateIcon","DeleteIcon"],"sources":["../../src/icons/index.tsx"],"sourcesContent":["import { Icon, type IconProps } from './Icon';\n\nexport { Icon, isFillable } from './Icon';\nexport type { IconProps } from './Icon';\nexport { ICON_FILLS, ICON_GROUPS, ICON_PATHS } from './paths';\nexport { ShapeKindIcon } from './ShapeKindIcon';\nexport type { ShapeKindIconProps } from './ShapeKindIcon';\nexport type { FillableIconName, IconName } from './paths';\n\n// Tool glyphs live in @weasel-js/core because core needs them for\n// `Tool.presentation.icon` defaults and cannot depend on this package.\n// Re-exported here so consumers have one import site for the whole set.\nexport {\n SelectIcon, LassoIcon, RectIcon, EllipseIcon, ImageIcon, EyedropperIcon,\n LineIcon, ArrowIcon, PolygonIcon, StarIcon, PencilIcon, TextIcon, PenIcon, HandIcon,\n UnknownIcon,\n} from '@weasel-js/core';\n// The standard edit actions' glyphs live beside those actions in core, for the\n// same reason.\nexport {\n CutIcon, CopyIcon, PasteIcon, DuplicateIcon, GroupIcon, UngroupIcon,\n BringForwardIcon, BringToFrontIcon, SendBackwardIcon, SendToBackIcon, FlipXIcon, FlipYIcon,\n UndoIcon, RedoIcon, DeleteIcon,\n AlignLeftIcon, AlignCenterXIcon, AlignRightIcon, AlignTopIcon, AlignCenterYIcon, AlignBottomIcon,\n DistributeHorizontalIcon, DistributeVerticalIcon,\n} from '@weasel-js/core';\n\nexport const CloneIcon = (p: IconProps) => <Icon name=\"clone\" {...p} />;\nexport const ResetIcon = (p: IconProps) => <Icon name=\"reset\" {...p} />;\nexport const CloseIcon = (p: IconProps) => <Icon name=\"close\" {...p} />;\nexport const ExportIcon = (p: IconProps) => <Icon name=\"export\" {...p} />;\nexport const ZoomInIcon = (p: IconProps) => <Icon name=\"zoomIn\" {...p} />;\nexport const PanIcon = (p: IconProps) => <Icon name=\"pan\" {...p} />;\nexport const AddIcon = (p: IconProps) => <Icon name=\"add\" {...p} />;\nexport const ModeLightIcon = (p: IconProps) => <Icon name=\"modeLight\" {...p} />;\nexport const ModeDarkIcon = (p: IconProps) => <Icon name=\"modeDark\" {...p} />;\nexport const ModeAutoIcon = (p: IconProps) => <Icon name=\"modeAuto\" {...p} />;\nexport const RemoveIcon = (p: IconProps) => <Icon name=\"remove\" {...p} />;\nexport const SortIcon = (p: IconProps) => <Icon name=\"sort\" {...p} />;\nexport const ZoomOutIcon = (p: IconProps) => <Icon name=\"zoomOut\" {...p} />;\nexport const FitIcon = (p: IconProps) => <Icon name=\"fit\" {...p} />;\nexport const SnapshotIcon = (p: IconProps) => <Icon name=\"snapshot\" {...p} />;\nexport const PlayIcon = (p: IconProps) => <Icon name=\"play\" {...p} />;\nexport const PauseIcon = (p: IconProps) => <Icon name=\"pause\" {...p} />;\nexport const StopIcon = (p: IconProps) => <Icon name=\"stop\" {...p} />;\nexport const StepBackIcon = (p: IconProps) => <Icon name=\"stepBack\" {...p} />;\nexport const StepForwardIcon = (p: IconProps) => <Icon name=\"stepForward\" {...p} />;\n/** @deprecated Use {@link StepForwardIcon}; `step` alone stopped naming a direction. */\nexport const StepIcon = StepForwardIcon;\nexport const CrosshairIcon = (p: IconProps) => <Icon name=\"crosshair\" {...p} />;\nexport const FullscreenIcon = (p: IconProps) => <Icon name=\"fullscreen\" {...p} />;\nexport const CompareIcon = (p: IconProps) => <Icon name=\"compare\" {...p} />;\nexport const FilterIcon = (p: IconProps) => <Icon name=\"filter\" {...p} />;\nexport const SearchIcon = (p: IconProps) => <Icon name=\"search\" {...p} />;\nexport const LoupeIcon = (p: IconProps) => <Icon name=\"loupe\" {...p} />;\nexport const LayersIcon = (p: IconProps) => <Icon name=\"layers\" {...p} />;\nexport const PageIcon = (p: IconProps) => <Icon name=\"page\" {...p} />;\nexport const LockIcon = (p: IconProps) => <Icon name=\"lock\" {...p} />;\nexport const UnlockIcon = (p: IconProps) => <Icon name=\"unlock\" {...p} />;\nexport const VisibleIcon = (p: IconProps) => <Icon name=\"visible\" {...p} />;\nexport const HiddenIcon = (p: IconProps) => <Icon name=\"hidden\" {...p} />;\nexport const PinIcon = (p: IconProps) => <Icon name=\"pin\" {...p} />;\nexport const LinkIcon = (p: IconProps) => <Icon name=\"link\" {...p} />;\nexport const CollapseIcon = (p: IconProps) => <Icon name=\"collapse\" {...p} />;\nexport const ExpandIcon = (p: IconProps) => <Icon name=\"expand\" {...p} />;\nexport const ChevronIcon = (p: IconProps) => <Icon name=\"chevron\" {...p} />;\nexport const TuneIcon = (p: IconProps) => <Icon name=\"tune\" {...p} />;\nexport const GridIcon = (p: IconProps) => <Icon name=\"grid\" {...p} />;\nexport const SnapIcon = (p: IconProps) => <Icon name=\"snap\" {...p} />;\nexport const MeasureIcon = (p: IconProps) => <Icon name=\"measure\" {...p} />;\nexport const RandomizeIcon = (p: IconProps) => <Icon name=\"randomize\" {...p} />;\nexport const RefreshIcon = (p: IconProps) => <Icon name=\"refresh\" {...p} />;\nexport const InfoIcon = (p: IconProps) => <Icon name=\"info\" {...p} />;\nexport const WarningIcon = (p: IconProps) => <Icon name=\"warning\" {...p} />;\nexport const ErrorIcon = (p: IconProps) => <Icon name=\"error\" {...p} />;\nexport const BusyIcon = (p: IconProps) => <Icon name=\"busy\" {...p} />;\nexport const CheckIcon = (p: IconProps) => <Icon name=\"check\" {...p} />;\nexport const LayoutRowsIcon = (p: IconProps) => <Icon name=\"layoutRows\" {...p} />;\nexport const LayoutColumnsIcon = (p: IconProps) => <Icon name=\"layoutColumns\" {...p} />;\nexport const LayoutGridIcon = (p: IconProps) => <Icon name=\"layoutGrid\" {...p} />;\n"],"mappings":"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"}
|