@jimka/typescript-ui 0.1.1 → 0.2.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/{AbstractBooleanInput-C3rj7sje.js → AbstractBooleanInput-BGesvIZy.js} +2 -2
- package/dist/lib/{AbstractBooleanInput-C3rj7sje.js.map → AbstractBooleanInput-BGesvIZy.js.map} +1 -1
- package/dist/lib/{AbstractInput-CfjW_HM2.js → AbstractInput-BxOtFrER.js} +2 -2
- package/dist/lib/{AbstractInput-CfjW_HM2.js.map → AbstractInput-BxOtFrER.js.map} +1 -1
- package/dist/lib/AnimatedDropdown-CZQEqQi-.js +2 -0
- package/dist/lib/AnimatedDropdown-CZQEqQi-.js.map +1 -0
- package/dist/lib/Border-BgaZkc1R.js +2 -0
- package/dist/lib/Border-BgaZkc1R.js.map +1 -0
- package/dist/lib/{BoxLayout-8ryMD4j5.js → BoxLayout-DrKGfsup.js} +2 -2
- package/dist/lib/{BoxLayout-8ryMD4j5.js.map → BoxLayout-DrKGfsup.js.map} +1 -1
- package/dist/lib/Button-U1rsP4v8.js +2 -0
- package/dist/lib/Button-U1rsP4v8.js.map +1 -0
- package/dist/lib/{Card-AKIUAWYS.js → Card-BVwOS8AG.js} +2 -2
- package/dist/lib/{Card-AKIUAWYS.js.map → Card-BVwOS8AG.js.map} +1 -1
- package/dist/lib/ComboBox-B9EDPu6T.js +2 -0
- package/dist/lib/ComboBox-B9EDPu6T.js.map +1 -0
- package/dist/lib/Component-DXf5a3g0.js +2 -0
- package/dist/lib/Component-DXf5a3g0.js.map +1 -0
- package/dist/lib/Container-D5H8VxJK.js +2 -0
- package/dist/lib/{Container-3KsvsJ6S.js.map → Container-D5H8VxJK.js.map} +1 -1
- package/dist/lib/DOM-CGn7xyTw.js +2 -0
- package/dist/lib/DOM-CGn7xyTw.js.map +1 -0
- package/dist/lib/{DragManager-c6M_mE3e.js → DragManager-CI4mZQFy.js} +2 -2
- package/dist/lib/{DragManager-tPMnbjeO.js.map → DragManager-CI4mZQFy.js.map} +1 -1
- package/dist/lib/FieldDecorator-CJs9gwqH.js +2 -0
- package/dist/lib/{FieldDecorator-Bl0h9UEF.js.map → FieldDecorator-CJs9gwqH.js.map} +1 -1
- package/dist/lib/{Fit-CFIr4P9R.js → Fit-DjRsiwlg.js} +2 -2
- package/dist/lib/{Fit-CUS1JXy3.js.map → Fit-DjRsiwlg.js.map} +1 -1
- package/dist/lib/Glyph-KEf4nIv2.js +2 -0
- package/dist/lib/Glyph-KEf4nIv2.js.map +1 -0
- package/dist/lib/{Grid-Czux--Mr.js → Grid-DdL9TVeJ.js} +2 -2
- package/dist/lib/{Grid-D8luwRPI.js.map → Grid-DdL9TVeJ.js.map} +1 -1
- package/dist/lib/GridConstraints-DkLueyrf.js +2 -0
- package/dist/lib/GridConstraints-DkLueyrf.js.map +1 -0
- package/dist/lib/{HBox-BWMf9h6r.js → HBox-Ce0GTCJP.js} +2 -2
- package/dist/lib/{HBox-BWMf9h6r.js.map → HBox-Ce0GTCJP.js.map} +1 -1
- package/dist/lib/{Header-CQjomjo0.js → Header-BQIVpBte.js} +2 -2
- package/dist/lib/{Header-CQjomjo0.js.map → Header-BQIVpBte.js.map} +1 -1
- package/dist/lib/{IconText-BXJK0MOq.js → IconText-Bo4Qcnot.js} +2 -2
- package/dist/lib/{IconText-BXJK0MOq.js.map → IconText-Bo4Qcnot.js.map} +1 -1
- package/dist/lib/LayoutConstraints-DkctJZXB.js +2 -0
- package/dist/lib/LayoutConstraints-DkctJZXB.js.map +1 -0
- package/dist/lib/LayoutSerialization-BT66TY83.js +2 -0
- package/dist/lib/LayoutSerialization-BT66TY83.js.map +1 -0
- package/dist/lib/LayoutSizes-DU3qSq0w.js +2 -0
- package/dist/lib/LayoutSizes-DU3qSq0w.js.map +1 -0
- package/dist/lib/List-DtTVTyWW.js +2 -0
- package/dist/lib/List-DtTVTyWW.js.map +1 -0
- package/dist/lib/Menu-Dz4L7EKJ.js +2 -0
- package/dist/lib/Menu-Dz4L7EKJ.js.map +1 -0
- package/dist/lib/{MenuButton-D15cSbMf.js → MenuButton-VJ5uC3c1.js} +2 -2
- package/dist/lib/{MenuButton-D15cSbMf.js.map → MenuButton-VJ5uC3c1.js.map} +1 -1
- package/dist/lib/Panel-DzWdYwq1.js +2 -0
- package/dist/lib/Panel-DzWdYwq1.js.map +1 -0
- package/dist/lib/{Position-DJKB0N3l.js → Position-A39T7-_1.js} +2 -2
- package/dist/lib/{Position-DJKB0N3l.js.map → Position-A39T7-_1.js.map} +1 -1
- package/dist/lib/ProgressSpinner-zJKtGyNJ.js +2 -0
- package/dist/lib/ProgressSpinner-zJKtGyNJ.js.map +1 -0
- package/dist/lib/RadioButton-CYSSv4nV.js +2 -0
- package/dist/lib/RadioButton-CYSSv4nV.js.map +1 -0
- package/dist/lib/{RovingTabIndex-CFIzIjjU.js → RovingTabIndex-BSZ31Vp5.js} +2 -2
- package/dist/lib/{RovingTabIndex-D-zOuptw.js.map → RovingTabIndex-BSZ31Vp5.js.map} +1 -1
- package/dist/lib/Scrollbar-BhtOjqkG.js +2 -0
- package/dist/lib/Scrollbar-BhtOjqkG.js.map +1 -0
- package/dist/lib/Slider-CdXm7E64.js +2 -0
- package/dist/lib/Slider-CdXm7E64.js.map +1 -0
- package/dist/lib/{Spacer-BVQncB5B.js → Spacer-D9NGW4QG.js} +2 -2
- package/dist/lib/{Spacer-BVQncB5B.js.map → Spacer-D9NGW4QG.js.map} +1 -1
- package/dist/lib/{TabButton-DqYDfN7P.js → TabButton-CThevdY_.js} +2 -2
- package/dist/lib/{TabButton-DqYDfN7P.js.map → TabButton-CThevdY_.js.map} +1 -1
- package/dist/lib/Text-gz6qjFfP.js +2 -0
- package/dist/lib/Text-gz6qjFfP.js.map +1 -0
- package/dist/lib/Tooltip-tkXDk5Bo.js +3 -0
- package/dist/lib/Tooltip-tkXDk5Bo.js.map +1 -0
- package/dist/lib/{VBox-CdV9VGxR.js → VBox-EIqw85Rh.js} +2 -2
- package/dist/lib/{VBox-CdV9VGxR.js.map → VBox-EIqw85Rh.js.map} +1 -1
- package/dist/lib/{VirtualRowView-C18j90n5.js → VirtualRowView-BxpHQ_u8.js} +2 -2
- package/dist/lib/{VirtualRowView-C18j90n5.js.map → VirtualRowView-BxpHQ_u8.js.map} +1 -1
- package/dist/lib/{VirtualScroller-BKMvTisA.js → VirtualScroller-DwEEJE1_.js} +2 -2
- package/dist/lib/{VirtualScroller-BKMvTisA.js.map → VirtualScroller-DwEEJE1_.js.map} +1 -1
- 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 +2 -2
- 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/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +2 -2
- 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/layout.es.js +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/types/component/button/Button.d.ts +4 -3
- package/dist/lib/types/component/chart/AbstractChart.d.ts +1 -1
- package/dist/lib/types/component/chart/ChartLegend.d.ts +1 -1
- package/dist/lib/types/component/container/DialogBackdrop.d.ts +2 -1
- package/dist/lib/types/component/container/MenuItem.d.ts +1 -1
- package/dist/lib/types/component/container/ScrollStrip.d.ts +1 -0
- package/dist/lib/types/component/container/SplitGutter.d.ts +3 -2
- package/dist/lib/types/component/container/TabBar.d.ts +1 -2
- package/dist/lib/types/component/container/TabPanel.d.ts +6 -3
- package/dist/lib/types/component/container/WindowBorder.d.ts +2 -1
- package/dist/lib/types/component/container/WindowHeader.d.ts +2 -1
- package/dist/lib/types/component/display/Glyph.d.ts +2 -1
- package/dist/lib/types/component/display/Markdown.d.ts +1 -1
- package/dist/lib/types/component/display/PaginationBar.d.ts +1 -1
- package/dist/lib/types/component/display/SpinnerWrap.d.ts +2 -0
- package/dist/lib/types/component/display/Video.d.ts +1 -1
- package/dist/lib/types/component/display/VideoPlayer.d.ts +1 -1
- package/dist/lib/types/component/editor/CodeEditor.d.ts +2 -1
- package/dist/lib/types/component/editor/MarkdownEditor.d.ts +1 -1
- package/dist/lib/types/component/input/Checkbox.d.ts +2 -1
- package/dist/lib/types/component/input/Link.d.ts +1 -1
- package/dist/lib/types/component/input/RadioButton.d.ts +2 -1
- package/dist/lib/types/component/input/Slider.d.ts +2 -1
- package/dist/lib/types/component/input/Text.d.ts +1 -3
- package/dist/lib/types/component/input/TextInput.d.ts +3 -2
- package/dist/lib/types/component/list/AbstractSelectableList.d.ts +2 -1
- package/dist/lib/types/component/menubar/MenuBarButton.d.ts +1 -1
- package/dist/lib/types/core/AnimatedDropdown.d.ts +6 -2
- package/dist/lib/types/core/Animation.d.ts +9 -6
- package/dist/lib/types/core/Component.d.ts +16 -11
- package/dist/lib/types/core/DOM.d.ts +8 -0
- package/dist/lib/types/core/Event.d.ts +12 -6
- package/dist/lib/types/core/index.d.ts +2 -2
- package/dist/lib/types/layout/Accordion.d.ts +2 -0
- package/dist/lib/types/layout/Border.d.ts +1 -0
- package/dist/lib/types/layout/CollapseSupport.d.ts +5 -1
- package/dist/lib/types/layout/LayoutConstraints.d.ts +1 -0
- package/dist/lib/types/layout/LayoutManager.d.ts +2 -0
- package/dist/lib/types/layout/Split.d.ts +1 -0
- package/dist/lib/types/layout/Tab.d.ts +10 -3
- package/dist/lib/types/overlay/AbstractWindow.d.ts +9 -2
- package/dist/lib/types/overlay/Dialog.d.ts +6 -0
- package/dist/lib/types/overlay/Dock.d.ts +12 -2
- package/dist/lib/types/overlay/Drawer.d.ts +5 -0
- package/dist/lib/types/overlay/Menu.d.ts +3 -1
- package/dist/lib/types/overlay/Notification.d.ts +3 -0
- package/dist/lib/types/overlay/Popover.d.ts +3 -1
- package/dist/lib/types/overlay/Rail.d.ts +7 -0
- package/dist/lib/types/overlay/Tooltip.d.ts +3 -0
- package/dist/lib/types/overlay/index.d.ts +1 -1
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/dist/lib/AbstractBooleanInput-C6CidMMX.js +0 -2
- package/dist/lib/AbstractBooleanInput-C6CidMMX.js.map +0 -1
- package/dist/lib/AbstractInput-DD-NpicS.js +0 -2
- package/dist/lib/AbstractInput-DD-NpicS.js.map +0 -1
- package/dist/lib/AnimatedDropdown-BFz-DO7R.js +0 -2
- package/dist/lib/AnimatedDropdown-BFz-DO7R.js.map +0 -1
- package/dist/lib/AnimatedDropdown-BbGCs70E.js +0 -2
- package/dist/lib/AnimatedDropdown-BbGCs70E.js.map +0 -1
- package/dist/lib/Border-5Ki2DCWz.js +0 -2
- package/dist/lib/Border-5Ki2DCWz.js.map +0 -1
- package/dist/lib/Border-oZC_SDy8.js +0 -2
- package/dist/lib/Border-oZC_SDy8.js.map +0 -1
- package/dist/lib/BoxLayout-DgZukB5_.js +0 -2
- package/dist/lib/BoxLayout-DgZukB5_.js.map +0 -1
- package/dist/lib/Button-Cdq2ySPL.js +0 -2
- package/dist/lib/Button-Cdq2ySPL.js.map +0 -1
- package/dist/lib/Button-DEUtBqK4.js +0 -2
- package/dist/lib/Button-DEUtBqK4.js.map +0 -1
- package/dist/lib/Card-UF0fq8cQ.js +0 -2
- package/dist/lib/Card-UF0fq8cQ.js.map +0 -1
- package/dist/lib/ComboBox-GOBOAJ1N.js +0 -2
- package/dist/lib/ComboBox-GOBOAJ1N.js.map +0 -1
- package/dist/lib/ComboBox-e_YVsWBr.js +0 -2
- package/dist/lib/ComboBox-e_YVsWBr.js.map +0 -1
- package/dist/lib/Component-BR2f0Itb.js +0 -2
- package/dist/lib/Component-BR2f0Itb.js.map +0 -1
- package/dist/lib/Component-Bs6TvaGZ.js +0 -2
- package/dist/lib/Component-Bs6TvaGZ.js.map +0 -1
- package/dist/lib/Container-3KsvsJ6S.js +0 -2
- package/dist/lib/Container-CzyZeMyZ.js +0 -2
- package/dist/lib/Container-CzyZeMyZ.js.map +0 -1
- package/dist/lib/DOM-DeF_dWe2.js +0 -2
- package/dist/lib/DOM-DeF_dWe2.js.map +0 -1
- package/dist/lib/DragManager-c6M_mE3e.js.map +0 -1
- package/dist/lib/DragManager-tPMnbjeO.js +0 -2
- package/dist/lib/FieldDecorator-Bl0h9UEF.js +0 -2
- package/dist/lib/FieldDecorator-E7WzutjO.js +0 -2
- package/dist/lib/FieldDecorator-E7WzutjO.js.map +0 -1
- package/dist/lib/Fit-CFIr4P9R.js.map +0 -1
- package/dist/lib/Fit-CUS1JXy3.js +0 -2
- package/dist/lib/Glyph-6Ki3A1_a.js +0 -2
- package/dist/lib/Glyph-6Ki3A1_a.js.map +0 -1
- package/dist/lib/Glyph-WUqTF_Z9.js +0 -2
- package/dist/lib/Glyph-WUqTF_Z9.js.map +0 -1
- package/dist/lib/Grid-Czux--Mr.js.map +0 -1
- package/dist/lib/Grid-D8luwRPI.js +0 -2
- package/dist/lib/GridConstraints-CzC0w4i-.js +0 -2
- package/dist/lib/GridConstraints-CzC0w4i-.js.map +0 -1
- package/dist/lib/GridConstraints-Q3wvuovN.js +0 -2
- package/dist/lib/GridConstraints-Q3wvuovN.js.map +0 -1
- package/dist/lib/HBox-Q8y1PHlk.js +0 -2
- package/dist/lib/HBox-Q8y1PHlk.js.map +0 -1
- package/dist/lib/Header-zPdvC2AX.js +0 -2
- package/dist/lib/Header-zPdvC2AX.js.map +0 -1
- package/dist/lib/IconText-BvGfu7eq.js +0 -2
- package/dist/lib/IconText-BvGfu7eq.js.map +0 -1
- package/dist/lib/LayoutConstraints-CHI2lhPd.js +0 -2
- package/dist/lib/LayoutConstraints-CHI2lhPd.js.map +0 -1
- package/dist/lib/LayoutSerialization-CWU0iEuV.js +0 -2
- package/dist/lib/LayoutSerialization-CWU0iEuV.js.map +0 -1
- package/dist/lib/LayoutSerialization-C_zcwaN3.js +0 -2
- package/dist/lib/LayoutSerialization-C_zcwaN3.js.map +0 -1
- package/dist/lib/LayoutSizes-BW4wyGDI.js +0 -2
- package/dist/lib/LayoutSizes-BW4wyGDI.js.map +0 -1
- package/dist/lib/LayoutSizes-XdhpAOmc.js +0 -2
- package/dist/lib/LayoutSizes-XdhpAOmc.js.map +0 -1
- package/dist/lib/List-BgxnLWnl.js +0 -2
- package/dist/lib/List-BgxnLWnl.js.map +0 -1
- package/dist/lib/List-D-GhoVgB.js +0 -2
- package/dist/lib/List-D-GhoVgB.js.map +0 -1
- package/dist/lib/Menu-BdnwRY0M.js +0 -2
- package/dist/lib/Menu-BdnwRY0M.js.map +0 -1
- package/dist/lib/Menu-Wz4MK6sA.js +0 -2
- package/dist/lib/Menu-Wz4MK6sA.js.map +0 -1
- package/dist/lib/MenuButton-JQQaKThJ.js +0 -2
- package/dist/lib/MenuButton-JQQaKThJ.js.map +0 -1
- package/dist/lib/Panel-DApa7vA6.js +0 -2
- package/dist/lib/Panel-DApa7vA6.js.map +0 -1
- package/dist/lib/Panel-DIsdaqc2.js +0 -2
- package/dist/lib/Panel-DIsdaqc2.js.map +0 -1
- package/dist/lib/Position-B-WfZYAJ.js +0 -2
- package/dist/lib/Position-B-WfZYAJ.js.map +0 -1
- package/dist/lib/ProgressSpinner-CNYcsBhw.js +0 -2
- package/dist/lib/ProgressSpinner-CNYcsBhw.js.map +0 -1
- package/dist/lib/ProgressSpinner-Dzaka7_c.js +0 -2
- package/dist/lib/ProgressSpinner-Dzaka7_c.js.map +0 -1
- package/dist/lib/RadioButton-CepkneSA.js +0 -2
- package/dist/lib/RadioButton-CepkneSA.js.map +0 -1
- package/dist/lib/RadioButton-eI3-vXn3.js +0 -2
- package/dist/lib/RadioButton-eI3-vXn3.js.map +0 -1
- package/dist/lib/RovingTabIndex-CFIzIjjU.js.map +0 -1
- package/dist/lib/RovingTabIndex-D-zOuptw.js +0 -2
- package/dist/lib/Scrollbar-DQdCdj94.js +0 -2
- package/dist/lib/Scrollbar-DQdCdj94.js.map +0 -1
- package/dist/lib/Scrollbar-DchfiFKC.js +0 -2
- package/dist/lib/Scrollbar-DchfiFKC.js.map +0 -1
- package/dist/lib/Slider-DvDdVvRm.js +0 -2
- package/dist/lib/Slider-DvDdVvRm.js.map +0 -1
- package/dist/lib/Slider-xRxNSjFN.js +0 -2
- package/dist/lib/Slider-xRxNSjFN.js.map +0 -1
- package/dist/lib/Spacer-BqiPiCqz.js +0 -2
- package/dist/lib/Spacer-BqiPiCqz.js.map +0 -1
- package/dist/lib/TabButton-pZKFYg7b.js +0 -2
- package/dist/lib/TabButton-pZKFYg7b.js.map +0 -1
- package/dist/lib/Text-D1RrBY52.js +0 -2
- package/dist/lib/Text-D1RrBY52.js.map +0 -1
- package/dist/lib/Text-DJoUHukb.js +0 -2
- package/dist/lib/Text-DJoUHukb.js.map +0 -1
- package/dist/lib/Tooltip-4lU_tf6r.js +0 -3
- package/dist/lib/Tooltip-4lU_tf6r.js.map +0 -1
- package/dist/lib/Tooltip-5BR7yYEX.js +0 -3
- package/dist/lib/Tooltip-5BR7yYEX.js.map +0 -1
- package/dist/lib/VBox-D5B9ecw0.js +0 -2
- package/dist/lib/VBox-D5B9ecw0.js.map +0 -1
- package/dist/lib/VirtualRowView-Con9SWiU.js +0 -2
- package/dist/lib/VirtualRowView-Con9SWiU.js.map +0 -1
- package/dist/lib/VirtualScroller-BPDmO1ir.js +0 -2
- package/dist/lib/VirtualScroller-BPDmO1ir.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComboBox-B9EDPu6T.js","names":[],"sources":["../../src/typescript/lib/component/input/Link.ts","../../src/typescript/lib/component/input/TextInput.ts","../../src/typescript/lib/component/input/PickerInput.ts","../../src/typescript/lib/component/input/PickerButton.ts","../../src/typescript/lib/component/input/focusRing.ts","../../src/typescript/lib/component/input/AbstractPickerField.ts","../../src/typescript/lib/component/input/TextField.ts","../../src/typescript/lib/component/input/PickerColumn.ts","../../src/typescript/lib/component/input/AbstractCalendarDropdown.ts","../../src/typescript/lib/component/input/DatePickerDropdown.ts","../../src/typescript/lib/component/input/TimeColumns.ts","../../src/typescript/lib/component/input/TimePickerDropdown.ts","../../src/typescript/lib/component/input/TimeField.ts","../../src/typescript/lib/component/input/DateTimePickerDropdown.ts","../../src/typescript/lib/component/input/Checkbox.ts","../../src/typescript/lib/component/input/ComboBox.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Text, TextOptions } from \"~/component/input/Text.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport type { ClickListener } from \"~/component/button/Button.js\";\n\n/**\n * The link foreground colour. `--ts-ui-link-color` lets a theme retint every\n * link at once; the literal is the shipped fallback.\n */\nconst LINK_COLOR_CSS = \"var(--ts-ui-link-color, rgb(21, 101, 192))\";\n\n/**\n * The link's two class-level rules.\n *\n * The underline is constant for every link and varies per instance for none, so\n * it is a rule on the class rather than per-instance state: it costs one CSS\n * rule for the whole page instead of one per link, and it is not an options\n * field, which would owe a typed setter, a getter and a cache it has no use\n * for. A caller who wants it gone passes a `styleRules` entry — those compile\n * to an `#<id>` selector, and an id outranks a class, so the caller's rule wins\n * on specificity without any ordering subtlety.\n *\n * The focus mark uses `:focus-visible` rather than the `:focus` the text inputs\n * use: a link is activated by clicking it, and `:focus` would leave the ring\n * painted after the click. A plain `outline` suffices — the `::after` ring in\n * `focusRing.ts` exists for composite inputs painting onto outer chrome,\n * whereas a link is a leaf element that focuses itself. Note `outlineOffset`\n * pushes the ring *outward*, so it does not protect against an ancestor's\n * `overflow: hidden`; if clipping ever shows up, that `::after` inset ring is\n * the fallback.\n *\n * Both rules key off `.Link`, which comes from the class name, so a subclass\n * would not inherit them — `Link` is not designed for extension.\n */\n(() => {\n new StyleRule({\n scope: \"selector\",\n name: \".Link\",\n styles: {\n textDecoration: \"underline\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".Link:focus-visible\",\n styles: {\n outline: \"2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))\",\n outlineOffset: \"1px\",\n },\n });\n})();\n\n/**\n * String-literal union of the events emitted by {@link Link}. A typed shorthand\n * over the `Event` API — the DOM `\"click\"` event is dispatched through the\n * framework's window-level capture handler.\n *\n * @category Components\n */\nexport type LinkEvent = \"action\";\n\n/**\n * Construction-time options for {@link Link}.\n *\n * @category Components\n */\nexport interface LinkOptions extends TextOptions {\n\n /**\n * When `false`, the link is presentational: it claims no `role` and no\n * `tabindex`, and it does not activate on Enter. For a link inside a\n * container that owns its own keyboard navigation and click routing — a\n * table cell, say — where a focusable child would fight the host.\n * Defaults to `true`.\n *\n * This is not a disabled state: the link keeps its normal appearance, and\n * a host that routes its own clicks still acts on them.\n */\n interactive?: boolean;\n\n /**\n * Construction-time listener wiring — the declarative form of\n * {@link Link.on}. The `action` entry is wired as if `on(\"action\", fn)`\n * had been called.\n */\n listeners?: { action?: ClickListener };\n}\n\n// Only getter-backed options belong here, which is what `_defaultOptions` is\n// for: Component resolves `tag` from it, and `applyStyle` re-reads the two\n// folding getters at render, so all three survive without an `applyOptions`\n// dispatch — and `clearForegroundColor()` still suppresses the default.\n// `interactive` is here so the always-dispatch `?? this.isInteractive()` in\n// applyOptions resolves the class default.\n//\n// The underline is deliberately absent: it is constant styling, not per-instance\n// state, so it is a class-level rule above rather than an option. (`applyOptions`\n// reads `styleRules` only from the caller's bag, so a default here would be\n// dropped silently anyway.)\nconst _defaultLinkOptions: Partial<LinkOptions> = {\n tag: \"a\",\n foregroundColor: LINK_COLOR_CSS,\n cursor: \"pointer\",\n interactive: true,\n};\n\n/**\n * A text link: link-coloured, underlined, and activated by a click or the\n * Enter key. Its **hit area is exactly its text** — it is a {@link Text}\n * subclass rendering a real `<a>`, so the box is the glyph box, unlike a\n * chromeless [`Button`](/api/component/button/classes/Button) whose padding\n * overshoots its label.\n *\n * There is no `href`: a `Link` navigates nothing by itself and activation is\n * always `on(\"action\", fn)`. Enter activates it; Space does not, because Space\n * is button semantics.\n *\n * The hit area only equals the text while the parent sizes the link to its\n * preferred width. A `Fit` parent, or an `HBox`/`VBox` with `stretching: true`,\n * widens the box and the hit area with it.\n *\n * `Link` inherits {@link Text}'s theme subscription, so a link created\n * dynamically and removed from the page must be `dispose()`d — which also\n * releases its keyboard listener.\n *\n * @example\n * ```typescript\n * import { Link } from '@jimka/typescript-ui/component/input';\n *\n * const link = new Link('Open the release notes', {\n * listeners: { action: () => openReleaseNotes() },\n * });\n * panel.addComponent(link);\n * ```\n *\n * @category Components\n */\nclass Link extends Text<LinkOptions> {\n\n // No `_interactive` backing field: `_options` is the cache. A field\n // initializer here would run after super() and clobber the value the\n // applyOptions cascade wrote.\n\n constructor(text?: String, options?: LinkOptions) {\n super(text, options, _defaultLinkOptions);\n\n // Wired once for the component's whole life, regardless of\n // `interactive`: handleKeyDown self-guards, so the flag needs no\n // listener churn — and a non-interactive link can never be a keydown\n // target anyway, since it is not focusable and Event dispatches by\n // event target. dispose() removes it.\n Event.addListener(this, \"keydown\", this.handleKeyDown);\n\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Dispatches the `interactive` option to its setter.\n *\n * @param options - The caller's construction options.\n *\n * @returns This link, for method chaining.\n */\n protected applyOptions(options: LinkOptions): this {\n super.applyOptions(options);\n\n // Always-dispatch: the effect is construction-time with no render\n // re-read, so the class default must fire too. Gating this on\n // `options.interactive !== undefined` would leave a default link\n // without its role and tabindex.\n this.setInteractive(options.interactive ?? this.isInteractive());\n\n return this;\n }\n\n /**\n * Whether this link is focusable and keyboard-activatable.\n *\n * @returns `true` when the link claims its interactive affordance.\n */\n isInteractive(): boolean {\n return this._options.interactive ?? this._defaultOptions.interactive ?? true;\n }\n\n /**\n * Toggles the link's interactive affordance. `role` and `tabindex` move\n * together because both describe the one affordance.\n *\n * Does no listener work: the keyboard handler is wired once in the\n * constructor and reads this flag when it fires. No idempotence guard is\n * needed either — the ARIA setters are value-assignments, and the listener\n * is never re-registered.\n *\n * @param value - `true` to make the link focusable and keyboard-activatable.\n *\n * @returns This link, for method chaining.\n */\n setInteractive(value: boolean): this {\n this._options.interactive = value;\n\n if (value) {\n // An `<a>` with no href is neither focusable nor exposed as a link\n // (it maps to `generic`), so both are supplied explicitly.\n this.getAria().setRole(\"link\").setTabIndex(0);\n } else {\n // A presentational link claims neither: it cannot be activated, and\n // its host already announces the text.\n this.getAria().clearRole().setTabIndex(null);\n }\n\n return this;\n }\n\n /**\n * Registers a listener for this link's `\"action\"` event — fired on click\n * and on Enter. A typed semantic shorthand over the `Event` API (the\n * underlying DOM event is `\"click\"`).\n *\n * @param event - The event name. Only `\"action\"` is accepted.\n * @param listener - The callback to invoke when the link is actioned.\n *\n * @returns This link, for method chaining.\n */\n on(event: \"action\", listener: ClickListener): this;\n on(_event: \"action\", listener: ClickListener): this {\n Event.addListener(this, \"click\", listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered `\"action\"` listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This link, for method chaining.\n */\n off(event: \"action\", listener: ClickListener): this;\n off(_event: \"action\", listener: ClickListener): this {\n Event.removeListener(this, \"click\", listener);\n\n return this;\n }\n\n /**\n * Programmatically actions the link, as if the user had clicked it: fires\n * this link's own `\"click\"` event so every registered {@link on | `\"action\"`}\n * handler runs. With no handler registered this is a no-op — the link has\n * no click plumbing of its own.\n *\n * @returns This link, for method chaining.\n */\n click(): this {\n Event.fireEvent(this, \"click\");\n\n return this;\n }\n\n /**\n * Removes the keyboard listener, then the inherited theme listener. Call\n * when the link is permanently removed.\n */\n protected destructor(): void {\n // Unconditional — the listener is always registered.\n Event.removeListener(this, \"keydown\", this.handleKeyDown);\n\n super.destructor();\n }\n\n /**\n * Activates on Enter only — Space is button semantics, not link semantics.\n * A no-href `<a>` fires no native click on Enter, so it is synthesised\n * here; with no href it can never double-fire.\n *\n * The `isInteractive()` guard keeps the link locally correct rather than\n * resting on the browser never targeting a non-focusable element.\n *\n * A prototype method, not an arrow field: `Event` binds `this` by applying\n * the listener to the component, and the stable reference is what lets\n * `dispose()` unregister it.\n *\n * @param event - The keyboard event being handled.\n */\n private handleKeyDown(event: KeyboardEvent): void {\n if (!this.isInteractive()) {\n return;\n }\n\n if (event.key !== \"Enter\") {\n return;\n }\n\n event.preventDefault();\n\n this.click();\n }\n}\n\nconst LinkCallable = callable(Link);\ntype LinkCallable = Link;\nexport {\n Link as _Link,\n LinkCallable as Link\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Unified focus mark for every standalone TextInput subclass — `TextField`,\n * `TextArea`, `PasswordField`. Uses `box-shadow: inset` rather than the\n * pseudo-element overlay the composite inputs (`AutoCompleteField`, the\n * picker fields, `NumberSpinner`) rely on, because `<input>` is a CSS\n * replaced element and doesn't render `::before` / `::after` reliably.\n * The inset 2-px shadow paints at the same visual position as those\n * pseudo borders — just inside the element's own border edge — so the\n * two recipes are interchangeable visually. `PickerInput` and any inner\n * input that opts out via `setOutline(\"none\")` (AutoCompleteField,\n * NumberSpinner) keep the focus indicator on the outer composite\n * instead.\n */\n(() => {\n new StyleRule({\n scope: \"selector\",\n name: \".TextField:focus, .TextArea:focus, .PasswordField:focus\",\n styles: {\n outline: \"none\",\n boxShadow: \"inset 0 0 0 2px var(--ts-ui-indicator-focus, rgb(30, 100, 200))\",\n },\n });\n})();\n\n/**\n * Construction-time options for {@link TextInput}.\n *\n * @remarks `tag` is inherited from {@link ComponentOptions} but defaults to\n * `\"input\"` for `TextInput` (subclasses such as {@link TextArea} pass\n * `\"textarea\"`).\n *\n * @category Components\n */\nexport interface TextInputOptions extends AbstractInputOptions {\n type?: string;\n text?: string;\n textAlign?: string | null;\n placeholder?: string;\n maxLength?: number;\n inputMode?: string;\n autoComplete?: string;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * text input's `action` shorthand to the inherited `change` / `binding`.\n */\n listeners?: {\n action?: () => void;\n change?: (value: string) => void;\n binding?: () => void;\n };\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * The cascade in `Component`'s constructor dispatches each setter once with\n * the final value, so any field the caller supplied wins.\n */\nconst _defaultTextInputOptions: Partial<TextInputOptions> = {\n tag: \"input\",\n backgroundColor: \"var(--ts-ui-input-bg, rgb(255, 255, 255))\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n};\n\n/**\n * Base class for `<input>`- and `<textarea>`-backed text controls. Owns\n * the `<input>`-by-default `render()`, the type/name HTML attributes, the\n * text value cache, placeholder / maxLength / inputMode / autoComplete /\n * textAlign setters, the native `disabled` and `readonly` writes, and the\n * `getValue` / `setValue` aliases that satisfy the {@link AbstractInput}\n * value contract. Subclasses ({@link TextField}, {@link TextArea},\n * {@link PasswordField}, [`PickerInput`](/api/component/input/classes/PickerInput))\n * inherit the full surface.\n *\n * @category Components\n */\nclass TextInput<TOptions extends TextInputOptions = TextInputOptions>\n extends AbstractInput<string, TOptions>\n{\n\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n super(\n options,\n { ..._defaultTextInputOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n // Default sans-serif 12px font lives on the per-component CSS rule.\n // Queueing through `setElementCSSRules` at construction defers the\n // write until `applyStyle` flushes the buffer at render time, so we\n // no longer need a class-level `applyStyle` override.\n this.setElementCSSRules({\n fontFamily: \"var(--ts-ui-font-family, sans-serif)\",\n fontSize: \"var(--ts-ui-font-size, 14px)\",\n // Render the input's single line at the same px line box every text\n // control measures against (`Util.lineHeightPx`), so the input no\n // longer inherits the UA `line-height: normal` and its baseline\n // coincides with a `Text`/`Label` in the same row.\n lineHeight: \"calc(1em + var(--ts-ui-line-padding, 2px))\",\n });\n\n // Single native `input` listener for every text-derived control: it\n // syncs the cached text from the live DOM, then fans the fresh value\n // out through AbstractInput's change / binding listeners. Folding the\n // sync and the notify into one base listener (rather than a per-subclass\n // second `input` hook wired after this one) guarantees the cache is\n // current before `on(\"change\")` reads it — the fix for the\n // one-keystroke-behind value bug.\n Event.addListener(this, \"input\", this.onInput);\n }\n\n /**\n * Native `input` handler: syncs the cached text from the live DOM element,\n * then notifies the change / binding listeners with the fresh value.\n *\n * @remarks Registered once by the base constructor for every subclass, so\n * `getText()` and the `on(\"change\")` fan-out always observe the just-typed\n * value on the same event. Subclasses must not wire a second `input`\n * listener.\n */\n protected onInput(): void {\n const element = this.getElement();\n\n this.setText(element ? DOM.source.getValue(element) : \"\");\n this.notifyChange(this.getValue());\n }\n\n /**\n * Applies a {@link TextInputOptions} bag, dispatching name, text,\n * alignment, and native HTML attributes (placeholder, maxLength,\n * inputMode, autoComplete) after inherited Component fields. The\n * `enabled` / `readOnly` flags are routed through the typed setters\n * because TextInput's `applyEnabled` / `applyReadOnly` are\n * cascade-safe (the cache-then-write pattern survives the element not\n * yet existing).\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.text !== undefined) {\n this.setText(options.text);\n }\n\n if (options.textAlign !== undefined) {\n this.setTextAlign(options.textAlign);\n }\n\n if (options.placeholder !== undefined) {\n this.setPlaceholder(options.placeholder);\n }\n\n if (options.readOnly !== undefined) {\n this.setReadOnly(options.readOnly);\n }\n\n if (options.enabled !== undefined) {\n this.setEnabled(options.enabled);\n }\n\n if (options.maxLength !== undefined) {\n this.setMaxLength(options.maxLength);\n }\n\n if (options.inputMode !== undefined) {\n this.setInputMode(options.inputMode);\n }\n\n if (options.autoComplete !== undefined) {\n this.setAutoComplete(options.autoComplete);\n }\n\n return this;\n }\n\n /**\n * Registers a listener for one of this text input's events. `\"action\"`\n * is a typed semantic shorthand over {@link Event.addListener} for the\n * native `input` DOM event (fired on every keystroke); `\"keydown\"` is the\n * same shorthand for the native `keydown` DOM event (so a consumer can wire\n * keyboard shortcuts without reaching for the raw {@link Event} API);\n * `\"change\"` and `\"binding\"` are the inherited {@link AbstractInput}\n * value-change events dispatched through the listener bag.\n *\n * @param event - The event name.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"action\", listener: Event.Listener): this;\n on(event: \"keydown\", listener: (e: KeyboardEvent) => Event.ListenerResult): this;\n on(event: \"change\", listener: (value: string) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: \"action\" | \"keydown\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.addListener(this, \"input\", listener as Event.Listener);\n\n return this;\n }\n\n if (event === \"keydown\") {\n Event.addListener(this, \"keydown\", listener as Event.Listener);\n\n return this;\n }\n\n return super.on(event as \"change\", listener as (value: string) => void);\n }\n\n /**\n * Removes a previously registered listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: \"action\" | \"keydown\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.removeListener(this, \"input\", listener as Event.Listener);\n\n return this;\n }\n\n if (event === \"keydown\") {\n Event.removeListener(this, \"keydown\", listener as Event.Listener);\n\n return this;\n }\n\n return super.off(event, listener);\n }\n\n /**\n * Sets the HTML `type` attribute on the underlying input element.\n *\n * Typically called once at construction time by subclasses (e.g.\n * `PasswordField` sets `\"password\"`, `PickerInput` sets `\"text\"`). Most\n * consumers should not need this directly.\n *\n * @param value - The input type (e.g. \"text\", \"password\").\n *\n * @returns This component, for method chaining.\n */\n setType(value: string): this {\n this._options.type = value;\n this.setElementAttribute(\"type\", value);\n\n return this;\n }\n\n /**\n * Sets the component's name — see\n * [`Component.setName`](/api/core/classes/Component#setname) for the shared\n * intrinsic-name semantics — and, because this is a form control, mirrors it\n * to the underlying element's HTML `name` attribute (used for form\n * submission and radio grouping). Passing `null` clears both the stored name\n * and the attribute. The intrinsic name is inherited (no separate `name`\n * state); this override only adds the DOM reflection.\n *\n * @param name - The name, or `null` to clear it.\n *\n * @returns This component, for method chaining.\n */\n setName(name: string | null): this {\n super.setName(name);\n\n if (name == null) {\n this.removeElementAttribute(\"name\");\n } else {\n this.setElementAttribute(\"name\", name);\n }\n\n return this;\n }\n\n /**\n * Removes the HTML `name` attribute from the underlying input.\n *\n * @returns This component, for method chaining.\n */\n clearName(): this {\n if (this._options.name === undefined) {\n return this;\n }\n\n this._options.name = undefined;\n this.removeElementAttribute(\"name\");\n\n return this;\n }\n\n /**\n * Returns the cached HTML `inputmode` attribute value, or null when unset.\n *\n * @returns The inputmode string, or null.\n */\n getInputMode(): string | null {\n return this._options.inputMode ?? null;\n }\n\n /**\n * Sets the HTML `inputmode` attribute on the underlying input. Typical\n * values are `\"none\"` (suppress on-screen keyboards), `\"text\"`,\n * `\"numeric\"`, `\"decimal\"`, `\"tel\"`, `\"email\"`, `\"url\"`, `\"search\"`.\n *\n * @param value - A valid `inputmode` value.\n *\n * @returns This component, for method chaining.\n */\n setInputMode(value: string): this {\n if (this._options.inputMode === value) {\n return this;\n }\n\n this._options.inputMode = value;\n\n // Behavioral HTML attribute the browser interprets natively. Routed\n // via `setElementAttribute` rather than `setDataAttribute` so the\n // attribute renders as `inputmode=\"...\"` (not `data-inputmode=\"...\"`).\n // The value lives on `_options.inputMode`; `init()` replays it from\n // there once the element exists.\n this.setElementAttribute(\"inputmode\", value);\n\n return this;\n }\n\n /**\n * Removes the HTML `inputmode` attribute from the underlying input.\n *\n * @returns This component, for method chaining.\n */\n clearInputMode(): this {\n if (this._options.inputMode === undefined) {\n return this;\n }\n\n this._options.inputMode = undefined;\n\n this.removeElementAttribute(\"inputmode\");\n\n return this;\n }\n\n /**\n * Returns the cached HTML `autocomplete` attribute value, or null when unset.\n *\n * @returns The autocomplete string, or null.\n */\n getAutoComplete(): string | null {\n return this._options.autoComplete ?? null;\n }\n\n /**\n * Sets the HTML `autocomplete` attribute on the underlying input. Common\n * values are `\"on\"`, `\"off\"`, `\"email\"`, `\"current-password\"`, etc.\n *\n * @param value - A valid `autocomplete` token.\n *\n * @returns This component, for method chaining.\n */\n setAutoComplete(value: string): this {\n if (this._options.autoComplete === value) {\n return this;\n }\n\n this._options.autoComplete = value;\n\n this.setElementAttribute(\"autocomplete\", value);\n\n return this;\n }\n\n /**\n * Removes the HTML `autocomplete` attribute from the underlying input.\n *\n * @returns This component, for method chaining.\n */\n clearAutoComplete(): this {\n if (this._options.autoComplete === undefined) {\n return this;\n }\n\n this._options.autoComplete = undefined;\n\n this.removeElementAttribute(\"autocomplete\");\n\n return this;\n }\n\n /**\n * Returns the offset from the top of the text input to its inner-text baseline.\n *\n * @returns The baseline offset in pixels.\n *\n * @remarks Adds the component's top border and CSS padding-top to the\n * unified content-relative baseline ([`Util.measureTextBaseline`](/api/core/namespaces/Util/functions/measureTextBaseline)).\n * `insets` is layout-side metadata used only\n * when sizing children; for a leaf input it does not visually push the\n * rendered element down, so it is excluded from the baseline. `padding` is\n * applied as real CSS padding (with `box-sizing: border-box`) and shifts\n * the inner text down. Bare text controls without inner text (e.g.\n * [`Checkbox`](/api/component/input/classes/Checkbox), the inner radio of\n * [`RadioButton`](/api/component/input/classes/RadioButton)) inherit the\n * default `null` baseline from [`Component`](/api/core/classes/Component)\n * and are treated as graphical elements by horizontal layouts.\n */\n getBaseline(): number | null {\n return this.wrapInnerBaseline(Util.measureTextBaseline());\n }\n\n /**\n * Returns the current CSS text-align value.\n *\n * @returns The CSS text-align string, or null if not set.\n */\n getTextAlign(): string | null {\n return this._options.textAlign ?? null;\n }\n\n /**\n * Sets the CSS text-align and updates the component's CSS rule.\n *\n * @param align - A CSS text-align value (e.g. \"left\", \"center\", \"right\"),\n * or null to clear the rule.\n *\n * @returns This component, for method chaining.\n */\n setTextAlign(align: string | null): this {\n this._options.textAlign = align;\n\n this.setElementCSSRule(\"textAlign\", align);\n\n return this;\n }\n\n /**\n * Clears the CSS text-align value, removing the rule.\n *\n * @returns This component, for method chaining.\n */\n clearTextAlign(): this {\n return this.setTextAlign(null);\n }\n\n /**\n * Returns the current text value.\n *\n * @returns The current text string.\n */\n getText(): string {\n return this._options.text ?? \"\";\n }\n\n /**\n * Sets the text value and updates the DOM element's value property.\n *\n * @param text - The new text value.\n *\n * @returns This component, for method chaining.\n */\n setText(text: string): this {\n this._options.text = text || \"\";\n\n let element = this.getElement();\n if (!element) {\n return this;\n }\n\n DOM.sink.setValue(element, this._options.text);\n\n return this;\n }\n\n /**\n * Returns the current value (alias for {@link getText}, satisfies\n * {@link AbstractInput}'s [`Bindable`](/api/core/interfaces/Bindable) contract).\n *\n * @returns The current text string.\n */\n getValue(): string {\n return this.getText();\n }\n\n /**\n * Sets the current value (alias for {@link setText}, satisfies\n * {@link AbstractInput}'s [`Bindable`](/api/core/interfaces/Bindable) contract).\n *\n * @param value - The new text value.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: string): this {\n return this.setText(value);\n }\n\n /**\n * Returns the placeholder text shown when the input is empty, or null if none is set.\n *\n * @returns The placeholder string, or null.\n */\n getPlaceholder(): string | null {\n return this._options.placeholder ?? null;\n }\n\n /**\n * Sets the HTML `placeholder` attribute on the underlying input.\n *\n * @param value - The placeholder text.\n *\n * @returns This component, for method chaining.\n */\n setPlaceholder(value: string): this {\n this._options.placeholder = value;\n this.setElementAttribute(\"placeholder\", value);\n\n return this;\n }\n\n /**\n * Removes the HTML `placeholder` attribute from the underlying input.\n *\n * @returns This component, for method chaining.\n */\n clearPlaceholder(): this {\n if (this._options.placeholder === undefined) {\n return this;\n }\n\n this._options.placeholder = undefined;\n this.removeElementAttribute(\"placeholder\");\n\n return this;\n }\n\n /**\n * Returns the configured maximum text length, or null if unset.\n *\n * @returns The maxlength value, or null.\n */\n getMaxLength(): number | null {\n return this._options.maxLength ?? null;\n }\n\n /**\n * Sets the HTML `maxlength` attribute on the underlying input.\n *\n * @param value - The maximum number of characters allowed.\n *\n * @returns This component, for method chaining.\n */\n setMaxLength(value: number): this {\n this._options.maxLength = value;\n this.setElementAttribute(\"maxlength\", String(value));\n\n return this;\n }\n\n /**\n * Removes the HTML `maxlength` attribute from the underlying input.\n *\n * @returns This component, for method chaining.\n */\n clearMaxLength(): this {\n if (this._options.maxLength === undefined) {\n return this;\n }\n\n this._options.maxLength = undefined;\n this.removeElementAttribute(\"maxlength\");\n\n return this;\n }\n\n /**\n * Selects a range of text in the input; defaults to selecting all if start/end are omitted.\n *\n * @param start - Optional. The start index of the selection. Defaults to 0.\n * @param end - Optional. The end index of the selection. Defaults to the text length + 1.\n *\n * @returns This component, for method chaining.\n */\n select(start?: number, end?: number): this {\n let element = this.getElement();\n if (!element) {\n return this;\n }\n\n if (!start || start < 0) {\n start = 0;\n }\n\n const text = this._options.text ?? \"\";\n if (!end || end > text.length) {\n end = text.length + 1;\n }\n\n DOM.sink.setSelectionRange(element, start, end);\n\n return this;\n }\n\n /**\n * Reflects the enabled flag by writing the native `disabled` attribute.\n * Routes through {@link setDisabledAttribute} so the existing\n * `_disabledAttribute` cache stays the single source of truth for the\n * native attribute; the cache replays at render time when the element\n * doesn't yet exist.\n */\n protected applyEnabled(value: boolean): void {\n this.setDisabledAttribute(!value);\n }\n\n /**\n * Reflects the read-only flag by writing the native `readonly`\n * attribute. The cached `_options.readOnly` set by\n * {@link AbstractInput.setReadOnly} drives `init()`'s replay path\n * when the element doesn't yet exist.\n */\n protected applyReadOnly(value: boolean): void {\n if (value) {\n this.setElementAttribute(\"readonly\", \"\");\n } else {\n this.removeElementAttribute(\"readonly\");\n }\n }\n\n /**\n * Returns the DOM element handle.\n *\n * @param createIfMissing - Optional. When true, renders the element if it does not yet exist.\n *\n * @returns The component's element handle.\n */\n getElement(createIfMissing: boolean = false): Handle | undefined {\n return super.getElement(createIfMissing);\n }\n\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement()!;\n\n if (this._options.type !== undefined) {\n DOM.sink.apply(el, { setAttr: { type: this._options.type } });\n }\n\n if (this._options.name != null) {\n DOM.sink.apply(el, { setAttr: { name: this._options.name } });\n }\n\n if (this._options.placeholder !== undefined) {\n DOM.sink.apply(el, { setAttr: { placeholder: this._options.placeholder } });\n }\n\n if (this._options.readOnly) {\n DOM.sink.apply(el, { setAttr: { readonly: \"\" } });\n }\n\n if (this._options.maxLength !== undefined) {\n DOM.sink.apply(el, { setAttr: { maxlength: String(this._options.maxLength) } });\n }\n\n if (this._options.inputMode !== undefined) {\n DOM.sink.apply(el, { setAttr: { inputmode: this._options.inputMode } });\n }\n\n if (this._options.autoComplete !== undefined) {\n DOM.sink.apply(el, { setAttr: { autocomplete: this._options.autoComplete } });\n }\n\n return this;\n }\n\n /**\n * Renders the input element and sets its initial value.\n *\n * @returns The created input element handle.\n */\n protected render(): Handle {\n let element = super.render();\n\n DOM.sink.setValue(element, this._options.text ?? \"\");\n\n return element;\n }\n}\n\nconst TextInputCallable = callable(TextInput);\ntype TextInputCallable<TOptions extends TextInputOptions = TextInputOptions> = TextInput<TOptions>;\nexport {\n TextInput as _TextInput,\n TextInputCallable as TextInput\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { TextInput, TextInputOptions } from \"~/component/input/TextInput.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * `cursor: \"text\"` matches the caret hover on the field root so the inner\n * `<input>` doesn't switch to the default arrow on its own surface.\n *\n * `border: \"none\"` and `outline: \"none\"` suppress the inherited TextInput\n * border + the browser-default focus ring; the outer\n * {@link AbstractPickerField} root carries the visible chrome (and its\n * `:focus-within` rule shows the focus indicator) so the two don't draw\n * over each other.\n */\nconst _defaultPickerInputOptions: Partial<TextInputOptions> = {\n cursor: \"text\",\n border: \"none\",\n outline: \"none\",\n};\n\n/**\n * Internal `<input>` subclass shared by every {@link AbstractPickerField}\n * concrete subclass (DateField / TimeField / DateTimeField). Inherits the base\n * `TextInput` on-input sync, which pulls the live DOM value into the cached\n * text on every keystroke so callers can read it through `getText()` instead of\n * touching `element.value` directly.\n *\n * @category Components\n */\nclass PickerInput extends TextInput<TextInputOptions> {\n\n constructor() {\n super(undefined, _defaultPickerInputOptions);\n }\n}\n\nconst PickerInputCallable = callable(PickerInput);\ntype PickerInputCallable = PickerInput;\nexport {\n PickerInput as _PickerInput,\n PickerInputCallable as PickerInput,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Button } from \"~/component/button/Button.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Internal `<button>` Component used by every {@link AbstractPickerField}\n * concrete subclass (DateField / TimeField / DateTimeField) as the\n * glyph-bearing trigger to the right of the input.\n *\n * Extends `Button` with `chromeless: true` (suppresses Button's border /\n * shadow / gradient defaults and the UA `<button>` background). The\n * per-field glyph (calendar / clock / calendar) is set after construction\n * via `setGlyph` — Button's content-row Fit layout centres it within the\n * inner rect automatically.\n *\n * @category Components\n */\nclass PickerButton extends Button {\n\n constructor() {\n super({\n chromeless: true,\n insets: new Insets(0, 4, 0, 4),\n });\n }\n}\n\nconst PickerButtonCallable = callable(PickerButton);\ntype PickerButtonCallable = PickerButton;\nexport {\n PickerButton as _PickerButton,\n PickerButtonCallable as PickerButton,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { StyleRule } from \"~/core/StyleTarget.js\";\n\n/**\n * Shared style body for the `:focus-within::after` focus ring. A pseudo-element\n * drawn at `inset: 0` carries the 2px focus-indicator border so the ring sits\n * *inside* the composite's padding box and isn't clipped by an ancestor's\n * `overflow: hidden` (the framework's default). `z-index: 1` lifts it above the\n * absolutely-positioned inner input so the ring is never painted over.\n */\nconst FOCUS_WITHIN_RING_STYLES: Record<string, string> = {\n content: \"''\",\n position: \"absolute\",\n inset: \"0\",\n border: \"2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))\",\n borderRadius: \"inherit\",\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n zIndex: \"1\",\n};\n\n/**\n * Registers the shared `:focus-within::after` focus-ring overlay rule for the\n * given base selector(s). Used by the composite inputs (the picker fields,\n * {@link AutoCompleteField}, `NumberSpinner`) so the focus indicator paints on\n * the outer composite chrome rather than the border-stripped inner input. The\n * `:focus-within::after` pseudo-element suffix is owned here (appended to each\n * comma-separated selector) so it lives in exactly one place.\n *\n * @param baseSelector - One or more comma-separated class selectors (e.g.\n * `\".NumberSpinner\"` or `\".DateField, .TimeField, .DateTimeField\"`), without\n * the pseudo-element suffix.\n */\nexport function registerFocusWithinRing(baseSelector: string): void {\n const selector = baseSelector\n .split(\",\")\n .map(part => part.trim() + \":focus-within::after\")\n .join(\", \");\n\n new StyleRule({\n scope: \"selector\",\n name: selector,\n styles: FOCUS_WITHIN_RING_STYLES,\n });\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { AnimatedDropdown } from \"~/core/AnimatedDropdown.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { PickerInput } from \"~/component/input/PickerInput.js\";\nimport { PickerButton } from \"~/component/input/PickerButton.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { registerFocusWithinRing } from \"~/component/input/focusRing.js\";\nimport { Util } from \"~/core/Util.js\";\n\n// Focus ring highlighting the picker root whenever the inner PickerInput is\n// focused. The three concrete selectors share the one helper-registered overlay\n// rule (the helper appends the focus pseudo-element to each).\nregisterFocusWithinRing(\".DateField, .TimeField, .DateTimeField\");\n\n// Width of the picker glyph button in pixels. Matches the prior `display: flex`\n// + 24px caret column the framework used before the per-field doLayout\n// override; sized to the calendar/clock glyph's intrinsic 16px box plus 4px\n// padding on each side so the icon centres without crowding the input edge.\nconst PICKER_BUTTON_WIDTH_PX = 24;\n\n/**\n * Construction-time options for {@link AbstractPickerField}. The `value`\n * field is supplied by each concrete subclass's options interface\n * (DateFieldOptions / TimeFieldOptions / DateTimeFieldOptions) so its type\n * matches the subclass's `TValue`.\n *\n * @category Components\n */\nexport interface AbstractPickerFieldOptions extends AbstractInputOptions {\n /** When false, the dropdown opens/closes instantly. Default: true. */\n dropdownAnimated?: boolean;\n}\n\n/**\n * User-overridable visual defaults shared by every concrete picker field\n * (DateField / TimeField / DateTimeField); merged in the base constructor. The\n * three fields' defaults were byte-identical, so they live here once.\n */\nconst _defaultPickerFieldOptions: Partial<AbstractPickerFieldOptions> = {\n cursor: \"text\",\n padding: new Insets(3, 3, 3, 3),\n backgroundColor: \"var(--ts-ui-input-bg, rgb(255, 255, 255))\",\n foregroundColor: \"var(--ts-ui-text-color, black)\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n};\n\n/**\n * Abstract base for the three picker fields ({@link DateField},\n * {@link TimeField}, {@link DateTimeField}). Owns the shared chrome — a\n * [`PickerInput`](/api/component/input/classes/PickerInput) on the left, a\n * [`PickerButton`](/api/component/input/classes/PickerButton) on the right,\n * the 24-px layout, the dropdown lifecycle (open/close/animated), the\n * invalid-border swap, the viewport-pointerdown dismissal, and the\n * ArrowDown/Escape keyboard contract. Subclasses provide only\n * format/parse, dropdown construction + anchoring, the dropdown's\n * selection callback, the preferred width (160 / 140 / 200), and the\n * default border.\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated;\n * concrete subclasses do the callable wrapping themselves.\n *\n * @category Components\n */\nabstract class AbstractPickerField<\n TValue,\n TDropdown extends AnimatedDropdown & { showAt(anchorEl: Handle, value: TValue | null): unknown },\n TOptions extends AbstractPickerFieldOptions = AbstractPickerFieldOptions\n>\n extends AbstractInput<TValue | null, TOptions>\n{\n protected _input: PickerInput;\n protected _button: PickerButton;\n protected _dropdown: TDropdown | null = null;\n protected _value: TValue | null = null;\n protected _invalid: boolean = false;\n // Hoisted here so it is declared once; only TimeField / DateTimeField\n // read it (from their constructor body). Harmless-and-unused on DateField.\n protected _showSeconds: boolean = false;\n\n /**\n * @param options - Caller-supplied options bag.\n */\n constructor(options?: TOptions) {\n super(options, _defaultPickerFieldOptions as Partial<TOptions>);\n\n this._input = new PickerInput();\n this._input.setType(\"text\");\n this._input.setInputMode(\"none\");\n this._input.setAutoComplete(\"off\");\n this._input.setPadding(new Insets(0, 3, 0, 3));\n\n // Subclasses add the per-field glyph (calendar / clock / calendar) to\n // `_button` after `super()` returns; `PickerButton.doLayout` then\n // centers it within the button's inner rect.\n this._button = new PickerButton();\n\n this.addComponent(this._input);\n this.addComponent(this._button);\n\n this.updateHeight();\n this.subscribeTheme(() => this.updateHeight());\n\n Event.addListener(this._input, \"input\", () => this.onInput());\n Event.addListener(this._input, \"blur\", () => this.onBlur());\n Event.addListener(this._input, \"keydown\", (e: KeyboardEvent) => this.onKeyDown(e));\n\n // Route button events through the named-method surface — never raw\n // `Event.addListener(button, …)` per ARCHITECTURE.md's \"component\n // owns its event surface\" rule.\n this._button.on(\"action\", () => this.onButtonClick());\n // Suppress focus loss when clicking the button (it would blur the input).\n this._button.addPointerDownListener((e: PointerEvent) => this.onButtonPointerDown(e));\n\n // Late-built dispatch: `applyOptions` cached enabled / readOnly onto\n // `_options` during `super()` before `_input` existed. Dispatch them now\n // that `_input` is built. The per-subclass `value` re-dispatch stays in\n // each subclass because it reads the subclass-typed `_options.value`.\n if (this._options.enabled !== undefined) this.applyEnabled(this._options.enabled);\n if (this._options.readOnly !== undefined) this.applyReadOnly(this._options.readOnly);\n }\n\n /**\n * Subclass hook: format a non-null value for display in the text input.\n *\n * @param value - The value to format.\n * @returns The display string.\n */\n protected abstract formatValue(value: TValue): string;\n\n /**\n * Subclass hook: parse the typed text into a value. Return `null` on\n * parse failure to drive the invalid-border state.\n *\n * @param raw - The raw text typed into the input.\n * @returns The parsed value, or `null` on parse failure.\n */\n protected abstract parseRaw(raw: string): TValue | null;\n\n /**\n * Subclass hook: lazily construct the picker dropdown. Runs once per\n * field instance on first open.\n *\n * @returns The constructed dropdown.\n */\n protected abstract createDropdown(): TDropdown;\n\n /**\n * Subclass hook: called when the user selects a value from the dropdown.\n * Implementations typically call `this.setValue(value)` and\n * `this.closeDropdown()`.\n *\n * @param value - The value chosen in the dropdown.\n */\n protected abstract onDropdownSelected(value: TValue): void;\n\n /**\n * Subclass hook: returns the field's preferred width in pixels\n * (DateField 160, TimeField 140, DateTimeField 200).\n *\n * @returns The preferred width in pixels.\n */\n protected abstract getPreferredWidth(): number;\n\n /**\n * Returns the default border restored when the invalid-border state clears\n * — the shared `--ts-ui-input-border` token, identical across all three\n * picker fields. The value is passed straight to {@link Component.setBorder}.\n *\n * @returns The default border shorthand string.\n */\n protected getDefaultBorder(): string {\n return _defaultPickerFieldOptions.border as string;\n }\n\n /**\n * Applies an {@link AbstractPickerFieldOptions} bag. The inherited\n * `enabled` / `readOnly` flags are cached on `_options` by\n * {@link AbstractInput} and dispatched from the concrete subclass's\n * constructor tail once `_input` exists.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.dropdownAnimated !== undefined) {\n this.setDropdownAnimated(options.dropdownAnimated);\n }\n\n return this;\n }\n\n /**\n * Lays out the input flush left and the button flush right at the\n * fixed 24-px column width.\n */\n doLayout(): this {\n super.doLayout();\n\n const w = this.getWidth();\n const h = this.getHeight();\n\n this._input.setX(0);\n this._input.setY(0);\n this._input.setWidth(Math.max(0, w - PICKER_BUTTON_WIDTH_PX));\n this._input.setHeight(h);\n\n this._button.setX(w - PICKER_BUTTON_WIDTH_PX);\n this._button.setY(0);\n this._button.setWidth(PICKER_BUTTON_WIDTH_PX);\n this._button.setHeight(h);\n\n // The button was already laid out by `super.doLayout()` against its\n // construction-time preferred size; the manual setWidth/setHeight\n // calls above don't auto-relayout, so the inner glyph would stay\n // anchored to the smaller pre-resize inner rect. Re-fire the button's\n // own layout so the Fit-centred content row tracks the new height.\n this._button.doLayout();\n\n return this;\n }\n\n /**\n * Recalculates preferred and maximum height from the unified line box plus\n * this field's own chrome; preferred width comes from the subclass-supplied\n * {@link getPreferredWidth}.\n *\n * @remarks Box height is `Util.lineHeightPx()` plus the field root's own\n * vertical insets, padding, and border — the same sum `wrapInnerBaseline`\n * re-adds — so the picker shares its row height and baseline with a sibling\n * `TextField`. `doLayout` stretches the inner input to this full height, so\n * the root's chrome (not the inner input's) governs the box.\n */\n protected updateHeight(): void {\n const h = Util.singleLineBoxHeight(this.getInsets(), this.getPadding(), this.getBorderSize());\n\n this.setPreferredSize({ width: this.getPreferredWidth(), height: h });\n this.setMaxSize({ width: Number.MAX_SAFE_INTEGER, height: h });\n // Min-height pinned to the single-line box so the field can't be\n // vertically compressed below one line; min-width 0 keeps it\n // horizontally flexible.\n this.setMinSize({ width: 0, height: h });\n }\n\n /**\n * Sets the field value from a parsed value and updates the DOM element.\n *\n * @param value - The value to display, or null to clear the field.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: TValue | null): this {\n this._value = value;\n // Optional chain because the cascade-time `applyOptions` may dispatch\n // this from inside `super()` before `_input` is constructed; the\n // concrete subclass's constructor tail re-runs the assignment once\n // `_input` exists.\n this._input?.setText(value ? this.formatValue(value) : \"\");\n\n return this;\n }\n\n /**\n * Returns the currently selected value, or null if the field is empty.\n *\n * @returns The selected value, or null.\n */\n getValue(): TValue | null {\n return this._value;\n }\n\n /**\n * Returns the offset from the top of the picker field to its inner-text\n * baseline.\n *\n * @returns The baseline offset in pixels.\n */\n getBaseline(): number | null {\n return this.wrapInnerBaseline(this._input.getBaseline());\n }\n\n /**\n * Enables or disables the fade animation on the dropdown.\n *\n * @param value - true to fade, false for instant open/close.\n *\n * @returns This component, for method chaining.\n */\n setDropdownAnimated(value: boolean): this {\n this._options.dropdownAnimated = value;\n\n if (this._dropdown) {\n this._dropdown.setAnimated(value);\n }\n\n return this;\n }\n\n /**\n * Returns whether the dropdown fade is enabled.\n *\n * @returns true when the dropdown fades; false when it opens/closes instantly.\n */\n isDropdownAnimated(): boolean {\n return this._options.dropdownAnimated ?? true;\n }\n\n /**\n * Reflects the enabled flag by forwarding to the inner input's native\n * `disabled` attribute write — the same path the per-field\n * `applyOptions` blocks used before this base existed.\n */\n protected applyEnabled(value: boolean): void {\n this._input.setEnabled(value);\n }\n\n /**\n * Reflects the read-only flag by forwarding to the inner input's native\n * `readonly` attribute write.\n */\n protected applyReadOnly(value: boolean): void {\n this._input.setReadOnly(value);\n }\n\n /**\n * Toggles the dropdown when the glyph button is clicked. Re-focuses the\n * input first so the caret stays in the field while the picker is open.\n */\n protected onButtonClick(): void {\n if (this._dropdown?.isOpen()) {\n this.closeDropdown();\n } else {\n this._input.focus();\n this.openDropdown();\n }\n }\n\n /**\n * Suppresses focus loss on the input when the button is pointed at; the\n * subsequent `click` handler does the open/close work.\n *\n * @param e - The pointerdown event.\n */\n protected onButtonPointerDown(e: PointerEvent): void {\n e.preventDefault();\n }\n\n /**\n * Syncs the internal value from the typed text on every input event and\n * toggles the invalid-border state based on whether the typed text\n * parses. Notifies change/binding listeners with the new value.\n */\n protected onInput(): void {\n const raw = this._input.getText();\n\n if (!raw) {\n this._value = null;\n this.setInvalid(false);\n this.notifyChange(null);\n\n return;\n }\n\n const parsed = this.parseRaw(raw);\n if (parsed !== null) {\n this._value = parsed;\n this.setInvalid(false);\n this.notifyChange(parsed);\n } else {\n this.setInvalid(true);\n }\n }\n\n /**\n * Clears non-empty unparseable text when the input loses focus, so the\n * field doesn't carry an invalid string across interactions.\n */\n protected onBlur(): void {\n if (!this._invalid) {\n return;\n }\n\n this._input.setText(\"\");\n this._value = null;\n this.setInvalid(false);\n }\n\n /**\n * Toggles the red validation-error border on the field root.\n *\n * @param invalid - True to show the red border, false to restore the default.\n */\n protected setInvalid(invalid: boolean): void {\n if (this._invalid === invalid) {\n return;\n }\n this._invalid = invalid;\n\n if (invalid) {\n this.setBorder({ border: \"1px solid var(--ts-ui-validation-error-border)\" });\n } else {\n this.setBorder(this.getDefaultBorder());\n }\n }\n\n /**\n * Keyboard shortcuts: ArrowDown opens the dropdown; Escape closes it.\n * While the dropdown is open the event is first offered to\n * {@link AnimatedDropdown.handleKey} so the dropdown can consume\n * navigation keys (arrows for day grid / year scroller, PageUp/Down,\n * Home/End, Enter / Space, and digit-keys for the year-scroller's\n * type-ahead). Keys the dropdown does not consume fall through to the\n * host input's own contract.\n *\n * @param e - The keyboard event.\n */\n protected onKeyDown(e: KeyboardEvent): void {\n if (this._dropdown && this._dropdown.isOpen()) {\n if (this._dropdown.handleKey(e)) {\n e.preventDefault();\n\n return;\n }\n }\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n this.openDropdown();\n } else if (e.key === \"Escape\") {\n this.closeDropdown();\n }\n }\n\n /**\n * Returns or lazily creates the picker dropdown instance.\n *\n * @returns The owned dropdown instance.\n */\n protected ensureDropdown(): TDropdown {\n if (!this._dropdown) {\n this._dropdown = this.createDropdown();\n const animated = this._options.dropdownAnimated;\n if (animated !== undefined) {\n this._dropdown.setAnimated(animated);\n }\n }\n\n return this._dropdown;\n }\n\n /**\n * Opens the dropdown anchored to the input. Every concrete dropdown\n * declares `showAt(anchorEl, value: TValue | null)` (enforced by the\n * `TDropdown` bound), so the value-typed call lives here directly.\n */\n protected openDropdown(): void {\n const dropdown = this.ensureDropdown();\n if (dropdown.isOpen()) {\n return;\n }\n\n // The manager closes the dropdown on an outside click via its\n // \"click-outside\" mode; route that through the field's own\n // closeDropdown and exclude the field root (the trigger) so the\n // toggle click doesn't immediately re-close it.\n dropdown.setCloseHandler(() => this.closeDropdown());\n dropdown.setAnchorElement(this.getElement(true) ?? null);\n\n dropdown.showAt(this._input.getElement(true)!, this._value);\n }\n\n /**\n * Closes the dropdown if open.\n */\n protected closeDropdown(): void {\n if (this._dropdown && this._dropdown.isOpen()) {\n this._dropdown.hideAnimated();\n }\n }\n}\n\nexport { AbstractPickerField };\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { TextInput, TextInputOptions } from \"~/component/input/TextInput.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link TextField}.\n *\n * @category Components\n */\nexport interface TextFieldOptions extends TextInputOptions {\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * The cascade in `Component`'s constructor dispatches each setter once with\n * the final value, so any field the caller supplied wins.\n */\nconst _defaultTextFieldOptions: Partial<TextFieldOptions> = {\n cursor: \"text\",\n padding: new Insets(3, 3, 3, 3),\n backgroundColor: \"var(--ts-ui-input-bg, rgb(255, 255, 255))\",\n foregroundColor: \"var(--ts-ui-text-color, black)\",\n};\n\n/**\n * A single-line text field component backed by an `<input type=\"text\">` element.\n *\n * Keeps internal text state in sync with the DOM on every input event.\n *\n * @category Components\n */\nclass TextField extends TextInput<TextFieldOptions> {\n\n constructor(options?: TextFieldOptions) {\n super(options, _defaultTextFieldOptions);\n\n this.updateHeight();\n this.subscribeTheme(() => this.updateHeight());\n\n this.setType(\"text\");\n }\n\n /**\n * Recalculates preferred and maximum height from the unified line box plus\n * this field's own chrome.\n *\n * @remarks Box height is `Util.lineHeightPx()` plus the field's own vertical\n * insets, padding, and border — the same sum `wrapInnerBaseline` re-adds —\n * so the rendered input and its baseline match a sibling `Text`/`ComboBox`.\n * Called at construction time and after each theme change so that font-size\n * adjustments propagate to the layout hint automatically.\n */\n private updateHeight(): void {\n const h = Util.singleLineBoxHeight(this.getInsets(), this.getPadding(), this.getBorderSize());\n\n this.setPreferredSize({ width: 200, height: h });\n this.setMaxSize({ width: Number.MAX_SAFE_INTEGER, height: h });\n // Min-height pinned to the single-line box so the field can't be\n // vertically compressed below one line; min-width 0 keeps it\n // horizontally flexible.\n this.setMinSize({ width: 0, height: h });\n }\n\n}\n\nconst TextFieldCallable = callable(TextField);\ntype TextFieldCallable = TextField;\nexport {\n TextField as _TextField,\n TextFieldCallable as TextField\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Panel } from \"~/core/Panel.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { VBox } from \"~/layout/VBox.js\";\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\n\n/** Pixel height of each clickable cell row. Mirrors `TimePickerDropdown`'s historical layout. */\nconst CELL_HEIGHT: number = 22;\n\n/** Pixel height of the column header row. Mirrors `TimePickerDropdown`'s historical layout. */\nconst HEADER_HEIGHT: number = 18;\n\n// Static typography, hover effect, and disabled-state shading defined once via\n// class rules. Layout (column widths, cell stacking, scrolling) is driven by\n// the framework HBox / VBox managers and Panel.autoScroll — no display:flex/grid here.\n(() => {\n new StyleRule({\n scope: \"class\",\n name: \"PickerColumnHeader\",\n styles: {\n opacity: \"0.7\",\n },\n });\n\n // Visual properties only. `cursor` is set per-instance via `setCursor`\n // because Component's per-element `#id { cursor: … }` CSS rule (emitted\n // from `applyStyle` using the cached default `\"default\"`) wins on\n // specificity over any class-level cursor declaration.\n new StyleRule({\n scope: \"class\",\n name: \"PickerCell\",\n styles: {\n borderRadius: \"3px\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".PickerCell:hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-autocomplete-item-hover-bg, rgba(30, 100, 200, 0.08))\",\n },\n });\n\n // Disabled cells: no hover effect, dim foreground, optional background\n // shading from the theme token. The `:hover` selector above is overridden\n // because the more specific `.PickerCell.disabled` selector wins for\n // properties declared here. Cursor is per-instance — see\n // `PickerCell.setDisabled`.\n new StyleRule({\n scope: \"selector\",\n name: \".PickerCell.disabled\",\n styles: {\n pointerEvents: \"none\",\n color: \"var(--ts-ui-autocomplete-item-disabled-color, rgb(170, 170, 170))\",\n backgroundColor: \"var(--ts-ui-picker-cell-disabled-bg, transparent)\",\n },\n });\n})();\n\n/** Column header label (\"Hour\" / \"Min\" / \"Sec\" / …). Centred within its row. */\nclass PickerColumnHeader extends Text {\n /**\n * @param text - The header text.\n */\n constructor(text: string) {\n super(text, { textAlign: \"center\", fontSize: 12 });\n }\n}\n\n/**\n * Scrollable list of picker cells. A {@link Panel} with `autoScroll: 'y'` and a\n * stretching {@link VBox} so cells render at the full column width — giving the\n * mouse-hover region the full row, not just the digits' bounding box.\n *\n * @category Components\n */\nclass PickerCellList extends Panel {\n\n /**\n * Constructs an empty scrollable cell list. Cells are added via\n * {@link PickerColumn.addCell}.\n */\n constructor() {\n super({\n layoutManager: new VBox({ spacing: 0, stretching: true }),\n autoScroll: \"y\",\n insets: new Insets(0, 0, 0, 0),\n });\n }\n\n /**\n * Reports **no vertical content minimum**: this list is an `autoScroll: \"y\"`\n * surface, so it may be allocated less height than its stacked cells need and\n * scroll the overflow rather than demand its full content height.\n *\n * Without this override the inherited `Component.getMinSize` sums the\n * cells' minimums — and each {@link PickerCell} (a {@link Text}) reports a\n * one-line height floor — so the list's min height equals its entire content\n * height. The parent {@link PickerColumn}'s `VBox` then floors the weighted\n * list at that min, pinning it to its content size: the list never overflows,\n * the inner scroll never engages, and the fixed-height\n * {@link TimePickerDropdown} panel is inflated past the viewport. The\n * horizontal minimum is left untouched so the column still reserves room for\n * the widest label.\n *\n * @returns The inherited minimum with its height floored to `0`, or `null`\n * when there is no inherited minimum.\n */\n getMinSize(): Size | null {\n const base = super.getMinSize();\n\n if (!base) {\n return base;\n }\n\n return { width: base.width, height: 0 };\n }\n}\n\n/**\n * A single picker cell — text label, hover + selection styling, click + focus\n * guard. The row width is set by the parent's stretching {@link VBox} so the\n * cell's `text-align: center` actually centres across the column.\n *\n * @category Components\n */\nclass PickerCell extends Text {\n\n private _selected: boolean = false;\n private _disabled: boolean = false;\n private readonly _onClick: () => void;\n\n /**\n * @param label - Text shown inside the cell.\n * @param onClick - Called when the cell is clicked. Suppressed while disabled.\n */\n constructor(label: string, onClick: () => void) {\n super(label, {\n textAlign: \"center\",\n preferredSize: { width: 0, height: CELL_HEIGHT },\n });\n\n this._onClick = onClick;\n\n // `lineHeight = CELL_HEIGHT` centres the single line of digits vertically\n // within the row so the hover area looks consistent.\n this.setLineHeight(CELL_HEIGHT);\n // Component's per-instance CSS rule emits the cached cursor at render\n // time, which beats the `.PickerCell { cursor: pointer }` class rule\n // on specificity. The cursor must be set on this instance.\n this.setCursor(\"pointer\");\n\n Event.addListener(this, \"pointerdown\", this.handlePointerDown);\n Event.addListener(this, \"click\", this.handleClick);\n }\n\n /**\n * Suppresses focus loss when the cell is pointed at so the host input's\n * blur-to-commit path doesn't fire mid-click.\n *\n * @param e - The pointerdown event.\n */\n private handlePointerDown(e: PointerEvent): void {\n e.preventDefault();\n }\n\n /**\n * Forwards a click to the constructor-supplied callback. No-op while the\n * cell is disabled.\n */\n private handleClick(): void {\n if (this._disabled) {\n return;\n }\n\n this._onClick();\n }\n\n /**\n * Toggles the selected (highlighted) state.\n *\n * @param selected - True to highlight this cell as the active value.\n * @returns This component, for method chaining.\n */\n setSelected(selected: boolean): this {\n if (this._selected === selected) {\n return this;\n }\n\n this._selected = selected;\n\n if (selected) {\n this.setBackgroundColor(\"var(--ts-ui-autocomplete-item-highlight-bg, rgba(30, 100, 200, 0.18))\");\n this.setFontWeight(\"bold\");\n } else {\n this.clearBackgroundColor();\n this.setFontWeight(\"normal\");\n }\n\n return this;\n }\n\n /**\n * Returns the current selected state.\n *\n * @returns True when this cell is highlighted.\n */\n isSelected(): boolean {\n return this._selected;\n }\n\n /**\n * Toggles the disabled state. Disabled cells render with the\n * `.PickerCell.disabled` rule (dim colour, no pointer cursor, no hover)\n * and ignore clicks. State is cached on `_disabled`; the live DOM class\n * is toggled on first paint and via `classList.toggle` thereafter,\n * matching the cached-state pattern from `AccordionIndicator.setExpanded`.\n *\n * @param disabled - True to disable interaction.\n * @returns This component, for method chaining.\n */\n setDisabled(disabled: boolean): this {\n if (this._disabled === disabled) {\n return this;\n }\n\n this._disabled = disabled;\n // Component's per-instance cursor rule wins over the `.PickerCell.disabled`\n // class rule, so the cursor flip has to be mirrored on the instance.\n this.setCursor(disabled ? \"default\" : \"pointer\");\n\n const element = this.getElement();\n\n if (element) {\n DOM.sink.apply(element, { toggleClass: { disabled: disabled } });\n }\n\n return this;\n }\n\n /**\n * Returns the current disabled state.\n *\n * @returns True when this cell is disabled.\n */\n isDisabled(): boolean {\n return this._disabled;\n }\n\n /**\n * Renders the cell and applies the cached `.disabled` class so the first\n * paint reflects state set before the element was realised.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n if (this._disabled) {\n DOM.sink.apply(element, { addClass: [\"disabled\"] });\n }\n\n return element;\n }\n}\n\n/**\n * A single picker column. Stacks an optional header above the scrollable cell\n * list via a stretching {@link VBox} — no `display: flex` on the column element.\n *\n * @category Components\n */\nclass PickerColumn extends Component {\n\n private _cellList: PickerCellList;\n\n /**\n * @param headerText - Header label, or null to render the column with no header row.\n */\n constructor(headerText: string | null) {\n super();\n this.setLayoutManager(new VBox({ spacing: 2, stretching: true }));\n\n if (headerText !== null) {\n const header = new PickerColumnHeader(headerText);\n header.setPreferredSize({ width: 0, height: HEADER_HEIGHT });\n this.addComponent(header);\n }\n\n this._cellList = new PickerCellList();\n // Weight=1 so the list takes all remaining vertical space after the\n // fixed-height header.\n const listConstraints = new LayoutConstraints();\n listConstraints.weight = 1;\n this.addComponent(this._cellList, listConstraints);\n }\n\n /**\n * Adds a cell to this column's scrollable list.\n *\n * @param cell - The cell to append.\n * @returns This component, for method chaining.\n */\n addCell(cell: PickerCell): this {\n this._cellList.addComponent(cell);\n\n return this;\n }\n\n /**\n * Clears every cell from this column's scrollable list.\n *\n * @returns This component, for method chaining.\n */\n clearCells(): this {\n this._cellList.removeAllComponents();\n\n return this;\n }\n\n /**\n * Returns the inner scrollable list component, for callers that need to\n * reach the underlying DOM (e.g. to measure the column's own scroll state).\n *\n * @returns The inner cell-list panel.\n */\n getCellList(): PickerCellList {\n return this._cellList;\n }\n\n /**\n * Scrolls the inner panel so the first {@link PickerCell} whose\n * {@link PickerCell.isSelected} is `true` lands mid-viewport. Reads and\n * writes the panel's native `scrollTop` directly — the framework's typed\n * scroll setter lives only on the `VirtualScroller`-backed components, and\n * a `Panel`-with-`autoScroll: \"y\"` surface relies on native browser\n * overflow (the same pattern `AbstractSelectableList.scrollIndexIntoView` uses).\n *\n * @returns This component, for method chaining.\n */\n scrollSelectedIntoView(): this {\n const panelEl = this._cellList.getElement();\n\n if (!panelEl) {\n return this;\n }\n\n const children = this._cellList.getComponents();\n let target: PickerCell | null = null;\n\n for (const child of children) {\n if (child instanceof PickerCell && child.isSelected()) {\n target = child;\n break;\n }\n }\n\n if (!target) {\n return this;\n }\n\n const cellEl = target.getElement();\n\n if (!cellEl) {\n return this;\n }\n\n // `offsetTop` is the cell's top edge relative to its offsetParent (the\n // panel). Centring = top minus half the viewport plus half the cell.\n const cellBox = DOM.source.getOffsetSize(cellEl);\n const panelMetrics = DOM.source.getScrollMetrics(panelEl);\n const cellTop = cellBox.offsetTop;\n const cellHeight = cellBox.offsetHeight;\n const viewportH = panelMetrics.clientHeight;\n const desiredTop = cellTop - (viewportH - cellHeight) / 2;\n const maxScrollTop = panelMetrics.scrollHeight - viewportH;\n const clamped = Util.clamp(desiredTop, 0, maxScrollTop);\n\n DOM.sink.apply(panelEl, { scrollTop: clamped });\n\n return this;\n }\n\n /**\n * Re-highlights cells in place: the first {@link PickerCell} whose label\n * equals `value` is selected and every other cell is cleared. Passing\n * `null` clears the whole column. Unlike a rebuild this touches no DOM\n * structure and leaves `scrollTop` untouched, so a click-driven selection\n * change doesn't jump the scroll position. Mirrors the in-place\n * `refreshYearSelection` pattern in `AbstractCalendarDropdown`.\n *\n * @param value - The cell label to select, or null to clear the column.\n * @returns This component, for method chaining.\n */\n setSelectedValue(value: string | null): this {\n for (const child of this._cellList.getComponents()) {\n if (child instanceof PickerCell) {\n child.setSelected(child.getText().valueOf() === value);\n }\n }\n\n return this;\n }\n}\n\nexport {\n PickerCell,\n PickerCellList,\n PickerColumn,\n PickerColumnHeader,\n CELL_HEIGHT as PICKER_CELL_HEIGHT,\n HEADER_HEIGHT as PICKER_HEADER_HEIGHT,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AnimatedDropdown, AnimatedDropdownOptions } from \"~/core/AnimatedDropdown.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { chevron_left } from \"~/glyphs/solid/chevron_left.js\";\nimport { chevron_right } from \"~/glyphs/solid/chevron_right.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { VBox } from \"~/layout/VBox.js\";\nimport { Grid } from \"~/layout/Grid.js\";\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { PickerCell, PickerColumn } from \"~/component/input/PickerColumn.js\";\n\nGlyph.register(chevron_left);\nGlyph.register(chevron_right);\n\n/** Pixel height of the month-name + year row at the top of the panel. */\nconst MONTH_HEIGHT: number = 24;\n\n/** Pixel width of each chevron navigation cell on the header row. */\nconst NAV_BTN_WIDTH: number = 24;\n\n/** Pixel height of the weekday-name row. */\nconst HEADER_HEIGHT: number = 20;\n\n/** Pixel height of each day cell (and each empty leading/trailing cell). */\nconst CELL_HEIGHT: number = 24;\n\n/** Pixel height of the day grid (6 rows × CELL_HEIGHT + 5 inter-row gaps of 2 px). */\nconst DAY_GRID_HEIGHT: number = 6 * CELL_HEIGHT + 5 * 2;\n\n/** Pixel gap between rows in the panel's outer VBox (header, weekday, grid, …). */\nconst ROOT_GAP: number = 4;\n\n/** Pixel size of the chevron Glyph inside a `PickerNavButton`. The 24-px button cell holds the click target; the glyph just paints. */\nconst GLYPH_PX: number = 12;\n\n/**\n * Index of the day-grid (or year-scroller) slot inside `_root`'s children\n * array. Header sits at 0, weekday row at 1; the grid/scroller swap happens\n * at index 2. Subclasses that add extra rows (e.g. a time row) append them\n * after this slot so the swap stays a single insertion/removal.\n */\nconst DAY_GRID_INDEX: number = 2;\n\n/**\n * Default lower bound for the year scroller when no `minDate` is supplied.\n * 120 years back keeps the scroller bounded for \"date of birth\" style fields.\n */\nconst DEFAULT_YEAR_SPAN_BACK: number = 120;\n\n/**\n * Default upper bound for the year scroller when no `maxDate` is supplied.\n * 50 years ahead covers \"due date\" / \"subscription expiry\" use without\n * flooding the scrollable region.\n */\nconst DEFAULT_YEAR_SPAN_FORWARD: number = 50;\n\n/**\n * Idle-timeout for the year-scroller's 4-digit type-ahead buffer. 800 ms is\n * the macOS Finder type-ahead threshold (ComboBox uses the same value), so\n * users who pause briefly mid-typing pick up where they left off rather than\n * the buffer resetting underneath them.\n */\nconst YEAR_TYPE_IDLE_MS: number = 800;\n\n// Static hover / cursor styling shared across every calendar dropdown.\n// Layout (grid, row stacking) is driven by framework Grid / VBox managers —\n// no display:flex/grid on the elements themselves.\n(() => {\n // Visual properties only. `cursor` is set per-instance via `setCursor`\n // because Component's per-element `#id { cursor: … }` CSS rule (emitted\n // from `applyStyle` using the cached default `\"default\"`) wins on\n // specificity over any class-level cursor declaration.\n new StyleRule({\n scope: \"class\",\n name: \"PickerDay\",\n styles: {\n borderRadius: \"3px\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".PickerDay:hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-autocomplete-item-hover-bg, rgba(30, 100, 200, 0.08))\",\n },\n });\n\n // Out-of-range day cells dim and ignore pointer events. Mirrors\n // `.PickerCell.disabled` so the year-scroller and day-grid look identical\n // when the user is at the bound's edge. Cursor is per-instance — see\n // `PickerDay.setDisabled`.\n new StyleRule({\n scope: \"selector\",\n name: \".PickerDay.disabled\",\n styles: {\n pointerEvents: \"none\",\n color: \"var(--ts-ui-autocomplete-item-disabled-color, rgb(170, 170, 170))\",\n backgroundColor: \"var(--ts-ui-picker-cell-disabled-bg, transparent)\",\n },\n });\n\n // Header chevron + month-label-as-button styling — single hover background\n // shared by the chevrons and the label. Cursor is per-instance — see\n // `PickerNavButton` / `PickerMonthLabel`.\n new StyleRule({\n scope: \"class\",\n name: \"PickerNavButton\",\n styles: {\n borderRadius: \"3px\",\n color: \"var(--ts-ui-picker-nav-fg, var(--ts-ui-text-color))\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".PickerNavButton:hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-picker-nav-hover-bg, rgba(30, 100, 200, 0.08))\",\n },\n });\n})();\n\n/** Single weekday-name header (`\"Sun\"`, `\"Mon\"`, …). */\nclass PickerDayHeader extends Text {\n /**\n * @param text - Header label (`\"Sun\"`, `\"Mon\"`, …).\n */\n constructor(text: string) {\n super(text, {\n textAlign: \"center\",\n fontSize: 12,\n preferredSize: { width: 0, height: HEADER_HEIGHT },\n });\n this.setLineHeight(HEADER_HEIGHT);\n }\n}\n\n/**\n * Empty cell shown before the first day of the month (or trailing the last)\n * so the day grid always renders as a full 6-row block.\n */\nclass PickerBlankCell extends Component {\n constructor() {\n super({ preferredSize: { width: 0, height: CELL_HEIGHT } });\n }\n}\n\n/**\n * Header chevron button (←/→). Carries the shared `.PickerNavButton` class\n * so a single CSS rule covers the chevron and the month-label-as-button\n * hover state. Owns a single child Glyph; click + pointerdown listeners\n * are wired internally.\n */\nclass PickerNavButton extends Component {\n /**\n * @param glyphName - Registered glyph key (`\"chevron-left\"` / `\"chevron-right\"`).\n * @param onClick - Click handler.\n */\n constructor(glyphName: string, onClick: () => void) {\n super({ preferredSize: { width: NAV_BTN_WIDTH, height: MONTH_HEIGHT } });\n this.setLayoutManager(new Fit());\n // Component's per-instance CSS rule emits the cached cursor at render\n // time, which beats any `.PickerNavButton { cursor: pointer }` class\n // rule on specificity. The cursor must be set on this instance.\n this.setCursor(\"pointer\");\n this.getAria().setRole(\"button\");\n\n const glyph = new Glyph(glyphName);\n glyph.setPointerEvents(\"none\");\n // Constrain the glyph so the chevron stays a visual icon — the\n // surrounding 24-px button cell holds the click target.\n glyph.setPreferredSize({ width: GLYPH_PX, height: GLYPH_PX });\n this.addComponent(glyph);\n\n Event.addListener(this, \"pointerdown\", (e: PointerEvent) => e.preventDefault());\n Event.addListener(this, \"click\", () => onClick());\n }\n\n /**\n * Renders the root element and applies the shared nav-button class so a\n * single rule controls the hover background + foreground colour.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n DOM.sink.apply(element, { addClass: [\"PickerNavButton\"] });\n\n return element;\n }\n}\n\n/**\n * Month-label-as-button. Same hover/foreground treatment as the chevrons\n * via the shared `.PickerNavButton` class. Click + pointerdown listeners\n * and the button-affordance aria state are wired internally.\n */\nclass PickerMonthLabel extends Text {\n /**\n * @param onClick - Click handler invoked when the user activates the label.\n */\n constructor(onClick: () => void) {\n super(\"\", {\n textAlign: \"center\",\n fontWeight: \"bold\",\n });\n this.setLineHeight(MONTH_HEIGHT);\n this.setCursor(\"pointer\");\n this.getAria().setRole(\"button\");\n this.getAria().setExpanded(false);\n this.getAria().setTabIndex(0);\n\n Event.addListener(this, \"pointerdown\", (e: PointerEvent) => e.preventDefault());\n Event.addListener(this, \"click\", () => onClick());\n }\n\n /**\n * Renders the root element and applies the shared nav-button class.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n DOM.sink.apply(element, { addClass: [\"PickerNavButton\"] });\n\n return element;\n }\n}\n\n/**\n * A single day cell in the calendar grid. Carries selection + disabled\n * state through Component setters, and click + pointerdown suppression\n * through `Event.addListener`. Static styling lives on `.PickerDay` /\n * `.PickerDay:hover` / `.PickerDay.disabled` class rules.\n */\nclass PickerDay extends Text {\n\n private readonly _date: Date;\n private _selected: boolean = false;\n private _disabled: boolean = false;\n private readonly _onClick: (date: Date) => void;\n\n /**\n * @param date - The day represented by this cell.\n * @param onClick - Called with `date` when the cell is clicked. Suppressed while disabled.\n */\n constructor(date: Date, onClick: (date: Date) => void) {\n super(String(date.getDate()), {\n textAlign: \"center\",\n preferredSize: { width: 0, height: CELL_HEIGHT },\n });\n this._date = date;\n this._onClick = onClick;\n this.setLineHeight(CELL_HEIGHT);\n // Component's per-instance CSS rule emits the cached cursor at render\n // time, which beats the `.PickerDay { cursor: pointer }` class rule\n // on specificity. The cursor must be set on this instance.\n this.setCursor(\"pointer\");\n\n Event.addListener(this, \"pointerdown\", (e: PointerEvent) => this.onPointerDown(e));\n Event.addListener(this, \"click\", () => this.onClick());\n }\n\n /**\n * Returns the date represented by this cell.\n *\n * @returns The cell's date.\n */\n getDate(): Date {\n return this._date;\n }\n\n /**\n * Suppresses focus loss when the day is pointed at so the host input's\n * blur-to-commit path doesn't fire mid-click.\n *\n * @param e - The pointerdown event.\n */\n private onPointerDown(e: PointerEvent): void {\n e.preventDefault();\n }\n\n /**\n * Forwards the cell's date to the owner-supplied click callback. No-op\n * while the cell is disabled.\n */\n private onClick(): void {\n if (this._disabled) {\n return;\n }\n\n this._onClick(this._date);\n }\n\n /**\n * Toggles the selected state.\n *\n * @param selected - True to mark this day as the currently-selected one.\n * @returns This component, for method chaining.\n */\n setSelected(selected: boolean): this {\n if (this._selected === selected) {\n return this;\n }\n\n this._selected = selected;\n\n if (selected) {\n this.setBackgroundColor(\"var(--ts-ui-autocomplete-item-highlight-bg, rgba(30, 100, 200, 0.18))\");\n this.setFontWeight(\"bold\");\n } else {\n this.clearBackgroundColor();\n this.setFontWeight(\"normal\");\n }\n\n return this;\n }\n\n /**\n * Returns whether this cell is currently marked as selected.\n *\n * @returns True when this cell is highlighted as the active selection.\n */\n isSelected(): boolean {\n return this._selected;\n }\n\n /**\n * Toggles the disabled state. Disabled days are dim, ignore pointer\n * events, and skip the constructor-supplied click callback.\n *\n * @param disabled - True to disable the cell.\n * @returns This component, for method chaining.\n */\n setDisabled(disabled: boolean): this {\n if (this._disabled === disabled) {\n return this;\n }\n\n this._disabled = disabled;\n // Component's per-instance cursor rule wins over the `.PickerDay.disabled`\n // class rule, so the cursor flip has to be mirrored on the instance.\n this.setCursor(disabled ? \"default\" : \"pointer\");\n\n const element = this.getElement();\n\n if (element) {\n DOM.sink.apply(element, { toggleClass: { disabled: disabled } });\n }\n\n return this;\n }\n\n /**\n * Returns whether this cell is currently disabled (out of allowed range).\n *\n * @returns True when this cell is disabled.\n */\n isDisabled(): boolean {\n return this._disabled;\n }\n\n /**\n * Renders the cell and applies the `.PickerDay` class + the cached\n * `.disabled` class so the first paint reflects state set before the\n * element was realised.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n DOM.sink.apply(element, { addClass: [\"PickerDay\"] });\n\n if (this._disabled) {\n DOM.sink.apply(element, { addClass: [\"disabled\"] });\n }\n\n return element;\n }\n}\n\n/**\n * Returns midnight at the start of `date`'s local day. Bound comparisons\n * use `dayStart(minDate)` and `dayEnd(maxDate)` so a `new Date(year, m, d)`\n * with `00:00:00` semantics counts as \"in range\" even when the bound has a\n * non-zero time component.\n *\n * @param date - The date whose day-start is wanted.\n * @returns A new `Date` at 00:00:00 local time on the same day.\n */\nfunction dayStart(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Returns the last instant of `date`'s local day (23:59:59.999).\n *\n * @param date - The date whose day-end is wanted.\n * @returns A new `Date` at 23:59:59.999 local time on the same day.\n */\nfunction dayEnd(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);\n}\n\n/**\n * Construction-time options shared by every {@link AbstractCalendarDropdown}\n * subclass. Subclass-specific fields (e.g. `showSeconds`) live in the\n * subclass's own options interface.\n *\n * @category Components\n */\nexport interface AbstractCalendarDropdownOptions extends AnimatedDropdownOptions {\n /** Earliest date the picker will allow selection of. Optional. */\n minDate?: Date | null;\n /** Latest date the picker will allow selection of. Optional. */\n maxDate?: Date | null;\n}\n\n/**\n * Abstract base for the two calendar dropdowns\n * ({@link DatePickerDropdown}, {@link DateTimePickerDropdown}). Owns the\n * shared structure (header row, weekday row, day grid, year scroller),\n * the keyboard contract (day-grid arrows, year-scroller type-ahead),\n * the min/max-date clamping, and the open/close lifecycle.\n *\n * Subclasses provide the panel width, optional extra rows beneath the day\n * grid (e.g. a time-row for `DateTimeField`), and decide what fraction of\n * the value to mutate on a day-cell or year-cell commit.\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated;\n * concrete subclasses do the callable wrapping themselves.\n *\n * @category Components\n */\nabstract class AbstractCalendarDropdown<\n TOptions extends AbstractCalendarDropdownOptions = AbstractCalendarDropdownOptions\n> extends AnimatedDropdown<TOptions> {\n\n /**\n * Constructor-supplied callback. Fired with a fresh copy of `_value`\n * whenever the value changes (day click, year-cell commit, subclass\n * time-row edit). The DateField subclass closes the panel from inside\n * the callback; DateTimeField leaves it open.\n */\n private readonly _onSelect: (value: Date) => void;\n\n /**\n * The current value. The day/month/year portion reflects the user's\n * date selection; the time portion is whatever the subclass chooses to\n * preserve (DateField: 00:00; DateTimeField: the user-picked time).\n * `null` when nothing is selected.\n */\n protected _value: Date | null = null;\n\n /** Currently-displayed month (1st-of-month, time 00:00). Source of truth for the grid. */\n protected _monthAnchor: Date = new Date();\n\n /** True while the year-scroller is replacing the day-grid in the panel. */\n protected _yearScrollOpen: boolean = false;\n\n /** Outer VBox container holding (header row, weekday row, day-grid OR year-scroller, plus any subclass-supplied rows). */\n protected _root: Component;\n\n /** Header row: prev-chevron, month-label-as-button, next-chevron. */\n protected _headerRow: Component;\n protected _prevButton: PickerNavButton;\n protected _nextButton: PickerNavButton;\n protected _monthLabel: PickerMonthLabel;\n\n /** The \"Sun Mon Tue …\" row above the day grid. */\n protected _weekdayRow: Component;\n\n /** Day grid (swapped out for `_yearColumn` while the scroller is open). */\n protected _dayGrid: Component;\n\n /** Lazily-built year scroller; null until the user first opens it. */\n protected _yearColumn: PickerColumn | null = null;\n\n /** Index in `_dayGrid` children of the highlighted cell, for keyboard nav. -1 when no cell is highlighted. */\n private _highlightedDayIdx: number = -1;\n\n /** Highlighted year in the year scroller, -1 when none. */\n private _highlightedYear: number = -1;\n\n /** Type-ahead buffer for the year scroller (digits only, max length 4). */\n private _yearTypeBuffer: string = \"\";\n\n /** Timer id for the type-ahead idle reset, or null. */\n private _yearTypeTimer: number | null = null;\n\n /**\n * @param onSelect - Called with a fresh `Date` whenever the user updates the selection.\n * @param options - Caller-supplied options bag.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; deepest subclass values win.\n */\n constructor(\n onSelect: (value: Date) => void,\n options?: TOptions,\n subclassDefaults?: Partial<TOptions>,\n ) {\n super(\n options,\n {\n zIndex: 10050,\n layoutManager: new Fit(),\n backgroundColor: \"var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n shadow: \"var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))\",\n insets: new Insets(6, 6, 6, 6),\n ...(subclassDefaults ?? {}),\n } as Partial<TOptions>,\n );\n\n this._onSelect = onSelect;\n\n this.getAria().setRole(\"group\");\n this.setContain(\"layout\");\n\n this._root = new Component();\n this._root.setLayoutManager(new VBox({ spacing: ROOT_GAP, stretching: true }));\n\n // Header row: [<] [Month YYYY (button)] [>]\n this._headerRow = new Component({ preferredSize: { width: 0, height: MONTH_HEIGHT } });\n this._headerRow.setLayoutManager(new HBox({ spacing: 2, stretching: true }));\n\n this._prevButton = new PickerNavButton(\"chevron-left\", () => this.prevMonth());\n this._nextButton = new PickerNavButton(\"chevron-right\", () => this.nextMonth());\n this._monthLabel = new PickerMonthLabel(() => this.toggleYearScroller());\n\n // Chevrons take their fixed width from the NavButton constructor; the\n // month label takes the remaining width via weight.\n const labelWeight = new LayoutConstraints();\n labelWeight.weight = 1;\n\n this._headerRow.addComponent(this._prevButton);\n this._headerRow.addComponent(this._monthLabel, labelWeight);\n this._headerRow.addComponent(this._nextButton);\n\n this._root.addComponent(this._headerRow);\n\n this._weekdayRow = new Component({ preferredSize: { width: 0, height: HEADER_HEIGHT } });\n this._weekdayRow.setLayoutManager(new Grid({ columns: 7, spacing: 2 }));\n\n for (const dh of [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"]) {\n this._weekdayRow.addComponent(new PickerDayHeader(dh));\n }\n\n this._root.addComponent(this._weekdayRow);\n\n this._dayGrid = new Component({ preferredSize: { width: 0, height: DAY_GRID_HEIGHT } });\n this._dayGrid.setLayoutManager(new Grid({ columns: 7, spacing: 2 }));\n this._root.addComponent(this._dayGrid);\n\n this.addComponent(this._root);\n\n // Subclass hook: append any extra rows beneath the day grid (e.g. a\n // time row for `DateTimeField`). Called from the base constructor so\n // the extra rows participate in the initial layout pass.\n this.buildExtraRootChildren();\n\n // Suppress focus loss anywhere inside the panel — protects pooled\n // cell editors whose blur listener would otherwise commit before\n // a day-cell click is delivered. `addSubtreeListener` matches\n // descendant targets too, not just the dropdown's own element.\n Event.addSubtreeListener(this, \"pointerdown\", (e: PointerEvent) => this.onPointerDown(e));\n }\n\n /**\n * Applies the {@link AbstractCalendarDropdownOptions} bag. `minDate` /\n * `maxDate` are pure cache writes here — they're read at year-scroller\n * and day-grid build time.\n *\n * @param options - The options bag to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.minDate !== undefined) {\n this._options.minDate = options.minDate;\n }\n\n if (options.maxDate !== undefined) {\n this._options.maxDate = options.maxDate;\n }\n\n return this;\n }\n\n /**\n * Suppresses focus loss while the user is interacting with the panel — but\n * lets a `pointerdown` on a focusable `<input>` through (e.g. the embedded\n * time field in the date-time picker) so the user can place the caret and\n * type. The day/year cells are not inputs, so they stay guarded.\n *\n * @param e - The pointerdown event.\n */\n private onPointerDown(e: PointerEvent): void {\n if (DOM.source.isNode(e.target) && DOM.source.getTagName(DOM.source.intern(e.target)) === \"INPUT\") {\n return;\n }\n\n e.preventDefault();\n }\n\n /**\n * Anchors the picker below `anchorEl`, initialises the active value from\n * `selected` (or leaves it null when null), and plays the entrance fade.\n *\n * @param anchorEl - The input the picker anchors to.\n * @param selected - The currently-selected Date, or null.\n */\n showAt(anchorEl: Handle, selected: Date | null): this {\n this._value = selected ? new Date(selected.getTime()) : null;\n\n const anchor = this._value ?? new Date();\n this._monthAnchor = new Date(anchor.getFullYear(), anchor.getMonth(), 1);\n\n this._highlightedDayIdx = -1;\n this._highlightedYear = -1;\n this.resetYearTypeBuffer();\n\n // Reset the swap so consecutive opens always start on the day grid.\n if (this._yearScrollOpen) {\n this.closeYearScroller();\n }\n\n this.pauseLayout();\n this.rebuild();\n this.resumeLayout();\n\n const panelHeight = this.computePanelHeight();\n this.setWidth(this.getPanelWidth());\n this.setHeight(panelHeight);\n\n this.doLayout();\n\n this.placeAnchored(DOM.source.getElementRect(anchorEl));\n\n this.showAnimated();\n\n return this;\n }\n\n /**\n * Cleans up dropdown state when the panel is dismissed. Resets the\n * type-ahead buffer so a stale `\"19\"` doesn't merge with the next\n * opening's first digit.\n */\n hideAnimated(): this {\n super.hideAnimated();\n this.resetYearTypeBuffer();\n\n return this;\n }\n\n /**\n * Sums the fixed-height rows + any subclass-supplied extras + the\n * dropdown's chrome (border + insets) to produce the panel's outer\n * height. `getPerimeterSize` rather than `getInsets` so the 1-px\n * border counts.\n *\n * @returns Panel outer height in pixels.\n */\n protected computePanelHeight(): number {\n const perim = this.getPerimeterSize();\n const innerH = MONTH_HEIGHT + ROOT_GAP + HEADER_HEIGHT + ROOT_GAP + DAY_GRID_HEIGHT + this.getExtraInnerHeight();\n\n return perim.top + perim.bottom + innerH;\n }\n\n /**\n * Rebuilds the day grid and dispatches to the subclass hook for any\n * extra rows. Called from `showAt` and after value-changing\n * interactions so the subclass's extras can re-render against the\n * current `_value`.\n */\n protected rebuild(): void {\n this.buildDayGrid();\n this.rebuildExtraRowsAfterValueChange();\n }\n\n /**\n * Rebuilds the day-grid children for `_monthAnchor`. Clears the grid\n * first so repeated calls don't accumulate cells.\n */\n protected buildDayGrid(): void {\n this._dayGrid.removeAllComponents();\n this._highlightedDayIdx = -1;\n\n const year = this._monthAnchor.getFullYear();\n const month = this._monthAnchor.getMonth();\n\n this._monthLabel.setText(\n this._monthAnchor.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" })\n );\n\n const firstOfMonth = new Date(year, month, 1);\n const startWeekday = firstOfMonth.getDay();\n const daysInMonth = new Date(year, month + 1, 0).getDate();\n\n for (let i = 0; i < startWeekday; i++) {\n this._dayGrid.addComponent(new PickerBlankCell());\n }\n\n for (let day = 1; day <= daysInMonth; day++) {\n const date = new Date(year, month, day);\n const cell = new PickerDay(date, d => this.onDateSelected(d));\n\n if (!this.isDateInRange(date)) {\n cell.setDisabled(true);\n }\n\n if (this.isValueOnDay(date)) {\n cell.setSelected(true);\n }\n\n this._dayGrid.addComponent(cell);\n }\n\n // Pad to 42 cells (6 rows × 7) so the Grid renders a uniform block.\n const remaining = 42 - startWeekday - daysInMonth;\n\n for (let i = 0; i < remaining; i++) {\n this._dayGrid.addComponent(new PickerBlankCell());\n }\n }\n\n /**\n * Returns true when `_value` falls on the same local day as `date`.\n * Used by the day-grid renderer to mark the active cell.\n *\n * @param date - The day cell's date.\n * @returns True when the current value's day matches.\n */\n protected isValueOnDay(date: Date): boolean {\n if (!this._value) {\n return false;\n }\n\n return this._value.getFullYear() === date.getFullYear()\n && this._value.getMonth() === date.getMonth()\n && this._value.getDate() === date.getDate();\n }\n\n /**\n * Returns true when `date` falls within (or equal to) the configured\n * `minDate` and `maxDate` bounds. Both bounds are optional; an absent\n * bound is treated as ±∞.\n *\n * @param date - The date to test.\n * @returns True when `date` is allowed.\n */\n protected isDateInRange(date: Date): boolean {\n const minDate = this._options.minDate ?? null;\n const maxDate = this._options.maxDate ?? null;\n\n if (minDate && date.getTime() < dayStart(minDate).getTime()) {\n return false;\n }\n\n if (maxDate && date.getTime() > dayEnd(maxDate).getTime()) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Returns true when at least one day in `monthAnchor`'s month is within\n * range — used by the month chevrons to refuse advancing into a fully\n * out-of-bounds month.\n *\n * @param monthAnchor - 1st-of-month for the candidate month.\n * @returns True when at least one day in that month is in range.\n */\n protected hasAnyInRange(monthAnchor: Date): boolean {\n const year = monthAnchor.getFullYear();\n const month = monthAnchor.getMonth();\n const last = new Date(year, month + 1, 0).getDate();\n\n // Cheaper than scanning every day: a month is fully out-of-range\n // only if its last day is before `minDate` or its first day is\n // after `maxDate`.\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month, last);\n const minDate = this._options.minDate ?? null;\n const maxDate = this._options.maxDate ?? null;\n\n if (minDate && dayEnd(lastDay).getTime() < dayStart(minDate).getTime()) {\n return false;\n }\n\n if (maxDate && dayStart(firstDay).getTime() > dayEnd(maxDate).getTime()) {\n return false;\n }\n\n return true;\n }\n\n /**\n * Day-cell click handler. Lets the subclass fold the date into `_value`,\n * advances `_monthAnchor`, notifies, and rebuilds so the highlight\n * follows. The subclass's `_onSelect` callback decides whether to keep\n * the panel open or close it.\n *\n * @param date - The chosen day.\n */\n protected onDateSelected(date: Date): void {\n this.applyDateSelection(date);\n this._monthAnchor = new Date(date.getFullYear(), date.getMonth(), 1);\n this.notifyValueChanged();\n this.rebuild();\n this.doLayout();\n }\n\n /**\n * Fires `_onSelect` with a fresh copy of `_value` when the value is\n * non-null. Subclasses call this from their year/time/etc. handlers\n * after mutating `_value`.\n */\n protected notifyValueChanged(): void {\n if (this._value) {\n this._onSelect(new Date(this._value.getTime()));\n }\n }\n\n /**\n * Advances `_monthAnchor` by `-1` month and rebuilds the grid. No-op\n * when the previous month is fully out of range.\n */\n private prevMonth(): void {\n const candidate = new Date(this._monthAnchor.getFullYear(), this._monthAnchor.getMonth() - 1, 1);\n\n if (!this.hasAnyInRange(candidate)) {\n return;\n }\n\n this._monthAnchor = candidate;\n\n if (this._yearScrollOpen) {\n // Switching months while the scroller is open is allowed; just\n // re-render the header label and rebuild the scroller's\n // selection.\n this.updateMonthLabel();\n this.refreshYearSelection();\n } else {\n this.buildDayGrid();\n this.doLayout();\n }\n }\n\n /**\n * Advances `_monthAnchor` by `+1` month and rebuilds the grid. No-op\n * when the next month is fully out of range.\n */\n private nextMonth(): void {\n const candidate = new Date(this._monthAnchor.getFullYear(), this._monthAnchor.getMonth() + 1, 1);\n\n if (!this.hasAnyInRange(candidate)) {\n return;\n }\n\n this._monthAnchor = candidate;\n\n if (this._yearScrollOpen) {\n this.updateMonthLabel();\n this.refreshYearSelection();\n } else {\n this.buildDayGrid();\n this.doLayout();\n }\n }\n\n /**\n * Re-renders just the header label after `_monthAnchor` moves. Kept\n * separate from `buildDayGrid` so month-arrow clicks made while the\n * year scroller is open don't tear down the scroller.\n */\n private updateMonthLabel(): void {\n this._monthLabel.setText(\n this._monthAnchor.toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" })\n );\n }\n\n /**\n * Toggles the year scroller in place of the day grid. The header row\n * (and any subclass-supplied rows below the grid) stays visible.\n */\n private toggleYearScroller(): void {\n if (this._yearScrollOpen) {\n this.closeYearScroller();\n } else {\n this.openYearScroller();\n }\n }\n\n /**\n * Opens the year scroller: removes the day grid from the panel, builds\n * / rebuilds the year column, swaps it in at the day grid's slot, and\n * centres the active year. Subclass-supplied rows below the grid stay\n * in place because the swap uses `insertComponent` at the fixed slot\n * index.\n */\n protected openYearScroller(): void {\n if (!this._yearColumn) {\n this._yearColumn = new PickerColumn(null);\n // Match the day-grid's height slot so the panel doesn't resize on swap.\n this._yearColumn.setPreferredSize({ width: 0, height: DAY_GRID_HEIGHT });\n this._yearColumn.getAria().setRole(\"listbox\");\n }\n\n this.buildYearScroller();\n\n this._root.removeComponent(this._dayGrid);\n this._root.insertComponent(this._yearColumn, DAY_GRID_INDEX);\n\n this._yearScrollOpen = true;\n this._monthLabel.getAria().setExpanded(true);\n\n this.doLayout();\n\n // After layout commits the cells acquire their offsetTop; only then\n // can we centre the active year mid-viewport.\n this._yearColumn.scrollSelectedIntoView();\n }\n\n /**\n * Closes the year scroller and restores the day grid at the same slot.\n * Re-applies the selection so the highlight survives a year change.\n */\n protected closeYearScroller(): void {\n if (this._yearColumn) {\n this._root.removeComponent(this._yearColumn);\n }\n\n this._root.insertComponent(this._dayGrid, DAY_GRID_INDEX);\n\n this._yearScrollOpen = false;\n this._monthLabel.getAria().setExpanded(false);\n this.resetYearTypeBuffer();\n\n this.buildDayGrid();\n this.doLayout();\n }\n\n /**\n * Populates `_yearColumn` with one cell per year in the legal range,\n * marking the active year as selected. Bound by `minDate` / `maxDate`\n * when set, otherwise the default ±span around today.\n */\n private buildYearScroller(): void {\n if (!this._yearColumn) {\n return;\n }\n\n this._yearColumn.clearCells();\n this._highlightedYear = -1;\n\n const today = new Date();\n const minYear = this._options.minDate?.getFullYear() ?? today.getFullYear() - DEFAULT_YEAR_SPAN_BACK;\n const maxYear = this._options.maxDate?.getFullYear() ?? today.getFullYear() + DEFAULT_YEAR_SPAN_FORWARD;\n const activeY = this._monthAnchor.getFullYear();\n\n for (let y = minYear; y <= maxYear; y++) {\n const year = y;\n const cell = new PickerCell(String(year), () => this.onYearSelected(year));\n\n if (year === activeY) {\n cell.setSelected(true);\n }\n\n this._yearColumn.addCell(cell);\n }\n }\n\n /**\n * Updates the year scroller's selection highlight after a month-arrow\n * change moved `_monthAnchor` into a different year. Cheaper than a\n * full `buildYearScroller` because the cells themselves are unchanged.\n */\n private refreshYearSelection(): void {\n if (!this._yearColumn) {\n return;\n }\n\n const activeY = this._monthAnchor.getFullYear();\n\n for (const child of this._yearColumn.getCellList().getComponents()) {\n if (child instanceof PickerCell) {\n child.setSelected(child.getText().valueOf() === String(activeY));\n }\n }\n }\n\n /**\n * Year-cell click handler. Sets `_monthAnchor` to the same month in the\n * new year, lets the subclass decide whether the year alone commits\n * a value change, then closes the scroller.\n *\n * @param year - The chosen year.\n */\n private onYearSelected(year: number): void {\n this._monthAnchor = new Date(year, this._monthAnchor.getMonth(), 1);\n this.applyYearSelection(year);\n this.closeYearScroller();\n }\n\n /**\n * Resets the year-scroller's 4-digit type-ahead buffer and clears any\n * pending idle timer. Called when the dropdown closes, the user\n * presses Escape, or the user commits a year.\n */\n private resetYearTypeBuffer(): void {\n this._yearTypeBuffer = \"\";\n\n if (this._yearTypeTimer !== null) {\n clearTimeout(this._yearTypeTimer);\n this._yearTypeTimer = null;\n }\n }\n\n /**\n * Keyboard router. Returns `true` when the event was handled (the\n * caller should `preventDefault`); `false` lets the host input's own\n * handler run.\n *\n * @param e - The keyboard event.\n * @returns True when handled.\n */\n handleKey(e: KeyboardEvent): boolean {\n if (!this.isOpen()) {\n return false;\n }\n\n if (this._yearScrollOpen) {\n return this.handleKeyInYearScroller(e);\n }\n\n return this.handleKeyInDayGrid(e);\n }\n\n /**\n * Routes the keystroke when the day grid is visible.\n *\n * @param e - The keyboard event.\n * @returns True when handled.\n */\n private handleKeyInDayGrid(e: KeyboardEvent): boolean {\n switch (e.key) {\n case \"ArrowLeft\":\n return this.moveHighlightedDay(-1);\n case \"ArrowRight\":\n return this.moveHighlightedDay(1);\n case \"ArrowUp\":\n return this.moveHighlightedDay(-7);\n case \"ArrowDown\":\n return this.moveHighlightedDay(7);\n case \"PageUp\":\n this.prevMonth();\n return true;\n case \"PageDown\":\n this.nextMonth();\n return true;\n case \"Home\":\n return this.highlightFirstDayOfMonth();\n case \"End\":\n return this.highlightLastDayOfMonth();\n case \"Enter\":\n case \" \":\n return this.commitHighlightedDay();\n default:\n return false;\n }\n }\n\n /**\n * Returns the children of `_dayGrid` as a typed array. Includes\n * blank-cell entries.\n *\n * @returns The grid's day cells in DOM order.\n */\n private getDayGridChildren(): Component[] {\n return this._dayGrid.getComponents();\n }\n\n /**\n * Moves the keyboard-highlighted day cell by `delta` positions in the\n * grid. Skips disabled and blank cells.\n *\n * @param delta - Positive or negative step (±1 for arrow, ±7 for row).\n * @returns Always true (the keystroke is consumed even when no movement happens).\n */\n private moveHighlightedDay(delta: number): boolean {\n const children = this.getDayGridChildren();\n const dayCells: { idx: number; cell: PickerDay }[] = [];\n\n for (let i = 0; i < children.length; i++) {\n const c = children[i];\n\n if (c instanceof PickerDay && !c.isDisabled()) {\n dayCells.push({ idx: i, cell: c });\n }\n }\n\n if (dayCells.length === 0) {\n return true;\n }\n\n // Map the current highlighted index → its position within dayCells.\n let currentPos = -1;\n\n for (let i = 0; i < dayCells.length; i++) {\n if (dayCells[i].idx === this._highlightedDayIdx) {\n currentPos = i;\n break;\n }\n }\n\n if (currentPos < 0) {\n // No highlight yet — start from the selected cell if present,\n // otherwise the first in-range cell.\n currentPos = 0;\n\n for (let i = 0; i < dayCells.length; i++) {\n if (dayCells[i].cell.isSelected()) {\n currentPos = i;\n break;\n }\n }\n }\n\n const newPos = Math.max(0, Math.min(dayCells.length - 1, currentPos + delta));\n this.setHighlightedDay(dayCells[newPos].idx);\n\n return true;\n }\n\n /**\n * Sets the keyboard highlight on the day cell at the given grid index.\n * Visual highlight is the same as the click-selection style (background\n * + bold) so the user sees the same indicator either way.\n *\n * @param newIdx - Grid index of the cell to highlight.\n */\n private setHighlightedDay(newIdx: number): void {\n const children = this.getDayGridChildren();\n\n if (this._highlightedDayIdx >= 0 && this._highlightedDayIdx < children.length) {\n const prev = children[this._highlightedDayIdx];\n\n if (prev instanceof PickerDay && !this.matchesSelection(prev)) {\n prev.setSelected(false);\n }\n }\n\n if (newIdx < 0 || newIdx >= children.length) {\n this._highlightedDayIdx = -1;\n\n return;\n }\n\n const cell = children[newIdx];\n\n if (cell instanceof PickerDay) {\n cell.setSelected(true);\n this._highlightedDayIdx = newIdx;\n }\n }\n\n /**\n * True when `cell`'s date matches the currently-selected date — used\n * to decide whether removing the keyboard highlight should also clear\n * the selection styling.\n *\n * @param cell - The day cell to test.\n * @returns True when the cell represents the currently-selected date.\n */\n private matchesSelection(cell: PickerDay): boolean {\n return this.isValueOnDay(cell.getDate());\n }\n\n /**\n * Jumps the highlight to the first in-range day of the current month.\n *\n * @returns Always true.\n */\n private highlightFirstDayOfMonth(): boolean {\n const children = this.getDayGridChildren();\n\n for (let i = 0; i < children.length; i++) {\n const c = children[i];\n\n if (c instanceof PickerDay && !c.isDisabled()) {\n this.setHighlightedDay(i);\n\n return true;\n }\n }\n\n return true;\n }\n\n /**\n * Jumps the highlight to the last in-range day of the current month.\n *\n * @returns Always true.\n */\n private highlightLastDayOfMonth(): boolean {\n const children = this.getDayGridChildren();\n\n for (let i = children.length - 1; i >= 0; i--) {\n const c = children[i];\n\n if (c instanceof PickerDay && !c.isDisabled()) {\n this.setHighlightedDay(i);\n\n return true;\n }\n }\n\n return true;\n }\n\n /**\n * Commits the highlighted day as if the user had clicked it.\n *\n * @returns True when a day was committed; false when no highlight exists.\n */\n private commitHighlightedDay(): boolean {\n if (this._highlightedDayIdx < 0) {\n return false;\n }\n\n const children = this.getDayGridChildren();\n const cell = children[this._highlightedDayIdx];\n\n if (cell instanceof PickerDay && !cell.isDisabled()) {\n this.onDateSelected(cell.getDate());\n\n return true;\n }\n\n return false;\n }\n\n /**\n * Routes the keystroke when the year scroller is visible.\n *\n * @param e - The keyboard event.\n * @returns True when handled.\n */\n private handleKeyInYearScroller(e: KeyboardEvent): boolean {\n if (/^[0-9]$/.test(e.key)) {\n return this.appendYearDigit(e.key);\n }\n\n switch (e.key) {\n case \"ArrowLeft\":\n case \"ArrowUp\":\n return this.moveHighlightedYear(-1);\n case \"ArrowRight\":\n case \"ArrowDown\":\n return this.moveHighlightedYear(1);\n case \"PageUp\":\n return this.moveHighlightedYear(-10);\n case \"PageDown\":\n return this.moveHighlightedYear(10);\n case \"Home\":\n return this.highlightFirstYear();\n case \"End\":\n return this.highlightLastYear();\n case \"Enter\":\n case \" \":\n return this.commitHighlightedYear();\n case \"Escape\":\n this.closeYearScroller();\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Returns the year cells in the scroller.\n *\n * @returns PickerCell entries from the scroller's cell list.\n */\n private getYearCells(): PickerCell[] {\n if (!this._yearColumn) {\n return [];\n }\n\n const cells: PickerCell[] = [];\n\n for (const c of this._yearColumn.getCellList().getComponents()) {\n if (c instanceof PickerCell) {\n cells.push(c);\n }\n }\n\n return cells;\n }\n\n /**\n * Moves the year-scroller highlight by `delta` cells.\n *\n * @param delta - Step size (positive = down/later years, negative = up/earlier).\n * @returns Always true.\n */\n private moveHighlightedYear(delta: number): boolean {\n const cells = this.getYearCells();\n\n if (cells.length === 0) {\n return true;\n }\n\n const currentPos = this.findHighlightedYearPos(cells);\n const newPos = Math.max(0, Math.min(cells.length - 1, currentPos + delta));\n\n this.applyYearHighlight(cells, newPos);\n\n return true;\n }\n\n /**\n * Returns the cell position of the highlighted year (or the selected\n * year when none is keyboard-highlighted yet).\n *\n * @param cells - Snapshot of the scroller's cell list.\n * @returns Position in the cells array; 0 when nothing matches.\n */\n private findHighlightedYearPos(cells: PickerCell[]): number {\n if (this._highlightedYear < 0) {\n for (let i = 0; i < cells.length; i++) {\n if (cells[i].isSelected()) {\n return i;\n }\n }\n\n return 0;\n }\n\n for (let i = 0; i < cells.length; i++) {\n if (cells[i].getText().valueOf() === String(this._highlightedYear)) {\n return i;\n }\n }\n\n return 0;\n }\n\n /**\n * Sets the visual highlight on cell `pos` and remembers the year.\n * Clears the previous highlight where appropriate.\n *\n * @param cells - Snapshot of the scroller's cell list.\n * @param pos - Index of the cell to highlight.\n */\n private applyYearHighlight(cells: PickerCell[], pos: number): void {\n const activeY = this._monthAnchor.getFullYear();\n\n for (const c of cells) {\n // Only the truly-selected year keeps its highlight; everything\n // else clears so the new keyboard-highlight stands alone.\n c.setSelected(c.getText().valueOf() === String(activeY));\n }\n\n cells[pos].setSelected(true);\n this._highlightedYear = parseInt(cells[pos].getText().valueOf(), 10);\n\n // Mirror in the scrollable region so the new highlight is visible.\n if (this._yearColumn) {\n this._yearColumn.scrollSelectedIntoView();\n }\n }\n\n /**\n * Jumps the highlight to the first year cell.\n *\n * @returns Always true.\n */\n private highlightFirstYear(): boolean {\n const cells = this.getYearCells();\n\n if (cells.length === 0) {\n return true;\n }\n\n this.applyYearHighlight(cells, 0);\n\n return true;\n }\n\n /**\n * Jumps the highlight to the last year cell.\n *\n * @returns Always true.\n */\n private highlightLastYear(): boolean {\n const cells = this.getYearCells();\n\n if (cells.length === 0) {\n return true;\n }\n\n this.applyYearHighlight(cells, cells.length - 1);\n\n return true;\n }\n\n /**\n * Commits the highlighted year as if the user had clicked it. Falls\n * back to the currently-selected year when no keyboard highlight is\n * active.\n *\n * @returns Always true (the keystroke is consumed).\n */\n private commitHighlightedYear(): boolean {\n const year = this._highlightedYear >= 0\n ? this._highlightedYear\n : this._monthAnchor.getFullYear();\n\n this.onYearSelected(year);\n\n return true;\n }\n\n /**\n * Appends a digit to the type-ahead buffer; resets after\n * `YEAR_TYPE_IDLE_MS` ms idle or 4 digits. Commits the jump when the\n * buffer reaches 4 digits.\n *\n * @param digit - The single decimal digit pressed.\n * @returns Always true.\n */\n private appendYearDigit(digit: string): boolean {\n if (this._yearTypeBuffer.length >= 4) {\n this._yearTypeBuffer = \"\";\n }\n\n this._yearTypeBuffer += digit;\n\n if (this._yearTypeTimer !== null) {\n clearTimeout(this._yearTypeTimer);\n }\n\n this._yearTypeTimer = setTimeout(() => this.resetYearTypeBuffer(), YEAR_TYPE_IDLE_MS);\n\n // Prefix-match jump: as soon as the buffer matches a legal year\n // exactly (length === 4) or prefix-matches a single year, jump.\n const cells = this.getYearCells();\n const buf = this._yearTypeBuffer;\n let target = -1;\n\n for (let i = 0; i < cells.length; i++) {\n if (cells[i].getText().valueOf().startsWith(buf)) {\n target = i;\n break;\n }\n }\n\n if (target >= 0) {\n this.applyYearHighlight(cells, target);\n }\n\n // After 4 digits the buffer is \"complete\" — clear it so the next\n // digit starts fresh rather than appearing as a 5th character.\n if (buf.length === 4) {\n this.resetYearTypeBuffer();\n }\n\n return true;\n }\n\n // ===== Subclass hooks =====\n\n /**\n * Subclass hook: returns the panel's outer width in pixels. DateField\n * returns a constant; DateTimeField varies it by `showSeconds`.\n *\n * @returns Panel outer width in pixels.\n */\n protected abstract getPanelWidth(): number;\n\n /**\n * Subclass hook: extra inner height (px) contributed by subclass-supplied\n * rows beneath the day grid (e.g. a time row). Default 0.\n *\n * @returns Extra inner height in pixels.\n */\n protected getExtraInnerHeight(): number {\n return 0;\n }\n\n /**\n * Subclass hook: append extra rows to `_root` after the day grid\n * (e.g. a time row). Called from the base constructor so the extras\n * participate in the initial layout pass.\n */\n protected buildExtraRootChildren(): void {\n // Default: no extras.\n }\n\n /**\n * Subclass hook: refresh subclass-supplied rows after `_value` changed\n * (e.g. update time-row ComboBoxes to the new hours/minutes).\n */\n protected rebuildExtraRowsAfterValueChange(): void {\n // Default: no-op.\n }\n\n /**\n * Subclass hook: fold a clicked day into `_value`. Default replaces\n * `_value` with a midnight Date; DateTimeField overrides to preserve\n * the time portion.\n *\n * @param date - The clicked day.\n */\n protected applyDateSelection(date: Date): void {\n this._value = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);\n }\n\n /**\n * Subclass hook: react to a year cell being committed (click or\n * keyboard). DateField defaults to \"navigation only\" — picking a year\n * just moves the month anchor. DateTimeField overrides to mutate\n * `_value.setFullYear` and fire the change callback so a year-only\n * scroll commits as a value edit.\n *\n * @param _year - The chosen year. Default implementation ignores it.\n */\n protected applyYearSelection(_year: number): void {\n // Default: navigation only, no value commit.\n }\n}\n\nexport {\n AbstractCalendarDropdown,\n PickerDay,\n PickerBlankCell,\n PickerNavButton,\n PickerMonthLabel,\n PickerDayHeader,\n dayStart,\n dayEnd,\n MONTH_HEIGHT,\n NAV_BTN_WIDTH,\n HEADER_HEIGHT,\n CELL_HEIGHT,\n DAY_GRID_HEIGHT,\n ROOT_GAP,\n GLYPH_PX,\n DAY_GRID_INDEX,\n DEFAULT_YEAR_SPAN_BACK,\n DEFAULT_YEAR_SPAN_FORWARD,\n YEAR_TYPE_IDLE_MS,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport {\n AbstractCalendarDropdown,\n AbstractCalendarDropdownOptions,\n} from \"~/component/input/AbstractCalendarDropdown.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/** Pixel width of the calendar grid. */\nconst PANEL_WIDTH: number = 240;\n\n/**\n * Construction-time options for {@link DatePickerDropdown}.\n *\n * @category Components\n */\nexport interface DatePickerDropdownOptions extends AbstractCalendarDropdownOptions {\n}\n\n/**\n * Floating month-grid date picker. Renders the calendar for the currently\n * displayed month (initialised from the value passed to `showAt`, or today\n * when the value is null). Selecting a day fires the `onSelect` callback\n * supplied to the constructor.\n *\n * Navigation:\n * - Month-step `<` / `>` chevrons on the header row.\n * - Clicking the \"May 2026\" header swaps the day grid for an in-place\n * year-scroller; click a year to return to the day grid for that year.\n * - 4-digit type-ahead inside the year scroller jumps to the typed year.\n * - `minDate` / `maxDate` clamp both the year scroller range and which day\n * cells are clickable.\n *\n * Inherits everything except the panel width — the shared calendar\n * structure, keyboard contract, year scroller, and bound-clamping all live\n * on [`AbstractCalendarDropdown`](/api/component/input/classes/AbstractCalendarDropdown).\n *\n * @category Components\n */\nclass DatePickerDropdown extends AbstractCalendarDropdown<DatePickerDropdownOptions> {\n\n /**\n * @param onSelect - Called with the chosen `Date` when the user picks a day.\n * @param options - Optional construction-time options.\n */\n constructor(onSelect: (value: Date) => void, options?: DatePickerDropdownOptions) {\n super(onSelect, options);\n }\n\n /**\n * Returns the picker panel's outer width. Constant — the DateField\n * format (\"YYYY-MM-DD\") is narrower than DateTimeField, so the grid\n * doesn't need the seconds-variant extra width.\n */\n protected getPanelWidth(): number {\n return PANEL_WIDTH;\n }\n\n /**\n * Day-cell click handler. Folds the date into `_value`, notifies the\n * field, and stops — the field's selection callback closes the panel,\n * so refreshing the grid would be wasted work.\n *\n * @param date - The chosen day.\n */\n protected onDateSelected(date: Date): void {\n this.applyDateSelection(date);\n this._monthAnchor = new Date(date.getFullYear(), date.getMonth(), 1);\n this.notifyValueChanged();\n }\n}\n\nconst DatePickerDropdownCallable = callable(DatePickerDropdown);\ntype DatePickerDropdownCallable = DatePickerDropdown;\nexport {\n DatePickerDropdown as _DatePickerDropdown,\n DatePickerDropdownCallable as DatePickerDropdown\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { PickerCell, PickerColumn } from \"~/component/input/PickerColumn.js\";\n\n/**\n * Pixel height of the Hour/Min/Sec column block. Sized to show roughly seven\n * scrollable cells beneath the column headers. The `TimePickerDropdown` panel\n * has a fixed height and stretches this to fill via its `Fit` layout, so the\n * value only governs the embedded `DateTimePickerDropdown` case.\n */\nconst TIME_COLUMNS_HEIGHT: number = 176;\n\n/**\n * Construction-time options for {@link TimeColumns}.\n */\ninterface TimeColumnsOptions {\n /** When true, a third \"Sec\" column is built alongside Hour and Min. Default: false. */\n showSeconds?: boolean;\n}\n\n/**\n * The scrollable Hour/Min(/Sec) selection grid shared by `TimePickerDropdown`\n * and `DateTimePickerDropdown`. The columns are built once in the constructor;\n * selection changes (clicks and {@link setTime}) re-highlight the existing\n * cells in place via {@link PickerColumn.setSelectedValue} rather than tearing\n * the grid down, so a pick never resets a scrolled column's position.\n *\n * Internal — not exported from the input barrel.\n */\nclass TimeColumns extends Component {\n\n private readonly _onChange: (hours: number, minutes: number, seconds: number) => void;\n private readonly _showSeconds: boolean;\n /** -1 means the user has not yet picked an hour. */\n private _hours: number = -1;\n /** -1 means the user has not yet picked a minute. */\n private _minutes: number = -1;\n /** -1 means the user has not yet picked a second. Always 0 when `_showSeconds` is false. */\n private _seconds: number = -1;\n private readonly _hourColumn: PickerColumn;\n private readonly _minuteColumn: PickerColumn;\n /** The Sec column, or null when `_showSeconds` is false. */\n private readonly _secondColumn: PickerColumn | null;\n\n /**\n * @param onChange - Called with `(hours, minutes, seconds)` whenever the user picks a value.\n * The `seconds` argument is always `0` when `showSeconds` is not set.\n * @param options - Optional construction-time options.\n */\n constructor(\n onChange: (hours: number, minutes: number, seconds: number) => void,\n options?: TimeColumnsOptions,\n ) {\n super({ preferredSize: { width: 0, height: TIME_COLUMNS_HEIGHT } });\n\n this._onChange = onChange;\n this._showSeconds = options?.showSeconds ?? false;\n\n this.setLayoutManager(new HBox({ spacing: 4, stretching: true }));\n\n const weight = new LayoutConstraints();\n weight.weight = 1;\n\n this._hourColumn = this.buildColumn(\"Hour\", 24, 1, value => this.onUnitSelected(\"hours\", value));\n this._minuteColumn = this.buildColumn(\"Min\", 60, 5, value => this.onUnitSelected(\"minutes\", value));\n\n this.addComponent(this._hourColumn, weight);\n this.addComponent(this._minuteColumn, weight);\n\n if (this._showSeconds) {\n this._secondColumn = this.buildColumn(\"Sec\", 60, 5, value => this.onUnitSelected(\"seconds\", value));\n this.addComponent(this._secondColumn, weight);\n } else {\n this._secondColumn = null;\n }\n }\n\n /**\n * Seeds or refreshes the highlighted cells from `value`'s time portion (or\n * clears every column when null). In place — no rebuild, no scroll change.\n *\n * @param value - The time to highlight, or null to clear the selection.\n * @returns This component, for method chaining.\n */\n setTime(value: Date | null): this {\n if (value) {\n this._hours = value.getHours();\n this._minutes = value.getMinutes();\n this._seconds = this._showSeconds ? value.getSeconds() : 0;\n } else {\n this._hours = -1;\n this._minutes = -1;\n this._seconds = -1;\n }\n\n this.refreshColumns();\n\n return this;\n }\n\n /**\n * Builds a single scrollable column, populating it with `count / step`\n * cells whose labels are zero-padded values.\n *\n * @param label - Column header text (\"Hour\" / \"Min\" / \"Sec\").\n * @param count - Exclusive upper bound of the value range (24 for hours, 60 for minutes/seconds).\n * @param step - Step between cells (1 for hours, 5 for minutes/seconds).\n * @param onSelect - Callback fired with the clicked value.\n * @returns The constructed column.\n */\n private buildColumn(\n label: string,\n count: number,\n step: number,\n onSelect: (value: number) => void,\n ): PickerColumn {\n const column = new PickerColumn(label);\n\n for (let v = 0; v < count; v += step) {\n const value = v;\n const cell = new PickerCell(String(value).padStart(2, \"0\"), () => onSelect(value));\n\n column.addCell(cell);\n }\n\n return column;\n }\n\n /**\n * Records a clicked value for one unit, defaults the other units to `0` on\n * the first interaction so the consumer always receives a complete time,\n * re-highlights the columns in place, and fires `onChange`.\n *\n * @param unit - Which unit was picked.\n * @param value - The chosen value.\n */\n private onUnitSelected(unit: \"hours\" | \"minutes\" | \"seconds\", value: number): void {\n if (unit === \"hours\") {\n this._hours = value;\n } else if (unit === \"minutes\") {\n this._minutes = value;\n } else {\n this._seconds = value;\n }\n\n if (this._hours < 0) {\n this._hours = 0;\n }\n\n if (this._minutes < 0) {\n this._minutes = 0;\n }\n\n if (this._seconds < 0) {\n this._seconds = 0;\n }\n\n this.refreshColumns();\n\n this._onChange(this._hours, this._minutes, this._showSeconds ? this._seconds : 0);\n }\n\n /**\n * Re-applies each backing field's value as the active cell highlight. A\n * value with no matching cell (e.g. a non-multiple-of-5 minute seeded from\n * an external Date) leaves that column unhighlighted, matching the exact\n * cell-label match the picker has always used.\n */\n private refreshColumns(): void {\n this._hourColumn.setSelectedValue(this.cellLabel(this._hours));\n this._minuteColumn.setSelectedValue(this.cellLabel(this._minutes));\n this._secondColumn?.setSelectedValue(this.cellLabel(this._seconds));\n }\n\n /**\n * Formats a unit value as its zero-padded cell label, or null when unset\n * (so the column clears).\n *\n * @param value - The unit value, or -1 when unset.\n * @returns The two-digit label, or null.\n */\n private cellLabel(value: number): string | null {\n return value < 0 ? null : String(value).padStart(2, \"0\");\n }\n}\n\nexport {\n TimeColumns,\n TIME_COLUMNS_HEIGHT,\n};\nexport type { TimeColumnsOptions };\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AnimatedDropdown, AnimatedDropdownOptions } from \"~/core/AnimatedDropdown.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { TimeColumns } from \"~/component/input/TimeColumns.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/** Pixel width of the time picker panel (Hour + Minute). */\nconst PANEL_WIDTH: number = 140;\n\n/** Pixel width of the time picker panel when the Seconds column is shown. */\nconst PANEL_WIDTH_SECONDS: number = 200;\n\n/** Pixel height of the time picker panel. */\nconst PANEL_HEIGHT: number = 220;\n\n/**\n * Construction-time options for {@link TimePickerDropdown}.\n *\n * @category Components\n */\nexport interface TimePickerDropdownOptions extends AnimatedDropdownOptions {\n /** When true, the picker renders a third \"Sec\" column alongside Hour and Min. Default: false. */\n showSeconds?: boolean;\n}\n\n/**\n * Floating hour/minute selector with an optional seconds column. The grid is\n * intentionally minimal (24-hour list of hours, `:00`/`:05`/`:10`/… minute\n * snaps, and matching second snaps when `showSeconds` is on); 12-hour\n * formatting and locale-aware grouping are out of scope.\n *\n * The scrollable column grid is the shared `TimeColumns` unit, built\n * once and re-highlighted in place on every pick, so selecting a value never\n * resets a scrolled column.\n *\n * Inherits the fade lifecycle from\n * [`AnimatedDropdown`](/api/core/classes/AnimatedDropdown).\n *\n * @category Components\n */\nclass TimePickerDropdown extends AnimatedDropdown<TimePickerDropdownOptions> {\n\n private readonly _showSeconds: boolean;\n /** The shared Hour/Min(/Sec) selection grid. Built once; re-highlighted in place. */\n private readonly _timeColumns: TimeColumns;\n\n /**\n * @param onSelect - Called with `(hours, minutes, seconds)` whenever the user picks a value.\n * The `seconds` argument is always `0` when the picker is not configured with `showSeconds`.\n * @param options - Optional construction-time options.\n */\n constructor(onSelect: (hours: number, minutes: number, seconds: number) => void, options?: TimePickerDropdownOptions) {\n super(options, {\n zIndex: 10050,\n layoutManager: new Fit(),\n backgroundColor: \"var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n shadow: \"var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))\",\n insets: new Insets(4, 4, 4, 4),\n });\n\n this._showSeconds = options?.showSeconds ?? false;\n\n this.getAria().setRole(\"group\");\n this.setContain(\"layout\");\n\n this._timeColumns = new TimeColumns(onSelect, { showSeconds: this._showSeconds });\n this.addComponent(this._timeColumns);\n\n // Subtree listener so the preventDefault also fires for descendant\n // targets. With plain `addListener` only events whose exact target is\n // this dropdown's element would match, which would silently bypass\n // the focus-loss guard for the cell descendants.\n Event.addSubtreeListener(this, \"pointerdown\", (e: PointerEvent) => this.onPointerDown(e));\n }\n\n /**\n * Suppresses focus loss anywhere inside the panel so the host input\n * doesn't blur before a cell click is delivered.\n *\n * @param e - The pointerdown event.\n */\n private onPointerDown(e: PointerEvent): void {\n e.preventDefault();\n }\n\n /**\n * Anchors the picker below `anchorEl`, highlights the active hour/minute\n * from `selected` (or clears the highlight when null), and plays the\n * entrance fade. The columns already exist, so the selection is updated in\n * place rather than rebuilt.\n *\n * @param anchorEl - The input the picker anchors to.\n * @param selected - The currently-selected time (Date), or null.\n */\n showAt(anchorEl: Handle, selected: Date | null): this {\n this._timeColumns.setTime(selected);\n\n this.setWidth(this._showSeconds ? PANEL_WIDTH_SECONDS : PANEL_WIDTH);\n this.setHeight(PANEL_HEIGHT);\n\n this.placeAnchored(DOM.source.getElementRect(anchorEl));\n\n // Mount before laying out: the columns are built once in the\n // constructor, so — unlike the calendar dropdown, whose show-time\n // `buildDayGrid` forces element creation — nothing here realises the\n // panel's DOM element before layout. `Fit` reads `getInnerSize`, which\n // is null until the element exists, and would size the columns to 0.\n this.showAnimated();\n\n this.doLayout();\n\n return this;\n }\n}\n\nconst TimePickerDropdownCallable = callable(TimePickerDropdown);\ntype TimePickerDropdownCallable = TimePickerDropdown;\nexport {\n TimePickerDropdown as _TimePickerDropdown,\n TimePickerDropdownCallable as TimePickerDropdown\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractPickerField, AbstractPickerFieldOptions } from \"~/component/input/AbstractPickerField.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { clock } from \"~/glyphs/solid/clock.js\";\nimport { TimePickerDropdown } from \"~/component/input/TimePickerDropdown.js\";\nimport { callable } from \"~/core/Callable.js\";\n\nGlyph.register(clock);\n\n/**\n * Construction-time options for {@link TimeField}.\n *\n * @category Components\n */\nexport interface TimeFieldOptions extends AbstractPickerFieldOptions {\n value?: Date | null;\n /** When true, the field formats and the picker exposes seconds. Default: false. */\n showSeconds?: boolean;\n}\n\n/**\n * A time-picker input component.\n *\n * Renders a text input with a clock-glyph button on the right; clicking\n * either opens a\n * [`TimePickerDropdown`](/api/component/input/classes/TimePickerDropdown)\n * panel that fades in via the shared\n * [`AnimatedDropdown`](/api/core/classes/AnimatedDropdown) lifecycle. The\n * native browser time-picker is no longer used.\n *\n * Inherits the [`Bindable`](/api/core/interfaces/Bindable) value contract,\n * change/binding listeners, and enabled/read-only surface from\n * [`AbstractPickerField`](/api/component/input/classes/AbstractPickerField).\n * The Date value uses today's date for its date portion; only hours,\n * minutes (and optionally seconds) are meaningful.\n *\n * @category Components\n */\nclass TimeField extends AbstractPickerField<Date, TimePickerDropdown, TimeFieldOptions> {\n\n constructor(options?: TimeFieldOptions) {\n super(options);\n\n // Button.setGlyph adds the glyph as the leading child of the\n // content row (with pointer-events: none) so the outer Fit centres\n // it within the button's inner rect.\n this._button.setGlyph(\"clock\");\n\n // Late-built state: `applyOptions` cached these on `_options` at\n // super-time. `showSeconds` is read into the inherited field before\n // `setValue` so the initial formatting picks up the right precision.\n // The enabled / readOnly re-dispatch is handled by the base constructor.\n if (this._options.showSeconds !== undefined) {\n this._showSeconds = this._options.showSeconds;\n }\n\n if (this._options.value !== undefined) {\n this.setValue(this._options.value);\n }\n }\n\n /**\n * Applies a {@link TimeFieldOptions} bag. Late-built fields (value,\n * showSeconds) are cached pure on `_options` here and dispatched from\n * the constructor body once `_input` exists.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TimeFieldOptions): this {\n super.applyOptions(options);\n\n if (options.showSeconds !== undefined) {\n this._options.showSeconds = options.showSeconds;\n }\n\n if (options.value !== undefined) {\n this._options.value = options.value;\n }\n\n return this;\n }\n\n /**\n * Formats a Date as an \"HH:MM\" (or \"HH:MM:SS\" when `showSeconds` is\n * true) string for display in the text input.\n *\n * @param date - The Date to format.\n * @returns The formatted time string.\n */\n protected formatValue(date: Date): string {\n const h = String(date.getHours()).padStart(2, \"0\");\n const m = String(date.getMinutes()).padStart(2, \"0\");\n\n if (this._showSeconds) {\n const s = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${h}:${m}:${s}`;\n }\n\n return `${h}:${m}`;\n }\n\n /**\n * Parses an \"HH:MM\" or \"HH:MM:SS\" string into a Date with today's date\n * portion. Returns null on parse failure.\n *\n * @param raw - The raw text typed into the input.\n * @returns The parsed Date, or null.\n */\n protected parseRaw(raw: string): Date | null {\n const [hStr, mStr, sStr] = raw.split(\":\");\n const h = Number(hStr);\n const m = Number(mStr);\n const s = sStr === undefined ? 0 : Number(sStr);\n\n const hasMinutes = mStr !== undefined && mStr !== \"\";\n const validHour = !isNaN(h) && h >= 0 && h < 24;\n const validMin = !isNaN(m) && m >= 0 && m < 60;\n const validSec = !isNaN(s) && s >= 0 && s < 60;\n\n if (!hasMinutes || !validHour || !validMin || !validSec) {\n return null;\n }\n\n const d = new Date();\n d.setHours(h, m, s, 0);\n\n return d;\n }\n\n /**\n * Builds the time dropdown with the field's selection callback and the\n * cached `showSeconds` flag.\n */\n protected createDropdown(): TimePickerDropdown {\n return new TimePickerDropdown(\n (h: number, m: number, s: number) => this.onTimeSelected(h, m, s),\n { showSeconds: this._showSeconds },\n );\n }\n\n /**\n * Adapter from the inner dropdown's `(h, m, s)` selection callback to\n * the abstract base's `(value)` shape. Builds a Date with today's date\n * portion and the selected H:M:S.\n */\n private onTimeSelected(hours: number, minutes: number, seconds: number): void {\n const d = new Date();\n d.setHours(hours, minutes, seconds, 0);\n this.onDropdownSelected(d);\n }\n\n /**\n * Called when the user picks a time from the dropdown. Commits the\n * value and re-fires `input` on the inner field so any DOM-event\n * consumer still sees the change.\n *\n * @param date - The chosen Date.\n */\n protected onDropdownSelected(date: Date): void {\n this.setValue(date);\n Event.fireEvent(this._input, \"input\");\n }\n\n /**\n * The TimeField's preferred width — chosen to fit a \"HH:MM[:SS]\" string\n * plus the 24-px glyph button without overflow at the default font size.\n */\n protected getPreferredWidth(): number {\n return 140;\n }\n}\n\nconst TimeFieldCallable = callable(TimeField);\ntype TimeFieldCallable = TimeField;\nexport {\n TimeField as _TimeField,\n TimeFieldCallable as TimeField\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport {\n AbstractCalendarDropdown,\n AbstractCalendarDropdownOptions,\n ROOT_GAP,\n} from \"~/component/input/AbstractCalendarDropdown.js\";\nimport { TimeField } from \"~/component/input/TimeField.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/** Pixel width of the combined date+time picker panel. */\nconst PANEL_WIDTH: number = 240;\n\n/**\n * Construction-time options for {@link DateTimePickerDropdown}.\n *\n * @category Components\n */\nexport interface DateTimePickerDropdownOptions extends AbstractCalendarDropdownOptions {\n /** When true, the embedded time field and its picker expose seconds. Default: false. */\n showSeconds?: boolean;\n}\n\n/**\n * Floating combined date + time picker. The date grid (month view) sits\n * above a minimal hour/minute selector.\n *\n * Inherits the shared calendar structure, keyboard contract, and year\n * scroller from [`AbstractCalendarDropdown`](/api/component/input/classes/AbstractCalendarDropdown).\n * This subclass adds an embedded\n * [`TimeField`](/api/component/input/classes/TimeField) beneath the day grid —\n * clicking it opens the floating\n * [`TimePickerDropdown`](/api/component/input/classes/TimePickerDropdown) — and\n * preserves the picked time when the user changes the calendar day or year.\n *\n * @category Components\n */\nclass DateTimePickerDropdown extends AbstractCalendarDropdown<DateTimePickerDropdownOptions> {\n\n /**\n * The embedded time field beneath the day grid. Clicking it opens a\n * floating time-picker dropdown that layers above this panel. Assigned by\n * {@link buildExtraRootChildren}, which runs during the base\n * constructor — declared with `declare` so the field initialiser\n * doesn't clobber the super-time assignment.\n */\n declare protected _timeField: TimeField;\n\n /**\n * @param onSelect - Called with the chosen `Date` whenever the user updates any field.\n * @param options - Optional construction-time options.\n */\n constructor(onSelect: (value: Date) => void, options?: DateTimePickerDropdownOptions) {\n super(onSelect, options);\n }\n\n /**\n * Applies the {@link DateTimePickerDropdownOptions} bag. `showSeconds`\n * is a pure cache write — it's read at time-field build time.\n *\n * @param options - The options bag to apply.\n */\n protected applyOptions(options: DateTimePickerDropdownOptions): this {\n super.applyOptions(options);\n\n if (options.showSeconds !== undefined) {\n this._options.showSeconds = options.showSeconds;\n }\n\n return this;\n }\n\n /**\n * Builds the embedded {@link TimeField} once and appends it to `_root`.\n * Its `change` event folds the picked time into `_value`; the field's\n * displayed value is refreshed by {@link rebuildExtraRowsAfterValueChange}.\n */\n protected buildExtraRootChildren(): void {\n this._timeField = new TimeField({ showSeconds: this.isShowingSeconds() });\n this._timeField.on(\"change\", value => this.onTimeFieldChange(value));\n this._root.addComponent(this._timeField);\n }\n\n /**\n * Re-seeds the embedded time field from the current `_value`'s time\n * portion. Called from `showAt` and after every day commit so the field\n * always reflects the stored value. `setValue` is silent (it fires no\n * `change`), so this seeding can't feed back into {@link onTimeFieldChange}.\n */\n protected rebuildExtraRowsAfterValueChange(): void {\n this._timeField.setValue(this._value);\n }\n\n /**\n * Folds a time picked in the embedded field into `_value`'s time portion,\n * seeding from today at midnight when `_value` is null, and notifies. The\n * field's value carries today's date, so only its H/M/S is read. A null\n * value (cleared field) leaves the stored time untouched.\n *\n * @param value - The time field's new value, or null when cleared.\n */\n private onTimeFieldChange(value: Date | null): void {\n if (!value) {\n return;\n }\n\n const v = this._value ?? this.todayMidnight();\n v.setHours(value.getHours(), value.getMinutes(), this.isShowingSeconds() ? value.getSeconds() : 0, 0);\n this._value = v;\n this.notifyValueChanged();\n }\n\n /**\n * Folds a clicked day into `_value` while preserving the existing\n * time portion. When `_value` is null, seeds it with the clicked\n * day at 00:00.\n *\n * @param date - The clicked day.\n */\n protected applyDateSelection(date: Date): void {\n if (!this._value) {\n this._value = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);\n } else {\n this._value.setFullYear(date.getFullYear(), date.getMonth(), date.getDate());\n }\n }\n\n /**\n * Updates `_value`'s year when the year-scroller commits, and fires\n * the change callback. Unlike DateField, picking a year *is* a\n * meaningful edit here — the calendar year is part of the value the\n * user is constructing.\n *\n * @param year - The chosen year.\n */\n protected applyYearSelection(year: number): void {\n if (this._value) {\n this._value.setFullYear(year);\n this.notifyValueChanged();\n }\n }\n\n /**\n * Returns the panel width. The embedded time field stretches to fit, so\n * the seconds option doesn't widen the panel — the day grid sets the width.\n */\n protected getPanelWidth(): number {\n return PANEL_WIDTH;\n }\n\n /**\n * Extra inner height contributed by the embedded time field: the gap above\n * it plus the field's own preferred height.\n */\n protected getExtraInnerHeight(): number {\n const fieldH = this._timeField.getPreferredSize()?.height ?? 0;\n\n return ROOT_GAP + fieldH;\n }\n\n /**\n * Reads the cached `showSeconds` flag.\n *\n * @returns True when the embedded time field and its picker expose seconds.\n */\n private isShowingSeconds(): boolean {\n return this._options.showSeconds ?? false;\n }\n\n /**\n * Returns today's date at 00:00:00.000, used as the seed when the\n * user picks a time before picking a day.\n *\n * @returns A new `Date` for today at midnight.\n */\n private todayMidnight(): Date {\n const now = new Date();\n\n return new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0);\n }\n}\n\nconst DateTimePickerDropdownCallable = callable(DateTimePickerDropdown);\ntype DateTimePickerDropdownCallable = DateTimePickerDropdown;\nexport {\n DateTimePickerDropdown as _DateTimePickerDropdown,\n DateTimePickerDropdownCallable as DateTimePickerDropdown\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Animation } from \"~/core/Animation.js\";\nimport { AbstractBooleanInput, AbstractBooleanInputOptions } from \"~/component/input/AbstractBooleanInput.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { HBox } from \"~/layout/HBox.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { check } from \"~/glyphs/solid/check.js\";\n\n// Idempotent registration: the registry tolerates re-registration of the same\n// glyph definition, and this side-effect import lets Checkbox stand on its own\n// without an outside-the-class `Glyph.register` call.\nGlyph.register(check);\n\n/**\n * Construction-time options for {@link Checkbox}.\n *\n * @category Components\n */\nexport interface CheckboxOptions extends AbstractBooleanInputOptions {\n selected?: boolean;\n value?: boolean;\n indeterminate?: boolean;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * checkbox's `action` shorthand to the inherited `change` / `binding`.\n */\n listeners?: {\n action?: () => void;\n change?: (value: boolean) => void;\n binding?: () => void;\n };\n}\n\n/**\n * A custom-drawn checkbox rendered as a focusable `<div>` with `role=\"checkbox\"`.\n *\n * The control owns a small `<div>` box that hosts a check {@link Glyph}; when\n * `indeterminate` is set, a horizontal bar replaces the check. The native\n * `<input type=\"checkbox\">` is intentionally not used so the visual is fully\n * themable through the shared `--ts-ui-form-*` and per-control checkbox tokens.\n *\n * @category Components\n */\nclass Checkbox<TOptions extends CheckboxOptions = CheckboxOptions>\n extends AbstractBooleanInput<TOptions>\n{\n private _box: Component;\n private _check: Glyph;\n private _dash: Component;\n\n /**\n * Constructs a Checkbox.\n *\n * @param options - Optional construction-time options.\n */\n constructor(options?: TOptions) {\n super({ ...(options ?? {}) } as TOptions);\n\n this.setLayoutManager(new HBox());\n\n this._box = new Component();\n this._box.setPreferredSize({ width: 16, height: 16 });\n // Min = preferred = max so the outer HBox shrink-on-overallocation\n // can't collapse the box graphic when the checkbox sits next to\n // flexible siblings.\n this._box.setMinSize({ width: 16, height: 16 });\n this._box.setMaxSize({ width: 16, height: 16 });\n this._box.setSize({ width: 16, height: 16 });\n this._box.setBackgroundColor(\"var(--ts-ui-checkbox-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))\");\n this._box.setBorder(\"1px solid var(--ts-ui-form-border, rgb(160, 160, 160))\");\n this._box.setBorderRadius(\"var(--ts-ui-checkbox-radius, 3px)\");\n // The box owns the click + cursor surface so the pointer/click area\n // matches the visible graphic exactly. The root stays inert (default\n // cursor, no click listener), so clicks on the label or on stretched\n // empty space don't toggle and don't show the pointer cursor.\n this._box.setCursor(\"pointer\");\n\n this._check = new Glyph(\"check\");\n this._check.setForegroundColor(\"var(--ts-ui-checkbox-check-color, rgb(255, 255, 255))\");\n this._check.setPreferredSize({ width: 12, height: 12 });\n this._check.setMaxSize({ width: 12, height: 12 });\n // With box-sizing: border-box and the 1px box border, absolute children\n // are positioned relative to the 14×14 padding edge — so centering a\n // 12×12 glyph inside the 16×16 visible box means (14−12)/2 = 1, not 2.\n this._check.setX(1);\n this._check.setY(1);\n this._check.setOpacity(0);\n // Pass-through so clicks on the glyph still hit the box underneath.\n this._check.setPointerEvents(\"none\");\n\n this._dash = new Component();\n this._dash.setBackgroundColor(\"var(--ts-ui-checkbox-check-color, rgb(255, 255, 255))\");\n this._dash.setPreferredSize({ width: 8, height: 2 });\n this._dash.setMaxSize({ width: 8, height: 2 });\n this._dash.setSize({ width: 8, height: 2 });\n this._dash.setX(3);\n this._dash.setY(6);\n this._dash.setOpacity(0);\n this._dash.setPointerEvents(\"none\");\n\n if (!Animation.isReducedMotion()) {\n this._check.setTransition(\"opacity 120ms ease-out\");\n this._dash.setTransition(\"opacity 120ms ease-out\");\n this._box.setTransition(\"background-color 120ms ease-out, border-color 120ms ease-out\");\n }\n\n this._box.addComponent(this._check);\n this._box.addComponent(this._dash);\n super.addComponent(this._box);\n\n this.getAria().setRole(\"checkbox\");\n this.getAria().setTabIndex(0);\n this.getAria().setChecked(false);\n\n this.setOutline(\"none\");\n\n // The box owns the user-toggle click so the pointer/click + cursor\n // surface is exactly the visible 16 × 16 graphic — clicks on a label or\n // in any stretched empty area pass through to the root, which has no\n // listener of its own. This pointer line stays per-subclass (a closure\n // over the widget `this`) because a listener registered on the child\n // box would otherwise bind `this` to the box; only the keyboard path,\n // registered on the root, moves into the base.\n Event.addListener(this._box, \"click\", () => this.activateFromPointer());\n this.installKeyboard();\n\n if (this._options.value !== undefined && this._options.selected === undefined) {\n this._options.selected = this._options.value;\n }\n\n if (this._options.selected !== undefined) {\n this.applySelected(this._options.selected, this._options.indeterminate ?? false);\n }\n\n if (this._options.indeterminate !== undefined) {\n this.applySelected(this._options.selected ?? false, this._options.indeterminate);\n }\n\n if (this._options.label !== undefined) {\n this.applyLabel(this._options.label);\n }\n\n if (this._options.enabled !== undefined) {\n this.applyEnabled(this._options.enabled);\n }\n\n if (this._options.readOnly !== undefined) {\n this.applyReadOnly(this._options.readOnly);\n }\n }\n\n /**\n * Applies a {@link CheckboxOptions} bag. Inherited Component fields cascade\n * through `super.applyOptions`; checkbox-specific fields are stored pure on\n * `_options` so the constructor body can dispatch them after children are\n * built.\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @returns This component, for method chaining.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.selected !== undefined) this._options.selected = options.selected;\n if (options.value !== undefined) this._options.value = options.value;\n if (options.indeterminate !== undefined) this._options.indeterminate = options.indeterminate;\n if (options.label !== undefined) this._options.label = options.label;\n if (options.enabled !== undefined) this._options.enabled = options.enabled;\n if (options.readOnly !== undefined) this._options.readOnly = options.readOnly;\n\n return this;\n }\n\n /**\n * Activates the checkbox from a click or key: a user activation from the\n * \"mixed\" state first clears the indeterminate flag and selects (WAI-ARIA);\n * otherwise it flips the selected state. `setSelected` handles the visual +\n * listener sync — calling it from a mixed state always lands at\n * `selected=true` because its guard treats indeterminate as a force-out.\n * The enabled/read-only guard is applied by the base before this runs.\n */\n protected activate(): void {\n if (this.isIndeterminate()) {\n this.setSelected(true);\n\n return;\n }\n\n this.setSelected(!this.isSelected());\n }\n\n /**\n * Returns the inner box graphic — the click + cursor surface.\n *\n * @returns The box component.\n */\n protected getInteractiveSurface(): Component {\n return this._box;\n }\n\n /**\n * Returns whether the checkbox is currently selected.\n *\n * @returns `true` when checked.\n */\n isSelected(): boolean {\n return this._options.selected ?? false;\n }\n\n /**\n * Sets the checked state. Notifies change and binding listeners on a real\n * transition; no-op when unchanged.\n *\n * @param value - `true` to check, `false` to uncheck.\n *\n * @returns This component, for method chaining.\n */\n setSelected(value: boolean): this {\n const next = !!value;\n if (next === this.isSelected() && !this.isIndeterminate()) {\n return this;\n }\n\n this._options.selected = next;\n this._options.indeterminate = false;\n this.applySelected(next, false);\n this.notifyChange(next);\n\n // Existing consumers wire \"click\"-based behaviour through `on(\"action\", fn)`,\n // so synthesize a \"click\" on the root so a programmatic state flip\n // continues to fire it. The user-toggle handler lives on `_box`, not\n // the root, so this synthetic event no longer races back into the\n // toggle path. Skip the synthetic click pre-mount — listeners haven't\n // attached yet and `fireEvent` would throw on the missing element.\n if (this.getElement()) {\n Event.fireEvent(this, \"click\");\n } else {\n console.warn(\"Checkbox '\" + this.getId() + \"' setSelected before mount; synthetic 'click' skipped.\");\n }\n\n return this;\n }\n\n /**\n * Returns the current value (alias for {@link isSelected}, satisfies\n * [`Bindable`](/api/core/interfaces/Bindable)).\n *\n * @returns `true` when checked.\n */\n getValue(): boolean {\n return this.isSelected();\n }\n\n /**\n * Sets the value (alias for {@link setSelected}, satisfies [`Bindable`](/api/core/interfaces/Bindable)).\n *\n * @param value - The new boolean state.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: boolean): this {\n return this.setSelected(value);\n }\n\n /**\n * Returns whether the checkbox is in the mixed (`indeterminate`) state.\n *\n * @returns `true` when indeterminate.\n */\n isIndeterminate(): boolean {\n return this._options.indeterminate ?? false;\n }\n\n /**\n * Toggles the mixed (`indeterminate`) state. Setting `true` overrides the\n * visible check with a horizontal bar and announces `aria-checked=\"mixed\"`.\n *\n * @param value - `true` to enter the mixed state, `false` to leave it.\n *\n * @returns This component, for method chaining.\n */\n setIndeterminate(value: boolean): this {\n const next = !!value;\n if (next === this.isIndeterminate()) {\n return this;\n }\n\n this._options.indeterminate = next;\n this.applySelected(this.isSelected(), next);\n\n return this;\n }\n\n /**\n * Enables or disables the 120 ms check/fill CSS transition. Disabled\n * checkboxes still update their visual state instantly. Used by\n * `BooleanCell` to suppress the per-rebind transition flash when a\n * virtualized table re-binds many cells per scroll frame.\n *\n * @param value - `true` to keep the transition (default), `false` to remove it.\n */\n setAnimated(value: boolean): this {\n const t = value && !Animation.isReducedMotion();\n\n this._check.setTransition(t ? \"opacity 120ms ease-out\" : \"none\");\n this._dash .setTransition(t ? \"opacity 120ms ease-out\" : \"none\");\n this._box .setTransition(t ? \"background-color 120ms ease-out, border-color 120ms ease-out\" : \"none\");\n\n return this;\n }\n\n /**\n * Registers a listener for one of this checkbox's events. `\"action\"` is a\n * typed semantic shorthand over {@link Event.addListener} for the native\n * click (used e.g. by the [`BooleanEditor`](/api/component/table/cell/editor/classes/BooleanEditor)\n * cell editor); `\"change\"` and `\"binding\"` are the inherited\n * {@link AbstractInput} listener-bag events.\n *\n * @param event - The event name.\n * @param listener - Callback invoked when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"action\", listener: Event.Listener): this;\n on(event: \"change\", listener: (value: boolean) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.addListener(this, \"click\", listener as Event.Listener);\n\n return this;\n }\n\n return super.on(event as \"change\", listener as (value: boolean) => void);\n }\n\n /**\n * Removes a previously registered listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n if (event === \"action\") {\n Event.removeListener(this, \"click\", listener as Event.Listener);\n\n return this;\n }\n\n return super.off(event, listener);\n }\n\n /**\n * Updates the visual + ARIA state for a (selected, indeterminate) pair.\n */\n private applySelected(selected: boolean, indeterminate: boolean): void {\n if (indeterminate) {\n this.getAria().setChecked(\"mixed\");\n } else {\n this.getAria().setChecked(selected);\n }\n\n const fill = indeterminate\n ? \"var(--ts-ui-checkbox-bg-indeterminate, rgb(160, 160, 160))\"\n : selected\n ? \"var(--ts-ui-checkbox-bg-selected, rgb(30, 100, 200))\"\n : \"var(--ts-ui-checkbox-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))\";\n const border = selected || indeterminate\n ? \"1px solid \" + (indeterminate\n ? \"var(--ts-ui-checkbox-bg-indeterminate, rgb(160, 160, 160))\"\n : \"var(--ts-ui-checkbox-bg-selected, rgb(30, 100, 200))\")\n : \"1px solid var(--ts-ui-form-border, rgb(160, 160, 160))\";\n\n this._box.setBackgroundColor(fill);\n this._box.setBorder(border);\n\n this._check.setOpacity(selected && !indeterminate ? 1 : 0);\n this._dash.setOpacity(indeterminate ? 1 : 0);\n }\n\n}\n\nconst CheckboxCallable = callable(Checkbox);\ntype CheckboxCallable<TOptions extends CheckboxOptions = CheckboxOptions> = Checkbox<TOptions>;\nexport {\n Checkbox as _Checkbox,\n CheckboxCallable as Checkbox\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { AnimatedDropdown, AnimatedDropdownOptions } from \"~/core/AnimatedDropdown.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { AbstractStore } from \"~/data/AbstractStore.js\";\nimport { ModelRecord } from \"~/data/ModelRecord.js\";\nimport { SelectableListItem, SelectableListItemSpec } from \"~/component/list/AbstractSelectableList.js\";\nimport { ListItemRenderer } from \"~/component/list/ListItemRenderer.js\";\nimport { LabelListItemRenderer } from \"~/component/list/renderer/Label.js\";\nimport { List } from \"~/component/list/List.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { Glyph } from \"~/component/display/Glyph.js\";\nimport { chevron_down } from \"~/glyphs/solid/chevron_down.js\";\nimport { callable } from \"~/core/Callable.js\";\n\nGlyph.register(chevron_down);\n\n/**\n * Construction-time options for {@link ComboBox}.\n *\n * @category Components\n */\nexport interface ComboBoxOptions extends AbstractInputOptions {\n // Matches `setItems` (SelectableListItemSpec = a plain-string key or a\n // { key, label } item), so an options-bag `items` accepts the same shapes the\n // runtime setter does — a plain-string list or explicit keyed items.\n items?: SelectableListItemSpec | Array<SelectableListItemSpec>;\n store?: AbstractStore;\n displayField?: string;\n valueField?: string;\n /**\n * Record field whose value becomes each store-bound option's `glyph`, read\n * by [`GlyphListItemRenderer`](/api/component/list/classes/GlyphListItemRenderer).\n * Forwarded to the embedded list's `glyphField`.\n */\n glyphField?: string;\n /**\n * Zero-argument factory producing the renderer for each dropdown row and\n * the collapsed control. Defaults to a label renderer. Supply\n * `() => new GlyphListItemRenderer()` to show each option's `glyph` in both\n * the open dropdown and on the closed combo box.\n */\n rendererFactory?: () => ListItemRenderer;\n selectedIndex?: number;\n value?: string;\n selectedItem?: string;\n /** When false, the dropdown opens/closes instantly. Default: true. */\n dropdownAnimated?: boolean;\n /**\n * Lower bound (in pixels) on the dropdown width. Defaults to `200`. The\n * dropdown sizes to the widest label by default and is floored at the\n * input's width; this floor additionally guarantees the panel is at\n * least this wide even when both the input and the widest label are\n * narrower. Long labels that exceed it still widen the dropdown further\n * (capped at the viewport).\n */\n dropdownMinWidth?: number;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * combo box's `action` shorthand to the inherited `change` / `binding`.\n */\n listeners?: {\n action?: () => void;\n change?: (value: string) => void;\n binding?: () => void;\n };\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * The cascade in `Component`'s constructor dispatches each setter once with\n * the final value, so any field the caller supplied wins.\n */\nconst _defaultComboBoxOptions: Partial<ComboBoxOptions> = {\n tag: \"div\",\n backgroundColor: \"var(--ts-ui-input-bg, rgb(255, 255, 255))\",\n foregroundColor: \"var(--ts-ui-text-color, black)\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n cursor: \"pointer\",\n insets: new Insets(3, 6, 3, 6),\n};\n\n/**\n * Floating dropdown that lists the parent {@link ComboBox}'s options. Inherits\n * fade lifecycle from [`AnimatedDropdown`](/api/core/classes/AnimatedDropdown).\n *\n * @category Components\n */\n/** Maximum dropdown height in pixels. Long option lists scroll inside this cap. */\nconst COMBOBOX_DROPDOWN_MAX_HEIGHT_PX = 200;\n\n/** Pixel height of a single row inside the dropdown. Matches `SelectableListRow`'s cached `preferredSize(0, 22)`. */\nconst COMBOBOX_DROPDOWN_ROW_HEIGHT_PX = 22;\n\n/** Combined left + right padding inside a `SelectableListRow` (Insets(0, 8, 0, 8)). */\nconst COMBOBOX_DROPDOWN_ROW_PADDING_PX = 16;\n\n/**\n * Default lower bound on dropdown width. Ensures the panel is always at least\n * this wide even when both the input and the widest label are narrower;\n * override per-instance via {@link ComboBox.setDropdownMinWidth} or\n * `dropdownMinWidth` in the options bag.\n */\nconst COMBOBOX_DROPDOWN_MIN_WIDTH_PX = 200;\n\nclass ComboBoxDropdown extends AnimatedDropdown<AnimatedDropdownOptions> {\n\n /**\n * Inner [`List`](/api/component/list/classes/List) hosting the option rows.\n * The list owns the row pool, the keyboard model (ArrowUp/Down /\n * Home/End / PageUp/Down / Enter / Space / type-ahead), the ARIA\n * `option`-role wiring, and the per-row hover / selected / focused\n * chrome. The dropdown wrapper handles only the overlay lifecycle\n * (fade, anchored positioning, viewport clamp) and the\n * dropdown-specific width math.\n */\n private readonly _list: List;\n /** Lower bound on the dropdown width — see `COMBOBOX_DROPDOWN_MIN_WIDTH_PX`. */\n private _minWidth: number = COMBOBOX_DROPDOWN_MIN_WIDTH_PX;\n\n /**\n * @param onSelect - Called with the index of the row the user picked.\n * Fired on click (`SelectableListRow.onClick`) and on Enter / Space\n * forwarded into the inner list — both paths route through the\n * list's `change` event.\n */\n constructor(onSelect: (index: number) => void) {\n super(undefined, {\n layoutManager: new Fit(),\n backgroundColor: \"var(--ts-ui-autocomplete-bg, rgb(255, 255, 255))\",\n border: \"var(--ts-ui-input-border)\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n shadow: \"var(--ts-ui-autocomplete-shadow, 2px 4px 8px rgba(0,0,0,0.15))\",\n });\n\n // The inner List already exposes `role=\"listbox\"` from\n // `AbstractSelectableList`; the dropdown wrapper just provides the\n // overlay chrome and must not duplicate the listbox role\n // (nested listboxes break assistive-tech enumeration of the\n // `option` rows).\n this.setContain(\"layout\");\n\n // `Fit` makes the inner list fill the dropdown's content box. The\n // list's own border is stripped — the dropdown root carries the\n // visible chrome (border + radius + shadow) so the two never\n // double-stack. Focus-on-row-click is disabled because the host\n // ComboBox keeps DOM focus throughout the dropdown's lifetime;\n // letting the list grab focus on a row click would blur a\n // wrapping cell-editor / picker input and tear down the parent\n // overlay before `onRowSelected` runs `closeDropdown`.\n this._list = new List();\n this._list.setBorder(\"none\");\n this._list.setBorderRadius(\"0\");\n this._list.setFocusOnRowClick(false);\n this.addComponent(this._list);\n\n // Click and keyboard commits both arrive through the list's\n // `change` event (fired by `notifyUserChange` after the click /\n // keyboard reducer mutates the selection set). Programmatic\n // writes (`setItemsArray`, `setSelectedIndex(idx, false)` used\n // by `showAt`) bypass this path, so re-opening the dropdown\n // doesn't trigger a spurious commit.\n this._list.on(\"action\", () => onSelect(this._list.getSelectedIndex()));\n }\n\n /**\n * Forwards a keystroke from the host {@link ComboBox} (which keeps\n * DOM focus while the dropdown is open) into the inner list's\n * keyboard reducer. Mirrors {@link AnimatedDropdown.handleKey}.\n * Returns `true` when the list consumed the key so the host can\n * `preventDefault` and stop further processing.\n *\n * Keeping focus on the host (rather than calling `_list.focus()`\n * when the dropdown opens) is what lets a ComboBox embedded inside\n * a wrapping picker (e.g. the time selects inside\n * `DateTimePickerDropdown`, especially in a table-cell variant)\n * avoid stealing focus from the parent's input — a programmatic\n * focus shift bypasses the parent's `pointerdown.preventDefault`\n * focus-loss guard.\n *\n * @param e - The keyboard event captured by the host.\n *\n * @returns `true` when the list consumed the key.\n */\n handleKey(e: KeyboardEvent): boolean {\n return this._list.handleKey(e);\n }\n\n /**\n * Replaces the rendered row list with one entry per item, seeds the\n * inner list's selection from `selectedIndex`, and lays out the panel\n * anchored below `anchorEl`. The dropdown height is capped at\n * {@link COMBOBOX_DROPDOWN_MAX_HEIGHT_PX} so long option lists\n * scroll inside the panel rather than overflowing the viewport.\n *\n * @param anchorEl - Element the dropdown is anchored to.\n * @param items - The option pairs to display.\n * @param selectedIndex - The row to seed as currently selected, or\n * `-1` for no initial selection.\n */\n showAt(anchorEl: Handle, items: Array<SelectableListItem>, selectedIndex: number): this {\n this.pauseLayout();\n this._list.setItemsArray(items);\n this._list.setSelectedIndex(selectedIndex, false);\n this.resumeLayout();\n\n // Add the dropdown's border to the natural row stack so the inner List\n // (which receives `outerHeight - border`) has room for the rows without\n // overflowing by 2 px and triggering an unnecessary scrollbar.\n const perim = this.getPerimeterSize();\n const chromeH = perim.top + perim.bottom;\n const chromeW = perim.left + perim.right;\n const naturalH = items.length * COMBOBOX_DROPDOWN_ROW_HEIGHT_PX + chromeH;\n const panelH = Math.min(naturalH, COMBOBOX_DROPDOWN_MAX_HEIGHT_PX);\n const rect = DOM.source.getElementRect(anchorEl);\n\n // Dropdown lives outside the host's layout tree (overlay on\n // documentElement), so it isn't bound to the anchor's width.\n //\n // Sizing model:\n // floor = anchor.width (never narrower than input)\n // ceiling = max(anchor.width, _minWidth) (configured floor widens it\n // when the input is narrow,\n // but a wide input is the cap\n // — labels beyond it truncate)\n // width = clamp(naturalLabelWidth, floor, ceiling), capped at viewport\n const labelW = this.measureWidestLabel(items);\n const naturalW = labelW + COMBOBOX_DROPDOWN_ROW_PADDING_PX + chromeW;\n const floorW = rect.width;\n const ceilingW = Math.max(rect.width, this._minWidth);\n const dropdownW = Math.min(Math.max(naturalW, floorW), ceilingW, DOM.source.getViewportSize().width);\n\n this.setWidth(dropdownW);\n this.setHeight(panelH);\n\n this.placeAnchored(rect);\n\n this.showAnimated();\n\n // VBox-backed list positions rows via framework setters that no-op\n // while the dropdown element is detached. Run the layout pass\n // after `showAnimated` mounts the panel so rows land at the\n // correct y offsets on first open.\n this.doLayout();\n\n // Focus stays on the host ComboBox — `ComboBox.onKeyDown`\n // forwards keystrokes into `handleKey` so the list's keyboard\n // reducer runs without a DOM focus shift. Programmatically\n // focusing the list would blur whatever held focus before the\n // dropdown opened (a wrapping table-cell editor's input, the\n // parent picker's text input, …) and tear down the host above\n // us.\n return this;\n }\n\n /**\n * Sets the lower bound applied to the dropdown width. The dropdown is\n * always rendered at least this wide; if the widest label or the input\n * is wider, the dropdown grows beyond this floor.\n *\n * @param px - The minimum width in pixels.\n *\n * @returns This dropdown, for method chaining.\n */\n setMinWidth(px: number): this {\n this._minWidth = px;\n\n return this;\n }\n\n /**\n * Returns the configured lower bound on the dropdown width.\n *\n * @returns The minimum width in pixels.\n */\n getMinWidth(): number {\n return this._minWidth;\n }\n\n /**\n * Returns the inner [`List`](/api/component/list/classes/List) so the\n * host can forward store binding, value writes, and other list-side\n * operations directly. Used by [`ComboBox.setStore`](/api/component/input/classes/ComboBox#setstore)\n * to mirror its store onto the embedded list.\n *\n * @returns The hosted list instance.\n */\n getList(): List {\n return this._list;\n }\n\n /**\n * Returns the widest label measured at the row's font, in pixels. Used to\n * size the dropdown wide enough to display the longest entry without\n * truncation (capped at the viewport in `showAt`).\n *\n * @param items - The items to measure (only `label` is read).\n *\n * @returns The maximum measured width across all labels, or `0` when empty.\n */\n private measureWidestLabel(items: Array<SelectableListItem>): number {\n let max = 0;\n\n for (const item of items) {\n const w = Util.measureTextWidth(item.label);\n if (w > max) {\n max = w;\n }\n }\n\n return max;\n }\n}\n\n// Static typography for the ComboBox surface. Layout (label + caret\n// placement) is handled by the framework's HBox manager so no class\n// rule needs to write `display: flex` here. The dropdown's row chrome\n// comes from the shared `.SelectableListRow` / `.SelectableListRow:hover` /\n// `.SelectableListRow.selected` / `.SelectableListRow.focused` rules in\n// AbstractSelectableList — no ComboBox-side row styling is required.\n(() => {\n new StyleRule({\n scope: \"class\",\n name: \"ComboBox\",\n styles: {\n userSelect: \"none\",\n whiteSpace: \"nowrap\",\n },\n });\n\n // No `flex` here — `HBox` sizes the label component directly. `overflow`\n // and `text-overflow` keep long labels truncating with an ellipsis when\n // HBox clamps the label width to fit the row.\n new StyleRule({\n scope: \"class\",\n name: \"ComboBoxLabel\",\n styles: {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n },\n });\n\n // The dropdown wrapper already carries the visible chrome (border /\n // radius / shadow); the embedded List inherits a `:focus::after`\n // ring from `AbstractSelectableList`, which would paint a second ring\n // inside the dropdown when it takes focus on open. Suppress the\n // pseudo so the dropdown chrome reads as a single surface.\n new StyleRule({\n scope: \"selector\",\n name: \".ComboBoxDropdown .List:focus::after\",\n styles: {\n content: \"none\",\n },\n });\n})();\n\n/**\n * The visible label `<span>` inside a {@link ComboBox}. Hosts one\n * {@link ListItemRenderer} — built from the ComboBox's renderer factory — so\n * the collapsed control renders the selected entry exactly as the dropdown row\n * does (a glyph renderer shows the selected option's glyph here too). Positioned\n * by the parent `ComboBox`'s `doLayout` (flush left, taking the row's remaining\n * width after the fixed-size caret); the label's own `doLayout` forwards its box\n * to the renderer. Rendered `pointer-events: none` so clicks fall through to the\n * ComboBox surface that toggles the dropdown.\n */\nclass ComboBoxLabel extends Component {\n private _lineHeight: string | null = null;\n /** The renderer painting the selected entry on the collapsed control. */\n private _renderer: ListItemRenderer;\n\n /**\n * @param rendererFactory - Zero-argument factory producing this label's\n * content renderer, shared with the dropdown list.\n */\n constructor(rendererFactory: () => ListItemRenderer) {\n super({ tag: \"span\" });\n this.setPointerEvents(\"none\");\n\n this._renderer = rendererFactory();\n }\n\n /**\n * Rebinds the hosted renderer to the selected item. The empty /\n * no-selection state passes a blank item (`{ key: \"\", label: \"\" }`) at\n * index `-1`, so the label renders empty and a glyph renderer shows no\n * glyph.\n *\n * @param item - The selected item, or the blank item when nothing is\n * selected.\n * @param index - The selected index, or `-1`.\n *\n * @returns This component, for method chaining.\n */\n setItem(item: SelectableListItem, index: number): this {\n this._renderer.update({ item, index });\n\n return this;\n }\n\n /**\n * Swaps in a new content renderer, re-skinning the collapsed control in\n * step with the dropdown when the ComboBox's renderer factory changes.\n *\n * @param renderer - The replacement renderer.\n *\n * @returns This component, for method chaining.\n */\n setRenderer(renderer: ListItemRenderer): this {\n const el = this.getElement();\n\n if (el) {\n const oldEl = this._renderer.getElement();\n if (oldEl && DOM.source.getParentNode(oldEl) === el) {\n DOM.sink.removeChild(el, oldEl);\n }\n }\n\n this._renderer = renderer;\n\n if (el) {\n DOM.sink.appendChild(el, this._renderer.getElement(true)!);\n }\n\n return this;\n }\n\n /**\n * Sets the CSS `line-height` so a single line of label text vertically\n * centers within the label's allocated height. Numeric values are stored\n * with a `\"px\"` suffix; string values pass through unchanged. Retained\n * because `ComboBox.doLayout` still drives it; the hosted label renderer\n * also matches its own line-height to the box in `layoutChildren`, so the\n * collapsed line stays centred either way.\n *\n * @param value - A pixel count (number) or a CSS line-height string.\n *\n * @returns This component, for method chaining.\n */\n setLineHeight(value: number | string): this {\n this._lineHeight = typeof value === \"number\" ? value + \"px\" : value;\n\n this.setElementCSSRule(\"lineHeight\", this._lineHeight);\n\n return this;\n }\n\n /**\n * Returns the cached CSS `line-height` value, or null when unset.\n *\n * @returns The line-height string (e.g. `\"22px\"`), or null.\n */\n getLineHeight(): string | null {\n return this._lineHeight;\n }\n\n /**\n * Appends the renderer's element to the label DOM. The renderer's own\n * children (label, optional glyph) are appended by the renderer's `init`.\n *\n * @param element - Optional element passed by the rendering pipeline; falls\n * back to getElement().\n *\n * @returns This component, for method chaining.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (el) {\n DOM.sink.appendChild(el, this._renderer.getElement(true)!);\n }\n\n return this;\n }\n\n /**\n * Sizes the renderer to fill the label box, then lets it lay out its own\n * children. Only writes setters (no geometry reads).\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const width = this.getWidth();\n const height = this.getHeight();\n\n this._renderer.setAutoCommitStyle(false);\n this._renderer.setX(0);\n this._renderer.setY(0);\n this._renderer.setWidth(width);\n this._renderer.setHeight(height);\n this._renderer.setAutoCommitStyle(true);\n\n this._renderer.layoutChildren(width, height);\n\n return this;\n }\n}\n\n/**\n * The fixed-size caret container inside a {@link ComboBox}. Framework-absolute\n * (the default) so the caret's own inline `left`/`top` from `ComboBox.doLayout`\n * pins it relative to the ComboBox padding box, not its in-flow position\n * (which would otherwise be offset by the parent's padding-left and push the\n * caret past the right edge into `overflow: hidden`).\n */\nclass ComboBoxCaret extends Component {\n private _glyph: Glyph = new Glyph(\"chevron-down\");\n private _size: number;\n\n constructor() {\n super({ tag: \"span\" });\n // Size the caret to the field's text font so the chevron matches the\n // trigger icons of sibling fields (DateField/TimeField), whose\n // Button-hosted glyphs already sync to the text line. A bare Glyph\n // otherwise keeps its static 16×16 default and renders visibly larger\n // than every other field icon. Lock min == max so the box stays square\n // regardless of content (the glyph child contributes no intrinsic\n // height); the glyph fills the box so it centres trivially.\n this._size = Util.lineHeightPx({ linePadding: false });\n this.setMinSize({ width: this._size, height: this._size });\n this.setMaxSize({ width: this._size, height: this._size });\n this.setPointerEvents(\"none\");\n\n this._glyph.setPreferredSize({ width: this._size, height: this._size });\n this._glyph.setPointerEvents(\"none\");\n this.addComponent(this._glyph);\n }\n\n /**\n * Returns the square caret box size in pixels (the field's text font size),\n * so the owning {@link ComboBox}'s layout reserves a matching caret column.\n *\n * @returns The caret box edge length in pixels.\n */\n getCaretSize(): number {\n return this._size;\n }\n\n /**\n * Exposes the trigger glyph so the owning {@link ComboBox} can rotate it in\n * step with the dropdown's open / close animation.\n *\n * @returns The chevron glyph centered in the caret box.\n */\n getGlyph(): Glyph {\n return this._glyph;\n }\n}\n\n/**\n * A drop-down combo box backed by a styled `<div>` surface and an\n * `AnimatedDropdown` panel.\n *\n * Manages an internal list of [`SelectableListItem`](/api/component/list/interfaces/SelectableListItem) entries and an active selection.\n * Also accepts an {@link AbstractStore} via {@link setStore} to populate\n * options from the data layer. The dropdown fades in / out using the shared\n * `AnimatedDropdown` lifecycle; pass `dropdownAnimated: false` (or call\n * {@link setDropdownAnimated}) to bypass the fade.\n *\n * @example\n * ```typescript\n * import { ComboBox } from '@jimka/typescript-ui/component/input';\n *\n * const combo = new ComboBox({ items: ['Admin', 'User'] });\n * panel.addComponent(combo);\n * ```\n *\n * @category Components\n */\nclass ComboBox<TOptions extends ComboBoxOptions = ComboBoxOptions> extends AbstractInput<string, TOptions> {\n\n private readonly _dropdown: ComboBoxDropdown;\n private _label: ComboBoxLabel;\n private _caret: ComboBoxCaret;\n /**\n * Cached value passed to {@link setValue} before items / store are\n * available. The inner list silently drops unknown keys (its\n * `findIndex` returns -1 and clears the selection), so this field\n * holds the pending key until an items-load resolves it.\n */\n private _pendingValue: string | null = null;\n /** The store currently subscribed for option refreshes, or null. */\n private _boundStore: AbstractStore | null = null;\n /** Handler re-asserting selection + label after the inner list rebuilds from a store event. */\n private readonly _onStoreRefresh: () => void;\n\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?: ComboBoxOptions, subclassDefaults?: Partial<ComboBoxOptions>);\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n super(\n options,\n { ..._defaultComboBoxOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n this.getAria().setRole(\"combobox\");\n this.getAria().setExpanded(false);\n this.getAria().setTabIndex(0);\n\n this._label = new ComboBoxLabel(this._options.rendererFactory ?? (() => new LabelListItemRenderer()));\n this._caret = new ComboBoxCaret();\n this.addComponent(this._label);\n this.addComponent(this._caret);\n\n // Eager dropdown construction: the inner List now owns every items /\n // selection / store-binding state and must exist before the\n // late-dispatch block below routes `setItems` / `setValue` /\n // `setStore` / `setSelectedIndex` into it. The dropdown's outer\n // `<div>` is still lazy (built by `getElement(true)` on first show),\n // and the list's row DOM only mounts when the dropdown root mounts,\n // so the net cost is three JS instances and one `Fit` layout.\n this._dropdown = new ComboBoxDropdown(idx => this.onRowSelected(idx));\n\n // Forward the dropdown-specific options that were captured pure by\n // `applyOptions`. These run unconditionally now that the dropdown\n // is always present.\n if (this._options.dropdownAnimated !== undefined) {\n this._dropdown.setAnimated(this._options.dropdownAnimated);\n }\n if (this._options.dropdownMinWidth !== undefined) {\n this._dropdown.setMinWidth(this._options.dropdownMinWidth);\n }\n\n // Forward the renderer factory onto the embedded list before the\n // items / store late-dispatch so the first row build already paints\n // through it. The collapsed `_label` was constructed with the same\n // factory above.\n if (this._options.rendererFactory !== undefined) {\n this._dropdown.getList().setRendererFactory(this._options.rendererFactory);\n }\n\n this.refreshLabel();\n\n this.updateHeight();\n this.subscribeTheme(() => this.updateHeight());\n\n Event.addListener(this, \"click\", () => this.toggleDropdown());\n Event.addListener(this, \"keydown\", (e: KeyboardEvent) => this.onKeyDown(e));\n\n // The manager closes the dropdown on an outside click via its\n // \"click-outside\" mode; route that through closeDropdown. The anchor\n // (the ComboBox surface, excluded so the toggle click doesn't\n // re-close) is set lazily in toggleDropdown — `getElement(true)` must\n // not run during construction.\n this._dropdown.setCloseHandler(() => this.closeDropdown());\n\n this._onStoreRefresh = () => this.onStoreRefresh();\n\n // Late-built state: store / items / selection were written pure to\n // `_options` by the super-time cascade. Dispatch them now that the\n // dropdown's inner list is initialised.\n if (this._options.store !== undefined && this._options.displayField !== undefined) {\n this.setStore(this._options.store, this._options.displayField, this._options.valueField, this._options.glyphField);\n }\n\n if (this._options.items !== undefined) {\n this.setItems(this._options.items);\n }\n\n if (this._options.selectedIndex !== undefined) {\n this.setSelectedIndex(this._options.selectedIndex, false);\n }\n\n if (this._options.value !== undefined) {\n this.setValue(this._options.value);\n }\n\n if (this._options.selectedItem !== undefined) {\n this.setValue(this._options.selectedItem);\n }\n\n if (this._options.enabled !== undefined) {\n this.applyEnabled(this._options.enabled);\n }\n\n if (this._options.readOnly !== undefined) {\n this.applyReadOnly(this._options.readOnly);\n }\n }\n\n /**\n * Applies a {@link ComboBoxOptions} bag. Inherited Component fields cascade\n * through `super.applyOptions`; item / store / selection fields are written\n * pure into `_options` here and dispatched from the constructor body once\n * internal state is initialised.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.items !== undefined) this._options.items = options.items;\n if (options.store !== undefined) this._options.store = options.store;\n if (options.displayField !== undefined) this._options.displayField = options.displayField;\n if (options.valueField !== undefined) this._options.valueField = options.valueField;\n if (options.glyphField !== undefined) this._options.glyphField = options.glyphField;\n if (options.rendererFactory !== undefined) this._options.rendererFactory = options.rendererFactory;\n if (options.selectedIndex !== undefined) this._options.selectedIndex = options.selectedIndex;\n if (options.value !== undefined) this._options.value = options.value;\n if (options.selectedItem !== undefined) this._options.selectedItem = options.selectedItem;\n if (options.dropdownAnimated !== undefined) this._options.dropdownAnimated = options.dropdownAnimated;\n if (options.dropdownMinWidth !== undefined) this.setDropdownMinWidth(options.dropdownMinWidth);\n\n return this;\n }\n\n /**\n * Recalculates preferred and maximum height from the unified line box plus\n * this control's own chrome.\n *\n * @remarks Box height is `Util.lineHeightPx()` (the same line box every text\n * control renders at) plus the ComboBox's own vertical insets, padding, and\n * border — the identical sum `wrapInnerBaseline` re-adds — so a `ComboBox`\n * placed next to a `TextField` shares its row height and baseline without a\n * UA `<input>` probe.\n */\n protected updateHeight(): void {\n const h = Util.singleLineBoxHeight(this.getInsets(), this.getPadding(), this.getBorderSize());\n\n this.setPreferredSize({ width: 200, height: h });\n this.setMaxSize({ width: Number.MAX_SAFE_INTEGER, height: h });\n // Min-height pinned to the single-line box so the field can't be\n // vertically compressed below one line; min-width 0 keeps it\n // horizontally flexible.\n this.setMinSize({ width: 0, height: h });\n }\n\n /**\n * Places the label flush left and the caret flush right, both vertically\n * centered within the inner height. Replaces the prior `display: flex`\n * arrangement on the surface element so every child position is committed\n * via framework setters.\n */\n doLayout(): this {\n super.doLayout();\n\n const inner = this.getInnerSize();\n if (!inner) {\n return this;\n }\n\n // Layout constants. `gap` matches the prior `gap: 6px` on the\n // `.ComboBox` class rule; `caretSize` reads the caret's own square box\n // size (the field's text font size) so the reserved column tracks it.\n // The label fills the remaining width.\n const gap = 6;\n const caretSize = this._caret.getCaretSize();\n const insets = this.getInsets();\n\n const innerLeft = insets.getLeft();\n const innerTop = insets.getTop();\n const labelW = Math.max(0, inner.width - caretSize - gap);\n const caretX = innerLeft + labelW + gap;\n const caretY = innerTop + Math.max(0, (inner.height - caretSize) / 2);\n\n this._label.setX(innerLeft);\n this._label.setY(innerTop);\n this._label.setWidth(labelW);\n this._label.setHeight(inner.height);\n // `lineHeight` equals the label's height so the single line of label\n // text vertically centers without `display: flex` on the parent.\n this._label.setLineHeight(inner.height);\n // Position the label's hosted renderer now that its box is sized.\n this._label.doLayout();\n\n this._caret.setX(caretX);\n this._caret.setY(caretY);\n this._caret.setWidth(caretSize);\n this._caret.setHeight(caretSize);\n\n return this;\n }\n\n /**\n * Returns the offset from the top of the combo box to the inner-text baseline.\n *\n * @returns The baseline offset in pixels.\n */\n getBaseline(): number | null {\n return this.wrapInnerBaseline(Util.measureTextBaseline());\n }\n\n /**\n * Pops the option dropdown if it is currently closed; a no-op when it\n * is already open. Lets an embedding host (e.g. a table cell editor)\n * land the user straight in the option list on focus instead of\n * requiring a second click or keystroke to open the panel.\n *\n * @returns This component, for method chaining.\n */\n openDropdown(): this {\n if (!this._dropdown.isOpen()) {\n this.toggleDropdown();\n }\n\n return this;\n }\n\n /**\n * Toggles the dropdown's open state.\n */\n private toggleDropdown(): void {\n if (this._dropdown.isOpen()) {\n this.closeDropdown();\n return;\n }\n\n const surface = this.getElement(true)!;\n const list = this._dropdown.getList();\n\n // Exclude the ComboBox surface from the manager's outside-click test.\n this._dropdown.setAnchorElement(surface);\n\n // `showAt` re-applies the items / selectedIndex onto its own inner\n // list. Passing the list's current state round-trips harmlessly and\n // keeps the public `showAt` signature unchanged.\n this._dropdown.showAt(surface, list.getItems(), list.getSelectedIndex());\n this.getAria().setExpanded(true);\n this.setCaretOpen(true);\n }\n\n /**\n * Rotates the caret glyph to mirror the dropdown's open state, timed to the\n * dropdown's own fade so the arrow and panel move in lock-step. When the\n * dropdown is non-animated the rotation snaps instantly.\n *\n * @param open - `true` to point the chevron up (panel open), `false` to point it down (closed).\n */\n private setCaretOpen(open: boolean): void {\n const glyph = this._caret.getGlyph();\n const ms = this._dropdown.isAnimated() ? this._dropdown.getDurationMs() : 0;\n\n glyph.setTransition(`transform ${ms}ms ease`);\n glyph.setTransform(open ? \"rotate(180deg)\" : \"rotate(0deg)\");\n }\n\n /**\n * Closes the dropdown if open. Focus is never re-asserted onto the\n * ComboBox surface — the dropdown lifecycle keeps focus on the\n * ComboBox throughout (keystrokes route through {@link onKeyDown}\n * which forwards to `dropdown.handleKey`), and a wrapping picker /\n * cell-editor that owns its own input must not have its input\n * stolen by a child ComboBox dismissing.\n */\n private closeDropdown(): void {\n if (this._dropdown.isOpen()) {\n this._dropdown.hideAnimated();\n this.getAria().setExpanded(false);\n this.setCaretOpen(false);\n }\n }\n\n /**\n * Handles keydown on the ComboBox surface. While the dropdown is\n * open, keystrokes are forwarded into the inner list via\n * `dropdown.handleKey` so the list's keyboard reducer\n * (ArrowUp/Down/Home/End/PageUp/Down/Enter/Space/type-ahead) can\n * run without the dropdown ever taking DOM focus. When the\n * dropdown is closed, the open gesture (ArrowDown/Up/Enter/Space)\n * pops it. Escape closes the dropdown.\n *\n * @param e - The keyboard event.\n */\n private onKeyDown(e: KeyboardEvent): void {\n if (this._dropdown.isOpen()) {\n if (this._dropdown.handleKey(e)) {\n e.preventDefault();\n\n return;\n }\n\n if (e.key === \"Escape\") {\n e.preventDefault();\n this.closeDropdown();\n }\n\n return;\n }\n\n switch (e.key) {\n case \"ArrowDown\":\n case \"ArrowUp\":\n case \"Enter\":\n case \" \":\n e.preventDefault();\n this.toggleDropdown();\n break;\n case \"Escape\":\n // Nothing to close.\n break;\n default:\n break;\n }\n }\n\n /**\n * Internal callback fired when a row inside the dropdown is clicked.\n *\n * @param index - The selected row index.\n */\n private onRowSelected(index: number): void {\n this.setSelectedIndex(index, true);\n this.closeDropdown();\n }\n\n /**\n * Returns the selected item and its index for the collapsed control to\n * render. Falls back to a blank item at index `-1` when nothing is\n * selected, so the label renders empty and a glyph renderer shows no glyph.\n *\n * @returns The selected `{ item, index }`, or the blank item at `-1`.\n */\n private computeSelectedItem(): { item: SelectableListItem; index: number } {\n const list = this._dropdown.getList();\n const idx = list.getSelectedIndex();\n const items = list.getItems();\n\n if (idx >= 0 && idx < items.length) {\n return { item: items[idx], index: idx };\n }\n\n return { item: { key: \"\", label: \"\" }, index: -1 };\n }\n\n /**\n * Refreshes the collapsed control after a value or selection change by\n * rebinding the label's renderer to the selected item.\n */\n private refreshLabel(): void {\n const { item, index } = this.computeSelectedItem();\n this._label.setItem(item, index);\n }\n\n /**\n * Registers a listener for one of this combo box's events. `\"action\"` is\n * the semantic alias of `\"change\"` — both fire on every committed\n * selection through the inherited {@link AbstractInput} listener bag;\n * `\"binding\"` is the inherited data-binding event.\n *\n * @param event - The event name.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"action\", listener: Function): this;\n on(event: \"change\", listener: (value: string) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n return super.on(\n (event === \"action\" ? \"change\" : event) as \"change\",\n listener as (value: string) => void,\n );\n }\n\n /**\n * Removes a previously registered listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: \"action\" | \"change\" | \"binding\", listener: Function): this {\n return super.off(event === \"action\" ? \"change\" : event, listener);\n }\n\n /**\n * Sets the field value by matching the option's key. The key is also\n * cached in `_pendingValue` so a pre-items {@link setValue} survives a\n * later items / store load (the inner list silently drops unknown keys\n * by clearing its selection, which would otherwise lose the write).\n *\n * @param value - The option key to select. Falls back to no-op when unmatched.\n */\n setValue(value: string): this {\n this._pendingValue = value;\n this._dropdown.getList().setValue(value);\n this.refreshLabel();\n\n return this;\n }\n\n /**\n * Returns the current value (the key of the selected option). Falls back\n * to the cached pending value when no items have landed yet, so the\n * pre-items {@link setValue} contract survives store / items refreshes.\n *\n * @returns The selected option's key, or the last value passed to {@link setValue}.\n */\n getValue(): string {\n const v = this._dropdown.getList().getValue();\n\n // The list returns \"\" for \"nothing selected\". Surface the cached\n // pending value so the pre-items setValue contract survives until\n // items arrive and the key resolves to a real selection.\n return v || (this._pendingValue ?? \"\");\n }\n\n /**\n * Returns the zero-based index of the currently selected option.\n *\n * @returns The selected index, or -1 when nothing is selected.\n */\n getSelectedIndex(): number {\n return this._dropdown.getList().getSelectedIndex();\n }\n\n /**\n * Sets the selected index and optionally fires a 'change' event.\n *\n * @param idx - The zero-based index to select.\n * @param fireEvent - Optional. When true (default), fires the 'change' event after updating.\n */\n setSelectedIndex(idx: number, fireEvent: boolean = true): this {\n // Pass `false` to the inner list so its own `change` doesn't fire on\n // `this._dropdown.getList()`; ComboBox fans the committed value out\n // through AbstractInput's change / binding listeners directly below.\n this._dropdown.getList().setSelectedIndex(idx, false);\n this._pendingValue = null;\n this.refreshLabel();\n\n if (fireEvent) {\n this.notifyChange(this.getValue());\n }\n\n return this;\n }\n\n /**\n * Returns a copy of the current [`SelectableListItem`](/api/component/list/interfaces/SelectableListItem) array.\n *\n * @returns A shallow copy of the internal item array.\n */\n getItems(): Array<SelectableListItem> {\n return this._dropdown.getList().getItems();\n }\n\n /**\n * Replaces all options with the given specs. Each entry is either a plain\n * string — auto-keyed by its array position — or a pre-formed\n * [`SelectableListItem`](/api/component/list/interfaces/SelectableListItem) whose\n * explicit key is kept verbatim, in which case `getValue()` returns that\n * key instead of the positional index. The caller owns key uniqueness.\n *\n * @param items - A single spec or an array of specs. Each spec is a string\n * (auto-keyed by position) or a `{ key, label }` object (explicit key).\n */\n setItems(items: SelectableListItemSpec | Array<SelectableListItemSpec>): this {\n this._dropdown.getList().setItems(items);\n this.reapplyPendingValue();\n this.autoSelectFirstIfEmpty();\n this.refreshLabel();\n\n return this;\n }\n\n /**\n * Appends a new option to the end of the list. A plain string is auto-keyed\n * by the appended position; a pre-formed\n * [`SelectableListItem`](/api/component/list/interfaces/SelectableListItem) keeps\n * its explicit key verbatim.\n *\n * @param item - A string (auto-keyed by final position) or a `{ key, label }`\n * object (explicit key).\n */\n addItem(item: SelectableListItemSpec): this {\n this._dropdown.getList().addItem(item);\n this.reapplyPendingValue();\n this.autoSelectFirstIfEmpty();\n this.refreshLabel();\n\n return this;\n }\n\n /**\n * Binds this component to a store, populating options from the given display field.\n *\n * @param store - The store to bind to.\n * @param displayField - The record field whose value is shown as the option label.\n * @param valueField - Optional. The record field used as the option value; defaults to the record's primary key.\n * @param glyphField - Optional. The record field whose value becomes each\n * option's `glyph`; forwarded to the embedded list.\n */\n setStore(store: AbstractStore, displayField: string, valueField?: string, glyphField?: string): this {\n // Keep `_options.store` / `displayField` / `valueField` / `glyphField`\n // in sync so anything still inspecting them (constructor-time dispatch\n // on re-entry, future option-bag introspection) reads the current\n // binding.\n this._options.store = store;\n this._options.displayField = displayField;\n this._options.valueField = valueField;\n this._options.glyphField = glyphField;\n\n if (this._boundStore) {\n (['load', 'add', 'remove', 'datachange'] as const).forEach(e =>\n this._boundStore!.off(e, this._onStoreRefresh)\n );\n }\n\n // Bind the inner list first so its own store handler is registered —\n // and therefore fires — before the combo's `_onStoreRefresh`, which\n // relies on the list having already rebuilt its rows.\n this._dropdown.getList().setStore(store, displayField, valueField, glyphField);\n\n this._boundStore = store;\n\n (['load', 'add', 'remove', 'datachange'] as const).forEach(e =>\n store.on(e, this._onStoreRefresh)\n );\n\n this.reapplyPendingValue();\n this.autoSelectFirstIfEmpty();\n this.refreshLabel();\n\n return this;\n }\n\n /**\n * Returns the currently bound store, or null if none is set.\n *\n * @returns The bound store, or null.\n */\n getStore(): AbstractStore | null {\n return this._dropdown.getList().getStore();\n }\n\n /**\n * Replaces the renderer factory for both the dropdown rows and the\n * collapsed control, then rebinds the collapsed control so the selected\n * entry renders through the new renderer immediately.\n *\n * @param factory - Zero-argument factory producing a renderer per row.\n *\n * @returns This component, for method chaining.\n */\n setRendererFactory(factory: () => ListItemRenderer): this {\n this._options.rendererFactory = factory;\n this._dropdown.getList().setRendererFactory(factory);\n this._label.setRenderer(factory());\n this.refreshLabel();\n\n return this;\n }\n\n /**\n * Returns the renderer factory currently in use by the embedded list (and\n * mirrored on the collapsed control).\n *\n * @returns The zero-argument renderer factory.\n */\n getRendererFactory(): () => ListItemRenderer {\n return this._dropdown.getList().getRendererFactory();\n }\n\n /**\n * Returns the store record corresponding to the currently selected option.\n *\n * @returns The selected ModelRecord, or undefined if no store is bound or no item is selected.\n */\n getSelectedRecord(): ModelRecord | undefined {\n return this._dropdown.getList().getSelectedRecord();\n }\n\n /**\n * Re-attempts the pending {@link setValue} write after an items / store\n * load. The inner list rejects unknown keys by clearing its selection;\n * `_pendingValue` survives until a write resolves to a real index, at\n * which point it's cleared so later reads pick up the live selection.\n */\n private reapplyPendingValue(): void {\n if (this._pendingValue === null) {\n return;\n }\n\n const list = this._dropdown.getList();\n list.setValue(this._pendingValue);\n\n if (list.getSelectedIndex() >= 0) {\n this._pendingValue = null;\n }\n }\n\n /**\n * Selects the first row when none is selected and the list has at least\n * one item. Mirrors the prior ComboBox behaviour where `setItems` /\n * `addItem` / `setStore` would land on index 0 by default — the inner\n * List leaves nothing selected, so the auto-select happens here to keep\n * the surface's `getValue` non-empty for the typical \"fill items, render\n * the first label\" flow.\n */\n private autoSelectFirstIfEmpty(): void {\n const list = this._dropdown.getList();\n\n if (list.getSelectedIndex() < 0 && list.getItems().length > 0) {\n list.setSelectedIndex(0, false);\n }\n }\n\n /**\n * Re-asserts the surface selection and label after the inner list\n * rebuilds its rows from a deferred store event (an async `load`, or a\n * later `add` / `remove` / `datachange`). The inner list clears its\n * selection whenever it rebuilds from the store, so without this the\n * combo would show populated options but a blank label on first paint\n * when the store loads after construction.\n */\n private onStoreRefresh(): void {\n this.reapplyPendingValue();\n this.autoSelectFirstIfEmpty();\n this.refreshLabel();\n }\n\n /**\n * Enables or disables the fade animation on the dropdown.\n *\n * @param value - true to fade, false for instant open/close.\n */\n setDropdownAnimated(value: boolean): this {\n this._options.dropdownAnimated = value;\n this._dropdown.setAnimated(value);\n\n return this;\n }\n\n /**\n * Returns whether the dropdown fade is enabled.\n *\n * @returns true when the dropdown fades; false when it opens/closes instantly.\n */\n isDropdownAnimated(): boolean {\n return this._options.dropdownAnimated ?? true;\n }\n\n /**\n * Sets the lower bound on the dropdown width. The dropdown is always at\n * least this wide; long labels exceeding the floor still widen it further\n * (capped at the viewport).\n *\n * @param px - The minimum width in pixels. Defaults to `200`.\n *\n * @returns This component, for method chaining.\n */\n setDropdownMinWidth(px: number): this {\n this._options.dropdownMinWidth = px;\n this._dropdown.setMinWidth(px);\n\n return this;\n }\n\n /**\n * Returns the configured lower bound on the dropdown width.\n *\n * @returns The minimum width in pixels.\n */\n getDropdownMinWidth(): number {\n return this._options.dropdownMinWidth ?? COMBOBOX_DROPDOWN_MIN_WIDTH_PX;\n }\n\n /**\n * Reflects the enabled flag in the ARIA tree and the tabindex. Closes\n * the dropdown when transitioning to disabled so a stale panel doesn't\n * outlast the state change.\n */\n protected applyEnabled(value: boolean): void {\n this.getAria().setDisabled(!value);\n this.getAria().setTabIndex(value ? 0 : -1);\n this.setCursor(value ? \"pointer\" : \"default\");\n if (!value) {\n this.closeDropdown();\n }\n }\n\n /**\n * Reflects the read-only flag in the ARIA tree. Read-only ComboBoxes\n * stay focusable and announce their state but the click handler\n * intentionally still opens the dropdown for inspection; the inherited\n * `isReadOnly` flag is what callers query to gate writes.\n */\n protected applyReadOnly(value: boolean): void {\n this.getAria().setReadOnly(value);\n }\n}\n\nconst ComboBoxCallable = callable(ComboBox);\ntype ComboBoxCallable = ComboBox;\nexport {\n ComboBox as _ComboBox,\n ComboBoxDropdown as _ComboBoxDropdown,\n ComboBoxCallable as ComboBox\n};\n"],"mappings":"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"}
|