@jimka/typescript-ui 0.1.0 → 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/README.md +5 -18
- 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-DD-NpicS.js → AbstractInput-BxOtFrER.js} +2 -2
- package/dist/lib/{AbstractInput-DD-NpicS.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-DgZukB5_.js → BoxLayout-DrKGfsup.js} +2 -2
- package/dist/lib/{BoxLayout-DgZukB5_.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-UF0fq8cQ.js → Card-BVwOS8AG.js} +2 -2
- package/dist/lib/{Card-UF0fq8cQ.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-CI4mZQFy.js +2 -0
- 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-E7WzutjO.js.map → FieldDecorator-CJs9gwqH.js.map} +1 -1
- package/dist/lib/{Fit-CFIr4P9R.js → Fit-DjRsiwlg.js} +2 -2
- package/dist/lib/{Fit-CFIr4P9R.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-Czux--Mr.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-Q8y1PHlk.js → HBox-Ce0GTCJP.js} +2 -2
- package/dist/lib/{HBox-Q8y1PHlk.js.map → HBox-Ce0GTCJP.js.map} +1 -1
- package/dist/lib/{Header-zPdvC2AX.js → Header-BQIVpBte.js} +2 -2
- package/dist/lib/{Header-zPdvC2AX.js.map → Header-BQIVpBte.js.map} +1 -1
- package/dist/lib/{IconText-BvGfu7eq.js → IconText-Bo4Qcnot.js} +2 -2
- package/dist/lib/{IconText-BvGfu7eq.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-VJ5uC3c1.js +2 -0
- package/dist/lib/{MenuButton-JQQaKThJ.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-A39T7-_1.js +2 -0
- package/dist/lib/Position-A39T7-_1.js.map +1 -0
- 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-CFIzIjjU.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-CThevdY_.js +2 -0
- package/dist/lib/{TabButton-pZKFYg7b.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-D5B9ecw0.js → VBox-EIqw85Rh.js} +2 -2
- package/dist/lib/{VBox-D5B9ecw0.js.map → VBox-EIqw85Rh.js.map} +1 -1
- package/dist/lib/VirtualRowView-BxpHQ_u8.js +2 -0
- package/dist/lib/{VirtualRowView-Con9SWiU.js.map → VirtualRowView-BxpHQ_u8.js.map} +1 -1
- package/dist/lib/VirtualScroller-DwEEJE1_.js +2 -0
- package/dist/lib/{VirtualScroller-BPDmO1ir.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 +3 -1
- package/dist/lib/component/editor.es.js.map +1 -1
- package/dist/lib/component/input.es.js +1 -1
- package/dist/lib/component/input.es.js.map +1 -1
- package/dist/lib/component/list.es.js +1 -1
- package/dist/lib/component/list.es.js.map +1 -1
- package/dist/lib/component/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +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 +2 -0
- package/dist/lib/router.es.js.map +1 -0
- 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 +11 -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/display/index.d.ts +1 -1
- package/dist/lib/types/component/editor/CodeEditor.d.ts +2 -1
- package/dist/lib/types/component/editor/MarkdownEditor.d.ts +7 -1
- package/dist/lib/types/component/editor/markdownTableTransformer.d.ts +2 -0
- 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 +14 -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/types/router/RoutePattern.d.ts +18 -0
- package/dist/lib/types/router/Router.d.ts +36 -0
- package/dist/lib/types/router/index.d.ts +2 -0
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +9 -5
- package/package.json +6 -1
- package/dist/lib/AnimatedDropdown-BbGCs70E.js +0 -2
- package/dist/lib/AnimatedDropdown-BbGCs70E.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/Button-DEUtBqK4.js +0 -2
- package/dist/lib/Button-DEUtBqK4.js.map +0 -1
- package/dist/lib/ComboBox-GOBOAJ1N.js +0 -2
- package/dist/lib/ComboBox-GOBOAJ1N.js.map +0 -1
- package/dist/lib/Component-BR2f0Itb.js +0 -2
- package/dist/lib/Component-BR2f0Itb.js.map +0 -1
- package/dist/lib/Container-3KsvsJ6S.js +0 -2
- package/dist/lib/DragManager-tPMnbjeO.js +0 -2
- package/dist/lib/FieldDecorator-E7WzutjO.js +0 -2
- package/dist/lib/Glyph-WUqTF_Z9.js +0 -2
- package/dist/lib/Glyph-WUqTF_Z9.js.map +0 -1
- package/dist/lib/GridConstraints-Q3wvuovN.js +0 -2
- package/dist/lib/GridConstraints-Q3wvuovN.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/LayoutSizes-BW4wyGDI.js +0 -2
- package/dist/lib/LayoutSizes-BW4wyGDI.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-Wz4MK6sA.js +0 -2
- package/dist/lib/Menu-Wz4MK6sA.js.map +0 -1
- package/dist/lib/MenuButton-JQQaKThJ.js +0 -2
- 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-Dzaka7_c.js +0 -2
- package/dist/lib/ProgressSpinner-Dzaka7_c.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/Scrollbar-DchfiFKC.js +0 -2
- package/dist/lib/Scrollbar-DchfiFKC.js.map +0 -1
- package/dist/lib/Slider-xRxNSjFN.js +0 -2
- package/dist/lib/Slider-xRxNSjFN.js.map +0 -1
- package/dist/lib/TabButton-pZKFYg7b.js +0 -2
- package/dist/lib/Text-D1RrBY52.js +0 -2
- package/dist/lib/Text-D1RrBY52.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/VirtualRowView-Con9SWiU.js +0 -2
- package/dist/lib/VirtualScroller-BPDmO1ir.js +0 -2
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Panel-DIsdaqc2.js","names":[],"sources":["../../src/typescript/lib/core/Panel.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Container, ContainerOptions } from \"~/core/Container.js\";\nimport { Insets } from \"~/primitive/Insets\";\nimport { LayoutManager } from \"~/layout/LayoutManager.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { InlineStyle, StyleRule } from \"~/core/StyleTarget.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { scrollShadowBoxShadow, scrollShadowEdgeValue, scrollShadowRamp } from \"~/core/ScrollShadow.js\";\nimport { Scrollbar } from \"~/component/container/Scrollbar.js\";\n\n/**\n * Per-edge shadow strength for a panel's scroll shadows, cached as a whole\n * percentage (0–100). The per-scroll update only rewrites a custom property\n * when an edge's quantised strength actually changes, so a scroll that doesn't\n * move the visible strength costs nothing here.\n */\ntype ScrollShadowEdges = { top: number; bottom: number; left: number; right: number };\n\n/**\n * Selects the per-axis scroll behaviour for a {@link Panel}.\n *\n * - `\"none\"` — never scroll; oversized children clip (the default).\n * - `\"auto\"` — scrollbars appear on either axis only when content overflows.\n * - `\"x\"` — horizontal scrollbar on overflow; vertical overflow clips.\n * - `\"y\"` — vertical scrollbar on overflow; horizontal overflow clips.\n * - `\"both\"` — both scrollbars are always shown (`overflow: scroll`).\n *\n * @remarks For every value except `\"none\"` the panel measures the native\n * scrollbar gutter after each `doLayout` pass and subtracts it from\n * `getInnerSize` when a scrollbar is actually visible, so layout managers\n * naturally lay out children within the post-gutter content area instead of\n * letting them spill behind the scrollbar (which the browser would otherwise\n * resolve by adding the opposite-axis scrollbar — the classic V→H cascade).\n * A scrollbar transition triggers a one-frame re-layout via `scheduleLayout`.\n *\n * @category Core\n */\nexport type AutoScrollMode = \"none\" | \"auto\" | \"x\" | \"y\" | \"both\";\n\n/**\n * Selects how a scrolling {@link Panel} renders its scrollbar.\n *\n * - `\"overlay\"` — the default. Scrolling stays native (`overflow: auto`), the\n * native scrollbar is hidden visually, and two custom `Scrollbar` widgets\n * are overlaid at the trailing edges, synced to the element's native\n * `scrollTop` / `scrollLeft`. Every native scroll behaviour (keyboard, find,\n * focus-scroll, caret scroll, assistive tech) is preserved.\n * - `\"native\"` — the OS scrollbar renders as usual; the panel reserves the\n * measured native gutter width instead of the fixed overlay track width.\n *\n * Ignored while `autoScroll === \"none\"` (a non-scrolling panel shows neither).\n *\n * @category Core\n */\nexport type ScrollbarStyle = \"native\" | \"overlay\";\n\n/**\n * Construction-time options for {@link Panel}.\n *\n * @remarks `insets` is inherited from {@link ComponentOptions} but defaults to\n * `(4, 4, 4, 4)` for `Panel` (Component itself defaults to zero insets). Pass\n * an explicit `insets` to override.\n *\n * @category Core\n */\nexport interface PanelOptions extends ContainerOptions {\n tag?: string;\n\n /**\n * Construction-time shortcut for [`Panel.setAutoScroll`](/api/core/classes/Panel#setautoscroll). Defaults to\n * `\"none\"` (oversized children clip, matching the inherited `Component`\n * `overflow: hidden` behaviour).\n */\n autoScroll?: AutoScrollMode;\n\n /**\n * When `true` (the default), an `autoScroll` panel paints a fading edge\n * shadow on each side where hidden content can still be scrolled into\n * view — a cue that the content continues past the viewport border rather\n * than ending there. Set `false` to suppress the shadows. Ignored while\n * `autoScroll === \"none\"` (a non-scrolling panel never shows them).\n */\n scrollShadows?: boolean;\n\n /**\n * Selects the scrollbar rendering for an `autoScroll` panel. Defaults to\n * `\"overlay\"` — a scrolling panel hides its native bar and paints synced\n * overlay `Scrollbar` widgets instead. Pass `\"native\"` to opt out and keep\n * the OS scrollbar. Ignored while `autoScroll === \"none\"`.\n */\n scrollbarStyle?: ScrollbarStyle;\n\n /**\n * When `true`, the panel's default content insets are zero instead of the\n * usual `(4, 4, 4, 4)` — the rail-style default for a fixed-width strip\n * (activity rail, narrow Border/VBox region) that must sit flush against\n * its host and keep a constant width. Construction-time only; a\n * caller-supplied `insets` still wins. Defaults to `false`.\n */\n flush?: boolean;\n}\n\n/**\n * User-overridable defaults forwarded to `super` via the options bag. The\n * cascade in `Component`'s constructor dispatches `setInsets` once with the\n * final value, so a caller-supplied `insets` wins over the panel default.\n */\nconst _defaultPanelOptions: Partial<PanelOptions> = {\n tag: \"div\",\n insets: new Insets(4, 4, 4, 4),\n};\n\n/**\n * Class applied to the raw inner scroll element of an overlay-mode panel. The\n * inner element has no `#id` (it is not a `Component`), so its native bar is\n * hidden through a shared class rule rather than the per-`#id`\n * `setElementCSSRule` path the panel element uses — the framework's module-level\n * shared class-rule pattern (as the focus-ring and `Component` class rules use).\n */\nconst OVERLAY_SCROLLER_CLASS = \"PanelOverlayScroller\";\n\n// The shared inner-scroller class rules, retained once registered (mirrors the\n// CollapseButton / header-glyph module-singleton pattern). The array doubles as\n// the idempotency guard.\nlet _scrollerClassRules: StyleRule[] | null = null;\n\n/**\n * Registers, once, the shared class rules that hide the native scrollbar on an\n * overlay panel's raw inner scroll element: `scrollbar-width: none` (Firefox /\n * Chromium >= 121) plus a `::-webkit-scrollbar { display: none }` selector rule\n * (WebKit / older Blink) — the two-write pair the panel element's\n * `setNativeScrollbarHidden` uses, expressed as a shared class instead of a\n * per-`#id` rule.\n */\nfunction ensureOverlayScrollerClassRule(): void {\n if (_scrollerClassRules) {\n return;\n }\n\n _scrollerClassRules = [\n new StyleRule({\n scope: \"class\",\n name: OVERLAY_SCROLLER_CLASS,\n styles: { scrollbarWidth: \"none\" },\n }),\n new StyleRule({\n scope: \"selector\",\n name: `.${OVERLAY_SCROLLER_CLASS}::-webkit-scrollbar`,\n styles: { display: \"none\" },\n }),\n ];\n}\n\n/**\n * A [`Container`](/api/core/classes/Container) subclass that applies a default 4-pixel inset on all sides.\n *\n * Use `Panel` as the base class for grouped UI containers where children\n * should not sit flush against the outer edge. A plain [`Container`](/api/core/classes/Container) fits\n * its parent's allocation with zero insets to keep structural regions\n * pixel-predictable; `Panel` opts into the visual breathing room that grouped\n * content layouts typically want.\n *\n * `Panel` also exposes `setAutoScroll` to opt the container into native\n * browser scrolling when its children overflow the allocated rect.\n *\n * Pass `flush: true` to opt a panel into zero default insets instead of the\n * 4px default, for rail-style fixed-width strips that must sit flush against\n * their host.\n *\n * @category Core\n */\nclass Panel<TOptions extends PanelOptions = PanelOptions> extends Container<TOptions> {\n\n // `declare` rather than initialiser to dodge the class-field super-cascade\n // trap: a `= \"none\"` initialiser runs *after* super() returns, which\n // overwrites whatever `setAutoScroll(options.autoScroll)` had already\n // written during the super-time cascade. `applyOptions` below always\n // dispatches `setAutoScroll`, so the field gets seeded there.\n declare private _autoScroll: AutoScrollMode;\n declare private _scrollbarGutter: { right: number; bottom: number };\n\n // Scroll-shadow state. `_scrollShadows`, `_shadowOverlay` and `_shadowScrollHandler`\n // are written by `setScrollShadows` / `setAutoScroll` during the super-time\n // options cascade, so they are `declare`d (no initialiser) and seeded in\n // `applyOptions` to dodge the class-field super-cascade trap — an\n // initialiser would run after super() and clobber the seeded value.\n declare private _scrollShadows: boolean;\n declare private _shadowOverlay: Handle | null;\n declare private _shadowScrollHandler: (() => void) | null; // cached bound scroll handler — wired once\n\n // Runtime-only: never touched during the super cascade (the overlay only\n // exists post-render), so a plain initialiser is safe here.\n private _shadowOverlayStyle: InlineStyle = new InlineStyle();\n // Read during the super-time options cascade (setAutoScroll → doLayout →\n // scheduleGutterSettleOnShrink → showsScrollAffordance inspects the edges),\n // so `declare`d and seeded in `applyOptions` to dodge the class-field\n // super-cascade trap, exactly like `_scrollbarGutter`.\n declare private _shadowEdges: ScrollShadowEdges;\n // Child count observed on the previous layout pass, so a shrink (removed\n // children) can force one follow-up gutter/shadow re-measure. See\n // `scheduleGutterSettleOnShrink`.\n private _lastChildCount: number = 0;\n\n // Content preferred extent observed on the previous layout pass while a\n // scroll affordance was showing, so a shrink that happens inside a nested\n // descendant (whose removal leaves this panel's own child count unchanged)\n // still forces the follow-up re-measure. See `scheduleGutterSettleOnShrink`.\n // `declare`d + seeded in `applyOptions` for the same super-cascade reason.\n declare private _lastContentExtent: { width: number; height: number };\n\n // Overlay-scrollbar state. `_scrollbarStyle` is written by\n // `setScrollbarStyle` during the super-time options cascade, and\n // `_overlayScrollElement` / `_scrollbarV` / `_scrollbarH` / `_overlayScrollHandler`\n // are read (for the teardown guard) by the setter's install/refresh path\n // it triggers — so all five are `declare`d and seeded in `applyOptions`\n // for the same class-field super-cascade reason as the scroll-shadow\n // fields above.\n declare private _scrollbarStyle: ScrollbarStyle;\n declare private _overlayScrollElement: Handle | null; // raw inner scroll div (bars are its siblings)\n declare private _scrollbarV: Scrollbar | null;\n declare private _scrollbarH: Scrollbar | null;\n declare private _overlayScrollHandler: (() => void) | null; // native \"scroll\" -> sync\n\n // Runtime-only: never touched during the super cascade (the inner scroll\n // element only exists post-render), so a plain initialiser is safe here —\n // mirrors `_shadowOverlayStyle`.\n private _overlayScrollStyle: InlineStyle = new InlineStyle();\n\n // Bound scroll-forwarders wired to each overlay Scrollbar's \"scroll\"\n // event. Named class fields (per ARCHITECTURE.md *Listeners must\n // reference a named function*) so they are stable, removable references.\n private _onOverlayScrollV = (position: number): void => { this.setScrollTop(position); };\n private _onOverlayScrollH = (position: number): void => { this.setScrollLeft(position); };\n\n /**\n * Creates a panel with 4-pixel insets on all sides by default.\n *\n * @param options - Optional. Construction-time options applied to the panel.\n * `options.tag` overrides the default `\"div\"` tag for subclasses that need\n * a different element (e.g. `\"header\"`, `\"section\"`). `options.insets`\n * overrides the default `(4, 4, 4, 4)` perimeter. `options.flush` zeroes\n * that default instead (a caller-supplied `insets` still wins).\n */\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n // `flush` seeds a zero-inset default; a caller-supplied `insets` still\n // wins because Component.applyOptions dispatches setInsets only when\n // options.insets is defined, overriding whatever default we pick here.\n const flushDefault: Partial<TOptions> =\n options?.flush ? ({ insets: new Insets(0, 0, 0, 0) } as Partial<TOptions>) : {};\n\n super(\n options,\n { ..._defaultPanelOptions, ...(subclassDefaults ?? {}), ...flushDefault } as Partial<TOptions>,\n );\n }\n\n /**\n * Dispatches `Panel`-specific options after delegating the inherited\n * {@link Component} options bag to `super`.\n *\n * @param options - The options bag whose fields populate this panel.\n *\n * @returns This panel, for method chaining.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n // Seed the scrollbar gutter cache before `setAutoScroll` — the latter\n // reads `_scrollbarGutter` to decide whether to clear it on a\n // `\"none\"` transition, and the `declare`d field would otherwise be\n // undefined at first dispatch.\n this.setScrollbarGutter(0, 0);\n\n // Seed the shadow-edge and content-extent caches for the same reason:\n // `setAutoScroll` below triggers a `doLayout` whose\n // `scheduleGutterSettleOnShrink` reads both, and their `declare`d fields\n // would otherwise be undefined during this super-time cascade.\n this._shadowEdges = { top: 0, bottom: 0, left: 0, right: 0 };\n this._lastContentExtent = { width: 0, height: 0 };\n\n // Always dispatch `setAutoScroll` — the `?? \"none\"` covers the\n // no-option default. Routing through the setter (even for the\n // default) keeps the `declare`d backing field initialised and\n // dodges the class-field super-cascade trap that would bite a\n // `= \"none\"` initialiser.\n this.setAutoScroll(options.autoScroll ?? \"none\");\n\n // Seed the `declare`d overlay/handler fields before `setScrollShadows`\n // dispatches — the setter's teardown branch reads them, and the\n // `declare` leaves them `undefined` until first written.\n this._shadowOverlay = null;\n this._shadowScrollHandler = null;\n\n // Always dispatch (default on) so the backing field is seeded through\n // the setter, mirroring the `setAutoScroll` cascade above.\n this.setScrollShadows(options.scrollShadows ?? true);\n\n // Seed the `declare`d overlay fields before `setScrollbarStyle`\n // dispatches — its refresh path (via `refreshOverlayScrollbars` ->\n // `removeOverlayScrollbars`) reads them, and the `declare` leaves\n // them `undefined` until first written.\n this._overlayScrollElement = null;\n this._scrollbarV = null;\n this._scrollbarH = null;\n this._overlayScrollHandler = null;\n\n // Always dispatch so the backing field is seeded through the setter\n // (default \"overlay\"), mirroring the `setAutoScroll` / `setScrollShadows`\n // cascades above. Must run after `setAutoScroll` — the install path\n // this triggers reads `_autoScroll`.\n this.setScrollbarStyle(options.scrollbarStyle ?? \"overlay\");\n\n return this;\n }\n\n /**\n * Selects the panel's native scroll behaviour. Translates `mode` to\n * per-axis `overflow` writes via [`Component.setOverflowX`](/api/core/classes/Component#setoverflowx) /\n * [`Component.setOverflowY`](/api/core/classes/Component#setoverflowy).\n *\n * @param mode - The {@link AutoScrollMode} to apply.\n *\n * @returns This panel, for method chaining.\n *\n * @remarks Children render at their preferred size when `mode !== \"none\"`\n * — the panel no longer clips them to its allocated rect.\n *\n * Whenever a scrollbar becomes visible, `doLayout` measures the gutter\n * and shrinks the panel's reported inner size by that amount so the next\n * layout pass keeps children inside the visible content area (preventing\n * the classic V→H cascade where a right-anchored child gets exposed\n * behind a freshly-shown V scrollbar and triggers an H one).\n *\n * Do not combine with a [`Scrollbar`](/api/component/container/classes/Scrollbar) overlay or a\n * component (e.g. [`Table`](/api/component/table/classes/Table)) that already manages its own scroll\n * state — stacking native overflow on top of the custom scrollbar would\n * produce two scrollbars.\n */\n setAutoScroll(mode: AutoScrollMode): this {\n this._autoScroll = mode;\n\n switch (mode) {\n case \"none\":\n this.setOverflowX(\"hidden\").setOverflowY(\"hidden\");\n break;\n case \"auto\":\n this.setOverflowX(\"auto\").setOverflowY(\"auto\");\n break;\n case \"x\":\n this.setOverflowX(\"auto\").setOverflowY(\"hidden\");\n break;\n case \"y\":\n this.setOverflowX(\"hidden\").setOverflowY(\"auto\");\n break;\n case \"both\":\n this.setOverflowX(\"scroll\").setOverflowY(\"scroll\");\n break;\n }\n\n // Mode switched — drop any cached gutter from the previous mode so\n // the next `doLayout` re-measures against the new overflow setting.\n // (\"none\" never has a gutter; the other modes recompute below.)\n if (mode === \"none\" && (this._scrollbarGutter.right !== 0 || this._scrollbarGutter.bottom !== 0)) {\n this.setScrollbarGutter(0, 0);\n }\n\n // Forward the per-axis \"let children overflow the host\" decision to\n // the layout manager. Each manager honours these flags from its own\n // `doLayout` so trailing children land past `innerSize` when their\n // combined minSize exceeds the host's allocated rect, producing the\n // scrollbar the CSS `overflow: auto` above is waiting for.\n const axes = this.scrollableAxes();\n\n this.getLayoutManager()?.setOverflowing(axes.x, axes.y);\n\n // Re-evaluate the overlay scrollbar for the new mode FIRST: a transition\n // into `\"none\"` tears it (and the inner scroll element) down, a\n // transition into a scrolling mode installs it (when\n // `scrollbarStyle === \"overlay\"`). Must precede `refreshScrollShadows`\n // so `getScrollElement()` already resolves to the inner element when the\n // shadow refresh reads its scroll offsets. No-op before the element\n // exists (creation is deferred to `init`).\n this.refreshOverlayScrollbars();\n\n // Then re-evaluate the shadows for the new mode against the (now\n // correct) scroll element.\n this.refreshScrollShadows();\n\n return this;\n }\n\n /**\n * Re-applies the cached `autoScroll` mode to the new layout manager so\n * swapping managers preserves scroll behaviour. The base `setLayoutManager`\n * does the attach work; this override only forwards the overflow flags.\n *\n * @param layoutManager - The new LayoutManager to use for this panel.\n *\n * @returns This panel, for method chaining.\n */\n setLayoutManager(layoutManager: LayoutManager): this {\n super.setLayoutManager(layoutManager);\n this.setAutoScroll(this._autoScroll);\n\n return this;\n }\n\n /**\n * Returns the panel's current scroll mode.\n *\n * @returns The cached {@link AutoScrollMode}; `\"none\"` if never set.\n */\n getAutoScroll(): AutoScrollMode {\n return this._autoScroll;\n }\n\n /**\n * Resets the panel's scroll mode to `\"none\"`, restoring the inherited\n * `overflow: hidden` clipping behaviour.\n *\n * @returns This panel, for method chaining.\n */\n clearAutoScroll(): this {\n return this.setAutoScroll(\"none\");\n }\n\n /**\n * Enables or disables the position-aware edge shadows on a scrolling\n * panel. When enabled (the default), each side that can still be scrolled\n * toward fades its content into the viewport border; the shadows are\n * suppressed entirely while `autoScroll === \"none\"` or when content does\n * not overflow.\n *\n * @param enabled - `true` to paint the edge shadows, `false` to suppress them.\n *\n * @returns This panel, for method chaining.\n */\n setScrollShadows(enabled: boolean): this {\n this._scrollShadows = enabled;\n\n this.refreshScrollShadows();\n\n return this;\n }\n\n /**\n * Returns whether the panel's scroll edge shadows are enabled.\n *\n * @returns The cached `scrollShadows` flag; `true` unless explicitly disabled.\n */\n getScrollShadows(): boolean {\n return this._scrollShadows;\n }\n\n /**\n * Selects the scrollbar rendering for this panel — the overlay default\n * (native scroll, hidden native bar, two synced `Scrollbar` widgets) or\n * `\"native\"` to keep the OS scrollbar. Installs or tears down the overlay\n * immediately when the element already exists; a no-op before render\n * beyond caching the value (the first install happens in `init`).\n *\n * @param style - The {@link ScrollbarStyle} to apply.\n *\n * @returns This panel, for method chaining.\n */\n setScrollbarStyle(style: ScrollbarStyle): this {\n this._scrollbarStyle = style;\n\n this.refreshOverlayScrollbars();\n\n // Re-home the shadow metric source: an overlay<->native toggle changes\n // which element `getScrollElement()` resolves to (inner element vs panel\n // element), so the shadows must re-read from the new scroller.\n this.refreshScrollShadows();\n\n return this;\n }\n\n /**\n * Returns the panel's current scrollbar style.\n *\n * @returns The cached {@link ScrollbarStyle}; `\"overlay\"` unless\n * explicitly set to `\"native\"`.\n */\n getScrollbarStyle(): ScrollbarStyle {\n return this._scrollbarStyle;\n }\n\n /**\n * Routes every scroll read/write, the child host, and the content frame to\n * the inner scroll element while overlay mode is installed, and to the panel\n * element otherwise (native mode, `autoScroll: \"none\"`, pre-render). This is\n * the single seam that lets the overlay restructure move the actual scroller\n * inward without each scroll-plumbing call site knowing about it.\n *\n * @returns The inner scroll element in overlay mode, else the panel element.\n */\n protected getScrollElement(): Handle | undefined {\n return this._overlayScrollElement ?? this.getElement();\n }\n\n /**\n * Returns the panel's usable inner size with the currently-reserved\n * scrollbar gutter subtracted from each axis. Layout managers read this\n * to lay out children inside the post-gutter content area when a native\n * scrollbar is visible, instead of letting them fill the full rect and\n * spill behind (or be clipped by) the scrollbar.\n *\n * @returns The inner size minus the active scrollbar gutter, or null\n * when the element is not yet in the DOM (matches the base\n * `Component.getInnerSize` contract).\n */\n getInnerSize(): { width: number, height: number } | null {\n const size = super.getInnerSize();\n if (!size) {\n return null;\n }\n\n return {\n width: size.width - this._scrollbarGutter.right,\n height: size.height - this._scrollbarGutter.bottom,\n };\n }\n\n /**\n * Lays out children, then measures the post-layout scrollbar visibility\n * and, when it has changed since the last pass, caches the new gutter\n * and schedules a follow-up layout so children land inside the new\n * post-gutter content area. The follow-up is the \"one-frame reflow\"\n * documented on {@link AutoScrollMode}.\n *\n * @returns This panel, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n // Flush queued inline-style writes (own size in particular) before\n // reading scrollbar geometry: `LayoutManager.commitBounds` runs us\n // with `autoCommitStyle === false`, so the new width/height\n // `setSize` queued during the parent's layout pass haven't reached\n // the DOM yet — `scrollHeight` / `clientHeight` would otherwise\n // report the previous frame's dimensions and `measureScrollbarGutter`\n // wouldn't see the scrollbar transition.\n this.commitElementStyle();\n\n // Re-size the scroll-shadow overlay against the just-committed geometry\n // before measuring: it is the only in-flow child, so a stale height left\n // over from the previous pass floors `scrollHeight` and fakes an overflow\n // on every pass that shrinks the panel. See `resizeScrollShadowOverlay`.\n this.resizeScrollShadowOverlay();\n this.measureScrollbarGutter();\n\n // Re-pin the overlay and recompute edge state against the freshly\n // committed geometry (content-size or scrollbar-gutter changes can\n // flip which edges overflow). The preceding `commitElementStyle`\n // guarantees the reads see this frame's dimensions.\n this.updateScrollShadows();\n\n this.scheduleGutterSettleOnShrink();\n\n return this;\n }\n\n /**\n * Forces one follow-up layout pass after this panel's content shrinks, so a\n * shrink that brings overflowing content back within the viewport re-clears\n * the reserved scrollbar gutter and scroll shadow.\n *\n * `measureScrollbarGutter` only reschedules a pass when the gutter *value*\n * it reads changes. When content is removed, the overflow→fit transition\n * often has not settled on the pass that runs immediately after the\n * removal — the DOM `scrollHeight` still reads its old (overflowing) value,\n * so both the gutter and the shadow measure stale, see no change, and\n * schedule nothing; the stale gutter and shadow then linger until some later\n * unrelated layout (or a scroll event) re-measures. So this schedules one\n * more pass off a signal that *is* accurate at layout time — the content's\n * preferred extent, which drops synchronously when content is removed — and\n * the next frame re-measures against the settled content and clears anything\n * no longer needed.\n *\n * Two shrink signals are used. A direct-child-count drop is the cheap common\n * case. But content can also shrink inside a nested descendant (e.g. rows\n * removed from a grid several levels down), leaving this panel's own child\n * count unchanged; a drop in the panel's preferred extent catches that. The\n * preferred-extent read is gated behind an actually-showing scroll affordance\n * (a reserved gutter or a painted shadow edge) so it costs nothing on the\n * overwhelming majority of layouts, where there is nothing to settle.\n *\n * Bounded and non-looping: it fires only on the pass *after* a shrink (the\n * follow-up pass sees an unchanged count and extent), and never for a\n * `\"none\"` panel, which reserves no gutter and paints no shadow.\n */\n private scheduleGutterSettleOnShrink(): void {\n if (this._autoScroll === \"none\") {\n return;\n }\n\n const count = this.getComponents().length;\n const childShrank = count < this._lastChildCount;\n\n this._lastChildCount = count;\n\n // A shrink inside a nested descendant leaves `count` unchanged, so also\n // watch the preferred extent — but only while a scroll affordance is on\n // screen, since that is the only state a shrink could leave stale.\n let contentShrank = false;\n\n if (this.showsScrollAffordance()) {\n const preferred = this.getPreferredSize();\n const width = preferred ? preferred.width : 0;\n const height = preferred ? preferred.height : 0;\n\n contentShrank = width < this._lastContentExtent.width\n || height < this._lastContentExtent.height;\n\n this._lastContentExtent = { width, height };\n }\n\n if (childShrank || contentShrank) {\n this.scheduleLayout();\n }\n }\n\n /**\n * Whether this panel is currently painting a scroll affordance — a reserved\n * scrollbar gutter or any lit shadow edge. Used by\n * {@link Panel.scheduleGutterSettleOnShrink} to decide whether a shrink could\n * have left a stale gutter/shadow worth re-measuring.\n *\n * @returns `true` when a gutter is reserved or any shadow edge is lit.\n */\n private showsScrollAffordance(): boolean {\n return this._scrollbarGutter.right > 0\n || this._scrollbarGutter.bottom > 0\n || this._shadowEdges.top > 0\n || this._shadowEdges.bottom > 0\n || this._shadowEdges.left > 0\n || this._shadowEdges.right > 0;\n }\n\n /**\n * Initialises the panel element, then installs the scroll-shadow overlay\n * if the panel is a scroll-shadow candidate. Overlay creation is deferred\n * to here (rather than `applyOptions`) because the element only exists\n * once rendered.\n *\n * @param element - Optional. The element to initialise; falls back to the rendered element.\n *\n * @returns This panel, for method chaining.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n // `getElement()` is still undefined inside `init` (the base assigns\n // `_element` only after `render` returns), so hand the resolved\n // element straight to the installer instead of re-reading it.\n const resolved = element ?? this.getElement();\n\n // Install the overlay scrollbars (which create the inner scroll element)\n // BEFORE the scroll shadows, so `getScrollElement()` already resolves to\n // the inner element when `updateScrollShadows` first reads its offsets.\n if (resolved && this._scrollbarStyle === \"overlay\" && this._autoScroll !== \"none\") {\n this.installOverlayScrollbars(resolved);\n this.layoutOverlayScrollbars(resolved);\n }\n\n if (resolved && this._scrollShadows && this._autoScroll !== \"none\") {\n this.installScrollShadows(resolved);\n this.updateScrollShadows(resolved);\n }\n\n return this;\n }\n\n /**\n * Removes the cached scroll listener before the base destructor detaches\n * the element. The overlay is a child of that element, so it is removed\n * with it; only the window-level listener registration needs explicit\n * cleanup.\n */\n protected destructor(): void {\n this.removeScrollShadows();\n this.removeOverlayScrollbars();\n\n super.destructor();\n }\n\n /**\n * Which axes the current `autoScroll` mode lets the user scroll along. The\n * single source of truth behind the layout manager's overflow flags, the\n * gutter measurement, and the shadow edges — all three must agree on what\n * \"scrollable\" means or the panel paints an affordance for an axis that\n * cannot move.\n *\n * @returns A flag per axis; `true` when that axis scrolls under the current mode.\n */\n private scrollableAxes(): { x: boolean; y: boolean } {\n const mode = this._autoScroll;\n\n return {\n x: mode === \"x\" || mode === \"auto\" || mode === \"both\",\n y: mode === \"y\" || mode === \"auto\" || mode === \"both\",\n };\n }\n\n /**\n * Caches the new gutter for each axis. Internal — driven by\n * `measureScrollbarGutter` after a layout pass; consumers can't\n * configure this (it's derived from runtime DOM measurement, not a\n * declarative input), so it stays off the `PanelOptions` bag.\n *\n * @param right - Reserved gutter on the right edge in pixels.\n * @param bottom - Reserved gutter on the bottom edge in pixels.\n */\n private setScrollbarGutter(right: number, bottom: number): void {\n this._scrollbarGutter = { right, bottom };\n }\n\n /**\n * Reads the post-layout scrollbar visibility from the live DOM and\n * updates the cached gutter to match. When the gutter changed,\n * schedules a follow-up layout pass so children re-flow inside the new\n * inner area. No-op for `mode === \"none\"` and on browsers whose\n * scrollbars don't reserve space (e.g. macOS overlay scrollbars, where\n * the native width measures as 0 — the cascade can't happen there).\n */\n private measureScrollbarGutter(): void {\n if (this._autoScroll === \"none\") {\n return;\n }\n\n if (this._scrollbarStyle === \"overlay\") {\n this.layoutOverlayScrollbars();\n\n return;\n }\n\n const el = this.getElement();\n if (!el) {\n return;\n }\n\n const trackW = DOM.source.getScrollBarWidth();\n if (trackW === 0) {\n return;\n }\n\n // `\"both\"` forces both scrollbars on (`overflow: scroll` on both\n // axes), so the gutter is always reserved on both sides. The\n // single-axis modes only show their one bar, and `\"auto\"` shows\n // each independently; reading `scrollHeight > clientHeight` (and\n // its X-axis twin) detects whichever bars the browser has chosen\n // to render this frame, which matches the visible-only criterion.\n let vReserved: boolean;\n let hReserved: boolean;\n\n if (this._autoScroll === \"both\") {\n vReserved = true;\n hReserved = true;\n } else {\n const axes = this.scrollableAxes();\n const metrics = DOM.source.getScrollMetrics(el);\n\n vReserved = axes.y && metrics.scrollHeight > metrics.clientHeight;\n hReserved = axes.x && metrics.scrollWidth > metrics.clientWidth;\n }\n\n const newRight = vReserved ? trackW : 0;\n const newBottom = hReserved ? trackW : 0;\n\n if (newRight === this._scrollbarGutter.right && newBottom === this._scrollbarGutter.bottom) {\n return;\n }\n\n this.setScrollbarGutter(newRight, newBottom);\n this.scheduleLayout();\n }\n\n /**\n * Brings the scroll-shadow overlay into the state implied by the current\n * `scrollShadows` / `autoScroll` settings: torn down when disabled or\n * non-scrolling, otherwise installed and refreshed. No-op before the\n * element exists — `init` performs the first install once rendered.\n */\n private refreshScrollShadows(): void {\n if (!this._scrollShadows || this._autoScroll === \"none\") {\n this.removeScrollShadows();\n\n return;\n }\n\n const element = this.getElement();\n if (!element) {\n return;\n }\n\n this.installScrollShadows(element);\n this.updateScrollShadows(element);\n }\n\n /**\n * Creates the overlay and wires the scroll listener if they are not\n * already present. Idempotent: the `_shadowOverlay` / `_shadowScrollHandler` guards\n * keep it from stacking a duplicate overlay or listener across repeated\n * calls (the \"wire once\" rule).\n *\n * @param element - The rendered panel element to append the overlay to.\n */\n private installScrollShadows(element: Handle): void {\n if (!this._shadowOverlay) {\n this.createScrollShadowOverlay(element);\n }\n\n if (!this._shadowScrollHandler) {\n const handler = (): void => {\n this.updateScrollShadows();\n };\n\n this._shadowScrollHandler = handler;\n // Subtree, not exact-target: in overlay mode the scroll fires on the\n // id-less inner element, which only reaches the panel's id-keyed\n // listener bag by climbing the subtree. Native mode's scroll fires on\n // the panel element itself, which the subtree walk also matches.\n Event.addSubtreeListener(this, \"scroll\", handler);\n }\n }\n\n /**\n * Builds the non-interactive shadow overlay: an id-less, listener-free\n * presentational sheath (mirroring the clip/content frames) carrying four\n * blurred inset edge shadows, one per side. Each shadow's colour is a local\n * custom property defaulting to `transparent`, so the per-scroll path only\n * flips a property to light an edge rather than rebuilding the shadow.\n *\n * @param element - The panel element the overlay is appended to.\n */\n private createScrollShadowOverlay(element: Handle): void {\n const overlay = DOM.sink.createElement(\"div\");\n\n this._shadowOverlayStyle.attach(overlay);\n this._shadowOverlayStyle.setMany({\n // `sticky` pins the overlay to the scroll-port viewport on the\n // compositor: the browser keeps it at the `top: 0` / `left: 0`\n // edge as the content scrolls underneath, so it tracks the\n // viewport without any per-scroll JS write (no transform repin, no\n // main-thread flicker). It also does not extend the scrollable\n // region, since it stays inside the viewport box.\n position: \"sticky\",\n left: \"0px\",\n top: \"0px\",\n pointerEvents: \"none\",\n // Paint above the content frame: `setContentFrame` re-appends that\n // frame as the element's last child during layout, so DOM order\n // alone would let it cover an overlay appended here at `init`.\n zIndex: \"1\",\n // Four blurred inset shadows — one per edge — each gated by a local\n // custom property defaulting to `transparent` (flipped to the theme\n // colour by `setShadowEdge`). See `scrollShadowBoxShadow`.\n boxShadow: scrollShadowBoxShadow(),\n });\n\n DOM.sink.appendChild(element, overlay);\n // Track the panel-owned overlay so a discarded panel releases it on GC\n // even if removeScrollShadows never runs; untracked there on eager removal.\n this.trackHandle(overlay);\n this._shadowOverlay = overlay;\n }\n\n /**\n * Tears the overlay down and unwires the scroll listener, resetting the\n * cached edge state. Each step is guarded so this is safe to call before\n * the overlay was ever created (e.g. during the construction cascade).\n */\n private removeScrollShadows(): void {\n if (this._shadowScrollHandler) {\n Event.removeSubtreeListener(this, \"scroll\", this._shadowScrollHandler);\n this._shadowScrollHandler = null;\n }\n\n if (this._shadowOverlay) {\n DOM.sink.removeElement(this._shadowOverlay);\n this.untrackHandle(this._shadowOverlay);\n DOM.sink.release(this._shadowOverlay);\n this._shadowOverlay = null;\n\n // The buffer was bound to the now-removed overlay; a fresh one is\n // needed for any future re-install (mirrors `disposeFrame`).\n this._shadowOverlayStyle = new InlineStyle();\n }\n\n this._shadowEdges = { top: 0, bottom: 0, left: 0, right: 0 };\n }\n\n /**\n * Re-asserts the shadow overlay's size against the live viewport box (a\n * no-op write unless it changed).\n *\n * The overlay is the panel's only in-flow child — every child *component*\n * is absolutely positioned — so its height alone floors the element's\n * `scrollHeight`. That makes its size load-bearing for\n * {@link Panel.measureScrollbarGutter}, not merely cosmetic: while it\n * carries the previous pass's height, a panel that just shrank reads\n * `scrollHeight` (the stale, taller overlay) above `clientHeight` (the\n * freshly committed height) and reserves a scrollbar gutter for an overflow\n * that does not exist. Hence `doLayout` re-sizes the overlay *before* it\n * measures, which is what keeps the \"stays inside the viewport box, so it\n * never extends the scrollable region\" invariant true on the shrinking pass\n * as well as the settled one.\n *\n * @param element - Optional. The panel element; falls back to the rendered\n * element. Passed explicitly from `init`, where `getElement` is not yet\n * populated.\n */\n private resizeScrollShadowOverlay(element?: Handle): void {\n const el = element ?? this.getElement();\n if (!el || !this._shadowOverlay) {\n return;\n }\n\n const { clientWidth, clientHeight } = DOM.source.getScrollMetrics(el);\n\n // In overlay-scrollbar mode the native bar is hidden, so clientWidth /\n // clientHeight still span the strip the overlay Scrollbar paints on.\n // Inset the shadow overlay by the reserved overlay gutter so each edge\n // shadow lands just inside its bar — aligned with the content viewport\n // getInnerSize exposes — instead of bleeding under the translucent bar\n // track (which reads as the shadow painting on top of the scrollbar).\n // Native mode needs no inset: clientWidth / clientHeight already exclude\n // the OS scrollbar, so the gutter there is physical, not overlaid.\n const rightInset = this._scrollbarStyle === \"overlay\" ? this._scrollbarGutter.right : 0;\n const bottomInset = this._scrollbarStyle === \"overlay\" ? this._scrollbarGutter.bottom : 0;\n\n // Size the overlay to the viewport box; `position: sticky` keeps it\n // pinned there as the content scrolls, so no transform is needed.\n this._shadowOverlayStyle.setMany({\n width: (clientWidth - rightInset) + \"px\",\n height: (clientHeight - bottomInset) + \"px\",\n });\n }\n\n /**\n * Sizes the overlay to the live viewport and recomputes each edge's shadow\n * strength from its distance to that extreme. `sticky` handles the\n * positioning, so the per-scroll path only re-asserts the viewport size (a\n * no-op write unless it changed) and rescales the edges — no positioning\n * work runs here.\n *\n * @param element - Optional. The panel element; falls back to the rendered\n * element. Passed explicitly from `init`, where `getElement` is not yet\n * populated.\n */\n private updateScrollShadows(element?: Handle): void {\n const el = element ?? this.getElement();\n if (!el || !this._shadowOverlay) {\n return;\n }\n\n // Read the scroll offsets and extents from the element that actually\n // scrolls — the inner scroller in overlay mode (the panel element's own\n // offsets are always 0 there), the panel element otherwise. The overlay\n // is still sized against, and pinned to, the panel element (`el`).\n const { scrollTop, scrollLeft, scrollWidth, scrollHeight, clientWidth, clientHeight } =\n DOM.source.getScrollMetrics(this.getScrollElement() ?? el);\n\n this.resizeScrollShadowOverlay(el);\n\n const maxTop = scrollHeight - clientHeight;\n const maxLeft = scrollWidth - clientWidth;\n\n // Ramp an edge in by its distance past that extreme (see `scrollShadowRamp`).\n const ramp = scrollShadowRamp;\n\n // A shadow says \"there is more content this way, scroll to reach it\", so\n // only an axis the user can actually scroll may light its edges. A\n // clipped axis still reports overflow through `scrollWidth` /\n // `scrollHeight` — an `autoScroll: \"y\"` panel whose content is a few px\n // wider than its post-gutter width reads a non-zero `maxLeft` — and\n // ramping that would paint a right-edge fade promising content no\n // gesture can reveal.\n const axes = this.scrollableAxes();\n\n this.setShadowEdge(\"top\", \"--ts-ss-top\", axes.y ? ramp(scrollTop) : 0);\n this.setShadowEdge(\"bottom\", \"--ts-ss-bottom\", axes.y ? ramp(maxTop - scrollTop) : 0);\n this.setShadowEdge(\"left\", \"--ts-ss-left\", axes.x ? ramp(scrollLeft) : 0);\n this.setShadowEdge(\"right\", \"--ts-ss-right\", axes.x ? ramp(maxLeft - scrollLeft): 0);\n }\n\n /**\n * Sets a single edge's shadow strength by scaling the theme shadow colour\n * toward transparent. Strength is quantised to a whole percent so an\n * in-ramp scroll only repaints when the visible strength actually changes\n * (and never sub-pixel-thrashes); at zero the property is unset so the\n * `box-shadow` layer falls back to `transparent`.\n *\n * @param edge - The edge whose cached strength this updates.\n * @param property - The overlay custom property backing that edge's shadow.\n * @param strength - The target strength in the range 0–1.\n */\n private setShadowEdge(edge: keyof ScrollShadowEdges, property: string, strength: number): void {\n const percent = Math.round(strength * 100); // quantise: 0–1 → 0–100%\n\n if (this._shadowEdges[edge] === percent) {\n return;\n }\n\n this._shadowEdges[edge] = percent;\n this._shadowOverlayStyle.set(property, scrollShadowEdgeValue(percent));\n }\n\n /**\n * Brings the overlay scrollbar into the state implied by the current\n * `scrollbarStyle` / `autoScroll` settings: torn down when native or\n * non-scrolling, otherwise installed and laid out. No-op before the\n * element exists — `init` performs the first install once rendered.\n */\n private refreshOverlayScrollbars(): void {\n if (this._scrollbarStyle !== \"overlay\" || this._autoScroll === \"none\") {\n this.removeOverlayScrollbars();\n\n return;\n }\n\n const element = this.getElement();\n if (!element) {\n return;\n }\n\n this.installOverlayScrollbars(element);\n this.layoutOverlayScrollbars(element);\n }\n\n /**\n * Creates the inner scroll element (if absent), appends the two `Scrollbar`\n * widgets as its siblings on the panel element, and hides the native bar.\n * Idempotent: the element/bars/listener are each guarded by a `null` check,\n * so repeated calls neither stack duplicates nor re-hide an already-hidden\n * bar — but the inner element's per-axis overflow IS re-asserted on every\n * call so a runtime `setAutoScroll` mode-to-mode change (which keeps the\n * existing inner element) updates which axes scroll.\n *\n * @param element - The rendered panel element to append the inner scroller\n * and bars into.\n */\n private installOverlayScrollbars(element: Handle): void {\n if (!this._overlayScrollElement) {\n // The native scroll happens on this inner element, physically inset\n // by the reserved track (see `layoutOverlayScrollbars`) so content\n // clips at the inner viewport edge and can never scroll under a bar.\n // The bars are its SIBLINGS on the panel element (below), outside\n // this element's overflow clip — the two-element structure\n // `VirtualScroller` uses. The panel element keeps its own\n // `overflow: auto` (inert: the inner element is absolute / out of\n // flow and always fits, so the panel element never scrolls).\n ensureOverlayScrollerClassRule();\n\n const inner = DOM.sink.createElement(\"div\");\n\n // `width/height: 100%` fills the panel element's padding box (its\n // containing block, since every Component is positioned) so the\n // first overflow read sees the full viewport; `layoutOverlayScrollbars`\n // then overrides with the explicit post-gutter px size each pass.\n this._overlayScrollStyle.attach(inner);\n this._overlayScrollStyle.setMany({\n position: \"absolute\",\n left: \"0px\",\n top: \"0px\",\n width: \"100%\",\n height: \"100%\",\n });\n\n // Hide the inner element's own native bar via the shared class rule\n // (it has no `#id`, so the panel element's per-`#id` path can't reach it).\n DOM.sink.apply(inner, { addClass: [OVERLAY_SCROLLER_CLASS] });\n DOM.sink.appendChild(element, inner);\n\n // Shift the existing children (or the active content frame) onto the\n // inner scroller, preserving the scroll offset across the host swap.\n this.reparentContent(element, inner);\n\n this.trackHandle(inner);\n this._overlayScrollElement = inner;\n }\n\n // Re-assert the inner element's per-axis overflow every call: on a\n // runtime `setAutoScroll` mode-to-mode change the inner element already\n // exists (no teardown), so the guard above is skipped — but the newly\n // scrollable axis must flip from `hidden` to `auto` (and vice versa) or\n // native wheel/keyboard scroll and the matching bar would be inert.\n const axes = this.scrollableAxes();\n this._overlayScrollStyle.setMany({\n overflowX: axes.x ? \"auto\" : \"hidden\",\n overflowY: axes.y ? \"auto\" : \"hidden\",\n });\n\n if (!this._scrollbarV) {\n this._scrollbarV = new Scrollbar(\"vertical\");\n this._scrollbarV.setZIndex(2); // above the shadow overlay's z-index: 1\n DOM.sink.appendChild(element, this._scrollbarV.getElement(true)!);\n this._scrollbarV.on(\"scroll\", this._onOverlayScrollV);\n }\n\n if (!this._scrollbarH) {\n this._scrollbarH = new Scrollbar(\"horizontal\");\n this._scrollbarH.setZIndex(2);\n DOM.sink.appendChild(element, this._scrollbarH.getElement(true)!);\n this._scrollbarH.on(\"scroll\", this._onOverlayScrollH);\n }\n\n if (!this._overlayScrollHandler) {\n // Subtree, not exact-target: the inner scroll element is a raw,\n // id-less div, so its native \"scroll\" only reaches the panel's\n // id-keyed listener bag by climbing the subtree to the panel element\n // (the same mechanism the wheel listener uses). The handler reads\n // `getScrollElement()`, not the event target, so a nested\n // descendant's scroll only triggers a harmless re-read.\n const handler = (): void => {\n this.syncOverlayScrollbars();\n };\n\n this._overlayScrollHandler = handler;\n Event.addSubtreeListener(this, \"scroll\", handler);\n }\n\n this.setNativeScrollbarHidden(true);\n }\n\n /**\n * Tears the overlay scrollbar down: unwires the native scroll listener,\n * detaches and discards both bars, removes the sticky host, un-hides the\n * native bar, and clears any reserved gutter. Each step is guarded so\n * this is safe to call before the overlay was ever created (e.g. during\n * the construction cascade).\n */\n private removeOverlayScrollbars(): void {\n if (this._overlayScrollHandler) {\n Event.removeSubtreeListener(this, \"scroll\", this._overlayScrollHandler);\n this._overlayScrollHandler = null;\n }\n\n if (this._scrollbarV) {\n this._scrollbarV.off(\"scroll\", this._onOverlayScrollV);\n this._scrollbarV.removeElement();\n this._scrollbarV = null;\n }\n\n if (this._scrollbarH) {\n this._scrollbarH.off(\"scroll\", this._onOverlayScrollH);\n this._scrollbarH.removeElement();\n this._scrollbarH = null;\n }\n\n if (this._overlayScrollElement) {\n // Re-parent the children (or content frame) back onto the panel\n // element — which resumes scrolling in native mode — before the\n // inner element is destroyed, preserving the scroll offset.\n const element = this.getElement();\n\n if (element) {\n this.reparentContent(this._overlayScrollElement, element);\n }\n\n DOM.sink.removeElement(this._overlayScrollElement);\n this.untrackHandle(this._overlayScrollElement);\n DOM.sink.release(this._overlayScrollElement);\n this._overlayScrollElement = null;\n\n // The buffer was bound to the now-removed inner element; a fresh one\n // is needed for any future re-install (mirrors `_shadowOverlayStyle`\n // in `removeScrollShadows`).\n this._overlayScrollStyle = new InlineStyle();\n }\n\n this.setNativeScrollbarHidden(false);\n\n // Unconditional (rather than gated on the previous value, as\n // `setAutoScroll`'s native-path gutter-clear is): `setLayoutManager`\n // can re-enter this teardown from inside `Component.applyOptions`'s\n // own `layoutManager` option handling, before Panel's `applyOptions`\n // body has seeded `_scrollbarGutter` at all. The assignment itself is\n // a cheap plain-object write, so skipping the read-before-write\n // avoids that ordering hazard for free.\n this.setScrollbarGutter(0, 0);\n }\n\n /**\n * Hides or restores the native scrollbar through the framework's deferred\n * style seams — a `scrollbar-width: none` write on the component's own\n * `#id` rule (Firefox / Chromium >= 121) plus a `#id::-webkit-scrollbar {\n * display: none }` state rule (WebKit / older Blink).\n *\n * @param hidden - `true` to hide the native bar, `false` to restore it.\n */\n private setNativeScrollbarHidden(hidden: boolean): void {\n this.setElementCSSRule(\"scrollbarWidth\", hidden ? \"none\" : null);\n this.createStyleRule(\"::-webkit-scrollbar\").set(\"display\", hidden ? \"none\" : null);\n }\n\n /**\n * Sizes the inner scroll element to the available viewport minus the track\n * on each axis whose perpendicular bar is visible, positions both bars in\n * the reserved band at the trailing edges, pushes their metrics, and\n * reserves the matching gutter — rescheduling a layout pass when it changed.\n * Called from `init` (first install) and from `measureScrollbarGutter`'s\n * overlay branch (every `doLayout` pass).\n *\n * The dual read is the crux: the **available viewport** comes from the panel\n * element (which never scrolls, so its client box is the full viewport),\n * while content extent, offsets, and the current inner client box come from\n * the **inner scroll element**. Physically insetting the inner element is\n * what makes overflowing content clip before the bar band instead of\n * scrolling under it.\n *\n * @param element - Optional. The panel element; falls back to the rendered\n * element. Passed explicitly from `init`, where `getElement` is not yet\n * populated.\n */\n private layoutOverlayScrollbars(element?: Handle): void {\n const panelEl = element ?? this.getElement();\n const innerEl = this._overlayScrollElement;\n if (!panelEl || !innerEl || !this._scrollbarV || !this._scrollbarH) {\n return;\n }\n\n const trackW = this._scrollbarV.getTrackWidth();\n\n // Available viewport: the panel element's client box. The parent layout\n // sizes the panel element (and `doLayout` flushes it via\n // `commitElementStyle`) before this runs, so `avail` is always current —\n // it never lags a resize.\n const avail = DOM.source.getScrollMetrics(panelEl);\n const availW = avail.clientWidth;\n const availH = avail.clientHeight;\n\n const curRight = this._scrollbarGutter.right;\n const curBottom = this._scrollbarGutter.bottom;\n\n // Size the inner scroller to the CURRENT viewport (minus the currently\n // reserved gutter) BEFORE reading its metrics, so its `clientWidth`/\n // `clientHeight` — and thus `scrollWidth`/`scrollHeight`, which the\n // browser floors at the client box — reflect THIS frame's viewport. The\n // inner element otherwise carries the previous pass's size, which lags a\n // resize in BOTH directions: on expand the stale-small client box kept a\n // bar the widened viewport no longer needs; on shrink the stale-large\n // client box floored `scrollWidth` so content that now fits still read as\n // overflowing — each flickered a transient bar that could stick. A gutter\n // change below re-sizes and reschedules, converging in one extra pass.\n this._overlayScrollStyle.setMany({\n width: (availW - curRight) + \"px\",\n height: (availH - curBottom) + \"px\",\n });\n\n // Content extent, offsets, and the now-current inner client box.\n const m = DOM.source.getScrollMetrics(innerEl);\n const axes = this.scrollableAxes();\n\n // A bar shows when content exceeds the inner scroller's (now current)\n // viewport. The V<->H dependency — reserving one bar shrinks the other's\n // viewport — settles across passes via the gutter-change reschedule\n // below, the same one-extra-pass convergence the gutter always used.\n const vVisible = axes.y && m.scrollHeight > m.clientHeight;\n const hVisible = axes.x && m.scrollWidth > m.clientWidth;\n\n const innerW = availW - (vVisible ? trackW : 0);\n const innerH = availH - (hVisible ? trackW : 0);\n\n // Re-inset the inner scroller when this pass's gutter differs from the\n // one the pre-read sizing used, so overflowing content clips at the inner\n // viewport edge and can never scroll under a bar.\n if (innerW !== availW - curRight || innerH !== availH - curBottom) {\n this._overlayScrollStyle.setMany({ width: innerW + \"px\", height: innerH + \"px\" });\n }\n\n // Bars occupy the reserved band at the trailing edges, sized to the\n // inner extent so each stops short of the shared corner. setMetrics\n // takes the same reduced viewport (`innerH`/`innerW`) the visibility\n // test used, so a bar's shown/hidden state and the reserved gutter\n // never disagree.\n this._scrollbarV.setX(innerW);\n this._scrollbarV.setY(0);\n this._scrollbarV.setHeight(innerH);\n this._scrollbarV.setMetrics(innerH, m.scrollHeight, m.scrollTop);\n\n this._scrollbarH.setX(0);\n this._scrollbarH.setY(innerH);\n this._scrollbarH.setWidth(innerW);\n this._scrollbarH.setMetrics(innerW, m.scrollWidth, m.scrollLeft);\n\n const newRight = vVisible ? trackW : 0;\n const newBottom = hVisible ? trackW : 0;\n\n if (newRight !== curRight || newBottom !== curBottom) {\n this.setScrollbarGutter(newRight, newBottom);\n this.scheduleLayout();\n }\n }\n\n /**\n * Re-pushes metrics (thumb size/position only) to both overlay bars against\n * the inner scroller's live scroll offset. Called from the native `\"scroll\"`\n * handler — geometry (bar position/size, reserved gutter, inner element\n * size) changes only on layout, so this never repositions or resizes\n * anything and never schedules a layout.\n */\n private syncOverlayScrollbars(): void {\n const innerEl = this._overlayScrollElement;\n if (!innerEl || !this._scrollbarV || !this._scrollbarH) {\n return;\n }\n\n const m = DOM.source.getScrollMetrics(innerEl);\n\n this._scrollbarV.setMetrics(m.clientHeight, m.scrollHeight, m.scrollTop);\n this._scrollbarH.setMetrics(m.clientWidth, m.scrollWidth, m.scrollLeft);\n }\n}\n\nconst PanelCallable = callable(Panel);\ntype PanelCallable<TOptions extends PanelOptions = PanelOptions> = Panel<TOptions>;\nexport {\n Panel as _Panel,\n PanelCallable as Panel\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=null,t=-1;function _applyProbeStyles(e,t){for(let n of Object.keys(t))e.style[n]=t[n]}var HandleRegistry=class{_forward=new Map;_reverse=new WeakMap;_next=1;_finalizer=new FinalizationRegistry(e=>{this._forward.delete(e)});retain(e){let t=this._reverse.get(e);if(t!==void 0)return t;let n=this._mint(e);return this._forward.set(n,e),n}intern(e){let t=this._reverse.get(e);if(t!==void 0)return t;let n=this._mint(e);return this._forward.set(n,new WeakRef(e)),this._finalizer.register(e,n),n}resolve(e){let t=this._forward.get(e);if(t===void 0)throw Error(`DOM handle ${e} is not registered (released or never minted).`);let n=t instanceof WeakRef?t.deref():t;if(n===void 0)throw Error(`DOM handle ${e} refers to a collected node.`);return n}release(e){let t=this._forward.get(e);if(t===void 0)return;let n=t instanceof WeakRef?t.deref():t;n&&this._reverse.delete(n),this._forward.delete(e)}get size(){return this._forward.size}_mint(e){let t=this._next;return this._next+=1,this._reverse.set(e,t),t}},n=new HandleRegistry;function writeDeclaration(e,t,n){t.includes(`-`)?n===null?e.removeProperty(t):e.setProperty(t,n):n===null?e[t]=``:e[t]=n}function applyPatchTo(e,t){if(t.style)for(let n of Object.keys(t.style))writeDeclaration(e.style,n,t.style[n]);if(t.removeClass)for(let n of t.removeClass)e.classList.remove(n);if(t.addClass)for(let n of t.addClass)n&&e.classList.add(n);if(t.toggleClass)for(let n of Object.keys(t.toggleClass))e.classList.toggle(n,t.toggleClass[n]);if(t.removeAttr)for(let n of t.removeAttr)e.removeAttribute(n);if(t.setAttr)for(let n of Object.keys(t.setAttr))e.setAttribute(n,t.setAttr[n]);if(t.dataset)for(let n of Object.keys(t.dataset))e.dataset[n]=t.dataset[n];t.text!==void 0&&(e.textContent=t.text),t.scrollLeft!==void 0&&(e.scrollLeft=t.scrollLeft),t.scrollTop!==void 0&&(e.scrollTop=t.scrollTop)}var PatchBuilder=class{_commit;_patch={};constructor(e){this._commit=e}style(e,t){return(this._patch.style??={})[e]=t,this}addClass(e){return(this._patch.addClass??=[]).push(e),this}attr(e,t){return(this._patch.setAttr??={})[e]=t,this}text(e){return this._patch.text=e,this}commit(){this._commit(this._patch)}};function toRect(e){return{x:e.x,y:e.y,width:e.width,height:e.height,top:e.top,left:e.left,right:e.right,bottom:e.bottom}}var ProductionDOMSink=class{apply(e,t){applyPatchTo(n.resolve(e),t)}edit(e){return new PatchBuilder(t=>this.apply(e,t))}release(e){n.release(e)}setRuleStyle(e,t,n){writeDeclaration(e.style,t,n)}ensureStyleRule(e){let t=this.mainSheet();for(let n=0;n<t.cssRules.length;n+=1){let r=t.cssRules[n];if(r.selectorText===e)return r}let n=t.insertRule(e+`{}`,t.cssRules.length);return t.cssRules[n]}deleteStyleRule(e){if(typeof document>`u`)return;let t=this.mainSheet();for(let n=0;n<t.cssRules.length;n+=1)if(t.cssRules[n].selectorText===e){t.deleteRule(n);return}}ensureKeyframes(e,t){let n=this.mainSheet();for(let t=0;t<n.cssRules.length;t+=1){let r=n.cssRules[t];if(r.type===CSSRule.KEYFRAMES_RULE&&r.name===e)return}n.insertRule(`@keyframes `+e+` { `+t+` }`,n.cssRules.length)}mainSheet(){let e=document.getElementsByTagName(`head`)[0];e||(e=document.createElement(`head`),document.appendChild(e));let t=null,n=e.getElementsByTagName(`style`);for(let e=0;e<n.length;e+=1)n[e].id===`Base`&&(t=n[e]);return t||(t=document.createElement(`style`),t.id=`Base`,e.appendChild(t)),t.sheet}createElement(e){return n.retain(document.createElement(e))}createElementNS(e,t){return n.retain(document.createElementNS(e,t))}appendChild(e,t){n.resolve(e).appendChild(n.resolve(t))}removeChild(e,t){n.resolve(e).removeChild(n.resolve(t))}removeElement(e){n.resolve(e).remove()}focus(e,t){n.resolve(e).focus(t)}requestSubmit(e){n.resolve(e).requestSubmit()}blur(e){n.resolve(e).blur()}setValue(e,t){n.resolve(e).value=t}setSelectionRange(e,t,r){n.resolve(e).setSelectionRange(t,r)}addListener(e,t,r,i){n.resolve(e).addEventListener(t,r,i)}removeListener(e,t,r,i){n.resolve(e).removeEventListener(t,r,i)}dispatchEvent(e,t){n.resolve(e).dispatchEvent(t)}dispatchCustomEvent(e,t,r){n.resolve(e).dispatchEvent(new CustomEvent(t,r))}requestAnimationFrame(e){return requestAnimationFrame(e)}cancelAnimationFrame(e){cancelAnimationFrame(e)}setId(e,t){n.resolve(e).id=t}insertBefore(e,t,r){n.resolve(e).insertBefore(n.resolve(t),r===null?null:n.resolve(r))}createDocumentFragment(){return n.retain(document.createDocumentFragment())}click(e){n.resolve(e).click()}setPointerCapture(e,t){n.resolve(e).setPointerCapture(t)}releasePointerCapture(e,t){n.resolve(e).releasePointerCapture(t)}getContext(e,t,r){return n.resolve(e).getContext(t,r)}mountView(e,t){return t(n.resolve(e))}mediaPlay(e){n.resolve(e).play().catch(()=>{})}mediaPause(e){n.resolve(e).pause()}setCurrentTime(e,t){n.resolve(e).currentTime=t}setVolume(e,t){n.resolve(e).volume=t}setMuted(e,t){n.resolve(e).muted=t}setPlaybackRate(e,t){n.resolve(e).playbackRate=t}requestFullscreen(e){n.resolve(e).requestFullscreen().catch(()=>{})}exitFullscreen(){document.fullscreenElement&&document.exitFullscreen().catch(()=>{})}},ProductionDOMSource=class{intern(e){return n.intern(e)}isNode(e){return e instanceof Node}isElement(e){return e instanceof Element}escapeSelector(e){return typeof CSS<`u`&&typeof CSS.escape==`function`?CSS.escape(e):e.replace(/[^\w-]/g,e=>`\\`+e)}getViewportRect(e){return toRect(n.resolve(e.getElement()).getBoundingClientRect())}getElementRect(e){return toRect(n.resolve(e).getBoundingClientRect())}measureText(e,t={}){let{fontFamily:n=`var(--ts-ui-font-family, system-ui, sans-serif)`,fontSize:r=`var(--ts-ui-font-size, 14px)`,fontWeight:i=`normal`,fontStyle:a=`normal`,fontVariant:o=`normal`,fontStretch:s=`normal`,lineHeight:c=`calc(1em + var(--ts-ui-line-padding, 2px))`,maxWidth:l}=t,u=document.createElement(`span`);_applyProbeStyles(u,{position:`fixed`,visibility:`hidden`,whiteSpace:l===void 0?`nowrap`:`pre-wrap`,width:l===void 0?``:`${l}px`,fontFamily:n,fontSize:r,fontWeight:i,fontStyle:a,fontVariant:o,fontStretch:s,lineHeight:c}),u.textContent=e;let d=document.createElement(`span`);_applyProbeStyles(d,{display:`inline-block`,width:`0`,height:`0`,verticalAlign:`baseline`}),u.appendChild(d),document.body.appendChild(u);let f=u.getBoundingClientRect(),p=d.getBoundingClientRect();return document.body.removeChild(u),{width:Math.ceil(f.width),height:Math.ceil(f.height),baseline:Math.round(p.top-f.top)}}resolveFontSizePx(e){let t=document.createElement(`span`);_applyProbeStyles(t,{position:`fixed`,visibility:`hidden`,fontSize:e}),document.body.appendChild(t);let n=parseFloat(getComputedStyle(t).fontSize);return document.body.removeChild(t),isNaN(n)?14:n}measureFontMetrics(){e===null&&(e=document.createElement(`canvas`).getContext(`2d`));let t=e,n=this.getThemeVar(`--ts-ui-font-family`)||`system-ui, sans-serif`;t.font=`normal normal ${this.getThemeVar(`--ts-ui-font-size`)||`14px`} ${n}`;let r=t.measureText(`X`),i=typeof r.fontBoundingBoxAscent==`number`;return{ascent:i?r.fontBoundingBoxAscent:r.actualBoundingBoxAscent,descent:i?r.fontBoundingBoxDescent:r.actualBoundingBoxDescent,capTop:r.actualBoundingBoxAscent}}getThemeVar(e){return getComputedStyle(document.documentElement).getPropertyValue(e).trim()}getViewportSize(){return{width:Math.max(document.documentElement.clientWidth,window.innerWidth||0),height:Math.max(document.documentElement.clientHeight,window.innerHeight||0)}}getScrollBarWidth(){if(t>=0)return t;let e=document.createElement(`div`);_applyProbeStyles(e,{position:`absolute`,top:`-1000px`,left:`-1000px`,width:`100px`,height:`50px`,overflow:`hidden`});let n=document.createElement(`div`);_applyProbeStyles(n,{width:`100%`,height:`200px`}),e.appendChild(n),document.body.appendChild(e);let r=n.offsetWidth;_applyProbeStyles(e,{overflow:`auto`});let i=n.offsetWidth;return document.body.removeChild(e),t=r-i,t}getDevicePixelRatio(){return window.devicePixelRatio||1}isModelled(){return!1}getScrollLeft(e){return n.resolve(e).scrollLeft}getScrollTop(e){return n.resolve(e).scrollTop}getScrollMetrics(e){let t=n.resolve(e);return{scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight}}getOffsetSize(e){let t=n.resolve(e);return{offsetTop:t.offsetTop,offsetHeight:t.offsetHeight}}isConnected(e){return n.resolve(e).isConnected}getValue(e){return n.resolve(e).value}getActiveElement(){let e=document.activeElement;return e===null?null:n.intern(e)}matchMedia(e){if(typeof matchMedia!=`function`)return{matches:!1,addChangeListener:()=>{}};let t=matchMedia(e);return{matches:t.matches,addChangeListener(e){t.addEventListener(`change`,e)}}}isWindow(e){return e!==null&&n.resolve(e)===window}getWindow(){return n.intern(window)}contains(e,t){return n.resolve(e).contains(t===null?null:n.resolve(t))}querySelector(e,t){let r=n.resolve(e).querySelector(t);return r===null?null:n.intern(r)}querySelectorAll(e,t){return Array.from(n.resolve(e).querySelectorAll(t),e=>n.intern(e))}matches(e,t){return n.resolve(e).matches(t)}getParentElement(e){let t=n.resolve(e).parentElement;return t===null?null:n.intern(t)}getParentNode(e){let t=n.resolve(e).parentNode;return t===null?null:n.intern(t)}getFirstChild(e){let t=n.resolve(e).firstChild;return t===null?null:n.intern(t)}getBorderWidths(e){let t=getComputedStyle(n.resolve(e));return{top:t.borderTopWidth,right:t.borderRightWidth,bottom:t.borderBottomWidth,left:t.borderLeftWidth}}getComputedOverflow(e){let t=getComputedStyle(n.resolve(e));return{overflow:t.overflow,overflowX:t.overflowX,overflowY:t.overflowY}}getInlineStyle(e,t){let r=n.resolve(e).style;return t.includes(`-`)?r.getPropertyValue(t):r[t]}getDocumentElement(){return n.intern(document.documentElement)}getBody(){return n.intern(document.body)}getHead(){return n.intern(document.head)}onFontsReady(e){let t=document.fonts;t&&t.ready.then(()=>e())}getElementById(e){let t=document.getElementById(e);return t===null?null:n.intern(t)}getId(e){return n.resolve(e).id}getDataset(e,t){return n.resolve(e).dataset[t]}getTagName(e){return n.resolve(e).tagName}hasAttribute(e,t){return n.resolve(e).hasAttribute(t)}getAttribute(e,t){return n.resolve(e).getAttribute(t)}getNaturalSize(e){let t=n.resolve(e);return{width:t.naturalWidth,height:t.naturalHeight}}getMediaState(e){let t=n.resolve(e);return{currentTime:t.currentTime,duration:t.duration,paused:t.paused,ended:t.ended,volume:t.volume,muted:t.muted,playbackRate:t.playbackRate}}getFullscreenElement(){let e=document.fullscreenElement;return e?n.intern(e):null}getFiles(e){return n.resolve(e).files}hasPointerCapture(e,t){return n.resolve(e).hasPointerCapture(t)}elementsFromPoint(e,t){return Array.from(document.elementsFromPoint(e,t),e=>n.intern(e))}},r={sink:new ProductionDOMSink,source:new ProductionDOMSource,install(e){e.sink&&(r.sink=e.sink),e.source&&(r.source=e.source)},reset(){n=new HandleRegistry,r.sink=new ProductionDOMSink,r.source=new ProductionDOMSource}},i;(function(e){let t=-1,n=-1,a=-1,o=-1;function measureTextSize(e,t={}){let n=r.source.measureText(e,t);return{width:n.width,height:n.height}}e.measureTextSize=measureTextSize;function measureTextWidth(e,t){return measureTextSize(e,t).width}e.measureTextWidth=measureTextWidth;function linePaddingPx(){if(t>=0)return t;let e=r.source.getThemeVar(`--ts-ui-line-padding`),n=parseFloat(e);return t=isNaN(n)?2:n,t}function rootFontSizePx(){if(n>=0)return n;let e=r.source.getThemeVar(`--ts-ui-font-size`),t=parseFloat(e);return n=isNaN(t)?14:t,n}function lineHeightPx(e={}){let t=e.fontSizePx??rootFontSizePx(),n=e.linePadding??!0;return n===!0?t+=linePaddingPx():typeof n==`number`&&(t+=n),Math.round(t)}e.lineHeightPx=lineHeightPx;function measureTextBaseline(){if(a>=0)return a;let e=r.source.measureFontMetrics(),t=lineHeightPx()-(e.ascent+e.descent);return a=Math.round(t/2+e.ascent),a}e.measureTextBaseline=measureTextBaseline;function singleLineBoxHeight(e,t,n){let r=e.getTop()+e.getBottom()+(t?t.getTop()+t.getBottom():0)+n.top+n.bottom;return lineHeightPx()+r}e.singleLineBoxHeight=singleLineBoxHeight;function opticalCenterOffset(){if(o>=0)return o;let e=r.source.measureFontMetrics(),t=(e.ascent-e.descent)/2,n=e.capTop/2;return o=Math.max(0,Math.round(t-n)),o}e.opticalCenterOffset=opticalCenterOffset;function invalidateTextMetricsCache(){t=-1,n=-1,a=-1,o=-1}e.invalidateTextMetricsCache=invalidateTextMetricsCache;function generateUUID(){let e=`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,function(e){let t=Math.random()*16|0;return(e==`x`?t:t&3|8).toString(16)}),t=parseInt(e[0]);return i.isInteger(t)&&(e=`a`+e.substring(1,e.length)),e}e.generateUUID=generateUUID;function isInteger(e){return Number.isInteger(e)}e.isInteger=isInteger;function clamp(e,t,n){return Math.min(Math.max(e,t),n)}e.clamp=clamp;function kebabToCamel(e){return e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}e.kebabToCamel=kebabToCamel})(i||={});var BaseObject=class{_id;constructor(){this._id=i.generateUUID()}getId(){return this._id}setId(e){return this._id=e,this}getClassName(){return this.constructor.name}},a=2**53-1;function isUnbounded(e){return e>=2**53-1}function saturate(e){return Math.min(e,a)}function borderToStyle(e){let t=e.border??`none`;return{borderTop:e.borderTop??t,borderRight:e.borderRight??t,borderBottom:e.borderBottom??t,borderLeft:e.borderLeft??t}}function borderSideWidth(e){if(!e)return 0;let t=e.trim().match(/^([\d.]+)px\b/i);return t?parseFloat(t[1]):0}var Insets=class extends BaseObject{_top;_right;_bottom;_left;constructor(e,t,n,r){super(),this._top=e||0,this._right=t||0,this._bottom=n||0,this._left=r||0}getTop(){return this._top||0}setTop(e){return this._top=e,this}getRight(){return this._right||0}setRight(e){return this._right=e,this}getBottom(){return this._bottom||0}setBottom(e){return this._bottom=e,this}getLeft(){return this._left||0}setLeft(e){return this._left=e,this}set(e,t,n,r){return this._top=e,this._right=t,this._bottom=n,this._left=r,this}render(){return this.getTop()+`px `+this.getRight()+`px `+this.getBottom()+`px `+this.getLeft()+`px`}},o=function(e){return e.STATIC=`static`,e.FIXED=`fixed`,e.ABSOLUTE=`absolute`,e}({});export{a,BaseObject as c,PatchBuilder as d,ProductionDOMSink as f,borderToStyle as i,i as l,Insets as n,isUnbounded as o,ProductionDOMSource as p,borderSideWidth as r,saturate as s,o as t,r as u};
|
|
2
|
-
//# sourceMappingURL=Position-B-WfZYAJ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Position-B-WfZYAJ.js","names":[],"sources":["../../src/typescript/lib/core/DOM.ts","../../src/typescript/lib/core/Util.ts","../../src/typescript/lib/core/BaseObject.ts","../../src/typescript/lib/primitive/Size.ts","../../src/typescript/lib/primitive/Border.ts","../../src/typescript/lib/primitive/Insets.ts","../../src/typescript/lib/primitive/Position.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport type { TextMeasureOptions, TextMetrics } from \"~/core/Util.js\";\nimport type { Size } from \"~/primitive/Size.js\";\nimport type { Component } from \"~/core/Component.js\";\n\n// Production measurement caches. These live here because the irreducible\n// browser-measurement leaf (the off-screen probe, the canvas metrics context,\n// the scrollbar-width probe) is the production side of the read seam — the lone\n// place the framework touches the real DOM for measurement.\nlet _metricsCtx: CanvasRenderingContext2D | null = null;\nlet _scrollBarWidth: number = -1;\n\n/**\n * Applies a set of camelCase inline-style properties to an element, used by the\n * off-screen measurement probes below. Raw `style` access is intentional — this\n * is inside the seam's production implementation.\n */\nfunction _applyProbeStyles(element: HTMLElement, styles: Record<string, string>): void {\n for (const key of Object.keys(styles)) {\n (element.style as any)[key] = styles[key];\n }\n}\n\n/**\n * Plain serialisable rectangle in viewport coordinates. Deliberately *not* a\n * live [`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect):\n * the read seam returns plain data so the same call can be answered by a\n * geometry model (offline tests) or, in future, across a worker boundary.\n *\n * @remarks The `top` / `left` / `right` / `bottom` edges mirror `DOMRect`'s\n * derived fields so existing anchor-positioning call sites read this as a\n * drop-in for the rect they used to get from `getBoundingClientRect()`. A live\n * `DOMRect` is structurally assignable to a `Rect`.\n *\n * @category Core\n */\nexport interface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n left: number;\n right: number;\n bottom: number;\n}\n\n/**\n * Plain box-model snapshot — an element's native scroll offsets together with\n * its scrollable content size and visible viewport size, read in one shot.\n * Deliberately *not* a live element: like {@link Rect}, the read seam returns\n * plain data so the same call can be answered offline or across a worker\n * boundary.\n *\n * @category Core\n */\nexport interface ScrollMetrics {\n scrollTop: number;\n scrollLeft: number;\n scrollWidth: number;\n scrollHeight: number;\n clientWidth: number;\n clientHeight: number;\n}\n\n/**\n * Plain offset-box snapshot — an element's top edge and height relative to its\n * `offsetParent`. Plain data for the same reason as {@link ScrollMetrics}.\n *\n * @category Core\n */\nexport interface OffsetSize {\n offsetTop: number;\n offsetHeight: number;\n}\n\n/**\n * Plain snapshot of a media element's playback state, read in one shot through\n * {@link DOMSource.getMediaState}. Deliberately *not* a live element: like\n * {@link ScrollMetrics}, the read seam returns plain data so the same call can\n * be answered by a media model (offline tests) or across a worker boundary.\n *\n * @category Core\n */\nexport interface MediaState {\n /** Current playback position in seconds. */\n currentTime: number;\n /** Total media duration in seconds (`NaN` before metadata loads). */\n duration: number;\n /** Whether playback is currently paused. */\n paused: boolean;\n /** Whether playback has reached the end of the media. */\n ended: boolean;\n /** Current audio volume in `[0, 1]`. */\n volume: number;\n /** Whether audio is muted. */\n muted: boolean;\n /** Current playback speed multiplier (`1` is normal speed). */\n playbackRate: number;\n}\n\n/**\n * Opaque, serialisable element reference. A branded `number`, so a raw number\n * cannot be passed where a handle is expected and the reference forwards across\n * a worker boundary as plain data. The live `Node` it stands for never escapes\n * the seam — every sink/source method resolves the handle internally.\n *\n * @category Core\n */\nexport type Handle = number & { readonly __handleBrand: unique symbol };\n\n/**\n * A batch of mutations applied to a single element with one handle resolve.\n * Every field is plain serialisable data — no live element, no function — so a\n * worker transport forwards an entire patch as one `postMessage`.\n *\n * Application order is fixed: styles first, then class removals before\n * additions (so a `removeClass` + `addClass` of the same name lands \"on\"),\n * attribute removals before sets, then dataset / text / scroll.\n *\n * @category Core\n */\nexport interface ElementPatch {\n /** Inline style writes. `null` removes the property. camelCase or `--custom`. */\n style?: Readonly<Record<string, string | null>>;\n /** Classes to remove (applied before {@link ElementPatch.addClass}). */\n removeClass?: readonly string[];\n /** Classes to add. */\n addClass?: readonly string[];\n /** Classes to force on/off. */\n toggleClass?: Readonly<Record<string, boolean>>;\n /** Attributes to remove (applied before {@link ElementPatch.setAttr}). */\n removeAttr?: readonly string[];\n /** Attributes to set. */\n setAttr?: Readonly<Record<string, string>>;\n /** `data-*` writes (camelCase keys). */\n dataset?: Readonly<Record<string, string>>;\n /** Text content. */\n text?: string;\n /** Native horizontal scroll offset. */\n scrollLeft?: number;\n /** Native vertical scroll offset. */\n scrollTop?: number;\n}\n\n/**\n * Canonicalising handle registry — the lone holder of live DOM references in\n * the handle design. Maps a handle to its node (forward) and a node back to its\n * handle (reverse) so a node is never assigned two handles; that reverse map is\n * what makes handle equality mirror element equality.\n *\n * Two minting modes draw the leak-safety line. {@link HandleRegistry.retain} is\n * for nodes the framework owns (it created them): a strong forward entry,\n * released explicitly at the element's dispose site. {@link HandleRegistry.intern}\n * is for browser-supplied nodes the live DOM already owns: a weak forward entry\n * (`WeakRef`) plus a finalizer that drops the handle once the node is collected,\n * so interning can never pin a dead node.\n *\n * Module-private: only the production sink and source touch it.\n */\nclass HandleRegistry {\n private readonly _forward = new Map<Handle, Node | WeakRef<Node>>();\n private readonly _reverse = new WeakMap<Node, Handle>();\n private _next = 1;\n\n /** Drops the forward entry when a weakly-interned node is garbage-collected. */\n private readonly _finalizer = new FinalizationRegistry<Handle>((handle) => {\n this._forward.delete(handle);\n });\n\n /**\n * Mints a canonical handle for a node the framework owns (a created,\n * possibly-detached element). Strongly held so a detached node survives\n * until it is mounted or explicitly released.\n *\n * @param node - The owned node.\n * @returns Its canonical handle (stable across repeated calls).\n */\n retain(node: Node): Handle {\n const existing = this._reverse.get(node);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const handle = this._mint(node);\n\n this._forward.set(handle, node);\n\n return handle;\n }\n\n /**\n * Mints a canonical handle for a node supplied by the browser (an event\n * target, a `querySelector` result, the active element). The live DOM owns\n * it, so the registry holds only a weak reference plus a finalizer — no leak\n * even if the handle is never released.\n *\n * @param node - The browser-supplied node.\n * @returns Its canonical handle (stable while the node is alive).\n */\n intern(node: Node): Handle {\n const existing = this._reverse.get(node);\n\n if (existing !== undefined) {\n return existing;\n }\n\n const handle = this._mint(node);\n\n this._forward.set(handle, new WeakRef(node));\n this._finalizer.register(node, handle);\n\n return handle;\n }\n\n /**\n * Resolves a handle to its node. Throws on a released or collected handle —\n * a use-after-free becomes a loud failure instead of the silent no-op a\n * stale element pointer would give.\n *\n * @param handle - The handle to resolve.\n * @returns The live node.\n */\n resolve(handle: Handle): Node {\n const entry = this._forward.get(handle);\n\n if (entry === undefined) {\n throw new Error(`DOM handle ${handle} is not registered (released or never minted).`);\n }\n\n const node = entry instanceof WeakRef ? entry.deref() : entry;\n\n if (node === undefined) {\n throw new Error(`DOM handle ${handle} refers to a collected node.`);\n }\n\n return node;\n }\n\n /**\n * Releases an owned handle at its element's dispose site. Idempotent. A\n * missed release on a retained (strong) handle pins a detached element\n * forever, so the migration must place this at every created-element\n * teardown.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void {\n const entry = this._forward.get(handle);\n\n if (entry === undefined) {\n return;\n }\n\n const node = entry instanceof WeakRef ? entry.deref() : entry;\n\n if (node) {\n this._reverse.delete(node);\n }\n\n this._forward.delete(handle);\n }\n\n /** Live forward-map size — a test hook that verifies release / GC eviction. */\n get size(): number {\n return this._forward.size;\n }\n\n private _mint(node: Node): Handle {\n const handle = this._next as Handle;\n\n this._next += 1;\n this._reverse.set(node, handle);\n\n return handle;\n }\n}\n\n/** The shared production registry. Rebuilt together with the seams by {@link DOM.reset}. */\nlet _registry = new HandleRegistry();\n\n/** Forward-map size of the shared production registry; for tests only. @internal */\nexport function _handleRegistrySize(): number {\n return _registry.size;\n}\n\n/**\n * The single terminal style write, shared by the inline-style and patch paths.\n * A hyphenated key is either a custom property (`--foo`) or a standard\n * kebab-case name (`background-color`); both go through `setProperty` /\n * `removeProperty`. Only camelCase keys work through the indexed accessor.\n */\nfunction writeDeclaration(style: CSSStyleDeclaration, key: string, value: string | null): void {\n if (key.includes(\"-\")) {\n if (value === null) {\n style.removeProperty(key);\n } else {\n style.setProperty(key, value);\n }\n } else if (value === null) {\n (style as unknown as Record<string, string>)[key] = \"\";\n } else {\n (style as unknown as Record<string, string>)[key] = value;\n }\n}\n\n/**\n * Applies an {@link ElementPatch} to a resolved element — the terminal raw-DOM\n * write for the batched {@link DOMSink.apply} path. Fixed order: styles, class\n * removals before additions, attribute removals before sets, then dataset /\n * text / scroll.\n */\nfunction applyPatchTo(element: HTMLElement, patch: ElementPatch): void {\n if (patch.style) {\n for (const key of Object.keys(patch.style)) {\n writeDeclaration(element.style, key, patch.style[key]);\n }\n }\n\n if (patch.removeClass) {\n for (const name of patch.removeClass) {\n element.classList.remove(name);\n }\n }\n\n if (patch.addClass) {\n for (const name of patch.addClass) {\n // Skip empty tokens: `classList.add(\"\")` throws a SyntaxError. A\n // stray empty class name (e.g. an anonymous class whose\n // `constructor.name` is \"\") must not abort the whole patch.\n if (name) {\n element.classList.add(name);\n }\n }\n }\n\n if (patch.toggleClass) {\n for (const name of Object.keys(patch.toggleClass)) {\n element.classList.toggle(name, patch.toggleClass[name]);\n }\n }\n\n if (patch.removeAttr) {\n for (const key of patch.removeAttr) {\n element.removeAttribute(key);\n }\n }\n\n if (patch.setAttr) {\n for (const key of Object.keys(patch.setAttr)) {\n element.setAttribute(key, patch.setAttr[key]);\n }\n }\n\n if (patch.dataset) {\n for (const key of Object.keys(patch.dataset)) {\n element.dataset[key] = patch.dataset[key];\n }\n }\n\n if (patch.text !== undefined) {\n element.textContent = patch.text;\n }\n\n if (patch.scrollLeft !== undefined) {\n element.scrollLeft = patch.scrollLeft;\n }\n\n if (patch.scrollTop !== undefined) {\n element.scrollTop = patch.scrollTop;\n }\n}\n\n/**\n * Fluent accumulator over an {@link ElementPatch}. Each method appends to the\n * pending patch; {@link PatchBuilder.commit} flushes it as one batched write.\n * The fluent form is sugar for cold call sites — the batched {@link DOMSink.apply}\n * is the real primitive — and it allocates one builder per edit.\n *\n * @category Core\n */\nexport class PatchBuilder {\n private readonly _patch: {\n style?: Record<string, string | null>;\n addClass?: string[];\n setAttr?: Record<string, string>;\n text?: string;\n } = {};\n\n /**\n * @param _commit - Flush callback that performs the single handle resolve.\n */\n constructor(private readonly _commit: (patch: ElementPatch) => void) {}\n\n /**\n * Queues an inline-style write (`null` removes).\n *\n * @param key - The CSS property name (camelCase, or `--custom-property`).\n * @param value - The value to set, or null to remove the property.\n * @returns This builder.\n */\n style(key: string, value: string | null): this {\n (this._patch.style ??= {})[key] = value;\n\n return this;\n }\n\n /**\n * Queues a class addition.\n *\n * @param name - The class name.\n * @returns This builder.\n */\n addClass(name: string): this {\n (this._patch.addClass ??= []).push(name);\n\n return this;\n }\n\n /**\n * Queues an attribute set.\n *\n * @param key - The attribute name.\n * @param value - The attribute value.\n * @returns This builder.\n */\n attr(key: string, value: string): this {\n (this._patch.setAttr ??= {})[key] = value;\n\n return this;\n }\n\n /**\n * Queues a text-content write.\n *\n * @param value - The text content.\n * @returns This builder.\n */\n text(value: string): this {\n this._patch.text = value;\n\n return this;\n }\n\n /** Flushes the accumulated patch through one batched write (one resolve). */\n commit(): void {\n this._commit(this._patch);\n }\n}\n\n/**\n * Terminal DOM-write primitive. Every structural mutation and inline-style\n * write in the framework funnels through this seam instead of touching\n * `element.style` / `element.classList` / `appendChild` directly. The\n * production implementation ({@link ProductionDOMSink}) is a thin pass-through;\n * test implementations record the writes without touching a DOM.\n *\n * @remarks Methods are one-way (no return value drives control flow), so a\n * future worker transport can forward each as a `postMessage`.\n *\n * @category Core\n */\nexport interface DOMSink {\n /**\n * Applies a batch of mutations to one element with a single handle resolve.\n * The hot-path primitive that replaces the ten per-write data setters\n * (`setStyle`, `addClass`, `removeClass`, `toggleClass`, `setAttribute`,\n * `removeAttribute`, `setDataset`, `setTextContent`, `setScrollLeft`,\n * `setScrollTop`): a layout commit (width + height + classes + an attribute)\n * costs one `Map.get`, not one per write.\n *\n * @param handle - The target element handle.\n * @param patch - The batch of mutations.\n */\n apply(handle: Handle, patch: ElementPatch): void;\n\n /**\n * Fluent convenience that accumulates a patch and flushes it through a\n * single {@link apply}. For cold call sites — it allocates one builder per\n * edit.\n *\n * @param handle - The target element handle.\n * @returns A builder whose `commit()` performs the single resolve.\n */\n edit(handle: Handle): PatchBuilder;\n\n /**\n * Releases an owned (retained) handle at its element's dispose site.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void;\n\n /**\n * Writes a single style property onto a `CSSStyleRule`'s declaration. A\n * `CSSStyleRule` has no element, so it gets its own method.\n *\n * @param rule - The target `CSSStyleRule`.\n * @param key - The CSS property name (camelCase, or `--custom-property`).\n * @param value - The value to set, or null to remove the property.\n */\n setRuleStyle(rule: CSSStyleRule, key: string, value: string | null): void;\n\n /**\n * Finds, or inserts, the framework's shared-stylesheet `CSSStyleRule` for a\n * selector. Encapsulates the `cssRules` scan and `insertRule` so callers\n * never walk a `CSSStyleSheet` directly; the returned rule is handed to\n * {@link setRuleStyle}.\n *\n * @param selector - The CSS selector text.\n * @returns The existing or newly-inserted rule.\n */\n ensureStyleRule(selector: string): CSSStyleRule;\n\n /**\n * Removes the shared-stylesheet `CSSStyleRule` for a selector, if present.\n * The inverse of {@link ensureStyleRule}; scans `cssRules` for the matching\n * `selectorText` and `deleteRule()`s it. A no-op when no rule matches.\n *\n * @param selector - The CSS selector text of the rule to remove.\n */\n deleteStyleRule(selector: string): void;\n\n /**\n * Inserts a `@keyframes` block into the shared stylesheet if one with the\n * given name does not already exist (idempotent).\n *\n * @param name - The animation name (no `@keyframes` prefix).\n * @param body - The keyframe body (the text between the braces).\n */\n ensureKeyframes(name: string, body: string): void;\n\n /**\n * Creates a detached HTML element, retained behind a handle until released.\n *\n * @param tag - The element tag name.\n * @returns The new element's handle.\n */\n createElement(tag: string): Handle;\n\n /**\n * Creates a detached namespaced element (SVG sprite / glyph construction),\n * retained behind a handle until released.\n *\n * @param ns - The element namespace URI.\n * @param tag - The element tag name.\n * @returns The new element's handle.\n */\n createElementNS(ns: string, tag: string): Handle;\n\n /**\n * Appends a child to a parent.\n *\n * @param parent - The parent handle.\n * @param child - The child handle to append.\n */\n appendChild(parent: Handle, child: Handle): void;\n\n /**\n * Removes a child from a parent.\n *\n * @param parent - The parent handle.\n * @param child - The child handle to remove.\n */\n removeChild(parent: Handle, child: Handle): void;\n\n /**\n * Detaches an element from its parent.\n *\n * @param handle - The element to remove.\n */\n removeElement(handle: Handle): void;\n\n /**\n * Moves browser focus to an element.\n *\n * @param handle - The element to focus.\n * @param options - Focus options; `preventScroll` suppresses the native\n * scroll-into-view so a host that owns its own scroll offset is not fought.\n */\n focus(handle: Handle, options?: { preventScroll?: boolean }): void;\n\n /**\n * Requests a native form submission on a `<form>` element, firing the\n * cancelable `submit` event and running constraint validation.\n *\n * @param handle - The form element to submit.\n */\n requestSubmit(handle: Handle): void;\n\n /**\n * Removes browser focus from an element.\n *\n * @param handle - The element to blur.\n */\n blur(handle: Handle): void;\n\n /**\n * Writes the value of a form control.\n *\n * @param handle - The target form control.\n * @param value - The value to set.\n */\n setValue(handle: Handle, value: string): void;\n\n /**\n * Sets the text-selection range of a form control.\n *\n * @param handle - The target form control.\n * @param start - The selection start offset.\n * @param end - The selection end offset.\n */\n setSelectionRange(handle: Handle, start: number, end: number): void;\n\n /**\n * Registers a native event listener on a target. The framework's\n * {@link Event} class is the component-level routing layer; this seam covers\n * the low-level native hook it (and a few primitives) sits on.\n *\n * @param target - The event target handle (element, window, media-query list).\n * @param type - The event type.\n * @param handler - The listener.\n * @param options - Optional capture/passive/once options.\n */\n addListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | AddEventListenerOptions): void;\n\n /**\n * Removes a native event listener previously registered with {@link addListener}.\n *\n * @param target - The event target handle.\n * @param type - The event type.\n * @param handler - The listener to remove.\n * @param options - Optional capture options matching the registration.\n */\n removeListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | EventListenerOptions): void;\n\n /**\n * Dispatches an event on a target.\n *\n * @param target - The event target handle.\n * @param event - The event to dispatch.\n */\n dispatchEvent(target: Handle, event: Event): void;\n\n /**\n * Builds and dispatches a custom event of `type` with the given init on a\n * target. The framework's sole construction site for fired custom events:\n * the production sink mints a native `CustomEvent`, while the modelled sink\n * builds a plain sentinel event, so production code never names the global\n * `CustomEvent` constructor. `init` is a `CustomEventInit`, so `init.detail`\n * surfaces as the event's `detail` exactly as the inline `new CustomEvent`\n * it replaces did.\n *\n * @param target - The event target handle.\n * @param type - The event type (e.g. `\"keydown\"`).\n * @param init - Optional `CustomEventInit` (carries `detail`).\n */\n dispatchCustomEvent(target: Handle, type: string, init?: CustomEventInit): void;\n\n /**\n * Schedules a callback for the next animation frame.\n *\n * @param callback - The frame callback.\n * @returns The request handle, for {@link cancelAnimationFrame}.\n */\n requestAnimationFrame(callback: FrameRequestCallback): number;\n\n /**\n * Cancels a previously scheduled animation-frame callback.\n *\n * @param handle - The handle returned by {@link requestAnimationFrame}.\n */\n cancelAnimationFrame(handle: number): void;\n\n /**\n * Sets an element's `id`.\n *\n * @param handle - The target element.\n * @param id - The id to set.\n */\n setId(handle: Handle, id: string): void;\n\n /**\n * Inserts a node before a reference child of a parent.\n *\n * @param parent - The parent handle.\n * @param node - The node to insert.\n * @param reference - The child to insert before, or null to append.\n */\n insertBefore(parent: Handle, node: Handle, reference: Handle | null): void;\n\n /**\n * Creates an empty document fragment for batched insertion, retained behind\n * a handle until released.\n *\n * @returns The new fragment's handle.\n */\n createDocumentFragment(): Handle;\n\n /**\n * Synthesises a click on an element (file-input open, download anchor).\n *\n * @param handle - The element to click.\n */\n click(handle: Handle): void;\n\n /**\n * Routes subsequent pointer events for a pointer id to an element.\n *\n * @param handle - The capturing element.\n * @param pointerId - The pointer id to capture.\n */\n setPointerCapture(handle: Handle, pointerId: number): void;\n\n /**\n * Releases a pointer capture previously set on an element.\n *\n * @param handle - The element holding the capture.\n * @param pointerId - The pointer id to release.\n */\n releasePointerCapture(handle: Handle, pointerId: number): void;\n\n /**\n * Obtains a drawing context from a `<canvas>` element. Generic over\n * `contextId` (`\"2d\"`, `\"webgl\"`, `\"webgl2\"`) so a single seam entry serves\n * both the raster and WebGL components, each narrowing the returned union\n * itself.\n *\n * @remarks Unlike every other sink method this returns a live object rather\n * than a forwardable one-way write: a rendering context cannot cross a worker\n * boundary, so a modelled sink returns `null` and the caller no-ops offline.\n * This is the single, named escape from the seam's one-way contract — the\n * reason a canvas is a live-only component.\n *\n * @param handle - The `<canvas>` element handle.\n * @param contextId - The context identifier (`\"2d\"`, `\"webgl\"`, …).\n * @param options - Optional context attributes (e.g. `{ alpha: false }`).\n * @returns The rendering context, or `null` when unavailable (offline, or the\n * element does not support the requested context).\n */\n getContext(handle: Handle, contextId: string, options?: unknown): RenderingContext | null;\n\n /**\n * Resolves `handle` to its real element and hands it to `factory`, which\n * mounts a foreign live widget (a third-party library that takes a parent\n * element and mutates a whole DOM region it owns) into it — the second\n * named escape from the seam's one-way contract, after {@link getContext}.\n *\n * @remarks Like `getContext`, this returns a live object rather than a\n * forwardable one-way write: the mounted widget instance cannot cross a\n * worker boundary, so a modelled sink returns `null` and the caller no-ops\n * offline. This is the reason a component built on `mountView` (e.g.\n * `CodeEditor` on CodeMirror's `EditorView`) is live-only. `factory`'s\n * parameter is deliberately left unannotated at call sites outside this\n * seam — its type is inferred from this signature — so no call site names\n * a DOM element type and trips `no-raw-dom`'s *hold* clause.\n *\n * @param handle - The element handle to mount the foreign widget into.\n * @param factory - Builds and returns the foreign widget given the\n * resolved parent element.\n * @returns Whatever `factory` returns, or `null` offline / when the handle\n * does not resolve.\n */\n mountView<T>(handle: Handle, factory: (parent: HTMLElement) => T): T | null;\n\n /**\n * Starts (or resumes) playback of a media element. Wraps the `play()` IDL\n * method, whose returned promise is intentionally dropped — playback state is\n * observed through media events, not the promise.\n *\n * @param handle - The `<video>` / `<audio>` element handle.\n */\n mediaPlay(handle: Handle): void;\n\n /**\n * Pauses playback of a media element.\n *\n * @param handle - The media element handle.\n */\n mediaPause(handle: Handle): void;\n\n /**\n * Seeks a media element to a playback position.\n *\n * @param handle - The media element handle.\n * @param seconds - The target position in seconds.\n */\n setCurrentTime(handle: Handle, seconds: number): void;\n\n /**\n * Sets a media element's audio volume.\n *\n * @param handle - The media element handle.\n * @param value - The volume in `[0, 1]`.\n */\n setVolume(handle: Handle, value: number): void;\n\n /**\n * Sets a media element's muted state (the IDL property, which the boolean\n * attribute alone cannot toggle after load).\n *\n * @param handle - The media element handle.\n * @param muted - Whether audio is muted.\n */\n setMuted(handle: Handle, muted: boolean): void;\n\n /**\n * Sets a media element's playback speed multiplier.\n *\n * @param handle - The media element handle.\n * @param rate - The playback rate (`1` is normal speed).\n */\n setPlaybackRate(handle: Handle, rate: number): void;\n\n /**\n * Requests that an element enter fullscreen. Must be called from a user\n * gesture handler; the returned promise is dropped — the transition is\n * observed through the `fullscreenchange` event.\n *\n * @param handle - The element to display fullscreen.\n */\n requestFullscreen(handle: Handle): void;\n\n /**\n * Exits fullscreen for the document. No-op when nothing is fullscreen.\n */\n exitFullscreen(): void;\n}\n\n/**\n * Read seam. Geometry is keyed on the owning {@link Component} (so a model can\n * reproduce it from committed state); text metrics, theme variables, and\n * environment constants funnel through the remaining methods. The production\n * implementation ({@link ProductionDOMSource}) reads the live DOM; test\n * implementations answer from a geometry model and a baked metrics table.\n *\n * @category Core\n */\nexport interface DOMSource {\n /**\n * Converts a raw browser node arriving at an event boundary into a (weak)\n * handle. The one place a raw target legitimately enters the seam from\n * outside — the event system hands it `evnt.target`, and the handle is\n * interned so no call site downstream holds the raw node.\n *\n * @param target - The browser-supplied event target.\n * @returns Its canonical handle.\n */\n intern(target: EventTarget): Handle;\n\n /**\n * Whether a raw value arriving at an event boundary is a DOM node. Replaces\n * call-site `value instanceof Node` guards (which name a global constructor)\n * so an `EventTarget | null` field can be narrowed before {@link intern}.\n *\n * @param value - The raw value to test (typically `e.relatedTarget` / `e.target`).\n * @returns `true` when the value is a node; production matches `instanceof Node`.\n * The `EventTarget` type guard lets a nullable event field narrow for\n * the subsequent {@link intern}.\n */\n isNode(value: unknown): value is EventTarget;\n\n /**\n * Whether a raw value is a DOM element — {@link isNode} narrowed to elements.\n * Replaces call-site `value instanceof Element`.\n *\n * @param value - The raw value to test.\n * @returns `true` when the value is an element; production matches `instanceof Element`.\n */\n isElement(value: unknown): value is EventTarget;\n\n /**\n * Escapes a string for safe use inside a CSS selector. Replaces call-site\n * `CSS.escape`, which names a global the offline harness does not ship.\n *\n * @param value - The raw string (e.g. a glyph id).\n * @returns The escaped string; production uses `CSS.escape`.\n */\n escapeSelector(value: string): string;\n\n /**\n * Returns the viewport-space rectangle of a component's root element.\n *\n * @param component - The component to measure.\n * @returns The component's bounding rectangle as plain data.\n */\n getViewportRect(component: Component): Rect;\n\n /**\n * Returns the viewport-space rectangle of an arbitrary element. Escape\n * hatch for non-component nodes (anchor elements, ancestor scroll boxes).\n *\n * @param handle - The element to measure.\n * @returns The element's bounding rectangle as plain data.\n */\n getElementRect(handle: Handle): Rect;\n\n /**\n * Measures the rendered size and baseline of a text string.\n *\n * @param text - The string to measure.\n * @param options - Font properties; default to the active theme variables.\n * @returns The measured `{width, height, baseline}` in pixels.\n */\n measureText(text: string, options?: TextMeasureOptions): TextMetrics;\n\n /**\n * Resolves a CSS `font-size` value (possibly a `calc()`/`var()`) to a pixel\n * number by evaluating it on an off-screen probe.\n *\n * @param fontSizeCSS - A CSS font-size value.\n * @returns The resolved size in pixels (14 when unresolvable).\n */\n resolveFontSizePx(fontSizeCSS: string): number;\n\n /**\n * Returns the active font's vertical metrics in pixels.\n *\n * @returns The font `{ascent, descent, capTop}` in pixels.\n */\n measureFontMetrics(): { ascent: number; descent: number; capTop: number };\n\n /**\n * Resolves a theme CSS variable (e.g. `--ts-ui-font-size`) to its value.\n *\n * @param name - The CSS custom-property name, including the leading `--`.\n * @returns The resolved value, trimmed; empty string when unset.\n */\n getThemeVar(name: string): string;\n\n /**\n * Returns the current viewport size in pixels.\n *\n * @returns The viewport `{width, height}`.\n */\n getViewportSize(): Size;\n\n /**\n * Returns the native scrollbar width in pixels.\n *\n * @returns The scrollbar width.\n */\n getScrollBarWidth(): number;\n\n /**\n * Returns the display's device-pixel ratio — the factor by which a\n * `<canvas>` backing store must be scaled above its CSS size to stay crisp\n * on a HiDPI display. Reads the flagged `window.devicePixelRatio` global\n * behind the seam; a modelled source reports `1` so offline backing-store\n * math stays deterministic.\n *\n * @returns The device-pixel ratio (`1` or greater); `1` when unavailable.\n */\n getDevicePixelRatio(): number;\n\n /**\n * Whether this is a modelled (no-browser) source. Lets the few\n * irreducibly-browser reads short-circuit to a fallback offline.\n *\n * @returns `true` for a modelled source, `false` for production.\n */\n isModelled(): boolean;\n\n /**\n * Reads an element's native horizontal scroll offset (browser-clamped).\n *\n * @param handle - The element to read.\n * @returns The current `scrollLeft` in pixels.\n */\n getScrollLeft(handle: Handle): number;\n\n /**\n * Reads an element's native vertical scroll offset (browser-clamped).\n *\n * @param handle - The element to read.\n * @returns The current `scrollTop` in pixels.\n */\n getScrollTop(handle: Handle): number;\n\n /**\n * Reads an element's scroll offsets, scrollable content size, and visible\n * viewport size in one shot.\n *\n * @param handle - The element to measure.\n * @returns The element's {@link ScrollMetrics} as plain data.\n */\n getScrollMetrics(handle: Handle): ScrollMetrics;\n\n /**\n * Reads an element's offset-box top edge and height.\n *\n * @param handle - The element to measure.\n * @returns The element's {@link OffsetSize} as plain data.\n */\n getOffsetSize(handle: Handle): OffsetSize;\n\n /**\n * Whether an element is currently attached to a document.\n *\n * @param handle - The element to test.\n * @returns `true` when the element is connected.\n */\n isConnected(handle: Handle): boolean;\n\n /**\n * Reads the value of a form control.\n *\n * @param handle - The form control to read.\n * @returns The control's current value.\n */\n getValue(handle: Handle): string;\n\n /**\n * Returns the element that currently has focus, or null.\n *\n * @returns The active element handle, or null when nothing is focused.\n */\n getActiveElement(): Handle | null;\n\n /**\n * Evaluates a media query, returning its current match state and a\n * change-subscription hook. The live `MediaQueryList` never escapes the seam.\n *\n * @param query - The media-query string.\n * @returns The match state and a `change` subscription.\n */\n matchMedia(query: string): MediaQueryResult;\n\n /**\n * Whether an event target is the global `window` (identity check that keeps\n * the raw global out of call sites).\n *\n * @param target - The target handle to test, or null.\n * @returns `true` when the target is `window`.\n */\n isWindow(target: Handle | null): boolean;\n\n /**\n * Returns the global `window` interned to a handle, so window-level\n * listeners can be registered without a call site naming the raw global.\n *\n * @returns The `window` handle.\n */\n getWindow(): Handle;\n\n /**\n * Whether a node is the ancestor of (or equal to) another node.\n *\n * @param ancestor - The candidate ancestor handle.\n * @param node - The node handle to test, or null.\n * @returns `true` when `ancestor` contains `node`.\n */\n contains(ancestor: Handle, node: Handle | null): boolean;\n\n /**\n * Finds the first descendant of `root` matching a selector.\n *\n * @param root - The subtree root handle.\n * @param selector - The CSS selector.\n * @returns The first match handle, or null.\n */\n querySelector(root: Handle, selector: string): Handle | null;\n\n /**\n * Finds all descendants of `root` matching a selector, as a plain array.\n *\n * @param root - The subtree root handle.\n * @param selector - The CSS selector.\n * @returns The match handles (a snapshot array, never a live `NodeList`).\n */\n querySelectorAll(root: Handle, selector: string): Handle[];\n\n /**\n * Whether an element itself matches a selector. The self-test counterpart to\n * {@link DOMSource.querySelector}, which only sees descendants — needed when\n * a component's own root element is the candidate (a `TextField` renders as\n * the `<input>` itself, with no focusable descendant to find).\n *\n * @param handle - The element to test.\n * @param selector - The CSS selector.\n * @returns `true` when the element matches.\n */\n matches(handle: Handle, selector: string): boolean;\n\n /**\n * Returns an element's parent element, or null.\n *\n * @param handle - The element to read.\n * @returns The parent element handle, or null.\n */\n getParentElement(handle: Handle): Handle | null;\n\n /**\n * Returns a node's parent node, or null.\n *\n * @param handle - The node to read.\n * @returns The parent node handle, or null.\n */\n getParentNode(handle: Handle): Handle | null;\n\n /**\n * Returns a node's first child, or null.\n *\n * @param handle - The node to read.\n * @returns The first child handle, or null.\n */\n getFirstChild(handle: Handle): Handle | null;\n\n /**\n * Returns an element's resolved border widths as computed-style strings\n * (e.g. `\"1px\"`), one per side.\n *\n * @param handle - The element to measure.\n * @returns The four border-width strings.\n */\n getBorderWidths(handle: Handle): { top: string; right: string; bottom: string; left: string };\n\n /**\n * Returns an element's resolved `overflow` / `overflow-x` / `overflow-y`\n * computed-style strings.\n *\n * @param handle - The element to read.\n * @returns The three overflow strings.\n */\n getComputedOverflow(handle: Handle): { overflow: string; overflowX: string; overflowY: string };\n\n /**\n * Reads a single inline style property off an element.\n *\n * @param handle - The element to read.\n * @param key - The CSS property name (camelCase, or `--custom-property`).\n * @returns The inline value (empty string when unset).\n */\n getInlineStyle(handle: Handle, key: string): string;\n\n /**\n * Returns the document's root `<html>` element — the mount point for\n * top-layer overlays.\n *\n * @returns The document element handle.\n */\n getDocumentElement(): Handle;\n\n /**\n * Returns the document `<body>` element.\n *\n * @returns The body element handle.\n */\n getBody(): Handle;\n\n /**\n * Returns the document `<head>` element.\n *\n * @returns The head element handle.\n */\n getHead(): Handle;\n\n /**\n * Registers a callback fired once the document's web fonts have finished\n * loading (i.e. `document.fonts.ready` resolves). Text whose preferred size\n * was measured against a fallback font before a `font-display: swap` web\n * font swapped in must re-measure once the real font is available, or its\n * stale (fallback-derived) size clips the now-wider glyphs. Offline sources\n * measure against baked fonts with no async swap, so they never invoke it.\n *\n * @param callback - Invoked once when font loading settles.\n */\n onFontsReady(callback: () => void): void;\n\n /**\n * Looks up an element by its `id`.\n *\n * @param id - The element id (no `#` prefix).\n * @returns The matching element handle, or null.\n */\n getElementById(id: string): Handle | null;\n\n /**\n * Reads an element's `id`.\n *\n * @param handle - The element to read.\n * @returns The element's id (empty string when unset).\n */\n getId(handle: Handle): string;\n\n /**\n * Reads a `data-*` attribute via the element's dataset.\n *\n * @param handle - The element to read.\n * @param key - The dataset key (camelCase).\n * @returns The value, or undefined when unset.\n */\n getDataset(handle: Handle, key: string): string | undefined;\n\n /**\n * Reads an element's tag name (uppercase).\n *\n * @param handle - The element to read.\n * @returns The tag name.\n */\n getTagName(handle: Handle): string;\n\n /**\n * Whether an element has a given attribute.\n *\n * @param handle - The element to test.\n * @param key - The attribute name.\n * @returns `true` when the attribute is present.\n */\n hasAttribute(handle: Handle, key: string): boolean;\n\n /**\n * Reads an attribute value.\n *\n * @param handle - The element to read.\n * @param key - The attribute name.\n * @returns The value, or null when unset.\n */\n getAttribute(handle: Handle, key: string): string | null;\n\n /**\n * Reads an image's intrinsic pixel size.\n *\n * @param handle - The image element.\n * @returns The natural `{width, height}` in pixels.\n */\n getNaturalSize(handle: Handle): { width: number; height: number };\n\n /**\n * Reads a media element's playback state in one shot as plain data.\n *\n * @param handle - The `<video>` / `<audio>` element handle.\n * @returns The element's {@link MediaState}.\n */\n getMediaState(handle: Handle): MediaState;\n\n /**\n * Returns the element currently displayed fullscreen, or `null` when nothing\n * is. Reads `document.fullscreenElement` behind the seam so no call site\n * names the global.\n *\n * @returns The fullscreen element handle, or `null`.\n */\n getFullscreenElement(): Handle | null;\n\n /**\n * Reads the selected files of a file input.\n *\n * @param handle - The file-input element.\n * @returns The selected `FileList`, or null.\n */\n getFiles(handle: Handle): FileList | null;\n\n /**\n * Whether an element currently holds a given pointer capture.\n *\n * @param handle - The element to test.\n * @param pointerId - The pointer id.\n * @returns `true` when the element captures the pointer.\n */\n hasPointerCapture(handle: Handle, pointerId: number): boolean;\n\n /**\n * Returns the stack of elements at a viewport point (hit-testing).\n *\n * @param x - The viewport x coordinate.\n * @param y - The viewport y coordinate.\n * @returns The element handles at the point, topmost first.\n */\n elementsFromPoint(x: number, y: number): Handle[];\n}\n\n/**\n * Seam-friendly result of {@link DOMSource.matchMedia}: the current match state\n * plus a change subscription, so the live `MediaQueryList` stays behind the seam.\n *\n * @category Core\n */\nexport interface MediaQueryResult {\n /** Whether the query currently matches. */\n matches: boolean;\n /**\n * Subscribes to match-state changes.\n *\n * @param handler - Called on each `change` of the query.\n */\n addChangeListener(handler: (event: MediaQueryListEvent) => void): void;\n}\n\n/**\n * Boxes a live `DOMRect` into a plain {@link Rect}, preserving every edge.\n */\nfunction toRect(domRect: DOMRect): Rect {\n return {\n x: domRect.x,\n y: domRect.y,\n width: domRect.width,\n height: domRect.height,\n top: domRect.top,\n left: domRect.left,\n right: domRect.right,\n bottom: domRect.bottom\n };\n}\n\n/**\n * Production {@link DOMSink}: every method is a one-line pass-through to the\n * native DOM, behaving bit-for-bit like the pre-seam direct writes.\n *\n * @category Core\n */\nexport class ProductionDOMSink implements DOMSink {\n /**\n * Applies a batch of mutations to one element with a single handle resolve.\n * The hot-path primitive — a layout commit (width + height + classes + an\n * attribute) costs one `Map.get`, not one per write.\n *\n * @param handle - The target element handle.\n * @param patch - The batch of mutations.\n */\n apply(handle: Handle, patch: ElementPatch): void {\n applyPatchTo(_registry.resolve(handle) as HTMLElement, patch);\n }\n\n /**\n * Fluent convenience that accumulates a patch and flushes it through a\n * single {@link ProductionDOMSink.apply}. For cold call sites — it allocates\n * one builder per edit.\n *\n * @param handle - The target element handle.\n * @returns A builder whose `commit()` performs the single resolve.\n */\n edit(handle: Handle): PatchBuilder {\n return new PatchBuilder((patch) => this.apply(handle, patch));\n }\n\n /**\n * Releases an owned (retained) handle at its element's dispose site.\n *\n * @param handle - The handle to release.\n */\n release(handle: Handle): void {\n _registry.release(handle);\n }\n\n /** @inheritDoc */\n setRuleStyle(rule: CSSStyleRule, key: string, value: string | null): void {\n writeDeclaration(rule.style, key, value);\n }\n\n /** @inheritDoc */\n ensureStyleRule(selector: string): CSSStyleRule {\n const sheet = this.mainSheet();\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n const rule = sheet.cssRules[idx] as CSSStyleRule;\n\n if (rule.selectorText === selector) {\n return rule;\n }\n }\n\n const insertedAt = sheet.insertRule(selector + \"{}\", sheet.cssRules.length);\n\n return sheet.cssRules[insertedAt] as CSSStyleRule;\n }\n\n /** @inheritDoc */\n deleteStyleRule(selector: string): void {\n // Best-effort cleanup reached from the component GC finalizer, which runs\n // decoupled from the DOM lifecycle: at GC time this production sink may be\n // active in a headless environment (the node test env, or after a\n // DOM.reset()). With no document there is no shared sheet and nothing to\n // delete, so no-op rather than dereference `document` in `mainSheet()`.\n if (typeof document === \"undefined\") {\n return;\n }\n\n const sheet = this.mainSheet();\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n const rule = sheet.cssRules[idx] as CSSStyleRule;\n\n if (rule.selectorText === selector) {\n sheet.deleteRule(idx);\n return;\n }\n }\n }\n\n /** @inheritDoc */\n ensureKeyframes(name: string, body: string): void {\n const sheet = this.mainSheet();\n\n for (let idx = 0; idx < sheet.cssRules.length; idx += 1) {\n const rule = sheet.cssRules[idx] as CSSKeyframesRule;\n\n if (rule.type === CSSRule.KEYFRAMES_RULE && rule.name === name) {\n return;\n }\n }\n\n sheet.insertRule('@keyframes ' + name + ' { ' + body + ' }', sheet.cssRules.length);\n }\n\n /**\n * Returns the framework's shared `<style id=\"Base\">` stylesheet, creating\n * the `<head>` and `<style>` element on first call. The lone place the\n * framework touches a `CSSStyleSheet` — relocated here from `StyleTarget`\n * so the stylesheet plumbing lives behind the seam.\n */\n private mainSheet(): CSSStyleSheet {\n let head = document.getElementsByTagName(\"head\")[0] as HTMLHeadElement;\n\n if (!head) {\n head = document.createElement(\"head\");\n document.appendChild(head);\n }\n\n let style: HTMLStyleElement | null = null;\n const styles = head.getElementsByTagName(\"style\");\n\n for (let idx = 0; idx < styles.length; idx += 1) {\n if (styles[idx].id === \"Base\") {\n style = styles[idx];\n }\n }\n\n if (!style) {\n style = document.createElement(\"style\");\n style.id = \"Base\";\n head.appendChild(style);\n }\n\n return style.sheet as CSSStyleSheet;\n }\n\n /** @inheritDoc */\n createElement(tag: string): Handle {\n return _registry.retain(document.createElement(tag));\n }\n\n /** @inheritDoc */\n createElementNS(ns: string, tag: string): Handle {\n return _registry.retain(document.createElementNS(ns, tag));\n }\n\n /** @inheritDoc */\n appendChild(parent: Handle, child: Handle): void {\n _registry.resolve(parent).appendChild(_registry.resolve(child));\n }\n\n /** @inheritDoc */\n removeChild(parent: Handle, child: Handle): void {\n _registry.resolve(parent).removeChild(_registry.resolve(child));\n }\n\n /** @inheritDoc */\n removeElement(handle: Handle): void {\n (_registry.resolve(handle) as Element).remove();\n }\n\n /** @inheritDoc */\n focus(handle: Handle, options?: { preventScroll?: boolean }): void {\n (_registry.resolve(handle) as HTMLElement).focus(options);\n }\n\n /** @inheritDoc */\n requestSubmit(handle: Handle): void {\n (_registry.resolve(handle) as HTMLFormElement).requestSubmit();\n }\n\n /** @inheritDoc */\n blur(handle: Handle): void {\n (_registry.resolve(handle) as HTMLElement).blur();\n }\n\n /** @inheritDoc */\n setValue(handle: Handle, value: string): void {\n (_registry.resolve(handle) as HTMLInputElement).value = value;\n }\n\n /** @inheritDoc */\n setSelectionRange(handle: Handle, start: number, end: number): void {\n (_registry.resolve(handle) as HTMLInputElement).setSelectionRange(start, end);\n }\n\n /** @inheritDoc */\n addListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | AddEventListenerOptions): void {\n _registry.resolve(target).addEventListener(type, handler as EventListener, options);\n }\n\n /** @inheritDoc */\n removeListener<T extends Event = Event>(target: Handle, type: string, handler: (event: T) => void, options?: boolean | EventListenerOptions): void {\n _registry.resolve(target).removeEventListener(type, handler as EventListener, options);\n }\n\n /** @inheritDoc */\n dispatchEvent(target: Handle, event: Event): void {\n _registry.resolve(target).dispatchEvent(event);\n }\n\n /** @inheritDoc */\n dispatchCustomEvent(target: Handle, type: string, init?: CustomEventInit): void {\n _registry.resolve(target).dispatchEvent(new CustomEvent(type, init));\n }\n\n /** @inheritDoc */\n requestAnimationFrame(callback: FrameRequestCallback): number {\n return requestAnimationFrame(callback);\n }\n\n /** @inheritDoc */\n cancelAnimationFrame(handle: number): void {\n cancelAnimationFrame(handle);\n }\n\n /** @inheritDoc */\n setId(handle: Handle, id: string): void {\n (_registry.resolve(handle) as Element).id = id;\n }\n\n /** @inheritDoc */\n insertBefore(parent: Handle, node: Handle, reference: Handle | null): void {\n _registry.resolve(parent).insertBefore(\n _registry.resolve(node),\n reference === null ? null : _registry.resolve(reference)\n );\n }\n\n /** @inheritDoc */\n createDocumentFragment(): Handle {\n return _registry.retain(document.createDocumentFragment());\n }\n\n /** @inheritDoc */\n click(handle: Handle): void {\n (_registry.resolve(handle) as HTMLElement).click();\n }\n\n /** @inheritDoc */\n setPointerCapture(handle: Handle, pointerId: number): void {\n (_registry.resolve(handle) as Element).setPointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n releasePointerCapture(handle: Handle, pointerId: number): void {\n (_registry.resolve(handle) as Element).releasePointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n getContext(handle: Handle, contextId: string, options?: unknown): RenderingContext | null {\n return (_registry.resolve(handle) as HTMLCanvasElement).getContext(contextId, options);\n }\n\n /** @inheritDoc */\n mountView<T>(handle: Handle, factory: (parent: HTMLElement) => T): T | null {\n return factory(_registry.resolve(handle) as HTMLElement);\n }\n\n /** @inheritDoc */\n mediaPlay(handle: Handle): void {\n // The play() promise rejects on an autoplay-policy block; playback state\n // is observed through media events, so the promise is intentionally void.\n void (_registry.resolve(handle) as HTMLMediaElement).play().catch(() => {});\n }\n\n /** @inheritDoc */\n mediaPause(handle: Handle): void {\n (_registry.resolve(handle) as HTMLMediaElement).pause();\n }\n\n /** @inheritDoc */\n setCurrentTime(handle: Handle, seconds: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).currentTime = seconds;\n }\n\n /** @inheritDoc */\n setVolume(handle: Handle, value: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).volume = value;\n }\n\n /** @inheritDoc */\n setMuted(handle: Handle, muted: boolean): void {\n (_registry.resolve(handle) as HTMLMediaElement).muted = muted;\n }\n\n /** @inheritDoc */\n setPlaybackRate(handle: Handle, rate: number): void {\n (_registry.resolve(handle) as HTMLMediaElement).playbackRate = rate;\n }\n\n /** @inheritDoc */\n requestFullscreen(handle: Handle): void {\n // The transition is observed through fullscreenchange; a rejected request\n // (no user gesture) is swallowed rather than surfaced as an unhandled reject.\n void (_registry.resolve(handle) as HTMLElement).requestFullscreen().catch(() => {});\n }\n\n /** @inheritDoc */\n exitFullscreen(): void {\n if (document.fullscreenElement) {\n void document.exitFullscreen().catch(() => {});\n }\n }\n}\n\n/**\n * Production {@link DOMSource}: reads the live DOM and delegates text\n * measurement to the existing {@link Util} canvas/probe code.\n *\n * @category Core\n */\nexport class ProductionDOMSource implements DOMSource {\n /**\n * Converts a raw browser node arriving at an event boundary into a (weak)\n * handle. The one place a raw target legitimately enters the seam from\n * outside — the event system hands it `evnt.target`, and the handle is\n * interned so no call site downstream holds the raw node.\n *\n * @param target - The browser-supplied event target.\n * @returns Its canonical handle.\n */\n intern(target: EventTarget): Handle {\n return _registry.intern(target as Node);\n }\n\n /** @inheritDoc */\n isNode(value: unknown): value is EventTarget {\n return value instanceof Node;\n }\n\n /** @inheritDoc */\n isElement(value: unknown): value is EventTarget {\n return value instanceof Element;\n }\n\n /** @inheritDoc */\n escapeSelector(value: string): string {\n // Real browsers always ship `CSS.escape`; guard for environments that\n // don't (jsdom, some SSR contexts) with an equivalent backslash escape\n // of every non-identifier character.\n if (typeof CSS !== \"undefined\" && typeof CSS.escape === \"function\") {\n return CSS.escape(value);\n }\n\n return value.replace(/[^\\w-]/g, ch => \"\\\\\" + ch);\n }\n\n /** @inheritDoc */\n getViewportRect(component: Component): Rect {\n return toRect((_registry.resolve(component.getElement()!) as HTMLElement).getBoundingClientRect());\n }\n\n /** @inheritDoc */\n getElementRect(handle: Handle): Rect {\n return toRect((_registry.resolve(handle) as Element).getBoundingClientRect());\n }\n\n /** @inheritDoc */\n measureText(text: string, options: TextMeasureOptions = {}): TextMetrics {\n const {\n fontFamily = \"var(--ts-ui-font-family, system-ui, sans-serif)\",\n fontSize = \"var(--ts-ui-font-size, 14px)\",\n fontWeight = \"normal\",\n fontStyle = \"normal\",\n fontVariant = \"normal\",\n fontStretch = \"normal\",\n lineHeight = \"calc(1em + var(--ts-ui-line-padding, 2px))\",\n maxWidth,\n } = options;\n\n const probe = document.createElement(\"span\");\n\n _applyProbeStyles(probe, {\n position: \"fixed\",\n visibility: \"hidden\",\n // With a wrap width the probe must honour `\\n` and soft-wrap so the\n // measured height covers every visual line; otherwise stay on a\n // single `nowrap` line for the natural-size measurement.\n whiteSpace: maxWidth === undefined ? \"nowrap\" : \"pre-wrap\",\n width: maxWidth === undefined ? \"\" : `${maxWidth}px`,\n fontFamily, fontSize, fontWeight, fontStyle, fontVariant, fontStretch, lineHeight,\n });\n\n probe.textContent = text;\n\n const ref = document.createElement(\"span\");\n\n _applyProbeStyles(ref, {\n display: \"inline-block\",\n width: \"0\",\n height: \"0\",\n verticalAlign: \"baseline\",\n });\n\n probe.appendChild(ref);\n document.body.appendChild(probe);\n\n const probeRect = probe.getBoundingClientRect();\n const refRect = ref.getBoundingClientRect();\n\n document.body.removeChild(probe);\n\n return {\n width: Math.ceil(probeRect.width),\n height: Math.ceil(probeRect.height),\n baseline: Math.round(refRect.top - probeRect.top),\n };\n }\n\n /** @inheritDoc */\n resolveFontSizePx(fontSizeCSS: string): number {\n const probe = document.createElement(\"span\");\n\n _applyProbeStyles(probe, { position: \"fixed\", visibility: \"hidden\", fontSize: fontSizeCSS });\n\n document.body.appendChild(probe);\n const px = parseFloat(getComputedStyle(probe).fontSize);\n document.body.removeChild(probe);\n\n return isNaN(px) ? 14 : px; // 14 mirrors the base font fallback\n }\n\n /** @inheritDoc */\n measureFontMetrics(): { ascent: number; descent: number; capTop: number } {\n if (_metricsCtx === null) {\n _metricsCtx = document.createElement(\"canvas\").getContext(\"2d\");\n }\n\n const ctx = _metricsCtx as CanvasRenderingContext2D;\n\n // 14px / system-ui mirror the `--ts-ui-font-*` defaults shipped by the\n // themes; they only apply when the computed value is empty (pre-apply).\n const family = this.getThemeVar(\"--ts-ui-font-family\") || \"system-ui, sans-serif\";\n const size = this.getThemeVar(\"--ts-ui-font-size\") || \"14px\";\n\n ctx.font = `normal normal ${size} ${family}`;\n\n const m = ctx.measureText(\"X\");\n\n const hasFontBox = typeof m.fontBoundingBoxAscent === \"number\";\n const ascent = hasFontBox ? m.fontBoundingBoxAscent : m.actualBoundingBoxAscent;\n const descent = hasFontBox ? m.fontBoundingBoxDescent : m.actualBoundingBoxDescent;\n\n return { ascent, descent, capTop: m.actualBoundingBoxAscent };\n }\n\n /** @inheritDoc */\n getThemeVar(name: string): string {\n return getComputedStyle(document.documentElement).getPropertyValue(name).trim();\n }\n\n /** @inheritDoc */\n getViewportSize(): Size {\n const width = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);\n const height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);\n\n return { width, height };\n }\n\n /** @inheritDoc */\n getScrollBarWidth(): number {\n if (_scrollBarWidth >= 0) {\n return _scrollBarWidth;\n }\n\n const outer = document.createElement(\"div\");\n\n _applyProbeStyles(outer, {\n position: \"absolute\",\n top: \"-1000px\",\n left: \"-1000px\",\n width: \"100px\",\n height: \"50px\",\n overflow: \"hidden\",\n });\n\n const inner = document.createElement(\"div\");\n\n _applyProbeStyles(inner, { width: \"100%\", height: \"200px\" });\n\n outer.appendChild(inner);\n document.body.appendChild(outer);\n\n const widthNoScroll = inner.offsetWidth;\n\n _applyProbeStyles(outer, { overflow: \"auto\" });\n\n const widthScroll = inner.offsetWidth;\n\n document.body.removeChild(outer);\n\n _scrollBarWidth = widthNoScroll - widthScroll;\n\n return _scrollBarWidth;\n }\n\n /** @inheritDoc */\n getDevicePixelRatio(): number {\n return window.devicePixelRatio || 1;\n }\n\n /** @inheritDoc */\n isModelled(): boolean {\n return false;\n }\n\n /** @inheritDoc */\n getScrollLeft(handle: Handle): number {\n return (_registry.resolve(handle) as Element).scrollLeft;\n }\n\n /** @inheritDoc */\n getScrollTop(handle: Handle): number {\n return (_registry.resolve(handle) as Element).scrollTop;\n }\n\n /** @inheritDoc */\n getScrollMetrics(handle: Handle): ScrollMetrics {\n const element = _registry.resolve(handle) as Element;\n\n return {\n scrollTop: element.scrollTop,\n scrollLeft: element.scrollLeft,\n scrollWidth: element.scrollWidth,\n scrollHeight: element.scrollHeight,\n clientWidth: element.clientWidth,\n clientHeight: element.clientHeight\n };\n }\n\n /** @inheritDoc */\n getOffsetSize(handle: Handle): OffsetSize {\n const el = _registry.resolve(handle) as HTMLElement;\n\n return {\n offsetTop: el.offsetTop,\n offsetHeight: el.offsetHeight\n };\n }\n\n /** @inheritDoc */\n isConnected(handle: Handle): boolean {\n return (_registry.resolve(handle) as Element).isConnected;\n }\n\n /** @inheritDoc */\n getValue(handle: Handle): string {\n return (_registry.resolve(handle) as HTMLInputElement).value;\n }\n\n /** @inheritDoc */\n getActiveElement(): Handle | null {\n const active = document.activeElement;\n\n return active === null ? null : _registry.intern(active);\n }\n\n /** @inheritDoc */\n matchMedia(query: string): MediaQueryResult {\n // Non-browser environments (SSR, workers, bare Node) have no\n // `matchMedia`; degrade to an inert result so callers need no\n // environment guard of their own — the capability check lives here, in\n // the seam, rather than leaking a raw `window` probe into call sites.\n if (typeof matchMedia !== \"function\") {\n return { matches: false, addChangeListener: (): void => {} };\n }\n\n const mql = matchMedia(query);\n\n return {\n matches: mql.matches,\n addChangeListener(handler: (event: MediaQueryListEvent) => void): void {\n mql.addEventListener(\"change\", handler);\n }\n };\n }\n\n /** @inheritDoc */\n isWindow(target: Handle | null): boolean {\n return target !== null && _registry.resolve(target) === (window as unknown as Node);\n }\n\n /** @inheritDoc */\n getWindow(): Handle {\n return _registry.intern(window as unknown as Node);\n }\n\n /** @inheritDoc */\n contains(ancestor: Handle, node: Handle | null): boolean {\n return _registry.resolve(ancestor).contains(node === null ? null : _registry.resolve(node));\n }\n\n /** @inheritDoc */\n querySelector(root: Handle, selector: string): Handle | null {\n const found = (_registry.resolve(root) as ParentNode).querySelector(selector);\n\n return found === null ? null : _registry.intern(found);\n }\n\n /** @inheritDoc */\n querySelectorAll(root: Handle, selector: string): Handle[] {\n return Array.from((_registry.resolve(root) as ParentNode).querySelectorAll(selector), (node) => _registry.intern(node));\n }\n\n /** @inheritDoc */\n matches(handle: Handle, selector: string): boolean {\n return (_registry.resolve(handle) as Element).matches(selector);\n }\n\n /** @inheritDoc */\n getParentElement(handle: Handle): Handle | null {\n const parent = (_registry.resolve(handle) as Element).parentElement;\n\n return parent === null ? null : _registry.intern(parent);\n }\n\n /** @inheritDoc */\n getParentNode(handle: Handle): Handle | null {\n const parent = _registry.resolve(handle).parentNode;\n\n return parent === null ? null : _registry.intern(parent);\n }\n\n /** @inheritDoc */\n getFirstChild(handle: Handle): Handle | null {\n const child = _registry.resolve(handle).firstChild;\n\n return child === null ? null : _registry.intern(child);\n }\n\n /** @inheritDoc */\n getBorderWidths(handle: Handle): { top: string; right: string; bottom: string; left: string } {\n const cs = getComputedStyle(_registry.resolve(handle) as Element);\n\n return {\n top: cs.borderTopWidth,\n right: cs.borderRightWidth,\n bottom: cs.borderBottomWidth,\n left: cs.borderLeftWidth\n };\n }\n\n /** @inheritDoc */\n getComputedOverflow(handle: Handle): { overflow: string; overflowX: string; overflowY: string } {\n const cs = getComputedStyle(_registry.resolve(handle) as Element);\n\n return {\n overflow: cs.overflow,\n overflowX: cs.overflowX,\n overflowY: cs.overflowY\n };\n }\n\n /** @inheritDoc */\n getInlineStyle(handle: Handle, key: string): string {\n const style = (_registry.resolve(handle) as HTMLElement).style;\n\n if (key.includes(\"-\")) {\n return style.getPropertyValue(key);\n }\n\n return (style as any)[key];\n }\n\n /** @inheritDoc */\n getDocumentElement(): Handle {\n return _registry.intern(document.documentElement);\n }\n\n /** @inheritDoc */\n getBody(): Handle {\n return _registry.intern(document.body);\n }\n\n /** @inheritDoc */\n getHead(): Handle {\n return _registry.intern(document.head);\n }\n\n /** @inheritDoc */\n onFontsReady(callback: () => void): void {\n const fonts = document.fonts;\n\n // Older engines without the CSS Font Loading API: the fallback\n // measurement is the only one we get, so leave it standing.\n if (!fonts) {\n return;\n }\n\n // Resolves after every used `@font-face` settles (loaded or errored).\n // If the font is already loaded the promise resolves on the next\n // microtask — the re-measure it triggers is idempotent.\n fonts.ready.then(() => callback());\n }\n\n /** @inheritDoc */\n getElementById(id: string): Handle | null {\n const found = document.getElementById(id);\n\n return found === null ? null : _registry.intern(found);\n }\n\n /** @inheritDoc */\n getId(handle: Handle): string {\n return (_registry.resolve(handle) as Element).id;\n }\n\n /** @inheritDoc */\n getDataset(handle: Handle, key: string): string | undefined {\n return (_registry.resolve(handle) as HTMLElement).dataset[key];\n }\n\n /** @inheritDoc */\n getTagName(handle: Handle): string {\n return (_registry.resolve(handle) as Element).tagName;\n }\n\n /** @inheritDoc */\n hasAttribute(handle: Handle, key: string): boolean {\n return (_registry.resolve(handle) as Element).hasAttribute(key);\n }\n\n /** @inheritDoc */\n getAttribute(handle: Handle, key: string): string | null {\n return (_registry.resolve(handle) as Element).getAttribute(key);\n }\n\n /** @inheritDoc */\n getNaturalSize(handle: Handle): { width: number; height: number } {\n const image = _registry.resolve(handle) as HTMLImageElement;\n\n return { width: image.naturalWidth, height: image.naturalHeight };\n }\n\n /** @inheritDoc */\n getMediaState(handle: Handle): MediaState {\n const media = _registry.resolve(handle) as HTMLMediaElement;\n\n return {\n currentTime: media.currentTime,\n duration: media.duration,\n paused: media.paused,\n ended: media.ended,\n volume: media.volume,\n muted: media.muted,\n playbackRate: media.playbackRate,\n };\n }\n\n /** @inheritDoc */\n getFullscreenElement(): Handle | null {\n const element = document.fullscreenElement;\n\n return element ? _registry.intern(element) : null;\n }\n\n /** @inheritDoc */\n getFiles(handle: Handle): FileList | null {\n return (_registry.resolve(handle) as HTMLInputElement).files;\n }\n\n /** @inheritDoc */\n hasPointerCapture(handle: Handle, pointerId: number): boolean {\n return (_registry.resolve(handle) as Element).hasPointerCapture(pointerId);\n }\n\n /** @inheritDoc */\n elementsFromPoint(x: number, y: number): Handle[] {\n return Array.from(document.elementsFromPoint(x, y), (node) => _registry.intern(node));\n }\n}\n\n/**\n * The shape of the global {@link DOM} swap point.\n *\n * @category Core\n */\nexport interface DOMSeams {\n /** The active write seam. Defaults to a {@link ProductionDOMSink}. */\n sink: DOMSink;\n /** The active read seam. Defaults to a {@link ProductionDOMSource}. */\n source: DOMSource;\n /**\n * Swaps in test implementations. Omitted seams keep their current value.\n *\n * @param impls - The sink and/or source to install.\n */\n install(impls: { sink?: DOMSink; source?: DOMSource }): void;\n /** Restores the production implementations. */\n reset(): void;\n}\n\n/**\n * Global swap point for the DOM seams, mirroring `ThemeManager`'s active-theme\n * singleton. Production code reads {@link DOM.sink} / {@link DOM.source}; test\n * setup swaps them via {@link DOM.install} and restores via {@link DOM.reset}.\n *\n * @remarks A mutable-property `const` object rather than a `namespace` with\n * `export let`: the latter is not supported by the Oxc transformer the Vite\n * build uses. The binding is stable; the `sink` / `source` properties are the\n * swappable state.\n *\n * @category Core\n */\nexport const DOM: DOMSeams = {\n sink: new ProductionDOMSink(),\n source: new ProductionDOMSource(),\n\n install(impls: { sink?: DOMSink; source?: DOMSource }): void {\n if (impls.sink) {\n DOM.sink = impls.sink;\n }\n\n if (impls.source) {\n DOM.source = impls.source;\n }\n },\n\n reset(): void {\n // Rebuild the shared registry alongside the seams so a test never\n // resolves a handle minted against the previous DOM.\n _registry = new HandleRegistry();\n DOM.sink = new ProductionDOMSink();\n DOM.source = new ProductionDOMSource();\n },\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Size } from \"~/primitive/Size.js\";\nimport type { Insets } from \"~/primitive/Insets.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Font options for off-screen text measurement.\n * All properties default to the active theme variables when omitted.\n */\nexport interface TextMeasureOptions {\n fontFamily?: string;\n fontSize? : string;\n fontWeight?: string;\n fontStyle? : string;\n fontVariant?: string;\n fontStretch?: string;\n lineHeight?: string\n /**\n * When set, the probe wraps at this pixel width (using `pre-wrap`) instead of\n * measuring on a single `nowrap` line. The returned `height` then reflects the\n * wrapped, multi-line box. Omit to measure the natural single-line size.\n */\n maxWidth?: number;\n}\n\n/**\n * Result of an off-screen text measurement that also reports the typographic baseline.\n *\n * @remarks `baseline` is the offset from the top of the measured box to the font baseline,\n * in pixels — analogous to CSS `vertical-align: baseline` on an inline-block element.\n */\nexport interface TextMetrics {\n width: number;\n height: number;\n baseline: number;\n}\n\n/**\n * General-purpose utility functions for DOM interaction and browser environment queries.\n *\n * @category Util\n */\nexport namespace Util {\n\n // Cached text-metric results, invalidated together on theme change via\n // `invalidateTextMetricsCache`. `-1` is the \"not yet measured\" sentinel\n // (a real padding / font size / baseline / offset is always >= 0).\n let linePaddingCache: number = -1;\n let rootFontSizeCache: number = -1;\n let textBaselineCache: number = -1;\n let opticalOffsetCache: number = -1;\n\n /**\n * Measures the rendered size of a text string using an off-screen probe `<span>`.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured `{width, height}` in pixels, ceiled to whole pixels.\n */\n export function measureTextSize(text: string, options: TextMeasureOptions = {}): Size {\n const metrics = DOM.source.measureText(text, options);\n\n return { width: metrics.width, height: metrics.height };\n }\n\n /**\n * Returns the rendered pixel width of a text string.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured width in pixels, ceiled to a whole pixel.\n */\n export function measureTextWidth(text: string, options?: TextMeasureOptions): number {\n return measureTextSize(text, options).width;\n }\n\n /**\n * Returns the active theme's leading (`--ts-ui-line-padding`) in pixels.\n *\n * @returns The integer-pixel value of `--ts-ui-line-padding`, or `4` as a\n * fallback when the variable is missing or unparseable.\n */\n function linePaddingPx(): number {\n if (linePaddingCache >= 0) {\n return linePaddingCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-line-padding\");\n const parsed = parseFloat(raw);\n\n // 2 mirrors the `--ts-ui-line-padding` default shipped by every theme\n // (see ModernTheme/DarkTheme/ClassicTheme `font.linePadding: '2px'`);\n // it only applies when the var is absent (e.g. pre-theme-apply probe).\n linePaddingCache = isNaN(parsed) ? 2 : parsed;\n\n return linePaddingCache;\n }\n\n /**\n * Returns the document root font size (`--ts-ui-font-size`) in pixels, the\n * default font size for a control that doesn't override it.\n *\n * @returns The integer-pixel root font size, or `14` as a fallback.\n */\n function rootFontSizePx(): number {\n if (rootFontSizeCache >= 0) {\n return rootFontSizeCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-font-size\");\n const parsed = parseFloat(raw);\n\n rootFontSizeCache = isNaN(parsed) ? 14 : parsed;\n\n return rootFontSizeCache;\n }\n\n /**\n * Returns a vertical text metric in integer pixels: a control's font size,\n * plus the theme leading (`--ts-ui-line-padding`) by default.\n *\n * @param options - Measurement options.\n * @param options.fontSizePx - The control's font size in pixels. Omit to use\n * the document root font size (`--ts-ui-font-size`), which is what the\n * native `<input>`-backed controls render at.\n * @param options.linePadding - Controls the leading added to the font size:\n * `true` (the default) adds the theme `--ts-ui-line-padding`, giving the\n * full rendered line box (matching the `calc(1em + …)` line-height controls\n * render at); `false` adds nothing, returning the bare font size to size a\n * box from its font without leading; a number adds that exact pixel padding.\n * @returns `round(fontSize + leading)`, where leading is the theme padding,\n * `0`, or the given number.\n *\n * @remarks With the default leading the line box scales with font size, so\n * 12px and 14px text get proportionate line boxes from the one token. Text\n * components, table rows, and the baseline computation use the default so\n * their measurement matches the rendered line box; the native input box\n * heights pass `false` so the box hugs the font size plus their own chrome.\n * The padding and root font size are cached; call\n * {@link invalidateTextMetricsCache} after a theme change to force a\n * re-read.\n */\n export function lineHeightPx(options: { fontSizePx?: number, linePadding?: boolean | number } = {}): number {\n let fs = options.fontSizePx ?? rootFontSizePx();\n\n const linePadding = options.linePadding ?? true;\n\n if (linePadding === true) {\n fs += linePaddingPx();\n } else if (typeof linePadding === \"number\") {\n fs += linePadding;\n }\n\n return Math.round(fs);\n }\n\n /**\n * Returns the content-relative text baseline for the unified line-height\n * model: the offset from the top of the `lineHeightPx()` line box to the\n * font baseline.\n *\n * @returns The baseline offset in pixels, rounded to the nearest integer.\n *\n * @remarks Computed from the canvas 2D `measureText` font metrics rather\n * than a DOM probe, so it is deterministic and UA-independent. A CSS line\n * box centres the font's ascent+descent within `line-height`; this\n * reproduces that centring with the known px line box —\n * `round(lineGap / 2 + ascent)` where `lineGap = lineHeightPx - (ascent +\n * descent)` — so the measured baseline matches where the browser paints the\n * glyph in both a native `<input>` and a `Text`/`Label`. `fontBoundingBox*`\n * (font-intrinsic, string-independent) is used in preference to\n * `actualBoundingBox*` (glyph-ink specific) so the baseline does not shift\n * per measured string; `\"X\"` is passed only to satisfy `measureText`. The\n * result is cached; call {@link invalidateTextMetricsCache} after a theme\n * change to force re-measurement.\n */\n export function measureTextBaseline(): number {\n if (textBaselineCache >= 0) {\n return textBaselineCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const gap = lineHeightPx() - (m.ascent + m.descent);\n\n textBaselineCache = Math.round(gap / 2 + m.ascent);\n\n return textBaselineCache;\n }\n\n /**\n * Returns the pixel height of a single-line input box: the theme line-box\n * height ({@link lineHeightPx}) plus the component's own vertical chrome\n * (insets + optional padding + border).\n *\n * @param insets - The component's layout insets (top/bottom read).\n * @param padding - The component's CSS padding, or `null` when it has none.\n * @param border - The component's border widths (top/bottom read).\n * @returns The single-line box height in pixels.\n *\n * @remarks Factors out the `chrome = insets + padding + border; h =\n * lineHeightPx() + chrome` idiom shared by every single-line native-input\n * box height (`TextField` / `PasswordField` / `ComboBox` / the picker fields\n * / `NumberSpinner`). Only the vertical (top/bottom) edges contribute; the\n * horizontal edges are the caller's width concern. `NumberSpinner` uniquely\n * passes its *inner input's* padding rather than its own.\n */\n export function singleLineBoxHeight(\n insets: Insets,\n padding: Insets | null,\n border: { top: number; bottom: number },\n ): number {\n const chrome = insets.getTop() + insets.getBottom()\n + (padding ? padding.getTop() + padding.getBottom() : 0)\n + border.top + border.bottom;\n\n return lineHeightPx() + chrome;\n }\n\n /**\n * Returns the downward pixel offset that moves a single line of text from\n * its line-box (geometric) centre to its optical (cap-height) centre.\n *\n * @returns The downward offset in pixels (`>= 0`), rounded to the nearest\n * integer.\n *\n * @remarks A label's visible glyphs occupy cap-top→baseline; the descender\n * band below the baseline is empty ink, so the ink's visual centre sits\n * above the font box's geometric centre and a geometrically-centred label\n * reads as too high. This returns roughly half the unused descender space —\n * `round(boxMid - inkMid)` where `boxMid = (ascent - descent) / 2` and\n * `inkMid = capTop / 2` with `capTop = actualBoundingBoxAscent` (the cap-top\n * ink of `\"X\"`) — so a consumer ([`Button`](/api/component/button/classes/Button))\n * can nudge single-line text down onto its true optical centre. Derived\n * from the same cached canvas\n * metrics as {@link measureTextBaseline}; cached and invalidated together\n * via {@link invalidateTextMetricsCache}.\n */\n export function opticalCenterOffset(): number {\n if (opticalOffsetCache >= 0) {\n return opticalOffsetCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const boxMid = (m.ascent - m.descent) / 2;\n const inkMid = m.capTop / 2;\n\n opticalOffsetCache = Math.max(0, Math.round(boxMid - inkMid));\n\n return opticalOffsetCache;\n }\n\n /**\n * Discards every cached text metric (line box, baseline, optical offset) so\n * the next read re-measures against the active theme font.\n *\n * @remarks Call this whenever the active theme's font size, family, or\n * line-height changes, since the cached values reflect the font in use at\n * the time of the first measurement and would otherwise mis-align controls\n * against each other after a theme swap.\n */\n export function invalidateTextMetricsCache(): void {\n linePaddingCache = -1;\n rootFontSizeCache = -1;\n textBaselineCache = -1;\n opticalOffsetCache = -1;\n }\n\n /**\n * Generates a UUID string, ensuring the first character is never a digit.\n *\n * @returns A UUID v4 string with a guaranteed non-numeric first character.\n *\n * @remarks If the standard UUID generation produces a leading digit, it is replaced\n * with the letter \"a\" so the result is safe to use as a DOM id or CSS identifier.\n */\n export function generateUUID() {\n let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n let r = Math.random() * 16 | 0,\n v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n\n let first = parseInt(uuid[0]);\n if (Util.isInteger(first)) {\n uuid = \"a\" + uuid.substring(1, uuid.length);\n }\n\n return uuid;\n }\n\n /**\n * Returns true if value is an integer.\n *\n * @param value - The value to test.\n *\n * @returns `true` if `value` is an integer, `false` otherwise.\n */\n export function isInteger(value: Object) {\n return Number.isInteger(value);\n }\n\n /**\n * Clamps a number into an inclusive `[min, max]` range.\n *\n * @param value - The number to clamp.\n * @param min - The lower bound.\n * @param max - The upper bound.\n *\n * @returns `value` when it lies within the range, otherwise the nearer bound.\n *\n * @remarks Assumes `min <= max` (the framework's `min <= preferred <= max`\n * size invariant). When `min > max` the maximum wins (`clamp(v, 10, 0) === 0`)\n * — the low-first `Math.min(Math.max(...))` tie-break; callers must not rely\n * on it. `NaN` propagates (a `NaN` input returns `NaN`), matching the inlined\n * `Math.min`/`Math.max` expressions this replaces.\n */\n export function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n }\n\n /**\n * Converts a hyphen-separated identifier (e.g. `\"border-top-width\"`) to its\n * camelCase equivalent (`\"borderTopWidth\"`). Useful for translating\n * CSS-style kebab-case property names into the camelCase form expected by\n * `CSSStyleDeclaration` bracket-indexed assignment.\n *\n * @param value - The kebab-case input string.\n * @returns The camelCase equivalent.\n */\n export function kebabToCamel(value: string): string {\n return value.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n }\n\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Util } from \"~/core/Util.js\"\n\n/**\n * Base class for all library objects.\n * Automatically assigns a unique identifier on construction.\n *\n * @category Core\n */\nexport class BaseObject {\n\n private _id: string;\n\n constructor() {\n this._id = Util.generateUUID();\n }\n\n /**\n * Returns the unique identifier for this object.\n *\n * @returns The UUID string assigned at construction time.\n */\n getId() {\n return this._id;\n }\n\n /**\n * Sets the unique identifier for this object.\n *\n * @param id - The new identifier string to assign.\n */\n setId(id: string) : this {\n this._id = id;\n\n return this;\n }\n\n /**\n * Returns the runtime class name of this object.\n *\n * @returns The name of the constructor function as a string.\n */\n getClassName() {\n return this.constructor.name;\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * Represents a two-dimensional size with width and height in pixels.\n *\n * @category Util\n */\nexport interface Size {\n width: number,\n height: number\n}\n\n/**\n * The sentinel extent meaning \"no upper bound\" on a size axis.\n *\n * @category Util\n */\nexport const UNBOUNDED: number = Number.MAX_SAFE_INTEGER;\n\n/**\n * True when an extent is at or above the unbounded sentinel (recognises the\n * legacy `Number.MAX_VALUE` too).\n *\n * @param n - The extent to test.\n * @returns `true` when `n` is at or above {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function isUnbounded(n: number): boolean {\n return n >= Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Caps an extent at the unbounded sentinel so an unbounded sum cannot overflow\n * it.\n *\n * @param n - The extent to cap.\n * @returns `n`, capped at {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function saturate(n: number): number {\n return Math.min(n, UNBOUNDED);\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * A border specification built from complete CSS border strings.\n * `border` is the all-sides fallback; each per-side field overrides it for\n * that side. An unspecified side falls back to `border`, then to `\"none\"`.\n *\n * @category Util\n */\nexport interface BorderOptions {\n /** CSS `border` shorthand applied to all four sides (e.g. `\"1px solid rgb(...)\"`, `\"none\"`, `\"var(--x)\"`). */\n border?: string;\n /** CSS `border-top` value; overrides `border` for the top side. */\n borderTop?: string;\n /** CSS `border-right` value; overrides `border` for the right side. */\n borderRight?: string;\n /** CSS `border-bottom` value; overrides `border` for the bottom side. */\n borderBottom?: string;\n /** CSS `border-left` value; overrides `border` for the left side. */\n borderLeft?: string;\n}\n\n/**\n * Expands a {@link BorderOptions} into the four camelCase longhand style keys\n * (`borderTop`/`borderRight`/`borderBottom`/`borderLeft`) that `StyleRule.setMany`\n * consumes. Each side resolves via `side ?? border ?? \"none\"`, so a pure-longhand\n * map replays deterministically regardless of what else touched the rule.\n *\n * @param border - The border specification to expand.\n *\n * @returns A map of the four longhand keys to their resolved CSS values.\n *\n * @category Util\n */\nexport function borderToStyle(border: BorderOptions): Record<string, string | null> {\n const all = border.border ?? \"none\";\n\n return {\n borderTop: border.borderTop ?? all,\n borderRight: border.borderRight ?? all,\n borderBottom: border.borderBottom ?? all,\n borderLeft: border.borderLeft ?? all,\n };\n}\n\n/**\n * Best-effort leading-`<n>px` width of one side's CSS value. Returns `0` for\n * `undefined`, `none`, `0`, `var(...)`, or any non-`px` leading token. Used both\n * to parse the always-`<n>px` values `getComputedStyle` returns (authoritative,\n * post-render) and to estimate a width from a spec string before an element exists.\n *\n * @param value - A single side's CSS border value, or `undefined`.\n *\n * @returns The leading pixel width, or `0` when none can be parsed.\n *\n * @category Util\n */\nexport function borderSideWidth(value: string | undefined): number {\n if (!value) {\n return 0;\n }\n\n const match = value.trim().match(/^([\\d.]+)px\\b/i);\n\n return match ? parseFloat(match[1]) : 0;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from \"~/core/BaseObject.js\";\n\n/**\n * Represents the four directional inset (padding/margin) values for a rectangular area.\n * All values are expressed in pixels.\n *\n * @example\n * ```typescript\n * import { Insets } from '@jimka/typescript-ui/primitive';\n*\n * component.setInsets(new Insets(8, 12, 8, 12)); // top, right, bottom, left\n * ```\n *\n * @category Util\n */\nexport class Insets extends BaseObject {\n\n private _top: number;\n private _right: number;\n private _bottom: number;\n private _left: number;\n\n /**\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n constructor(top: number, right: number, bottom: number, left: number) {\n super();\n\n this._top = top || 0;\n this._right = right || 0;\n this._bottom = bottom || 0;\n this._left = left || 0;\n }\n\n /**\n * Returns the top inset in pixels.\n *\n * @returns The top inset value, defaulting to `0` if unset.\n */\n getTop() {\n return this._top || 0;\n }\n\n /**\n * Sets the top inset in pixels.\n *\n * @param value - The new top inset value in pixels.\n */\n setTop(value: number) : this {\n this._top = value;\n\n return this;\n }\n\n /**\n * Returns the right inset in pixels.\n *\n * @returns The right inset value, defaulting to `0` if unset.\n */\n getRight() {\n return this._right || 0;\n }\n\n /**\n * Sets the right inset in pixels.\n *\n * @param value - The new right inset value in pixels.\n */\n setRight(value: number) : this {\n this._right = value;\n\n return this;\n }\n\n /**\n * Returns the bottom inset in pixels.\n *\n * @returns The bottom inset value, defaulting to `0` if unset.\n */\n getBottom() {\n return this._bottom || 0;\n }\n\n /**\n * Sets the bottom inset in pixels.\n *\n * @param value - The new bottom inset value in pixels.\n */\n setBottom(value: number) : this {\n this._bottom = value;\n\n return this;\n }\n\n /**\n * Returns the left inset in pixels.\n *\n * @returns The left inset value, defaulting to `0` if unset.\n */\n getLeft() {\n return this._left || 0;\n }\n\n /**\n * Sets the left inset in pixels.\n *\n * @param value - The new left inset value in pixels.\n */\n setLeft(value: number) : this {\n this._left = value;\n\n return this;\n }\n\n /**\n * Sets all four inset values at once.\n *\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n set(top: number, right: number, bottom: number, left: number) : this {\n this._top = top;\n this._right = right;\n this._bottom = bottom;\n this._left = left;\n\n return this;\n }\n\n /**\n * Returns the insets as a CSS shorthand string (e.g. `\"4px 4px 4px 4px\"`).\n *\n * @returns A CSS margin/padding shorthand string with all four sides in top-right-bottom-left order.\n */\n render() {\n return this.getTop() + \"px \" + this.getRight() + \"px \" + this.getBottom() + \"px \" + this.getLeft() + \"px\";\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * CSS `position` values used by the framework.\n *\n * The framework positions every component absolutely (see\n * [ARCHITECTURE.md](/ARCHITECTURE.md) §Positioning). Only three values\n * are exposed:\n *\n * - `ABSOLUTE` — the universal default for every framework component.\n * - `FIXED` — the documented exception for floating overlays that anchor to\n * the viewport (`AnimatedDropdown`, `Popover`, `Notification`, `Dialog`,\n * `DialogBackdrop`). Set internally by these subclasses; never by callers.\n * - `STATIC` — the documented exception for an HTML element whose native\n * semantics require in-flow rendering (currently only `Legend`, which needs\n * the notch in its parent `<fieldset>`'s border).\n *\n * Other CSS values (`relative`, `sticky`, `initial`, `inherit`) are\n * intentionally **not** members. Application code does not call\n * `setPosition` — that setter is `protected` on `Component`.\n *\n * @category Util\n */\nexport enum Position {\n STATIC = \"static\",\n FIXED = \"fixed\",\n ABSOLUTE = \"absolute\",\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{u as e}from"./Position-B-WfZYAJ.js";import{_ as t,f as n,t as r}from"./Component-BR2f0Itb.js";t.ensureKeyframes(`ts-ui-progress-spinner-rotate`,`from { transform: rotate(0deg); } to { transform: rotate(360deg); }`);var i=3;function readThemeFontSizePx(){let t=e.source.getThemeVar(`--ts-ui-font-size`),n=parseFloat(t);return isNaN(n)?14:n}var ProgressSpinner=class extends r{_arc;_size;_trackThemeFontSize;_themeFontSizeResolved=!1;_overlayTarget=null;constructor(e,t){super(),this._trackThemeFontSize=e===void 0,this._size=this._trackThemeFontSize?14:e,this.clearInsets(),this._arc=new r,this._arc.setBorderRadius(`50%`),this._arc.setBorder({border:`${i}px solid var(--ts-ui-progress-spinner-color, rgb(30, 100, 200))`,borderTop:`${i}px solid transparent`}),this._arc.setAnimation(`ts-ui-progress-spinner-rotate 0.8s linear infinite`),super.addComponent(this._arc),this.setPreferredSize(this._size,this._size),this._trackThemeFontSize&&this.subscribeTheme(()=>{if(!this._trackThemeFontSize)return;let e=readThemeFontSizePx();e!==this._size&&(this._size=e,this.setPreferredSize(e,e),this.scheduleLayout())}),this.getAria().setRole(`status`),this.getAria().setLabel(`Loading`),t&&this.applyOptions(t)}applyOptions(e){return super.applyOptions(e),e.spinnerSize!==void 0&&this.setSpinnerSize(e.spinnerSize),this}getSpinnerSize(){return this._size}getBaseline(){let e=this.getPreferredSize();return e?e.height-2:null}setSpinnerSize(e){return this._trackThemeFontSize=!1,this._size===e?this:(this._size=e,this.setPreferredSize(e,e),this.scheduleLayout(),this)}showOverlay(t){if(this._overlayTarget)return;this._overlayTarget=t,this.setBackgroundColor(`var(--ts-ui-progress-spinner-backdrop, rgba(255, 255, 255, 0.6))`),this.setZIndex(9999);let n=t.getElement(!0),r=this.getElement(!0);e.sink.appendChild(n,r),this.setX(0),this.setY(0),this.setSize({width:t.getWidth(),height:t.getHeight()}),this.doLayout()}hideOverlay(){this._overlayTarget&&(this._overlayTarget=null,this.removeElement(),this.clearBackgroundColor(),this.setZIndex(0))}isOverlay(){return this._overlayTarget!==null}doLayout(){if(this._trackThemeFontSize&&!this._themeFontSizeResolved){this._themeFontSizeResolved=!0;let e=readThemeFontSizePx();e!==this._size&&(this._size=e,this.setPreferredSize(e,e))}this._overlayTarget&&this.setSize({width:this._overlayTarget.getWidth(),height:this._overlayTarget.getHeight()});let e=this.getInnerSize();if(!e)return super.doLayout(),this;let t=Math.min(this._size,e.width,e.height),n=Math.round((e.width-t)/2),r=Math.round((e.height-t)/2);return this._arc.setX(n),this._arc.setY(r),this._arc.setSize({width:t,height:t}),super.doLayout(),this}},a=n(ProgressSpinner);export{a as t};
|
|
2
|
-
//# sourceMappingURL=ProgressSpinner-Dzaka7_c.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressSpinner-Dzaka7_c.js","names":[],"sources":["../../src/typescript/lib/component/display/ProgressSpinner.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link ProgressSpinner}.\n *\n * @category Components\n */\nexport interface ProgressSpinnerOptions extends ComponentOptions {\n spinnerSize?: number;\n}\n\nStyleRule.ensureKeyframes(\n 'ts-ui-progress-spinner-rotate',\n 'from { transform: rotate(0deg); } to { transform: rotate(360deg); }'\n);\n\nconst ARC_BORDER_WIDTH = 3;\n\n/**\n * Reads the active theme's `--ts-ui-font-size` as a pixel value.\n *\n * @returns The current theme font size in pixels, or `14` as a fallback.\n */\nfunction readThemeFontSizePx(): number {\n const raw = DOM.source.getThemeVar(\"--ts-ui-font-size\");\n const parsed = parseFloat(raw);\n\n return isNaN(parsed) ? 14 : parsed;\n}\n\n/**\n * A circular loading indicator rendered as a rotating arc.\n *\n * Supports two usage modes:\n * - **Inline**: instantiate, size, and add to a parent like any other component.\n * - **Overlay**: call {@link showOverlay} to mount the spinner as an absolute\n * overlay over a target component, complete with a semi-transparent backdrop.\n * {@link hideOverlay} removes it.\n *\n * @category Components\n */\nclass ProgressSpinner extends Component {\n\n private _arc: Component;\n private _size: number;\n private _trackThemeFontSize: boolean;\n private _themeFontSizeResolved: boolean = false;\n private _overlayTarget: Component | null = null;\n\n /**\n * Constructs a ProgressSpinner.\n *\n * @param size - Optional. Diameter in pixels of the arc when used inline.\n * Omit to track the active theme's `--ts-ui-font-size` so the spinner\n * matches surrounding text by default; updates automatically on theme change.\n */\n constructor(size?: number, options?: ProgressSpinnerOptions) {\n // Child components are built first; options are applied via applyOptions at the constructor tail.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n this._trackThemeFontSize = size === undefined;\n // Theme font-size is resolved at first `doLayout` (post-attach) so\n // construction stays JS-only per ARCHITECTURE.md \"Defer DOM work to\n // render time\". Use the same `14` fallback that `readThemeFontSizePx`\n // returns when the variable is missing, so the preferred-size write a\n // few lines below has a sensible value before the theme read fires.\n this._size = this._trackThemeFontSize ? 14 : size!;\n\n // Use no insets so the arc fills the declared size — otherwise the\n // default 4-pixel inset shrinks a 24-pixel spinner's arc to 16 pixels\n // and leaves 8 pixels of empty space around it.\n this.clearInsets();\n\n this._arc = new Component();\n this._arc.setBorderRadius(\"50%\");\n this._arc.setBorder({\n border: `${ARC_BORDER_WIDTH}px solid var(--ts-ui-progress-spinner-color, rgb(30, 100, 200))`,\n borderTop: `${ARC_BORDER_WIDTH}px solid transparent`,\n });\n this._arc.setAnimation(\"ts-ui-progress-spinner-rotate 0.8s linear infinite\");\n\n super.addComponent(this._arc);\n\n this.setPreferredSize(this._size, this._size);\n\n if (this._trackThemeFontSize) {\n this.subscribeTheme(() => {\n if (!this._trackThemeFontSize) {\n return;\n }\n\n const next = readThemeFontSizePx();\n if (next === this._size) {\n return;\n }\n\n this._size = next;\n this.setPreferredSize(next, next);\n this.scheduleLayout();\n });\n }\n\n this.getAria().setRole(\"status\");\n this.getAria().setLabel(\"Loading\");\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link ProgressSpinnerOptions} bag, dispatching the explicit\n * spinner diameter after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: ProgressSpinnerOptions): this {\n super.applyOptions(options);\n\n if (options.spinnerSize !== undefined) {\n this.setSpinnerSize(options.spinnerSize);\n }\n\n return this;\n }\n\n /**\n * Returns the spinner arc diameter in pixels.\n *\n * @returns The diameter.\n *\n * @remarks Returns the most recently resolved diameter; when the spinner\n * tracks the theme font-size (default constructor with no `size` argument),\n * the resolved value is only available after the first layout pass — earlier\n * calls return the `14`-pixel fallback.\n */\n getSpinnerSize(): number {\n return this._size;\n }\n\n /**\n * Returns a baseline near the bottom edge so the spinner participates in\n * baseline alignment — sitting with its bottom roughly on the surrounding\n * text baseline — instead of being vertically centred in the row. The 2px\n * lift matches the other graphical controls so it doesn't sit below the\n * text descenders.\n *\n * @returns The preferred height minus 2, or `null` before a size is set.\n */\n getBaseline(): number | null {\n const size = this.getPreferredSize();\n\n return size ? size.height - 2 : null;\n }\n\n /**\n * Sets a new arc diameter and updates the component's preferred size.\n *\n * @param size - Diameter in pixels.\n *\n * @remarks Calling this disables the default theme-font-size tracking so\n * the spinner stays at the explicit size across subsequent theme changes.\n */\n setSpinnerSize(size: number): this {\n this._trackThemeFontSize = false;\n\n if (this._size === size) {\n return this;\n }\n\n this._size = size;\n this.setPreferredSize(size, size);\n this.scheduleLayout();\n\n return this;\n }\n\n /**\n * Mounts this ProgressSpinner as an absolute overlay covering the given component.\n *\n * The spinner element is appended directly to the target's DOM element (bypassing\n * the target's layout manager, mirroring how [`Window`](/api/overlay/classes/Window)\n * mounts itself onto `document.documentElement`). Sized to the target's full bounds with a\n * semi-transparent backdrop and the spinning arc centred inside it. No-op if\n * already shown as an overlay.\n *\n * @param target - The component to overlay.\n */\n showOverlay(target: Component): void {\n if (this._overlayTarget) {\n return;\n }\n\n this._overlayTarget = target;\n\n this.setBackgroundColor(\"var(--ts-ui-progress-spinner-backdrop, rgba(255, 255, 255, 0.6))\");\n this.setZIndex(9999);\n\n const targetEl = target.getElement(true)!;\n const spinnerEl = this.getElement(true)!;\n\n DOM.sink.appendChild(targetEl, spinnerEl);\n\n this.setX(0);\n this.setY(0);\n this.setSize({ width: target.getWidth(), height: target.getHeight() });\n this.doLayout();\n }\n\n /**\n * Removes the overlay from its target and resets state. No-op if not currently shown\n * as an overlay.\n */\n hideOverlay(): void {\n if (!this._overlayTarget) {\n return;\n }\n\n this._overlayTarget = null;\n\n this.removeElement();\n\n this.clearBackgroundColor();\n this.setZIndex(0);\n }\n\n /**\n * Returns whether the spinner is currently mounted as an overlay.\n *\n * @returns True if showOverlay has been called and hideOverlay has not.\n */\n isOverlay(): boolean {\n return this._overlayTarget !== null;\n }\n\n /**\n * Lays out the inner arc element at the centre of the component bounds.\n *\n * @returns This component, for method chaining.\n */\n doLayout(): this {\n if (this._trackThemeFontSize && !this._themeFontSizeResolved) {\n this._themeFontSizeResolved = true;\n\n const next = readThemeFontSizePx();\n if (next !== this._size) {\n this._size = next;\n this.setPreferredSize(next, next);\n }\n }\n\n if (this._overlayTarget) {\n this.setSize({ width: this._overlayTarget.getWidth(), height: this._overlayTarget.getHeight() });\n }\n\n const inner = this.getInnerSize();\n if (!inner) {\n super.doLayout();\n\n return this;\n }\n\n const diameter = Math.min(this._size, inner.width, inner.height);\n const x = Math.round((inner.width - diameter) / 2);\n const y = Math.round((inner.height - diameter) / 2);\n\n this._arc.setX(x);\n this._arc.setY(y);\n this._arc.setSize({ width: diameter, height: diameter });\n\n super.doLayout();\n\n return this;\n }\n}\n\nconst ProgressSpinnerCallable = callable(ProgressSpinner);\ntype ProgressSpinnerCallable = ProgressSpinner;\nexport {\n ProgressSpinner as _ProgressSpinner,\n ProgressSpinnerCallable as ProgressSpinner\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{f as e,h as t,t as n,y as r}from"./Component-BR2f0Itb.js";import{t as i}from"./Glyph-WUqTF_Z9.js";import{t as a}from"./AbstractBooleanInput-C3rj7sje.js";import{t as o}from"./HBox-Q8y1PHlk.js";import{circle as s}from"./glyphs/solid/circle.es.js";i.register(s);var RadioButton=class extends a{_ring;_dot;constructor(e,a){super({...a??{}}),this.setLayoutManager(new o),this._ring=new n,this._ring.setPreferredSize(16,16),this._ring.setMinSize(16,16),this._ring.setMaxSize(16,16),this._ring.setSize({width:16,height:16}),this._ring.setBackgroundColor(`var(--ts-ui-radio-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))`),this._ring.setBorder(`1px solid var(--ts-ui-form-border, rgb(160, 160, 160))`),this._ring.setBorderRadius(`50%`),this._ring.setCursor(`pointer`),this._dot=new i(`circle`),this._dot.setForegroundColor(`var(--ts-ui-radio-dot-color, rgb(255, 255, 255))`),this._dot.setPreferredSize(8,8),this._dot.setMaxSize(8,8),this._dot.setX(3),this._dot.setY(3),this._dot.setOpacity(0),this._dot.setPointerEvents(`none`),t.isReducedMotion()||(this._dot.setTransition(`opacity 120ms ease-out`),this._ring.setTransition(`background-color 120ms ease-out, border-color 120ms ease-out`)),this._ring.addComponent(this._dot),super.addComponent(this._ring),this.getAria().setRole(`radio`),this.getAria().setTabIndex(0),this.getAria().setChecked(!1),this.setOutline(`none`),r.addListener(this._ring,`click`,()=>this.activateFromPointer()),this.installKeyboard(),this._options.label===void 0&&this._options.text===void 0&&e!==void 0?this._options.label=e:this._options.label===void 0&&this._options.text!==void 0&&(this._options.label=this._options.text),this._options.value!==void 0&&this._options.selected===void 0&&(this._options.selected=this._options.value),this._options.selected!==void 0&&this.applySelected(this._options.selected),this._options.label!==void 0&&this.applyLabel(this._options.label),this._options.enabled!==void 0&&this.applyEnabled(this._options.enabled),this._options.readOnly!==void 0&&this.applyReadOnly(this._options.readOnly)}applyOptions(e){return super.applyOptions(e),e.selected!==void 0&&(this._options.selected=e.selected),e.value!==void 0&&(this._options.value=e.value),e.label!==void 0&&(this._options.label=e.label),e.text!==void 0&&(this._options.text=e.text),e.radioName!==void 0&&(this._options.radioName=e.radioName),e.enabled!==void 0&&(this._options.enabled=e.enabled),e.readOnly!==void 0&&(this._options.readOnly=e.readOnly),this}activate(){this.isSelected()||(this.setSelected(!0),r.fireEvent(this,`change`))}getInteractiveSurface(){return this._ring}isSelected(){return this._options.selected??!1}setSelected(e){let t=!!e;return t===this.isSelected()?this:(this._options.selected=t,this.applySelected(t),this.notifyChange(t),this)}getValue(){return this.isSelected()}setValue(e){return this.setSelected(e)}setRadioName(e){return this._options.radioName=e,this}clearRadioName(){return this._options.radioName=void 0,this}getRadioName(){return this._options.radioName??null}on(e,t){return e===`action`?(r.addListener(this,`change`,t),this):super.on(e,t)}off(e,t){return e===`action`?(r.removeListener(this,`change`,t),this):super.off(e,t)}applySelected(e){this.getAria().setChecked(e),this._ring.setBackgroundColor(e?`var(--ts-ui-radio-bg-selected, rgb(30, 100, 200))`:`var(--ts-ui-radio-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))`),this._ring.setBorder(e?`1px solid var(--ts-ui-radio-bg-selected, rgb(30, 100, 200))`:`1px solid var(--ts-ui-form-border, rgb(160, 160, 160))`),this._dot.setOpacity(+!!e)}},c=e(RadioButton);export{c as t};
|
|
2
|
-
//# sourceMappingURL=RadioButton-eI3-vXn3.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"RadioButton-eI3-vXn3.js","names":[],"sources":["../../src/typescript/lib/component/input/RadioButton.ts"],"sourcesContent":["// 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 { circle } from \"~/glyphs/solid/circle.js\";\n\n// Idempotent registration: makes the `\"circle\"` glyph available for the dot\n// regardless of which control imports first.\nGlyph.register(circle);\n\n/**\n * Construction-time options for {@link RadioButton}.\n *\n * @category Components\n */\nexport interface RadioButtonOptions extends AbstractBooleanInputOptions {\n selected?: boolean;\n value?: boolean;\n text?: string;\n radioName?: string;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * radio button'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 radio button rendered as a focusable `<div>` with\n * `role=\"radio\"`. The ring + dot is drawn with framework primitives; the\n * native `<input type=\"radio\">` is intentionally not used. Group selection\n * is coordinated by [`ButtonGroup`](/api/overlay/classes/ButtonGroup); keyboard\n * navigation within a group is provided by\n * [`RovingTabIndex`](/api/core/classes/RovingTabIndex).\n *\n * @category Components\n */\nclass RadioButton<TOptions extends RadioButtonOptions = RadioButtonOptions>\n extends AbstractBooleanInput<TOptions>\n{\n private _ring: Component;\n private _dot: Glyph;\n\n /**\n * Constructs a RadioButton.\n *\n * @param text - Optional label text. Equivalent to `options.label`; kept\n * positional for back-compat with consumers that wrote\n * `new RadioButton(\"Hello\")`.\n * @param options - Optional construction-time options bag.\n */\n constructor(text?: string, options?: TOptions) {\n super({ ...(options ?? {}) } as TOptions);\n\n this.setLayoutManager(new HBox());\n\n this._ring = new Component();\n this._ring.setPreferredSize(16, 16);\n // Min = preferred = max so the outer HBox shrink-on-overallocation\n // can't collapse the ring graphic when the radio is packed into a\n // tight container with siblings that have flexible widths.\n this._ring.setMinSize(16, 16);\n this._ring.setMaxSize(16, 16);\n this._ring.setSize({ width: 16, height: 16 });\n this._ring.setBackgroundColor(\"var(--ts-ui-radio-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))\");\n this._ring.setBorder(\"1px solid var(--ts-ui-form-border, rgb(160, 160, 160))\");\n this._ring.setBorderRadius(\"50%\");\n // The ring 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 a label or in any\n // stretched empty space don't select and don't show the pointer cursor.\n this._ring.setCursor(\"pointer\");\n\n this._dot = new Glyph(\"circle\");\n this._dot.setForegroundColor(\"var(--ts-ui-radio-dot-color, rgb(255, 255, 255))\");\n this._dot.setPreferredSize(8, 8);\n this._dot.setMaxSize(8, 8);\n this._dot.setX(3);\n this._dot.setY(3);\n this._dot.setOpacity(0);\n // Pass-through so clicks on the dot still hit the ring underneath.\n this._dot.setPointerEvents(\"none\");\n\n if (!Animation.isReducedMotion()) {\n this._dot.setTransition(\"opacity 120ms ease-out\");\n this._ring.setTransition(\"background-color 120ms ease-out, border-color 120ms ease-out\");\n }\n\n this._ring.addComponent(this._dot);\n super.addComponent(this._ring);\n\n this.getAria().setRole(\"radio\");\n this.getAria().setTabIndex(0);\n this.getAria().setChecked(false);\n\n this.setOutline(\"none\");\n\n // The ring owns the user-select 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 // ring would otherwise bind `this` to the ring; only the keyboard path,\n // registered on the root, moves into the base.\n Event.addListener(this._ring, \"click\", () => this.activateFromPointer());\n this.installKeyboard();\n\n // The positional `text` arg wins only when `options.label` (or\n // `options.text`) was not provided.\n if (this._options.label === undefined && this._options.text === undefined && text !== undefined) {\n this._options.label = text;\n } else if (this._options.label === undefined && this._options.text !== undefined) {\n this._options.label = this._options.text;\n }\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);\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 RadioButtonOptions} bag. Inherited Component fields\n * cascade through `super.applyOptions`; radio-button-specific fields are\n * stored pure on `_options` so the constructor body can dispatch them\n * after children are 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.label !== undefined) this._options.label = options.label;\n if (options.text !== undefined) this._options.text = options.text;\n if (options.radioName !== undefined) this._options.radioName = options.radioName;\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 radio button from a click or key: radio buttons can only be\n * selected, never directly deselected by the user (the `ButtonGroup`\n * deselects siblings on change), so this selects and fires the DOM `change`\n * only on a real off→on transition. The enabled/read-only guard is applied\n * by the base before this runs.\n */\n protected activate(): void {\n if (!this.isSelected()) {\n this.setSelected(true);\n Event.fireEvent(this, \"change\");\n }\n }\n\n /**\n * Returns the inner ring graphic — the click + cursor surface.\n *\n * @returns The ring component.\n */\n protected getInteractiveSurface(): Component {\n return this._ring;\n }\n\n /**\n * Returns whether the radio button is currently selected.\n *\n * @returns `true` when selected.\n */\n isSelected(): boolean {\n return this._options.selected ?? false;\n }\n\n /**\n * Sets the selected state and updates the visual + ARIA cache. Used both\n * by user-driven selection and by `ButtonGroup` when it deselects\n * siblings.\n *\n * @param value - `true` to select, `false` to deselect.\n *\n * @returns This component, for method chaining.\n */\n setSelected(value: boolean): this {\n const next = !!value;\n if (next === this.isSelected()) {\n return this;\n }\n\n this._options.selected = next;\n this.applySelected(next);\n this.notifyChange(next);\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 selected.\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 selected state.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: boolean): this {\n return this.setSelected(value);\n }\n\n /**\n * Back-compat shim that stores the supplied group name on `_options` but\n * does not emit a `name` attribute (the host element is no longer\n * `<input>`). Consumers that read the group name through\n * {@link getRadioName} keep working.\n *\n * @param name - Group name string.\n *\n * @returns This component, for method chaining.\n */\n setRadioName(name: string): this {\n this._options.radioName = name;\n\n return this;\n }\n\n /**\n * Clears the back-compat radio-name field.\n *\n * @returns This component, for method chaining.\n */\n clearRadioName(): this {\n this._options.radioName = undefined;\n\n return this;\n }\n\n /**\n * Returns the group name set via {@link setRadioName}, or `null`.\n *\n * @returns The group name string, or `null`.\n */\n getRadioName(): string | null {\n return this._options.radioName ?? null;\n }\n\n /**\n * Registers a listener for one of this radio button's events.\n * `\"action\"` is a typed semantic shorthand over {@link Event.addListener}\n * for the DOM change event — fired on user-driven selection and used by\n * [`ButtonGroup`](/api/overlay/classes/ButtonGroup) to enforce mutual\n * exclusivity. `\"change\"` and `\"binding\"` are the inherited\n * {@link AbstractInput} listener-bag events.\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: 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, \"change\", 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, \"change\", listener);\n\n return this;\n }\n\n return super.off(event, listener);\n }\n\n /**\n * Updates the visual + ARIA state for the given selected flag.\n */\n private applySelected(selected: boolean): void {\n this.getAria().setChecked(selected);\n\n this._ring.setBackgroundColor(selected\n ? \"var(--ts-ui-radio-bg-selected, rgb(30, 100, 200))\"\n : \"var(--ts-ui-radio-bg, var(--ts-ui-form-bg, rgb(255, 255, 255)))\");\n this._ring.setBorder(selected\n ? \"1px solid var(--ts-ui-radio-bg-selected, rgb(30, 100, 200))\"\n : \"1px solid var(--ts-ui-form-border, rgb(160, 160, 160))\");\n\n this._dot.setOpacity(selected ? 1 : 0);\n }\n\n}\n\nconst RadioButtonCallable = callable(RadioButton);\ntype RadioButtonCallable<TOptions extends RadioButtonOptions = RadioButtonOptions> = RadioButton<TOptions>;\nexport {\n RadioButton as _RadioButton,\n RadioButtonCallable as RadioButton\n};\n"],"mappings":"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"}
|