@jimka/typescript-ui 0.4.1 → 0.6.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/lib/{AbstractInput-BxfrmD2W.js → AbstractInput-sRNPzWel.js} +2 -2
- package/dist/lib/{AbstractInput-BxfrmD2W.js.map → AbstractInput-sRNPzWel.js.map} +1 -1
- package/dist/lib/Anchor-CwRhdP2J.js +2 -0
- package/dist/lib/Anchor-CwRhdP2J.js.map +1 -0
- package/dist/lib/AnchorConstraints-Bfkt8019.js +2 -0
- package/dist/lib/AnchorConstraints-Bfkt8019.js.map +1 -0
- package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js +2 -0
- package/dist/lib/AnimatedDropdown-H3Rh-YMZ.js.map +1 -0
- package/dist/lib/Border-0DJFDiij.js +2 -0
- package/dist/lib/Border-0DJFDiij.js.map +1 -0
- package/dist/lib/Button-MpMIYBYJ.js +2 -0
- package/dist/lib/Button-MpMIYBYJ.js.map +1 -0
- package/dist/lib/{Card-a4dzYrbX.js → Card-QYo27r5b.js} +2 -2
- package/dist/lib/{Card-a4dzYrbX.js.map → Card-QYo27r5b.js.map} +1 -1
- package/dist/lib/Checkbox-D0JYK-wc.js +2 -0
- package/dist/lib/Checkbox-D0JYK-wc.js.map +1 -0
- package/dist/lib/CheckboxMenuRow-CesLhSnp.js +2 -0
- package/dist/lib/CheckboxMenuRow-CesLhSnp.js.map +1 -0
- package/dist/lib/CodeEditor-N1FQodcF.js +2 -0
- package/dist/lib/CodeEditor-N1FQodcF.js.map +1 -0
- package/dist/lib/ComboBox-Dx8Tk9yg.js +2 -0
- package/dist/lib/ComboBox-Dx8Tk9yg.js.map +1 -0
- package/dist/lib/Component-B0ShfPVi.js +2 -0
- package/dist/lib/Component-B0ShfPVi.js.map +1 -0
- package/dist/lib/Container-abY5Ww3W.js +2 -0
- package/dist/lib/{Container-0bsG2Q8Z.js.map → Container-abY5Ww3W.js.map} +1 -1
- package/dist/lib/DOM-C-Edb3tA.js +2 -0
- package/dist/lib/DOM-C-Edb3tA.js.map +1 -0
- package/dist/lib/Dialog-cbA9V17e.js +2 -0
- package/dist/lib/Dialog-cbA9V17e.js.map +1 -0
- package/dist/lib/{FieldDecorator-Bpx8J8n9.js → FieldDecorator-BlYMfZ9L.js} +2 -2
- package/dist/lib/{FieldDecorator-Bpx8J8n9.js.map → FieldDecorator-BlYMfZ9L.js.map} +1 -1
- package/dist/lib/{Fit-CL1m1nIZ.js → Fit-BhlB-HAo.js} +2 -2
- package/dist/lib/{Fit-CL1m1nIZ.js.map → Fit-BhlB-HAo.js.map} +1 -1
- package/dist/lib/FloatingPanel-DkJXsZ2D.js +2 -0
- package/dist/lib/FloatingPanel-DkJXsZ2D.js.map +1 -0
- package/dist/lib/{Glyph-wN7bk7mg.js → Glyph-_VeBacS2.js} +2 -2
- package/dist/lib/{Glyph-wN7bk7mg.js.map → Glyph-_VeBacS2.js.map} +1 -1
- package/dist/lib/{Grid-DHHmaB-Y.js → Grid-Daiz7F5d.js} +2 -2
- package/dist/lib/Grid-Daiz7F5d.js.map +1 -0
- package/dist/lib/GridConstraints-C58LuTqM.js +2 -0
- package/dist/lib/{GridConstraints-DVc1BmlP.js.map → GridConstraints-C58LuTqM.js.map} +1 -1
- package/dist/lib/{Header-2hKwQo_u.js → Header-Dql3Zxc6.js} +2 -2
- package/dist/lib/{Header-2hKwQo_u.js.map → Header-Dql3Zxc6.js.map} +1 -1
- package/dist/lib/{IconText-DC7Xe34b.js → IconText-PUjhTLlp.js} +2 -2
- package/dist/lib/{IconText-DC7Xe34b.js.map → IconText-PUjhTLlp.js.map} +1 -1
- package/dist/lib/LanguageRegistry-CcVnbKuh.js +2 -0
- package/dist/lib/LanguageRegistry-CcVnbKuh.js.map +1 -0
- package/dist/lib/LayoutSerialization-CMxunLfV.js +2 -0
- package/dist/lib/LayoutSerialization-CMxunLfV.js.map +1 -0
- package/dist/lib/List-nx8220Fi.js +2 -0
- package/dist/lib/{List-CG4NvwuV.js.map → List-nx8220Fi.js.map} +1 -1
- package/dist/lib/MemoryStore-DhPoU-7X.js +2 -0
- package/dist/lib/MemoryStore-DhPoU-7X.js.map +1 -0
- package/dist/lib/Menu-Q0bpXXze.js +2 -0
- package/dist/lib/Menu-Q0bpXXze.js.map +1 -0
- package/dist/lib/{MenuButton-wy_0RskC.js → MenuButton-DCXi0tsP.js} +2 -2
- package/dist/lib/{MenuButton-wy_0RskC.js.map → MenuButton-DCXi0tsP.js.map} +1 -1
- package/dist/lib/OverlayFade-3pof2AJH.js +2 -0
- package/dist/lib/OverlayFade-3pof2AJH.js.map +1 -0
- package/dist/lib/Panel-Cy1pdlWO.js +2 -0
- package/dist/lib/{Panel-Rd9zkNXx.js.map → Panel-Cy1pdlWO.js.map} +1 -1
- package/dist/lib/{Position-Ck_KD4cR.js → Position-BwtxouxK.js} +2 -2
- package/dist/lib/{Position-Ck_KD4cR.js.map → Position-BwtxouxK.js.map} +1 -1
- package/dist/lib/{ProgressSpinner-yt-VXyCb.js → ProgressSpinner-DK8xEQ9y.js} +2 -2
- package/dist/lib/{ProgressSpinner-yt-VXyCb.js.map → ProgressSpinner-DK8xEQ9y.js.map} +1 -1
- package/dist/lib/RadioButton-BEwpqg1k.js +2 -0
- package/dist/lib/RadioButton-BEwpqg1k.js.map +1 -0
- package/dist/lib/RadioMenuRow-DP5qPyFR.js +2 -0
- package/dist/lib/RadioMenuRow-DP5qPyFR.js.map +1 -0
- package/dist/lib/{RovingTabIndex-DFJyoveq.js → RovingTabIndex-pHEv5oLD.js} +2 -2
- package/dist/lib/{RovingTabIndex-DFJyoveq.js.map → RovingTabIndex-pHEv5oLD.js.map} +1 -1
- package/dist/lib/Scrollbar-t8fFrUVQ.js +2 -0
- package/dist/lib/Scrollbar-t8fFrUVQ.js.map +1 -0
- package/dist/lib/Slider-CTbwR6HR.js +2 -0
- package/dist/lib/Slider-CTbwR6HR.js.map +1 -0
- package/dist/lib/{Spacer-qalSEJ5i.js → Spacer-srdN2d2b.js} +2 -2
- package/dist/lib/{Spacer-qalSEJ5i.js.map → Spacer-srdN2d2b.js.map} +1 -1
- package/dist/lib/TabButton-DLoMQzky.js +2 -0
- package/dist/lib/TabButton-DLoMQzky.js.map +1 -0
- package/dist/lib/TabCloseButton-CY7BGitY.js +2 -0
- package/dist/lib/TabCloseButton-CY7BGitY.js.map +1 -0
- package/dist/lib/Text-CMKnK9uB.js +2 -0
- package/dist/lib/Text-CMKnK9uB.js.map +1 -0
- package/dist/lib/{Tooltip-Dro4DOZs.js → Tooltip-CUOJOqQi.js} +3 -3
- package/dist/lib/Tooltip-CUOJOqQi.js.map +1 -0
- package/dist/lib/Tree-C64JNPWJ.js +2 -0
- package/dist/lib/Tree-C64JNPWJ.js.map +1 -0
- package/dist/lib/VBox-DfJPWXqc.js +2 -0
- package/dist/lib/VBox-DfJPWXqc.js.map +1 -0
- package/dist/lib/{Validator-Du8PqS5i.js → Validator-Cjs1EU5Q.js} +2 -2
- package/dist/lib/{Validator-Du8PqS5i.js.map → Validator-Cjs1EU5Q.js.map} +1 -1
- package/dist/lib/VirtualScroller-DTIn19o1.js +2 -0
- package/dist/lib/VirtualScroller-DTIn19o1.js.map +1 -0
- package/dist/lib/assets/StoreWorker-B5NwRM2I.js +2 -0
- package/dist/lib/assets/StoreWorker-B5NwRM2I.js.map +1 -0
- package/dist/lib/component/button.es.js +1 -1
- package/dist/lib/component/button.es.js.map +1 -1
- package/dist/lib/component/chart.es.js +1 -1
- package/dist/lib/component/chart.es.js.map +1 -1
- package/dist/lib/component/container.es.js +1 -1
- package/dist/lib/component/container.es.js.map +1 -1
- package/dist/lib/component/diagram.es.js +1 -1
- package/dist/lib/component/diagram.es.js.map +1 -1
- package/dist/lib/component/display.es.js +1 -1
- package/dist/lib/component/display.es.js.map +1 -1
- package/dist/lib/component/editor.es.js +3 -3
- package/dist/lib/component/editor.es.js.map +1 -1
- package/dist/lib/component/input.es.js +1 -1
- package/dist/lib/component/input.es.js.map +1 -1
- package/dist/lib/component/list.es.js +1 -1
- package/dist/lib/component/list.es.js.map +1 -1
- package/dist/lib/component/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +6 -3
- package/dist/lib/component/table.es.js.map +1 -1
- package/dist/lib/component/tree.es.js +1 -1
- package/dist/lib/component/tree.es.js.map +1 -1
- package/dist/lib/core.es.js +1 -1
- package/dist/lib/core.es.js.map +1 -1
- package/dist/lib/data.es.js +1 -1
- package/dist/lib/glyphs/solid/index.es.js +1 -1
- package/dist/lib/languages-Dl8qdL8a.js +2 -0
- package/dist/lib/languages-Dl8qdL8a.js.map +1 -0
- package/dist/lib/layout.es.js +1 -1
- package/dist/lib/layout.es.js.map +1 -1
- package/dist/lib/overlay.es.js +1 -1
- package/dist/lib/overlay.es.js.map +1 -1
- package/dist/lib/primitive.es.js +1 -1
- package/dist/lib/router.es.js +1 -1
- package/dist/lib/router.es.js.map +1 -1
- package/dist/lib/selectionsEqual-gMG7gCVI.js +2 -0
- package/dist/lib/selectionsEqual-gMG7gCVI.js.map +1 -0
- package/dist/lib/types/component/button/Button.d.ts +13 -0
- package/dist/lib/types/component/button/MenuButton.d.ts +1 -0
- package/dist/lib/types/component/button/PopupButton.d.ts +22 -0
- package/dist/lib/types/component/button/TabButton.d.ts +5 -1
- package/dist/lib/types/component/button/ToggleButton.d.ts +1 -1
- package/dist/lib/types/component/button/index.d.ts +2 -0
- package/dist/lib/types/component/chart/ChartLegend.d.ts +1 -1
- package/dist/lib/types/component/container/CheckboxMenuRow.d.ts +33 -0
- package/dist/lib/types/component/container/CollapseButton.d.ts +11 -3
- package/dist/lib/types/component/container/FloatingPanel.d.ts +23 -0
- package/dist/lib/types/component/container/MenuItem.d.ts +15 -5
- package/dist/lib/types/component/container/MenuRow.d.ts +24 -0
- package/dist/lib/types/component/container/MenuSeparator.d.ts +4 -2
- package/dist/lib/types/component/container/RadioMenuRow.d.ts +33 -0
- package/dist/lib/types/component/container/ScrollStrip.d.ts +1 -1
- package/dist/lib/types/component/container/Scrollbar.d.ts +6 -3
- package/dist/lib/types/component/container/SplitGutter.d.ts +7 -2
- package/dist/lib/types/component/container/TabBar.d.ts +3 -1
- package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
- package/dist/lib/types/component/container/index.d.ts +8 -1
- package/dist/lib/types/component/diagram/DiagramGroupNode.d.ts +1 -1
- package/dist/lib/types/component/display/Markdown.d.ts +42 -1
- package/dist/lib/types/component/display/MarkdownMinimap.d.ts +38 -0
- package/dist/lib/types/component/display/MarkdownViewer.d.ts +60 -0
- package/dist/lib/types/component/display/WebGLCanvas.d.ts +1 -0
- package/dist/lib/types/component/display/index.d.ts +6 -0
- package/dist/lib/types/component/editor/CodeEditor.d.ts +13 -0
- package/dist/lib/types/component/editor/index.d.ts +1 -1
- package/dist/lib/types/component/input/AbstractCalendarDropdown.d.ts +2 -0
- package/dist/lib/types/component/input/AbstractPickerField.d.ts +3 -2
- package/dist/lib/types/component/input/Checkbox.d.ts +1 -1
- package/dist/lib/types/component/input/RadioButton.d.ts +1 -1
- package/dist/lib/types/component/input/Slider.d.ts +1 -1
- package/dist/lib/types/component/input/Text.d.ts +0 -2
- package/dist/lib/types/component/input/Toggle.d.ts +1 -1
- package/dist/lib/types/component/list/AbstractSelectableList.d.ts +1 -1
- package/dist/lib/types/component/list/MultiSelectList.d.ts +2 -1
- package/dist/lib/types/component/menubar/MenuBar.d.ts +1 -1
- package/dist/lib/types/component/menubar/ToolBar.d.ts +1 -0
- package/dist/lib/types/component/shared/VirtualRowView.d.ts +2 -0
- package/dist/lib/types/component/table/Body.d.ts +23 -1
- package/dist/lib/types/component/table/Column.d.ts +3 -1
- package/dist/lib/types/component/table/ColumnConfig.d.ts +2 -0
- package/dist/lib/types/component/table/ColumnFilter.d.ts +27 -0
- package/dist/lib/types/component/table/Header.d.ts +30 -3
- package/dist/lib/types/component/table/Row.d.ts +4 -0
- package/dist/lib/types/component/table/Table.d.ts +29 -0
- package/dist/lib/types/component/table/TableExporter.d.ts +4 -3
- package/dist/lib/types/component/table/TreeBody.d.ts +2 -1
- package/dist/lib/types/component/table/cell/CellText.d.ts +9 -0
- package/dist/lib/types/component/table/cell/Filter.d.ts +54 -0
- package/dist/lib/types/component/table/cell/FilterClauseBadge.d.ts +21 -0
- package/dist/lib/types/component/table/cell/GroupSeparator.d.ts +9 -0
- package/dist/lib/types/component/table/cell/Header.d.ts +1 -0
- package/dist/lib/types/component/table/cell/SortPriorityBadge.d.ts +1 -1
- package/dist/lib/types/component/table/cell/editor/CellEditor.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/CellEditorPool.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/Date.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/DateTime.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/Time.d.ts +1 -0
- package/dist/lib/types/component/table/cell/renderer/CellRenderer.d.ts +1 -0
- package/dist/lib/types/component/table/cell/renderer/Combo.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/Date.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/DateTime.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/Filter.d.ts +16 -0
- package/dist/lib/types/component/table/cell/renderer/Glyph.d.ts +1 -0
- package/dist/lib/types/component/table/cell/renderer/Link.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/Number.d.ts +3 -1
- package/dist/lib/types/component/table/cell/renderer/String.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/Time.d.ts +2 -0
- package/dist/lib/types/component/table/cell/renderer/TreeCell.d.ts +1 -0
- package/dist/lib/types/component/table/index.d.ts +6 -0
- package/dist/lib/types/component/tree/Tree.d.ts +26 -2
- package/dist/lib/types/component/tree/index.d.ts +1 -1
- package/dist/lib/types/component/tree/renderer/Label.d.ts +1 -1
- package/dist/lib/types/core/AnimatedDropdown.d.ts +0 -9
- package/dist/lib/types/core/Body.d.ts +4 -0
- package/dist/lib/types/core/ClassStyleRules.d.ts +1 -0
- package/dist/lib/types/core/Component.d.ts +5 -0
- package/dist/lib/types/core/DOM.d.ts +10 -0
- package/dist/lib/types/core/Event.d.ts +11 -2
- package/dist/lib/types/core/OverlayFade.d.ts +12 -0
- package/dist/lib/types/core/OverlayPosition.d.ts +6 -0
- package/dist/lib/types/core/Theme.d.ts +12 -2
- package/dist/lib/types/core/index.d.ts +5 -3
- package/dist/lib/types/data/AbstractStore.d.ts +3 -0
- package/dist/lib/types/data/FilterDescriptor.d.ts +13 -0
- package/dist/lib/types/data/index.d.ts +2 -1
- package/dist/lib/types/data/temporalText.d.ts +2 -0
- package/dist/lib/types/layout/BoxLayout.d.ts +6 -1
- package/dist/lib/types/layout/Grid.d.ts +1 -0
- package/dist/lib/types/layout/HFlow.d.ts +1 -1
- package/dist/lib/types/layout/LayoutManager.d.ts +8 -0
- package/dist/lib/types/layout/Split.d.ts +10 -1
- package/dist/lib/types/layout/Tab.d.ts +7 -1
- package/dist/lib/types/layout/VFlow.d.ts +1 -1
- package/dist/lib/types/layout/index.d.ts +1 -1
- package/dist/lib/types/overlay/Dock.d.ts +1 -0
- package/dist/lib/types/overlay/Menu.d.ts +1 -1
- package/dist/lib/types/overlay/Popover.d.ts +3 -0
- package/dist/lib/types/overlay/PopupPanel.d.ts +17 -0
- package/dist/lib/types/overlay/Window.d.ts +2 -0
- package/dist/lib/types/overlay/index.d.ts +2 -0
- package/dist/lib/types/router/RoutePattern.d.ts +7 -0
- package/dist/lib/types/router/Router.d.ts +6 -2
- package/dist/lib/types/router/index.d.ts +1 -1
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +7 -0
- package/package.json +15 -15
- package/dist/lib/AbstractBooleanInput-DE5NNJT0.js +0 -2
- package/dist/lib/AbstractBooleanInput-DE5NNJT0.js.map +0 -1
- package/dist/lib/AnchorConstraints-DdDYSDkf.js +0 -2
- package/dist/lib/AnchorConstraints-DdDYSDkf.js.map +0 -1
- package/dist/lib/AnimatedDropdown-QLNasu_Y.js +0 -2
- package/dist/lib/AnimatedDropdown-QLNasu_Y.js.map +0 -1
- package/dist/lib/Border-CKKUk5G9.js +0 -2
- package/dist/lib/Border-CKKUk5G9.js.map +0 -1
- package/dist/lib/Button-MZDYJOMC.js +0 -2
- package/dist/lib/Button-MZDYJOMC.js.map +0 -1
- package/dist/lib/ComboBox-C04SfXAR.js +0 -2
- package/dist/lib/ComboBox-C04SfXAR.js.map +0 -1
- package/dist/lib/Component-fRQvgaEY.js +0 -2
- package/dist/lib/Component-fRQvgaEY.js.map +0 -1
- package/dist/lib/Container-0bsG2Q8Z.js +0 -2
- package/dist/lib/DOM-67StIm5G.js +0 -2
- package/dist/lib/DOM-67StIm5G.js.map +0 -1
- package/dist/lib/DragManager-DRor_-1x.js +0 -2
- package/dist/lib/DragManager-DRor_-1x.js.map +0 -1
- package/dist/lib/Grid-DHHmaB-Y.js.map +0 -1
- package/dist/lib/GridConstraints-DVc1BmlP.js +0 -2
- package/dist/lib/LayoutSerialization-D5bBas4W.js +0 -2
- package/dist/lib/LayoutSerialization-D5bBas4W.js.map +0 -1
- package/dist/lib/LayoutSizes-qNaURyiw.js +0 -2
- package/dist/lib/LayoutSizes-qNaURyiw.js.map +0 -1
- package/dist/lib/List-CG4NvwuV.js +0 -2
- package/dist/lib/MemoryStore-DT6iWWco.js +0 -2
- package/dist/lib/MemoryStore-DT6iWWco.js.map +0 -1
- package/dist/lib/Menu-CrZy2u0g.js +0 -2
- package/dist/lib/Menu-CrZy2u0g.js.map +0 -1
- package/dist/lib/Panel-Rd9zkNXx.js +0 -2
- package/dist/lib/RadioButton-D23rId-V.js +0 -2
- package/dist/lib/RadioButton-D23rId-V.js.map +0 -1
- package/dist/lib/Scrollbar-SOj9psiP.js +0 -2
- package/dist/lib/Scrollbar-SOj9psiP.js.map +0 -1
- package/dist/lib/Slider-DBnAZ-F7.js +0 -2
- package/dist/lib/Slider-DBnAZ-F7.js.map +0 -1
- package/dist/lib/TabButton-DKECTTk1.js +0 -2
- package/dist/lib/TabButton-DKECTTk1.js.map +0 -1
- package/dist/lib/Text-KB5LksJl.js +0 -2
- package/dist/lib/Text-KB5LksJl.js.map +0 -1
- package/dist/lib/Tooltip-Dro4DOZs.js.map +0 -1
- package/dist/lib/VBox-P3WFGkPc.js +0 -2
- package/dist/lib/VBox-P3WFGkPc.js.map +0 -1
- package/dist/lib/VirtualScroller-Bv4KXGKW.js +0 -2
- package/dist/lib/VirtualScroller-Bv4KXGKW.js.map +0 -1
- package/dist/lib/assets/StoreWorker-CgOBYoai.js +0 -2
- package/dist/lib/assets/StoreWorker-CgOBYoai.js.map +0 -1
- package/dist/lib/selectionsEqual-Ci3_uflt.js +0 -2
- package/dist/lib/selectionsEqual-Ci3_uflt.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dialog-cbA9V17e.js","names":[],"sources":["../../src/typescript/lib/overlay/Popover.ts","../../src/typescript/lib/component/container/DialogBackdrop.ts","../../src/typescript/lib/overlay/Dialog.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { LayerManager, DismissableLayer, LayerDismissMode } from \"~/core/LayerManager.js\";\nimport { trapWheel, untrapWheel } from \"~/core/WheelTrap.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { fadeShow, fadeHideAndDetach } from \"~/core/OverlayFade.js\";\nimport type { Animation } from \"~/core/Animation.js\";\nimport { Container, ContainerOptions } from \"~/core/Container.js\";\nimport type { Edge } from \"~/primitive/Edge.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { VBox } from \"~/layout/VBox.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { Button } from \"~/component/button/Button.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM, type Rect, type Handle } from \"~/core/DOM.js\";\n\n/** Fallback arrow side length used until the theme token is read. */\nconst DEFAULT_ARROW_SIZE_PX: number = 14;\n\n/**\n * Half of the visual extent of the rotated arrow along either axis. The\n * arrow is a square of side `DEFAULT_ARROW_SIZE_PX` rotated 45°, so its\n * bounding rectangle is `DEFAULT_ARROW_SIZE_PX * sqrt(2)` on each side and\n * each corner sits half that far from the centre.\n */\nconst ARROW_VISUAL_HALF: number = (DEFAULT_ARROW_SIZE_PX / 2) * Math.SQRT2;\n\n/** Pixel gap between the arrow tip and the anchor element. */\nconst ARROW_ANCHOR_GAP_PX: number = 2;\n\n/**\n * Pixel gap between the popover edge and the anchor element. Sized so the\n * arrow tip lands {@link ARROW_ANCHOR_GAP_PX} away from the anchor.\n */\nconst POPOVER_ANCHOR_GAP: number = Math.ceil(ARROW_VISUAL_HALF) + ARROW_ANCHOR_GAP_PX;\n\n/** Pixel inset preserved between the arrow and the popover corner. */\nconst ARROW_EDGE_INSET_PX: number = 6;\n\n/** Pixel inset preserved between the arrow / popover and any viewport edge. */\nconst VIEWPORT_EDGE_INSET_PX: number = 5;\n\n/** Fade duration matched to the rest of the floating-overlay family. */\nconst POPOVER_FADE_DURATION_MS: number = 120;\n\n/**\n * Placement of a {@link Popover} relative to its anchor element. `\"auto\"`\n * picks the side with the most viewport space at `show()` time.\n *\n * @category Core\n */\nexport type PopoverPlacement = Edge | \"auto\";\n\n/**\n * Strategy used to dismiss a {@link Popover}:\n *\n * - `\"click-outside\"`: closes on a `pointerdown` outside both the popover and\n * its anchor element (the anchor is excluded so the trigger click can\n * re-open without immediate re-close).\n * - `\"blur\"`: closes when focus or a pointer leaves the popover subtree —\n * including a portaled descendant layer such as a dropdown opened inside\n * the popover, which now keeps the popover open.\n * - `\"manual\"`: caller drives `hide()` explicitly.\n *\n * @remarks Dismissal is executed by {@link LayerManager}: the popover reports\n * this mode from its {@link DismissableLayer.getDismissMode} and the manager's\n * document-level handlers decide when to call `requestClose`. This is the\n * public option name; it maps 1:1 onto {@link LayerDismissMode}.\n *\n * @category Core\n */\nexport type PopoverDismissMode = \"click-outside\" | \"blur\" | \"manual\";\n\n/**\n * Construction-time options for {@link Popover}.\n *\n * @category Core\n */\nexport interface PopoverOptions extends ContainerOptions {\n /** Resolved placement relative to the anchor. Default `\"auto\"`. */\n placement?: PopoverPlacement;\n /** Dismiss strategy. Default `\"click-outside\"`. */\n dismissOn?: PopoverDismissMode;\n /** When `false`, the arrow tail is not rendered. Default `true`. */\n showArrow?: boolean;\n /** Optional title row rendered above the body. */\n title?: string;\n /** Callback invoked once whenever the popover closes, for any reason\n * (an explicit `hide()` or an outside-click `requestClose()`). Mirrors\n * [`Menu`](/api/overlay/classes/Menu)'s persistent-mode `onClose`. */\n onClose?: () => void;\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * The cascade in `Component`'s constructor dispatches each present setter once\n * with the final value, so any field the caller supplied wins.\n */\nconst _defaultPopoverOptions: Partial<PopoverOptions> = {\n insets: new Insets(5, 5, 5, 5),\n placement: \"auto\",\n dismissOn: \"click-outside\",\n showArrow: true,\n backgroundColor: \"var(--ts-ui-popover-bg, rgb(255, 255, 255))\",\n foregroundColor: \"var(--ts-ui-popover-color, rgb(0, 0, 0))\",\n // Theme-driven chrome.\n border: { border: \"1px solid var(--ts-ui-popover-border, rgb(200, 200, 200))\" },\n borderRadius: \"var(--ts-ui-popover-radius, 6px)\",\n shadow: \"var(--ts-ui-popover-shadow, 2px 4px 12px rgba(0, 0, 0, 0.18))\",\n};\n\n/**\n * An anchored, non-modal floating bubble with a directional arrow tail. Use\n * `Popover` for click-triggered, interactive content (title, body, action\n * buttons, or any arbitrary subtree) — for ephemeral hover hints reach for\n * [`Tooltip`](/api/overlay/classes/Tooltip), and for modal containment reach\n * for [`Dialog`](/api/overlay/classes/Dialog).\n *\n * `Popover` extends {@link Container} so authors can compose freely via\n * `addComponent`; the `setTitle` / `setBody` / `addAction` conveniences are\n * sugar over the same container surface.\n *\n * Positioning is anchor-relative. `attachToComponent(Component)` records the\n * anchor. While the popover is open, `window` `resize` and each scrollable\n * ancestor's `scroll` event trigger a reposition so the bubble follows the\n * anchor.\n *\n * Fade-in / fade-out reuse the shared [`fadeShow`](/api/core/functions/fadeShow)\n * and [`fadeHideAndDetach`](/api/core/functions/fadeHideAndDetach) helpers,\n * inheriting the standard 120 ms `opacity + translateY` transition and the\n * re-entrancy guard against a fresh `show()` mid-fade.\n *\n * @example\n * ```typescript\n * const popover = new Popover({ placement: \"auto\" });\n * popover.setTitle(\"Confirm delete\");\n * popover.setBody(\"This action cannot be undone.\");\n * popover.addAction(\"Delete\", () => doDelete());\n * popover.addAction(\"Cancel\", () => popover.hide());\n *\n * Event.addListener(triggerButton, \"click\", () => {\n * popover.attachToComponent(triggerButton);\n * popover.show();\n * });\n * ```\n *\n * @category Core\n */\nclass Popover extends Container<PopoverOptions> implements DismissableLayer {\n\n // Option-backed fields use `declare` rather than initializers to dodge the\n // class-field super-cascade trap: an initializer runs *after* super()\n // returns, overwriting whatever the cascade-dispatched setter wrote\n // during the super-time `applyOptions` call. The applyOptions override\n // below always dispatches each setter with a fallback so the field is\n // seeded even when no caller option was supplied.\n declare private _placement: PopoverPlacement;\n private _resolvedPlacement: PopoverPlacement = \"bottom\";\n declare private _dismissOn: PopoverDismissMode;\n declare private _showArrow: boolean;\n declare private _title: string | null;\n declare private _titleComponent: Text | null;\n declare private _onClose: (() => void) | null;\n private _bodyComponent: Component | null = null;\n private _actionsRow: Component | null = null;\n\n // In-flight fades, cancelled on teardown so their fallback timers cannot\n // fire against this popover's released element handle.\n private _fadeShowAnimation: Animation.CancelHandle | null = null;\n private _fadeHideAnimation: Animation.CancelHandle | null = null;\n private _anchorElement: Handle | null = null;\n private _arrowComponent: Component | null = null;\n private _isOpen: boolean = false;\n private _scrollAncestors: Handle[] = [];\n\n private readonly _onWindowResize: () => void;\n private readonly _onScroll: () => void;\n\n /**\n * Creates a popover with a 5px layout-side inset and the default chrome\n * wired to the theme tokens.\n *\n * @param options - Optional construction-time options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: PopoverOptions, subclassDefaults?: Partial<PopoverOptions>) {\n super(options as PopoverOptions, { ..._defaultPopoverOptions, ...(subclassDefaults ?? {}) });\n\n const vbox = new VBox();\n\n vbox.setStretching(true);\n this.setLayoutManager(vbox);\n\n // Overlay placement: top-level, viewport-fixed. The z-index is\n // stamped from LayerManager's Popover band at show() time, so no\n // static value is set here.\n this.setPosition(Position.FIXED);\n this.setVisible(false);\n\n // `paint` containment would clip the arrow tail (which straddles the\n // popover edge), so use `layout` containment only. The framework\n // default `overflow: hidden` would also clip the arrow, so opt out.\n this.setContain(\"layout\");\n this.setOverflow(\"visible\");\n this.getAria().setRole(\"dialog\");\n\n this._onWindowResize = () => this._reposition();\n this._onScroll = () => this._reposition();\n\n // Seed the `declare`-d title/onClose fields after the cascade has had\n // its chance to write them via setTitle / applyOptions. Without a\n // `title` (or `onClose`) option the cascade dispatch above skips\n // writing it entirely, so the field would otherwise remain undefined\n // (declare allocates no default).\n this._title ??= null;\n this._titleComponent ??= null;\n this._onClose ??= null;\n }\n\n /**\n * Applies a {@link PopoverOptions} bag, dispatching popover-specific\n * fields after the inherited Container cascade.\n *\n * @param options - The options bag carrying the values to apply.\n * @returns This popover, for method chaining.\n */\n protected applyOptions(options: PopoverOptions): this {\n super.applyOptions(options);\n\n // placement/dismissOn/showArrow carry a class default and seed\n // construction-time state, so always dispatch the caller value or the\n // class default; title has no default.\n this.setPlacement(options.placement ?? this.getPlacement());\n this.setDismissOn(options.dismissOn ?? this.getDismissOn());\n this.setShowArrow(options.showArrow ?? this.isShowArrow());\n if (options.title !== undefined) this.setTitle(options.title);\n // onClose has no setter (it's a plain callback, not a rendered/\n // resolvable field), so it's assigned directly, same as title has no\n // class default to fall back to.\n if (options.onClose !== undefined) this._onClose = options.onClose;\n\n return this;\n }\n\n /**\n * Sets the requested placement relative to the anchor.\n *\n * @param p - One of `\"top\"`, `\"bottom\"`, `\"left\"`, `\"right\"`, or `\"auto\"`.\n * @returns This popover, for method chaining.\n */\n setPlacement(p: PopoverPlacement): this {\n this._placement = p;\n\n return this;\n }\n\n /**\n * Returns the configured placement.\n *\n * @returns The placement set via {@link setPlacement}, or `\"auto\"` by default.\n */\n getPlacement(): PopoverPlacement {\n return this._placement ?? this._defaultOptions.placement!;\n }\n\n /**\n * Sets the dismiss strategy.\n *\n * @param mode - One of `\"click-outside\"`, `\"blur\"`, or `\"manual\"`.\n * @returns This popover, for method chaining.\n */\n setDismissOn(mode: PopoverDismissMode): this {\n this._dismissOn = mode;\n\n return this;\n }\n\n /**\n * Returns the active dismiss strategy.\n *\n * @returns The dismiss strategy set via {@link setDismissOn}.\n */\n getDismissOn(): PopoverDismissMode {\n return this._dismissOn ?? this._defaultOptions.dismissOn!;\n }\n\n /**\n * Enables or disables the arrow tail.\n *\n * @param value - `true` to render the arrow, `false` to hide it.\n * @returns This popover, for method chaining.\n */\n setShowArrow(value: boolean): this {\n this._showArrow = value;\n\n if (this._arrowComponent) {\n this._arrowComponent.setVisible(value);\n }\n\n return this;\n }\n\n /**\n * Returns whether the arrow tail is currently enabled.\n *\n * @returns `true` if the arrow is rendered.\n */\n isShowArrow(): boolean {\n return this._showArrow ?? this._defaultOptions.showArrow!;\n }\n\n /**\n * Sets the title row text. Lazily creates the underlying\n * [`Text`](/api/component/input/classes/Text) child on first call. Passing\n * `null` clears the title.\n *\n * @param text - The title string, or `null` to clear.\n * @returns This popover, for method chaining.\n */\n setTitle(text: string | null): this {\n if (text === null) {\n return this.clearTitle();\n }\n\n this._title = text;\n\n if (!this._titleComponent) {\n this._titleComponent = new Text(text);\n this._titleComponent.setFontWeight(\"bold\");\n\n this.insertComponent(this._titleComponent, 0);\n } else {\n this._titleComponent.setText(text);\n }\n\n this._reflowIfOpen();\n\n return this;\n }\n\n /**\n * Returns the current title string, or `null` if no title is set.\n *\n * @returns The title set via {@link setTitle}, or `null`.\n */\n getTitle(): string | null {\n return this._title;\n }\n\n /**\n * Removes the title row.\n *\n * @returns This popover, for method chaining.\n */\n clearTitle(): this {\n if (this._titleComponent) {\n this.removeComponent(this._titleComponent);\n this._titleComponent = null;\n }\n\n this._title = null;\n\n this._reflowIfOpen();\n\n return this;\n }\n\n /**\n * Sets the body content. A `string` is wrapped in a\n * [`Text`](/api/component/input/classes/Text) child; a `Component` is used\n * directly. Replaces any previous body.\n *\n * @param content - The body string or component.\n * @returns This popover, for method chaining.\n */\n setBody(content: Component | string): this {\n if (this._bodyComponent) {\n this.removeComponent(this._bodyComponent);\n this._bodyComponent = null;\n }\n\n const next: Component = typeof content === \"string\"\n ? new Text(content)\n : content;\n\n this._bodyComponent = next;\n\n // Insert after the title (if any) and before the actions row (if any).\n const titleOffset = this._titleComponent ? 1 : 0;\n\n this.insertComponent(next, titleOffset);\n\n this._reflowIfOpen();\n\n return this;\n }\n\n /**\n * Returns the current body component, or `null` when none has been set.\n *\n * @returns The body component, or `null`.\n */\n getBody(): Component | null {\n return this._bodyComponent;\n }\n\n /**\n * Appends an action button to the actions row. Lazily creates the row\n * (an [`HBox`](/api/layout/classes/HBox)-laid `Panel`) on first call.\n *\n * @param label - The button label.\n * @param onClick - Handler invoked when the button is activated.\n * @returns This popover, for method chaining.\n */\n addAction(label: string, onClick: () => void): this {\n if (!this._actionsRow) {\n this._actionsRow = new Component();\n this._actionsRow.setLayoutManager(new HBox());\n\n this.addComponent(this._actionsRow);\n }\n\n const button = new Button(label);\n\n button.on(\"action\", onClick);\n\n this._actionsRow.addComponent(button);\n\n return this;\n }\n\n /**\n * Removes every action button previously registered via {@link addAction}.\n *\n * @returns This popover, for method chaining.\n */\n clearActions(): this {\n if (this._actionsRow) {\n this.removeComponent(this._actionsRow);\n this._actionsRow = null;\n }\n\n return this;\n }\n\n /**\n * Records the raw DOM element used as the positioning anchor.\n *\n * @param el - The anchor element.\n * @returns This popover, for method chaining.\n */\n private _attachToElement(el: Handle): this {\n this._anchorElement = el;\n\n return this;\n }\n\n /**\n * Records the anchor by resolving the given component's element. Must be\n * called before {@link Popover.show}.\n *\n * @param c - The component whose element should be used as the anchor.\n * @returns This popover, for method chaining.\n */\n attachToComponent(c: Component): this {\n return this._attachToElement(c.getElement(true)!);\n }\n\n /**\n * Mounts the popover on `document.documentElement` (if not already\n * mounted), resolves the final placement, positions the bubble + arrow,\n * fades it in, and wires the dismiss listeners.\n *\n * @returns This popover, for method chaining.\n */\n show(): this {\n if (!this._anchorElement) {\n console.warn(\"Popover.show(): no anchor attached; call attachToComponent first.\");\n return this;\n }\n\n this._isOpen = true;\n\n // Join the central layer tree and mirror its band-based z-stamp so a\n // popover opened from inside a window or dropdown stacks correctly.\n LayerManager.register(this);\n this.setZIndex(LayerManager.getZIndex(this));\n\n const el = this.getElement(true)!;\n\n LayerManager.mount(el);\n\n // Trap wheels no inner scroller claimed so they cannot fall through to\n // scrollable content behind the popover.\n trapWheel(this);\n\n this.ensureArrow();\n this.setVisible(true);\n\n // First measurement pass: compute preferred size so we can resolve\n // placement against the real bubble dimensions.\n this.doLayout();\n this._reposition();\n\n this._fadeShowAnimation?.cancel();\n this._fadeShowAnimation = fadeShow(this, { durationMs: POPOVER_FADE_DURATION_MS });\n\n this.attachRepositionListeners();\n\n return this;\n }\n\n /**\n * Plays the exit fade, detaches the popover from the DOM, removes every\n * dismiss / reposition listener, and fires `onClose` (if configured)\n * once for this open→close transition.\n *\n * @returns This popover, for method chaining.\n */\n hide(): this {\n if (!this._isOpen) {\n return this;\n }\n\n this._isOpen = false;\n\n this.detachRepositionListeners();\n\n LayerManager.unregister(this);\n untrapWheel(this);\n\n this._fadeHideAnimation?.cancel();\n this._fadeHideAnimation = fadeHideAndDetach(this, { durationMs: POPOVER_FADE_DURATION_MS });\n\n // The `_isOpen` guard above already makes this method run at most\n // once per open→close transition, so `onClose` needs no separate\n // re-entrancy guard of its own.\n this._onClose?.();\n\n return this;\n }\n\n /**\n * Returns whether the popover is currently open (showing or fading in).\n *\n * @returns `true` when the popover is open.\n */\n isOpen(): boolean {\n return this._isOpen;\n }\n\n // ----- DismissableLayer -----\n\n /**\n * Returns the popover's root element for the central layer tree.\n *\n * @returns The popover's element, or null when not yet rendered.\n */\n getLayerElement(): Handle | null {\n return this.getElement() ?? null;\n }\n\n /**\n * Returns the dismiss mode the document-level handlers consult, mapping\n * the public {@link PopoverDismissMode} directly onto the manager's\n * vocabulary (the two share the `\"click-outside\"` / `\"blur\"` / `\"manual\"`\n * names). The manager now executes dismissal; the `\"blur\"` mode works for\n * a nested dropdown because the dropdown registers as the popover's child.\n *\n * @returns The layer dismiss mode.\n */\n getDismissMode(): LayerDismissMode {\n return this._dismissOn ?? this._defaultOptions.dismissOn!;\n }\n\n /**\n * Advisory close request from the manager — runs the standard\n * {@link Popover.hide} teardown, which unregisters the layer.\n */\n requestClose(): void {\n this.hide();\n }\n\n /**\n * Returns the anchor element excluded from outside-interaction tests so a\n * click on the trigger does not immediately re-close the popover.\n *\n * @returns The anchor element, or null when none is attached.\n */\n getAnchorElement(): Handle | null {\n return this._anchorElement;\n }\n\n /**\n * Returns the popover's z-index band so an unrelated top-level popover\n * stacks above windows but below dropdowns and dialogs.\n *\n * @returns The popover band base.\n */\n getBand(): number {\n return LayerManager.Band.Popover;\n }\n\n /**\n * Lays out children (delegating to the VBox) and positions the arrow\n * tail along the resolved edge.\n *\n * @returns This popover, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n if (this._arrowComponent && this._showArrow && this._anchorElement) {\n this.positionArrow();\n }\n\n return this;\n }\n\n /**\n * Releases per-instance resources. Closes the popover if it is still\n * open, disposes the raw-appended arrow, then defers to the base class\n * for the rest of teardown.\n */\n protected destructor(): void {\n if (this._isOpen) {\n this.hide();\n }\n\n // `_titleComponent` / `_bodyComponent` / `_actionsRow` are all\n // registered via `insertComponent` / `addComponent`, so\n // `super.destructor()`'s child recursion below already disposes\n // them — an explicit call here would run each one's destructor()\n // a second time. `_arrowComponent`, by contrast, is inserted\n // straight into the DOM via `ensureArrow()` (not registered in\n // `_components`), so recursion can never reach it and it must be\n // disposed explicitly.\n // After `hide()` above, since that starts a fresh fade-out whose\n // fallback timer would otherwise outlive the element handle\n // `super.destructor()` releases below.\n this._fadeShowAnimation?.cancel();\n this._fadeShowAnimation = null;\n this._fadeHideAnimation?.cancel();\n this._fadeHideAnimation = null;\n\n this._arrowComponent?.dispose();\n\n this._anchorElement = null;\n this._titleComponent = null;\n this._bodyComponent = null;\n this._actionsRow = null;\n this._arrowComponent = null;\n this._onClose = null;\n\n super.destructor();\n }\n\n /**\n * Re-measures and repositions the popover after a content mutation\n * (`setTitle` / `clearTitle` / `setBody`) — but only while the popover is\n * currently shown. `insertComponent` / `removeComponent` only *schedule*\n * a layout pass (next animation frame), so without this the bubble keeps\n * its old preferred size — and stays anchored at the old `x`/`y` derived\n * from it — until an unrelated `window` resize or ancestor scroll happens\n * to run `_reposition()` next. Mirrors the same \"measure, then position\"\n * pair `show()` runs on first open. A no-op before the first `show()`,\n * matching every other content setter's tolerance for being called on an\n * unshown popover.\n */\n private _reflowIfOpen(): void {\n if (!this._isOpen) {\n return;\n }\n\n this.doLayout();\n this._reposition();\n }\n\n /**\n * Resolves the requested placement against the viewport, anchor rect, and\n * own preferred size; updates the popover's `setX` / `setY` and the\n * resolved-placement field.\n */\n private _reposition(): void {\n if (!this._anchorElement) {\n return;\n }\n\n const anchorRect = DOM.source.getElementRect(this._anchorElement);\n\n // Anchor removed from the DOM or rendered with zero size — close.\n if (anchorRect.width === 0 && anchorRect.height === 0) {\n this.hide();\n return;\n }\n\n const preferred = this.getPreferredSize();\n const width = preferred?.width ?? this.getWidth();\n const height = preferred?.height ?? this.getHeight();\n const vp = DOM.source.getViewportSize();\n\n const resolved = this.resolvePlacement(anchorRect, width, height, vp);\n\n this._resolvedPlacement = resolved;\n\n let x: number = 0;\n let y: number = 0;\n\n if (resolved === \"top\") {\n x = anchorRect.left + (anchorRect.width - width) / 2;\n y = anchorRect.top - height - POPOVER_ANCHOR_GAP;\n } else if (resolved === \"bottom\") {\n x = anchorRect.left + (anchorRect.width - width) / 2;\n y = anchorRect.bottom + POPOVER_ANCHOR_GAP;\n } else if (resolved === \"left\") {\n x = anchorRect.left - width - POPOVER_ANCHOR_GAP;\n y = anchorRect.top + (anchorRect.height - height) / 2;\n } else { // \"right\"\n x = anchorRect.right + POPOVER_ANCHOR_GAP;\n y = anchorRect.top + (anchorRect.height - height) / 2;\n }\n\n // Clamp into viewport so the bubble stays on-screen. The arrow's\n // independent positioning keeps it pointing at the anchor centre\n // even when the bubble is shifted laterally. On the tip-direction\n // side, leave room for the arrow's outward visual extent so the tip\n // also stays at least VIEWPORT_EDGE_INSET_PX inside the viewport.\n let minX = VIEWPORT_EDGE_INSET_PX;\n let maxX = vp.width - width - VIEWPORT_EDGE_INSET_PX;\n let minY = VIEWPORT_EDGE_INSET_PX;\n let maxY = vp.height - height - VIEWPORT_EDGE_INSET_PX;\n\n if (resolved === \"right\") {\n minX += ARROW_VISUAL_HALF;\n } else if (resolved === \"left\") {\n maxX -= ARROW_VISUAL_HALF;\n } else if (resolved === \"bottom\") {\n minY += ARROW_VISUAL_HALF;\n } else {\n maxY -= ARROW_VISUAL_HALF;\n }\n\n x = Util.clamp(x, minX, maxX);\n y = Util.clamp(y, minY, maxY);\n\n this.setX(x);\n this.setY(y);\n this.setWidth(width);\n this.setHeight(height);\n\n if (this._arrowComponent && this._showArrow) {\n this.positionArrow();\n }\n }\n\n /**\n * Picks the placement to use given the configured value and the available\n * viewport space. `\"auto\"` selects the side with the most room; an\n * explicit side is honoured unless it would overflow, in which case the\n * opposite side is used and a console warning is logged.\n *\n * @param anchor - The anchor's `DOMRect`.\n * @param width - The popover's preferred width in pixels.\n * @param height - The popover's preferred height in pixels.\n * @param vp - The viewport size returned by `DOM.source.getViewportSize`.\n * @returns The resolved placement.\n */\n private resolvePlacement(\n anchor: Rect,\n width: number,\n height: number,\n vp: { width: number; height: number },\n ): PopoverPlacement {\n const spaceTop = anchor.top;\n const spaceBottom = vp.height - anchor.bottom;\n const spaceLeft = anchor.left;\n const spaceRight = vp.width - anchor.right;\n\n if (this._placement === \"auto\") {\n const needsH = height + POPOVER_ANCHOR_GAP;\n const needsV = width + POPOVER_ANCHOR_GAP;\n\n const candidates: Array<{ side: PopoverPlacement; space: number; need: number }> = [\n { side: \"bottom\", space: spaceBottom, need: needsH },\n { side: \"top\", space: spaceTop, need: needsH },\n { side: \"right\", space: spaceRight, need: needsV },\n { side: \"left\", space: spaceLeft, need: needsV },\n ];\n\n // Prefer a side that physically fits; otherwise pick the one\n // with the most absolute space.\n const fitting = candidates.filter(c => c.space >= c.need);\n const pool = fitting.length > 0 ? fitting : candidates;\n\n pool.sort((a, b) => b.space - a.space);\n\n return pool[0].side;\n }\n\n // Explicit placement — honour unless the requested side cannot fit.\n const fits = (side: PopoverPlacement): boolean => {\n if (side === \"top\") { return spaceTop >= height + POPOVER_ANCHOR_GAP; }\n if (side === \"bottom\") { return spaceBottom >= height + POPOVER_ANCHOR_GAP; }\n if (side === \"left\") { return spaceLeft >= width + POPOVER_ANCHOR_GAP; }\n\n return spaceRight >= width + POPOVER_ANCHOR_GAP;\n };\n\n if (fits(this._placement)) {\n return this._placement;\n }\n\n const opposite: Record<Exclude<PopoverPlacement, \"auto\">, Exclude<PopoverPlacement, \"auto\">> = {\n top: \"bottom\",\n bottom: \"top\",\n left: \"right\",\n right: \"left\",\n };\n\n const flipped = opposite[this._placement as Exclude<PopoverPlacement, \"auto\">];\n\n console.warn(`Popover: explicit placement \"${this._placement}\" overflows the viewport; falling back to \"${flipped}\".`);\n\n return flipped;\n }\n\n /**\n * Lazily creates the arrow tail component on first show.\n *\n * @remarks The arrow's element is inserted as the *first* DOM child of\n * the popover (not via `addComponent`) so the VBox layout manager does\n * not size it AND so it paints beneath subsequent sibling content. The\n * outward half of the diamond is still visible because it lies outside\n * the popover's bounds; the inward half is overlaid by the bubble's\n * children, preventing the arrow from obscuring the title/body text.\n */\n private ensureArrow(): void {\n if (this._arrowComponent) {\n return;\n }\n\n const arrow = new Component();\n const size = DEFAULT_ARROW_SIZE_PX;\n\n arrow.setBackgroundColor(\"var(--ts-ui-popover-bg, rgb(255, 255, 255))\");\n arrow.setWidth(size);\n arrow.setHeight(size);\n arrow.setTransform(\"rotate(45deg)\");\n arrow.setPointerEvents(\"none\");\n arrow.setVisible(this._showArrow);\n\n this._arrowComponent = arrow;\n\n const popoverEl = this.getElement(true)!;\n DOM.sink.insertBefore(popoverEl, arrow.getElement(true)!, DOM.source.getFirstChild(popoverEl));\n }\n\n /**\n * Positions the arrow tail along the resolved popover edge so it points\n * at the anchor centre, clamped to keep it within the popover's lateral\n * extent. Also re-applies the directional inset box-shadow that draws the\n * two outward-facing edges of the rotated diamond so the popover outline\n * appears continuous through the arrow.\n */\n private positionArrow(): void {\n if (!this._anchorElement || !this._arrowComponent) {\n return;\n }\n\n const anchorRect = DOM.source.getElementRect(this._anchorElement);\n const size = DEFAULT_ARROW_SIZE_PX;\n const half = size / 2;\n const popoverX = this.getX();\n const popoverY = this.getY();\n const popoverW = this.getWidth();\n const popoverH = this.getHeight();\n\n // High-first clamp (not Util.clamp): when the popover is larger than the\n // viewport, maxLocal < minLocal, and the arrow must pin to the leading\n // inset (minLocal), which the low-first Util.clamp would not do.\n const clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(value, max));\n\n // Inset box-shadow draws a 1px line on the two outward-facing edges\n // of the rotated diamond. The mapping below is given in\n // pre-rotation coordinates (the element's own CSS axes); after the\n // 45° clockwise rotation, original TOP/RIGHT/BOTTOM/LEFT edges map to\n // the rotated NE/SE/SW/NW edges.\n const borderColor = \"var(--ts-ui-popover-border, rgb(200, 200, 200))\";\n let arrowShadow: string;\n\n if (this._resolvedPlacement === \"bottom\") {\n arrowShadow = `inset 1px 0 0 ${borderColor}, inset 0 1px 0 ${borderColor}`;\n } else if (this._resolvedPlacement === \"top\") {\n arrowShadow = `inset -1px 0 0 ${borderColor}, inset 0 -1px 0 ${borderColor}`;\n } else if (this._resolvedPlacement === \"right\") {\n arrowShadow = `inset 1px 0 0 ${borderColor}, inset 0 -1px 0 ${borderColor}`;\n } else {\n arrowShadow = `inset 0 1px 0 ${borderColor}, inset -1px 0 0 ${borderColor}`;\n }\n\n this._arrowComponent.setShadow(arrowShadow);\n\n const vp = DOM.source.getViewportSize();\n const border = this.getBorderSize();\n\n // `position: absolute` measures from the popover's padding box (i.e.\n // inside the border). Subtracting the border width centres the\n // rotated diamond on the popover's *outer* edge, keeping the tip-to-\n // anchor gap predictable regardless of border thickness.\n if (this._resolvedPlacement === \"top\" || this._resolvedPlacement === \"bottom\") {\n const anchorCentreX = anchorRect.left + anchorRect.width / 2;\n const minLocalX = Math.max(\n ARROW_EDGE_INSET_PX,\n VIEWPORT_EDGE_INSET_PX - popoverX + ARROW_VISUAL_HALF - half,\n );\n const maxLocalX = Math.min(\n popoverW - size - ARROW_EDGE_INSET_PX,\n vp.width - VIEWPORT_EDGE_INSET_PX - popoverX - half - ARROW_VISUAL_HALF,\n );\n const localX = clamp(anchorCentreX - popoverX - half - border.left, minLocalX, maxLocalX);\n\n this._arrowComponent.setX(localX);\n\n // Pull the arrow half its own size outside the body so the\n // rotated diamond reads as a triangle straddling the edge.\n if (this._resolvedPlacement === \"bottom\") {\n this._arrowComponent.setY(-half - border.top);\n } else {\n this._arrowComponent.setY(popoverH - half - border.top);\n }\n } else {\n const anchorCentreY = anchorRect.top + anchorRect.height / 2;\n const minLocalY = Math.max(\n ARROW_EDGE_INSET_PX,\n VIEWPORT_EDGE_INSET_PX - popoverY + ARROW_VISUAL_HALF - half,\n );\n const maxLocalY = Math.min(\n popoverH - size - ARROW_EDGE_INSET_PX,\n vp.height - VIEWPORT_EDGE_INSET_PX - popoverY - half - ARROW_VISUAL_HALF,\n );\n const localY = clamp(anchorCentreY - popoverY - half - border.top, minLocalY, maxLocalY);\n\n this._arrowComponent.setY(localY);\n\n if (this._resolvedPlacement === \"right\") {\n this._arrowComponent.setX(-half - border.left);\n } else {\n this._arrowComponent.setX(popoverW - half - border.left);\n }\n }\n }\n\n /**\n * Registers `window` resize and `scroll` listeners on every scrollable\n * ancestor of the anchor so the popover follows the anchor while open.\n */\n private attachRepositionListeners(): void {\n Event.addViewportListener(this, \"resize\", this._onWindowResize);\n\n if (this._anchorElement) {\n this._scrollAncestors = this.collectScrollAncestors(this._anchorElement);\n\n for (const ancestor of this._scrollAncestors) {\n DOM.sink.addListener(ancestor, \"scroll\", this._onScroll, { passive: true });\n }\n }\n }\n\n /**\n * Detaches every reposition listener registered by {@link attachRepositionListeners}.\n */\n private detachRepositionListeners(): void {\n Event.removeViewportListener(this, \"resize\", this._onWindowResize);\n\n for (const ancestor of this._scrollAncestors) {\n DOM.sink.removeListener(ancestor, \"scroll\", this._onScroll);\n }\n\n this._scrollAncestors = [];\n }\n\n /**\n * Walks the anchor's ancestor chain up to `document.documentElement` and\n * collects every element whose computed `overflow` makes it scrollable.\n *\n * @param node - The starting element.\n * @returns The list of scrollable ancestors plus `document.documentElement`.\n */\n private collectScrollAncestors(node: Handle): Handle[] {\n const out: Handle[] = [];\n let cursor: Handle | null = DOM.source.getParentElement(node);\n\n while (cursor && cursor !== DOM.source.getDocumentElement()) {\n const style = DOM.source.getComputedOverflow(cursor);\n const overflow = style.overflow + style.overflowX + style.overflowY;\n\n if (/(auto|scroll|overlay)/.test(overflow)) {\n out.push(cursor);\n }\n\n cursor = DOM.source.getParentElement(cursor);\n }\n\n out.push(DOM.source.getDocumentElement());\n\n return out;\n }\n}\n\nconst PopoverCallable = callable(Popover);\ntype PopoverCallable = Popover;\nexport {\n Popover as _Popover,\n PopoverCallable as Popover\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link DialogBackdrop}.\n *\n * @category Components\n */\ninterface DialogBackdropOptions extends ComponentOptions {\n}\n\n/**\n * Empty subclass-default const so the super call follows the framework's\n * `(options, defaults)` shape uniformly.\n */\nconst _defaultDialogBackdropOptions: Partial<DialogBackdropOptions> = {};\n\n/**\n * A full-viewport fixed overlay that visually blocks content behind a modal dialog.\n *\n * Appended to `document.documentElement` as a sibling of the dialog panel at a lower\n * z-index, mirroring the pattern used by [`Notification`](/api/overlay/classes/Notification) and [`Menu`](/api/overlay/classes/Menu).\n */\nclass DialogBackdrop extends Component<DialogBackdropOptions> {\n\n /**\n * Creates the backdrop and applies viewport-filling fixed positioning.\n *\n * @param options - Optional construction options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: DialogBackdropOptions, subclassDefaults?: Partial<DialogBackdropOptions>) {\n super(options, { ..._defaultDialogBackdropOptions, ...(subclassDefaults ?? {}) });\n\n const vp = DOM.source.getViewportSize();\n\n this.setPosition(Position.FIXED);\n this.setX(0);\n this.setY(0);\n this.setWidth(vp.width);\n this.setHeight(vp.height);\n this.setZIndex(10100);\n this.setBackgroundColor(\"var(--ts-ui-dialog-backdrop-bg)\");\n }\n\n /**\n * Registers a click listener on this backdrop element.\n *\n * @param listener - Called when the user clicks the backdrop area.\n */\n addClickListener(listener: Event.Listener): this {\n Event.addListener(this, \"click\", listener);\n\n return this;\n }\n\n /**\n * Updates backdrop dimensions to match the current viewport size.\n */\n resize(): void {\n const vp = DOM.source.getViewportSize();\n\n this.setWidth(vp.width);\n this.setHeight(vp.height);\n }\n\n /**\n * Removes the backdrop from the DOM and runs component cleanup.\n */\n destroy(): void {\n this.removeElement();\n this.destructor();\n }\n}\n\nconst DialogBackdropCallable = callable(DialogBackdrop);\ntype DialogBackdropCallable = DialogBackdrop;\nexport {\n DialogBackdrop as _DialogBackdrop,\n DialogBackdropCallable as DialogBackdrop\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Panel } from \"~/core/Panel.js\";\nimport { Animation } from \"~/core/Animation.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { LayerManager, DismissableLayer, LayerDismissMode } from \"~/core/LayerManager.js\";\nimport { trapWheel, untrapWheel } from \"~/core/WheelTrap.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { Button } from \"~/component/button/Button.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { DialogBackdrop } from \"~/component/container/DialogBackdrop.js\";\nimport { Border as BorderLayout } from \"~/layout/Border.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { xmark } from \"~/glyphs/solid/xmark.js\";\nimport { circle_check } from \"~/glyphs/solid/circle_check.js\";\nimport { circle_info } from \"~/glyphs/solid/circle_info.js\";\nimport { triangle_exclamation } from \"~/glyphs/solid/triangle_exclamation.js\";\nimport { circle_exclamation } from \"~/glyphs/solid/circle_exclamation.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\n\nGlyph.register(xmark, circle_check, circle_info, triangle_exclamation, circle_exclamation);\n\n/**\n * The result produced when a dialog is dismissed.\n *\n * @category Core\n */\nexport type DialogResult = 'confirm' | 'cancel' | 'close';\n\n/**\n * Configuration for a single button in a dialog's button row.\n *\n * @category Core\n */\nexport interface DialogButtonConfig {\n /** The label text displayed on the button. */\n text : string;\n /** The result value emitted when this button is clicked. Defaults to `'cancel'`. */\n result? : DialogResult;\n /** When true, renders the button with primary (confirm) styling. */\n primary?: boolean;\n /** Optional registry glyph name shown to the left of the button label. */\n glyph? : string;\n /**\n * Optional foreground colour applied to the button's leading glyph. Accepts\n * any CSS colour string — typically a theme variable reference such as\n * `'var(--ts-ui-dialog-confirm-color)'`. When omitted the glyph inherits\n * the button's `currentColor`. The {@link DialogButtons} presets supply\n * the appropriate tint by default; reach for this field at the call site\n * only when overriding a preset or building a one-off button.\n */\n tint? : string;\n}\n\n/**\n * Severity tone for a dialog's title bar, mirroring\n * [`NotificationType`](/api/core/type-aliases/NotificationType). When set it\n * tints the header and shows a matching leading glyph, taking precedence over\n * the tone otherwise derived from the buttons.\n *\n * @category Core\n */\nexport type DialogSeverity = 'info' | 'success' | 'warning' | 'error';\n\n/**\n * Configuration object passed to `new Dialog(config)` or `Dialog.show(config)`.\n *\n * @category Core\n */\nexport interface DialogConfig {\n /** Text displayed in the dialog title bar. */\n title : string;\n /** Plain-text body message. Ignored when `contentComponent` is provided. */\n message? : string;\n /** A custom component rendered in the content area instead of a message label. */\n contentComponent?: Component;\n /**\n * Button definitions for the footer row.\n * Defaults to a single OK button that resolves with `'confirm'`.\n */\n buttons? : DialogButtonConfig[];\n /** Dialog panel width in pixels. Defaults to 480. */\n width? : number;\n /** Dialog panel height in pixels. When omitted the height is computed from content. */\n height? : number;\n /** When true, clicking the backdrop closes the dialog with result `'close'`. Defaults to false. */\n closeOnBackdrop? : boolean;\n /**\n * When `false`, the dialog is a mandatory modal: no title-bar close button,\n * Escape does not close it, and a backdrop click does not close it (regardless\n * of `closeOnBackdrop`). Defaults to `true`.\n */\n dismissable? : boolean;\n /**\n * Optional severity tone for the title bar (`'info'`, `'success'`,\n * `'warning'`, `'error'`). When set it tints the header and shows a matching\n * leading glyph, overriding the tone derived from the buttons. Omit for the\n * default button-derived chrome.\n */\n severity? : DialogSeverity;\n /**\n * Component to receive focus when the dialog opens, overriding the default\n * (the first focusable element in the content region). Use it when the field\n * that should take focus is not the first one — a form whose first control is\n * a read-only summary, say. Ignored when the component has no focusable\n * element on open, which falls back to the default order.\n */\n initialFocus? : Component;\n}\n\n// ---------------------------------------------------------------------------\n// Private constants\n// ---------------------------------------------------------------------------\n\nconst TITLE_HEIGHT : number = 36;\nconst BUTTON_HEIGHT : number = 52;\nconst BUTTON_WIDTH : number = 90;\nconst BUTTON_GAP : number = 8;\nconst BUTTON_V_PAD : number = 11;\nconst CLOSE_SIZE : number = 20;\nconst TITLE_H_PAD : number = 12;\nconst MIN_DIALOG_WIDTH : number = 320;\nconst MIN_DIALOG_HEIGHT: number = 160;\nconst MIN_CONTENT_HEIGHT: number = 80;\n// Minimum gap kept between a content-resized dialog and each viewport edge, so a\n// dialog grown to tall content never runs flush to the top/bottom of the screen.\nconst DIALOG_VIEWPORT_MARGIN: number = 24;\n\n// Leading title-bar glyph per severity tone, mirroring Notification's badges.\nconst SEVERITY_GLYPH: Record<DialogSeverity, string> = {\n info: \"circle-info\",\n success: \"circle-check\",\n warning: \"triangle-exclamation\",\n error: \"circle-exclamation\",\n};\n\n/**\n * Shared duration (ms) for the dialog entrance/exit transition. The backdrop\n * fade and the panel's opacity + scale all run for this many milliseconds.\n */\nconst DIALOG_ANIM_DURATION_MS: number = 150;\n\n/**\n * CSS selector matching the focusable elements inside a dialog — the Tab\n * focus-trap boundary set, the initial-focus candidates, and the primary-button\n * lookup all share it so the notion of \"focusable\" stays single-sourced.\n */\nconst FOCUSABLE_SELECTOR = 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n/**\n * Vertical breathing room reserved above and below the title text inside the\n * `TITLE_HEIGHT` row. 4 px on each side: keeps the bold label off the divider\n * border and gives a balanced visual cap height. Used both for the text's\n * line-height (via {@link Text.centerInHeight}) and for its laid-out height\n * inside the bar.\n */\nconst TITLE_V_PAD: number = 4;\n\n/**\n * Horizontal gap between the close button and the right edge of the title\n * bar, plus the gap between the title text and the close button. Two\n * separate offsets share the same value so the close-button column reads as\n * a balanced `[gap][icon][gap]` strip.\n */\nconst TITLE_RIGHT_GAP: number = 4;\n\n/**\n * Horizontal gap between the optional leading glyph and the title text.\n * Matches the 8 px gutter the WindowHeader uses between its title icon and\n * label so the two surfaces feel consistent.\n */\nconst TITLE_GLYPH_TEXT_GAP: number = 8;\n\n// ---------------------------------------------------------------------------\n// Private: DialogTitleBar\n// ---------------------------------------------------------------------------\n\n/**\n * Title bar that occupies the NORTH slot of a Dialog's border layout.\n * Contains a text label on the left, an optional leading glyph, and a glyph\n * close button on the right.\n *\n * @remarks\n * Reach this instance via [`Dialog.getTitleBar()`](/api/overlay/classes/Dialog#gettitlebar) — there is no public\n * constructor. The supported surface is `getTitleText()` (for tinting the\n * title text colour), `setGlyph()` / `getGlyph()` (for the optional leading\n * icon), and any inherited [`Component`](/api/core/classes/Component) setter\n * (e.g. `setBackgroundColor`).\n *\n * @category Core\n */\nclass DialogTitleBar extends Component {\n\n private readonly _titleText : Text;\n private _closeButton: Button | null = null;\n private _titleGlyph: Glyph | null = null;\n\n /**\n * @param title - Text to display in the title bar.\n * @param onClose - Called when the user clicks the close button.\n * @param dismissable - When `false`, the close button is not built at all\n * (mandatory-modal title bar).\n */\n constructor(title: string, onClose: () => void, dismissable: boolean) {\n super();\n\n this.setBackgroundColor(\"var(--ts-ui-body-bg)\");\n this.setBorder({\n border: \"none\",\n borderBottom: \"1px solid var(--ts-ui-dialog-border)\",\n });\n this.setPreferredSize({ width: 0, height: TITLE_HEIGHT });\n\n this._titleText = new Text(title);\n this._titleText.setFontWeight(\"bold\");\n this._titleText.setOverflow(\"hidden\");\n this._titleText.setTextOverflow(\"ellipsis\");\n this._titleText.setWhiteSpace(\"nowrap\");\n // Centre the label within the inner area of the row (TITLE_HEIGHT\n // minus the top + bottom TITLE_V_PAD breathing room).\n this._titleText.centerInHeight(TITLE_HEIGHT - TITLE_V_PAD * 2);\n this.addComponent(this._titleText);\n\n if (dismissable) {\n this._closeButton = new Button({ glyph: \"xmark\" });\n this._closeButton.setInsets(new Insets(0, 0, 0, 0));\n this._closeButton.setBorder(\"none\");\n this._closeButton.clearBackgroundImage();\n this._closeButton.setBackgroundColor(\"transparent\");\n this._closeButton.clearShadow();\n this._closeButton.clearPressedShadow();\n this._closeButton.clearHoverShadow();\n // Hover and pressed background swap out the framework's gray\n // var(--ts-ui-button-hover-bg, …) for a translucent overlay that\n // darkens whatever tinted header sits underneath without\n // imposing its own colour. Also drop the hover gradient so it\n // doesn't double up over the overlay.\n this._closeButton.setHoverBackgroundColor(\"var(--ts-ui-titlebar-btn-hover-bg, rgba(0, 0, 0, 0.08))\");\n this._closeButton.setPressedBackgroundColor(\"var(--ts-ui-titlebar-btn-active-bg, rgba(0, 0, 0, 0.16))\");\n this._closeButton.clearHoverBackgroundImage();\n this._closeButton.clearPressedBackgroundImage();\n this._closeButton.setPreferredSize({ width: CLOSE_SIZE, height: CLOSE_SIZE });\n this.addComponent(this._closeButton);\n\n this._closeButton.on(\"action\", onClose);\n }\n }\n\n /**\n * Returns the title bar's close button, or `null` when the title bar was\n * built non-dismissable (no close affordance).\n *\n * @returns The close [`Button`](/api/component/button/classes/Button), or `null`.\n */\n getCloseButton(): Button | null {\n return this._closeButton;\n }\n\n /**\n * Returns the title-text component, for callers that need to tint or\n * otherwise restyle it from outside the title bar.\n *\n * @returns The internal title [`Text`](/api/component/input/classes/Text) instance.\n */\n getTitleText(): Text {\n return this._titleText;\n }\n\n /**\n * Sets or clears an optional leading glyph shown to the left of the title text.\n *\n * @param name - Registry glyph name to display, or `null` to clear an existing glyph.\n *\n * @returns This component, for method chaining.\n *\n * @remarks\n * The current implementation positions the glyph in `doLayout`; only the\n * notification-detail path uses this slot, and the glyph never coexists with\n * other left-side decoration on a Dialog title bar.\n */\n setGlyph(name: string): this {\n if (this._titleGlyph) {\n this.removeComponent(this._titleGlyph);\n this._titleGlyph = null;\n }\n\n const glyph = new Glyph(name);\n glyph.setPointerEvents(\"none\");\n glyph.setPreferredSize({ width: 16, height: 16 });\n this._titleGlyph = glyph;\n this.addComponent(glyph);\n\n this.doLayout();\n\n return this;\n }\n\n /**\n * Removes the leading title-bar glyph from the dialog, if one is present.\n *\n * @returns This component, for method chaining.\n */\n clearGlyph(): this {\n if (this._titleGlyph) {\n this.removeComponent(this._titleGlyph);\n this._titleGlyph = null;\n this.doLayout();\n }\n\n return this;\n }\n\n /**\n * Returns the optional leading title-glyph component, or null if none is set.\n *\n * @returns The leading [`Glyph`](/api/component/display/classes/Glyph) instance, or null.\n */\n getGlyph(): Glyph | null {\n return this._titleGlyph;\n }\n\n /**\n * Positions the title label, optional leading glyph, and close button within\n * the title bar's content box.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const box = this.getContentBounds();\n\n if (!box) {\n return this;\n }\n\n const w = box.width;\n const h = box.height;\n const closeX = w - CLOSE_SIZE - TITLE_RIGHT_GAP;\n const centerY = Math.floor((h - CLOSE_SIZE) / 2);\n const rightBound = this._closeButton\n ? closeX // reserve the close-button slot\n : (w - TITLE_H_PAD); // no button: label runs to the right pad\n\n let labelX = TITLE_H_PAD;\n\n if (this._titleGlyph) {\n const glyphSize = this._titleGlyph.getPreferredSize() ?? { width: 16, height: 16 };\n const glyphY = Math.max(0, Math.floor((h - glyphSize.height) / 2));\n\n this._titleGlyph.setX(box.x + TITLE_H_PAD);\n this._titleGlyph.setY(box.y + glyphY);\n this._titleGlyph.setWidth(glyphSize.width);\n this._titleGlyph.setHeight(glyphSize.height);\n\n labelX = TITLE_H_PAD + glyphSize.width + TITLE_GLYPH_TEXT_GAP;\n }\n\n // Reserve TITLE_RIGHT_GAP of space between the label and the close button.\n const labelWidth = Math.max(0, rightBound - labelX - TITLE_RIGHT_GAP);\n const labelH = h - TITLE_V_PAD * 2;\n\n this._titleText.setX(box.x + labelX);\n this._titleText.setY(box.y + TITLE_V_PAD);\n this._titleText.setWidth(labelWidth);\n this._titleText.setHeight(labelH);\n\n if (this._closeButton) {\n this._closeButton.setX(box.x + closeX);\n this._closeButton.setY(box.y + centerY);\n this._closeButton.setWidth(CLOSE_SIZE);\n this._closeButton.setHeight(CLOSE_SIZE);\n // setX/setY/setWidth/setHeight don't cascade — explicitly relayout the\n // close button so its internal Fit layout sizes the times glyph.\n this._closeButton.doLayout();\n }\n\n return this;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Private: DialogButtonRow\n// ---------------------------------------------------------------------------\n\n/**\n * Footer row that occupies the SOUTH slot of a Dialog's border layout.\n * Lays out one or more buttons, right-aligned.\n */\nclass DialogButtonRow extends Component {\n\n private readonly _buttons: Button[] = [];\n\n /**\n * @param configs - Button definitions to render.\n * @param onButton - Called with the resolved [`DialogResult`](/api/overlay/type-aliases/DialogResult) when any button is clicked.\n */\n constructor(configs: DialogButtonConfig[], onButton: (result: DialogResult) => void) {\n super();\n\n this.setBorder({\n border: \"none\",\n borderTop: \"1px solid var(--ts-ui-dialog-border)\",\n });\n this.setBackgroundColor(\"var(--ts-ui-body-bg)\");\n this.setPreferredSize({ width: 0, height: BUTTON_HEIGHT });\n\n for (const cfg of configs) {\n const btn = new Button(cfg.text, cfg.glyph !== undefined ? { glyph: cfg.glyph } : undefined);\n const result = cfg.result ?? 'cancel';\n\n if (cfg.primary) {\n btn.setBackgroundImage(\"var(--ts-ui-toggle-selected-bg, rgb(200, 200, 200))\");\n }\n\n if (cfg.glyph !== undefined) {\n const glyph = btn.getGlyph();\n const tint = cfg.tint;\n\n if (glyph !== null && tint) {\n glyph.setForegroundColor(tint);\n }\n }\n\n btn.on(\"action\", () => onButton(result));\n this._buttons.push(btn);\n this.addComponent(btn);\n }\n }\n\n /**\n * Positions buttons right-aligned within the footer row's content box.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const box = this.getContentBounds();\n\n if (!box) {\n return this;\n }\n\n const btnH = box.height - BUTTON_V_PAD * 2;\n const totalW = this._buttons.length * BUTTON_WIDTH + (this._buttons.length - 1) * BUTTON_GAP;\n let x = Math.round((box.width - totalW) / 2);\n\n for (const btn of this._buttons) {\n btn.setX(box.x + x);\n btn.setY(box.y + BUTTON_V_PAD);\n btn.setWidth(BUTTON_WIDTH);\n btn.setHeight(btnH);\n\n btn.doLayout();\n\n x += BUTTON_WIDTH + BUTTON_GAP;\n }\n\n return this;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public: Dialog\n// ---------------------------------------------------------------------------\n\n/**\n * Canonical dialog button presets. Spread into the `buttons` array of a\n * {@link DialogConfig} to inherit the standard text / result / glyph mapping\n * for the three universal dismiss-row affordances; override `primary` per\n * call site since which button is default-focused is contextual (Cancel is\n * primary when paired with Confirm; Confirm is primary when it stands alone).\n *\n * Centralising the `glyph` here is the rule that prevents drift — the\n * checkmark/xmark mapping is bound to the button's identity, never re-typed\n * at the call site. {@link Dialog} also inspects the resolved result set to\n * pick the title-bar variant (only `confirm` → info header with leading\n * `circle-info`; `confirm` + `cancel` → affirm header).\n *\n * @category Core\n * @example\n * ```typescript\n * Dialog.show({\n * title: 'Delete record',\n * message: 'This cannot be undone.',\n * buttons: [\n * { ...DialogButtons.Cancel, primary: true },\n * DialogButtons.Confirm,\n * ],\n * });\n * ```\n */\nexport const DialogButtons = {\n /** Affirm an action — emits `'confirm'`, carries the green-tinted `circle-check` glyph. Paired with {@link Cancel} for action prompts. */\n Confirm: { text: 'Confirm', result: 'confirm', glyph: 'circle-check', tint: 'var(--ts-ui-dialog-confirm-color)' },\n /** Acknowledge information — emits `'confirm'`, carries the green-tinted `circle-check` glyph. Stands alone on informational dialogs. */\n Ok: { text: 'Ok', result: 'confirm', glyph: 'circle-check', tint: 'var(--ts-ui-dialog-confirm-color)' },\n /** Reject an action — emits `'cancel'`, carries the red-tinted `xmark` glyph. Paired with {@link Confirm}. */\n Cancel: { text: 'Cancel', result: 'cancel', glyph: 'xmark', tint: 'var(--ts-ui-dialog-cancel-color)' },\n /** Dismiss without choosing — emits `'close'`, carries the red-tinted `xmark` glyph (same icon family as cancel; the result value disambiguates). */\n Close: { text: 'Close', result: 'close', glyph: 'xmark', tint: 'var(--ts-ui-dialog-cancel-color)' },\n} as const satisfies Record<string, DialogButtonConfig>;\n\n/** Default button set when no buttons are supplied in config. */\nconst DEFAULT_BUTTONS: DialogButtonConfig[] = [\n { ...DialogButtons.Ok, primary: true },\n];\n\n/**\n * A modal dialog component with a title bar, scrollable content area, and button row.\n *\n * Use the static `Dialog.show(config)` convenience method for one-shot confirm/cancel\n * prompts, or construct an instance and call `show()` for fine-grained control.\n *\n * @example\n * ```typescript\n * const result = await Dialog.show({\n * title : 'Confirm deletion',\n * message: 'Are you sure you want to delete this record?',\n * buttons: [\n * { text: 'Delete', result: 'confirm', primary: true },\n * { text: 'Cancel', result: 'cancel' },\n * ],\n * });\n * if (result === 'confirm') { ... }\n * ```\n *\n * @category Core\n */\nclass Dialog extends Component implements DismissableLayer {\n\n private readonly _titleBar : DialogTitleBar;\n private readonly _contentContainer: Panel;\n private readonly _buttonRow : DialogButtonRow;\n private readonly _backdrop : DialogBackdrop;\n private readonly _config : DialogConfig;\n\n private _resolvePromise : ((result: DialogResult) => void) | null = null;\n private _previousFocus : Handle | null = null;\n private _boundKeyHandler : (e: KeyboardEvent) => Event.ListenerResult;\n private _boundResizeHandler: () => void;\n\n // In-flight entrance / dismiss animations for the panel and its backdrop,\n // cancelled on teardown so their fallback timers cannot fire against\n // released element handles.\n private _panelInAnimation : Animation.CancelHandle | null = null;\n private _backdropInAnimation : Animation.CancelHandle | null = null;\n private _panelOutAnimation : Animation.CancelHandle | null = null;\n private _backdropOutAnimation: Animation.CancelHandle | null = null;\n\n // True once `hide()`'s finalize has begun. `finalize` calls `destructor()`\n // partway through and finishes the rest afterwards, so the destructor uses\n // this to tell \"reached from a completing hide\" (leave the remainder to\n // finalize) from \"reached from a bare dispose\" (run it here, because the\n // cancelled dismiss animation will never call finalize at all).\n private _finalizing: boolean = false;\n\n /**\n * Constructs a Dialog but does not display it. Call `show()` to open.\n *\n * @param config - Dialog configuration.\n */\n constructor(config: DialogConfig) {\n super();\n\n this._config = config;\n\n const dialogWidth = Math.max(MIN_DIALOG_WIDTH, config.width ?? 480);\n const buttons = config.buttons ?? DEFAULT_BUTTONS;\n const contentHeight = Math.max(MIN_CONTENT_HEIGHT, this.computeContentHeight(config));\n const dialogHeight = Math.max(\n MIN_DIALOG_HEIGHT,\n config.height ?? (TITLE_HEIGHT + contentHeight + BUTTON_HEIGHT)\n );\n\n this.setPosition(Position.FIXED);\n this.setWidth(dialogWidth);\n this.setHeight(dialogHeight);\n // z-index is stamped from LayerManager's Dialog band at open() time\n // so stacked dialogs ascend monotonically; the backdrop is set one\n // below the panel there.\n this.setBackgroundColor(\"var(--ts-ui-body-bg)\");\n this.setBorderRadius(\"var(--ts-ui-border-radius, 4px)\");\n this.setShadow(\"var(--ts-ui-dialog-shadow)\");\n this.setOverflow(\"hidden\");\n // Fixed dimensions, hidden overflow, no escaping descendants — full strict containment.\n this.setContain(\"strict\");\n\n const layout = new BorderLayout();\n layout.setComponentSpacing(0);\n this.setLayoutManager(layout);\n\n this._titleBar = new DialogTitleBar(config.title, () => this.hide('close'), config.dismissable !== false);\n this.addComponent(this._titleBar, { placement: Placement.NORTH });\n\n // An explicit severity tone wins over the tone derived from the buttons,\n // so an error/warning dialog reads as such regardless of its footer.\n if (config.severity) {\n this.applySeverityHeader(config.severity);\n } else {\n this.applyHeaderVariant(this.computeHeaderVariant(buttons));\n }\n\n // A Panel (not a bare Component) so the content area is a real scroll\n // region: `autoScroll: \"y\"` opts it into the framework's overflow\n // handling, and — because Panel does not clamp itself to its content size\n // (`clampsToContentSize` is false) — a dialog capped shorter than its\n // content (see resizeToContent) shrinks this container to the available\n // space and scrolls, instead of a bare Component flooring to its content\n // height and clipping. Vertical only: a horizontal scrollbar would cover\n // the bottom rows of body text and is rarely useful for dialog content.\n // Zero insets so content sits flush, matching the former bare container.\n this._contentContainer = new Panel({\n autoScroll: \"y\",\n layoutManager: new Fit(),\n insets: new Insets(0, 0, 0, 0),\n });\n\n if (config.contentComponent) {\n this._contentContainer.addComponent(config.contentComponent);\n } else {\n const messageText = new Text(config.message ?? '');\n messageText.setWhiteSpace(\"normal\");\n messageText.setWordBreak(\"break-word\");\n messageText.setPadding(new Insets(16, 16, 16, 16));\n messageText.setUserSelect(\"text\");\n messageText.setCursor(\"text\");\n this._contentContainer.addComponent(messageText);\n }\n\n this.addComponent(this._contentContainer, { placement: Placement.CENTER });\n\n this._buttonRow = new DialogButtonRow(buttons, (result) => this.hide(result));\n this.addComponent(this._buttonRow, { placement: Placement.SOUTH });\n\n this._backdrop = new DialogBackdrop();\n\n this._boundKeyHandler = (e: KeyboardEvent) => this.onKeyDown(e);\n this._boundResizeHandler = () => this.onViewportResize();\n }\n\n /**\n * Picks the title-bar tint variant for this dialog by inspecting the set\n * of button results. The variant is derived from the buttons rather than\n * a config flag so callers cannot signal one intent via buttons and a\n * conflicting intent via a separate option.\n *\n * @param buttons - The resolved button configuration array.\n * @returns `'info'` for a single confirm-result button (informational\n * dialog), `'affirm'` when both confirm and cancel are present\n * (affirmative-action dialog), `'plain'` otherwise.\n */\n private computeHeaderVariant(buttons: DialogButtonConfig[]): 'info' | 'affirm' | 'plain' {\n const results = new Set(buttons.map(b => b.result ?? 'cancel'));\n\n if (results.size === 1 && results.has('confirm')) {\n return 'info';\n }\n\n if (results.has('confirm') && results.has('cancel')) {\n return 'affirm';\n }\n\n return 'plain';\n }\n\n /**\n * Applies the chosen header variant's background, title-text foreground,\n * and (for the info variant only) a leading `circle-info` glyph. The\n * close button inside the title bar is intentionally untouched — dismiss\n * affordances stay on `currentColor` per the modal-glyph-theming rule.\n *\n * @param variant - One of `'info'`, `'affirm'`, or `'plain'`.\n */\n private applyHeaderVariant(variant: 'info' | 'affirm' | 'plain'): void {\n if (variant === 'plain') {\n return;\n }\n\n const bgVar = variant === 'info' ? 'var(--ts-ui-dialog-info-bg)' : 'var(--ts-ui-dialog-affirm-bg)';\n const fgVar = variant === 'info' ? 'var(--ts-ui-dialog-info-fg)' : 'var(--ts-ui-dialog-affirm-fg)';\n\n this._titleBar.setBackgroundColor(bgVar);\n this._titleBar.getTitleText().setForegroundColor(fgVar);\n\n if (variant === 'info') {\n this._titleBar.setGlyph('circle-info');\n\n const headerGlyph = this._titleBar.getGlyph();\n\n if (headerGlyph !== null) {\n headerGlyph.setForegroundColor(fgVar);\n }\n }\n }\n\n /**\n * Tints the title bar for an explicit {@link DialogSeverity}, reusing the\n * notification severity palette and leading glyph (matching the\n * notification-detail dialog). The border colour doubles as the title-text\n * and glyph foreground, as it does for a notification.\n *\n * @param severity - The severity tone to apply.\n */\n private applySeverityHeader(severity: DialogSeverity): void {\n const bgVar = `var(--ts-ui-notification-${severity}-bg)`;\n const fgVar = `var(--ts-ui-notification-${severity}-border)`;\n\n this._titleBar.setBackgroundColor(bgVar);\n this._titleBar.getTitleText().setForegroundColor(fgVar);\n this._titleBar.setGlyph(SEVERITY_GLYPH[severity]);\n\n const headerGlyph = this._titleBar.getGlyph();\n\n if (headerGlyph !== null) {\n headerGlyph.setForegroundColor(fgVar);\n }\n }\n\n /**\n * Computes the default content area height based on config.\n *\n * @param config - Dialog configuration.\n * @returns Height in pixels for the content region.\n *\n * @remarks\n * Content whose height depends on its width — a wrapping {@link Text} only\n * knows its line count once laid out — reports a single-line height here,\n * before it has been sized. {@link resizeToContent}, scheduled after the\n * first layout in {@link open}, re-fits the dialog once the content has\n * settled at the dialog width.\n */\n private computeContentHeight(config: DialogConfig): number {\n if (config.contentComponent) {\n const ps = config.contentComponent.getPreferredSize();\n\n if (ps) {\n return ps.height;\n }\n }\n\n return 100;\n }\n\n /**\n * Displays the dialog, attaches event listeners, and returns a promise that\n * resolves when the dialog is dismissed.\n *\n * @returns A promise resolving to the [`DialogResult`](/api/overlay/type-aliases/DialogResult) of the closing action.\n */\n show(): Promise<DialogResult> {\n return new Promise((resolve) => {\n this._resolvePromise = resolve;\n this.open();\n });\n }\n\n /**\n * Re-fits the dialog's height to its content's current preferred size and\n * re-centres it. A dialog's height is otherwise fixed at construction, so a\n * form whose content grows or shrinks after `show()` (e.g. add/remove rows)\n * is stretched or clipped to the original box; call this after mutating the\n * content so the dialog tracks it.\n *\n * The new height is `TITLE_HEIGHT + content + BUTTON_HEIGHT`, floored at the\n * dialog minimum and capped so the panel keeps a margin from the top and\n * bottom viewport edges — past that cap the content area scrolls (its\n * container is already `overflow-y: auto`). No-op before `show()` (nothing to\n * re-centre) and when the height is unchanged. Width is untouched.\n *\n * @returns This dialog, for method chaining.\n */\n resizeToContent(): this {\n if (!this.getElement()) {\n return this;\n }\n\n const contentHeight = Math.max(MIN_CONTENT_HEIGHT, this.computeContentHeight(this._config));\n const target = Math.max(MIN_DIALOG_HEIGHT, TITLE_HEIGHT + contentHeight + BUTTON_HEIGHT);\n\n const vp = DOM.source.getViewportSize();\n const capped = Math.min(target, Math.max(MIN_DIALOG_HEIGHT, vp.height - DIALOG_VIEWPORT_MARGIN * 2));\n\n if (capped === this.getHeight()) {\n return this;\n }\n\n this.setHeight(capped);\n this.scheduleLayout();\n this.center();\n\n return this;\n }\n\n /**\n * Appends backdrop and dialog to the DOM, centers the panel, and captures focus.\n */\n private open(): void {\n this._previousFocus = DOM.source.getActiveElement();\n\n if (this._config.closeOnBackdrop && this._config.dismissable !== false) {\n this._backdrop.addClickListener(() => { this.hide('close'); });\n }\n\n // Join the central layer tree and stamp the panel from the Dialog\n // band; the backdrop sits one below the panel so stacked dialogs keep\n // each panel above its own backdrop.\n LayerManager.register(this);\n\n const panelZ = LayerManager.getZIndex(this);\n this.setZIndex(panelZ);\n this._backdrop.setZIndex(panelZ - 1);\n\n const backdropEl = this._backdrop.getElement(true)!;\n LayerManager.mount(backdropEl);\n\n const dialogEl = this.getElement(true)!;\n LayerManager.mount(dialogEl);\n\n // Trap wheels no inner scroller claimed so the content behind a modal\n // dialog stays inert, matching modality.\n trapWheel(this);\n\n this.scheduleLayout();\n this.center();\n this.animateIn();\n\n // The construction-time height assumed single-line content; once the\n // first layout has sized the content at the dialog width, content whose\n // height depends on width (wrapping Text) has settled, so re-fit to it.\n // A no-op for content whose height did not change (resizeToContent bails\n // when the height is unchanged), so only width-dependent content reflows.\n Component.afterNextLayout(() => this.resizeToContent());\n\n Event.addViewportListener(this, 'keydown', this._boundKeyHandler);\n Event.addViewportListener(this, 'resize', this._boundResizeHandler);\n\n // Deferred past the scheduled layout: focusing synchronously here does\n // land on the right element, but the first layout then wraps the content\n // in its frame and re-parents the subtree into it. Moving a focused\n // element out of the document blurs it — silently, with no blur event —\n // so the focus is undone a frame later and lands nowhere.\n Component.afterNextLayout(() => this.focusFirst());\n }\n\n /**\n * Fades the backdrop in and the dialog panel in from `opacity: 0` +\n * `scale(0.97)` to `opacity: 1` + `scale(1)` over 150ms. No-op when\n * `prefers-reduced-motion: reduce` is set.\n */\n private animateIn(): void {\n const el = this.getElement();\n const bdEl = this._backdrop.getElement();\n\n if (!el) {\n return;\n }\n\n this._panelInAnimation?.cancel();\n this._panelInAnimation = Animation.play(el, {\n from: { opacity: \"0\", transform: \"scale(0.97)\" },\n to: { opacity: \"1\", transform: \"scale(1)\" },\n durationMs: DIALOG_ANIM_DURATION_MS,\n properties: [\"opacity\", \"transform\"],\n });\n\n if (bdEl) {\n this._backdropInAnimation?.cancel();\n this._backdropInAnimation = Animation.play(bdEl, {\n from: { opacity: \"0\" },\n to: { opacity: \"1\" },\n durationMs: DIALOG_ANIM_DURATION_MS,\n properties: [\"opacity\"],\n });\n }\n }\n\n /**\n * Centers the dialog panel within the viewport.\n */\n private center(): void {\n const vp = DOM.source.getViewportSize();\n const x = Math.max(0, Math.round((vp.width - this.getWidth()) / 2));\n const y = Math.max(0, Math.round((vp.height - this.getHeight()) / 2));\n\n this.setX(x);\n this.setY(y);\n }\n\n /**\n * Moves initial focus into the dialog. Prefers the configured\n * `initialFocus` component, then the first focusable element in the content\n * region, so a form field — not the title-bar close button, which is first in\n * DOM order — receives focus on open. Falls back to the primary action\n * button, then to the first focusable element anywhere in the dialog.\n *\n * @remarks Must run after the dialog's first layout, which re-parents the\n * content into its frame and would blur anything focused before it.\n */\n private focusFirst(): void {\n const requested = this.requestedFocusElement();\n\n if (requested) {\n DOM.sink.focus(requested);\n\n return;\n }\n\n const contentEl = this._contentContainer.getElement();\n const inContent = contentEl ? DOM.source.querySelectorAll(contentEl, FOCUSABLE_SELECTOR) : [];\n\n if (inContent.length > 0) {\n DOM.sink.focus(inContent[0]);\n\n return;\n }\n\n const primary = this.primaryButtonElement();\n\n if (primary) {\n DOM.sink.focus(primary);\n\n return;\n }\n\n const el = this.getElement();\n const focusable = el ? DOM.source.querySelectorAll(el, FOCUSABLE_SELECTOR) : [];\n\n if (focusable.length > 0) {\n DOM.sink.focus(focusable[0]);\n }\n }\n\n /**\n * Resolves the configured `initialFocus` component to the element that\n * should take focus: the component's own root element when it is itself\n * focusable (a `TextField` renders as the `<input>`), otherwise its first\n * focusable descendant (a `Panel` wrapping a field).\n *\n * @returns The element to focus, or `null` when no `initialFocus` is\n * configured or it offers nothing focusable — both of which fall through\n * to the default order.\n */\n private requestedFocusElement(): Handle | null {\n const component = this._config.initialFocus;\n const element = component?.getElement();\n\n if (!element) {\n return null;\n }\n\n if (DOM.source.matches(element, FOCUSABLE_SELECTOR)) {\n return element;\n }\n\n return DOM.source.querySelector(element, FOCUSABLE_SELECTOR);\n }\n\n /**\n * Returns the DOM element of the primary action button, used as the initial\n * focus target when the content region has nothing focusable. Resolves by\n * position: the index of the `primary` entry in the resolved button set maps\n * to the same-indexed focusable in the button row.\n *\n * @returns The primary button element, or `null` when none is primary or the\n * row is not yet rendered.\n */\n private primaryButtonElement(): Handle | null {\n const buttons = this._config.buttons ?? DEFAULT_BUTTONS;\n const index = buttons.findIndex(b => b.primary);\n\n if (index < 0) {\n return null;\n }\n\n const rowEl = this._buttonRow.getElement();\n const focusable = rowEl ? DOM.source.querySelectorAll(rowEl, FOCUSABLE_SELECTOR) : [];\n\n return focusable[index] ?? null;\n }\n\n /**\n * Collects all currently focusable elements inside the dialog.\n *\n * @returns An array of focusable elements in DOM order.\n */\n private getFocusable(): Handle[] {\n const el = this.getElement();\n\n if (!el) {\n return [];\n }\n\n return DOM.source.querySelectorAll(el, FOCUSABLE_SELECTOR)\n .filter(el => !DOM.source.hasAttribute(el, 'disabled'));\n }\n\n /**\n * Handles document-level keydown events for Escape and Tab focus trapping.\n *\n * @param e - The keyboard event.\n * @returns A stop-and-prevent disposition when the dialog handles the key (the Tab trap, or Enter); nothing otherwise, so unhandled keys keep propagating.\n */\n private onKeyDown(e: KeyboardEvent): Event.ListenerResult {\n // Escape is owned by LayerManager's keydown handler, which closes the\n // topmost non-manual layer (this dialog when it is on top). The dialog\n // keeps only the Tab focus-trap and the Enter-confirms-the-primary\n // shortcut here.\n if (e.key === 'Enter') {\n return this.onEnter(e);\n }\n\n if (e.key === 'Tab') {\n const focusable = this.getFocusable();\n\n if (focusable.length === 0) {\n return { stop: true, prevent: true };\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n if (DOM.source.getActiveElement() === first) {\n DOM.sink.focus(last);\n\n return { stop: true, prevent: true };\n }\n } else {\n if (DOM.source.getActiveElement() === last) {\n DOM.sink.focus(first);\n\n return { stop: true, prevent: true };\n }\n }\n }\n\n return;\n }\n\n /**\n * Confirms the dialog on Enter by resolving the primary button's result,\n * so a simple form submits like one without the caller wiring Enter itself.\n *\n * @remarks Deliberately inert when focus is on a `<textarea>` (Enter inserts\n * a newline) or on a `<button>` (the button activates itself on Enter, and\n * hijacking it would fire the wrong action). No-op when no button is marked\n * `primary`, so a dialog with no clear default action does not submit blind.\n *\n * @param _e - The keydown event for the Enter press.\n * @returns `{ stop: true, prevent: true }` when Enter confirms the dialog; nothing when there is nothing to confirm.\n */\n private onEnter(_e: KeyboardEvent): Event.ListenerResult {\n const active = DOM.source.getActiveElement();\n const tag = active ? DOM.source.getTagName(active).toLowerCase() : null;\n\n if (tag === 'textarea' || tag === 'button') {\n return;\n }\n\n const result = this.primaryResult();\n\n if (result === null) {\n return;\n }\n\n this.hide(result);\n\n return { stop: true, prevent: true };\n }\n\n /**\n * Returns the result of the button marked `primary` in this dialog's\n * resolved button set — the action Enter confirms — or `null` when none is\n * primary.\n *\n * @returns The primary button's [`DialogResult`](/api/overlay/type-aliases/DialogResult), or `null`.\n */\n private primaryResult(): DialogResult | null {\n const buttons = this._config.buttons ?? DEFAULT_BUTTONS;\n const primary = buttons.find(b => b.primary);\n\n return primary ? (primary.result ?? 'cancel') : null;\n }\n\n /**\n * Re-fits the dialog to the resized viewport: {@link Dialog.resizeToContent}\n * grows it back toward its content when the viewport gained room, or caps it\n * (so the content area scrolls) when the viewport shrank below the content —\n * keeping the dialog within the viewport instead of overflowing it. The\n * backdrop is resized to the new viewport and the panel re-centred (again\n * unconditionally here, since `resizeToContent` skips re-centring when the\n * height is unchanged).\n */\n private onViewportResize(): void {\n this._backdrop.resize();\n this.resizeToContent();\n this.center();\n }\n\n /**\n * Dismisses the dialog with a brief fade-and-scale animation, restores\n * focus, and resolves the promise.\n *\n * @param result - The result to resolve the promise with.\n *\n * @remarks Honours `prefers-reduced-motion: reduce` — the transition is\n * skipped when motion is reduced.\n */\n hide(result: DialogResult): this {\n Event.removeViewportListener(this, 'keydown', this._boundKeyHandler);\n Event.removeViewportListener(this, 'resize', this._boundResizeHandler);\n\n const finalize = (): void => {\n this._finalizing = true;\n\n this._backdrop.destroy();\n this.removeElement();\n this.destructor();\n\n LayerManager.unregister(this);\n untrapWheel(this);\n\n if (this._previousFocus !== null) {\n DOM.sink.focus(this._previousFocus);\n }\n\n if (this._resolvePromise) {\n this._resolvePromise(result);\n this._resolvePromise = null;\n }\n };\n\n const el = this.getElement();\n const bdEl = this._backdrop.getElement();\n\n if (!el) {\n finalize();\n return this;\n }\n\n this._panelOutAnimation?.cancel();\n this._panelOutAnimation = Animation.play(el, {\n to: { opacity: \"0\", transform: \"scale(0.97)\" },\n durationMs: DIALOG_ANIM_DURATION_MS,\n properties: [\"opacity\", \"transform\"],\n onComplete: finalize,\n });\n\n if (bdEl) {\n this._backdropOutAnimation?.cancel();\n this._backdropOutAnimation = Animation.play(bdEl, {\n to: { opacity: \"0\" },\n durationMs: DIALOG_ANIM_DURATION_MS,\n properties: [\"opacity\"],\n });\n }\n\n return this;\n }\n\n /**\n * Cancels any in-flight panel / backdrop animation, then defers to the base\n * class. Reached from `hide()`'s completion callback as well as from a\n * direct dispose: on that path the dismiss animation is already finished, so\n * cancelling it is a no-op.\n */\n protected destructor(): void {\n this._panelInAnimation?.cancel();\n this._panelInAnimation = null;\n this._backdropInAnimation?.cancel();\n this._backdropInAnimation = null;\n this._panelOutAnimation?.cancel();\n this._panelOutAnimation = null;\n this._backdropOutAnimation?.cancel();\n this._backdropOutAnimation = null;\n\n // A dispose that lands mid-dismiss cancels the animation whose\n // completion callback owns the rest of teardown, so run that work here.\n // The backdrop is a private field rather than a registered child, so the\n // base class's recursion cannot reach it and it would otherwise stay\n // mounted over the whole app; the promise `show()` handed the caller\n // would never settle. Skipped when `finalize` is already running, which\n // reaches this method partway through and completes the rest itself —\n // including resolving with the caller's real result rather than the\n // `\"close\"` stand-in used here.\n if (!this._finalizing) {\n this._backdrop.destroy();\n\n LayerManager.unregister(this);\n untrapWheel(this);\n\n if (this._resolvePromise) {\n this._resolvePromise('close');\n this._resolvePromise = null;\n }\n }\n\n super.destructor();\n }\n\n /**\n * Returns the content container component where custom content is rendered.\n *\n * @returns The content container [`Component`](/api/core/classes/Component).\n */\n getContentComponent(): Component {\n return this._contentContainer;\n }\n\n /**\n * The dialog sizes itself explicitly — its height is computed to fit its\n * content at construction and re-fit (capped to the viewport) in\n * {@link Dialog.resizeToContent} — so it must not additionally floor itself\n * to its content's min-size. If it did, a dialog whose content is taller\n * than the viewport could not shrink to the capped height, and its\n * `autoScroll` content container would never get the constrained space it\n * needs to scroll (it would clip instead). The `MIN_DIALOG_HEIGHT` floor is\n * applied explicitly wherever the height is set.\n */\n protected clampsToContentSize(): boolean {\n return false;\n }\n\n /**\n * Returns the dialog's title-bar component.\n *\n * @returns The internal title-bar instance, exposing `getTitleText()` and\n * `setGlyph()` for callers (e.g. the notification detail dialog)\n * that need to tint or decorate the header.\n *\n * @remarks\n * The `DialogTitleBar` class itself is not exported — callers reach it\n * only through this accessor and interact via its few public methods\n * (`getTitleText`, `setGlyph`, `getGlyph`).\n */\n getTitleBar(): DialogTitleBar {\n return this._titleBar;\n }\n\n // ----- DismissableLayer -----\n\n /**\n * Returns the dialog panel's root element for the central layer tree.\n *\n * @returns The dialog's element, or null when not yet rendered.\n */\n getLayerElement(): Handle | null {\n return this.getElement() ?? null;\n }\n\n /**\n * Returns the dismiss mode the document-level handlers consult. A dialog\n * is `\"modal\"`: the manager neither dismisses ancestors on an outside\n * interaction nor lets one fall through, and it owns the Escape-to-close\n * shortcut. The dialog keeps its own Tab focus-trap.\n *\n * @returns The layer dismiss mode.\n */\n getDismissMode(): LayerDismissMode {\n return \"modal\";\n }\n\n /**\n * Advisory close request from the manager — closes the dialog with the\n * `'close'` result, matching the title-bar close affordance.\n *\n * @remarks No-op when `dismissable` is `false`: this is the Escape path\n * (`LayerManager` routes Escape to the topmost non-`\"manual\"` layer's\n * `requestClose()`), so a mandatory modal swallows Escape rather than\n * closing. `getDismissMode()` deliberately stays `\"modal\"` here — a\n * `\"manual\"` layer would be skipped by the Escape loop, letting Escape\n * fall through to close a layer beneath this one.\n */\n requestClose(): void {\n if (this._config.dismissable === false) {\n return;\n }\n\n this.hide('close');\n }\n\n /**\n * Returns the dialog's z-index band so unrelated dialogs stack above\n * every other overlay family.\n *\n * @returns The dialog band base.\n */\n getBand(): number {\n return LayerManager.Band.Dialog;\n }\n\n /**\n * Displays a modal dialog and returns a promise that resolves on dismissal.\n *\n * @param config - Dialog configuration.\n * @returns A promise resolving to the [`DialogResult`](/api/overlay/type-aliases/DialogResult) of the closing action.\n *\n * @example\n * ```typescript\n * const result = await Dialog.show({ title: 'Confirm', message: 'Proceed?' });\n * ```\n */\n static show(config: DialogConfig): Promise<DialogResult> {\n const dialog = new Dialog(config);\n\n return dialog.show();\n }\n\n /**\n * Displays a confirm/cancel dialog and resolves to `true` when the user confirms.\n *\n * Buttons are ordered Cancel (default focus) then Confirm, so pressing Enter or\n * Escape both safely default to cancellation.\n *\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n * @returns A promise resolving to `true` if the user clicked Confirm, `false` otherwise.\n *\n * @example\n * ```typescript\n * if (await Dialog.confirm('Delete record', 'This cannot be undone.')) {\n * store.remove(record);\n * }\n * ```\n */\n static async confirm(title: string, message: string): Promise<boolean> {\n const result = await Dialog.show({\n title,\n message,\n buttons: [\n { ...DialogButtons.Cancel, primary: true },\n DialogButtons.Confirm,\n ],\n });\n\n return result === 'confirm';\n }\n\n /**\n * Displays a severity-toned dialog with a single OK button and resolves once\n * the user acknowledges it. Shared by the {@link Dialog.info} /\n * {@link Dialog.success} / {@link Dialog.warning} / {@link Dialog.error}\n * shorthands.\n *\n * @param severity - The title-bar severity tone (see {@link DialogConfig.severity}).\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n */\n private static async alert(severity: DialogSeverity, title: string, message: string): Promise<void> {\n await Dialog.show({\n title,\n message,\n severity,\n buttons: [{ ...DialogButtons.Ok, primary: true }],\n });\n }\n\n /**\n * Displays an info-toned dialog with a single OK button and resolves once the\n * user acknowledges it.\n *\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n *\n * @example\n * ```typescript\n * await Dialog.info('Import complete', 'Loaded 1,204 rows.');\n * ```\n */\n static info(title: string, message: string): Promise<void> {\n return Dialog.alert('info', title, message);\n }\n\n /**\n * Displays a success-toned dialog with a single OK button and resolves once\n * the user acknowledges it.\n *\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n *\n * @example\n * ```typescript\n * await Dialog.success('Saved', 'Your changes have been stored.');\n * ```\n */\n static success(title: string, message: string): Promise<void> {\n return Dialog.alert('success', title, message);\n }\n\n /**\n * Displays a warning-toned dialog with a single OK button and resolves once\n * the user acknowledges it.\n *\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n *\n * @example\n * ```typescript\n * await Dialog.warning('Unsaved changes', 'They will be lost if you continue.');\n * ```\n */\n static warning(title: string, message: string): Promise<void> {\n return Dialog.alert('warning', title, message);\n }\n\n /**\n * Displays an error-toned dialog with a single OK button and resolves once\n * the user acknowledges it. The title bar carries the error severity tint and\n * glyph (see {@link DialogConfig.severity}).\n *\n * @param title - Text displayed in the title bar.\n * @param message - Body message shown in the content area.\n *\n * @example\n * ```typescript\n * await Dialog.error('Connection failed', 'Host not allowed.');\n * ```\n */\n static error(title: string, message: string): Promise<void> {\n return Dialog.alert('error', title, message);\n }\n}\n\nconst DialogCallable = callable(Dialog);\ntype DialogCallable = Dialog;\nexport {\n Dialog as _Dialog,\n DialogCallable as Dialog,\n DialogTitleBar\n};\n"],"mappings":"0/BAqBA,IAAM,EAAgC,GAQhC,EAA6B,EAAwB,EAAK,KAAK,MAS/D,EAA6B,KAAK,KAAK,CAAiB,EAAI,EAG5D,EAA8B,EAG9B,EAAiC,EAGjC,EAAmC,IAuDnC,EAAkD,CACpD,OAAW,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,EAChC,UAAW,OACX,UAAW,gBACX,UAAW,GACX,gBAAiB,8CACjB,gBAAiB,2CAEjB,OAAc,CAAE,OAAQ,2DAA4D,EACpF,aAAc,mCACd,OAAc,+DAClB,EAuCM,QAAN,cAAsB,CAAsD,CASxE,mBAAuD,SAMvD,eAAuD,KACvD,YAA+C,KAI/C,mBAA4D,KAC5D,mBAA4D,KAC5D,eAA4C,KAC5C,gBAA+C,KAC/C,QAAsC,GACtC,iBAAuC,CAAC,EAExC,gBACA,UAWA,YAAY,EAA0B,EAA4C,CAC9E,MAAM,EAA2B,CAAE,GAAG,EAAwB,GAAI,GAAoB,CAAC,CAAG,CAAC,EAE3F,IAAM,EAAO,IAAI,EAEjB,EAAK,cAAc,EAAI,EACvB,KAAK,iBAAiB,CAAI,EAK1B,KAAK,YAAY,EAAS,KAAK,EAC/B,KAAK,WAAW,EAAK,EAKrB,KAAK,WAAW,QAAQ,EACxB,KAAK,YAAY,SAAS,EAC1B,KAAK,QAAQ,CAAC,CAAC,QAAQ,QAAQ,EAE/B,KAAK,oBAAwB,KAAK,YAAY,EAC9C,KAAK,cAAwB,KAAK,YAAY,EAO9C,KAAK,SAAoB,KACzB,KAAK,kBAAoB,KACzB,KAAK,WAAoB,IAC7B,CASA,aAAuB,EAA+B,CAelD,OAdA,MAAM,aAAa,CAAO,EAK1B,KAAK,aAAa,EAAQ,WAAa,KAAK,aAAa,CAAC,EAC1D,KAAK,aAAa,EAAQ,WAAa,KAAK,aAAa,CAAC,EAC1D,KAAK,aAAa,EAAQ,WAAa,KAAK,YAAY,CAAC,EACrD,EAAQ,QAAU,IAAA,IAAW,KAAK,SAAS,EAAQ,KAAK,EAIxD,EAAQ,UAAY,IAAA,KAAW,KAAK,SAAW,EAAQ,SAEpD,IACX,CAQA,aAAa,EAA2B,CAGpC,MAFA,MAAK,WAAa,EAEX,IACX,CAOA,cAAiC,CAC7B,OAAO,KAAK,YAAc,KAAK,gBAAgB,SACnD,CAQA,aAAa,EAAgC,CAGzC,MAFA,MAAK,WAAa,EAEX,IACX,CAOA,cAAmC,CAC/B,OAAO,KAAK,YAAc,KAAK,gBAAgB,SACnD,CAQA,aAAa,EAAsB,CAO/B,MANA,MAAK,WAAa,EAEd,KAAK,iBACL,KAAK,gBAAgB,WAAW,CAAK,EAGlC,IACX,CAOA,aAAuB,CACnB,OAAO,KAAK,YAAc,KAAK,gBAAgB,SACnD,CAUA,SAAS,EAA2B,CAkBhC,OAjBI,IAAS,KACF,KAAK,WAAW,GAG3B,KAAK,OAAS,EAET,KAAK,gBAMN,KAAK,gBAAgB,QAAQ,CAAI,GALjC,KAAK,gBAAkB,IAAI,EAAK,CAAI,EACpC,KAAK,gBAAgB,cAAc,MAAM,EAEzC,KAAK,gBAAgB,KAAK,gBAAiB,CAAC,GAKhD,KAAK,cAAc,EAEZ,KACX,CAOA,UAA0B,CACtB,OAAO,KAAK,MAChB,CAOA,YAAmB,CAUf,MATA,CAEI,KAAK,mBADL,KAAK,gBAAgB,KAAK,eAAe,EAClB,MAG3B,KAAK,OAAS,KAEd,KAAK,cAAc,EAEZ,IACX,CAUA,QAAQ,EAAmC,CACvC,AAEI,KAAK,kBADL,KAAK,gBAAgB,KAAK,cAAc,EAClB,MAG1B,IAAM,EAAkB,OAAO,GAAY,SACrC,IAAI,EAAK,CAAO,EAChB,EAEN,KAAK,eAAiB,EAGtB,IAAM,EAAgB,QAAK,gBAM3B,OAJA,KAAK,gBAAgB,EAAM,CAAW,EAEtC,KAAK,cAAc,EAEZ,IACX,CAOA,SAA4B,CACxB,OAAO,KAAK,cAChB,CAUA,UAAU,EAAe,EAA2B,CAC3C,KAAK,cACN,KAAK,YAAc,IAAI,EACvB,KAAK,YAAY,iBAAiB,IAAI,CAAM,EAE5C,KAAK,aAAa,KAAK,WAAW,GAGtC,IAAM,EAAS,IAAI,EAAO,CAAK,EAM/B,OAJA,EAAO,GAAG,SAAU,CAAO,EAE3B,KAAK,YAAY,aAAa,CAAM,EAE7B,IACX,CAOA,cAAqB,CAMjB,MALA,CAEI,KAAK,eADL,KAAK,gBAAgB,KAAK,WAAW,EAClB,MAGhB,IACX,CAQA,iBAAyB,EAAkB,CAGvC,MAFA,MAAK,eAAiB,EAEf,IACX,CASA,kBAAkB,EAAoB,CAClC,OAAO,KAAK,iBAAiB,EAAE,WAAW,EAAI,CAAE,CACpD,CASA,MAAa,CACT,GAAI,CAAC,KAAK,eAEN,OADA,QAAQ,KAAK,mEAAmE,EACzE,KAGX,KAAK,QAAU,GAIf,EAAa,SAAS,IAAI,EAC1B,KAAK,UAAU,EAAa,UAAU,IAAI,CAAC,EAE3C,IAAM,EAAK,KAAK,WAAW,EAAI,EAqB/B,OAnBA,EAAa,MAAM,CAAE,EAIrB,EAAU,IAAI,EAEd,KAAK,YAAY,EACjB,KAAK,WAAW,EAAI,EAIpB,KAAK,SAAS,EACd,KAAK,YAAY,EAEjB,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,EAAS,KAAM,CAAE,WAAY,CAAyB,CAAC,EAEjF,KAAK,0BAA0B,EAExB,IACX,CASA,MAAa,CAoBT,OAnBK,KAAK,SAIV,KAAK,QAAU,GAEf,KAAK,0BAA0B,EAE/B,EAAa,WAAW,IAAI,EAC5B,EAAY,IAAI,EAEhB,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,EAAkB,KAAM,CAAE,WAAY,CAAyB,CAAC,EAK1F,KAAK,WAAW,EAET,MAlBI,IAmBf,CAOA,QAAkB,CACd,OAAO,KAAK,OAChB,CASA,iBAAiC,CAC7B,OAAO,KAAK,WAAW,GAAK,IAChC,CAWA,gBAAmC,CAC/B,OAAO,KAAK,YAAc,KAAK,gBAAgB,SACnD,CAMA,cAAqB,CACjB,KAAK,KAAK,CACd,CAQA,kBAAkC,CAC9B,OAAO,KAAK,cAChB,CAQA,SAAkB,CACd,OAAO,EAAa,KAAK,OAC7B,CAQA,UAAiB,CAOb,OANA,MAAM,SAAS,EAEX,KAAK,iBAAmB,KAAK,YAAc,KAAK,gBAChD,KAAK,cAAc,EAGhB,IACX,CAOA,YAA6B,CACrB,KAAK,SACL,KAAK,KAAK,EAcd,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,KAC1B,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,KAE1B,KAAK,iBAAiB,QAAQ,EAE9B,KAAK,eAAmB,KACxB,KAAK,gBAAmB,KACxB,KAAK,eAAmB,KACxB,KAAK,YAAmB,KACxB,KAAK,gBAAmB,KACxB,KAAK,SAAmB,KAExB,MAAM,WAAW,CACrB,CAcA,eAA8B,CACrB,KAAK,UAIV,KAAK,SAAS,EACd,KAAK,YAAY,EACrB,CAOA,aAA4B,CACxB,GAAI,CAAC,KAAK,eACN,OAGJ,IAAM,EAAa,EAAI,OAAO,eAAe,KAAK,cAAc,EAGhE,GAAI,EAAW,QAAU,GAAK,EAAW,SAAW,EAAG,CACnD,KAAK,KAAK,EACV,MACJ,CAEA,IAAM,EAAY,KAAK,iBAAiB,EAClC,EAAY,GAAW,OAAU,KAAK,SAAS,EAC/C,EAAY,GAAW,QAAU,KAAK,UAAU,EAChD,EAAY,EAAI,OAAO,gBAAgB,EAEvC,EAAW,KAAK,iBAAiB,EAAY,EAAO,EAAQ,CAAE,EAEpE,KAAK,mBAAqB,EAE1B,IAAI,EAAY,EACZ,EAAY,EAEZ,IAAa,OACb,EAAI,EAAW,MAAQ,EAAW,MAAS,GAAU,EACrD,EAAI,EAAW,IAAO,EAAS,GACxB,IAAa,UACpB,EAAI,EAAW,MAAQ,EAAW,MAAS,GAAU,EACrD,EAAI,EAAW,OAAS,GACjB,IAAa,QACpB,EAAI,EAAW,KAAO,EAAQ,EAC9B,EAAI,EAAW,KAAQ,EAAW,OAAS,GAAU,IAErD,EAAI,EAAW,MAAQ,EACvB,EAAI,EAAW,KAAS,EAAW,OAAS,GAAU,GAQ1D,IAAI,EAAO,EACP,EAAO,EAAG,MAAQ,EAAQ,EAC1B,EAAO,EACP,EAAO,EAAG,OAAS,EAAS,EAE5B,IAAa,QACb,GAAQ,EACD,IAAa,OACpB,GAAQ,EACD,IAAa,SACpB,GAAQ,EAER,GAAQ,EAGZ,EAAI,EAAK,MAAM,EAAG,EAAM,CAAI,EAC5B,EAAI,EAAK,MAAM,EAAG,EAAM,CAAI,EAE5B,KAAK,KAAK,CAAC,EACX,KAAK,KAAK,CAAC,EACX,KAAK,SAAS,CAAK,EACnB,KAAK,UAAU,CAAM,EAEjB,KAAK,iBAAmB,KAAK,YAC7B,KAAK,cAAc,CAE3B,CAcA,iBACI,EACA,EACA,EACA,EACgB,CAChB,IAAM,EAAc,EAAO,IACrB,EAAc,EAAG,OAAS,EAAO,OACjC,EAAc,EAAO,KACrB,EAAc,EAAG,MAAS,EAAO,MAEvC,GAAI,KAAK,aAAe,OAAQ,CAC5B,IAAM,EAAS,EAAS,EAClB,EAAS,EAAS,EAElB,EAA6E,CAC/E,CAAE,KAAM,SAAU,MAAO,EAAa,KAAM,CAAO,EACnD,CAAE,KAAM,MAAU,MAAO,EAAa,KAAM,CAAO,EACnD,CAAE,KAAM,QAAU,MAAO,EAAa,KAAM,CAAO,EACnD,CAAE,KAAM,OAAU,MAAO,EAAa,KAAM,CAAO,CACvD,EAIM,EAAU,EAAW,OAAO,GAAK,EAAE,OAAS,EAAE,IAAI,EAClD,EAAU,EAAQ,OAAS,EAAI,EAAU,EAI/C,OAFA,EAAK,MAAM,EAAG,IAAM,EAAE,MAAQ,EAAE,KAAK,EAE9B,EAAK,EAAE,CAAC,IACnB,CAGA,IAAM,KAAQ,GACN,IAAS,MAAmB,GAAe,EAAS,EACpD,IAAS,SAAmB,GAAe,EAAS,EACpD,IAAS,OAAmB,GAAe,EAAS,EAEjD,GAAc,EAAQ,EAGjC,GAAI,KAAK,KAAK,UAAU,EACpB,OAAO,KAAK,WAUhB,IAAM,EAAU,CANZ,IAAQ,SACR,OAAQ,MACR,KAAQ,QACR,MAAQ,MAGI,EAAS,KAAK,YAI9B,OAFA,QAAQ,KAAK,gCAAgC,KAAK,WAAW,6CAA6C,EAAQ,GAAG,EAE9G,CACX,CAYA,aAA4B,CACxB,GAAI,KAAK,gBACL,OAGJ,IAAM,EAAQ,IAAI,EACZ,EAAQ,EAEd,EAAM,mBAAmB,6CAA6C,EACtE,EAAM,SAAS,CAAI,EACnB,EAAM,UAAU,CAAI,EACpB,EAAM,aAAa,eAAe,EAClC,EAAM,iBAAiB,MAAM,EAC7B,EAAM,WAAW,KAAK,UAAU,EAEhC,KAAK,gBAAkB,EAEvB,IAAM,EAAY,KAAK,WAAW,EAAI,EACtC,EAAI,KAAK,aAAa,EAAW,EAAM,WAAW,EAAI,EAAI,EAAI,OAAO,cAAc,CAAS,CAAC,CACjG,CASA,eAA8B,CAC1B,GAAI,CAAC,KAAK,gBAAkB,CAAC,KAAK,gBAC9B,OAGJ,IAAM,EAAa,EAAI,OAAO,eAAe,KAAK,cAAc,EAC1D,EAAa,EACb,EAAa,EAAO,EACpB,EAAa,KAAK,KAAK,EACvB,EAAa,KAAK,KAAK,EACvB,EAAa,KAAK,SAAS,EAC3B,EAAa,KAAK,UAAU,EAK5B,OAAS,EAAe,EAAa,IAAwB,KAAK,IAAI,EAAK,KAAK,IAAI,EAAO,CAAG,CAAC,EAO/F,EAAc,kDAChB,EAEJ,AAOI,EAPA,KAAK,qBAAuB,SACd,iBAAiB,EAAY,kBAAkB,IACtD,KAAK,qBAAuB,MACrB,kBAAkB,EAAY,mBAAmB,IACxD,KAAK,qBAAuB,QACrB,iBAAiB,EAAY,mBAAmB,IAEhD,iBAAiB,EAAY,mBAAmB,IAGlE,KAAK,gBAAgB,UAAU,CAAW,EAE1C,IAAM,EAAS,EAAI,OAAO,gBAAgB,EACpC,EAAS,KAAK,cAAc,EAMlC,GAAI,KAAK,qBAAuB,OAAS,KAAK,qBAAuB,SAAU,CAC3E,IAAM,EAAgB,EAAW,KAAO,EAAW,MAAQ,EACrD,EAAgB,KAAK,IACvB,EACA,EAAyB,EAAW,EAAoB,CAC5D,EACM,EAAgB,KAAK,IACvB,EAAW,EAAO,EAClB,EAAG,MAAQ,EAAyB,EAAW,EAAO,CAC1D,EACM,EAAgB,MAAM,EAAgB,EAAW,EAAO,EAAO,KAAM,EAAW,CAAS,EAE/F,KAAK,gBAAgB,KAAK,CAAM,EAI5B,KAAK,qBAAuB,SAC5B,KAAK,gBAAgB,KAAK,GAAQ,EAAO,GAAG,EAE5C,KAAK,gBAAgB,KAAK,EAAW,EAAO,EAAO,GAAG,CAE9D,KAAO,CACH,IAAM,EAAgB,EAAW,IAAM,EAAW,OAAS,EACrD,EAAgB,KAAK,IACvB,EACA,EAAyB,EAAW,EAAoB,CAC5D,EACM,EAAgB,KAAK,IACvB,EAAW,EAAO,EAClB,EAAG,OAAS,EAAyB,EAAW,EAAO,CAC3D,EACM,EAAgB,MAAM,EAAgB,EAAW,EAAO,EAAO,IAAK,EAAW,CAAS,EAE9F,KAAK,gBAAgB,KAAK,CAAM,EAE5B,KAAK,qBAAuB,QAC5B,KAAK,gBAAgB,KAAK,GAAQ,EAAO,IAAI,EAE7C,KAAK,gBAAgB,KAAK,EAAW,EAAO,EAAO,IAAI,CAE/D,CACJ,CAMA,2BAA0C,CAGtC,GAFA,EAAM,oBAAoB,KAAM,SAAU,KAAK,eAAe,EAE1D,KAAK,eAAgB,CACrB,KAAK,iBAAmB,KAAK,uBAAuB,KAAK,cAAc,EAEvE,IAAK,IAAM,KAAY,KAAK,iBACxB,EAAI,KAAK,YAAY,EAAU,SAAU,KAAK,UAAW,CAAE,QAAS,EAAK,CAAC,CAElF,CACJ,CAKA,2BAA0C,CACtC,EAAM,uBAAuB,KAAM,SAAU,KAAK,eAAe,EAEjE,IAAK,IAAM,KAAY,KAAK,iBACxB,EAAI,KAAK,eAAe,EAAU,SAAU,KAAK,SAAS,EAG9D,KAAK,iBAAmB,CAAC,CAC7B,CASA,uBAA+B,EAAwB,CACnD,IAAM,EAAgB,CAAC,EACnB,EAAwB,EAAI,OAAO,iBAAiB,CAAI,EAE5D,KAAO,GAAU,IAAW,EAAI,OAAO,mBAAmB,GAAG,CACzD,IAAM,EAAQ,EAAI,OAAO,oBAAoB,CAAM,EAC7C,EAAW,EAAM,SAAW,EAAM,UAAY,EAAM,UAEtD,wBAAwB,KAAK,CAAQ,GACrC,EAAI,KAAK,CAAM,EAGnB,EAAS,EAAI,OAAO,iBAAiB,CAAM,CAC/C,CAIA,OAFA,EAAI,KAAK,EAAI,OAAO,mBAAmB,CAAC,EAEjC,CACX,CACJ,EAEM,EAAkB,EAAS,OAAO,ECn+BlC,EAAgE,CAAC,EAQjE,eAAN,cAA6B,CAAiC,CAU1D,YAAY,EAAiC,EAAmD,CAC5F,MAAM,EAAS,CAAE,GAAG,EAA+B,GAAI,GAAoB,CAAC,CAAG,CAAC,EAEhF,IAAM,EAAK,EAAI,OAAO,gBAAgB,EAEtC,KAAK,YAAY,EAAS,KAAK,EAC/B,KAAK,KAAK,CAAC,EACX,KAAK,KAAK,CAAC,EACX,KAAK,SAAS,EAAG,KAAK,EACtB,KAAK,UAAU,EAAG,MAAM,EACxB,KAAK,UAAU,KAAK,EACpB,KAAK,mBAAmB,iCAAiC,CAC7D,CAOA,iBAAiB,EAAgC,CAG7C,OAFA,EAAM,YAAY,KAAM,QAAS,CAAQ,EAElC,IACX,CAKA,QAAe,CACX,IAAM,EAAK,EAAI,OAAO,gBAAgB,EAEtC,KAAK,SAAS,EAAG,KAAK,EACtB,KAAK,UAAU,EAAG,MAAM,CAC5B,CAKA,SAAgB,CACZ,KAAK,cAAc,EACnB,KAAK,WAAW,CACpB,CACJ,EAEM,EAAyB,EAAS,cAAc,ECxDtD,EAAM,SAAS,EAAO,EAAc,EAAa,EAAsB,CAAkB,EA8FzF,IAAM,EAAyB,GACzB,EAAyB,GACzB,EAAyB,GACzB,EAAyB,EACzB,EAAyB,GACzB,EAAyB,GACzB,EAAyB,GACzB,EAA4B,IAC5B,EAA4B,IAC5B,EAA6B,GAM7B,EAAiD,CACnD,KAAS,cACT,QAAS,eACT,QAAS,uBACT,MAAS,oBACb,EAMM,EAAkC,IAOlC,EAAqB,2EASrB,GAAsB,EAQtB,EAA0B,EAO1B,GAA+B,EAoB/B,eAAN,cAA6B,CAAU,CAEnC,WACA,aAAsC,KACtC,YAAoC,KAQpC,YAAY,EAAe,EAAqB,EAAsB,CAClE,MAAM,EAEN,KAAK,mBAAmB,sBAAsB,EAC9C,KAAK,UAAU,CACX,OAAc,OACd,aAAc,sCAClB,CAAC,EACD,KAAK,iBAAiB,CAAE,MAAO,EAAG,OAAQ,CAAa,CAAC,EAExD,KAAK,WAAa,IAAI,EAAK,CAAK,EAChC,KAAK,WAAW,cAAc,MAAM,EACpC,KAAK,WAAW,YAAY,QAAQ,EACpC,KAAK,WAAW,gBAAgB,UAAU,EAC1C,KAAK,WAAW,cAAc,QAAQ,EAGtC,KAAK,WAAW,eAAe,EAA8B,EAC7D,KAAK,aAAa,KAAK,UAAU,EAE7B,IACA,KAAK,aAAe,IAAI,EAAO,CAAE,MAAO,OAAQ,CAAC,EACjD,KAAK,aAAa,UAAU,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CAAC,EAClD,KAAK,aAAa,UAAU,MAAM,EAClC,KAAK,aAAa,qBAAqB,EACvC,KAAK,aAAa,mBAAmB,aAAa,EAClD,KAAK,aAAa,YAAY,EAC9B,KAAK,aAAa,mBAAmB,EACrC,KAAK,aAAa,iBAAiB,EAMnC,KAAK,aAAa,wBAAwB,yDAAyD,EACnG,KAAK,aAAa,0BAA0B,0DAA0D,EACtG,KAAK,aAAa,0BAA0B,EAC5C,KAAK,aAAa,4BAA4B,EAC9C,KAAK,aAAa,iBAAiB,CAAE,MAAO,EAAY,OAAQ,CAAW,CAAC,EAC5E,KAAK,aAAa,KAAK,YAAY,EAEnC,KAAK,aAAa,GAAG,SAAU,CAAO,EAE9C,CAQA,gBAAgC,CAC5B,OAAO,KAAK,YAChB,CAQA,cAAqB,CACjB,OAAO,KAAK,UAChB,CAcA,SAAS,EAAoB,CACzB,AAEI,KAAK,eADL,KAAK,gBAAgB,KAAK,WAAW,EAClB,MAGvB,IAAM,EAAQ,IAAI,EAAM,CAAI,EAQ5B,OAPA,EAAM,iBAAiB,MAAM,EAC7B,EAAM,iBAAiB,CAAE,MAAO,GAAI,OAAQ,EAAG,CAAC,EAChD,KAAK,YAAc,EACnB,KAAK,aAAa,CAAK,EAEvB,KAAK,SAAS,EAEP,IACX,CAOA,YAAmB,CAOf,OANI,KAAK,cACL,KAAK,gBAAgB,KAAK,WAAW,EACrC,KAAK,YAAc,KACnB,KAAK,SAAS,GAGX,IACX,CAOA,UAAyB,CACrB,OAAO,KAAK,WAChB,CAQA,UAAiB,CACb,MAAM,SAAS,EAEf,IAAM,EAAM,KAAK,iBAAiB,EAElC,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAU,EAAI,MACd,EAAU,EAAI,OACd,EAAU,EAAI,EAAa,EAC3B,EAAU,KAAK,OAAO,EAAI,GAAc,CAAC,EACzC,EAAa,KAAK,aAClB,EACC,EAAI,EAEP,EAAS,EAEb,GAAI,KAAK,YAAa,CAClB,IAAM,EAAY,KAAK,YAAY,iBAAiB,GAAK,CAAE,MAAO,GAAI,OAAQ,EAAG,EAC3E,EAAY,KAAK,IAAI,EAAG,KAAK,OAAO,EAAI,EAAU,QAAU,CAAC,CAAC,EAEpE,KAAK,YAAY,KAAK,EAAI,EAAI,CAAW,EACzC,KAAK,YAAY,KAAK,EAAI,EAAI,CAAM,EACpC,KAAK,YAAY,SAAS,EAAU,KAAK,EACzC,KAAK,YAAY,UAAU,EAAU,MAAM,EAE3C,EAAS,EAAc,EAAU,MAAQ,EAC7C,CAGA,IAAM,EAAa,KAAK,IAAI,EAAG,EAAa,EAAS,CAAe,EAC9D,EAAa,EAAI,EAiBvB,OAfA,KAAK,WAAW,KAAK,EAAI,EAAI,CAAM,EACnC,KAAK,WAAW,KAAK,EAAI,EAAI,EAAW,EACxC,KAAK,WAAW,SAAS,CAAU,EACnC,KAAK,WAAW,UAAU,CAAM,EAE5B,KAAK,eACL,KAAK,aAAa,KAAK,EAAI,EAAI,CAAM,EACrC,KAAK,aAAa,KAAK,EAAI,EAAI,CAAO,EACtC,KAAK,aAAa,SAAS,CAAU,EACrC,KAAK,aAAa,UAAU,CAAU,EAGtC,KAAK,aAAa,SAAS,GAGxB,IACX,CACJ,EAUM,gBAAN,cAA8B,CAAU,CAEpC,SAAsC,CAAC,EAMvC,YAAY,EAA+B,EAA0C,CACjF,MAAM,EAEN,KAAK,UAAU,CACX,OAAW,OACX,UAAW,sCACf,CAAC,EACD,KAAK,mBAAmB,sBAAsB,EAC9C,KAAK,iBAAiB,CAAE,MAAO,EAAG,OAAQ,CAAc,CAAC,EAEzD,IAAK,IAAM,KAAO,EAAS,CACvB,IAAM,EAAS,IAAI,EAAO,EAAI,KAAM,EAAI,QAAU,IAAA,GAAmC,IAAA,GAAvB,CAAE,MAAO,EAAI,KAAM,CAAa,EACxF,EAAS,EAAI,QAAU,SAM7B,GAJI,EAAI,SACJ,EAAI,mBAAmB,qDAAqD,EAG5E,EAAI,QAAU,IAAA,GAAW,CACzB,IAAM,EAAQ,EAAI,SAAS,EACrB,EAAO,EAAI,KAEb,IAAU,MAAQ,GAClB,EAAM,mBAAmB,CAAI,CAErC,CAEA,EAAI,GAAG,aAAgB,EAAS,CAAM,CAAC,EACvC,KAAK,SAAS,KAAK,CAAG,EACtB,KAAK,aAAa,CAAG,CACzB,CACJ,CAOA,UAAiB,CACb,MAAM,SAAS,EAEf,IAAM,EAAM,KAAK,iBAAiB,EAElC,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAY,EAAI,OAAS,GACzB,EAAY,KAAK,SAAS,OAAS,GAAgB,KAAK,SAAS,OAAS,GAAK,EAC/E,EAAY,KAAK,OAAO,EAAI,MAAQ,GAAU,CAAC,EAErD,IAAK,IAAM,KAAO,KAAK,SACnB,EAAI,KAAK,EAAI,EAAI,CAAC,EAClB,EAAI,KAAK,EAAI,EAAI,CAAY,EAC7B,EAAI,SAAS,CAAY,EACzB,EAAI,UAAU,CAAI,EAElB,EAAI,SAAS,EAEb,GAAK,GAGT,OAAO,IACX,CACJ,EAgCa,EAAgB,CAEzB,QAAS,CAAE,KAAM,UAAW,OAAQ,UAAW,MAAO,eAAgB,KAAM,mCAAoC,EAEhH,GAAS,CAAE,KAAM,KAAW,OAAQ,UAAW,MAAO,eAAgB,KAAM,mCAAoC,EAEhH,OAAS,CAAE,KAAM,SAAW,OAAQ,SAAW,MAAO,QAAgB,KAAM,kCAAoC,EAEhH,MAAS,CAAE,KAAM,QAAW,OAAQ,QAAW,MAAO,QAAgB,KAAM,kCAAoC,CACpH,EAGM,EAAwC,CAC1C,CAAE,GAAG,EAAc,GAAI,QAAS,EAAK,CACzC,EAuBM,EAAN,MAAM,eAAe,CAAsC,CAEvD,UACA,kBACA,WACA,UACA,QAEA,gBAAqE,KACrE,eAA2C,KAC3C,iBACA,oBAKA,kBAA+D,KAC/D,qBAA+D,KAC/D,mBAA+D,KAC/D,sBAA+D,KAO/D,YAA+B,GAO/B,YAAY,EAAsB,CAC9B,MAAM,EAEN,KAAK,QAAa,EAElB,IAAM,EAAe,KAAK,IAAI,EAAkB,EAAO,OAAS,GAAG,EAC7D,EAAe,EAAO,SAAW,EACjC,EAAgB,KAAK,IAAI,EAAoB,KAAK,qBAAqB,CAAM,CAAC,EAC9E,EAAgB,KAAK,IACvB,EACA,EAAO,QAAW,EAAe,EAAgB,CACrD,EAEA,KAAK,YAAY,EAAS,KAAK,EAC/B,KAAK,SAAS,CAAW,EACzB,KAAK,UAAU,CAAY,EAI3B,KAAK,mBAAmB,sBAAsB,EAC9C,KAAK,gBAAgB,iCAAiC,EACtD,KAAK,UAAU,4BAA4B,EAC3C,KAAK,YAAY,QAAQ,EAEzB,KAAK,WAAW,QAAQ,EAExB,IAAM,EAAS,IAAI,EA8BnB,GA7BA,EAAO,oBAAoB,CAAC,EAC5B,KAAK,iBAAiB,CAAM,EAE5B,KAAK,UAAY,IAAI,eAAe,EAAO,UAAa,KAAK,KAAK,OAAO,EAAG,EAAO,cAAgB,EAAK,EACxG,KAAK,aAAa,KAAK,UAAW,CAAE,UAAW,EAAU,KAAM,CAAC,EAI5D,EAAO,SACP,KAAK,oBAAoB,EAAO,QAAQ,EAExC,KAAK,mBAAmB,KAAK,qBAAqB,CAAO,CAAC,EAY9D,KAAK,kBAAoB,IAAI,EAAM,CAC/B,WAAe,IACf,cAAe,IAAI,GACnB,OAAe,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,CACxC,CAAC,EAEG,EAAO,iBACP,KAAK,kBAAkB,aAAa,EAAO,gBAAgB,MACxD,CACH,IAAM,EAAc,IAAI,EAAK,EAAO,SAAW,EAAE,EACjD,EAAY,cAAc,QAAQ,EAClC,EAAY,aAAa,YAAY,EACrC,EAAY,WAAW,IAAI,EAAO,GAAI,GAAI,GAAI,EAAE,CAAC,EACjD,EAAY,cAAc,MAAM,EAChC,EAAY,UAAU,MAAM,EAC5B,KAAK,kBAAkB,aAAa,CAAW,CACnD,CAEA,KAAK,aAAa,KAAK,kBAAmB,CAAE,UAAW,EAAU,MAAO,CAAC,EAEzE,KAAK,WAAa,IAAI,gBAAgB,EAAU,GAAW,KAAK,KAAK,CAAM,CAAC,EAC5E,KAAK,aAAa,KAAK,WAAY,CAAE,UAAW,EAAU,KAAM,CAAC,EAEjE,KAAK,UAAY,IAAI,EAErB,KAAK,iBAAuB,GAAqB,KAAK,UAAU,CAAC,EACjE,KAAK,wBAA4B,KAAK,iBAAiB,CAC3D,CAaA,qBAA6B,EAA4D,CACrF,IAAM,EAAU,IAAI,IAAI,EAAQ,IAAI,GAAK,EAAE,QAAU,QAAQ,CAAC,EAU9D,OARI,EAAQ,OAAS,GAAK,EAAQ,IAAI,SAAS,EACpC,OAGP,EAAQ,IAAI,SAAS,GAAK,EAAQ,IAAI,QAAQ,EACvC,SAGJ,OACX,CAUA,mBAA2B,EAA4C,CACnE,GAAI,IAAY,QACZ,OAGJ,IAAM,EAAQ,IAAY,OAAS,8BAAgC,gCAC7D,EAAQ,IAAY,OAAS,8BAAgC,gCAKnE,GAHA,KAAK,UAAU,mBAAmB,CAAK,EACvC,KAAK,UAAU,aAAa,CAAC,CAAC,mBAAmB,CAAK,EAElD,IAAY,OAAQ,CACpB,KAAK,UAAU,SAAS,aAAa,EAErC,IAAM,EAAc,KAAK,UAAU,SAAS,EAExC,IAAgB,MAChB,EAAY,mBAAmB,CAAK,CAE5C,CACJ,CAUA,oBAA4B,EAAgC,CACxD,IAAM,EAAQ,4BAA4B,EAAS,MAC7C,EAAQ,4BAA4B,EAAS,UAEnD,KAAK,UAAU,mBAAmB,CAAK,EACvC,KAAK,UAAU,aAAa,CAAC,CAAC,mBAAmB,CAAK,EACtD,KAAK,UAAU,SAAS,EAAe,EAAS,EAEhD,IAAM,EAAc,KAAK,UAAU,SAAS,EAExC,IAAgB,MAChB,EAAY,mBAAmB,CAAK,CAE5C,CAeA,qBAA6B,EAA8B,CACvD,GAAI,EAAO,iBAAkB,CACzB,IAAM,EAAK,EAAO,iBAAiB,iBAAiB,EAEpD,GAAI,EACA,OAAO,EAAG,MAElB,CAEA,MAAO,IACX,CAQA,MAA8B,CAC1B,OAAO,IAAI,QAAS,GAAY,CAC5B,KAAK,gBAAkB,EACvB,KAAK,KAAK,CACd,CAAC,CACL,CAiBA,iBAAwB,CACpB,GAAI,CAAC,KAAK,WAAW,EACjB,OAAO,KAGX,IAAM,EAAgB,KAAK,IAAI,EAAoB,KAAK,qBAAqB,KAAK,OAAO,CAAC,EACpF,EAAgB,KAAK,IAAI,EAAmB,EAAe,EAAgB,CAAa,EAExF,EAAS,EAAI,OAAO,gBAAgB,EACpC,EAAS,KAAK,IAAI,EAAQ,KAAK,IAAI,EAAmB,EAAG,OAAS,EAA0B,CAAC,EAUnG,OARI,IAAW,KAAK,UAAU,EACnB,MAGX,KAAK,UAAU,CAAM,EACrB,KAAK,eAAe,EACpB,KAAK,OAAO,EAEL,KACX,CAKA,MAAqB,CACjB,KAAK,eAAiB,EAAI,OAAO,iBAAiB,EAE9C,KAAK,QAAQ,iBAAmB,KAAK,QAAQ,cAAgB,IAC7D,KAAK,UAAU,qBAAuB,CAAE,KAAK,KAAK,OAAO,CAAG,CAAC,EAMjE,EAAa,SAAS,IAAI,EAE1B,IAAM,EAAS,EAAa,UAAU,IAAI,EAC1C,KAAK,UAAU,CAAM,EACrB,KAAK,UAAU,UAAU,EAAS,CAAC,EAEnC,IAAM,EAAa,KAAK,UAAU,WAAW,EAAI,EACjD,EAAa,MAAM,CAAU,EAE7B,IAAM,EAAW,KAAK,WAAW,EAAI,EACrC,EAAa,MAAM,CAAQ,EAI3B,EAAU,IAAI,EAEd,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,UAAU,EAOf,EAAU,oBAAsB,KAAK,gBAAgB,CAAC,EAEtD,EAAM,oBAAoB,KAAM,UAAW,KAAK,gBAAgB,EAChE,EAAM,oBAAoB,KAAM,SAAU,KAAK,mBAAmB,EAOlE,EAAU,oBAAsB,KAAK,WAAW,CAAC,CACrD,CAOA,WAA0B,CACtB,IAAM,EAAO,KAAK,WAAW,EACvB,EAAO,KAAK,UAAU,WAAW,EAElC,IAIL,KAAK,mBAAmB,OAAO,EAC/B,KAAK,kBAAoB,EAAU,KAAK,EAAI,CACxC,KAAY,CAAE,QAAS,IAAK,UAAW,aAAc,EACrD,GAAY,CAAE,QAAS,IAAK,UAAW,UAAc,EACrD,WAAY,EACZ,WAAY,CAAC,UAAW,WAAW,CACvC,CAAC,EAEG,IACA,KAAK,sBAAsB,OAAO,EAClC,KAAK,qBAAuB,EAAU,KAAK,EAAM,CAC7C,KAAY,CAAE,QAAS,GAAI,EAC3B,GAAY,CAAE,QAAS,GAAI,EAC3B,WAAY,EACZ,WAAY,CAAC,SAAS,CAC1B,CAAC,GAET,CAKA,QAAuB,CACnB,IAAM,EAAK,EAAI,OAAO,gBAAgB,EAChC,EAAK,KAAK,IAAI,EAAG,KAAK,OAAO,EAAG,MAAS,KAAK,SAAS,GAAM,CAAC,CAAC,EAC/D,EAAK,KAAK,IAAI,EAAG,KAAK,OAAO,EAAG,OAAS,KAAK,UAAU,GAAK,CAAC,CAAC,EAErE,KAAK,KAAK,CAAC,EACX,KAAK,KAAK,CAAC,CACf,CAYA,YAA2B,CACvB,IAAM,EAAY,KAAK,sBAAsB,EAE7C,GAAI,EAAW,CACX,EAAI,KAAK,MAAM,CAAS,EAExB,MACJ,CAEA,IAAM,EAAY,KAAK,kBAAkB,WAAW,EAC9C,EAAY,EAAY,EAAI,OAAO,iBAAiB,EAAW,CAAkB,EAAI,CAAC,EAE5F,GAAI,EAAU,OAAS,EAAG,CACtB,EAAI,KAAK,MAAM,EAAU,EAAE,EAE3B,MACJ,CAEA,IAAM,EAAU,KAAK,qBAAqB,EAE1C,GAAI,EAAS,CACT,EAAI,KAAK,MAAM,CAAO,EAEtB,MACJ,CAEA,IAAM,EAAY,KAAK,WAAW,EAC5B,EAAY,EAAK,EAAI,OAAO,iBAAiB,EAAI,CAAkB,EAAI,CAAC,EAE1E,EAAU,OAAS,GACnB,EAAI,KAAK,MAAM,EAAU,EAAE,CAEnC,CAYA,uBAA+C,CAE3C,IAAM,EADY,KAAK,QAAQ,cACF,WAAW,EAUxC,OARK,EAID,EAAI,OAAO,QAAQ,EAAS,CAAkB,EACvC,EAGJ,EAAI,OAAO,cAAc,EAAS,CAAkB,EAPhD,IAQf,CAWA,sBAA8C,CAE1C,IAAM,GADU,KAAK,QAAQ,SAAW,EAAA,CAChB,UAAU,GAAK,EAAE,OAAO,EAEhD,GAAI,EAAQ,EACR,OAAO,KAGX,IAAM,EAAQ,KAAK,WAAW,WAAW,EAGzC,OAFkB,EAAQ,EAAI,OAAO,iBAAiB,EAAO,CAAkB,EAAI,CAAC,EAAA,CAEnE,IAAU,IAC/B,CAOA,cAAiC,CAC7B,IAAM,EAAK,KAAK,WAAW,EAM3B,OAJK,EAIE,EAAI,OAAO,iBAAiB,EAAI,CAAkB,CAAC,CACrD,OAAO,GAAM,CAAC,EAAI,OAAO,aAAa,EAAI,UAAU,CAAC,EAJ/C,CAAC,CAKhB,CAQA,UAAkB,EAAwC,CAKtD,GAAI,EAAE,MAAQ,QACV,OAAO,KAAK,QAAQ,CAAC,EAGzB,GAAI,EAAE,MAAQ,MAAO,CACjB,IAAM,EAAY,KAAK,aAAa,EAEpC,GAAI,EAAU,SAAW,EACrB,MAAO,CAAE,KAAM,GAAM,QAAS,EAAK,EAGvC,IAAM,EAAQ,EAAU,GAClB,EAAQ,EAAU,EAAU,OAAS,GAE3C,GAAI,EAAE,SACE,IAAA,EAAI,OAAO,iBAAiB,IAAM,EAGlC,OAFA,EAAI,KAAK,MAAM,CAAI,EAEZ,CAAE,KAAM,GAAM,QAAS,EAAK,CACvC,MAEA,GAAI,EAAI,OAAO,iBAAiB,IAAM,EAGlC,OAFA,EAAI,KAAK,MAAM,CAAK,EAEb,CAAE,KAAM,GAAM,QAAS,EAAK,CAG/C,CAGJ,CAcA,QAAgB,EAAyC,CACrD,IAAM,EAAS,EAAI,OAAO,iBAAiB,EACrC,EAAS,EAAS,EAAI,OAAO,WAAW,CAAM,CAAC,CAAC,YAAY,EAAI,KAEtE,GAAI,IAAQ,YAAc,IAAQ,SAC9B,OAGJ,IAAM,EAAS,KAAK,cAAc,EAE9B,OAAW,KAMf,OAFA,KAAK,KAAK,CAAM,EAET,CAAE,KAAM,GAAM,QAAS,EAAK,CACvC,CASA,eAA6C,CAEzC,IAAM,GADU,KAAK,QAAQ,SAAW,EAAA,CAChB,KAAK,GAAK,EAAE,OAAO,EAE3C,OAAO,EAAW,EAAQ,QAAU,SAAY,IACpD,CAWA,kBAAiC,CAC7B,KAAK,UAAU,OAAO,EACtB,KAAK,gBAAgB,EACrB,KAAK,OAAO,CAChB,CAWA,KAAK,EAA4B,CAC7B,EAAM,uBAAuB,KAAM,UAAW,KAAK,gBAAgB,EACnE,EAAM,uBAAuB,KAAM,SAAU,KAAK,mBAAmB,EAErE,IAAM,aAAuB,CACzB,KAAK,YAAc,GAEnB,KAAK,UAAU,QAAQ,EACvB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,EAAa,WAAW,IAAI,EAC5B,EAAY,IAAI,EAEZ,KAAK,iBAAmB,MACxB,EAAI,KAAK,MAAM,KAAK,cAAc,EAGtC,AAEI,KAAK,mBADL,KAAK,gBAAgB,CAAM,EACJ,KAE/B,EAEM,EAAO,KAAK,WAAW,EACvB,EAAO,KAAK,UAAU,WAAW,EAwBvC,OAtBK,GAKL,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,EAAU,KAAK,EAAI,CACzC,GAAY,CAAE,QAAS,IAAK,UAAW,aAAc,EACrD,WAAY,EACZ,WAAY,CAAC,UAAW,WAAW,EACnC,WAAY,QAChB,CAAC,EAEG,IACA,KAAK,uBAAuB,OAAO,EACnC,KAAK,sBAAwB,EAAU,KAAK,EAAM,CAC9C,GAAY,CAAE,QAAS,GAAI,EAC3B,WAAY,EACZ,WAAY,CAAC,SAAS,CAC1B,CAAC,GAGE,OArBH,SAAS,EACF,KAqBf,CAQA,YAA6B,CACzB,KAAK,mBAAmB,OAAO,EAC/B,KAAK,kBAAoB,KACzB,KAAK,sBAAsB,OAAO,EAClC,KAAK,qBAAuB,KAC5B,KAAK,oBAAoB,OAAO,EAChC,KAAK,mBAAqB,KAC1B,KAAK,uBAAuB,OAAO,EACnC,KAAK,sBAAwB,KAWxB,KAAK,cACN,KAAK,UAAU,QAAQ,EAEvB,EAAa,WAAW,IAAI,EAC5B,EAAY,IAAI,EAEhB,AAEI,KAAK,mBADL,KAAK,gBAAgB,OAAO,EACL,OAI/B,MAAM,WAAW,CACrB,CAOA,qBAAiC,CAC7B,OAAO,KAAK,iBAChB,CAYA,qBAAyC,CACrC,MAAO,EACX,CAcA,aAA8B,CAC1B,OAAO,KAAK,SAChB,CASA,iBAAiC,CAC7B,OAAO,KAAK,WAAW,GAAK,IAChC,CAUA,gBAAmC,CAC/B,MAAO,OACX,CAaA,cAAqB,CACb,KAAK,QAAQ,cAAgB,IAIjC,KAAK,KAAK,OAAO,CACrB,CAQA,SAAkB,CACd,OAAO,EAAa,KAAK,MAC7B,CAaA,OAAO,KAAK,EAA6C,CAGrD,OAAO,IAFY,OAAO,CAEnB,CAAA,CAAO,KAAK,CACvB,CAmBA,aAAa,QAAQ,EAAe,EAAmC,CAUnE,OAAO,MATc,OAAO,KAAK,CAC7B,QACA,UACA,QAAS,CACL,CAAE,GAAG,EAAc,OAAQ,QAAS,EAAK,EACzC,EAAc,OAClB,CACJ,CAAC,IAEiB,SACtB,CAYA,aAAqB,MAAM,EAA0B,EAAe,EAAgC,CAChG,MAAM,OAAO,KAAK,CACd,QACA,UACA,WACA,QAAS,CAAC,CAAE,GAAG,EAAc,GAAI,QAAS,EAAK,CAAC,CACpD,CAAC,CACL,CAcA,OAAO,KAAK,EAAe,EAAgC,CACvD,OAAO,OAAO,MAAM,OAAQ,EAAO,CAAO,CAC9C,CAcA,OAAO,QAAQ,EAAe,EAAgC,CAC1D,OAAO,OAAO,MAAM,UAAW,EAAO,CAAO,CACjD,CAcA,OAAO,QAAQ,EAAe,EAAgC,CAC1D,OAAO,OAAO,MAAM,UAAW,EAAO,CAAO,CACjD,CAeA,OAAO,MAAM,EAAe,EAAgC,CACxD,OAAO,OAAO,MAAM,QAAS,EAAO,CAAO,CAC/C,CACJ,EAEM,GAAiB,EAAS,CAAM"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{h as e,t}from"./Component-
|
|
2
|
-
//# sourceMappingURL=FieldDecorator-
|
|
1
|
+
import{h as e,t}from"./Component-B0ShfPVi.js";import{t as n}from"./Tooltip-CUOJOqQi.js";import{t as r}from"./Fit-BhlB-HAo.js";var FieldDecorator=class extends t{constructor(e,t){super(),this.setLayoutManager(new r),this.clearInsets(),this.setBorderRadius(`var(--ts-ui-border-radius)`);let n=e.getPreferredSize();n?this.setPreferredSize({width:n.width,height:n.height}):this.setPreferredSize({width:e.getWidth(),height:e.getHeight()}),t.removeComponent(e),t.addComponent(this),this.addComponent(e)}showError(e){return this.setOutline(`2px solid var(--ts-ui-validation-error-border)`),n.attach(this,e,{background:`var(--ts-ui-validation-error-tooltip-bg)`,color:`var(--ts-ui-validation-error-tooltip-color)`,border:`var(--ts-ui-validation-error-tooltip-border)`}),this}clearError(){return this.clearOutline(),n.detach(this),this}},i=e(FieldDecorator);export{i as t};
|
|
2
|
+
//# sourceMappingURL=FieldDecorator-BlYMfZ9L.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldDecorator-
|
|
1
|
+
{"version":3,"file":"FieldDecorator-BlYMfZ9L.js","names":[],"sources":["../../src/typescript/lib/validation/FieldDecorator.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from '~/core/Component.js';\nimport { Fit } from '~/layout/Fit.js';\nimport { Tooltip } from '~/overlay/Tooltip.js';\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * A thin wrapper component that provides error visualisation for a field component.\n *\n * On construction the decorator removes the field from its current parent and inserts\n * itself in the parent, then re-adds the field as its own child. This means the error\n * border is applied to the decorator — never to the field itself — so the field's own\n * border is left untouched and removing the validation state is a clean one-step reset.\n *\n * @remarks Due to the framework's append-only `addComponent` API the decorator is\n * placed at the end of the parent's children rather than in the field's original slot.\n * A future `addComponentAt(index, component)` enhancement could address this.\n *\n * @category Validation\n */\nclass FieldDecorator extends Component {\n\n /**\n * Creates a decorator that wraps `field` inside `parent`.\n *\n * The field is removed from `parent` and the decorator is added in its place,\n * then the field is added as a child of the decorator.\n *\n * @param field - The UI component to decorate.\n * @param parent - The current parent container of `field`.\n */\n constructor(field: Component, parent: Component) {\n super();\n\n this.setLayoutManager(new Fit());\n\n // Every Component defaults to 4px insets on all sides. Zero them out so\n // the Fit layout gives the field the decorator's full content area.\n this.clearInsets();\n\n // Inherit the theme border radius so the outline follows the field's rounded corners.\n this.setBorderRadius('var(--ts-ui-border-radius)');\n\n // Mirror the field's preferred size so the parent layout allocates the\n // same space for the decorator as it did for the field. Without this,\n // layouts that fall back to a default width (e.g. HBox defaultComponentWidth)\n // would give the decorator a different — usually smaller — allocation.\n const ps = field.getPreferredSize();\n\n if (ps) {\n this.setPreferredSize({ width: ps.width, height: ps.height });\n } else {\n this.setPreferredSize({ width: field.getWidth(), height: field.getHeight() });\n }\n\n parent.removeComponent(field);\n parent.addComponent(this);\n this.addComponent(field);\n }\n\n /**\n * Applies a red validation-error outline to this decorator and attaches an error\n * tooltip that appears on hover.\n *\n * CSS `outline` is used instead of `border` so that the decorator's content area\n * and the wrapped field's size are completely unaffected — outline renders outside\n * the box model and takes up no layout space.\n *\n * @param message - The error message to display in the tooltip.\n */\n showError(message: string): this {\n this.setOutline('2px solid var(--ts-ui-validation-error-border)');\n\n Tooltip.attach(this, message, {\n background: 'var(--ts-ui-validation-error-tooltip-bg)',\n color : 'var(--ts-ui-validation-error-tooltip-color)',\n border : 'var(--ts-ui-validation-error-tooltip-border)',\n });\n\n return this;\n }\n\n /**\n * Removes the error outline and detaches the error tooltip.\n */\n clearError(): this {\n this.clearOutline();\n Tooltip.detach(this);\n\n return this;\n }\n}\n\nconst FieldDecoratorCallable = callable(FieldDecorator);\ntype FieldDecoratorCallable = FieldDecorator;\nexport {\n FieldDecorator as _FieldDecorator,\n FieldDecoratorCallable as FieldDecorator\n};\n"],"mappings":"8HAqBA,IAAM,eAAN,cAA6B,CAAU,CAWnC,YAAY,EAAkB,EAAmB,CAC7C,MAAM,EAEN,KAAK,iBAAiB,IAAI,CAAK,EAI/B,KAAK,YAAY,EAGjB,KAAK,gBAAgB,4BAA4B,EAMjD,IAAM,EAAK,EAAM,iBAAiB,EAE9B,EACA,KAAK,iBAAiB,CAAE,MAAO,EAAG,MAAO,OAAQ,EAAG,MAAO,CAAC,EAE5D,KAAK,iBAAiB,CAAE,MAAO,EAAM,SAAS,EAAG,OAAQ,EAAM,UAAU,CAAE,CAAC,EAGhF,EAAO,gBAAgB,CAAK,EAC5B,EAAO,aAAa,IAAI,EACxB,KAAK,aAAa,CAAK,CAC3B,CAYA,UAAU,EAAuB,CAS7B,OARA,KAAK,WAAW,gDAAgD,EAEhE,EAAQ,OAAO,KAAM,EAAS,CAC1B,WAAY,2CACZ,MAAY,8CACZ,OAAY,8CAChB,CAAC,EAEM,IACX,CAKA,YAAmB,CAIf,OAHA,KAAK,aAAa,EAClB,EAAQ,OAAO,IAAI,EAEZ,IACX,CACJ,EAEM,EAAyB,EAAS,cAAc"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{f as e,h as t,m as n}from"./Component-
|
|
2
|
-
//# sourceMappingURL=Fit-
|
|
1
|
+
import{f as e,h as t,m as n}from"./Component-B0ShfPVi.js";var Fit=class extends e{_fill=n.BOTH;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.fill!==void 0&&this.setFill(e.fill)}getFill(){return this._fill}setFill(e){return this._fill=e,this}getPreferredSize(){return this.computeSize(e=>e.getPreferredSize())}getMinSize(){return this.computeSize(e=>e.getMinSize())}getMaxSize(){return this.computeSize(e=>e.getMaxSize())}computeSize(e){let t=this.getContainer();if(!t)return null;let n=t.getPerimeterSize(),r=n.left+n.right,i=n.top+n.bottom,a=t.getLaidOutComponents()[0]??null;if(!a)return null;let o=e(a);return o?{width:o.width+r,height:o.height+i}:null}getComponent(){let e=this.getContainer();if(!e)return null;let t=e.getComponents();if(t.length>1)throw Error(`Container contains more than one component.`);let n;return t.length==1&&(n=t[0]),n}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=e.getLaidOutComponents()[0];return t?t.getMinSize()??{width:0,height:0}:{width:0,height:0}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getLaidOutComponents();if(t.length>1)throw Error(`Container contains more than one component.`);let n;if(t.length==1&&(n=t[0]),!n)return;let r=e.getInnerSize(),i=e.getContentInsets();r&&=this.inflateForOverflow(r),this.placeComponent(n,i?i.getLeft():0,i?i.getTop():0,r?r.width:0,r?r.height:0,this._fill)}},r=t(Fit);export{r as t};
|
|
2
|
+
//# sourceMappingURL=Fit-BhlB-HAo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Fit-CL1m1nIZ.js","names":[],"sources":["../../src/typescript/lib/layout/Fit.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Fit}.\n *\n * @category Layouts\n */\nexport interface FitOptions extends LayoutManagerOptions {\n fill?: FillType;\n}\n\n/**\n * A layout manager that expects exactly one child component and positions it\n * inside the container's entire inner bounds. The default fill mode is\n * `FillType.BOTH` — the child stretches to fill the bounds. Pass\n * `fill: FillType.NONE` (or call {@link Fit.setFill}) to centre the child at\n * its preferred size instead; `HORIZONTAL` / `VERTICAL` stretch on one axis\n * and centre on the other. Throws if the container holds more than one\n * component.\n *\n * @category Layouts\n */\nclass Fit extends LayoutManager {\n\n private _fill: FillType = FillType.BOTH;\n\n constructor(options?: FitOptions) {\n // LayoutManager's constructor takes no options; applied via applyOptions below.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link FitOptions} bag, dispatching the fill mode after the\n * inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: FitOptions): void {\n super.applyOptions(options);\n\n if (options.fill !== undefined) {\n this.setFill(options.fill);\n }\n }\n\n /**\n * Returns the fill mode applied to the single child.\n *\n * @returns The current [`FillType`](/api/layout/enumerations/FillType).\n */\n getFill(): FillType {\n return this._fill;\n }\n\n /**\n * Sets the fill mode applied to the single child.\n *\n * @param fill - `BOTH` stretches the child to fill (default), `NONE`\n * centres it at its preferred size, `HORIZONTAL` / `VERTICAL` stretch on\n * one axis and centre on the other.\n *\n * @returns This layout manager, for method chaining.\n */\n setFill(fill: FillType): this {\n this._fill = fill;\n\n return this;\n }\n\n /**\n * Returns the preferred size of the single child component plus the container perimeter.\n *\n * @returns The preferred `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getPreferredSize(): Size | null {\n return this.computeSize(component => component.getPreferredSize());\n }\n\n /**\n * Returns the minimum size of the single child component plus the container perimeter.\n *\n * @returns The minimum `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getMinSize(): Size | null {\n return this.computeSize(component => component.getMinSize());\n }\n\n /**\n * Returns the maximum size of the single child component plus the container perimeter.\n *\n * @returns The maximum `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getMaxSize(): Size | null {\n return this.computeSize(component => component.getMaxSize());\n }\n\n /**\n * Shared core of {@link getPreferredSize} / {@link getMinSize} /\n * {@link getMaxSize}: adds the displayed child's size (selected by `sizeOf`)\n * to the container perimeter.\n *\n * @param sizeOf - Selects the child's preferred, minimum, or maximum size.\n * @returns The composed `{width, height}`, or `null` if there is no\n * container, no displayed child, or the child reports no size.\n */\n private computeSize(sizeOf: (component: Component) => Size | null): Size | null {\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const perimeterSize = container.getPerimeterSize();\n\n const outerWidth = perimeterSize.left + perimeterSize.right;\n const outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n // Size the displayed child only: a hidden sole child contributes no\n // size, so the Fit container reports none and its own parent reserves\n // nothing for it (honouring `displayed`, matching doLayout below).\n const component = container.getLaidOutComponents()[0] ?? null;\n if (!component) {\n return null;\n }\n\n const size = sizeOf(component);\n if (!size) {\n return null;\n }\n\n return {\n width: size.width + outerWidth,\n height: size.height + outerHeight\n };\n }\n\n /**\n * Returns the single child component of the container, or `undefined` if the container is empty.\n *\n * @returns The child component, or `undefined`.\n *\n * @remarks Throws if the container holds more than one component.\n */\n getComponent() {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let components = container.getComponents();\n\n if (components.length > 1) {\n throw new Error(\"Container contains more than one component.\");\n }\n\n let component;\n\n if (components.length == 1) {\n component = components[0];\n }\n\n return component;\n }\n\n /**\n * Computes the children's combined minSize along this manager's geometry:\n * the single child's minSize. Used by `doLayout` to inflate the working\n * size when the host has opted into `setOverflowing`.\n *\n * @returns The single child's min-size; `{ width: 0, height: 0 }` when\n * the container is absent or empty.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n const component = container.getLaidOutComponents()[0];\n if (!component) {\n return { width: 0, height: 0 };\n }\n\n const min = component.getMinSize();\n\n return min ?? { width: 0, height: 0 };\n }\n\n /**\n * Places the single child component inside the container's inner bounds\n * using the configured fill mode.\n *\n * @remarks Throws if the container holds more than one component. With\n * the default `FillType.BOTH` the child is sized to the full bounds;\n * with `FillType.NONE` it is placed at its preferred size and centred\n * via the inherited anchor-displacement logic in `placeComponent`.\n */\n doLayout() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n // Honour `displayed`: a hidden sole child contributes nothing and a\n // hidden first-of-two is skipped, so the visible child still fits.\n let components = container.getLaidOutComponents();\n\n if (components.length > 1) {\n throw new Error(\"Container contains more than one component.\");\n }\n\n let component;\n\n if (components.length == 1) {\n component = components[0];\n }\n\n if (!component) {\n return;\n }\n\n let containerSize = container.getInnerSize();\n let containerInsets = container.getContentInsets();\n\n // Universal scroll: see HBox.doLayout for the rationale. When the\n // host has marked the corresponding axis as overflowing, grow the\n // working size past the host's inner rect to the child's minSize so\n // the host's CSS `overflow: auto` produces a scrollbar.\n if (containerSize) {\n containerSize = this.inflateForOverflow(containerSize);\n }\n\n this.placeComponent(\n component,\n containerInsets ? containerInsets.getLeft() : 0,\n containerInsets ? containerInsets.getTop() : 0,\n containerSize ? containerSize.width : 0,\n containerSize ? containerSize.height : 0,\n this._fill\n );\n }\n}\n\nconst FitCallable = callable(Fit);\ntype FitCallable = Fit;\nexport {\n Fit as _Fit,\n FitCallable as Fit\n};\n"],"mappings":"0DA4BA,IAAM,IAAN,cAAkB,CAAc,CAE5B,MAA0B,EAAS,KAEnC,YAAY,EAAsB,CAG9B,MAAM,EAEF,GACA,KAAK,aAAa,CAAO,CAEjC,CAQA,aAAuB,EAA2B,CAC9C,MAAM,aAAa,CAAO,EAEtB,EAAQ,OAAS,IAAA,IACjB,KAAK,QAAQ,EAAQ,IAAI,CAEjC,CAOA,SAAoB,CAChB,OAAO,KAAK,KAChB,CAWA,QAAQ,EAAsB,CAG1B,MAFA,MAAK,MAAQ,EAEN,IACX,CAOA,kBAAgC,CAC5B,OAAO,KAAK,YAAY,GAAa,EAAU,iBAAiB,CAAC,CACrE,CAOA,YAA0B,CACtB,OAAO,KAAK,YAAY,GAAa,EAAU,WAAW,CAAC,CAC/D,CAOA,YAA0B,CACtB,OAAO,KAAK,YAAY,GAAa,EAAU,WAAW,CAAC,CAC/D,CAWA,YAAoB,EAA4D,CAC5E,IAAM,EAAY,KAAK,aAAa,EACpC,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAgB,EAAU,iBAAiB,EAE3C,EAAa,EAAc,KAAO,EAAc,MAChD,EAAc,EAAc,IAAM,EAAc,OAKhD,EAAY,EAAU,qBAAqB,CAAC,CAAC,IAAM,KACzD,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAO,EAAO,CAAS,EAK7B,OAJK,EAIE,CACH,MAAO,EAAK,MAAQ,EACpB,OAAQ,EAAK,OAAS,CAC1B,EANW,IAOf,CASA,cAAe,CACX,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAAO,KAGX,IAAI,EAAa,EAAU,cAAc,EAEzC,GAAI,EAAW,OAAS,EACpB,MAAU,MAAM,6CAA6C,EAGjE,IAAI,EAMJ,OAJI,EAAW,QAAU,IACrB,EAAY,EAAW,IAGpB,CACX,CAUA,qBAAsC,CAClC,IAAM,EAAY,KAAK,aAAa,EACpC,GAAI,CAAC,EACD,MAAO,CAAE,MAAO,EAAG,OAAQ,CAAE,EAGjC,IAAM,EAAY,EAAU,qBAAqB,CAAC,CAAC,GAOnD,OANK,EAIO,EAAU,WAEf,GAAO,CAAE,MAAO,EAAG,OAAQ,CAAE,EALzB,CAAE,MAAO,EAAG,OAAQ,CAAE,CAMrC,CAWA,UAAW,CACP,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAKJ,IAAI,EAAa,EAAU,qBAAqB,EAEhD,GAAI,EAAW,OAAS,EACpB,MAAU,MAAM,6CAA6C,EAGjE,IAAI,EAMJ,GAJI,EAAW,QAAU,IACrB,EAAY,EAAW,IAGvB,CAAC,EACD,OAGJ,IAAI,EAAgB,EAAU,aAAa,EACvC,EAAkB,EAAU,iBAAiB,EAMjD,AACI,IAAgB,KAAK,mBAAmB,CAAa,EAGzD,KAAK,eACD,EACA,EAAkB,EAAgB,QAAQ,EAAI,EAC9C,EAAkB,EAAgB,OAAO,EAAI,EAC7C,EAAgB,EAAc,MAAQ,EACtC,EAAgB,EAAc,OAAS,EACvC,KAAK,KACT,CACJ,CACJ,EAEM,EAAc,EAAS,GAAG"}
|
|
1
|
+
{"version":3,"file":"Fit-BhlB-HAo.js","names":[],"sources":["../../src/typescript/lib/layout/Fit.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Fit}.\n *\n * @category Layouts\n */\nexport interface FitOptions extends LayoutManagerOptions {\n fill?: FillType;\n}\n\n/**\n * A layout manager that expects exactly one child component and positions it\n * inside the container's entire inner bounds. The default fill mode is\n * `FillType.BOTH` — the child stretches to fill the bounds. Pass\n * `fill: FillType.NONE` (or call {@link Fit.setFill}) to centre the child at\n * its preferred size instead; `HORIZONTAL` / `VERTICAL` stretch on one axis\n * and centre on the other. Throws if the container holds more than one\n * component.\n *\n * @category Layouts\n */\nclass Fit extends LayoutManager {\n\n private _fill: FillType = FillType.BOTH;\n\n constructor(options?: FitOptions) {\n // LayoutManager's constructor takes no options; applied via applyOptions below.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link FitOptions} bag, dispatching the fill mode after the\n * inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: FitOptions): void {\n super.applyOptions(options);\n\n if (options.fill !== undefined) {\n this.setFill(options.fill);\n }\n }\n\n /**\n * Returns the fill mode applied to the single child.\n *\n * @returns The current [`FillType`](/api/layout/enumerations/FillType).\n */\n getFill(): FillType {\n return this._fill;\n }\n\n /**\n * Sets the fill mode applied to the single child.\n *\n * @param fill - `BOTH` stretches the child to fill (default), `NONE`\n * centres it at its preferred size, `HORIZONTAL` / `VERTICAL` stretch on\n * one axis and centre on the other.\n *\n * @returns This layout manager, for method chaining.\n */\n setFill(fill: FillType): this {\n this._fill = fill;\n\n return this;\n }\n\n /**\n * Returns the preferred size of the single child component plus the container perimeter.\n *\n * @returns The preferred `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getPreferredSize(): Size | null {\n return this.computeSize(component => component.getPreferredSize());\n }\n\n /**\n * Returns the minimum size of the single child component plus the container perimeter.\n *\n * @returns The minimum `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getMinSize(): Size | null {\n return this.computeSize(component => component.getMinSize());\n }\n\n /**\n * Returns the maximum size of the single child component plus the container perimeter.\n *\n * @returns The maximum `{width, height}`, or `null` if there is no container or no displayed child.\n */\n getMaxSize(): Size | null {\n return this.computeSize(component => component.getMaxSize());\n }\n\n /**\n * Shared core of {@link getPreferredSize} / {@link getMinSize} /\n * {@link getMaxSize}: adds the displayed child's size (selected by `sizeOf`)\n * to the container perimeter.\n *\n * @param sizeOf - Selects the child's preferred, minimum, or maximum size.\n * @returns The composed `{width, height}`, or `null` if there is no\n * container, no displayed child, or the child reports no size.\n */\n private computeSize(sizeOf: (component: Component) => Size | null): Size | null {\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const perimeterSize = container.getPerimeterSize();\n\n const outerWidth = perimeterSize.left + perimeterSize.right;\n const outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n // Size the displayed child only: a hidden sole child contributes no\n // size, so the Fit container reports none and its own parent reserves\n // nothing for it (honouring `displayed`, matching doLayout below).\n const component = container.getLaidOutComponents()[0] ?? null;\n if (!component) {\n return null;\n }\n\n const size = sizeOf(component);\n if (!size) {\n return null;\n }\n\n return {\n width: size.width + outerWidth,\n height: size.height + outerHeight\n };\n }\n\n /**\n * Returns the single child component of the container, or `undefined` if the container is empty.\n *\n * @returns The child component, or `undefined`.\n *\n * @remarks Throws if the container holds more than one component.\n */\n getComponent() {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let components = container.getComponents();\n\n if (components.length > 1) {\n throw new Error(\"Container contains more than one component.\");\n }\n\n let component;\n\n if (components.length == 1) {\n component = components[0];\n }\n\n return component;\n }\n\n /**\n * Computes the children's combined minSize along this manager's geometry:\n * the single child's minSize. Used by `doLayout` to inflate the working\n * size when the host has opted into `setOverflowing`.\n *\n * @returns The single child's min-size; `{ width: 0, height: 0 }` when\n * the container is absent or empty.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n const component = container.getLaidOutComponents()[0];\n if (!component) {\n return { width: 0, height: 0 };\n }\n\n const min = component.getMinSize();\n\n return min ?? { width: 0, height: 0 };\n }\n\n /**\n * Places the single child component inside the container's inner bounds\n * using the configured fill mode.\n *\n * @remarks Throws if the container holds more than one component. With\n * the default `FillType.BOTH` the child is sized to the full bounds;\n * with `FillType.NONE` it is placed at its preferred size and centred\n * via the inherited anchor-displacement logic in `placeComponent`.\n */\n doLayout() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n // Honour `displayed`: a hidden sole child contributes nothing and a\n // hidden first-of-two is skipped, so the visible child still fits.\n let components = container.getLaidOutComponents();\n\n if (components.length > 1) {\n throw new Error(\"Container contains more than one component.\");\n }\n\n let component;\n\n if (components.length == 1) {\n component = components[0];\n }\n\n if (!component) {\n return;\n }\n\n let containerSize = container.getInnerSize();\n let containerInsets = container.getContentInsets();\n\n // Universal scroll: see HBox.doLayout for the rationale. When the\n // host has marked the corresponding axis as overflowing, grow the\n // working size past the host's inner rect to the child's minSize so\n // the host's CSS `overflow: auto` produces a scrollbar.\n if (containerSize) {\n containerSize = this.inflateForOverflow(containerSize);\n }\n\n this.placeComponent(\n component,\n containerInsets ? containerInsets.getLeft() : 0,\n containerInsets ? containerInsets.getTop() : 0,\n containerSize ? containerSize.width : 0,\n containerSize ? containerSize.height : 0,\n this._fill\n );\n }\n}\n\nconst FitCallable = callable(Fit);\ntype FitCallable = Fit;\nexport {\n Fit as _Fit,\n FitCallable as Fit\n};\n"],"mappings":"0DA4BA,IAAM,IAAN,cAAkB,CAAc,CAE5B,MAA0B,EAAS,KAEnC,YAAY,EAAsB,CAG9B,MAAM,EAEF,GACA,KAAK,aAAa,CAAO,CAEjC,CAQA,aAAuB,EAA2B,CAC9C,MAAM,aAAa,CAAO,EAEtB,EAAQ,OAAS,IAAA,IACjB,KAAK,QAAQ,EAAQ,IAAI,CAEjC,CAOA,SAAoB,CAChB,OAAO,KAAK,KAChB,CAWA,QAAQ,EAAsB,CAG1B,MAFA,MAAK,MAAQ,EAEN,IACX,CAOA,kBAAgC,CAC5B,OAAO,KAAK,YAAY,GAAa,EAAU,iBAAiB,CAAC,CACrE,CAOA,YAA0B,CACtB,OAAO,KAAK,YAAY,GAAa,EAAU,WAAW,CAAC,CAC/D,CAOA,YAA0B,CACtB,OAAO,KAAK,YAAY,GAAa,EAAU,WAAW,CAAC,CAC/D,CAWA,YAAoB,EAA4D,CAC5E,IAAM,EAAY,KAAK,aAAa,EACpC,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAgB,EAAU,iBAAiB,EAE3C,EAAa,EAAc,KAAO,EAAc,MAChD,EAAc,EAAc,IAAM,EAAc,OAKhD,EAAY,EAAU,qBAAqB,CAAC,CAAC,IAAM,KACzD,GAAI,CAAC,EACD,OAAO,KAGX,IAAM,EAAO,EAAO,CAAS,EAK7B,OAJK,EAIE,CACH,MAAO,EAAK,MAAQ,EACpB,OAAQ,EAAK,OAAS,CAC1B,EANW,IAOf,CASA,cAAe,CACX,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAAO,KAGX,IAAI,EAAa,EAAU,cAAc,EAEzC,GAAI,EAAW,OAAS,EACpB,MAAU,MAAM,6CAA6C,EAGjE,IAAI,EAMJ,OAJI,EAAW,QAAU,IACrB,EAAY,EAAW,IAGpB,CACX,CAUA,qBAAsC,CAClC,IAAM,EAAY,KAAK,aAAa,EACpC,GAAI,CAAC,EACD,MAAO,CAAE,MAAO,EAAG,OAAQ,CAAE,EAGjC,IAAM,EAAY,EAAU,qBAAqB,CAAC,CAAC,GAOnD,OANK,EAIO,EAAU,WAEf,GAAO,CAAE,MAAO,EAAG,OAAQ,CAAE,EALzB,CAAE,MAAO,EAAG,OAAQ,CAAE,CAMrC,CAWA,UAAW,CACP,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAKJ,IAAI,EAAa,EAAU,qBAAqB,EAEhD,GAAI,EAAW,OAAS,EACpB,MAAU,MAAM,6CAA6C,EAGjE,IAAI,EAMJ,GAJI,EAAW,QAAU,IACrB,EAAY,EAAW,IAGvB,CAAC,EACD,OAGJ,IAAI,EAAgB,EAAU,aAAa,EACvC,EAAkB,EAAU,iBAAiB,EAMjD,AACI,IAAgB,KAAK,mBAAmB,CAAa,EAGzD,KAAK,eACD,EACA,EAAkB,EAAgB,QAAQ,EAAI,EAC9C,EAAkB,EAAgB,OAAO,EAAI,EAC7C,EAAgB,EAAc,MAAQ,EACtC,EAAgB,EAAc,OAAS,EACvC,KAAK,KACT,CACJ,CACJ,EAEM,EAAc,EAAS,GAAG"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{t as e}from"./DOM-C-Edb3tA.js";import{n as t}from"./Position-BwtxouxK.js";import{h as n}from"./Component-B0ShfPVi.js";import{t as r}from"./Panel-Cy1pdlWO.js";import{t as i}from"./AnchorConstraints-Bfkt8019.js";var a=16,o=`top-right`,s=12,c={insets:new t(0,0,0,0),corner:o,margin:s},FloatingPanel=class extends r{_anchorConstraints=new i;constructor(e,t){super(e,{...c,...t??{}}),this.applyCornerAndMargin()}applyOptions(e){return super.applyOptions(e),e.corner!==void 0&&(this._options.corner=e.corner),e.margin!==void 0&&(this._options.margin=e.margin),this}getCorner(){return this._options.corner??this._defaultOptions.corner??o}setCorner(e){return this.getCorner()===e?this:(this._options.corner=e,this.applyCornerAndMargin(),this.getParentComponent()?.scheduleLayout(),this)}getMargin(){return this._options.margin??this._defaultOptions.margin??s}setMargin(e){return this.getMargin()===e?this:(this._options.margin=e,this.applyCornerAndMargin(),this.getParentComponent()?.scheduleLayout(),this)}getAnchorConstraints(){return this._anchorConstraints}placeNextTo(t){let n=this.getParentComponent(),r=n?.getInnerSize();if(!n||!r)return this;let i=n.getContentInsets().getLeft()+r.width-this.getWidth()-this.getMargin();this.getAnchorConstraints().right=void 0;let o=t?.getElement()??null;if(!t||!o)return this.setX(i),this;let s=e.source.getElementRect(o).width,c=t.getX()+s+a;return this.setX(Math.min(c,i)),this}applyCornerAndMargin(){let e=this.getCorner(),t=this.getMargin();this._anchorConstraints.top=void 0,this._anchorConstraints.bottom=void 0,this._anchorConstraints.left=void 0,this._anchorConstraints.right=void 0,e===`top-left`||e===`top-right`?this._anchorConstraints.top=t:this._anchorConstraints.bottom=t,e===`top-left`||e===`bottom-left`?this._anchorConstraints.left=t:this._anchorConstraints.right=t}},l=n(FloatingPanel);export{l as t};
|
|
2
|
+
//# sourceMappingURL=FloatingPanel-DkJXsZ2D.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingPanel-DkJXsZ2D.js","names":[],"sources":["../../src/typescript/lib/component/container/FloatingPanel.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Panel, PanelOptions } from \"~/core/Panel.js\";\nimport { AnchorConstraints } from \"~/layout/AnchorConstraints.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/** Pixel gap kept between a hugged text column's right edge and this panel's left edge — see {@link FloatingPanel.placeNextTo}. */\nconst TEXT_COLUMN_GAP_PX = 16;\n\n/** Which corner of the host's inner box a {@link FloatingPanel} pins itself to. */\nexport type FloatingPanelCorner = \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n\n/**\n * Construction-time options for {@link FloatingPanel}.\n *\n * @category Containers\n */\nexport interface FloatingPanelOptions extends PanelOptions {\n /** Which corner of the host's inner box to pin to. Default `\"top-right\"`. */\n corner?: FloatingPanelCorner;\n\n /** Pixel distance from the two corner edges. Default `12`. */\n margin?: number;\n}\n\n/** Corner a `FloatingPanel` pins to when the caller doesn't specify one. */\nconst DEFAULT_CORNER: FloatingPanelCorner = \"top-right\";\n\n/**\n * Default pixel margin between a `FloatingPanel` and the two edges of its\n * pinned corner — mirrors `DiagramView`'s own `CONTROLS_MARGIN`, the\n * hand-rolled precedent this class formalizes.\n */\nconst DEFAULT_MARGIN = 12;\n\nconst _defaultFloatingPanelOptions: Partial<FloatingPanelOptions> = {\n insets: new Insets(0, 0, 0, 0),\n corner: DEFAULT_CORNER,\n margin: DEFAULT_MARGIN,\n};\n\n/**\n * A `Panel` that pins itself to one corner of its host's inner box, via an\n * owned {@link AnchorConstraints} instance.\n *\n * Exposed through {@link FloatingPanel.getAnchorConstraints}, this formalizes\n * the corner-pinning technique `DiagramView` used by hand for its zoom/fit/\n * reset control cluster: a consumer whose own layout manager is `Anchor`\n * adds a `FloatingPanel` the same way — `host.addComponent(panel,\n * panel.getAnchorConstraints())`.\n *\n * `FloatingPanel` does not install `Anchor` on its host and does not touch\n * the host's other children. It carries no default background, border, or\n * shadow, and defaults to zero insets, so wrapping an existing bare cluster\n * in one changes nothing visible until a consumer styles it.\n *\n * @category Containers\n */\nclass FloatingPanel<TOptions extends FloatingPanelOptions = FloatingPanelOptions> extends Panel<TOptions> {\n\n private readonly _anchorConstraints: AnchorConstraints = new AnchorConstraints();\n\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n super(options, { ..._defaultFloatingPanelOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>);\n\n this.applyCornerAndMargin();\n }\n\n /**\n * Dispatches `corner` / `margin`; every other option is inherited from `Panel`.\n *\n * @param options - The options bag carrying the values to apply.\n * @returns This panel, for method chaining.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.corner !== undefined) {\n this._options.corner = options.corner;\n }\n\n if (options.margin !== undefined) {\n this._options.margin = options.margin;\n }\n\n return this;\n }\n\n /**\n * Which corner this panel currently pins to.\n *\n * @returns The cached corner, or the class default when never set.\n */\n getCorner(): FloatingPanelCorner {\n return this._options.corner ?? this._defaultOptions.corner ?? DEFAULT_CORNER;\n }\n\n /**\n * Re-pins this panel to a different corner of its host's inner box.\n * Idempotent: a repeat call with the unchanged corner writes nothing.\n *\n * @param value - The corner to pin to.\n *\n * @returns This panel, for method chaining.\n */\n setCorner(value: FloatingPanelCorner): this {\n if (this.getCorner() === value) {\n return this;\n }\n\n this._options.corner = value;\n this.applyCornerAndMargin();\n this.getParentComponent()?.scheduleLayout();\n\n return this;\n }\n\n /**\n * The pixel margin between this panel and the two edges of its pinned corner.\n *\n * @returns The cached margin, or the class default when never set.\n */\n getMargin(): number {\n return this._options.margin ?? this._defaultOptions.margin ?? DEFAULT_MARGIN;\n }\n\n /**\n * Changes the pixel margin between this panel and the two edges of its\n * pinned corner. Idempotent: a repeat call with the unchanged margin\n * writes nothing.\n *\n * @param value - The new margin, in pixels.\n *\n * @returns This panel, for method chaining.\n */\n setMargin(value: number): this {\n if (this.getMargin() === value) {\n return this;\n }\n\n this._options.margin = value;\n this.applyCornerAndMargin();\n this.getParentComponent()?.scheduleLayout();\n\n return this;\n }\n\n /**\n * The `AnchorConstraints` instance this panel owns and keeps in sync with\n * {@link getCorner} / {@link getMargin}. Pass it as the second argument to\n * the host's `addComponent` call: `host.addComponent(panel,\n * panel.getAnchorConstraints())`.\n *\n * @returns This panel's owned constraints instance.\n */\n getAnchorConstraints(): AnchorConstraints {\n return this._anchorConstraints;\n }\n\n /**\n * Repositions this panel horizontally to sit just past `textColumn`'s\n * real rendered right edge, instead of pinning to this panel's own\n * corner — so it reads as \"beside the prose\" rather than \"in the far\n * corner of the window\" on a wide viewport. Clamped so it never sits\n * further right than the plain corner position would, and falls back to\n * that same corner position outright when `textColumn` is `null` or not\n * yet mounted.\n *\n * The caller — not this panel's own `doLayout` — decides when to call\n * this, mirroring how other self-positioning components in this codebase\n * expose a placement verb for their *owner* to drive (`TabBar.placeAt`,\n * `Menu`'s anchored placement) rather than fighting their own parent's\n * layout pass from inside `doLayout`. A host must call this from its own\n * `doLayout` (after `super.doLayout()`, so every sibling this pass\n * touches — including `textColumn` — has already committed and flushed\n * its geometry for it) *and* after anything that can change\n * `textColumn`'s rendered width without triggering a layout pass at all,\n * e.g. `Markdown.setMaxMeasure` / `setFontScale` (both write a CSS rule\n * directly and schedule no layout of their own).\n *\n * Reads `textColumn`'s *rendered* width via a live DOM rect rather than\n * `textColumn.getWidth()` — deliberately: a reading-width cap is\n * sometimes CSS-only (e.g. `Markdown`'s `max-width`), not a JS layout\n * constraint, so on a wide viewport the *rendered* box can be far\n * narrower than the *allocated* one `getWidth()` would report. Needs no\n * DOM read of this panel's own host, only of `textColumn` itself — its\n * left edge (`getX()`) is a plain JS layout query, since only\n * `textColumn`'s *width* is ever CSS-overridden, not its position.\n *\n * @param textColumn - The column whose rendered right edge to hug, or\n * `null` to use the plain corner position outright.\n * @returns This panel, for method chaining.\n */\n placeNextTo(textColumn: Component | null): this {\n const host = this.getParentComponent();\n const innerSize = host?.getInnerSize();\n\n if (!host || !innerSize) {\n return this;\n }\n\n const origin = host.getContentInsets().getLeft();\n const cornerX = origin + innerSize.width - this.getWidth() - this.getMargin();\n\n // Frees the X axis for this method to drive directly — only the\n // corner's vertical edge (top/bottom) stays anchor-managed. Reasserted\n // on every call (idempotent) since a later setCorner/setMargin call\n // would otherwise silently restore `right` and re-introduce the\n // conflict this is meant to avoid.\n this.getAnchorConstraints().right = undefined;\n\n const textEl = textColumn?.getElement() ?? null;\n\n if (!textColumn || !textEl) {\n this.setX(cornerX);\n\n return this;\n }\n\n const renderedWidth = DOM.source.getElementRect(textEl).width;\n const hugX = textColumn.getX() + renderedWidth + TEXT_COLUMN_GAP_PX;\n\n this.setX(Math.min(hugX, cornerX));\n\n return this;\n }\n\n /**\n * Resolves the current corner/margin into the two edge offsets `Anchor`\n * reads, clearing the other two edges so a corner change doesn't leave a\n * stale offset behind on the constraints instance this panel owns for its\n * whole lifetime.\n */\n private applyCornerAndMargin(): void {\n const corner = this.getCorner();\n const margin = this.getMargin();\n\n this._anchorConstraints.top = undefined;\n this._anchorConstraints.bottom = undefined;\n this._anchorConstraints.left = undefined;\n this._anchorConstraints.right = undefined;\n\n if (corner === \"top-left\" || corner === \"top-right\") {\n this._anchorConstraints.top = margin;\n } else {\n this._anchorConstraints.bottom = margin;\n }\n\n if (corner === \"top-left\" || corner === \"bottom-left\") {\n this._anchorConstraints.left = margin;\n } else {\n this._anchorConstraints.right = margin;\n }\n }\n}\n\nconst FloatingPanelCallable = callable(FloatingPanel);\ntype FloatingPanelCallable = FloatingPanel;\nexport {\n FloatingPanel as _FloatingPanel,\n FloatingPanelCallable as FloatingPanel,\n};\n"],"mappings":"yNAUA,IAAM,EAAqB,GAmBrB,EAAsC,YAOtC,EAAiB,GAEjB,EAA8D,CAChE,OAAQ,IAAI,EAAO,EAAG,EAAG,EAAG,CAAC,EAC7B,OAAQ,EACR,OAAQ,CACZ,EAmBM,cAAN,cAA0F,CAAgB,CAEtG,mBAAyD,IAAI,EAE7D,YAAY,EAAoB,EAAsC,CAClE,MAAM,EAAS,CAAE,GAAG,EAA8B,GAAI,GAAoB,CAAC,CAAG,CAAsB,EAEpG,KAAK,qBAAqB,CAC9B,CAQA,aAAuB,EAAyB,CAW5C,OAVA,MAAM,aAAa,CAAO,EAEtB,EAAQ,SAAW,IAAA,KACnB,KAAK,SAAS,OAAS,EAAQ,QAG/B,EAAQ,SAAW,IAAA,KACnB,KAAK,SAAS,OAAS,EAAQ,QAG5B,IACX,CAOA,WAAiC,CAC7B,OAAO,KAAK,SAAS,QAAU,KAAK,gBAAgB,QAAU,CAClE,CAUA,UAAU,EAAkC,CASxC,OARI,KAAK,UAAU,IAAM,EACd,MAGX,KAAK,SAAS,OAAS,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,CAAC,EAAE,eAAe,EAEnC,KACX,CAOA,WAAoB,CAChB,OAAO,KAAK,SAAS,QAAU,KAAK,gBAAgB,QAAU,CAClE,CAWA,UAAU,EAAqB,CAS3B,OARI,KAAK,UAAU,IAAM,EACd,MAGX,KAAK,SAAS,OAAS,EACvB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,CAAC,EAAE,eAAe,EAEnC,KACX,CAUA,sBAA0C,CACtC,OAAO,KAAK,kBAChB,CAoCA,YAAY,EAAoC,CAC5C,IAAM,EAAO,KAAK,mBAAmB,EAC/B,EAAY,GAAM,aAAa,EAErC,GAAI,CAAC,GAAQ,CAAC,EACV,OAAO,KAIX,IAAM,EADU,EAAK,iBAAiB,CAAC,CAAC,QACxB,EAAS,EAAU,MAAQ,KAAK,SAAS,EAAI,KAAK,UAAU,EAO5E,KAAK,qBAAqB,CAAC,CAAC,MAAQ,IAAA,GAEpC,IAAM,EAAS,GAAY,WAAW,GAAK,KAE3C,GAAI,CAAC,GAAc,CAAC,EAGhB,OAFA,KAAK,KAAK,CAAO,EAEV,KAGX,IAAM,EAAgB,EAAI,OAAO,eAAe,CAAM,CAAC,CAAC,MAClD,EAAO,EAAW,KAAK,EAAI,EAAgB,EAIjD,OAFA,KAAK,KAAK,KAAK,IAAI,EAAM,CAAO,CAAC,EAE1B,IACX,CAQA,sBAAqC,CACjC,IAAM,EAAS,KAAK,UAAU,EACxB,EAAS,KAAK,UAAU,EAE9B,KAAK,mBAAmB,IAAS,IAAA,GACjC,KAAK,mBAAmB,OAAS,IAAA,GACjC,KAAK,mBAAmB,KAAS,IAAA,GACjC,KAAK,mBAAmB,MAAS,IAAA,GAE7B,IAAW,YAAc,IAAW,YACpC,KAAK,mBAAmB,IAAM,EAE9B,KAAK,mBAAmB,OAAS,EAGjC,IAAW,YAAc,IAAW,cACpC,KAAK,mBAAmB,KAAO,EAE/B,KAAK,mBAAmB,MAAQ,CAExC,CACJ,EAEM,EAAwB,EAAS,aAAa"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./DOM-
|
|
2
|
-
//# sourceMappingURL=Glyph-
|
|
1
|
+
import{t as e}from"./DOM-C-Edb3tA.js";import{b as t,h as n,t as r,v as i}from"./Component-B0ShfPVi.js";var a=new Map;a.set(`unicode-arrow-up`,{kind:`char`,char:`▲`}),a.set(`unicode-arrow-down`,{kind:`char`,char:`▼`}),a.set(`unicode-arrow-left`,{kind:`char`,char:`◀`}),a.set(`unicode-arrow-right`,{kind:`char`,char:`▶`});var o=`http://www.w3.org/2000/svg`,s=`ts-glyph-`,c=!1,l=null;function registerGlyph(e){a.set(e.name,e),e.kind===`svg`&&c&&_addSymbolToSprite(e.name,e)}function unregisterGlyph(e){let t=a.get(e);a.delete(e),t&&t.kind===`svg`&&c&&_removeSymbolFromSprite(e)}function lookupGlyph(e){return a.get(e)}function ensureGlyphSprite(){if(c)return;let t=e.sink.createElementNS(o,`svg`);e.sink.apply(t,{setAttr:{"aria-hidden":`true`,focusable:`false`},style:{position:`absolute`,width:`0`,height:`0`,overflow:`hidden`}}),e.sink.appendChild(e.source.getBody(),t),l=t,c=!0}function ensureGlyphSymbolMounted(e){if(!c)return;let t=a.get(e);t&&t.kind===`svg`&&_addSymbolToSprite(e,t)}function _addSymbolToSprite(t,n){if(!l||n.kind!==`svg`)return;let r=s+t;if(e.source.querySelector(l,`#${e.source.escapeSelector(r)}`))return;let i=e.sink.createElementNS(o,`symbol`);e.sink.apply(i,{setAttr:{id:r,viewBox:n.viewBox}});let a=e.sink.createElementNS(o,`path`);e.sink.apply(a,{setAttr:{d:n.path}}),e.sink.appendChild(i,a),e.sink.appendChild(l,i)}function _removeSymbolFromSprite(t){if(!l)return;let n=s+t,r=e.source.querySelector(l,`#${e.source.escapeSelector(n)}`);if(r){let t=e.source.querySelector(r,`path`);e.sink.removeChild(l,r),e.sink.release(r),t&&e.sink.release(t)}}var u=`ts-ui-glyph-`,d=new Set,f=!1;function ensureGlyphKeyframes(){f||(f=!0,t.ensureKeyframes(`ts-ui-glyph-spin`,`from { transform: rotate(0deg); } to { transform: rotate(360deg); }`),t.ensureKeyframes(`ts-ui-glyph-pulse`,`0%, 12.5% { transform: rotate(0deg); } 12.5%, 25% { transform: rotate(45deg); } 25%, 37.5% { transform: rotate(90deg); } 37.5%, 50% { transform: rotate(135deg); } 50%, 62.5% { transform: rotate(180deg); } 62.5%, 75% { transform: rotate(225deg); } 75%, 87.5% { transform: rotate(270deg); } 87.5%, 100% { transform: rotate(315deg); }`),t.ensureKeyframes(`ts-ui-glyph-beat`,`0%, 90% { transform: scale(1); } 45% { transform: scale(1.25); }`),new t({scope:`class`,name:`ts-ui-glyph-spin`,styles:{animation:`ts-ui-glyph-spin var(--ts-ui-glyph-spin-duration, 2000ms) linear infinite`}}),new t({scope:`class`,name:`ts-ui-glyph-pulse`,styles:{animation:`ts-ui-glyph-pulse var(--ts-ui-glyph-pulse-duration, 1000ms) steps(8) infinite`}}),new t({scope:`class`,name:`ts-ui-glyph-beat`,styles:{animation:`ts-ui-glyph-beat var(--ts-ui-glyph-beat-duration, 1000ms) ease-in-out infinite`}}))}function _onReducedMotionChange(){for(let e of Array.from(d)){let t=e.deref();if(!t){d.delete(e);continue}t._syncReducedMotion()}}e.source.matchMedia(`(prefers-reduced-motion: reduce)`).addChangeListener(_onReducedMotionChange);var p={preferredSize:{width:16,height:16},tag:`span`},Glyph=class extends r{_name;_def;static register(...e){for(let t of e)registerGlyph(t)}static unregister(e){unregisterGlyph(e)}constructor(e,t,n){let r=lookupGlyph(e);if(!r)throw Error(`Unknown glyph: `+e);super(t,{...p,...n??{}}),this._name=e,this._def=r,r.kind===`char`&&(this._options.lineHeight===void 0&&this.setLineHeight(`1`),this._options.textAlign===void 0&&this.setTextAlign(`center`))}setPreferredSize(e){return super.setPreferredSize(e),super.setMinSize(e),super.setMaxSize(e),this}getBaseline(){let e=this.getPreferredSize();return e?e.height-3:null}getGlyphName(){return this._name}getFontSize(){return this._options.fontSize??null}setFontSize(e){return this._options.fontSize=e,this.setElementCSSRule(`fontSize`,e+`px`),this}getLineHeight(){let e=this._options.lineHeight;return e===void 0?null:typeof e==`number`?e+`px`:e}setLineHeight(e){return this._options.lineHeight=e,this.setElementCSSRule(`lineHeight`,typeof e==`number`?e+`px`:e),this}getTextAlign(){return this._options.textAlign??null}setTextAlign(e){return this._options.textAlign=e,this.setElementCSSRule(`textAlign`,e),this}getAnimated(){return this._glyphAnimation}setAnimated(t){if(this._glyphAnimation===t)return this;let n=this._glyphAnimation;this._glyphAnimation=t;let r=this.getElement();return r&&n&&e.sink.apply(r,{removeClass:[u+n]}),t===null?(this.setElementCSSRule(`animationDuration`,null),this._animatedRef&&=(d.delete(this._animatedRef),null),this):(ensureGlyphKeyframes(),this._animatedRef||(this._animatedRef=new WeakRef(this),d.add(this._animatedRef)),!i.isReducedMotion()&&r&&e.sink.apply(r,{addClass:[u+t]}),this._glyphAnimationDuration>0&&this.setElementCSSRule(`animationDuration`,this._glyphAnimationDuration+`ms`),this)}clearAnimated(){return this.setAnimated(null)}onEffectiveVisibilityChange(e){super.onEffectiveVisibilityChange(e),this._glyphAnimation!=null&&this.setAnimationPlayState(e?null:`paused`)}getAnimationDuration(){return this._glyphAnimationDuration}setAnimationDuration(e){return this._glyphAnimationDuration=e,this._glyphAnimation!=null&&!i.isReducedMotion()&&this.setElementCSSRule(`animationDuration`,e>0?e+`ms`:null),this}_syncReducedMotion(){let t=this._glyphAnimation;if(!t)return;let n=this.getElement(!0),r=u+t;i.isReducedMotion()?(e.sink.apply(n,{removeClass:[r]}),this.setElementCSSRule(`animationDuration`,null)):(e.sink.apply(n,{addClass:[r]}),this._glyphAnimationDuration>0&&this.setElementCSSRule(`animationDuration`,this._glyphAnimationDuration+`ms`))}applyOptions(e){super.applyOptions(e),e.fontSize!==void 0&&this.setFontSize(e.fontSize),e.lineHeight!==void 0&&this.setLineHeight(e.lineHeight),e.textAlign!==void 0&&this.setTextAlign(e.textAlign),e.animationDuration!==void 0&&this.setAnimationDuration(e.animationDuration);let t=this.getPreferredSizeConstraint();return t&&(e.minSize===void 0&&this.setMinSize({width:t.width,height:t.height}),e.maxSize===void 0&&this.setMaxSize({width:t.width,height:t.height})),e.animation!==void 0&&this.setAnimated(e.animation),this}createRootElement(){let t=super.createRootElement();if(this._def.kind!==`svg`)return t;ensureGlyphSprite(),ensureGlyphSymbolMounted(this._name);let n=`http://www.w3.org/2000/svg`,r=e.sink.createElementNS(n,`svg`);e.sink.apply(r,{style:{position:`absolute`,left:`0`,top:`0`,width:`100%`,height:`100%`,display:`block`},setAttr:{fill:`currentColor`,"aria-hidden":`true`,focusable:`false`}});let i=e.sink.createElementNS(n,`use`);return e.sink.apply(i,{setAttr:{href:`#`+s+this._name}}),e.sink.appendChild(r,i),e.sink.appendChild(t,r),this.trackHandle(r),this.trackHandle(i),t}render(){let t=super.render();this._def.kind===`char`&&e.sink.apply(t,{text:this._def.char}),this._glyphAnimation&&!i.isReducedMotion()&&e.sink.apply(t,{addClass:[u+this._glyphAnimation]});let n=this._options.preferredSize;return n&&(this.setElementStyle(`width`,n.width+`px`),this.setElementStyle(`height`,n.height+`px`)),t}},m=n(Glyph);export{m as t};
|
|
2
|
+
//# sourceMappingURL=Glyph-_VeBacS2.js.map
|