@jimka/typescript-ui 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/{AbstractBooleanInput-DE5NNJT0.js → AbstractBooleanInput-CbW7ZrDT.js} +2 -2
- package/dist/lib/{AbstractBooleanInput-DE5NNJT0.js.map → AbstractBooleanInput-CbW7ZrDT.js.map} +1 -1
- package/dist/lib/{AbstractInput-BxfrmD2W.js → AbstractInput-B10DfLOf.js} +2 -2
- package/dist/lib/{AbstractInput-BxfrmD2W.js.map → AbstractInput-B10DfLOf.js.map} +1 -1
- package/dist/lib/Anchor-BsblS5it.js +2 -0
- package/dist/lib/Anchor-BsblS5it.js.map +1 -0
- package/dist/lib/AnchorConstraints-Bfkt8019.js +2 -0
- package/dist/lib/AnchorConstraints-Bfkt8019.js.map +1 -0
- package/dist/lib/{AnimatedDropdown-QLNasu_Y.js → AnimatedDropdown-kL47HPGP.js} +2 -2
- package/dist/lib/{AnimatedDropdown-QLNasu_Y.js.map → AnimatedDropdown-kL47HPGP.js.map} +1 -1
- package/dist/lib/Border-CNS6aEXB.js +2 -0
- package/dist/lib/{Border-CKKUk5G9.js.map → Border-CNS6aEXB.js.map} +1 -1
- package/dist/lib/Button-T16zSZip.js +2 -0
- package/dist/lib/Button-T16zSZip.js.map +1 -0
- package/dist/lib/{Card-a4dzYrbX.js → Card-CD3jxshU.js} +2 -2
- package/dist/lib/{Card-a4dzYrbX.js.map → Card-CD3jxshU.js.map} +1 -1
- package/dist/lib/CodeEditor-BGlB232h.js +2 -0
- package/dist/lib/CodeEditor-BGlB232h.js.map +1 -0
- package/dist/lib/ComboBox-C9FYMuLv.js +2 -0
- package/dist/lib/ComboBox-C9FYMuLv.js.map +1 -0
- package/dist/lib/Component-w65rPK75.js +2 -0
- package/dist/lib/Component-w65rPK75.js.map +1 -0
- package/dist/lib/Container-C7RPLQEc.js +2 -0
- package/dist/lib/{Container-0bsG2Q8Z.js.map → Container-C7RPLQEc.js.map} +1 -1
- package/dist/lib/DOM-Ba8YRVel.js +2 -0
- package/dist/lib/{DOM-67StIm5G.js.map → DOM-Ba8YRVel.js.map} +1 -1
- package/dist/lib/DragManager-UvPHSoRm.js +2 -0
- package/dist/lib/{DragManager-DRor_-1x.js.map → DragManager-UvPHSoRm.js.map} +1 -1
- package/dist/lib/{FieldDecorator-Bpx8J8n9.js → FieldDecorator-HG65hEtk.js} +2 -2
- package/dist/lib/{FieldDecorator-Bpx8J8n9.js.map → FieldDecorator-HG65hEtk.js.map} +1 -1
- package/dist/lib/{Fit-CL1m1nIZ.js → Fit-Cg3dPyZg.js} +2 -2
- package/dist/lib/{Fit-CL1m1nIZ.js.map → Fit-Cg3dPyZg.js.map} +1 -1
- package/dist/lib/FloatingPanel-D5buuVrQ.js +2 -0
- package/dist/lib/FloatingPanel-D5buuVrQ.js.map +1 -0
- package/dist/lib/{Glyph-wN7bk7mg.js → Glyph-DeJF_zsR.js} +2 -2
- package/dist/lib/{Glyph-wN7bk7mg.js.map → Glyph-DeJF_zsR.js.map} +1 -1
- package/dist/lib/{Grid-DHHmaB-Y.js → Grid-BYBohJIA.js} +2 -2
- package/dist/lib/{Grid-DHHmaB-Y.js.map → Grid-BYBohJIA.js.map} +1 -1
- package/dist/lib/{GridConstraints-DVc1BmlP.js → GridConstraints-Bts284FI.js} +2 -2
- package/dist/lib/{GridConstraints-DVc1BmlP.js.map → GridConstraints-Bts284FI.js.map} +1 -1
- package/dist/lib/{Header-2hKwQo_u.js → Header-BIFJK9nR.js} +2 -2
- package/dist/lib/{Header-2hKwQo_u.js.map → Header-BIFJK9nR.js.map} +1 -1
- package/dist/lib/{IconText-DC7Xe34b.js → IconText-Dsb1xS-E.js} +2 -2
- package/dist/lib/{IconText-DC7Xe34b.js.map → IconText-Dsb1xS-E.js.map} +1 -1
- package/dist/lib/LanguageRegistry-CcVnbKuh.js +2 -0
- package/dist/lib/LanguageRegistry-CcVnbKuh.js.map +1 -0
- package/dist/lib/LayoutSerialization-ySzY1h2l.js +2 -0
- package/dist/lib/{LayoutSerialization-D5bBas4W.js.map → LayoutSerialization-ySzY1h2l.js.map} +1 -1
- package/dist/lib/LayoutSizes-DKDK1Cle.js +2 -0
- package/dist/lib/LayoutSizes-DKDK1Cle.js.map +1 -0
- package/dist/lib/List-BPd-IXZR.js +2 -0
- package/dist/lib/{List-CG4NvwuV.js.map → List-BPd-IXZR.js.map} +1 -1
- package/dist/lib/MemoryStore-BgP7-Uzn.js +2 -0
- package/dist/lib/{MemoryStore-DT6iWWco.js.map → MemoryStore-BgP7-Uzn.js.map} +1 -1
- package/dist/lib/Menu-C0roOCY7.js +2 -0
- package/dist/lib/Menu-C0roOCY7.js.map +1 -0
- package/dist/lib/{MenuButton-wy_0RskC.js → MenuButton-BR4KOFld.js} +2 -2
- package/dist/lib/{MenuButton-wy_0RskC.js.map → MenuButton-BR4KOFld.js.map} +1 -1
- package/dist/lib/Panel-CpNQTLNF.js +2 -0
- package/dist/lib/{Panel-Rd9zkNXx.js.map → Panel-CpNQTLNF.js.map} +1 -1
- package/dist/lib/{Position-Ck_KD4cR.js → Position-PBVBW1JS.js} +2 -2
- package/dist/lib/{Position-Ck_KD4cR.js.map → Position-PBVBW1JS.js.map} +1 -1
- package/dist/lib/{ProgressSpinner-yt-VXyCb.js → ProgressSpinner-lAsK26C-.js} +2 -2
- package/dist/lib/{ProgressSpinner-yt-VXyCb.js.map → ProgressSpinner-lAsK26C-.js.map} +1 -1
- package/dist/lib/RadioButton-CCcIaL54.js +2 -0
- package/dist/lib/RadioButton-CCcIaL54.js.map +1 -0
- package/dist/lib/{RovingTabIndex-DFJyoveq.js → RovingTabIndex-C2Vzq0IX.js} +2 -2
- package/dist/lib/{RovingTabIndex-DFJyoveq.js.map → RovingTabIndex-C2Vzq0IX.js.map} +1 -1
- package/dist/lib/Scrollbar-C3ZZyZ1e.js +2 -0
- package/dist/lib/Scrollbar-C3ZZyZ1e.js.map +1 -0
- package/dist/lib/Slider-DZ9drUxn.js +2 -0
- package/dist/lib/Slider-DZ9drUxn.js.map +1 -0
- package/dist/lib/{Spacer-qalSEJ5i.js → Spacer-SDhOMp2g.js} +2 -2
- package/dist/lib/{Spacer-qalSEJ5i.js.map → Spacer-SDhOMp2g.js.map} +1 -1
- package/dist/lib/TabButton-DNo4ZgV8.js +2 -0
- package/dist/lib/TabButton-DNo4ZgV8.js.map +1 -0
- package/dist/lib/Text-CdHf3B-1.js +2 -0
- package/dist/lib/Text-CdHf3B-1.js.map +1 -0
- package/dist/lib/{Tooltip-Dro4DOZs.js → Tooltip-B_UF5bXD.js} +2 -2
- package/dist/lib/{Tooltip-Dro4DOZs.js.map → Tooltip-B_UF5bXD.js.map} +1 -1
- package/dist/lib/Tree-C7qLbIYH.js +2 -0
- package/dist/lib/Tree-C7qLbIYH.js.map +1 -0
- package/dist/lib/VBox-32fxpkDl.js +2 -0
- package/dist/lib/VBox-32fxpkDl.js.map +1 -0
- package/dist/lib/{Validator-Du8PqS5i.js → Validator-Cjs1EU5Q.js} +2 -2
- package/dist/lib/{Validator-Du8PqS5i.js.map → Validator-Cjs1EU5Q.js.map} +1 -1
- package/dist/lib/{VirtualScroller-Bv4KXGKW.js → VirtualScroller-cvFNMS7U.js} +2 -2
- package/dist/lib/{VirtualScroller-Bv4KXGKW.js.map → VirtualScroller-cvFNMS7U.js.map} +1 -1
- package/dist/lib/component/button.es.js +1 -1
- package/dist/lib/component/chart.es.js +1 -1
- package/dist/lib/component/chart.es.js.map +1 -1
- package/dist/lib/component/container.es.js +1 -1
- package/dist/lib/component/container.es.js.map +1 -1
- package/dist/lib/component/diagram.es.js +1 -1
- package/dist/lib/component/diagram.es.js.map +1 -1
- package/dist/lib/component/display.es.js +1 -1
- package/dist/lib/component/display.es.js.map +1 -1
- package/dist/lib/component/editor.es.js +3 -3
- package/dist/lib/component/editor.es.js.map +1 -1
- package/dist/lib/component/input.es.js +1 -1
- package/dist/lib/component/input.es.js.map +1 -1
- package/dist/lib/component/list.es.js +1 -1
- package/dist/lib/component/list.es.js.map +1 -1
- package/dist/lib/component/menubar.es.js +1 -1
- package/dist/lib/component/menubar.es.js.map +1 -1
- package/dist/lib/component/table.es.js +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/data.es.js +1 -1
- package/dist/lib/glyphs/solid/index.es.js +1 -1
- package/dist/lib/languages-Dl8qdL8a.js +2 -0
- package/dist/lib/languages-Dl8qdL8a.js.map +1 -0
- package/dist/lib/layout.es.js +1 -1
- package/dist/lib/layout.es.js.map +1 -1
- package/dist/lib/overlay.es.js +1 -1
- package/dist/lib/overlay.es.js.map +1 -1
- package/dist/lib/primitive.es.js +1 -1
- package/dist/lib/router.es.js +1 -1
- package/dist/lib/router.es.js.map +1 -1
- package/dist/lib/selectionsEqual-BrTxPMmK.js +2 -0
- package/dist/lib/{selectionsEqual-Ci3_uflt.js.map → selectionsEqual-BrTxPMmK.js.map} +1 -1
- package/dist/lib/types/component/button/TabButton.d.ts +1 -1
- package/dist/lib/types/component/button/ToggleButton.d.ts +1 -1
- package/dist/lib/types/component/chart/ChartLegend.d.ts +1 -1
- package/dist/lib/types/component/container/FloatingPanel.d.ts +23 -0
- package/dist/lib/types/component/container/ScrollStrip.d.ts +1 -1
- package/dist/lib/types/component/container/Scrollbar.d.ts +1 -3
- package/dist/lib/types/component/container/TabBar.d.ts +1 -1
- package/dist/lib/types/component/container/index.d.ts +2 -0
- package/dist/lib/types/component/diagram/DiagramGroupNode.d.ts +1 -1
- package/dist/lib/types/component/display/Markdown.d.ts +42 -1
- package/dist/lib/types/component/display/MarkdownMinimap.d.ts +38 -0
- package/dist/lib/types/component/display/MarkdownViewer.d.ts +60 -0
- package/dist/lib/types/component/display/index.d.ts +6 -0
- package/dist/lib/types/component/editor/CodeEditor.d.ts +13 -0
- package/dist/lib/types/component/editor/index.d.ts +1 -1
- package/dist/lib/types/component/input/Checkbox.d.ts +1 -1
- package/dist/lib/types/component/input/RadioButton.d.ts +1 -1
- package/dist/lib/types/component/input/Slider.d.ts +1 -1
- package/dist/lib/types/component/input/Text.d.ts +0 -2
- package/dist/lib/types/component/input/Toggle.d.ts +1 -1
- package/dist/lib/types/component/menubar/MenuBar.d.ts +1 -1
- package/dist/lib/types/component/menubar/ToolBar.d.ts +1 -0
- package/dist/lib/types/component/table/Body.d.ts +1 -0
- package/dist/lib/types/component/table/cell/SortPriorityBadge.d.ts +1 -1
- package/dist/lib/types/component/table/cell/editor/CellEditorPool.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/Date.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/DateTime.d.ts +1 -0
- package/dist/lib/types/component/table/cell/editor/Time.d.ts +1 -0
- package/dist/lib/types/component/tree/Tree.d.ts +9 -1
- package/dist/lib/types/component/tree/index.d.ts +1 -1
- package/dist/lib/types/component/tree/renderer/Label.d.ts +1 -1
- package/dist/lib/types/core/Component.d.ts +5 -0
- package/dist/lib/types/core/Theme.d.ts +4 -2
- package/dist/lib/types/layout/LayoutManager.d.ts +8 -0
- package/dist/lib/validation.es.js +1 -1
- package/llms.txt +3 -0
- package/package.json +15 -15
- package/dist/lib/AnchorConstraints-DdDYSDkf.js +0 -2
- package/dist/lib/AnchorConstraints-DdDYSDkf.js.map +0 -1
- package/dist/lib/Border-CKKUk5G9.js +0 -2
- package/dist/lib/Button-MZDYJOMC.js +0 -2
- package/dist/lib/Button-MZDYJOMC.js.map +0 -1
- package/dist/lib/ComboBox-C04SfXAR.js +0 -2
- package/dist/lib/ComboBox-C04SfXAR.js.map +0 -1
- package/dist/lib/Component-fRQvgaEY.js +0 -2
- package/dist/lib/Component-fRQvgaEY.js.map +0 -1
- package/dist/lib/Container-0bsG2Q8Z.js +0 -2
- package/dist/lib/DOM-67StIm5G.js +0 -2
- package/dist/lib/DragManager-DRor_-1x.js +0 -2
- package/dist/lib/LayoutSerialization-D5bBas4W.js +0 -2
- package/dist/lib/LayoutSizes-qNaURyiw.js +0 -2
- package/dist/lib/LayoutSizes-qNaURyiw.js.map +0 -1
- package/dist/lib/List-CG4NvwuV.js +0 -2
- package/dist/lib/MemoryStore-DT6iWWco.js +0 -2
- package/dist/lib/Menu-CrZy2u0g.js +0 -2
- package/dist/lib/Menu-CrZy2u0g.js.map +0 -1
- package/dist/lib/Panel-Rd9zkNXx.js +0 -2
- package/dist/lib/RadioButton-D23rId-V.js +0 -2
- package/dist/lib/RadioButton-D23rId-V.js.map +0 -1
- package/dist/lib/Scrollbar-SOj9psiP.js +0 -2
- package/dist/lib/Scrollbar-SOj9psiP.js.map +0 -1
- package/dist/lib/Slider-DBnAZ-F7.js +0 -2
- package/dist/lib/Slider-DBnAZ-F7.js.map +0 -1
- package/dist/lib/TabButton-DKECTTk1.js +0 -2
- package/dist/lib/TabButton-DKECTTk1.js.map +0 -1
- package/dist/lib/Text-KB5LksJl.js +0 -2
- package/dist/lib/Text-KB5LksJl.js.map +0 -1
- package/dist/lib/VBox-P3WFGkPc.js +0 -2
- package/dist/lib/VBox-P3WFGkPc.js.map +0 -1
- package/dist/lib/selectionsEqual-Ci3_uflt.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Border-CKKUk5G9.js","names":[],"sources":["../../src/typescript/lib/core/PointerDrag.ts","../../src/typescript/lib/layout/CollapseSupport.ts","../../src/typescript/lib/component/container/CollapseButton.ts","../../src/typescript/lib/component/container/SplitGutter.ts","../../src/typescript/lib/layout/Border.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Body-level bookkeeping shared by every component that drags a handle against\n * the viewport — a split gutter, a window border, a table column edge.\n *\n * Two things have to happen together for the duration of such a drag, which is\n * why they live in one call rather than at each drag site:\n *\n * 1. `<body>` stops taking pointer events, so the drag can't snag on whatever\n * the pointer passes over.\n * 2. The document element holds the drag cursor. This is the half that is easy\n * to miss: suppressing (1) also takes body's whole subtree — the drag handle\n * included — out of hit-testing, so nothing there resolves a cursor any more\n * and the pointer reverts to the default arrow mid-drag. The document\n * element stays hit-testable and is what the cursor falls back to, so it has\n * to carry the cursor instead.\n */\n\n/**\n * Suppresses body pointer events and pins `cursor` for the duration of a drag.\n * Pair every call with {@link endPointerDrag}.\n *\n * @param cursor - The CSS cursor to hold until the drag ends, normally the one\n * the handle shows on hover so the two can't disagree.\n */\nexport function beginPointerDrag(cursor: string): void {\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"none\" } });\n DOM.sink.apply(DOM.source.getDocumentElement(), { style: { cursor } });\n}\n\n/**\n * Restores body pointer events and hands the cursor back to whatever the\n * pointer is actually over. Safe to call without a matching\n * {@link beginPointerDrag} — it only clears inline values.\n */\nexport function endPointerDrag(): void {\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"\" } });\n DOM.sink.apply(DOM.source.getDocumentElement(), { style: { cursor: \"\" } });\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Animation } from \"~/core/Animation.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n// Pixel thickness of the opaque collapse strip a collapsed pane/region tucks\n// into — the size the gutter assumes in its strip state, leaving room for its\n// restore chevron. The layout math in `Split.doLayout`/`Border.doLayout` needs\n// a number, so the value lives here as a constant rather than only as the\n// `--ts-ui-collapse-strip-size` theme token — kept in lockstep by convention\n// (token default 18px).\nexport const COLLAPSE_STRIP_SIZE = 18;\n\n// Collapse/restore transition duration in milliseconds. Mirrors the\n// Accordion's 200ms default so the two surfaces share one motion personality;\n// kept as a code constant (not a theme token) for the same reason Accordion's\n// duration is — motion belongs to the layout, not the theme.\nconst COLLAPSE_DURATION = 200;\n\n// Symmetric easing curve, identical to the Accordion's, so a collapse reads as\n// a time-reverse of a restore. A symmetric curve (`easing(t) + easing(1-t) = 1`)\n// avoids the \"content vanished, then nothing happened\" feel of asymmetric\n// material curves. Shared with Accordion deliberately for a consistent feel.\nconst COLLAPSE_EASING = \"cubic-bezier(0.4, 0, 0.6, 1)\";\n\n/** Handle for the reduced-motion path, where no transition is primed at all. */\nconst NOOP_HANDLE: Animation.CancelHandle = { cancel: (): void => {} };\n\n/**\n * A primed CSS transition that has not settled yet, as held in a manager's\n * pending list. Two dispositions, because teardown has two shapes.\n *\n * @category Layout\n */\nexport interface CollapseTransition {\n /**\n * Abandons the transition and its completion callback. For the dispose\n * path, where every participant is being destroyed anyway and touching one\n * would write through a released element handle.\n */\n cancel(): void;\n\n /**\n * Abandons the transition but runs its cleanup — clearing `transition` on\n * every participant and `will-change` on the animating one — immediately.\n * For the manager-swap path, where the participants stay mounted and would\n * otherwise keep a live transition and a permanent compositor layer.\n */\n settle(): void;\n}\n\n/**\n * Primes a transition via `create` and adds its handle to `pending`, arranging\n * for the handle to remove itself once the transition settles. The list is\n * therefore always exactly the set of transitions still in flight — which is\n * what a manager's `detach` needs, and what neither the geometry canceller nor\n * a per-toggle field can hold (both are replaced or nulled while primed\n * transitions from an earlier toggle are still running).\n *\n * @param pending - The manager's live-transition list.\n * @param create - Primes the transition, given the callback that prunes it.\n */\nfunction track(\n pending: CollapseTransition[],\n create: (onSettled: () => void) => { handle: Animation.CancelHandle; cleanup: () => void },\n): void {\n let entry: CollapseTransition | null = null;\n let settled = false;\n\n const prune = (): void => {\n settled = true;\n\n const index = entry === null ? -1 : pending.indexOf(entry);\n\n if (index >= 0) {\n pending.splice(index, 1);\n }\n };\n\n const { handle, cleanup } = create(prune);\n\n // `create` settles synchronously under reduced motion, and also when the\n // animating component has no element — in both cases `prune` already ran,\n // before `entry` existed, so there is nothing live to track.\n if (settled) {\n return;\n }\n\n entry = {\n cancel: (): void => handle.cancel(),\n settle: (): void => {\n handle.cancel();\n cleanup();\n },\n };\n\n pending.push(entry);\n}\n\n/**\n * Primes a collapse/restore animation: installs a multi-property geometry\n * transition on every participating element, pre-promotes the driving element\n * to its own compositor layer, and schedules the layer's release plus\n * transition cleanup on `transitionend` (with a `setTimeout` fallback).\n *\n * The gutter that carries the motion both *moves* (`left`/`top`) and *resizes*\n * (`width`/`height`) between its divider and strip states, so the transition\n * spans the full axis property list rather than a single size property.\n *\n * The caller is expected to flip its collapsed flag and call `scheduleLayout`\n * immediately after — the next `doLayout` writes the new geometry, which the\n * just-installed transition animates.\n *\n * Under `prefers-reduced-motion: reduce` this is a no-op: no transition is\n * installed, so the upcoming `doLayout` writes land instantly.\n *\n * @param animating - The element that visibly moves; promoted via `will-change`\n * and the one whose `transitionend` (filtered to `completionProperty`) ends\n * the animation.\n * @param properties - The CSS properties to transition (e.g. `[\"left\", \"width\"]`\n * for a horizontal move-and-resize).\n * @param participants - Every element that should carry the transition for this\n * toggle: the gutter plus whatever shifts to fill — `Border` passes the gutter\n * and the centre; `Split` passes all panes and gutters.\n * @param onSettled - Invoked once the transition completes (or immediately under\n * reduced motion), so the caller can drop this handle from its live list.\n * @param completionProperty - Which property's `transitionend` ends the\n * animation. Defaults to the first property; pass the size property (whose\n * `transitionend` fires reliably) when the move delta may be zero.\n */\nfunction primeCollapse(\n animating: Component,\n properties: string[],\n participants: Component[],\n onSettled: () => void,\n completionProperty?: string,\n): { handle: Animation.CancelHandle; cleanup: () => void } {\n const cleanup = (): void => {\n for (const participant of participants) {\n participant.setTransition(null);\n }\n\n animating.setWillChange(null);\n };\n\n if (Animation.isReducedMotion()) {\n onSettled();\n\n return { handle: NOOP_HANDLE, cleanup };\n }\n\n const transition = properties\n .map(property => `${property} ${COLLAPSE_DURATION}ms ${COLLAPSE_EASING}`)\n .join(\", \");\n\n for (const participant of participants) {\n participant.setTransition(transition);\n }\n\n animating.setWillChange(properties.join(\", \"));\n\n const handle = Animation.afterTransition({\n component: animating,\n property: completionProperty ?? properties[0],\n durationMs: COLLAPSE_DURATION,\n fallbackBufferMs: 40,\n onComplete: () => {\n cleanup();\n onSettled();\n },\n });\n\n return { handle, cleanup };\n}\n\n/** An axis-aligned box used to snapshot and interpolate a participant's bounds. */\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * One element animated by {@link animateLayout}: its captured start/end bounds\n * and whether its content must be re-laid-out each frame.\n *\n * @remarks A content-bearing pane (`relayout: true`) needs `doLayout` per frame\n * so its children track the animating box instead of snapping to the final\n * size; an empty gutter (`relayout: false`) only needs its box geometry written,\n * since its single chevron child re-centres via CSS as the box resizes.\n */\ninterface CollapseMover {\n component: Component;\n relayout: boolean;\n start: Rect;\n end: Rect;\n}\n\n/** Reads a component's current box geometry into a {@link Rect}. */\nfunction captureRect(component: Component): Rect {\n return { x: component.getX(), y: component.getY(), width: component.getWidth(), height: component.getHeight() };\n}\n\n/**\n * Parses a `cubic-bezier(x1, y1, x2, y2)` CSS timing string into a JS easing\n * function `progress → eased`, so a JS-driven animation can move in lockstep\n * with a CSS transition that uses the same curve. Falls back to linear if the\n * string isn't a cubic-bezier. Uses Newton-Raphson (then bisection) to invert\n * the bezier's x(t) for a given progress before sampling y(t).\n */\nfunction parseCubicBezier(css: string): (progress: number) => number {\n const match = css.match(/cubic-bezier\\(([^)]+)\\)/);\n if (!match) {\n return progress => progress;\n }\n\n const [x1, y1, x2, y2] = match[1].split(\",\").map(value => parseFloat(value));\n\n const ax = 3 * x1, bx = 3 * (x2 - x1) - ax, cx = 1 - ax - bx;\n const ay = 3 * y1, by = 3 * (y2 - y1) - ay, cy = 1 - ay - by;\n\n const sampleX = (t: number) => ((cx * t + bx) * t + ax) * t;\n const sampleY = (t: number) => ((cy * t + by) * t + ay) * t;\n const sampleDX = (t: number) => (3 * cx * t + 2 * bx) * t + ax;\n\n return progress => {\n let t = progress;\n\n for (let i = 0; i < 8; i += 1) {\n const x = sampleX(t) - progress;\n if (Math.abs(x) < 1e-6) {\n return sampleY(t);\n }\n\n const dx = sampleDX(t);\n if (Math.abs(dx) < 1e-6) {\n break;\n }\n\n t -= x / dx;\n }\n\n // Bisection fallback for the rare flat-slope case.\n let lo = 0, hi = 1;\n t = progress;\n while (lo < hi) {\n const x = sampleX(t);\n if (Math.abs(x - progress) < 1e-6) {\n break;\n }\n if (x < progress) {\n lo = t;\n } else {\n hi = t;\n }\n t = (lo + hi) / 2;\n }\n\n return sampleY(t);\n };\n}\n\n// JS twin of COLLAPSE_EASING, so the rAF geometry interpolation and the\n// clip-path CSS transition share one motion curve.\nconst COLLAPSE_EASE = parseCubicBezier(COLLAPSE_EASING);\n\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\n\nconst lerpRect = (a: Rect, b: Rect, t: number): Rect => ({\n x: lerp(a.x, b.x, t),\n y: lerp(a.y, b.y, t),\n width: lerp(a.width, b.width, t),\n height: lerp(a.height, b.height, t),\n});\n\n/**\n * Writes a resolved rect to a component as a single batched DOM update,\n * mirroring `LayoutManager.commitBounds`: the four positional setters flush\n * together, and a content-bearing participant re-lays-out its children at the\n * new size.\n */\nfunction commitRect(component: Component, rect: Rect, relayout: boolean): void {\n component.setAutoCommitStyle(false);\n component.setX(rect.x);\n component.setY(rect.y);\n component.setWidth(rect.width);\n component.setHeight(rect.height);\n\n if (relayout) {\n component.doLayout();\n }\n\n component.setAutoCommitStyle(true);\n}\n\n/**\n * Drives a coordinated collapse/restore by interpolating every participant's\n * box from its `start` to its `end` over {@link COLLAPSE_DURATION} on\n * {@link COLLAPSE_EASING}, re-laying-out content-bearing panes each frame.\n *\n * This is the JS half of the collapse animation: it keeps the resizing panes,\n * the moving gutter, and their contents moving together, while the *toggled*\n * pane/region holds its final geometry and only reveals via a `clip-path` CSS\n * transition (primed separately by {@link primeCollapse}). Both halves share\n * the easing curve, so they stay in lockstep. Because linear interpolation of\n * two gap-free layouts is itself gap-free at every step, no seams open between\n * adjacent panes mid-animation.\n *\n * The caller is expected to have already snapshotted each mover's `start`,\n * written the end layout (its `doLayout`), and captured each mover's `end`.\n * This function lands on `start` synchronously — so the just-written end state\n * never paints — then animates forward.\n *\n * Under `prefers-reduced-motion: reduce` it writes the end state and completes\n * immediately, with no animation frames.\n *\n * @param movers - The participants with their captured start/end bounds.\n * @param onComplete - Invoked once the animation settles (or immediately under\n * reduced motion); not invoked if the returned canceller runs first.\n * @returns A canceller that stops the animation in place (leaving the current\n * interpolated geometry), so a rapid re-toggle can re-snapshot and retarget.\n */\nfunction animateLayout(movers: CollapseMover[], onComplete?: () => void): () => void {\n if (Animation.isReducedMotion()) {\n for (const mover of movers) {\n commitRect(mover.component, mover.end, mover.relayout);\n }\n\n onComplete?.();\n\n return () => {};\n }\n\n let cancelled = false;\n let raf = 0;\n\n // Land on the start frame synchronously so the caller's just-written end\n // geometry never reaches the screen.\n for (const mover of movers) {\n commitRect(mover.component, mover.start, mover.relayout);\n }\n\n const startTime = performance.now();\n\n const frame = (now: number): void => {\n if (cancelled) {\n return;\n }\n\n const progress = Math.min(1, (now - startTime) / COLLAPSE_DURATION);\n const eased = COLLAPSE_EASE(progress);\n\n for (const mover of movers) {\n commitRect(mover.component, progress >= 1 ? mover.end : lerpRect(mover.start, mover.end, eased), mover.relayout);\n }\n\n if (progress < 1) {\n raf = DOM.sink.requestAnimationFrame(frame);\n } else {\n onComplete?.();\n }\n };\n\n raf = DOM.sink.requestAnimationFrame(frame);\n\n return () => {\n cancelled = true;\n\n if (raf) {\n DOM.sink.cancelAnimationFrame(raf);\n }\n };\n}\n\n/**\n * One participant in a {@link runCollapse} pass: the moving element and whether\n * its content must be re-laid-out each frame — `true` for a content-bearing\n * pane/region, `false` for an empty gutter.\n */\nexport interface CollapseParticipant {\n component: Component;\n relayout: boolean;\n}\n\n/**\n * Runs one coordinated collapse/restore for a layout manager — the shared\n * plumbing behind [`Split.setPaneCollapsed`](/api/layout/classes/Split) and\n * [`Border.setRegionCollapsed`](/api/layout/classes/Border). The caller has\n * already flipped its own collapsed flag and assembled `participants`: every\n * box that moves — the panes/regions (`relayout: true`) and the gutters\n * (`relayout: false`), the `toggled` one included.\n *\n * The pass: cancel any in-flight collapse (`previous`); prime the `toggled`\n * pane/region's clip-path reveal (it keeps its final size and only clips, so it\n * never reads as a content snap); snapshot every participant's start geometry;\n * write the end layout via the container's `doLayout`; capture the end geometry;\n * and hand the lot to the rAF driver, which interpolates the boxes — re-laying\n * out the content-bearing ones — in lockstep with the clip transition.\n *\n * @param container - The manager's container, laid out to compute the end state.\n * @param toggled - The pane/region being collapsed or restored (clip-revealed).\n * @param participants - Every moving box, including `toggled`.\n * @param previous - The manager's current animation canceller, or null when idle.\n * @param pending - The manager's list of primed CSS transitions that have not\n * settled yet. `runCollapse` appends to it and each entry removes itself on\n * completion, so the manager's `detach` can cancel exactly the live ones.\n * Kept off the returned canceller deliberately: that canceller is nulled when\n * the geometry animation settles, ~40 ms before the primed transitions'\n * fallbacks disarm, and a re-toggle replaces it while old transitions are\n * still running — either would strand a live handle.\n * @param onIdle - Invoked when the animation settles; clears the manager's handle.\n * @returns A canceller the manager stores and passes back as `previous` next time.\n */\nexport function runCollapse(\n container: Component,\n toggled: Component,\n participants: CollapseParticipant[],\n previous: (() => void) | null,\n pending: CollapseTransition[],\n onIdle?: () => void,\n): () => void {\n // Stop any in-flight collapse so a rapid re-toggle re-snapshots from the\n // current mid-animation geometry and retargets cleanly. Only the geometry\n // animation is stopped: the primed CSS transitions are left to finish and\n // run their own cleanup, because that cleanup (clearing `transition` and\n // `will-change` on the previous participants) has no other trigger and the\n // fresh prime below covers only the new participant set.\n previous?.();\n\n // The toggled pane/region holds its final size and reveals only via a\n // clip-path transition; every other participant is JS-driven below so boxes\n // and contents move together.\n track(pending, handle => primeCollapse(toggled, [\"clip-path\"], [toggled], handle, \"clip-path\"));\n\n // Cross-fade each gutter's fill between its transparent divider colour and\n // its opaque strip colour as it morphs, so the strip doesn't pop in or out.\n // Only the toggling gutter's colour actually changes when `doLayout` runs\n // `setOpaque` below; the rest carry the transition harmlessly. The fade is a\n // CSS transition (colour interpolation, `var()` resolution, and the\n // transparent endpoint are all easier left to the browser) sharing the\n // geometry's duration and curve.\n const gutters = participants.filter(participant => !participant.relayout).map(participant => participant.component);\n if (gutters.length > 0) {\n track(pending, handle => primeCollapse(gutters[0], [\"background-color\"], gutters, handle, \"background-color\"));\n }\n\n // Snapshot the start geometry, write the end layout, then capture the end\n // geometry and animate between the two.\n const starts = participants.map(participant => captureRect(participant.component));\n\n container.doLayout();\n\n const movers: CollapseMover[] = participants.map((participant, index) => ({\n component: participant.component,\n relayout: participant.relayout,\n start: starts[index],\n end: captureRect(participant.component),\n }));\n\n return animateLayout(movers, onIdle);\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { COLLAPSE_STRIP_SIZE } from \"~/layout/CollapseSupport.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n// The chevron handle's thickness across the host gutter in its two states: a\n// narrow grip while the gutter is an expanded divider, widening to the full\n// collapse-strip width so the restore handle fills the strip once collapsed.\n// The length along the gutter is constant in both states.\nconst GRIP_ACROSS = 10;\nconst HANDLE_ALONG = 40;\n\n/**\n * The four directions a {@link CollapseButton}'s chevron can point — the\n * direction the pane/region travels when the button is activated (collapse) or\n * restored.\n *\n * @category Components\n */\nexport type CollapseDirection = \"north\" | \"south\" | \"east\" | \"west\";\n\n/**\n * String-literal union of the events emitted by {@link CollapseButton}.\n *\n * @category Components\n */\nexport type CollapseButtonEvent = \"collapse\";\n\n/**\n * Construction-time options for {@link CollapseButton}.\n *\n * @category Components\n */\nexport interface CollapseButtonOptions extends ComponentOptions {\n direction?: CollapseDirection;\n /**\n * Multi-event listener bag dispatched to {@link CollapseButton.on} at\n * construction time.\n */\n listeners?: {\n collapse?: () => void;\n };\n}\n\n/**\n * Degrees of rotation applied to the base east-pointing chevron glyph (`▶`) to\n * make it point in each {@link CollapseDirection}. Keyed so {@link CollapseButton}\n * can resolve the per-instance transform without a `switch`.\n */\nconst _rotationByDirection: Record<CollapseDirection, number> = {\n east: 0,\n south: 90,\n west: 180,\n north: -90,\n};\n\nlet _classRule: StyleRule | null = null;\n\n/**\n * Registers the shared `.CollapseButton` class rule once on first use. The rule\n * holds the centred overlay geometry, chevron colour, and the raised themed\n * grip styling (the button overflows its thin host gutter so it stays\n * clickable).\n *\n * Idempotent and module-local; safe across hot reloads.\n */\nfunction ensureCollapseButtonClassRule(): void {\n if (_classRule) {\n return;\n }\n\n _classRule = new StyleRule({\n scope: \"class\",\n name: \"CollapseButton\",\n styles: {\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n // Fallback centring transform; each instance overrides it via a\n // per-instance rule that layers on the direction rotation.\n transform: \"translate(-50%, -50%)\",\n // A raised, themed grip handle rather than a bare glyph, so the\n // whole thing is an easy double-click target. The box is uniform\n // (thin across the track, long along it) and the per-instance\n // rotation orients it: a tall handle on a vertical (west/east)\n // gutter, a wide one on a horizontal (north/south) gutter. Reuses\n // the button tokens so it matches the theme's raised controls.\n boxSizing: \"border-box\",\n width: `${GRIP_ACROSS}px`,\n height: `${HANDLE_ALONG}px`,\n borderRadius: \"2px\",\n background: \"var(--ts-ui-button-bg, #e8e8e8)\",\n border: \"1px solid var(--ts-ui-button-border, #c8c8c8)\",\n boxShadow: \"var(--ts-ui-button-shadow, 0 1px 2px rgba(0, 0, 0, 0.2))\",\n textAlign: \"center\",\n fontSize: \"9px\",\n lineHeight: `${HANDLE_ALONG - 2}px`,\n color: \"var(--ts-ui-collapse-button-color, rgb(100,100,100))\",\n // The handle keeps its own pointer events so it stays clickable\n // even where it overhangs the thin host gutter. The clickable\n // `cursor: pointer` is applied per-instance (the Component default\n // `cursor: default` would otherwise override a class-rule cursor).\n pointerEvents: \"auto\",\n userSelect: \"none\",\n },\n });\n}\n\n/**\n * A small chevron button carried by a [`SplitGutter`](/api/component/container/classes/SplitGutter)\n * that triggers a collapse in the gutter's divider state or a restore in its\n * collapsed-strip state.\n *\n * Activation is a **double-click**, never a single click, so grabbing the button\n * for a drag can never collapse by accident — a drag produces no `dblclick`, and\n * the button's `mousedown` is stopped from reaching the host so it never begins\n * a gutter resize.\n *\n * @category Components\n */\nclass CollapseButton extends Component<CollapseButtonOptions> {\n\n declare private _direction: CollapseDirection;\n private _listeners: ListenerBag<CollapseButtonEvent> = new ListenerBag<CollapseButtonEvent>();\n\n /**\n * Constructs a collapse button. The chevron points east unless\n * `options.direction` says otherwise.\n *\n * @param options - Optional configuration bag (chevron direction, listener\n * bag, plus common Component fields).\n */\n constructor(options?: CollapseButtonOptions) {\n ensureCollapseButtonClassRule();\n\n // `cursor: \"pointer\"` is set here (not only in the class rule) because\n // Component defaults `cursor` to `\"default\"` and writes it per-instance,\n // which would override a class-rule cursor. A caller-supplied cursor\n // still wins via the trailing spread.\n super({ tag: \"span\", cursor: \"pointer\", ...(options ?? {}) });\n\n this._direction ??= \"east\";\n\n this.applyRotation();\n\n // Listener wiring runs here — NOT inside `applyOptions` — because\n // Component's constructor calls `applyOptions` from inside super(),\n // before the class-field `_listeners` initializer has run.\n this.applyListeners(options?.listeners);\n\n Event.addListener(this, \"dblclick\", this.onDoubleClick);\n Event.addListener(this, \"mousedown\", this.onMouseDown);\n }\n\n /**\n * Applies a {@link CollapseButtonOptions} bag, dispatching the chevron\n * direction after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: CollapseButtonOptions): this {\n super.applyOptions(options);\n\n if (options.direction !== undefined) {\n this.setDirection(options.direction);\n }\n\n return this;\n }\n\n /**\n * Renders the root span, writes the chevron glyph, and applies the cached\n * rotation for the current direction at first paint.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n DOM.sink.apply(element, { text: \"▶\" });\n\n return element;\n }\n\n /**\n * Writes the per-instance `transform` (centring plus the rotation for the\n * current direction) onto a `createStyleRule` rule, overriding the shared\n * class rule's centring-only transform. Routed through `createStyleRule`\n * rather than `setTransform` because that builder's rules are replayed by\n * `applyStyle` at render time, whereas a main-rule write made before render\n * is dropped when the rule is rebuilt.\n */\n private applyRotation(): void {\n const degrees = _rotationByDirection[this._direction];\n\n this.createStyleRule(\"\").set(\"transform\", `translate(-50%, -50%) rotate(${degrees}deg)`);\n }\n\n /**\n * Toggles the handle between its expanded-grip and collapsed-strip widths.\n * Collapsed, it widens to the collapse-strip size so the restore handle\n * fills the entire width of the gutter's strip; expanded, it returns to the\n * narrow grip. The width rides the per-instance rule\n * (replayed by `applyStyle`) so it survives a render. The rotation maps this\n * `width` to the across-gutter axis for every chevron direction.\n *\n * @param filled - True for the collapsed strip-filling width, false for the grip.\n * @returns This component, for method chaining.\n */\n setStripMode(filled: boolean): this {\n this.createStyleRule(\"\").set(\"width\", `${filled ? COLLAPSE_STRIP_SIZE : GRIP_ACROSS}px`);\n\n return this;\n }\n\n /**\n * Returns the cached chevron direction.\n *\n * @returns The direction the chevron currently points.\n */\n getDirection(): CollapseDirection {\n return this._direction;\n }\n\n /**\n * Sets the chevron direction, rotating the glyph to match.\n *\n * @param direction - The direction the chevron should point.\n * @returns This component, for method chaining.\n */\n setDirection(direction: CollapseDirection): this {\n this._direction = direction;\n\n this.applyRotation();\n\n return this;\n }\n\n /**\n * Registers a listener for this button's `collapse` event, fired on a\n * double-click.\n *\n * @param event - Always `\"collapse\"`.\n * @param listener - The callback to invoke on double-click.\n * @returns This component, for method chaining.\n */\n on(event: \"collapse\", listener: () => void): this;\n on(event: CollapseButtonEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n * @returns This component, for method chaining.\n */\n off(event: CollapseButtonEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event`, in registration order.\n *\n * @param event - The event to emit.\n */\n protected emit(event: CollapseButtonEvent): void {\n this._listeners.fire(event);\n }\n\n /**\n * Emits `collapse` on a double-click.\n *\n * @param _evnt - The dblclick event; propagation is stopped so the host\n * never also reacts.\n * @returns `true`, consuming the double-click so it does not also reach the header behind the button.\n */\n private onDoubleClick(_evnt: MouseEvent): Event.ListenerResult {\n this.emit(\"collapse\");\n\n return true;\n }\n\n /**\n * Stops a `mousedown` on the button from reaching the host gutter, so\n * grabbing the chevron never begins a resize drag.\n *\n * @param _evnt - The mousedown event to suppress.\n * @returns `true`, consuming the press so it does not start a drag on the header behind the button.\n */\n private onMouseDown(_evnt: MouseEvent): Event.ListenerResult {\n return true;\n }\n\n}\n\nconst CollapseButtonCallable = callable(CollapseButton);\ntype CollapseButtonCallable = CollapseButton;\nexport {\n CollapseButton as _CollapseButton,\n CollapseButtonCallable as CollapseButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { CollapseButton, CollapseDirection } from \"~/component/container/CollapseButton.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { beginPointerDrag, endPointerDrag } from \"~/core/PointerDrag.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { Tooltip } from \"~/overlay/Tooltip.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * String-literal union of the events emitted by {@link SplitGutter}.\n *\n * @category Components\n */\nexport type SplitGutterEvent = \"dragstart\" | \"drag\" | \"dragend\" | \"collapse\";\n\n/**\n * Maps each chevron direction to its opposite, used to flip the single\n * collapse chevron between its collapse heading (toward the pane/region's\n * outer edge) and its restore heading (back toward the centre) when the gutter\n * toggles between divider and strip state.\n */\nconst OPPOSITE_DIRECTION: Record<CollapseDirection, CollapseDirection> = {\n west: \"east\",\n east: \"west\",\n north: \"south\",\n south: \"north\",\n};\n\n/**\n * Construction-time options for {@link SplitGutter}.\n *\n * @category Components\n */\nexport interface SplitGutterOptions extends ComponentOptions {\n orientation?: string;\n /** Whether the gutter carries a collapse chevron. Defaults to `true`. */\n collapsible?: boolean;\n /**\n * Whether the gutter wires drag-to-resize listeners. `Split` leaves this\n * `true`; `Border` passes `false` for a fixed, non-draggable gutter.\n * Defaults to `true`. Read once at construction.\n */\n movable?: boolean;\n /**\n * Whether the gutter paints the opaque collapse-strip fill (collapsed\n * state) or its expanded background (divider state). Defaults to `false`.\n */\n opaque?: boolean;\n /**\n * The chevron's collapse heading — the way it points (and the way the\n * gutter travels) when collapsing. The restore heading is its opposite.\n * Defaults to `west` for a horizontal gutter, `north` for a vertical one.\n */\n collapseDirection?: CollapseDirection;\n /**\n * The background painted in the expanded (divider) state, restored when\n * {@link SplitGutter.setOpaque} is cleared. Defaults to the gutter token;\n * `Border` passes `\"transparent\"` for its minimal-until-collapsed look.\n */\n expandedBackground?: string;\n /**\n * Multi-event listener bag dispatched to {@link SplitGutter.on} at\n * construction time.\n */\n listeners?: {\n dragstart?: (position: number) => void;\n drag?: (position: number) => void;\n dragend?: () => void;\n collapse?: () => void;\n };\n}\n\n/**\n * Class-level defaults. `orientation` rides the cascade so the `declare`-d\n * `_direction` backing field is seeded by `setDirection` during super(),\n * dodging the class-field super-cascade trap; `collapsible` and `movable`\n * likewise seed their backing fields through their setters.\n */\nconst _defaultSplitGutterOptions: Partial<SplitGutterOptions> = {\n orientation: \"horizontal\",\n collapsible: true,\n movable: true,\n};\n\n/**\n * A gutter component shared by [`Split`](/api/layout/classes/Split) and the\n * [`Border`](/api/layout/classes/Border) layout that doubles as both a divider\n * and a collapsed strip.\n *\n * In the **divider** state it is the thin bar between two panes (draggable when\n * `movable`) or a transparent track at a region's inner edge, carrying a single\n * collapse chevron. In the **strip** state (`opaque`) it is the opaque\n * collapse-strip the pane/region tucks into, the same chevron now pointing the\n * restore way. The owning manager animates the gutter between the two by\n * writing its geometry; the gutter is the only thing that moves.\n *\n * When `movable`, it listens for mouse/touch drag events on the viewport and\n * notifies registered drag listeners with the absolute pointer coordinate\n * (`clientX`/`clientY`) in the gutter's drag axis on each move, disabling body\n * pointer events during a drag to prevent text selection.\n *\n * @category Components\n */\nclass SplitGutter extends Component<SplitGutterOptions> {\n\n declare private _direction: String;\n declare private _collapsible: boolean;\n declare private _movable: boolean;\n declare private _collapseButton: CollapseButton;\n private _opaque: boolean = false;\n private _collapseDirection: CollapseDirection = \"west\";\n private _expandedBackground: string = \"var(--ts-ui-gutter-bg, #AAAAAA)\";\n private _tooltipText: string = \"\";\n private _listeners: ListenerBag<SplitGutterEvent> = new ListenerBag<SplitGutterEvent>();\n\n /**\n * @param direction - Split orientation this gutter drags along.\n * @param options - Optional construction options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(\n direction: String,\n options?: SplitGutterOptions,\n subclassDefaults?: Partial<SplitGutterOptions>,\n ) {\n super(options, { ..._defaultSplitGutterOptions, ...(subclassDefaults ?? {}) });\n\n // Pre-migration the trailing applyOptions(options) ran *after* the\n // body's positional assignment, so a caller-supplied `orientation`\n // option won. Apply the positional only when the caller did not\n // supply orientation, preserving the option-wins-over-positional\n // contract.\n if (direction && options?.orientation === undefined) {\n this._direction = direction;\n }\n\n // The expanded fill is the gutter token by default; Border passes a\n // transparent value so its divider state shows only the chevron.\n this._expandedBackground = options?.expandedBackground ?? \"var(--ts-ui-gutter-bg, #AAAAAA)\";\n this.setBackgroundColor(this._expandedBackground);\n\n // The chevron's collapse heading points the way the gutter travels on\n // collapse — toward the pane/region's outer edge. Defaults from the\n // axis (Split's leading pane is west/north); Border overrides per\n // placement. The restore heading is its opposite, applied by setOpaque.\n this._collapseDirection = options?.collapseDirection ?? (this._direction === \"horizontal\" ? \"west\" : \"north\");\n\n this._collapseButton = new CollapseButton({\n direction: this._collapseDirection,\n listeners: { collapse: () => this.emit(\"collapse\") },\n });\n\n this._collapseButton.setVisible(this._collapsible);\n\n if (options?.opaque) {\n this.setOpaque(true);\n }\n\n // A fixed gutter (Border) never resizes, so its body should not swallow\n // pointer events — the transparent track must let clicks reach the\n // region behind it, and the opaque strip has nothing behind to click.\n // The chevron child keeps its own `pointer-events: auto`, so it stays\n // clickable regardless.\n if (!this._movable) {\n this.setPointerEvents(\"none\");\n }\n\n // Drag wiring lives here, gated on `movable`, NOT in `applyOptions`:\n // Component's constructor runs applyOptions from inside super(), and\n // the listener machinery (`_listeners`) is only live after super().\n // Border's fixed gutters pass `movable: false` and skip the wiring.\n if (this._movable) {\n Event.addListener(this, 'mousedown', this.onDragStart);\n }\n\n this.applyListeners(options?.listeners);\n\n // Seed the expanded-state hover hint (setOpaque already refreshes it\n // when an opaque gutter is constructed).\n this.updateTooltip();\n }\n\n /**\n * Appends the collapse button's element to the gutter element once the DOM\n * node exists.\n *\n * @param element - Optional element passed from the framework init chain.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n\n if (!el) {\n return this;\n }\n\n DOM.sink.appendChild(el, this._collapseButton.getElement(true)!);\n\n return this;\n }\n\n /**\n * Returns whether the gutter carries a collapse chevron.\n *\n * @returns True when the collapse button is shown.\n */\n isCollapsible(): boolean {\n return this._collapsible ?? this._defaultOptions.collapsible!;\n }\n\n /**\n * Shows or hides the gutter's collapse chevron.\n *\n * @param value - True to show the collapse button, false to hide it.\n * @returns This gutter, for method chaining.\n */\n setCollapsible(value: boolean): this {\n this._collapsible = value;\n\n this._collapseButton?.setVisible(value);\n\n // Keep the hover hint in step with collapsibility: a non-collapsible\n // gutter (a plain draggable divider whose neighbour opted out of\n // collapse) must not advertise a double-click-to-collapse action.\n // Guarded on `_collapseButton` so the construction-time cascade — which\n // runs this setter from `super()` before the button and the\n // `_tooltipText` field exist — defers to the constructor's own\n // `updateTooltip` call.\n if (this._collapseButton) {\n this.updateTooltip();\n }\n\n return this;\n }\n\n /**\n * Applies a {@link SplitGutterOptions} bag, dispatching the gutter\n * orientation after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: SplitGutterOptions): this {\n super.applyOptions(options);\n\n // All three carry a class default and seed construction-time backing\n // state, so dispatch the caller value or the class default.\n this.setDirection(options.orientation ?? this.getDirection());\n this.setCollapsible(options.collapsible ?? this.isCollapsible());\n this.setMovable(options.movable ?? this.isMovable());\n\n return this;\n }\n\n /**\n * Returns whether the gutter wires drag-to-resize.\n *\n * @returns True when the gutter is draggable.\n */\n isMovable(): boolean {\n return this._movable ?? this._defaultOptions.movable!;\n }\n\n /**\n * Records whether the gutter is draggable. The actual `mousedown` drag\n * wiring is established once in the constructor from this flag (a fixed\n * Border gutter never wires it); this setter seeds the cached value during\n * the options cascade.\n *\n * @param value - True for a draggable gutter, false for a fixed one.\n * @returns This gutter, for method chaining.\n */\n setMovable(value: boolean): this {\n this._movable = value;\n\n return this;\n }\n\n /**\n * Returns whether the gutter is painting the opaque collapse-strip fill.\n *\n * @returns True in the collapsed strip state.\n */\n isOpaque(): boolean {\n return this._opaque;\n }\n\n /**\n * Toggles the gutter between its divider and collapsed-strip appearance.\n * `true` paints the opaque collapse-strip fill and flips the chevron to the\n * restore heading; `false` restores the expanded background and the\n * collapse heading.\n *\n * @param value - True for the collapsed strip state, false for the divider state.\n * @returns This gutter, for method chaining.\n */\n setOpaque(value: boolean): this {\n this._opaque = value;\n\n if (value) {\n // Collapsed: the strip reads as a themed button surface (the same\n // fill and border the framework's buttons use), inviting a click to\n // restore. `--ts-ui-button-bg` is a solid colour in some themes and\n // a gradient in others, so set both background properties to it —\n // the browser ignores whichever is type-invalid for the given theme.\n this.setBackgroundColor(\"var(--ts-ui-button-bg, #e8e8e8)\");\n this.setBackgroundImage(\"var(--ts-ui-button-bg, linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200)))\");\n this.setBorder(\"1px solid var(--ts-ui-button-border, #c8c8c8)\");\n this._collapseButton?.setDirection(OPPOSITE_DIRECTION[this._collapseDirection]);\n } else {\n this.clearBackgroundImage();\n this.clearBorder();\n this.setBackgroundColor(this._expandedBackground);\n this._collapseButton?.setDirection(this._collapseDirection);\n }\n\n // Collapsed, the restore handle fills the strip's full width; expanded,\n // it shrinks back to the narrow grip.\n this._collapseButton?.setStripMode(value);\n\n // The collapsed strip cannot be dragged (see `onDragStart`), so it must\n // not advertise a resize cursor either.\n this.applyCursor();\n\n // The hover hint flips between \"collapse\" and \"expand\".\n this.updateTooltip();\n\n return this;\n }\n\n /**\n * Returns the chevron's collapse heading.\n *\n * @returns The direction the chevron points (and the gutter travels) on collapse.\n */\n getCollapseDirection(): CollapseDirection {\n return this._collapseDirection;\n }\n\n /**\n * Sets the chevron's collapse heading — the way it points in the divider\n * state and the way the gutter travels on collapse. The restore heading is\n * its opposite. Re-applies the chevron for the current opaque state.\n *\n * @param direction - The collapse heading.\n * @returns This gutter, for method chaining.\n */\n setCollapseDirection(direction: CollapseDirection): this {\n this._collapseDirection = direction;\n\n this._collapseButton?.setDirection(this._opaque ? OPPOSITE_DIRECTION[direction] : direction);\n this.updateTooltip();\n\n return this;\n }\n\n /**\n * Refreshes the hover tooltip on the gutter and its chevron to describe the\n * double-click action for the current state: which way the gutter will\n * collapse when expanded, or that it will expand back when collapsed. Both\n * the gutter body (hovered on a draggable `Split` divider) and the chevron\n * handle (the always-visible grip) carry it. No-op when the text is\n * unchanged so repeated layouts don't re-wire the hover listeners.\n */\n private updateTooltip(): void {\n // A non-collapsible gutter carries no chevron and cannot collapse, so it\n // gets no hint at all — dropping any hint a prior collapsible state left\n // attached. `_tooltipText === \"\"` marks the already-detached state, so a\n // repeated layout doesn't re-detach (and re-`hide`) every pass.\n if (!this._collapsible) {\n if (this._tooltipText !== \"\") {\n Tooltip.detach(this);\n\n if (this._collapseButton) {\n Tooltip.detach(this._collapseButton);\n }\n\n this._tooltipText = \"\";\n }\n\n return;\n }\n\n const action = this._opaque ? \"expand\" : \"collapse\";\n const direction = this._opaque ? OPPOSITE_DIRECTION[this._collapseDirection] : this._collapseDirection;\n const text = `Double-click to ${action} ${direction}ward`;\n\n if (text === this._tooltipText) {\n return;\n }\n\n this._tooltipText = text;\n\n Tooltip.attach(this, text);\n\n if (this._collapseButton) {\n Tooltip.attach(this._collapseButton, text);\n }\n }\n\n /**\n * Returns the gutter's split direction: 'horizontal' or 'vertical'.\n *\n * @returns The current direction string.\n */\n getDirection() {\n return this._direction ?? this._defaultOptions.orientation!;\n }\n\n /**\n * Sets the split direction, defaulting to 'horizontal' if not provided.\n *\n * @param direction - Optional. \"horizontal\" or \"vertical\". Defaults to \"horizontal\".\n */\n setDirection(direction?: String) : this {\n if (!direction) {\n direction = \"horizontal\";\n }\n\n this._direction = direction;\n\n return this;\n }\n\n /**\n * Registers a listener for one of this gutter's events.\n *\n * @param event - `\"dragstart\"` fires on mousedown, receiving the absolute\n * pointer coordinate (`clientX`/`clientY`) in the gutter's drag axis at\n * the moment the drag begins; `\"drag\"` fires on each mousemove/touchmove\n * during a drag, receiving the absolute pointer coordinate in that axis;\n * `\"dragend\"` fires once the drag ends (mouseup, touchend, or\n * touchcancel); `\"collapse\"` fires when the gutter's chevron is\n * double-clicked.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This gutter, for method chaining.\n */\n on(event: \"dragstart\", listener: (position: number) => void): this;\n on(event: \"drag\", listener: (position: number) => void): this;\n on(event: \"dragend\", listener: () => void): this;\n on(event: \"collapse\", listener: () => void): this;\n on(event: SplitGutterEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This gutter, for method chaining.\n */\n off(event: SplitGutterEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"dragstart\", position: number): void;\n protected emit(event: \"drag\", position: number): void;\n protected emit(event: \"dragend\"): void;\n protected emit(event: \"collapse\"): void;\n protected emit(event: SplitGutterEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Disposes the collapse button, then runs the inherited teardown. The\n * explicit `_collapseButton` disposal is required, not redundant: the\n * button is raw-appended to this gutter's element rather than registered\n * as a child, so `super.destructor()`'s child recursion cannot reach it.\n */\n protected destructor(): void {\n this._collapseButton?.dispose();\n\n super.destructor();\n }\n\n /**\n * Internal mousemove/touchmove dispatch — fires the `drag` event with the\n * absolute pointer coordinate in the gutter's drag axis.\n *\n * @param position - The absolute pointer coordinate (`clientX`/`clientY`)\n * in the relevant axis for this drag event.\n */\n private _dispatchDrag(position: number): void {\n this.emit(\"drag\", position);\n }\n\n /**\n * Attaches viewport mouse/touch move and stop listeners, disables body\n * pointer events, and fires the `dragstart` event with the absolute pointer\n * coordinate so the consumer can capture its drag origin.\n *\n * @param evnt - The mousedown event; its `clientX`/`clientY` seeds the\n * drag origin in the gutter's axis.\n */\n onDragStart(evnt: MouseEvent) {\n // A gutter in its collapsed strip state is not a resize handle — the\n // pane behind it is hidden, so a drag would corrupt its stored size.\n if (this._opaque) {\n return;\n }\n\n const position = this._direction === \"horizontal\" ? evnt.clientX : evnt.clientY;\n\n this.emit(\"dragstart\", position);\n\n Event.addViewportListener(this, 'mouseup', this.onDragStop);\n Event.addViewportListener(this, 'touchend', this.onDragStop);\n Event.addViewportListener(this, 'touchcancel', this.onDragStop);\n Event.addViewportListener(this, 'mousemove', this.onDrag);\n Event.addViewportListener(this, 'touchmove', this.onDrag);\n\n beginPointerDrag(this.dragCursor());\n }\n\n /**\n * Removes viewport listeners and restores body pointer events and the\n * document element's cursor when drag ends, then fires `dragend`. Also\n * callable directly (with no argument) so tests can simulate a drag end.\n *\n * @returns `true`, consuming the release that ends the gutter drag.\n */\n onDragStop(): Event.ListenerResult {\n Event.removeViewportListener(this, 'mouseup', this.onDragStop);\n Event.removeViewportListener(this, 'touchend', this.onDragStop);\n Event.removeViewportListener(this, 'touchcancel', this.onDragStop);\n Event.removeViewportListener(this, 'mousemove', this.onDrag);\n Event.removeViewportListener(this, 'touchmove', this.onDrag);\n\n endPointerDrag();\n\n this.emit(\"dragend\");\n\n return true;\n }\n\n /**\n * Extracts the absolute pointer coordinate from the mouse event and fires\n * all drag listeners.\n *\n * @param evnt - The MouseEvent from which clientX or clientY is read.\n * @returns `true`, consuming the move so nothing else tracks the pointer mid-drag.\n */\n onDrag(evnt: MouseEvent): Event.ListenerResult {\n let position;\n if (this._direction === \"horizontal\") {\n position = evnt.clientX;\n } else {\n position = evnt.clientY;\n }\n\n this._dispatchDrag(position);\n\n return true;\n }\n\n /**\n * The resize cursor for this gutter's drag axis, shared by the hover state\n * and the drag itself so the two can never disagree.\n *\n * @returns The CSS cursor naming the axis the gutter resizes along.\n */\n private dragCursor(): string {\n return this._direction == \"horizontal\" ? \"ew-resize\" : \"ns-resize\";\n }\n\n /**\n * Applies the hover cursor for the gutter's current state. Only a movable\n * gutter in its divider state shows the axis resize cursor; a fixed Border\n * gutter, or a gutter in its collapsed strip state (which cannot be\n * dragged), shows the default cursor so it doesn't invite a resize.\n */\n private applyCursor(): void {\n if (this._movable && !this._opaque) {\n this.setCursor(this.dragCursor());\n } else {\n this.setCursor(\"default\");\n }\n }\n\n /**\n * Renders the gutter element and sets the appropriate resize cursor.\n *\n * @returns The created element with the correct resize cursor applied.\n */\n render() {\n let element = super.render();\n\n this.applyCursor();\n\n return element;\n }\n}\n\nconst SplitGutterCallable = callable(SplitGutter);\ntype SplitGutterCallable = SplitGutter;\nexport {\n SplitGutter as _SplitGutter,\n SplitGutterCallable as SplitGutter\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\"\nimport { Component } from \"~/core/Component.js\"\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { SplitGutter } from \"~/component/container/SplitGutter.js\";\nimport { CollapseDirection } from \"~/component/container/CollapseButton.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport { Size, UNBOUNDED, saturate } from \"~/primitive/Size.js\";\nimport { COLLAPSE_STRIP_SIZE, runCollapse, CollapseParticipant, CollapseTransition } from \"~/layout/CollapseSupport.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n// Pixel thickness of a region's transparent collapse track in its expanded\n// state — just enough to carry the (overflowing) chevron at the region's inner\n// edge. Mirrors `Split`'s GUTTER_SIZE so the two managers' divider tracks match.\nconst TRACK_SIZE = 4;\n\n// The way each region's chevron points (and the gutter travels) when collapsing\n// — toward the region's outer edge. The restore heading is its opposite,\n// handled by the gutter's `setOpaque`.\nconst COLLAPSE_CHEVRON: Record<string, CollapseDirection> = {\n [Placement.NORTH]: \"north\",\n [Placement.SOUTH]: \"south\",\n [Placement.WEST]: \"west\",\n [Placement.EAST]: \"east\",\n};\n\n/**\n * Construction-time options for the {@link Border} layout manager.\n *\n * @remarks Re-exported as `BorderLayoutOptions` from the package barrel to\n * disambiguate from the line-style `Border`'s {@link BorderOptions}.\n *\n * @category Layouts\n */\nexport interface BorderOptions extends LayoutManagerOptions {\n spacing?: number;\n}\n\n/**\n * A layout manager that divides a container into five named regions:\n * north, south, east, west, and center.\n * North and south regions span the full width; east and west regions flank the center.\n *\n * Exported from `@jimka/typescript-ui/layout`. Disambiguate from the line-style\n * [`Border`](/api/primitive/classes/Border) utility (in `@jimka/typescript-ui/primitive`)\n * by aliasing one of them on import — e.g. `import { Border as BorderLayout } from '@jimka/typescript-ui/layout';`.\n *\n * @category Layouts\n */\nclass Border extends LayoutManager {\n\n private _northComponent: Component | null = null;\n private _southComponent: Component | null = null;\n private _westComponent: Component | null = null;\n private _eastComponent: Component | null = null;\n private _centerComponent: Component | null = null;\n private _spacing: number = 5;\n\n // Per-region collapse state, keyed by placement. `_collapsed` and\n // `_collapsible` both default to false: collapsing is opt-in per region\n // (`collapsible: true` on the constraint), so a plain Border — including\n // the ones Header, Dialog, and the table panels use internally — never\n // sprouts collapse affordances. `_gutters` holds one lazily-created fixed\n // gutter per collapsible edge region — a transparent track carrying the\n // chevron when expanded, the opaque strip when collapsed. The child\n // component stays unaware it is collapsible — this is layout geometry, so\n // it lives here.\n private _collapsed: Map<Placement, boolean> = new Map<Placement, boolean>();\n private _collapsible: Map<Placement, boolean> = new Map<Placement, boolean>();\n private _gutters: Map<Placement, SplitGutter> = new Map<Placement, SplitGutter>();\n\n // Canceller for the in-flight region collapse/restore animation, or null\n // when idle. Calling it stops the rAF loop in place so a rapid re-toggle\n // re-snapshots and retargets without two loops fighting.\n private _collapseAnimation: (() => void) | null = null;\n\n // Collapse/restore CSS transitions primed by `runCollapse` that have not\n // settled yet. Cancelled on detach so their fallback timers cannot fire\n // against released element handles. Held separately from\n // `_collapseAnimation` because that field is nulled when the geometry\n // animation settles — ~40ms before these fallbacks disarm — and is replaced\n // outright by a re-toggle while these may still be running.\n private readonly _pendingCollapseTransitions: CollapseTransition[] = [];\n\n // True while a collapse/restore animation is being driven. The animation\n // slides every region by writing each element's own `left`/`top` (via\n // `CollapseSupport.commitRect`'s `setX`/`setY`), which a clip frame defeats\n // because the frame — not the element — carries a framed region's position\n // and the element sits parked at `(0, 0)` inside it. While this is set,\n // `doLayout` lays every region out unframed (plain `placeComponent`) so the\n // animation can move them; the steady-state frames are reinstated by the\n // final `doLayout` once the animation settles.\n private _collapsing: boolean = false;\n\n constructor(options?: BorderOptions) {\n // LayoutManager's constructor takes no options; applied via applyOptions below.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link BorderOptions} bag, dispatching the inter-region spacing\n * after the inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: BorderOptions): void {\n super.applyOptions(options);\n\n if (options.spacing !== undefined) {\n this.setComponentSpacing(options.spacing);\n }\n }\n\n /**\n * Registers a component in the north, south, east, west, or center slot\n * based on `constraints.placement`.\n *\n * @param component - The component to register.\n * @param constraints - Optional. Layout constraints specifying the target placement slot.\n *\n * @returns The resolved constraints object, or `undefined` if none were provided.\n *\n * @remarks When `constraints` or `constraints.placement` is absent the component\n * defaults to the center slot.\n */\n setLayoutConstraints(component: Component, constraints?: LayoutConstraints): LayoutConstraints | undefined {\n if (!constraints) {\n constraints = new LayoutConstraints();\n constraints.placement = Placement.CENTER;\n }\n\n if (!constraints.placement) {\n constraints.placement = Placement.CENTER;\n }\n\n switch (constraints.placement) {\n case Placement.NORTH:\n this._northComponent = component;\n break;\n case Placement.SOUTH:\n this._southComponent = component;\n break;\n case Placement.WEST:\n this._westComponent = component;\n break;\n case Placement.EAST:\n this._eastComponent = component;\n break;\n case Placement.CENTER:\n this._centerComponent = component;\n break;\n }\n\n // The center is never collapsible; every edge region defaults to\n // non-collapsible and opts in via `collapsible: true`.\n if (constraints.placement === Placement.CENTER) {\n this._collapsible.set(Placement.CENTER, false);\n } else {\n this._collapsible.set(constraints.placement, constraints.collapsible ?? false);\n }\n\n return super.setLayoutConstraints(component, constraints);\n }\n\n /**\n * Clears the region slot a component occupied when it is removed from the\n * container. Without this the region reference goes stale: a component moved\n * out of a `Border` container (e.g. a window's content panel re-homed\n * elsewhere) would still be held as that region's child and re-sized by this\n * manager on its next `doLayout`, fighting its new parent's layout.\n *\n * @param component - The component being removed.\n * @returns The removed constraints, or `undefined` if none were stored.\n */\n delLayoutConstraints(component: Component): LayoutConstraints | undefined {\n if (this._northComponent === component) {\n this._northComponent = null;\n } else if (this._southComponent === component) {\n this._southComponent = null;\n } else if (this._westComponent === component) {\n this._westComponent = null;\n } else if (this._eastComponent === component) {\n this._eastComponent = null;\n } else if (this._centerComponent === component) {\n this._centerComponent = null;\n }\n\n return super.delLayoutConstraints(component);\n }\n\n /**\n * Returns the pixel spacing between adjacent border regions.\n *\n * @returns The current spacing in pixels.\n */\n getComponentSpacing() {\n return this._spacing;\n }\n\n /**\n * Sets the pixel spacing between adjacent border regions.\n *\n * @param spacing - Spacing size in pixels.\n */\n setComponentSpacing(spacing: number) : this {\n this._spacing = spacing;\n\n return this;\n }\n\n /**\n * Returns the component currently registered in the given region slot.\n *\n * @param placement - The region to look up.\n * @returns The region's component, or `null` if the slot is empty.\n */\n private getRegionComponent(placement: Placement): Component | null {\n switch (placement) {\n case Placement.NORTH: return this._northComponent;\n case Placement.SOUTH: return this._southComponent;\n case Placement.WEST: return this._westComponent;\n case Placement.EAST: return this._eastComponent;\n case Placement.CENTER: return this._centerComponent;\n }\n }\n\n /**\n * Returns whether the given region is collapsed.\n *\n * @param placement - The region to query.\n * @returns True when the region is collapsed.\n */\n isRegionCollapsed(placement: Placement): boolean {\n return this._collapsed.get(placement) ?? false;\n }\n\n /**\n * Collapses or restores an edge region, animating the change. The region's\n * gutter slides from its inner edge to its outer edge and widens into the\n * opaque collapse strip (cross-fading its fill) while the region keeps its\n * full size and reveals via a clip-path; the center grows into the reclaimed\n * space. The whole pass is one coordinated animation: the toggled region\n * clip-reveals while the center and the gutter interpolate their geometry —\n * re-laying out their contents each frame — in lockstep (see\n * `CollapseSupport.runCollapse`). The center cannot be collapsed and a\n * non-collapsible region ignores a collapse request.\n *\n * @param placement - The region to collapse or restore.\n * @param collapsed - True to collapse, false to restore.\n * @returns This layout manager, for method chaining.\n */\n setRegionCollapsed(placement: Placement, collapsed: boolean): this {\n if (placement === Placement.CENTER || !this.isRegionCollapsible(placement)) {\n return this;\n }\n\n const component = this.getRegionComponent(placement);\n if (!component) {\n return this;\n }\n\n const current = this._collapsed.get(placement) ?? false;\n if (current === collapsed) {\n return this;\n }\n\n const container = this.getContainer();\n if (!container) {\n return this;\n }\n\n // Enter the animated phase before laying out the start state. When no\n // animation is already running the regions are clip-framed, parked at\n // `(0, 0)` inside frames that carry their real position; this `doLayout`\n // (now that `_collapsing` is set) re-lays them out unframed at their\n // current pre-toggle position, so each element's own `left`/`top` holds\n // the real start that `runCollapse` snapshots — a framed element would\n // otherwise snapshot `(0, 0)` and never move. A re-toggle mid-animation\n // is already unframed (its elements hold live interpolated positions),\n // so it skips this and lets `runCollapse` re-snapshot the live geometry\n // for a smooth retarget.\n const wasAnimating = this._collapsing;\n this._collapsing = true;\n\n if (!wasAnimating) {\n container.doLayout();\n }\n\n this._collapsed.set(placement, collapsed);\n\n // Materialise the region's gutter so it joins the participant list.\n this.ensureGutter(placement);\n\n // Every box that moves: the regions (content re-laid-out each frame) and\n // the gutters (geometry only). The toggled region is among them and also\n // clip-reveals; `runCollapse` coordinates the whole pass.\n const regions = [this._northComponent, this._southComponent, this._westComponent, this._eastComponent, this._centerComponent]\n .filter((c): c is Component => c != null);\n\n const participants: CollapseParticipant[] = [\n ...regions.map(region => ({ component: region, relayout: true })),\n ...[...this._gutters.values()].map(gutter => ({ component: gutter, relayout: false })),\n ];\n\n this._collapseAnimation = runCollapse(container, component, participants, this._collapseAnimation, this._pendingCollapseTransitions, () => {\n this._collapseAnimation = null;\n\n // Leave the animated phase and re-lay-out so the non-collapsible\n // regions get their steady-state clip frames back.\n this._collapsing = false;\n\n container.doLayout();\n });\n\n return this;\n }\n\n /**\n * Returns whether the given region may be collapsed. The center is never\n * collapsible; edge regions are non-collapsible unless they opt in with\n * `collapsible: true` on their constraint.\n *\n * @param placement - The region to query.\n * @returns True when the region may be collapsed.\n */\n isRegionCollapsible(placement: Placement): boolean {\n if (placement === Placement.CENTER) {\n return false;\n }\n\n return this._collapsible.get(placement) ?? false;\n }\n\n /**\n * Sets whether an edge region may be collapsed. Hides the collapse chevron\n * when set false; the center is always non-collapsible regardless.\n *\n * @param placement - The region to configure.\n * @param value - True to allow collapsing, false to opt out.\n * @returns This layout manager, for method chaining.\n */\n setRegionCollapsible(placement: Placement, value: boolean): this {\n if (placement === Placement.CENTER) {\n return this;\n }\n\n this._collapsible.set(placement, value);\n\n this.getContainer()?.scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the existing fixed gutter for a region, creating and wiring it on\n * first use. The gutter is non-movable, transparent in its divider state,\n * and carries the chevron pointing toward the region's outer edge; its\n * double-click collapses the region.\n *\n * @param placement - The region the gutter collapses.\n * @returns The region's gutter.\n */\n private ensureGutter(placement: Placement): SplitGutter {\n let gutter = this._gutters.get(placement);\n if (gutter) {\n return gutter;\n }\n\n const container = this.getContainer()!;\n const vertical = placement === Placement.NORTH || placement === Placement.SOUTH;\n\n gutter = new SplitGutter(vertical ? \"vertical\" : \"horizontal\", {\n movable: false,\n opaque: false,\n collapseDirection: COLLAPSE_CHEVRON[placement],\n expandedBackground: \"transparent\",\n listeners: { collapse: () => this.setRegionCollapsed(placement, !this.isRegionCollapsed(placement)) },\n });\n\n gutter.setVisible(false);\n\n DOM.sink.appendChild(container.getElement()!, gutter.getElement(true)!);\n\n this._gutters.set(placement, gutter);\n\n return gutter;\n }\n\n /**\n * Returns a region's effective edge extent: the strip thickness when the\n * region is collapsed, otherwise the region's own preferred main-axis size.\n *\n * @param placement - The edge region.\n * @param preferred - The region's preferred main-axis extent (width for\n * west/east, height for north/south).\n * @returns The extent to reserve for the region in `doLayout`.\n */\n private regionExtent(placement: Placement, preferred: number): number {\n return this.isRegionCollapsed(placement) ? COLLAPSE_STRIP_SIZE : preferred;\n }\n\n /**\n * Floors a region's preferred main-axis extent at the region component's\n * own minimum main-axis extent, so a region whose consumer pinned a\n * sub-minimum `preferredSize` is still reserved — and clip-framed — at the\n * size the component clamps itself up to on commit. Mirrors\n * {@link VBox.preferredChildHeight} / {@link HBox.preferredChildWidth}.\n * Reading the region's `getMinSize()` here is a non-recursive sibling call,\n * not a re-entry into this manager's own size gathering.\n *\n * @param preferred - The region's preferred main-axis extent.\n * @param min - The region's min-size, or null.\n * @param vertical - True for NORTH/SOUTH (height axis), false for WEST/EAST (width axis).\n * @returns `max(preferred, region min on the main axis)`.\n */\n private flooredMainExtent(preferred: number, min: Size | null, vertical: boolean): number {\n const minMain = min ? (vertical ? min.height : min.width) : 0;\n\n return Math.max(preferred, minMain);\n }\n\n /**\n * Clips a region's element toward its outer edge for the current collapse\n * state. The component is always laid out at its full size; collapsing\n * progressively clips it away (animated via a `clip-path` transition) so the\n * region visibly retreats into the strip rather than vanishing instantly,\n * mirroring the expand. Expanded, the clip is cleared. `clip-path` also\n * suppresses pointer events on the clipped-away area, so the hidden region\n * doesn't intercept clicks meant for the grown centre.\n *\n * @param component - The region's component.\n * @param placement - The edge region, which fixes the clip direction.\n */\n private applyRegionClip(component: Component, placement: Placement): void {\n // Never clip a region that can't collapse: `clip-path` establishes a\n // stacking context and a containing block for fixed descendants, which\n // could disturb a plain region's popovers. Only collapsible regions —\n // which need `inset(0)` as the transition's expanded keyframe — get it.\n if (!this.isRegionCollapsible(placement)) {\n return;\n }\n\n if (!this.isRegionCollapsed(placement)) {\n component.setClipPath(\"inset(0 0 0 0)\");\n\n return;\n }\n\n switch (placement) {\n case Placement.WEST: component.setClipPath(\"inset(0 100% 0 0)\"); break;\n case Placement.EAST: component.setClipPath(\"inset(0 0 0 100%)\"); break;\n case Placement.NORTH: component.setClipPath(\"inset(0 0 100% 0)\"); break;\n case Placement.SOUTH: component.setClipPath(\"inset(100% 0 0 0)\"); break;\n }\n }\n\n /**\n * Positions a region's single gutter for the region's current state: a\n * transparent track at the inner edge (carrying the chevron) when expanded,\n * the opaque strip filling the region's strip-sized rect when collapsed. The\n * region component is hidden while collapsed. No gutter is shown for a\n * non-collapsible region.\n *\n * @param placement - The edge region.\n * @param x - The region's left position.\n * @param y - The region's top position.\n * @param width - The region's width (strip-sized when collapsed).\n * @param height - The region's height (strip-sized when collapsed for north/south).\n */\n private updateRegionGutter(placement: Placement, x: number, y: number, width: number, height: number): void {\n const component = this.getRegionComponent(placement);\n if (!component) {\n return;\n }\n\n if (!this.isRegionCollapsible(placement)) {\n component.setVisible(true);\n this._gutters.get(placement)?.setVisible(false);\n\n return;\n }\n\n const collapsed = this.isRegionCollapsed(placement);\n const gutter = this.ensureGutter(placement);\n\n // The region stays visible and laid out at full size; `applyRegionClip`\n // clips it away while collapsed (it can't shrink past its min-size), so\n // the gutter strip is what reads as the collapsed region.\n component.setVisible(true);\n\n gutter.setOpaque(collapsed);\n gutter.setVisible(true);\n\n // Collapsed: the gutter fills the region's strip-sized rect. Expanded:\n // a thin transparent track in the gap just past the region's\n // center-facing edge, where the chevron reads naturally.\n const rect = collapsed ? { x, y, width, height } : this.innerEdgeTrack(placement, x, y, width, height);\n\n gutter.setX(rect.x);\n gutter.setY(rect.y);\n gutter.setWidth(rect.width);\n gutter.setHeight(rect.height);\n }\n\n /**\n * Computes the thin transparent track rect in the gap just past a region's\n * center-facing edge, where the expanded gutter parks its chevron. The\n * track sits flush against the region's outer edge of the gap rather than\n * overlapping the region's own content.\n *\n * @param placement - The edge region.\n * @param x - The region's left position.\n * @param y - The region's top position.\n * @param width - The region's width.\n * @param height - The region's height.\n * @returns The track rect.\n */\n private innerEdgeTrack(placement: Placement, x: number, y: number, width: number, height: number): { x: number; y: number; width: number; height: number } {\n switch (placement) {\n case Placement.NORTH: return { x, y: y + height, width, height: TRACK_SIZE };\n case Placement.SOUTH: return { x, y: y - TRACK_SIZE, width, height: TRACK_SIZE };\n case Placement.WEST: return { x: x + width, y, width: TRACK_SIZE, height };\n case Placement.EAST: return { x: x - TRACK_SIZE, y, width: TRACK_SIZE, height };\n default: return { x, y, width, height };\n }\n }\n\n /**\n * Resolves a slot component for layout: a non-displayed region component is\n * treated as an empty slot (`null`), so a `display: none` region reserves no\n * space and is not placed — the same outcome as removing it from the region.\n * Every slot read in the size/layout methods routes through this so the\n * \"hidden = absent\" rule is uniform.\n *\n * @param component - The slot component, or `null` when the region is empty.\n * @returns The component when present and displayed, otherwise `null`.\n */\n private laidOut(component: Component | null): Component | null {\n return component && component.isDisplayed() ? component : null;\n }\n\n /**\n * Computes the preferred size by summing the preferred sizes of all occupied border regions.\n *\n * @returns The preferred `{width, height}` or `null` if no container is attached.\n */\n getPreferredSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let innerWidth = 0;\n let innerHeight = 0;\n\n let middleWidth = 0;\n let middleHeight = 0;\n\n // A non-displayed region is treated as absent, contributing nothing.\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n if (north) {\n let size = north.getPreferredSize();\n if (size) {\n const flooredHeight = this.flooredMainExtent(size.height, north.getMinSize(), true);\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : flooredHeight;\n }\n }\n\n if (south) {\n let size = south.getPreferredSize();\n if (size) {\n const flooredHeight = this.flooredMainExtent(size.height, south.getMinSize(), true);\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : flooredHeight;\n }\n }\n\n if (west) {\n let size = west.getPreferredSize();\n if (size) {\n const flooredWidth = this.flooredMainExtent(size.width, west.getMinSize(), false);\n middleWidth += this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : flooredWidth;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (center) {\n let size = center.getPreferredSize();\n if (size) {\n middleWidth += size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (east) {\n let size = east.getPreferredSize();\n if (size) {\n const flooredWidth = this.flooredMainExtent(size.width, east.getMinSize(), false);\n middleWidth += this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : flooredWidth;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n innerWidth = Math.max(innerWidth, middleWidth);\n innerHeight += middleHeight;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Computes the minimum size by summing the minimum sizes of all occupied border regions.\n *\n * @returns The minimum `{width, height}` or `null` if no container is attached.\n */\n getMinSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let innerWidth = 0;\n let innerHeight = 0;\n\n let middleWidth = 0;\n let middleHeight = 0;\n\n // A non-displayed region is treated as absent, contributing nothing.\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n if (north) {\n let size = north.getMinSize();\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : size.height;\n }\n }\n\n if (south) {\n let size = south.getMinSize();\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : size.height;\n }\n }\n\n if (west) {\n let size = west.getMinSize();\n if (size) {\n middleWidth += this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (center) {\n let size = center.getMinSize();\n if (size) {\n middleWidth += size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (east) {\n let size = east.getMinSize();\n if (size) {\n middleWidth += this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n innerWidth = Math.max(innerWidth, middleWidth);\n innerHeight += middleHeight;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Computes the maximum size the border layout can usefully occupy. The five\n * regions stack as three rows that share one width: north (full width), the\n * middle row of west + center + east (summed across, tallest of the three\n * down), and south (full width). The width is capped to the narrowest row\n * that exists — a region cannot usefully widen the border past where its own\n * row stops growing — and the height is the sum of the three row heights.\n * An absent region imposes no constraint; an unbounded region contributes\n * the unbounded sentinel.\n *\n * @returns The maximum `{width, height}` or `null` if no container is attached.\n */\n getMaxSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n // A non-displayed region resolves to null here (no constraint), not the\n // unbounded sentinel — it must not widen/heighten the layout at all.\n const maxOf = (component: Component | null): Size | null =>\n this.laidOut(component) ? (component!.getMaxSize() ?? { width: UNBOUNDED, height: UNBOUNDED }) : null;\n\n const north = maxOf(this._northComponent);\n const south = maxOf(this._southComponent);\n const west = maxOf(this._westComponent);\n const center = maxOf(this._centerComponent);\n const east = maxOf(this._eastComponent);\n\n // Middle row: west / center / east sit side by side — widths sum, the\n // row height is the tallest region.\n let middleWidth = 0;\n let middleHeight = 0;\n let hasMiddle = false;\n\n for (const region of [west, center, east]) {\n if (region) {\n hasMiddle = true;\n middleWidth += region.width;\n middleHeight = Math.max(middleHeight, region.height);\n }\n }\n\n // Width is shared by every row; cap to the narrowest existing row.\n let innerWidth = UNBOUNDED;\n if (north) { innerWidth = Math.min(innerWidth, north.width); }\n if (south) { innerWidth = Math.min(innerWidth, south.width); }\n if (hasMiddle) { innerWidth = Math.min(innerWidth, middleWidth); }\n\n // Height stacks the three rows.\n let innerHeight = 0;\n if (north) { innerHeight += north.height; }\n if (hasMiddle) { innerHeight += middleHeight; }\n if (south) { innerHeight += south.height; }\n\n return {\n width: saturate(innerWidth + outerWidth),\n height: saturate(innerHeight + outerHeight)\n };\n }\n\n /**\n * Computes the children's combined minSize along this manager's\n * 5-region geometry: width = west.minWidth + center.minWidth +\n * east.minWidth + gaps; height = north.minHeight + center.minHeight +\n * south.minHeight + gaps. Used by `doLayout` to inflate the working\n * size when the host has opted into `setOverflowing`.\n *\n * @returns The total min-size; `{ width: 0, height: 0 }` when the\n * container is absent.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n // A non-displayed region is treated as absent (laidOut → null), so it\n // contributes no min-size to the total.\n const westMin = this.laidOut(this._westComponent) ?.getMinSize();\n const centerMin = this.laidOut(this._centerComponent)?.getMinSize();\n const eastMin = this.laidOut(this._eastComponent) ?.getMinSize();\n const northMin = this.laidOut(this._northComponent) ?.getMinSize();\n const southMin = this.laidOut(this._southComponent) ?.getMinSize();\n\n // Horizontal regions contribute to width; vertical regions contribute\n // to height. Each inter-region gap is added only when both adjacent\n // regions exist so single-region layouts (only center, for instance)\n // don't gain phantom gap pixels. A collapsed edge region contributes\n // only the strip thickness along its collapse axis.\n const hContribs: number[] = [];\n if (westMin) { hContribs.push(this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : westMin.width); }\n if (centerMin) { hContribs.push(centerMin.width); }\n if (eastMin) { hContribs.push(this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : eastMin.width); }\n\n const vContribs: number[] = [];\n if (northMin) { vContribs.push(this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : northMin.height); }\n if (centerMin) { vContribs.push(centerMin.height); }\n if (southMin) { vContribs.push(this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : southMin.height); }\n\n let width = 0;\n let height = 0;\n\n for (const w of hContribs) {\n width += w;\n }\n width += Math.max(0, hContribs.length - 1) * this._spacing;\n\n // For width we also need to ensure the height-region's own width is\n // honoured: the center column may need at least the wider of\n // north.minWidth / south.minWidth (which span the full row).\n if (northMin) {\n width = Math.max(width, northMin.width);\n }\n if (southMin) {\n width = Math.max(width, southMin.width);\n }\n\n for (const h of vContribs) {\n height += h;\n }\n height += Math.max(0, vContribs.length - 1) * this._spacing;\n\n return { width, height };\n }\n\n /**\n * Clears the clip frame of every region that `doLayout` will skip because it\n * resolved to `null` (a non-displayed region), so a `display: none` region\n * does not leave its `overflow: hidden` wrapper orphaned around the hidden\n * element until the region is shown again.\n *\n * @param laidOutRegions - The `laidOut` results for north, south, west,\n * center, and east; a `null` entry marks a region `doLayout` will skip.\n */\n private clearSkippedRegionFrames(...laidOutRegions: (Component | null)[]): void {\n const rawRegions = [\n this._northComponent,\n this._southComponent,\n this._westComponent,\n this._centerComponent,\n this._eastComponent\n ];\n\n rawRegions.forEach((component, index) => {\n if (component && !laidOutRegions[index]) {\n component.clearClipFrame();\n }\n });\n }\n\n /**\n * Positions north, south, east, west, and center children within the container's inner bounds.\n *\n * @remarks The north component may opt out of parent insets via `constraints.ignoreParentInsets`,\n * which is useful for components such as toolbars that should span the full container width.\n */\n doLayout() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n // The container has no element yet (e.g. laid out before it is\n // rendered, as an autoScroll host's synchronous setOverflowing pass\n // can do to a not-yet-mounted child); defer to the next pass, which\n // every other layout manager (HBox, VBox, Grid, Split, Tab) already\n // does in this situation.\n let containerSize = container.getInnerSize();\n if (!containerSize) {\n return;\n }\n\n let containerInsets = container.getContentInsets();\n\n // Universal scroll: see HBox.doLayout for the rationale. Inflates the\n // working size to the children's combined minSize on the axes the\n // host has marked as overflowing.\n containerSize = this.inflateForOverflow(containerSize);\n\n // Resolve every region through laidOut so a non-displayed region is\n // treated as absent: skipped for placement and excluded from the\n // adjacent-region gap checks below — the same outcome as an empty slot.\n // This also keeps the preferred-size throws below unreachable for a\n // hidden region (its `if` block is skipped entirely).\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n // A non-displayed region is skipped by its `if (region)` block below, so\n // its clip frame is never re-driven or cleared there. Clear it now on the\n // raw component so a `display: none` region doesn't orphan its\n // `overflow: hidden` wrapper around the hidden element; clearClipFrame is\n // a no-op when no frame is active.\n this.clearSkippedRegionFrames(north, south, west, center, east);\n\n let width = containerSize.width;\n let height = containerSize.height;\n let centerX;\n let middleY;\n let centerWidth;\n let middleHeight;\n\n if (north) {\n let constraints = this.getLayoutConstraints(north);\n if (!constraints) {\n throw new Error(\"Unable to determine layout constraints for north component.\");\n }\n\n let preferredSize = north.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for north component.\");\n }\n\n const northExtent = this.flooredMainExtent(preferredSize.height, north.getMinSize(), true);\n let northHeight = this.regionExtent(Placement.NORTH, northExtent);\n let northX = constraints.ignoreParentInsets ? 0 : containerInsets.getLeft();\n let northY = constraints.ignoreParentInsets ? 0 : containerInsets.getTop();\n let northWidth = width + (constraints.ignoreParentInsets ? containerInsets.getLeft() + containerInsets.getRight() : 0);\n let northInsetTop = constraints.ignoreParentInsets ? containerInsets.getTop() : 0;\n\n middleY = northHeight + northInsetTop;\n\n // The region is always laid out at full size and clipped toward its\n // outer edge while collapsed; the centre and gutter use the strip\n // extent (`middleY`) so they grow into the reclaimed space. While a\n // collapse animates, every region takes the unframed path so its own\n // `left`/`top` can be interpolated (a frame would freeze it).\n if (this.isRegionCollapsible(Placement.NORTH) || this._collapsing) {\n this.placeComponent(\n north,\n northX,\n northY,\n northWidth,\n northExtent + northInsetTop,\n FillType.BOTH\n );\n north.clearClipFrame();\n this.applyRegionClip(north, Placement.NORTH);\n } else {\n // Containment via clip frame: an oversized or mis-sized region's\n // own box is clipped to its allocated rect rather than bleeding\n // over the adjacent region. Clear any stale clip-path left by a\n // prior collapsible state (setRegionCollapsible can flip a region\n // at runtime); this branch never calls applyRegionClip.\n north.setClipPath(null);\n north.setClipFrame(northX, northY, northWidth, northExtent + northInsetTop);\n this.commitBounds(north, 0, 0, northWidth, northExtent + northInsetTop);\n }\n\n this.updateRegionGutter(Placement.NORTH, northX, northY, northWidth, middleY);\n\n if (west || center || east || south) {\n middleY += this._spacing;\n }\n } else {\n middleY = 0;\n }\n\n middleHeight = height - middleY;\n if (south) {\n let preferredSize = south.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for south component.\");\n }\n\n const southExtent = this.flooredMainExtent(preferredSize.height, south.getMinSize(), true);\n let southHeight = this.regionExtent(Placement.SOUTH, southExtent);\n let southX = containerInsets.getLeft();\n let southY = containerInsets.getTop() + height - southHeight;\n\n middleHeight -= this._spacing;\n middleHeight -= southHeight;\n\n // Full-size and bottom-anchored, clipped toward the bottom while\n // collapsed; the gutter uses the strip rect (`southY`/`southHeight`).\n let southFullY = containerInsets.getTop() + height - southExtent;\n\n if (this.isRegionCollapsible(Placement.SOUTH) || this._collapsing) {\n this.placeComponent(\n south,\n southX,\n southFullY,\n width,\n southExtent,\n FillType.BOTH\n );\n south.clearClipFrame();\n this.applyRegionClip(south, Placement.SOUTH);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full position equals the strip position, so the\n // element commits at (0, 0) inside the frame.\n south.setClipPath(null);\n south.setClipFrame(southX, southFullY, width, southExtent);\n this.commitBounds(south, 0, 0, width, southExtent);\n }\n\n this.updateRegionGutter(Placement.SOUTH, southX, southY, width, southHeight);\n }\n\n // Reserve east's preferred width up front so west can be clamped\n // to avoid overlapping east when west.preferred + east.preferred\n // exceeds the container width (e.g. a Window header where the\n // title is wider than the available space between the icon and\n // the trailing buttons).\n let eastPreferredWidth = 0;\n let eastFullWidth = 0;\n if (east) {\n let eastPreferred = east.getPreferredSize();\n if (!eastPreferred) {\n throw new Error(\"Unable to determine preferred size for east component.\");\n }\n const eastExtent = this.flooredMainExtent(eastPreferred.width, east.getMinSize(), false);\n eastFullWidth = eastExtent;\n eastPreferredWidth = this.regionExtent(Placement.EAST, eastExtent);\n }\n\n if (west) {\n let preferredSize = west.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for west component.\");\n }\n\n const westExtent = this.flooredMainExtent(preferredSize.width, west.getMinSize(), false);\n let westWidth = Math.max(0, Math.min(this.regionExtent(Placement.WEST, westExtent), width - eastPreferredWidth));\n let westX = containerInsets.getLeft();\n let westY = containerInsets.getTop() + middleY;\n\n centerX = westWidth;\n\n // Full-size and left-anchored, clipped toward the left while\n // collapsed; the centre and gutter use the strip extent (`westWidth`).\n let westFullWidth = Math.max(0, Math.min(westExtent, width - eastPreferredWidth));\n\n if (this.isRegionCollapsible(Placement.WEST) || this._collapsing) {\n this.placeComponent(\n west,\n westX,\n westY,\n westFullWidth,\n middleHeight,\n FillType.BOTH\n );\n west.clearClipFrame();\n this.applyRegionClip(west, Placement.WEST);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full width equals the strip width, so the\n // element commits at (0, 0) inside the frame.\n west.setClipPath(null);\n west.setClipFrame(westX, westY, westFullWidth, middleHeight);\n this.commitBounds(west, 0, 0, westFullWidth, middleHeight);\n }\n\n this.updateRegionGutter(Placement.WEST, westX, westY, westWidth, middleHeight);\n\n if (center) {\n centerX += this._spacing;\n }\n } else {\n centerX = 0;\n }\n\n centerWidth = width - centerX;\n\n if (east) {\n centerWidth -= this._spacing;\n centerWidth -= eastPreferredWidth;\n\n let eastX = containerInsets.getLeft() + width - eastPreferredWidth;\n let eastY = containerInsets.getTop() + middleY;\n\n // Full-size and right-anchored, clipped toward the right while\n // collapsed; the gutter uses the strip rect (`eastX`/`eastPreferredWidth`).\n let eastFullX = containerInsets.getLeft() + width - eastFullWidth;\n\n if (this.isRegionCollapsible(Placement.EAST) || this._collapsing) {\n this.placeComponent(\n east,\n eastFullX,\n eastY,\n eastFullWidth,\n middleHeight,\n FillType.BOTH\n );\n east.clearClipFrame();\n this.applyRegionClip(east, Placement.EAST);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full position equals the strip position, so the\n // element commits at (0, 0) inside the frame.\n east.setClipPath(null);\n east.setClipFrame(eastFullX, eastY, eastFullWidth, middleHeight);\n this.commitBounds(east, 0, 0, eastFullWidth, middleHeight);\n }\n\n this.updateRegionGutter(Placement.EAST, eastX, eastY, eastPreferredWidth, middleHeight);\n }\n\n if (center) {\n let centerLeft = containerInsets.getLeft() + centerX;\n let centerTop = containerInsets.getTop() + middleY;\n\n // CENTER is never collapsible, so outside an animation it always\n // takes the frame branch and never carries a clip-path. Its rect is\n // its own allocation (it can never overflow it), so the frame is a\n // perfect-fit sheath that clips nothing — keeping one code path for\n // the non-collapsible case. While a collapse animates, CENTER grows\n // into the reclaimed space, so it takes the unframed path so its own\n // `left`/`top` can be interpolated.\n if (this._collapsing) {\n this.placeComponent(center, centerLeft, centerTop, centerWidth, middleHeight, FillType.BOTH);\n center.clearClipFrame();\n } else {\n center.setClipFrame(centerLeft, centerTop, centerWidth, middleHeight);\n this.commitBounds(center, 0, 0, centerWidth, middleHeight);\n }\n }\n }\n\n /**\n * Detaches from the container, removing every lazily-created collapse gutter\n * from the DOM and tearing down its event listeners so a layout-manager swap\n * leaves no orphaned affordances. Also clears the clip frame installed on\n * each non-collapsible region: when Border is swapped out but its regions\n * stay mounted, a successor manager that doesn't drive clip frames would\n * otherwise leave Border's `overflow: hidden` wrapper orphaned around the\n * region element. `clearClipFrame` is a no-op for an unframed region.\n */\n detach(): this {\n // Abandon any in-flight collapse first: the primed CSS transitions\n // carry fallback timers that would otherwise outlive the element\n // handles teardown releases.\n this._collapseAnimation?.();\n this._collapseAnimation = null;\n\n // That canceller's `onIdle` is the only place `_collapsing` is cleared,\n // and cancelling suppressed it. Left set, a swapped-out-then-reattached\n // Border takes the unframed / clearClipFrame branch for every region\n // forever, so the clip frames never come back.\n this._collapsing = false;\n\n // Two shapes of detach. A manager swap leaves the panes mounted, so\n // their primed transitions must be settled — cleared — or each keeps a\n // live transition and a permanent compositor layer. A dispose reaches\n // here from `Component.destructor`, which already destroyed the\n // children (so `getComponents()` is empty), and touching one would\n // write through a released element handle: cancel silently instead.\n const survives = (this.getContainer()?.getComponents().length ?? 0) > 0;\n\n for (const transition of this._pendingCollapseTransitions) {\n if (survives) {\n transition.settle();\n } else {\n transition.cancel();\n }\n }\n this._pendingCollapseTransitions.length = 0;\n\n super.detach();\n\n for (const gutter of this._gutters.values()) {\n const element = gutter.getElement();\n const parent = element ? DOM.source.getParentNode(element) : null;\n\n if (element && parent) {\n DOM.sink.removeChild(parent, element);\n }\n\n gutter.dispose();\n }\n\n this._gutters.clear();\n\n for (const placement of [Placement.NORTH, Placement.SOUTH, Placement.WEST, Placement.EAST, Placement.CENTER]) {\n this.getRegionComponent(placement)?.clearClipFrame();\n }\n\n return this;\n }\n}\n\nconst BorderCallable = callable(Border);\ntype BorderCallable = Border;\nexport {\n Border as _Border,\n BorderCallable as Border\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Border-CNS6aEXB.js","names":[],"sources":["../../src/typescript/lib/core/PointerDrag.ts","../../src/typescript/lib/layout/CollapseSupport.ts","../../src/typescript/lib/component/container/CollapseButton.ts","../../src/typescript/lib/component/container/SplitGutter.ts","../../src/typescript/lib/layout/Border.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Body-level bookkeeping shared by every component that drags a handle against\n * the viewport — a split gutter, a window border, a table column edge.\n *\n * Two things have to happen together for the duration of such a drag, which is\n * why they live in one call rather than at each drag site:\n *\n * 1. `<body>` stops taking pointer events, so the drag can't snag on whatever\n * the pointer passes over.\n * 2. The document element holds the drag cursor. This is the half that is easy\n * to miss: suppressing (1) also takes body's whole subtree — the drag handle\n * included — out of hit-testing, so nothing there resolves a cursor any more\n * and the pointer reverts to the default arrow mid-drag. The document\n * element stays hit-testable and is what the cursor falls back to, so it has\n * to carry the cursor instead.\n */\n\n/**\n * Suppresses body pointer events and pins `cursor` for the duration of a drag.\n * Pair every call with {@link endPointerDrag}.\n *\n * @param cursor - The CSS cursor to hold until the drag ends, normally the one\n * the handle shows on hover so the two can't disagree.\n */\nexport function beginPointerDrag(cursor: string): void {\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"none\" } });\n DOM.sink.apply(DOM.source.getDocumentElement(), { style: { cursor } });\n}\n\n/**\n * Restores body pointer events and hands the cursor back to whatever the\n * pointer is actually over. Safe to call without a matching\n * {@link beginPointerDrag} — it only clears inline values.\n */\nexport function endPointerDrag(): void {\n DOM.sink.apply(DOM.source.getBody(), { style: { pointerEvents: \"\" } });\n DOM.sink.apply(DOM.source.getDocumentElement(), { style: { cursor: \"\" } });\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { Animation } from \"~/core/Animation.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n// Pixel thickness of the opaque collapse strip a collapsed pane/region tucks\n// into — the size the gutter assumes in its strip state, leaving room for its\n// restore chevron. The layout math in `Split.doLayout`/`Border.doLayout` needs\n// a number, so the value lives here as a constant rather than only as the\n// `--ts-ui-collapse-strip-size` theme token — kept in lockstep by convention\n// (token default 18px).\nexport const COLLAPSE_STRIP_SIZE = 18;\n\n// Collapse/restore transition duration in milliseconds. Mirrors the\n// Accordion's 200ms default so the two surfaces share one motion personality;\n// kept as a code constant (not a theme token) for the same reason Accordion's\n// duration is — motion belongs to the layout, not the theme.\nconst COLLAPSE_DURATION = 200;\n\n// Symmetric easing curve, identical to the Accordion's, so a collapse reads as\n// a time-reverse of a restore. A symmetric curve (`easing(t) + easing(1-t) = 1`)\n// avoids the \"content vanished, then nothing happened\" feel of asymmetric\n// material curves. Shared with Accordion deliberately for a consistent feel.\nconst COLLAPSE_EASING = \"cubic-bezier(0.4, 0, 0.6, 1)\";\n\n/** Handle for the reduced-motion path, where no transition is primed at all. */\nconst NOOP_HANDLE: Animation.CancelHandle = { cancel: (): void => {} };\n\n/**\n * A primed CSS transition that has not settled yet, as held in a manager's\n * pending list. Two dispositions, because teardown has two shapes.\n *\n * @category Layout\n */\nexport interface CollapseTransition {\n /**\n * Abandons the transition and its completion callback. For the dispose\n * path, where every participant is being destroyed anyway and touching one\n * would write through a released element handle.\n */\n cancel(): void;\n\n /**\n * Abandons the transition but runs its cleanup — clearing `transition` on\n * every participant and `will-change` on the animating one — immediately.\n * For the manager-swap path, where the participants stay mounted and would\n * otherwise keep a live transition and a permanent compositor layer.\n */\n settle(): void;\n}\n\n/**\n * Primes a transition via `create` and adds its handle to `pending`, arranging\n * for the handle to remove itself once the transition settles. The list is\n * therefore always exactly the set of transitions still in flight — which is\n * what a manager's `detach` needs, and what neither the geometry canceller nor\n * a per-toggle field can hold (both are replaced or nulled while primed\n * transitions from an earlier toggle are still running).\n *\n * @param pending - The manager's live-transition list.\n * @param create - Primes the transition, given the callback that prunes it.\n */\nfunction track(\n pending: CollapseTransition[],\n create: (onSettled: () => void) => { handle: Animation.CancelHandle; cleanup: () => void },\n): void {\n let entry: CollapseTransition | null = null;\n let settled = false;\n\n const prune = (): void => {\n settled = true;\n\n const index = entry === null ? -1 : pending.indexOf(entry);\n\n if (index >= 0) {\n pending.splice(index, 1);\n }\n };\n\n const { handle, cleanup } = create(prune);\n\n // `create` settles synchronously under reduced motion, and also when the\n // animating component has no element — in both cases `prune` already ran,\n // before `entry` existed, so there is nothing live to track.\n if (settled) {\n return;\n }\n\n entry = {\n cancel: (): void => handle.cancel(),\n settle: (): void => {\n handle.cancel();\n cleanup();\n },\n };\n\n pending.push(entry);\n}\n\n/**\n * Primes a collapse/restore animation: installs a multi-property geometry\n * transition on every participating element, pre-promotes the driving element\n * to its own compositor layer, and schedules the layer's release plus\n * transition cleanup on `transitionend` (with a `setTimeout` fallback).\n *\n * The gutter that carries the motion both *moves* (`left`/`top`) and *resizes*\n * (`width`/`height`) between its divider and strip states, so the transition\n * spans the full axis property list rather than a single size property.\n *\n * The caller is expected to flip its collapsed flag and call `scheduleLayout`\n * immediately after — the next `doLayout` writes the new geometry, which the\n * just-installed transition animates.\n *\n * Under `prefers-reduced-motion: reduce` this is a no-op: no transition is\n * installed, so the upcoming `doLayout` writes land instantly.\n *\n * @param animating - The element that visibly moves; promoted via `will-change`\n * and the one whose `transitionend` (filtered to `completionProperty`) ends\n * the animation.\n * @param properties - The CSS properties to transition (e.g. `[\"left\", \"width\"]`\n * for a horizontal move-and-resize).\n * @param participants - Every element that should carry the transition for this\n * toggle: the gutter plus whatever shifts to fill — `Border` passes the gutter\n * and the centre; `Split` passes all panes and gutters.\n * @param onSettled - Invoked once the transition completes (or immediately under\n * reduced motion), so the caller can drop this handle from its live list.\n * @param completionProperty - Which property's `transitionend` ends the\n * animation. Defaults to the first property; pass the size property (whose\n * `transitionend` fires reliably) when the move delta may be zero.\n */\nfunction primeCollapse(\n animating: Component,\n properties: string[],\n participants: Component[],\n onSettled: () => void,\n completionProperty?: string,\n): { handle: Animation.CancelHandle; cleanup: () => void } {\n const cleanup = (): void => {\n for (const participant of participants) {\n participant.setTransition(null);\n }\n\n animating.setWillChange(null);\n };\n\n if (Animation.isReducedMotion()) {\n onSettled();\n\n return { handle: NOOP_HANDLE, cleanup };\n }\n\n const transition = properties\n .map(property => `${property} ${COLLAPSE_DURATION}ms ${COLLAPSE_EASING}`)\n .join(\", \");\n\n for (const participant of participants) {\n participant.setTransition(transition);\n }\n\n animating.setWillChange(properties.join(\", \"));\n\n const handle = Animation.afterTransition({\n component: animating,\n property: completionProperty ?? properties[0],\n durationMs: COLLAPSE_DURATION,\n fallbackBufferMs: 40,\n onComplete: () => {\n cleanup();\n onSettled();\n },\n });\n\n return { handle, cleanup };\n}\n\n/** An axis-aligned box used to snapshot and interpolate a participant's bounds. */\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * One element animated by {@link animateLayout}: its captured start/end bounds\n * and whether its content must be re-laid-out each frame.\n *\n * @remarks A content-bearing pane (`relayout: true`) needs `doLayout` per frame\n * so its children track the animating box instead of snapping to the final\n * size; an empty gutter (`relayout: false`) only needs its box geometry written,\n * since its single chevron child re-centres via CSS as the box resizes.\n */\ninterface CollapseMover {\n component: Component;\n relayout: boolean;\n start: Rect;\n end: Rect;\n}\n\n/** Reads a component's current box geometry into a {@link Rect}. */\nfunction captureRect(component: Component): Rect {\n return { x: component.getX(), y: component.getY(), width: component.getWidth(), height: component.getHeight() };\n}\n\n/**\n * Parses a `cubic-bezier(x1, y1, x2, y2)` CSS timing string into a JS easing\n * function `progress → eased`, so a JS-driven animation can move in lockstep\n * with a CSS transition that uses the same curve. Falls back to linear if the\n * string isn't a cubic-bezier. Uses Newton-Raphson (then bisection) to invert\n * the bezier's x(t) for a given progress before sampling y(t).\n */\nfunction parseCubicBezier(css: string): (progress: number) => number {\n const match = css.match(/cubic-bezier\\(([^)]+)\\)/);\n if (!match) {\n return progress => progress;\n }\n\n const [x1, y1, x2, y2] = match[1].split(\",\").map(value => parseFloat(value));\n\n const ax = 3 * x1, bx = 3 * (x2 - x1) - ax, cx = 1 - ax - bx;\n const ay = 3 * y1, by = 3 * (y2 - y1) - ay, cy = 1 - ay - by;\n\n const sampleX = (t: number) => ((cx * t + bx) * t + ax) * t;\n const sampleY = (t: number) => ((cy * t + by) * t + ay) * t;\n const sampleDX = (t: number) => (3 * cx * t + 2 * bx) * t + ax;\n\n return progress => {\n let t = progress;\n\n for (let i = 0; i < 8; i += 1) {\n const x = sampleX(t) - progress;\n if (Math.abs(x) < 1e-6) {\n return sampleY(t);\n }\n\n const dx = sampleDX(t);\n if (Math.abs(dx) < 1e-6) {\n break;\n }\n\n t -= x / dx;\n }\n\n // Bisection fallback for the rare flat-slope case.\n let lo = 0, hi = 1;\n t = progress;\n while (lo < hi) {\n const x = sampleX(t);\n if (Math.abs(x - progress) < 1e-6) {\n break;\n }\n if (x < progress) {\n lo = t;\n } else {\n hi = t;\n }\n t = (lo + hi) / 2;\n }\n\n return sampleY(t);\n };\n}\n\n// JS twin of COLLAPSE_EASING, so the rAF geometry interpolation and the\n// clip-path CSS transition share one motion curve.\nconst COLLAPSE_EASE = parseCubicBezier(COLLAPSE_EASING);\n\nconst lerp = (a: number, b: number, t: number): number => a + (b - a) * t;\n\nconst lerpRect = (a: Rect, b: Rect, t: number): Rect => ({\n x: lerp(a.x, b.x, t),\n y: lerp(a.y, b.y, t),\n width: lerp(a.width, b.width, t),\n height: lerp(a.height, b.height, t),\n});\n\n/**\n * Writes a resolved rect to a component as a single batched DOM update,\n * mirroring `LayoutManager.commitBounds`: the four positional setters flush\n * together, and a content-bearing participant re-lays-out its children at the\n * new size.\n */\nfunction commitRect(component: Component, rect: Rect, relayout: boolean): void {\n component.setAutoCommitStyle(false);\n component.setX(rect.x);\n component.setY(rect.y);\n component.setWidth(rect.width);\n component.setHeight(rect.height);\n\n if (relayout) {\n component.doLayout();\n }\n\n component.setAutoCommitStyle(true);\n}\n\n/**\n * Drives a coordinated collapse/restore by interpolating every participant's\n * box from its `start` to its `end` over {@link COLLAPSE_DURATION} on\n * {@link COLLAPSE_EASING}, re-laying-out content-bearing panes each frame.\n *\n * This is the JS half of the collapse animation: it keeps the resizing panes,\n * the moving gutter, and their contents moving together, while the *toggled*\n * pane/region holds its final geometry and only reveals via a `clip-path` CSS\n * transition (primed separately by {@link primeCollapse}). Both halves share\n * the easing curve, so they stay in lockstep. Because linear interpolation of\n * two gap-free layouts is itself gap-free at every step, no seams open between\n * adjacent panes mid-animation.\n *\n * The caller is expected to have already snapshotted each mover's `start`,\n * written the end layout (its `doLayout`), and captured each mover's `end`.\n * This function lands on `start` synchronously — so the just-written end state\n * never paints — then animates forward.\n *\n * Under `prefers-reduced-motion: reduce` it writes the end state and completes\n * immediately, with no animation frames.\n *\n * @param movers - The participants with their captured start/end bounds.\n * @param onComplete - Invoked once the animation settles (or immediately under\n * reduced motion); not invoked if the returned canceller runs first.\n * @returns A canceller that stops the animation in place (leaving the current\n * interpolated geometry), so a rapid re-toggle can re-snapshot and retarget.\n */\nfunction animateLayout(movers: CollapseMover[], onComplete?: () => void): () => void {\n if (Animation.isReducedMotion()) {\n for (const mover of movers) {\n commitRect(mover.component, mover.end, mover.relayout);\n }\n\n onComplete?.();\n\n return () => {};\n }\n\n let cancelled = false;\n let raf = 0;\n\n // Land on the start frame synchronously so the caller's just-written end\n // geometry never reaches the screen.\n for (const mover of movers) {\n commitRect(mover.component, mover.start, mover.relayout);\n }\n\n const startTime = performance.now();\n\n const frame = (now: number): void => {\n if (cancelled) {\n return;\n }\n\n const progress = Math.min(1, (now - startTime) / COLLAPSE_DURATION);\n const eased = COLLAPSE_EASE(progress);\n\n for (const mover of movers) {\n commitRect(mover.component, progress >= 1 ? mover.end : lerpRect(mover.start, mover.end, eased), mover.relayout);\n }\n\n if (progress < 1) {\n raf = DOM.sink.requestAnimationFrame(frame);\n } else {\n onComplete?.();\n }\n };\n\n raf = DOM.sink.requestAnimationFrame(frame);\n\n return () => {\n cancelled = true;\n\n if (raf) {\n DOM.sink.cancelAnimationFrame(raf);\n }\n };\n}\n\n/**\n * One participant in a {@link runCollapse} pass: the moving element and whether\n * its content must be re-laid-out each frame — `true` for a content-bearing\n * pane/region, `false` for an empty gutter.\n */\nexport interface CollapseParticipant {\n component: Component;\n relayout: boolean;\n}\n\n/**\n * Runs one coordinated collapse/restore for a layout manager — the shared\n * plumbing behind [`Split.setPaneCollapsed`](/api/layout/classes/Split) and\n * [`Border.setRegionCollapsed`](/api/layout/classes/Border). The caller has\n * already flipped its own collapsed flag and assembled `participants`: every\n * box that moves — the panes/regions (`relayout: true`) and the gutters\n * (`relayout: false`), the `toggled` one included.\n *\n * The pass: cancel any in-flight collapse (`previous`); prime the `toggled`\n * pane/region's clip-path reveal (it keeps its final size and only clips, so it\n * never reads as a content snap); snapshot every participant's start geometry;\n * write the end layout via the container's `doLayout`; capture the end geometry;\n * and hand the lot to the rAF driver, which interpolates the boxes — re-laying\n * out the content-bearing ones — in lockstep with the clip transition.\n *\n * @param container - The manager's container, laid out to compute the end state.\n * @param toggled - The pane/region being collapsed or restored (clip-revealed).\n * @param participants - Every moving box, including `toggled`.\n * @param previous - The manager's current animation canceller, or null when idle.\n * @param pending - The manager's list of primed CSS transitions that have not\n * settled yet. `runCollapse` appends to it and each entry removes itself on\n * completion, so the manager's `detach` can cancel exactly the live ones.\n * Kept off the returned canceller deliberately: that canceller is nulled when\n * the geometry animation settles, ~40 ms before the primed transitions'\n * fallbacks disarm, and a re-toggle replaces it while old transitions are\n * still running — either would strand a live handle.\n * @param onIdle - Invoked when the animation settles; clears the manager's handle.\n * @returns A canceller the manager stores and passes back as `previous` next time.\n */\nexport function runCollapse(\n container: Component,\n toggled: Component,\n participants: CollapseParticipant[],\n previous: (() => void) | null,\n pending: CollapseTransition[],\n onIdle?: () => void,\n): () => void {\n // Stop any in-flight collapse so a rapid re-toggle re-snapshots from the\n // current mid-animation geometry and retargets cleanly. Only the geometry\n // animation is stopped: the primed CSS transitions are left to finish and\n // run their own cleanup, because that cleanup (clearing `transition` and\n // `will-change` on the previous participants) has no other trigger and the\n // fresh prime below covers only the new participant set.\n previous?.();\n\n // The toggled pane/region holds its final size and reveals only via a\n // clip-path transition; every other participant is JS-driven below so boxes\n // and contents move together.\n track(pending, handle => primeCollapse(toggled, [\"clip-path\"], [toggled], handle, \"clip-path\"));\n\n // Cross-fade each gutter's fill between its transparent divider colour and\n // its opaque strip colour as it morphs, so the strip doesn't pop in or out.\n // Only the toggling gutter's colour actually changes when `doLayout` runs\n // `setOpaque` below; the rest carry the transition harmlessly. The fade is a\n // CSS transition (colour interpolation, `var()` resolution, and the\n // transparent endpoint are all easier left to the browser) sharing the\n // geometry's duration and curve.\n const gutters = participants.filter(participant => !participant.relayout).map(participant => participant.component);\n if (gutters.length > 0) {\n track(pending, handle => primeCollapse(gutters[0], [\"background-color\"], gutters, handle, \"background-color\"));\n }\n\n // Snapshot the start geometry, write the end layout, then capture the end\n // geometry and animate between the two.\n const starts = participants.map(participant => captureRect(participant.component));\n\n container.doLayout();\n\n const movers: CollapseMover[] = participants.map((participant, index) => ({\n component: participant.component,\n relayout: participant.relayout,\n start: starts[index],\n end: captureRect(participant.component),\n }));\n\n return animateLayout(movers, onIdle);\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { COLLAPSE_STRIP_SIZE } from \"~/layout/CollapseSupport.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n// The chevron handle's thickness across the host gutter in its two states: a\n// narrow grip while the gutter is an expanded divider, widening to the full\n// collapse-strip width so the restore handle fills the strip once collapsed.\n// The length along the gutter is constant in both states.\nconst GRIP_ACROSS = 10;\nconst HANDLE_ALONG = 40;\n\n/**\n * The four directions a {@link CollapseButton}'s chevron can point — the\n * direction the pane/region travels when the button is activated (collapse) or\n * restored.\n *\n * @category Components\n */\nexport type CollapseDirection = \"north\" | \"south\" | \"east\" | \"west\";\n\n/**\n * String-literal union of the events emitted by {@link CollapseButton}.\n *\n * @category Components\n */\nexport type CollapseButtonEvent = \"collapse\";\n\n/**\n * Construction-time options for {@link CollapseButton}.\n *\n * @category Components\n */\nexport interface CollapseButtonOptions extends ComponentOptions {\n direction?: CollapseDirection;\n /**\n * Multi-event listener bag dispatched to {@link CollapseButton.on} at\n * construction time.\n */\n listeners?: {\n collapse?: () => void;\n };\n}\n\n/**\n * Degrees of rotation applied to the base east-pointing chevron glyph (`▶`) to\n * make it point in each {@link CollapseDirection}. Keyed so {@link CollapseButton}\n * can resolve the per-instance transform without a `switch`.\n */\nconst _rotationByDirection: Record<CollapseDirection, number> = {\n east: 0,\n south: 90,\n west: 180,\n north: -90,\n};\n\nlet _classRule: StyleRule | null = null;\n\n/**\n * Registers the shared `.CollapseButton` class rule once on first use. The rule\n * holds the centred overlay geometry, chevron colour, and the raised themed\n * grip styling (the button overflows its thin host gutter so it stays\n * clickable).\n *\n * Idempotent and module-local; safe across hot reloads.\n */\nfunction ensureCollapseButtonClassRule(): void {\n if (_classRule) {\n return;\n }\n\n _classRule = new StyleRule({\n scope: \"class\",\n name: \"CollapseButton\",\n styles: {\n position: \"absolute\",\n top: \"50%\",\n left: \"50%\",\n // Fallback centring transform; each instance overrides it via a\n // per-instance rule that layers on the direction rotation.\n transform: \"translate(-50%, -50%)\",\n // A raised, themed grip handle rather than a bare glyph, so the\n // whole thing is an easy double-click target. The box is uniform\n // (thin across the track, long along it) and the per-instance\n // rotation orients it: a tall handle on a vertical (west/east)\n // gutter, a wide one on a horizontal (north/south) gutter. Reuses\n // the button tokens so it matches the theme's raised controls.\n boxSizing: \"border-box\",\n width: `${GRIP_ACROSS}px`,\n height: `${HANDLE_ALONG}px`,\n borderRadius: \"2px\",\n background: \"var(--ts-ui-button-bg, #e8e8e8)\",\n border: \"1px solid var(--ts-ui-button-border, #c8c8c8)\",\n boxShadow: \"var(--ts-ui-button-shadow, 0 1px 2px rgba(0, 0, 0, 0.2))\",\n textAlign: \"center\",\n fontSize: \"9px\",\n lineHeight: `${HANDLE_ALONG - 2}px`,\n color: \"var(--ts-ui-collapse-button-color, rgb(100,100,100))\",\n // The handle keeps its own pointer events so it stays clickable\n // even where it overhangs the thin host gutter. The clickable\n // `cursor: pointer` is applied per-instance (the Component default\n // `cursor: default` would otherwise override a class-rule cursor).\n pointerEvents: \"auto\",\n userSelect: \"none\",\n },\n });\n}\n\n/**\n * A small chevron button carried by a [`SplitGutter`](/api/component/container/classes/SplitGutter)\n * that triggers a collapse in the gutter's divider state or a restore in its\n * collapsed-strip state.\n *\n * Activation is a **double-click**, never a single click, so grabbing the button\n * for a drag can never collapse by accident — a drag produces no `dblclick`, and\n * the button's `mousedown` is stopped from reaching the host so it never begins\n * a gutter resize.\n *\n * @category Components\n */\nclass CollapseButton extends Component<CollapseButtonOptions> {\n\n declare private _direction: CollapseDirection;\n private _listeners: ListenerBag<CollapseButtonEvent> = new ListenerBag<CollapseButtonEvent>();\n\n /**\n * Constructs a collapse button. The chevron points east unless\n * `options.direction` says otherwise.\n *\n * @param options - Optional configuration bag (chevron direction, listener\n * bag, plus common Component fields).\n */\n constructor(options?: CollapseButtonOptions) {\n ensureCollapseButtonClassRule();\n\n // `cursor: \"pointer\"` is set here (not only in the class rule) because\n // Component defaults `cursor` to `\"default\"` and writes it per-instance,\n // which would override a class-rule cursor. A caller-supplied cursor\n // still wins via the trailing spread.\n super({ tag: \"span\", cursor: \"pointer\", ...(options ?? {}) });\n\n this._direction ??= \"east\";\n\n this.applyRotation();\n\n // Listener wiring runs here — NOT inside `applyOptions` — because\n // Component's constructor calls `applyOptions` from inside super(),\n // before the class-field `_listeners` initializer has run.\n this.applyListeners(options?.listeners);\n\n Event.addListener(this, \"dblclick\", this.onDoubleClick);\n Event.addListener(this, \"mousedown\", this.onMouseDown);\n }\n\n /**\n * Applies a {@link CollapseButtonOptions} bag, dispatching the chevron\n * direction after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: CollapseButtonOptions): this {\n super.applyOptions(options);\n\n if (options.direction !== undefined) {\n this.setDirection(options.direction);\n }\n\n return this;\n }\n\n /**\n * Renders the root span, writes the chevron glyph, and applies the cached\n * rotation for the current direction at first paint.\n *\n * @returns The rendered root element.\n */\n protected render(): Handle {\n const element = super.render();\n\n DOM.sink.apply(element, { text: \"▶\" });\n\n return element;\n }\n\n /**\n * Writes the per-instance `transform` (centring plus the rotation for the\n * current direction) onto a `createStyleRule` rule, overriding the shared\n * class rule's centring-only transform. Routed through `createStyleRule`\n * rather than `setTransform` because that builder's rules are replayed by\n * `applyStyle` at render time, whereas a main-rule write made before render\n * is dropped when the rule is rebuilt.\n */\n private applyRotation(): void {\n const degrees = _rotationByDirection[this._direction];\n\n this.createStyleRule(\"\").set(\"transform\", `translate(-50%, -50%) rotate(${degrees}deg)`);\n }\n\n /**\n * Toggles the handle between its expanded-grip and collapsed-strip widths.\n * Collapsed, it widens to the collapse-strip size so the restore handle\n * fills the entire width of the gutter's strip; expanded, it returns to the\n * narrow grip. The width rides the per-instance rule\n * (replayed by `applyStyle`) so it survives a render. The rotation maps this\n * `width` to the across-gutter axis for every chevron direction.\n *\n * @param filled - True for the collapsed strip-filling width, false for the grip.\n * @returns This component, for method chaining.\n */\n setStripMode(filled: boolean): this {\n this.createStyleRule(\"\").set(\"width\", `${filled ? COLLAPSE_STRIP_SIZE : GRIP_ACROSS}px`);\n\n return this;\n }\n\n /**\n * Returns the cached chevron direction.\n *\n * @returns The direction the chevron currently points.\n */\n getDirection(): CollapseDirection {\n return this._direction;\n }\n\n /**\n * Sets the chevron direction, rotating the glyph to match.\n *\n * @param direction - The direction the chevron should point.\n * @returns This component, for method chaining.\n */\n setDirection(direction: CollapseDirection): this {\n this._direction = direction;\n\n this.applyRotation();\n\n return this;\n }\n\n /**\n * Registers a listener for this button's `collapse` event, fired on a\n * double-click.\n *\n * @param event - Always `\"collapse\"`.\n * @param listener - The callback to invoke on double-click.\n * @returns This component, for method chaining.\n */\n on(event: \"collapse\", listener: () => void): this;\n on(event: CollapseButtonEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n * @returns This component, for method chaining.\n */\n off(event: CollapseButtonEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event`, in registration order.\n *\n * @param event - The event to emit.\n */\n protected emit(event: CollapseButtonEvent): void {\n this._listeners.fire(event);\n }\n\n /**\n * Emits `collapse` on a double-click.\n *\n * @param _evnt - The dblclick event; propagation is stopped so the host\n * never also reacts.\n * @returns `true`, consuming the double-click so it does not also reach the header behind the button.\n */\n private onDoubleClick(_evnt: MouseEvent): Event.ListenerResult {\n this.emit(\"collapse\");\n\n return true;\n }\n\n /**\n * Stops a `mousedown` on the button from reaching the host gutter, so\n * grabbing the chevron never begins a resize drag.\n *\n * @param _evnt - The mousedown event to suppress.\n * @returns `true`, consuming the press so it does not start a drag on the header behind the button.\n */\n private onMouseDown(_evnt: MouseEvent): Event.ListenerResult {\n return true;\n }\n\n}\n\nconst CollapseButtonCallable = callable(CollapseButton);\ntype CollapseButtonCallable = CollapseButton;\nexport {\n CollapseButton as _CollapseButton,\n CollapseButtonCallable as CollapseButton\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { CollapseButton, CollapseDirection } from \"~/component/container/CollapseButton.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { beginPointerDrag, endPointerDrag } from \"~/core/PointerDrag.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { Tooltip } from \"~/overlay/Tooltip.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * String-literal union of the events emitted by {@link SplitGutter}.\n *\n * @category Components\n */\nexport type SplitGutterEvent = \"dragstart\" | \"drag\" | \"dragend\" | \"collapse\";\n\n/**\n * Maps each chevron direction to its opposite, used to flip the single\n * collapse chevron between its collapse heading (toward the pane/region's\n * outer edge) and its restore heading (back toward the centre) when the gutter\n * toggles between divider and strip state.\n */\nconst OPPOSITE_DIRECTION: Record<CollapseDirection, CollapseDirection> = {\n west: \"east\",\n east: \"west\",\n north: \"south\",\n south: \"north\",\n};\n\n/**\n * Construction-time options for {@link SplitGutter}.\n *\n * @category Components\n */\nexport interface SplitGutterOptions extends ComponentOptions {\n orientation?: string;\n /** Whether the gutter carries a collapse chevron. Defaults to `true`. */\n collapsible?: boolean;\n /**\n * Whether the gutter wires drag-to-resize listeners. `Split` leaves this\n * `true`; `Border` passes `false` for a fixed, non-draggable gutter.\n * Defaults to `true`. Read once at construction.\n */\n movable?: boolean;\n /**\n * Whether the gutter paints the opaque collapse-strip fill (collapsed\n * state) or its expanded background (divider state). Defaults to `false`.\n */\n opaque?: boolean;\n /**\n * The chevron's collapse heading — the way it points (and the way the\n * gutter travels) when collapsing. The restore heading is its opposite.\n * Defaults to `west` for a horizontal gutter, `north` for a vertical one.\n */\n collapseDirection?: CollapseDirection;\n /**\n * The background painted in the expanded (divider) state, restored when\n * {@link SplitGutter.setOpaque} is cleared. Defaults to the gutter token;\n * `Border` passes `\"transparent\"` for its minimal-until-collapsed look.\n */\n expandedBackground?: string;\n /**\n * Multi-event listener bag dispatched to {@link SplitGutter.on} at\n * construction time.\n */\n listeners?: {\n dragstart?: (position: number) => void;\n drag?: (position: number) => void;\n dragend?: () => void;\n collapse?: () => void;\n };\n}\n\n/**\n * Class-level defaults. `orientation` rides the cascade so the `declare`-d\n * `_direction` backing field is seeded by `setDirection` during super(),\n * dodging the class-field super-cascade trap; `collapsible` and `movable`\n * likewise seed their backing fields through their setters.\n */\nconst _defaultSplitGutterOptions: Partial<SplitGutterOptions> = {\n orientation: \"horizontal\",\n collapsible: true,\n movable: true,\n};\n\n/**\n * A gutter component shared by [`Split`](/api/layout/classes/Split) and the\n * [`Border`](/api/layout/classes/Border) layout that doubles as both a divider\n * and a collapsed strip.\n *\n * In the **divider** state it is the thin bar between two panes (draggable when\n * `movable`) or a transparent track at a region's inner edge, carrying a single\n * collapse chevron. In the **strip** state (`opaque`) it is the opaque\n * collapse-strip the pane/region tucks into, the same chevron now pointing the\n * restore way. The owning manager animates the gutter between the two by\n * writing its geometry; the gutter is the only thing that moves.\n *\n * When `movable`, it listens for mouse/touch drag events on the viewport and\n * notifies registered drag listeners with the absolute pointer coordinate\n * (`clientX`/`clientY`) in the gutter's drag axis on each move, disabling body\n * pointer events during a drag to prevent text selection.\n *\n * @category Components\n */\nclass SplitGutter extends Component<SplitGutterOptions> {\n\n declare private _direction: String;\n declare private _collapsible: boolean;\n declare private _movable: boolean;\n declare private _collapseButton: CollapseButton;\n private _opaque: boolean = false;\n private _collapseDirection: CollapseDirection = \"west\";\n private _expandedBackground: string = \"var(--ts-ui-gutter-bg, #AAAAAA)\";\n private _tooltipText: string = \"\";\n private _listeners: ListenerBag<SplitGutterEvent> = new ListenerBag<SplitGutterEvent>();\n\n /**\n * @param direction - Split orientation this gutter drags along.\n * @param options - Optional construction options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(\n direction: String,\n options?: SplitGutterOptions,\n subclassDefaults?: Partial<SplitGutterOptions>,\n ) {\n super(options, { ..._defaultSplitGutterOptions, ...(subclassDefaults ?? {}) });\n\n // Pre-migration the trailing applyOptions(options) ran *after* the\n // body's positional assignment, so a caller-supplied `orientation`\n // option won. Apply the positional only when the caller did not\n // supply orientation, preserving the option-wins-over-positional\n // contract.\n if (direction && options?.orientation === undefined) {\n this._direction = direction;\n }\n\n // The expanded fill is the gutter token by default; Border passes a\n // transparent value so its divider state shows only the chevron.\n this._expandedBackground = options?.expandedBackground ?? \"var(--ts-ui-gutter-bg, #AAAAAA)\";\n this.setBackgroundColor(this._expandedBackground);\n\n // The chevron's collapse heading points the way the gutter travels on\n // collapse — toward the pane/region's outer edge. Defaults from the\n // axis (Split's leading pane is west/north); Border overrides per\n // placement. The restore heading is its opposite, applied by setOpaque.\n this._collapseDirection = options?.collapseDirection ?? (this._direction === \"horizontal\" ? \"west\" : \"north\");\n\n this._collapseButton = new CollapseButton({\n direction: this._collapseDirection,\n listeners: { collapse: () => this.emit(\"collapse\") },\n });\n\n this._collapseButton.setVisible(this._collapsible);\n\n if (options?.opaque) {\n this.setOpaque(true);\n }\n\n // A fixed gutter (Border) never resizes, so its body should not swallow\n // pointer events — the transparent track must let clicks reach the\n // region behind it, and the opaque strip has nothing behind to click.\n // The chevron child keeps its own `pointer-events: auto`, so it stays\n // clickable regardless.\n if (!this._movable) {\n this.setPointerEvents(\"none\");\n }\n\n // Drag wiring lives here, gated on `movable`, NOT in `applyOptions`:\n // Component's constructor runs applyOptions from inside super(), and\n // the listener machinery (`_listeners`) is only live after super().\n // Border's fixed gutters pass `movable: false` and skip the wiring.\n if (this._movable) {\n Event.addListener(this, 'mousedown', this.onDragStart);\n }\n\n this.applyListeners(options?.listeners);\n\n // Seed the expanded-state hover hint (setOpaque already refreshes it\n // when an opaque gutter is constructed).\n this.updateTooltip();\n }\n\n /**\n * Appends the collapse button's element to the gutter element once the DOM\n * node exists.\n *\n * @param element - Optional element passed from the framework init chain.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n\n if (!el) {\n return this;\n }\n\n DOM.sink.appendChild(el, this._collapseButton.getElement(true)!);\n\n return this;\n }\n\n /**\n * Returns whether the gutter carries a collapse chevron.\n *\n * @returns True when the collapse button is shown.\n */\n isCollapsible(): boolean {\n return this._collapsible ?? this._defaultOptions.collapsible!;\n }\n\n /**\n * Shows or hides the gutter's collapse chevron.\n *\n * @param value - True to show the collapse button, false to hide it.\n * @returns This gutter, for method chaining.\n */\n setCollapsible(value: boolean): this {\n this._collapsible = value;\n\n this._collapseButton?.setVisible(value);\n\n // Keep the hover hint in step with collapsibility: a non-collapsible\n // gutter (a plain draggable divider whose neighbour opted out of\n // collapse) must not advertise a double-click-to-collapse action.\n // Guarded on `_collapseButton` so the construction-time cascade — which\n // runs this setter from `super()` before the button and the\n // `_tooltipText` field exist — defers to the constructor's own\n // `updateTooltip` call.\n if (this._collapseButton) {\n this.updateTooltip();\n }\n\n return this;\n }\n\n /**\n * Applies a {@link SplitGutterOptions} bag, dispatching the gutter\n * orientation after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: SplitGutterOptions): this {\n super.applyOptions(options);\n\n // All three carry a class default and seed construction-time backing\n // state, so dispatch the caller value or the class default.\n this.setDirection(options.orientation ?? this.getDirection());\n this.setCollapsible(options.collapsible ?? this.isCollapsible());\n this.setMovable(options.movable ?? this.isMovable());\n\n return this;\n }\n\n /**\n * Returns whether the gutter wires drag-to-resize.\n *\n * @returns True when the gutter is draggable.\n */\n isMovable(): boolean {\n return this._movable ?? this._defaultOptions.movable!;\n }\n\n /**\n * Records whether the gutter is draggable. The actual `mousedown` drag\n * wiring is established once in the constructor from this flag (a fixed\n * Border gutter never wires it); this setter seeds the cached value during\n * the options cascade.\n *\n * @param value - True for a draggable gutter, false for a fixed one.\n * @returns This gutter, for method chaining.\n */\n setMovable(value: boolean): this {\n this._movable = value;\n\n return this;\n }\n\n /**\n * Returns whether the gutter is painting the opaque collapse-strip fill.\n *\n * @returns True in the collapsed strip state.\n */\n isOpaque(): boolean {\n return this._opaque;\n }\n\n /**\n * Toggles the gutter between its divider and collapsed-strip appearance.\n * `true` paints the opaque collapse-strip fill and flips the chevron to the\n * restore heading; `false` restores the expanded background and the\n * collapse heading.\n *\n * @param value - True for the collapsed strip state, false for the divider state.\n * @returns This gutter, for method chaining.\n */\n setOpaque(value: boolean): this {\n this._opaque = value;\n\n if (value) {\n // Collapsed: the strip reads as a themed button surface (the same\n // fill and border the framework's buttons use), inviting a click to\n // restore. `--ts-ui-button-bg` is a solid colour in some themes and\n // a gradient in others, so set both background properties to it —\n // the browser ignores whichever is type-invalid for the given theme.\n this.setBackgroundColor(\"var(--ts-ui-button-bg, #e8e8e8)\");\n this.setBackgroundImage(\"var(--ts-ui-button-bg, linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200)))\");\n this.setBorder(\"1px solid var(--ts-ui-button-border, #c8c8c8)\");\n this._collapseButton?.setDirection(OPPOSITE_DIRECTION[this._collapseDirection]);\n } else {\n this.clearBackgroundImage();\n this.clearBorder();\n this.setBackgroundColor(this._expandedBackground);\n this._collapseButton?.setDirection(this._collapseDirection);\n }\n\n // Collapsed, the restore handle fills the strip's full width; expanded,\n // it shrinks back to the narrow grip.\n this._collapseButton?.setStripMode(value);\n\n // The collapsed strip cannot be dragged (see `onDragStart`), so it must\n // not advertise a resize cursor either.\n this.applyCursor();\n\n // The hover hint flips between \"collapse\" and \"expand\".\n this.updateTooltip();\n\n return this;\n }\n\n /**\n * Returns the chevron's collapse heading.\n *\n * @returns The direction the chevron points (and the gutter travels) on collapse.\n */\n getCollapseDirection(): CollapseDirection {\n return this._collapseDirection;\n }\n\n /**\n * Sets the chevron's collapse heading — the way it points in the divider\n * state and the way the gutter travels on collapse. The restore heading is\n * its opposite. Re-applies the chevron for the current opaque state.\n *\n * @param direction - The collapse heading.\n * @returns This gutter, for method chaining.\n */\n setCollapseDirection(direction: CollapseDirection): this {\n this._collapseDirection = direction;\n\n this._collapseButton?.setDirection(this._opaque ? OPPOSITE_DIRECTION[direction] : direction);\n this.updateTooltip();\n\n return this;\n }\n\n /**\n * Refreshes the hover tooltip on the gutter and its chevron to describe the\n * double-click action for the current state: which way the gutter will\n * collapse when expanded, or that it will expand back when collapsed. Both\n * the gutter body (hovered on a draggable `Split` divider) and the chevron\n * handle (the always-visible grip) carry it. No-op when the text is\n * unchanged so repeated layouts don't re-wire the hover listeners.\n */\n private updateTooltip(): void {\n // A non-collapsible gutter carries no chevron and cannot collapse, so it\n // gets no hint at all — dropping any hint a prior collapsible state left\n // attached. `_tooltipText === \"\"` marks the already-detached state, so a\n // repeated layout doesn't re-detach (and re-`hide`) every pass.\n if (!this._collapsible) {\n if (this._tooltipText !== \"\") {\n Tooltip.detach(this);\n\n if (this._collapseButton) {\n Tooltip.detach(this._collapseButton);\n }\n\n this._tooltipText = \"\";\n }\n\n return;\n }\n\n const action = this._opaque ? \"expand\" : \"collapse\";\n const direction = this._opaque ? OPPOSITE_DIRECTION[this._collapseDirection] : this._collapseDirection;\n const text = `Double-click to ${action} ${direction}ward`;\n\n if (text === this._tooltipText) {\n return;\n }\n\n this._tooltipText = text;\n\n Tooltip.attach(this, text);\n\n if (this._collapseButton) {\n Tooltip.attach(this._collapseButton, text);\n }\n }\n\n /**\n * Returns the gutter's split direction: 'horizontal' or 'vertical'.\n *\n * @returns The current direction string.\n */\n getDirection() {\n return this._direction ?? this._defaultOptions.orientation!;\n }\n\n /**\n * Sets the split direction, defaulting to 'horizontal' if not provided.\n *\n * @param direction - Optional. \"horizontal\" or \"vertical\". Defaults to \"horizontal\".\n */\n setDirection(direction?: String) : this {\n if (!direction) {\n direction = \"horizontal\";\n }\n\n this._direction = direction;\n\n return this;\n }\n\n /**\n * Registers a listener for one of this gutter's events.\n *\n * @param event - `\"dragstart\"` fires on mousedown, receiving the absolute\n * pointer coordinate (`clientX`/`clientY`) in the gutter's drag axis at\n * the moment the drag begins; `\"drag\"` fires on each mousemove/touchmove\n * during a drag, receiving the absolute pointer coordinate in that axis;\n * `\"dragend\"` fires once the drag ends (mouseup, touchend, or\n * touchcancel); `\"collapse\"` fires when the gutter's chevron is\n * double-clicked.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This gutter, for method chaining.\n */\n on(event: \"dragstart\", listener: (position: number) => void): this;\n on(event: \"drag\", listener: (position: number) => void): this;\n on(event: \"dragend\", listener: () => void): this;\n on(event: \"collapse\", listener: () => void): this;\n on(event: SplitGutterEvent, listener: Function): this {\n this._listeners.add(event, listener);\n\n return this;\n }\n\n /**\n * Removes a previously registered listener. The exact callback reference\n * must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This gutter, for method chaining.\n */\n off(event: SplitGutterEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every listener registered for `event` with `payload`, in\n * registration order.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"dragstart\", position: number): void;\n protected emit(event: \"drag\", position: number): void;\n protected emit(event: \"dragend\"): void;\n protected emit(event: \"collapse\"): void;\n protected emit(event: SplitGutterEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Disposes the collapse button, then runs the inherited teardown. The\n * explicit `_collapseButton` disposal is required, not redundant: the\n * button is raw-appended to this gutter's element rather than registered\n * as a child, so `super.destructor()`'s child recursion cannot reach it.\n */\n protected destructor(): void {\n this._collapseButton?.dispose();\n\n super.destructor();\n }\n\n /**\n * Internal mousemove/touchmove dispatch — fires the `drag` event with the\n * absolute pointer coordinate in the gutter's drag axis.\n *\n * @param position - The absolute pointer coordinate (`clientX`/`clientY`)\n * in the relevant axis for this drag event.\n */\n private _dispatchDrag(position: number): void {\n this.emit(\"drag\", position);\n }\n\n /**\n * Attaches viewport mouse/touch move and stop listeners, disables body\n * pointer events, and fires the `dragstart` event with the absolute pointer\n * coordinate so the consumer can capture its drag origin.\n *\n * @param evnt - The mousedown event; its `clientX`/`clientY` seeds the\n * drag origin in the gutter's axis.\n */\n onDragStart(evnt: MouseEvent) {\n // A gutter in its collapsed strip state is not a resize handle — the\n // pane behind it is hidden, so a drag would corrupt its stored size.\n if (this._opaque) {\n return;\n }\n\n const position = this._direction === \"horizontal\" ? evnt.clientX : evnt.clientY;\n\n this.emit(\"dragstart\", position);\n\n Event.addViewportListener(this, 'mouseup', this.onDragStop);\n Event.addViewportListener(this, 'touchend', this.onDragStop);\n Event.addViewportListener(this, 'touchcancel', this.onDragStop);\n Event.addViewportListener(this, 'mousemove', this.onDrag);\n Event.addViewportListener(this, 'touchmove', this.onDrag);\n\n beginPointerDrag(this.dragCursor());\n }\n\n /**\n * Removes viewport listeners and restores body pointer events and the\n * document element's cursor when drag ends, then fires `dragend`. Also\n * callable directly (with no argument) so tests can simulate a drag end.\n *\n * @returns `true`, consuming the release that ends the gutter drag.\n */\n onDragStop(): Event.ListenerResult {\n Event.removeViewportListener(this, 'mouseup', this.onDragStop);\n Event.removeViewportListener(this, 'touchend', this.onDragStop);\n Event.removeViewportListener(this, 'touchcancel', this.onDragStop);\n Event.removeViewportListener(this, 'mousemove', this.onDrag);\n Event.removeViewportListener(this, 'touchmove', this.onDrag);\n\n endPointerDrag();\n\n this.emit(\"dragend\");\n\n return true;\n }\n\n /**\n * Extracts the absolute pointer coordinate from the mouse event and fires\n * all drag listeners.\n *\n * @param evnt - The MouseEvent from which clientX or clientY is read.\n * @returns `true`, consuming the move so nothing else tracks the pointer mid-drag.\n */\n onDrag(evnt: MouseEvent): Event.ListenerResult {\n let position;\n if (this._direction === \"horizontal\") {\n position = evnt.clientX;\n } else {\n position = evnt.clientY;\n }\n\n this._dispatchDrag(position);\n\n return true;\n }\n\n /**\n * The resize cursor for this gutter's drag axis, shared by the hover state\n * and the drag itself so the two can never disagree.\n *\n * @returns The CSS cursor naming the axis the gutter resizes along.\n */\n private dragCursor(): string {\n return this._direction == \"horizontal\" ? \"ew-resize\" : \"ns-resize\";\n }\n\n /**\n * Applies the hover cursor for the gutter's current state. Only a movable\n * gutter in its divider state shows the axis resize cursor; a fixed Border\n * gutter, or a gutter in its collapsed strip state (which cannot be\n * dragged), shows the default cursor so it doesn't invite a resize.\n */\n private applyCursor(): void {\n if (this._movable && !this._opaque) {\n this.setCursor(this.dragCursor());\n } else {\n this.setCursor(\"default\");\n }\n }\n\n /**\n * Renders the gutter element and sets the appropriate resize cursor.\n *\n * @returns The created element with the correct resize cursor applied.\n */\n render() {\n let element = super.render();\n\n this.applyCursor();\n\n return element;\n }\n}\n\nconst SplitGutterCallable = callable(SplitGutter);\ntype SplitGutterCallable = SplitGutter;\nexport {\n SplitGutter as _SplitGutter,\n SplitGutterCallable as SplitGutter\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\"\nimport { Component } from \"~/core/Component.js\"\nimport { LayoutConstraints } from \"~/layout/LayoutConstraints.js\";\nimport { SplitGutter } from \"~/component/container/SplitGutter.js\";\nimport { CollapseDirection } from \"~/component/container/CollapseButton.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { Placement } from \"~/primitive/Placement.js\";\nimport { Size, UNBOUNDED, saturate } from \"~/primitive/Size.js\";\nimport { COLLAPSE_STRIP_SIZE, runCollapse, CollapseParticipant, CollapseTransition } from \"~/layout/CollapseSupport.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n// Pixel thickness of a region's transparent collapse track in its expanded\n// state — just enough to carry the (overflowing) chevron at the region's inner\n// edge. Mirrors `Split`'s GUTTER_SIZE so the two managers' divider tracks match.\nconst TRACK_SIZE = 4;\n\n// The way each region's chevron points (and the gutter travels) when collapsing\n// — toward the region's outer edge. The restore heading is its opposite,\n// handled by the gutter's `setOpaque`.\nconst COLLAPSE_CHEVRON: Record<string, CollapseDirection> = {\n [Placement.NORTH]: \"north\",\n [Placement.SOUTH]: \"south\",\n [Placement.WEST]: \"west\",\n [Placement.EAST]: \"east\",\n};\n\n/**\n * Construction-time options for the {@link Border} layout manager.\n *\n * @remarks Re-exported as `BorderLayoutOptions` from the package barrel to\n * disambiguate from the line-style `Border`'s {@link BorderOptions}.\n *\n * @category Layouts\n */\nexport interface BorderOptions extends LayoutManagerOptions {\n spacing?: number;\n}\n\n/**\n * A layout manager that divides a container into five named regions:\n * north, south, east, west, and center.\n * North and south regions span the full width; east and west regions flank the center.\n *\n * Exported from `@jimka/typescript-ui/layout`. Disambiguate from the line-style\n * [`Border`](/api/primitive/classes/Border) utility (in `@jimka/typescript-ui/primitive`)\n * by aliasing one of them on import — e.g. `import { Border as BorderLayout } from '@jimka/typescript-ui/layout';`.\n *\n * @category Layouts\n */\nclass Border extends LayoutManager {\n\n private _northComponent: Component | null = null;\n private _southComponent: Component | null = null;\n private _westComponent: Component | null = null;\n private _eastComponent: Component | null = null;\n private _centerComponent: Component | null = null;\n private _spacing: number = 5;\n\n // Per-region collapse state, keyed by placement. `_collapsed` and\n // `_collapsible` both default to false: collapsing is opt-in per region\n // (`collapsible: true` on the constraint), so a plain Border — including\n // the ones Header, Dialog, and the table panels use internally — never\n // sprouts collapse affordances. `_gutters` holds one lazily-created fixed\n // gutter per collapsible edge region — a transparent track carrying the\n // chevron when expanded, the opaque strip when collapsed. The child\n // component stays unaware it is collapsible — this is layout geometry, so\n // it lives here.\n private _collapsed: Map<Placement, boolean> = new Map<Placement, boolean>();\n private _collapsible: Map<Placement, boolean> = new Map<Placement, boolean>();\n private _gutters: Map<Placement, SplitGutter> = new Map<Placement, SplitGutter>();\n\n // Canceller for the in-flight region collapse/restore animation, or null\n // when idle. Calling it stops the rAF loop in place so a rapid re-toggle\n // re-snapshots and retargets without two loops fighting.\n private _collapseAnimation: (() => void) | null = null;\n\n // Collapse/restore CSS transitions primed by `runCollapse` that have not\n // settled yet. Cancelled on detach so their fallback timers cannot fire\n // against released element handles. Held separately from\n // `_collapseAnimation` because that field is nulled when the geometry\n // animation settles — ~40ms before these fallbacks disarm — and is replaced\n // outright by a re-toggle while these may still be running.\n private readonly _pendingCollapseTransitions: CollapseTransition[] = [];\n\n // True while a collapse/restore animation is being driven. The animation\n // slides every region by writing each element's own `left`/`top` (via\n // `CollapseSupport.commitRect`'s `setX`/`setY`), which a clip frame defeats\n // because the frame — not the element — carries a framed region's position\n // and the element sits parked at `(0, 0)` inside it. While this is set,\n // `doLayout` lays every region out unframed (plain `placeComponent`) so the\n // animation can move them; the steady-state frames are reinstated by the\n // final `doLayout` once the animation settles.\n private _collapsing: boolean = false;\n\n constructor(options?: BorderOptions) {\n // LayoutManager's constructor takes no options; applied via applyOptions below.\n // eslint-disable-next-line local/forward-super-options\n super();\n\n if (options) {\n this.applyOptions(options);\n }\n }\n\n /**\n * Applies a {@link BorderOptions} bag, dispatching the inter-region spacing\n * after the inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: BorderOptions): void {\n super.applyOptions(options);\n\n if (options.spacing !== undefined) {\n this.setComponentSpacing(options.spacing);\n }\n }\n\n /**\n * Registers a component in the north, south, east, west, or center slot\n * based on `constraints.placement`.\n *\n * @param component - The component to register.\n * @param constraints - Optional. Layout constraints specifying the target placement slot.\n *\n * @returns The resolved constraints object, or `undefined` if none were provided.\n *\n * @remarks When `constraints` or `constraints.placement` is absent the component\n * defaults to the center slot.\n */\n setLayoutConstraints(component: Component, constraints?: LayoutConstraints): LayoutConstraints | undefined {\n if (!constraints) {\n constraints = new LayoutConstraints();\n constraints.placement = Placement.CENTER;\n }\n\n if (!constraints.placement) {\n constraints.placement = Placement.CENTER;\n }\n\n switch (constraints.placement) {\n case Placement.NORTH:\n this._northComponent = component;\n break;\n case Placement.SOUTH:\n this._southComponent = component;\n break;\n case Placement.WEST:\n this._westComponent = component;\n break;\n case Placement.EAST:\n this._eastComponent = component;\n break;\n case Placement.CENTER:\n this._centerComponent = component;\n break;\n }\n\n // The center is never collapsible; every edge region defaults to\n // non-collapsible and opts in via `collapsible: true`.\n if (constraints.placement === Placement.CENTER) {\n this._collapsible.set(Placement.CENTER, false);\n } else {\n this._collapsible.set(constraints.placement, constraints.collapsible ?? false);\n }\n\n return super.setLayoutConstraints(component, constraints);\n }\n\n /**\n * Clears the region slot a component occupied when it is removed from the\n * container. Without this the region reference goes stale: a component moved\n * out of a `Border` container (e.g. a window's content panel re-homed\n * elsewhere) would still be held as that region's child and re-sized by this\n * manager on its next `doLayout`, fighting its new parent's layout.\n *\n * @param component - The component being removed.\n * @returns The removed constraints, or `undefined` if none were stored.\n */\n delLayoutConstraints(component: Component): LayoutConstraints | undefined {\n if (this._northComponent === component) {\n this._northComponent = null;\n } else if (this._southComponent === component) {\n this._southComponent = null;\n } else if (this._westComponent === component) {\n this._westComponent = null;\n } else if (this._eastComponent === component) {\n this._eastComponent = null;\n } else if (this._centerComponent === component) {\n this._centerComponent = null;\n }\n\n return super.delLayoutConstraints(component);\n }\n\n /**\n * Returns the pixel spacing between adjacent border regions.\n *\n * @returns The current spacing in pixels.\n */\n getComponentSpacing() {\n return this._spacing;\n }\n\n /**\n * Sets the pixel spacing between adjacent border regions.\n *\n * @param spacing - Spacing size in pixels.\n */\n setComponentSpacing(spacing: number) : this {\n this._spacing = spacing;\n\n return this;\n }\n\n /**\n * Returns the component currently registered in the given region slot.\n *\n * @param placement - The region to look up.\n * @returns The region's component, or `null` if the slot is empty.\n */\n private getRegionComponent(placement: Placement): Component | null {\n switch (placement) {\n case Placement.NORTH: return this._northComponent;\n case Placement.SOUTH: return this._southComponent;\n case Placement.WEST: return this._westComponent;\n case Placement.EAST: return this._eastComponent;\n case Placement.CENTER: return this._centerComponent;\n }\n }\n\n /**\n * Returns whether the given region is collapsed.\n *\n * @param placement - The region to query.\n * @returns True when the region is collapsed.\n */\n isRegionCollapsed(placement: Placement): boolean {\n return this._collapsed.get(placement) ?? false;\n }\n\n /**\n * Collapses or restores an edge region, animating the change. The region's\n * gutter slides from its inner edge to its outer edge and widens into the\n * opaque collapse strip (cross-fading its fill) while the region keeps its\n * full size and reveals via a clip-path; the center grows into the reclaimed\n * space. The whole pass is one coordinated animation: the toggled region\n * clip-reveals while the center and the gutter interpolate their geometry —\n * re-laying out their contents each frame — in lockstep (see\n * `CollapseSupport.runCollapse`). The center cannot be collapsed and a\n * non-collapsible region ignores a collapse request.\n *\n * @param placement - The region to collapse or restore.\n * @param collapsed - True to collapse, false to restore.\n * @returns This layout manager, for method chaining.\n */\n setRegionCollapsed(placement: Placement, collapsed: boolean): this {\n if (placement === Placement.CENTER || !this.isRegionCollapsible(placement)) {\n return this;\n }\n\n const component = this.getRegionComponent(placement);\n if (!component) {\n return this;\n }\n\n const current = this._collapsed.get(placement) ?? false;\n if (current === collapsed) {\n return this;\n }\n\n const container = this.getContainer();\n if (!container) {\n return this;\n }\n\n // Enter the animated phase before laying out the start state. When no\n // animation is already running the regions are clip-framed, parked at\n // `(0, 0)` inside frames that carry their real position; this `doLayout`\n // (now that `_collapsing` is set) re-lays them out unframed at their\n // current pre-toggle position, so each element's own `left`/`top` holds\n // the real start that `runCollapse` snapshots — a framed element would\n // otherwise snapshot `(0, 0)` and never move. A re-toggle mid-animation\n // is already unframed (its elements hold live interpolated positions),\n // so it skips this and lets `runCollapse` re-snapshot the live geometry\n // for a smooth retarget.\n const wasAnimating = this._collapsing;\n this._collapsing = true;\n\n if (!wasAnimating) {\n container.doLayout();\n }\n\n this._collapsed.set(placement, collapsed);\n\n // Materialise the region's gutter so it joins the participant list.\n this.ensureGutter(placement);\n\n // Every box that moves: the regions (content re-laid-out each frame) and\n // the gutters (geometry only). The toggled region is among them and also\n // clip-reveals; `runCollapse` coordinates the whole pass.\n const regions = [this._northComponent, this._southComponent, this._westComponent, this._eastComponent, this._centerComponent]\n .filter((c): c is Component => c != null);\n\n const participants: CollapseParticipant[] = [\n ...regions.map(region => ({ component: region, relayout: true })),\n ...[...this._gutters.values()].map(gutter => ({ component: gutter, relayout: false })),\n ];\n\n this._collapseAnimation = runCollapse(container, component, participants, this._collapseAnimation, this._pendingCollapseTransitions, () => {\n this._collapseAnimation = null;\n\n // Leave the animated phase and re-lay-out so the non-collapsible\n // regions get their steady-state clip frames back.\n this._collapsing = false;\n\n container.doLayout();\n });\n\n return this;\n }\n\n /**\n * Returns whether the given region may be collapsed. The center is never\n * collapsible; edge regions are non-collapsible unless they opt in with\n * `collapsible: true` on their constraint.\n *\n * @param placement - The region to query.\n * @returns True when the region may be collapsed.\n */\n isRegionCollapsible(placement: Placement): boolean {\n if (placement === Placement.CENTER) {\n return false;\n }\n\n return this._collapsible.get(placement) ?? false;\n }\n\n /**\n * Sets whether an edge region may be collapsed. Hides the collapse chevron\n * when set false; the center is always non-collapsible regardless.\n *\n * @param placement - The region to configure.\n * @param value - True to allow collapsing, false to opt out.\n * @returns This layout manager, for method chaining.\n */\n setRegionCollapsible(placement: Placement, value: boolean): this {\n if (placement === Placement.CENTER) {\n return this;\n }\n\n this._collapsible.set(placement, value);\n\n this.getContainer()?.scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the existing fixed gutter for a region, creating and wiring it on\n * first use. The gutter is non-movable, transparent in its divider state,\n * and carries the chevron pointing toward the region's outer edge; its\n * double-click collapses the region.\n *\n * @param placement - The region the gutter collapses.\n * @returns The region's gutter.\n */\n private ensureGutter(placement: Placement): SplitGutter {\n let gutter = this._gutters.get(placement);\n if (gutter) {\n return gutter;\n }\n\n const container = this.getContainer()!;\n const vertical = placement === Placement.NORTH || placement === Placement.SOUTH;\n\n gutter = new SplitGutter(vertical ? \"vertical\" : \"horizontal\", {\n movable: false,\n opaque: false,\n collapseDirection: COLLAPSE_CHEVRON[placement],\n expandedBackground: \"transparent\",\n listeners: { collapse: () => this.setRegionCollapsed(placement, !this.isRegionCollapsed(placement)) },\n });\n\n gutter.setVisible(false);\n\n DOM.sink.appendChild(container.getElement()!, gutter.getElement(true)!);\n\n this._gutters.set(placement, gutter);\n\n return gutter;\n }\n\n /**\n * Returns a region's effective edge extent: the strip thickness when the\n * region is collapsed, otherwise the region's own preferred main-axis size.\n *\n * @param placement - The edge region.\n * @param preferred - The region's preferred main-axis extent (width for\n * west/east, height for north/south).\n * @returns The extent to reserve for the region in `doLayout`.\n */\n private regionExtent(placement: Placement, preferred: number): number {\n return this.isRegionCollapsed(placement) ? COLLAPSE_STRIP_SIZE : preferred;\n }\n\n /**\n * Floors a region's preferred main-axis extent at the region component's\n * own minimum main-axis extent, so a region whose consumer pinned a\n * sub-minimum `preferredSize` is still reserved — and clip-framed — at the\n * size the component clamps itself up to on commit. Mirrors\n * {@link VBox.preferredChildHeight} / {@link HBox.preferredChildWidth}.\n * Reading the region's `getMinSize()` here is a non-recursive sibling call,\n * not a re-entry into this manager's own size gathering.\n *\n * @param preferred - The region's preferred main-axis extent.\n * @param min - The region's min-size, or null.\n * @param vertical - True for NORTH/SOUTH (height axis), false for WEST/EAST (width axis).\n * @returns `max(preferred, region min on the main axis)`.\n */\n private flooredMainExtent(preferred: number, min: Size | null, vertical: boolean): number {\n const minMain = min ? (vertical ? min.height : min.width) : 0;\n\n return Math.max(preferred, minMain);\n }\n\n /**\n * Clips a region's element toward its outer edge for the current collapse\n * state. The component is always laid out at its full size; collapsing\n * progressively clips it away (animated via a `clip-path` transition) so the\n * region visibly retreats into the strip rather than vanishing instantly,\n * mirroring the expand. Expanded, the clip is cleared. `clip-path` also\n * suppresses pointer events on the clipped-away area, so the hidden region\n * doesn't intercept clicks meant for the grown centre.\n *\n * @param component - The region's component.\n * @param placement - The edge region, which fixes the clip direction.\n */\n private applyRegionClip(component: Component, placement: Placement): void {\n // Never clip a region that can't collapse: `clip-path` establishes a\n // stacking context and a containing block for fixed descendants, which\n // could disturb a plain region's popovers. Only collapsible regions —\n // which need `inset(0)` as the transition's expanded keyframe — get it.\n if (!this.isRegionCollapsible(placement)) {\n return;\n }\n\n if (!this.isRegionCollapsed(placement)) {\n component.setClipPath(\"inset(0 0 0 0)\");\n\n return;\n }\n\n switch (placement) {\n case Placement.WEST: component.setClipPath(\"inset(0 100% 0 0)\"); break;\n case Placement.EAST: component.setClipPath(\"inset(0 0 0 100%)\"); break;\n case Placement.NORTH: component.setClipPath(\"inset(0 0 100% 0)\"); break;\n case Placement.SOUTH: component.setClipPath(\"inset(100% 0 0 0)\"); break;\n }\n }\n\n /**\n * Positions a region's single gutter for the region's current state: a\n * transparent track at the inner edge (carrying the chevron) when expanded,\n * the opaque strip filling the region's strip-sized rect when collapsed. The\n * region component is hidden while collapsed. No gutter is shown for a\n * non-collapsible region.\n *\n * @param placement - The edge region.\n * @param x - The region's left position.\n * @param y - The region's top position.\n * @param width - The region's width (strip-sized when collapsed).\n * @param height - The region's height (strip-sized when collapsed for north/south).\n */\n private updateRegionGutter(placement: Placement, x: number, y: number, width: number, height: number): void {\n const component = this.getRegionComponent(placement);\n if (!component) {\n return;\n }\n\n if (!this.isRegionCollapsible(placement)) {\n component.setVisible(true);\n this._gutters.get(placement)?.setVisible(false);\n\n return;\n }\n\n const collapsed = this.isRegionCollapsed(placement);\n const gutter = this.ensureGutter(placement);\n\n // The region stays visible and laid out at full size; `applyRegionClip`\n // clips it away while collapsed (it can't shrink past its min-size), so\n // the gutter strip is what reads as the collapsed region.\n component.setVisible(true);\n\n gutter.setOpaque(collapsed);\n gutter.setVisible(true);\n\n // Collapsed: the gutter fills the region's strip-sized rect. Expanded:\n // a thin transparent track in the gap just past the region's\n // center-facing edge, where the chevron reads naturally.\n const rect = collapsed ? { x, y, width, height } : this.innerEdgeTrack(placement, x, y, width, height);\n\n gutter.setX(rect.x);\n gutter.setY(rect.y);\n gutter.setWidth(rect.width);\n gutter.setHeight(rect.height);\n }\n\n /**\n * Computes the thin transparent track rect in the gap just past a region's\n * center-facing edge, where the expanded gutter parks its chevron. The\n * track sits flush against the region's outer edge of the gap rather than\n * overlapping the region's own content.\n *\n * @param placement - The edge region.\n * @param x - The region's left position.\n * @param y - The region's top position.\n * @param width - The region's width.\n * @param height - The region's height.\n * @returns The track rect.\n */\n private innerEdgeTrack(placement: Placement, x: number, y: number, width: number, height: number): { x: number; y: number; width: number; height: number } {\n switch (placement) {\n case Placement.NORTH: return { x, y: y + height, width, height: TRACK_SIZE };\n case Placement.SOUTH: return { x, y: y - TRACK_SIZE, width, height: TRACK_SIZE };\n case Placement.WEST: return { x: x + width, y, width: TRACK_SIZE, height };\n case Placement.EAST: return { x: x - TRACK_SIZE, y, width: TRACK_SIZE, height };\n default: return { x, y, width, height };\n }\n }\n\n /**\n * Resolves a slot component for layout: a non-displayed region component is\n * treated as an empty slot (`null`), so a `display: none` region reserves no\n * space and is not placed — the same outcome as removing it from the region.\n * Every slot read in the size/layout methods routes through this so the\n * \"hidden = absent\" rule is uniform.\n *\n * @param component - The slot component, or `null` when the region is empty.\n * @returns The component when present and displayed, otherwise `null`.\n */\n private laidOut(component: Component | null): Component | null {\n return component && component.isDisplayed() ? component : null;\n }\n\n /**\n * Computes the preferred size by summing the preferred sizes of all occupied border regions.\n *\n * @returns The preferred `{width, height}` or `null` if no container is attached.\n */\n getPreferredSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let innerWidth = 0;\n let innerHeight = 0;\n\n let middleWidth = 0;\n let middleHeight = 0;\n\n // A non-displayed region is treated as absent, contributing nothing.\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n if (north) {\n let size = north.getPreferredSize();\n if (size) {\n const flooredHeight = this.flooredMainExtent(size.height, north.getMinSize(), true);\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : flooredHeight;\n }\n }\n\n if (south) {\n let size = south.getPreferredSize();\n if (size) {\n const flooredHeight = this.flooredMainExtent(size.height, south.getMinSize(), true);\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : flooredHeight;\n }\n }\n\n if (west) {\n let size = west.getPreferredSize();\n if (size) {\n const flooredWidth = this.flooredMainExtent(size.width, west.getMinSize(), false);\n middleWidth += this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : flooredWidth;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (center) {\n let size = center.getPreferredSize();\n if (size) {\n middleWidth += size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (east) {\n let size = east.getPreferredSize();\n if (size) {\n const flooredWidth = this.flooredMainExtent(size.width, east.getMinSize(), false);\n middleWidth += this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : flooredWidth;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n innerWidth = Math.max(innerWidth, middleWidth);\n innerHeight += middleHeight;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Computes the minimum size by summing the minimum sizes of all occupied border regions.\n *\n * @returns The minimum `{width, height}` or `null` if no container is attached.\n */\n getMinSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n let innerWidth = 0;\n let innerHeight = 0;\n\n let middleWidth = 0;\n let middleHeight = 0;\n\n // A non-displayed region is treated as absent, contributing nothing.\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n if (north) {\n let size = north.getMinSize();\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : size.height;\n }\n }\n\n if (south) {\n let size = south.getMinSize();\n if (size) {\n innerWidth = Math.max(innerWidth, size.width);\n innerHeight += this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : size.height;\n }\n }\n\n if (west) {\n let size = west.getMinSize();\n if (size) {\n middleWidth += this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (center) {\n let size = center.getMinSize();\n if (size) {\n middleWidth += size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n if (east) {\n let size = east.getMinSize();\n if (size) {\n middleWidth += this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : size.width;\n middleHeight = Math.max(middleHeight, size.height);\n }\n }\n\n innerWidth = Math.max(innerWidth, middleWidth);\n innerHeight += middleHeight;\n\n return {\n width: innerWidth + outerWidth,\n height: innerHeight + outerHeight\n };\n }\n\n /**\n * Computes the maximum size the border layout can usefully occupy. The five\n * regions stack as three rows that share one width: north (full width), the\n * middle row of west + center + east (summed across, tallest of the three\n * down), and south (full width). The width is capped to the narrowest row\n * that exists — a region cannot usefully widen the border past where its own\n * row stops growing — and the height is the sum of the three row heights.\n * An absent region imposes no constraint; an unbounded region contributes\n * the unbounded sentinel.\n *\n * @returns The maximum `{width, height}` or `null` if no container is attached.\n */\n getMaxSize(): Size | null {\n let container = this.getContainer();\n if (!container) {\n return null;\n }\n\n let perimeterSize = container.getPerimeterSize();\n\n let outerWidth = perimeterSize.left + perimeterSize.right;\n let outerHeight = perimeterSize.top + perimeterSize.bottom;\n\n // A non-displayed region resolves to null here (no constraint), not the\n // unbounded sentinel — it must not widen/heighten the layout at all.\n const maxOf = (component: Component | null): Size | null =>\n this.laidOut(component) ? (component!.getMaxSize() ?? { width: UNBOUNDED, height: UNBOUNDED }) : null;\n\n const north = maxOf(this._northComponent);\n const south = maxOf(this._southComponent);\n const west = maxOf(this._westComponent);\n const center = maxOf(this._centerComponent);\n const east = maxOf(this._eastComponent);\n\n // Middle row: west / center / east sit side by side — widths sum, the\n // row height is the tallest region.\n let middleWidth = 0;\n let middleHeight = 0;\n let hasMiddle = false;\n\n for (const region of [west, center, east]) {\n if (region) {\n hasMiddle = true;\n middleWidth += region.width;\n middleHeight = Math.max(middleHeight, region.height);\n }\n }\n\n // Width is shared by every row; cap to the narrowest existing row.\n let innerWidth = UNBOUNDED;\n if (north) { innerWidth = Math.min(innerWidth, north.width); }\n if (south) { innerWidth = Math.min(innerWidth, south.width); }\n if (hasMiddle) { innerWidth = Math.min(innerWidth, middleWidth); }\n\n // Height stacks the three rows.\n let innerHeight = 0;\n if (north) { innerHeight += north.height; }\n if (hasMiddle) { innerHeight += middleHeight; }\n if (south) { innerHeight += south.height; }\n\n return {\n width: saturate(innerWidth + outerWidth),\n height: saturate(innerHeight + outerHeight)\n };\n }\n\n /**\n * Computes the children's combined minSize along this manager's\n * 5-region geometry: width = west.minWidth + center.minWidth +\n * east.minWidth + gaps; height = north.minHeight + center.minHeight +\n * south.minHeight + gaps. Used by `doLayout` to inflate the working\n * size when the host has opted into `setOverflowing`.\n *\n * @returns The total min-size; `{ width: 0, height: 0 }` when the\n * container is absent.\n */\n protected computeTotalMinSize(): Size {\n const container = this.getContainer();\n if (!container) {\n return { width: 0, height: 0 };\n }\n\n // A non-displayed region is treated as absent (laidOut → null), so it\n // contributes no min-size to the total.\n const westMin = this.laidOut(this._westComponent) ?.getMinSize();\n const centerMin = this.laidOut(this._centerComponent)?.getMinSize();\n const eastMin = this.laidOut(this._eastComponent) ?.getMinSize();\n const northMin = this.laidOut(this._northComponent) ?.getMinSize();\n const southMin = this.laidOut(this._southComponent) ?.getMinSize();\n\n // Horizontal regions contribute to width; vertical regions contribute\n // to height. Each inter-region gap is added only when both adjacent\n // regions exist so single-region layouts (only center, for instance)\n // don't gain phantom gap pixels. A collapsed edge region contributes\n // only the strip thickness along its collapse axis.\n const hContribs: number[] = [];\n if (westMin) { hContribs.push(this.isRegionCollapsed(Placement.WEST) ? COLLAPSE_STRIP_SIZE : westMin.width); }\n if (centerMin) { hContribs.push(centerMin.width); }\n if (eastMin) { hContribs.push(this.isRegionCollapsed(Placement.EAST) ? COLLAPSE_STRIP_SIZE : eastMin.width); }\n\n const vContribs: number[] = [];\n if (northMin) { vContribs.push(this.isRegionCollapsed(Placement.NORTH) ? COLLAPSE_STRIP_SIZE : northMin.height); }\n if (centerMin) { vContribs.push(centerMin.height); }\n if (southMin) { vContribs.push(this.isRegionCollapsed(Placement.SOUTH) ? COLLAPSE_STRIP_SIZE : southMin.height); }\n\n let width = 0;\n let height = 0;\n\n for (const w of hContribs) {\n width += w;\n }\n width += Math.max(0, hContribs.length - 1) * this._spacing;\n\n // For width we also need to ensure the height-region's own width is\n // honoured: the center column may need at least the wider of\n // north.minWidth / south.minWidth (which span the full row).\n if (northMin) {\n width = Math.max(width, northMin.width);\n }\n if (southMin) {\n width = Math.max(width, southMin.width);\n }\n\n for (const h of vContribs) {\n height += h;\n }\n height += Math.max(0, vContribs.length - 1) * this._spacing;\n\n return { width, height };\n }\n\n /**\n * Clears the clip frame of every region that `doLayout` will skip because it\n * resolved to `null` (a non-displayed region), so a `display: none` region\n * does not leave its `overflow: hidden` wrapper orphaned around the hidden\n * element until the region is shown again.\n *\n * @param laidOutRegions - The `laidOut` results for north, south, west,\n * center, and east; a `null` entry marks a region `doLayout` will skip.\n */\n private clearSkippedRegionFrames(...laidOutRegions: (Component | null)[]): void {\n const rawRegions = [\n this._northComponent,\n this._southComponent,\n this._westComponent,\n this._centerComponent,\n this._eastComponent\n ];\n\n rawRegions.forEach((component, index) => {\n if (component && !laidOutRegions[index]) {\n component.clearClipFrame();\n }\n });\n }\n\n /**\n * Positions north, south, east, west, and center children within the container's inner bounds.\n *\n * @remarks The north component may opt out of parent insets via `constraints.ignoreParentInsets`,\n * which is useful for components such as toolbars that should span the full container width.\n */\n doLayout() {\n let container = this.getContainer();\n if (!container) {\n return;\n }\n\n // The container has no element yet (e.g. laid out before it is\n // rendered, as an autoScroll host's synchronous setOverflowing pass\n // can do to a not-yet-mounted child); defer to the next pass, which\n // every other layout manager (HBox, VBox, Grid, Split, Tab) already\n // does in this situation.\n let containerSize = container.getInnerSize();\n if (!containerSize) {\n return;\n }\n\n let containerInsets = container.getContentInsets();\n\n // Universal scroll: see HBox.doLayout for the rationale. Inflates the\n // working size to the children's combined minSize on the axes the\n // host has marked as overflowing.\n containerSize = this.inflateForOverflow(containerSize);\n\n // Resolve every region through laidOut so a non-displayed region is\n // treated as absent: skipped for placement and excluded from the\n // adjacent-region gap checks below — the same outcome as an empty slot.\n // This also keeps the preferred-size throws below unreachable for a\n // hidden region (its `if` block is skipped entirely).\n const north = this.laidOut(this._northComponent);\n const south = this.laidOut(this._southComponent);\n const west = this.laidOut(this._westComponent);\n const center = this.laidOut(this._centerComponent);\n const east = this.laidOut(this._eastComponent);\n\n // A non-displayed region is skipped by its `if (region)` block below, so\n // its clip frame is never re-driven or cleared there. Clear it now on the\n // raw component so a `display: none` region doesn't orphan its\n // `overflow: hidden` wrapper around the hidden element; clearClipFrame is\n // a no-op when no frame is active.\n this.clearSkippedRegionFrames(north, south, west, center, east);\n\n let width = containerSize.width;\n let height = containerSize.height;\n let centerX;\n let middleY;\n let centerWidth;\n let middleHeight;\n\n if (north) {\n let constraints = this.getLayoutConstraints(north);\n if (!constraints) {\n throw new Error(\"Unable to determine layout constraints for north component.\");\n }\n\n let preferredSize = north.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for north component.\");\n }\n\n const northExtent = this.flooredMainExtent(preferredSize.height, north.getMinSize(), true);\n let northHeight = this.regionExtent(Placement.NORTH, northExtent);\n let northX = constraints.ignoreParentInsets ? 0 : containerInsets.getLeft();\n let northY = constraints.ignoreParentInsets ? 0 : containerInsets.getTop();\n let northWidth = width + (constraints.ignoreParentInsets ? containerInsets.getLeft() + containerInsets.getRight() : 0);\n let northInsetTop = constraints.ignoreParentInsets ? containerInsets.getTop() : 0;\n\n middleY = northHeight + northInsetTop;\n\n // The region is always laid out at full size and clipped toward its\n // outer edge while collapsed; the centre and gutter use the strip\n // extent (`middleY`) so they grow into the reclaimed space. While a\n // collapse animates, every region takes the unframed path so its own\n // `left`/`top` can be interpolated (a frame would freeze it).\n if (this.isRegionCollapsible(Placement.NORTH) || this._collapsing) {\n this.placeComponent(\n north,\n northX,\n northY,\n northWidth,\n northExtent + northInsetTop,\n FillType.BOTH\n );\n north.clearClipFrame();\n this.applyRegionClip(north, Placement.NORTH);\n } else {\n // Containment via clip frame: an oversized or mis-sized region's\n // own box is clipped to its allocated rect rather than bleeding\n // over the adjacent region. Clear any stale clip-path left by a\n // prior collapsible state (setRegionCollapsible can flip a region\n // at runtime); this branch never calls applyRegionClip.\n north.setClipPath(null);\n north.setClipFrame(northX, northY, northWidth, northExtent + northInsetTop);\n this.commitBounds(north, 0, 0, northWidth, northExtent + northInsetTop);\n }\n\n this.updateRegionGutter(Placement.NORTH, northX, northY, northWidth, middleY);\n\n if (west || center || east || south) {\n middleY += this._spacing;\n }\n } else {\n middleY = 0;\n }\n\n middleHeight = height - middleY;\n if (south) {\n let preferredSize = south.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for south component.\");\n }\n\n const southExtent = this.flooredMainExtent(preferredSize.height, south.getMinSize(), true);\n let southHeight = this.regionExtent(Placement.SOUTH, southExtent);\n let southX = containerInsets.getLeft();\n let southY = containerInsets.getTop() + height - southHeight;\n\n middleHeight -= this._spacing;\n middleHeight -= southHeight;\n\n // Full-size and bottom-anchored, clipped toward the bottom while\n // collapsed; the gutter uses the strip rect (`southY`/`southHeight`).\n let southFullY = containerInsets.getTop() + height - southExtent;\n\n if (this.isRegionCollapsible(Placement.SOUTH) || this._collapsing) {\n this.placeComponent(\n south,\n southX,\n southFullY,\n width,\n southExtent,\n FillType.BOTH\n );\n south.clearClipFrame();\n this.applyRegionClip(south, Placement.SOUTH);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full position equals the strip position, so the\n // element commits at (0, 0) inside the frame.\n south.setClipPath(null);\n south.setClipFrame(southX, southFullY, width, southExtent);\n this.commitBounds(south, 0, 0, width, southExtent);\n }\n\n this.updateRegionGutter(Placement.SOUTH, southX, southY, width, southHeight);\n }\n\n // Reserve east's preferred width up front so west can be clamped\n // to avoid overlapping east when west.preferred + east.preferred\n // exceeds the container width (e.g. a Window header where the\n // title is wider than the available space between the icon and\n // the trailing buttons).\n let eastPreferredWidth = 0;\n let eastFullWidth = 0;\n if (east) {\n let eastPreferred = east.getPreferredSize();\n if (!eastPreferred) {\n throw new Error(\"Unable to determine preferred size for east component.\");\n }\n const eastExtent = this.flooredMainExtent(eastPreferred.width, east.getMinSize(), false);\n eastFullWidth = eastExtent;\n eastPreferredWidth = this.regionExtent(Placement.EAST, eastExtent);\n }\n\n if (west) {\n let preferredSize = west.getPreferredSize();\n if (!preferredSize) {\n throw new Error(\"Unable to determine preferred size for west component.\");\n }\n\n const westExtent = this.flooredMainExtent(preferredSize.width, west.getMinSize(), false);\n let westWidth = Math.max(0, Math.min(this.regionExtent(Placement.WEST, westExtent), width - eastPreferredWidth));\n let westX = containerInsets.getLeft();\n let westY = containerInsets.getTop() + middleY;\n\n centerX = westWidth;\n\n // Full-size and left-anchored, clipped toward the left while\n // collapsed; the centre and gutter use the strip extent (`westWidth`).\n let westFullWidth = Math.max(0, Math.min(westExtent, width - eastPreferredWidth));\n\n if (this.isRegionCollapsible(Placement.WEST) || this._collapsing) {\n this.placeComponent(\n west,\n westX,\n westY,\n westFullWidth,\n middleHeight,\n FillType.BOTH\n );\n west.clearClipFrame();\n this.applyRegionClip(west, Placement.WEST);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full width equals the strip width, so the\n // element commits at (0, 0) inside the frame.\n west.setClipPath(null);\n west.setClipFrame(westX, westY, westFullWidth, middleHeight);\n this.commitBounds(west, 0, 0, westFullWidth, middleHeight);\n }\n\n this.updateRegionGutter(Placement.WEST, westX, westY, westWidth, middleHeight);\n\n if (center) {\n centerX += this._spacing;\n }\n } else {\n centerX = 0;\n }\n\n centerWidth = width - centerX;\n\n if (east) {\n centerWidth -= this._spacing;\n centerWidth -= eastPreferredWidth;\n\n let eastX = containerInsets.getLeft() + width - eastPreferredWidth;\n let eastY = containerInsets.getTop() + middleY;\n\n // Full-size and right-anchored, clipped toward the right while\n // collapsed; the gutter uses the strip rect (`eastX`/`eastPreferredWidth`).\n let eastFullX = containerInsets.getLeft() + width - eastFullWidth;\n\n if (this.isRegionCollapsible(Placement.EAST) || this._collapsing) {\n this.placeComponent(\n east,\n eastFullX,\n eastY,\n eastFullWidth,\n middleHeight,\n FillType.BOTH\n );\n east.clearClipFrame();\n this.applyRegionClip(east, Placement.EAST);\n } else {\n // Containment via clip frame; see the NORTH branch. The\n // non-collapsible full position equals the strip position, so the\n // element commits at (0, 0) inside the frame.\n east.setClipPath(null);\n east.setClipFrame(eastFullX, eastY, eastFullWidth, middleHeight);\n this.commitBounds(east, 0, 0, eastFullWidth, middleHeight);\n }\n\n this.updateRegionGutter(Placement.EAST, eastX, eastY, eastPreferredWidth, middleHeight);\n }\n\n if (center) {\n let centerLeft = containerInsets.getLeft() + centerX;\n let centerTop = containerInsets.getTop() + middleY;\n\n // CENTER is never collapsible, so outside an animation it always\n // takes the frame branch and never carries a clip-path. Its rect is\n // its own allocation (it can never overflow it), so the frame is a\n // perfect-fit sheath that clips nothing — keeping one code path for\n // the non-collapsible case. While a collapse animates, CENTER grows\n // into the reclaimed space, so it takes the unframed path so its own\n // `left`/`top` can be interpolated.\n if (this._collapsing) {\n this.placeComponent(center, centerLeft, centerTop, centerWidth, middleHeight, FillType.BOTH);\n center.clearClipFrame();\n } else {\n center.setClipFrame(centerLeft, centerTop, centerWidth, middleHeight);\n this.commitBounds(center, 0, 0, centerWidth, middleHeight);\n }\n }\n }\n\n /**\n * Detaches from the container, removing every lazily-created collapse gutter\n * from the DOM and tearing down its event listeners so a layout-manager swap\n * leaves no orphaned affordances. Also clears the clip frame installed on\n * each non-collapsible region: when Border is swapped out but its regions\n * stay mounted, a successor manager that doesn't drive clip frames would\n * otherwise leave Border's `overflow: hidden` wrapper orphaned around the\n * region element. `clearClipFrame` is a no-op for an unframed region.\n */\n detach(): this {\n // Abandon any in-flight collapse first: the primed CSS transitions\n // carry fallback timers that would otherwise outlive the element\n // handles teardown releases.\n this._collapseAnimation?.();\n this._collapseAnimation = null;\n\n // That canceller's `onIdle` is the only place `_collapsing` is cleared,\n // and cancelling suppressed it. Left set, a swapped-out-then-reattached\n // Border takes the unframed / clearClipFrame branch for every region\n // forever, so the clip frames never come back.\n this._collapsing = false;\n\n // Two shapes of detach. A manager swap leaves the panes mounted, so\n // their primed transitions must be settled — cleared — or each keeps a\n // live transition and a permanent compositor layer. A dispose reaches\n // here from `Component.destructor`, which already destroyed the\n // children (so `getComponents()` is empty), and touching one would\n // write through a released element handle: cancel silently instead.\n const survives = (this.getContainer()?.getComponents().length ?? 0) > 0;\n\n for (const transition of this._pendingCollapseTransitions) {\n if (survives) {\n transition.settle();\n } else {\n transition.cancel();\n }\n }\n this._pendingCollapseTransitions.length = 0;\n\n super.detach();\n\n for (const gutter of this._gutters.values()) {\n const element = gutter.getElement();\n const parent = element ? DOM.source.getParentNode(element) : null;\n\n if (element && parent) {\n DOM.sink.removeChild(parent, element);\n }\n\n gutter.dispose();\n }\n\n this._gutters.clear();\n\n for (const placement of [Placement.NORTH, Placement.SOUTH, Placement.WEST, Placement.EAST, Placement.CENTER]) {\n this.getRegionComponent(placement)?.clearClipFrame();\n }\n\n return this;\n }\n}\n\nconst BorderCallable = callable(Border);\ntype BorderCallable = Border;\nexport {\n Border as _Border,\n BorderCallable as Border\n};\n"],"mappings":"sWA4BA,SAAgB,iBAAiB,EAAsB,CACnD,EAAI,KAAK,MAAM,EAAI,OAAO,QAAQ,EAAG,CAAE,MAAO,CAAE,cAAe,MAAO,CAAE,CAAC,EACzE,EAAI,KAAK,MAAM,EAAI,OAAO,mBAAmB,EAAG,CAAE,MAAO,CAAE,QAAO,CAAE,CAAC,CACzE,CAOA,SAAgB,gBAAuB,CACnC,EAAI,KAAK,MAAM,EAAI,OAAO,QAAQ,EAAG,CAAE,MAAO,CAAE,cAAe,EAAG,CAAE,CAAC,EACrE,EAAI,KAAK,MAAM,EAAI,OAAO,mBAAmB,EAAG,CAAE,MAAO,CAAE,OAAQ,EAAG,CAAE,CAAC,CAC7E,CCvBA,IAAM,EAAoB,IAMpB,EAAkB,+BAGlB,EAAsC,CAAE,WAAoB,CAAC,CAAE,EAoCrE,SAAS,MACL,EACA,EACI,CACJ,IAAI,EAAmC,KACnC,EAAU,GAER,UAAoB,CACtB,EAAU,GAEV,IAAM,EAAQ,IAAU,KAAO,GAAK,EAAQ,QAAQ,CAAK,EAErD,GAAS,GACT,EAAQ,OAAO,EAAO,CAAC,CAE/B,EAEM,CAAE,SAAQ,WAAY,EAAO,KAAK,EAKpC,IAIJ,EAAQ,CACJ,WAAoB,EAAO,OAAO,EAClC,WAAoB,CAChB,EAAO,OAAO,EACd,EAAQ,CACZ,CACJ,EAEA,EAAQ,KAAK,CAAK,EACtB,CAiCA,SAAS,cACL,EACA,EACA,EACA,EACA,EACuD,CACvD,IAAM,YAAsB,CACxB,IAAK,IAAM,KAAe,EACtB,EAAY,cAAc,IAAI,EAGlC,EAAU,cAAc,IAAI,CAChC,EAEA,GAAI,EAAU,gBAAgB,EAG1B,OAFA,EAAU,EAEH,CAAE,OAAQ,EAAa,OAAQ,EAG1C,IAAM,EAAa,EACd,IAAI,GAAY,GAAG,EAAS,GAAG,EAAkB,KAAK,GAAiB,CAAC,CACxE,KAAK,IAAI,EAEd,IAAK,IAAM,KAAe,EACtB,EAAY,cAAc,CAAU,EAgBxC,OAbA,EAAU,cAAc,EAAW,KAAK,IAAI,CAAC,EAatC,CAAE,OAXM,EAAU,gBAAgB,CACrC,UAAkB,EAClB,SAAkB,GAAsB,EAAW,GACnD,WAAkB,EAClB,iBAAkB,GAClB,eAAwB,CACpB,QAAQ,EACR,EAAU,CACd,CACJ,CAES,EAAQ,OAAQ,CAC7B,CA2BA,SAAS,YAAY,EAA4B,CAC7C,MAAO,CAAE,EAAG,EAAU,KAAK,EAAG,EAAG,EAAU,KAAK,EAAG,MAAO,EAAU,SAAS,EAAG,OAAQ,EAAU,UAAU,CAAE,CAClH,CASA,SAAS,iBAAiB,EAA2C,CACjE,IAAM,EAAQ,EAAI,MAAM,yBAAyB,EACjD,GAAI,CAAC,EACD,MAAO,IAAY,EAGvB,GAAM,CAAC,EAAI,EAAI,EAAI,GAAM,EAAM,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAS,WAAW,CAAK,CAAC,EAErE,EAAK,EAAI,EAAI,EAAK,GAAK,EAAK,GAAM,EAAI,EAAK,EAAI,EAAK,EACpD,EAAK,EAAI,EAAI,EAAK,GAAK,EAAK,GAAM,EAAI,EAAK,EAAI,EAAK,EAEpD,QAAY,KAAgB,EAAK,EAAI,GAAM,EAAI,GAAM,EACrD,QAAY,KAAgB,EAAK,EAAI,GAAM,EAAI,GAAM,EACrD,SAAY,IAAe,EAAI,EAAK,EAAI,EAAI,GAAM,EAAI,EAE5D,MAAO,IAAY,CACf,IAAI,EAAI,EAER,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,GAAK,EAAG,CAC3B,IAAM,EAAI,QAAQ,CAAC,EAAI,EACvB,GAAI,KAAK,IAAI,CAAC,EAAI,KACd,OAAO,QAAQ,CAAC,EAGpB,IAAM,EAAK,SAAS,CAAC,EACrB,GAAI,KAAK,IAAI,CAAE,EAAI,KACf,MAGJ,GAAK,EAAI,CACb,CAGA,IAAI,EAAK,EAAG,EAAK,EAEjB,IADA,EAAI,EACG,EAAK,GAAI,CACZ,IAAM,EAAI,QAAQ,CAAC,EACnB,GAAI,KAAK,IAAI,EAAI,CAAQ,EAAI,KACzB,MAEA,EAAI,EACJ,EAAK,EAEL,EAAK,EAET,GAAK,EAAK,GAAM,CACpB,CAEA,OAAO,QAAQ,CAAC,CACpB,CACJ,CAIA,IAAM,EAAgB,iBAAiB,CAAe,EAEhD,MAAQ,EAAW,EAAW,IAAsB,GAAK,EAAI,GAAK,EAElE,UAAY,EAAS,EAAS,KAAqB,CACrD,EAAQ,KAAK,EAAE,EAAQ,EAAE,EAAQ,CAAC,EAClC,EAAQ,KAAK,EAAE,EAAQ,EAAE,EAAQ,CAAC,EAClC,MAAQ,KAAK,EAAE,MAAQ,EAAE,MAAQ,CAAC,EAClC,OAAQ,KAAK,EAAE,OAAQ,EAAE,OAAQ,CAAC,CACtC,GAQA,SAAS,WAAW,EAAsB,EAAY,EAAyB,CAC3E,EAAU,mBAAmB,EAAK,EAClC,EAAU,KAAK,EAAK,CAAC,EACrB,EAAU,KAAK,EAAK,CAAC,EACrB,EAAU,SAAS,EAAK,KAAK,EAC7B,EAAU,UAAU,EAAK,MAAM,EAE3B,GACA,EAAU,SAAS,EAGvB,EAAU,mBAAmB,EAAI,CACrC,CA6BA,SAAS,cAAc,EAAyB,EAAqC,CACjF,GAAI,EAAU,gBAAgB,EAAG,CAC7B,IAAK,IAAM,KAAS,EAChB,WAAW,EAAM,UAAW,EAAM,IAAK,EAAM,QAAQ,EAKzD,OAFA,IAAa,MAEA,CAAC,CAClB,CAEA,IAAI,EAAY,GACZ,EAAY,EAIhB,IAAK,IAAM,KAAS,EAChB,WAAW,EAAM,UAAW,EAAM,MAAO,EAAM,QAAQ,EAG3D,IAAM,EAAY,YAAY,IAAI,EAE5B,MAAS,GAAsB,CACjC,GAAI,EACA,OAGJ,IAAM,EAAW,KAAK,IAAI,GAAI,EAAM,GAAa,CAAiB,EAC5D,EAAY,EAAc,CAAQ,EAExC,IAAK,IAAM,KAAS,EAChB,WAAW,EAAM,UAAW,GAAY,EAAI,EAAM,IAAM,SAAS,EAAM,MAAO,EAAM,IAAK,CAAK,EAAG,EAAM,QAAQ,EAG/G,EAAW,EACX,EAAM,EAAI,KAAK,sBAAsB,KAAK,EAE1C,IAAa,CAErB,EAIA,MAFA,GAAM,EAAI,KAAK,sBAAsB,KAAK,MAE7B,CACT,EAAY,GAER,GACA,EAAI,KAAK,qBAAqB,CAAG,CAEzC,CACJ,CAyCA,SAAgB,YACZ,EACA,EACA,EACA,EACA,EACA,EACU,CAOV,IAAW,EAKX,MAAM,EAAS,GAAU,cAAc,EAAS,CAAC,WAAW,EAAG,CAAC,CAAO,EAAG,EAAQ,WAAW,CAAC,EAS9F,IAAM,EAAU,EAAa,OAAO,GAAe,CAAC,EAAY,QAAQ,CAAC,CAAC,IAAI,GAAe,EAAY,SAAS,EAC9G,EAAQ,OAAS,GACjB,MAAM,EAAS,GAAU,cAAc,EAAQ,GAAI,CAAC,kBAAkB,EAAG,EAAS,EAAQ,kBAAkB,CAAC,EAKjH,IAAM,EAAS,EAAa,IAAI,GAAe,YAAY,EAAY,SAAS,CAAC,EAWjF,OATA,EAAU,SAAS,EASZ,cAPyB,EAAa,KAAK,EAAa,KAAW,CACtE,UAAW,EAAY,UACvB,SAAW,EAAY,SACvB,MAAW,EAAO,GAClB,IAAW,YAAY,EAAY,SAAS,CAChD,EAEqB,EAAQ,CAAM,CACvC,CC/bA,IAAM,EAAe,GACf,EAAe,GAuCf,EAA0D,CAC5D,KAAQ,EACR,MAAQ,GACR,KAAQ,IACR,MAAQ,GACZ,EAEI,EAA+B,KAUnC,SAAS,+BAAsC,CACvC,AAIJ,IAAa,IAAI,EAAU,CACvB,MAAQ,QACR,KAAQ,iBACR,OAAQ,CACJ,SAAe,WACf,IAAe,MACf,KAAe,MAGf,UAAe,wBAOf,UAAe,aACf,MAAe,GAAG,EAAY,IAC9B,OAAe,GAAG,EAAa,IAC/B,aAAe,MACf,WAAe,kCACf,OAAe,gDACf,UAAe,2DACf,UAAe,SACf,SAAe,MACf,WAAe,OACf,MAAe,uDAKf,cAAe,OACf,WAAe,MACnB,CACJ,CAAC,CACL,CAcA,IAAM,eAAN,cAA6B,CAAiC,CAG1D,WAAuD,IAAI,EAS3D,YAAY,EAAiC,CACzC,8BAA8B,EAM9B,MAAM,CAAE,IAAK,OAAQ,OAAQ,UAAW,GAAI,GAAW,CAAC,CAAG,CAAC,EAE5D,KAAK,aAAe,OAEpB,KAAK,cAAc,EAKnB,KAAK,eAAe,GAAS,SAAS,EAEtC,EAAM,YAAY,KAAM,WAAY,KAAK,aAAa,EACtD,EAAM,YAAY,KAAM,YAAa,KAAK,WAAW,CACzD,CAQA,aAAuB,EAAsC,CAOzD,OANA,MAAM,aAAa,CAAO,EAEtB,EAAQ,YAAc,IAAA,IACtB,KAAK,aAAa,EAAQ,SAAS,EAGhC,IACX,CAQA,QAA2B,CACvB,IAAM,EAAU,MAAM,OAAO,EAI7B,OAFA,EAAI,KAAK,MAAM,EAAS,CAAE,KAAM,GAAI,CAAC,EAE9B,CACX,CAUA,eAA8B,CAC1B,IAAM,EAAU,EAAqB,KAAK,YAE1C,KAAK,gBAAgB,EAAE,CAAC,CAAC,IAAI,YAAa,gCAAgC,EAAQ,KAAK,CAC3F,CAaA,aAAa,EAAuB,CAGhC,OAFA,KAAK,gBAAgB,EAAE,CAAC,CAAC,IAAI,QAAS,GAAG,EAAA,GAA+B,EAAY,GAAG,EAEhF,IACX,CAOA,cAAkC,CAC9B,OAAO,KAAK,UAChB,CAQA,aAAa,EAAoC,CAK7C,MAJA,MAAK,WAAa,EAElB,KAAK,cAAc,EAEZ,IACX,CAWA,GAAG,EAA4B,EAA0B,CAGrD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAUA,IAAI,EAA4B,EAA0B,CAGtD,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAOA,KAAe,EAAkC,CAC7C,KAAK,WAAW,KAAK,CAAK,CAC9B,CASA,cAAsB,EAAyC,CAG3D,OAFA,KAAK,KAAK,UAAU,EAEb,EACX,CASA,YAAoB,EAAyC,CACzD,MAAO,EACX,CAEJ,EAEM,EAAyB,EAAS,cAAc,EC3RhD,EAAmE,CACrE,KAAO,OACP,KAAO,OACP,MAAO,QACP,MAAO,OACX,EAoDM,EAA0D,CAC5D,YAAa,aACb,YAAa,GACb,QAAa,EACjB,EAqBM,YAAN,cAA0B,CAA8B,CAMpD,QAA2B,GAC3B,mBAAgD,OAChD,oBAAsC,kCACtC,aAA+B,GAC/B,WAAoD,IAAI,EASxD,YACI,EACA,EACA,EACF,CACE,MAAM,EAAS,CAAE,GAAG,EAA4B,GAAI,GAAoB,CAAC,CAAG,CAAC,EAOzE,GAAa,GAAS,cAAgB,IAAA,KACtC,KAAK,WAAa,GAKtB,KAAK,oBAAsB,GAAS,oBAAsB,kCAC1D,KAAK,mBAAmB,KAAK,mBAAmB,EAMhD,KAAK,mBAAqB,GAAS,oBAAsB,KAAK,aAAe,aAAe,OAAS,SAErG,KAAK,gBAAkB,IAAI,EAAe,CACtC,UAAW,KAAK,mBAChB,UAAW,CAAE,aAAgB,KAAK,KAAK,UAAU,CAAE,CACvD,CAAC,EAED,KAAK,gBAAgB,WAAW,KAAK,YAAY,EAE7C,GAAS,QACT,KAAK,UAAU,EAAI,EAQlB,KAAK,UACN,KAAK,iBAAiB,MAAM,EAO5B,KAAK,UACL,EAAM,YAAY,KAAM,YAAa,KAAK,WAAW,EAGzD,KAAK,eAAe,GAAS,SAAS,EAItC,KAAK,cAAc,CACvB,CAQA,KAAe,EAAwB,CACnC,MAAM,KAAK,CAAO,EAElB,IAAM,EAAK,GAAW,KAAK,WAAW,EAQtC,OANK,GAIL,EAAI,KAAK,YAAY,EAAI,KAAK,gBAAgB,WAAW,EAAI,CAAE,EAHpD,IAMf,CAOA,eAAyB,CACrB,OAAO,KAAK,cAAgB,KAAK,gBAAgB,WACrD,CAQA,eAAe,EAAsB,CAgBjC,MAfA,MAAK,aAAe,EAEpB,KAAK,iBAAiB,WAAW,CAAK,EASlC,KAAK,iBACL,KAAK,cAAc,EAGhB,IACX,CAQA,aAAuB,EAAmC,CAStD,OARA,MAAM,aAAa,CAAO,EAI1B,KAAK,aAAa,EAAQ,aAAe,KAAK,aAAa,CAAC,EAC5D,KAAK,eAAe,EAAQ,aAAe,KAAK,cAAc,CAAC,EAC/D,KAAK,WAAW,EAAQ,SAAW,KAAK,UAAU,CAAC,EAE5C,IACX,CAOA,WAAqB,CACjB,OAAO,KAAK,UAAY,KAAK,gBAAgB,OACjD,CAWA,WAAW,EAAsB,CAG7B,MAFA,MAAK,SAAW,EAET,IACX,CAOA,UAAoB,CAChB,OAAO,KAAK,OAChB,CAWA,UAAU,EAAsB,CA+B5B,MA9BA,MAAK,QAAU,EAEX,GAMA,KAAK,mBAAmB,iCAAiC,EACzD,KAAK,mBAAmB,iFAAiF,EACzG,KAAK,UAAU,+CAA+C,EAC9D,KAAK,iBAAiB,aAAa,EAAmB,KAAK,mBAAmB,IAE9E,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EACjB,KAAK,mBAAmB,KAAK,mBAAmB,EAChD,KAAK,iBAAiB,aAAa,KAAK,kBAAkB,GAK9D,KAAK,iBAAiB,aAAa,CAAK,EAIxC,KAAK,YAAY,EAGjB,KAAK,cAAc,EAEZ,IACX,CAOA,sBAA0C,CACtC,OAAO,KAAK,kBAChB,CAUA,qBAAqB,EAAoC,CAMrD,MALA,MAAK,mBAAqB,EAE1B,KAAK,iBAAiB,aAAa,KAAK,QAAU,EAAmB,GAAa,CAAS,EAC3F,KAAK,cAAc,EAEZ,IACX,CAUA,eAA8B,CAK1B,GAAI,CAAC,KAAK,aAAc,CAChB,KAAK,eAAiB,KACtB,EAAQ,OAAO,IAAI,EAEf,KAAK,iBACL,EAAQ,OAAO,KAAK,eAAe,EAGvC,KAAK,aAAe,IAGxB,MACJ,CAIA,IAAM,EAAY,mBAFA,KAAK,QAAU,SAAW,WAEA,GAD1B,KAAK,QAAU,EAAmB,KAAK,oBAAsB,KAAK,mBAC3B,MAErD,IAAS,KAAK,eAIlB,KAAK,aAAe,EAEpB,EAAQ,OAAO,KAAM,CAAI,EAErB,KAAK,iBACL,EAAQ,OAAO,KAAK,gBAAiB,CAAI,EAEjD,CAOA,cAAe,CACX,OAAO,KAAK,YAAc,KAAK,gBAAgB,WACnD,CAOA,aAAa,EAA2B,CAOpC,MANA,CACI,IAAY,aAGhB,KAAK,WAAa,EAEX,IACX,CAoBA,GAAG,EAA0B,EAA0B,CAGnD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAWA,IAAI,EAAyB,EAA0B,CAGnD,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAaA,KAAe,EAAyB,GAAG,EAA0B,CACjE,KAAK,WAAW,KAAK,EAAO,GAAG,CAAO,CAC1C,CAQA,YAA6B,CACzB,KAAK,iBAAiB,QAAQ,EAE9B,MAAM,WAAW,CACrB,CASA,cAAsB,EAAwB,CAC1C,KAAK,KAAK,OAAQ,CAAQ,CAC9B,CAUA,YAAY,EAAkB,CAG1B,GAAI,KAAK,QACL,OAGJ,IAAM,EAAW,KAAK,aAAe,aAAe,EAAK,QAAU,EAAK,QAExE,KAAK,KAAK,YAAa,CAAQ,EAE/B,EAAM,oBAAoB,KAAM,UAAW,KAAK,UAAU,EAC1D,EAAM,oBAAoB,KAAM,WAAY,KAAK,UAAU,EAC3D,EAAM,oBAAoB,KAAM,cAAe,KAAK,UAAU,EAC9D,EAAM,oBAAoB,KAAM,YAAa,KAAK,MAAM,EACxD,EAAM,oBAAoB,KAAM,YAAa,KAAK,MAAM,EAExD,iBAAiB,KAAK,WAAW,CAAC,CACtC,CASA,YAAmC,CAW/B,OAVA,EAAM,uBAAuB,KAAM,UAAW,KAAK,UAAU,EAC7D,EAAM,uBAAuB,KAAM,WAAY,KAAK,UAAU,EAC9D,EAAM,uBAAuB,KAAM,cAAe,KAAK,UAAU,EACjE,EAAM,uBAAuB,KAAM,YAAa,KAAK,MAAM,EAC3D,EAAM,uBAAuB,KAAM,YAAa,KAAK,MAAM,EAE3D,eAAe,EAEf,KAAK,KAAK,SAAS,EAEZ,EACX,CASA,OAAO,EAAwC,CAC3C,IAAI,EASJ,MARA,CAGI,EAHA,KAAK,aAAe,aACT,EAAK,QAEL,EAAK,QAGpB,KAAK,cAAc,CAAQ,EAEpB,EACX,CAQA,YAA6B,CACzB,OAAO,KAAK,YAAc,aAAe,YAAc,WAC3D,CAQA,aAA4B,CACpB,KAAK,UAAY,CAAC,KAAK,QACvB,KAAK,UAAU,KAAK,WAAW,CAAC,EAEhC,KAAK,UAAU,SAAS,CAEhC,CAOA,QAAS,CACL,IAAI,EAAU,MAAM,OAAO,EAI3B,OAFA,KAAK,YAAY,EAEV,CACX,CACJ,EAEM,EAAsB,EAAS,WAAW,ECrlB1C,EAAa,EAKb,EAAsD,EACvD,EAAU,OAAQ,SAClB,EAAU,OAAQ,SAClB,EAAU,MAAQ,QAClB,EAAU,MAAQ,MACvB,EAyBM,OAAN,cAAqB,CAAc,CAE/B,gBAA4C,KAC5C,gBAA4C,KAC5C,eAA2C,KAC3C,eAA2C,KAC3C,iBAA6C,KAC7C,SAA2B,EAW3B,WAA8C,IAAI,IAClD,aAAgD,IAAI,IACpD,SAAgD,IAAI,IAKpD,mBAAkD,KAQlD,4BAAqE,CAAC,EAUtE,YAA+B,GAE/B,YAAY,EAAyB,CAGjC,MAAM,EAEF,GACA,KAAK,aAAa,CAAO,CAEjC,CAQA,aAAuB,EAA8B,CACjD,MAAM,aAAa,CAAO,EAEtB,EAAQ,UAAY,IAAA,IACpB,KAAK,oBAAoB,EAAQ,OAAO,CAEhD,CAcA,qBAAqB,EAAsB,EAAgE,CAUvG,OATK,IACD,EAAc,IAAI,EAClB,EAAY,UAAY,EAAU,QAGjC,EAAY,YACb,EAAY,UAAY,EAAU,QAG9B,EAAY,UAApB,CACI,KAAK,EAAU,MACX,KAAK,gBAAkB,EACvB,MACJ,KAAK,EAAU,MACX,KAAK,gBAAkB,EACvB,MACJ,KAAK,EAAU,KACX,KAAK,eAAiB,EACtB,MACJ,KAAK,EAAU,KACX,KAAK,eAAiB,EACtB,MACJ,KAAK,EAAU,OACX,KAAK,iBAAmB,CAEhC,CAUA,OANI,EAAY,YAAc,EAAU,OACpC,KAAK,aAAa,IAAI,EAAU,OAAQ,EAAK,EAE7C,KAAK,aAAa,IAAI,EAAY,UAAW,EAAY,aAAe,EAAK,EAG1E,MAAM,qBAAqB,EAAW,CAAW,CAC5D,CAYA,qBAAqB,EAAqD,CAatE,OAZI,KAAK,kBAAoB,EACzB,KAAK,gBAAkB,KAChB,KAAK,kBAAoB,EAChC,KAAK,gBAAkB,KAChB,KAAK,iBAAmB,EAC/B,KAAK,eAAiB,KACf,KAAK,iBAAmB,EAC/B,KAAK,eAAiB,KACf,KAAK,mBAAqB,IACjC,KAAK,iBAAmB,MAGrB,MAAM,qBAAqB,CAAS,CAC/C,CAOA,qBAAsB,CAClB,OAAO,KAAK,QAChB,CAOA,oBAAoB,EAAwB,CAGxC,MAFA,MAAK,SAAW,EAET,IACX,CAQA,mBAA2B,EAAwC,CAC/D,OAAQ,EAAR,CACI,KAAK,EAAU,MAAQ,OAAO,KAAK,gBACnC,KAAK,EAAU,MAAQ,OAAO,KAAK,gBACnC,KAAK,EAAU,KAAQ,OAAO,KAAK,eACnC,KAAK,EAAU,KAAQ,OAAO,KAAK,eACnC,KAAK,EAAU,OAAQ,OAAO,KAAK,gBACvC,CACJ,CAQA,kBAAkB,EAA+B,CAC7C,OAAO,KAAK,WAAW,IAAI,CAAS,GAAK,EAC7C,CAiBA,mBAAmB,EAAsB,EAA0B,CAC/D,GAAI,IAAc,EAAU,QAAU,CAAC,KAAK,oBAAoB,CAAS,EACrE,OAAO,KAGX,IAAM,EAAY,KAAK,mBAAmB,CAAS,EAMnD,GALI,CAAC,IAIW,KAAK,WAAW,IAAI,CAAS,GAAK,MAClC,EACZ,OAAO,KAGX,IAAM,EAAY,KAAK,aAAa,EACpC,GAAI,CAAC,EACD,OAAO,KAaX,IAAM,EAAe,KAAK,YAC1B,KAAK,YAAc,GAEd,GACD,EAAU,SAAS,EAGvB,KAAK,WAAW,IAAI,EAAW,CAAS,EAGxC,KAAK,aAAa,CAAS,EAQ3B,IAAM,EAAsC,CACxC,GAJY,CAAC,KAAK,gBAAiB,KAAK,gBAAiB,KAAK,eAAgB,KAAK,eAAgB,KAAK,gBAAgB,CAAC,CACxH,OAAQ,GAAsB,GAAK,IAGjC,CAAA,CAAQ,IAAI,IAAW,CAAE,UAAW,EAAQ,SAAU,EAAK,EAAE,EAChE,GAAG,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,CAAC,CAAC,IAAI,IAAW,CAAE,UAAW,EAAQ,SAAU,EAAM,EAAE,CACzF,EAYA,MAVA,MAAK,mBAAqB,YAAY,EAAW,EAAW,EAAc,KAAK,mBAAoB,KAAK,gCAAmC,CACvI,KAAK,mBAAqB,KAI1B,KAAK,YAAc,GAEnB,EAAU,SAAS,CACvB,CAAC,EAEM,IACX,CAUA,oBAAoB,EAA+B,CAK/C,OAJI,IAAc,EAAU,OACjB,GAGJ,KAAK,aAAa,IAAI,CAAS,GAAK,EAC/C,CAUA,qBAAqB,EAAsB,EAAsB,CAS7D,OARI,IAAc,EAAU,OACjB,MAGX,KAAK,aAAa,IAAI,EAAW,CAAK,EAEtC,KAAK,aAAa,CAAC,EAAE,eAAe,EAE7B,KACX,CAWA,aAAqB,EAAmC,CACpD,IAAI,EAAS,KAAK,SAAS,IAAI,CAAS,EACxC,GAAI,EACA,OAAO,EAGX,IAAM,EAAY,KAAK,aAAa,EAiBpC,MAdA,GAAS,IAAI,EAFK,IAAc,EAAU,OAAS,IAAc,EAAU,MAEvC,WAAa,aAAc,CAC3D,QAAoB,GACpB,OAAoB,GACpB,kBAAoB,EAAiB,GACrC,mBAAoB,cACpB,UAAoB,CAAE,aAAgB,KAAK,mBAAmB,EAAW,CAAC,KAAK,kBAAkB,CAAS,CAAC,CAAE,CACjH,CAAC,EAED,EAAO,WAAW,EAAK,EAEvB,EAAI,KAAK,YAAY,EAAU,WAAW,EAAI,EAAO,WAAW,EAAI,CAAE,EAEtE,KAAK,SAAS,IAAI,EAAW,CAAM,EAE5B,CACX,CAWA,aAAqB,EAAsB,EAA2B,CAClE,OAAO,KAAK,kBAAkB,CAAS,EAAA,GAA0B,CACrE,CAgBA,kBAA0B,EAAmB,EAAkB,EAA2B,CACtF,IAAM,EAAU,EAAO,EAAW,EAAI,OAAS,EAAI,MAAS,EAE5D,OAAO,KAAK,IAAI,EAAW,CAAO,CACtC,CAcA,gBAAwB,EAAsB,EAA4B,CAKjE,QAAK,oBAAoB,CAAS,EAIvC,IAAI,CAAC,KAAK,kBAAkB,CAAS,EAAG,CACpC,EAAU,YAAY,gBAAgB,EAEtC,MACJ,CAEA,OAAQ,EAAR,CACI,KAAK,EAAU,KAAO,EAAU,YAAY,mBAAmB,EAAG,MAClE,KAAK,EAAU,KAAO,EAAU,YAAY,mBAAmB,EAAG,MAClE,KAAK,EAAU,MAAO,EAAU,YAAY,mBAAmB,EAAG,MAClE,KAAK,EAAU,MAAO,EAAU,YAAY,mBAAmB,CACnE,CAPA,CAQJ,CAeA,mBAA2B,EAAsB,EAAW,EAAW,EAAe,EAAsB,CACxG,IAAM,EAAY,KAAK,mBAAmB,CAAS,EACnD,GAAI,CAAC,EACD,OAGJ,GAAI,CAAC,KAAK,oBAAoB,CAAS,EAAG,CACtC,EAAU,WAAW,EAAI,EACzB,KAAK,SAAS,IAAI,CAAS,CAAC,EAAE,WAAW,EAAK,EAE9C,MACJ,CAEA,IAAM,EAAY,KAAK,kBAAkB,CAAS,EAC5C,EAAY,KAAK,aAAa,CAAS,EAK7C,EAAU,WAAW,EAAI,EAEzB,EAAO,UAAU,CAAS,EAC1B,EAAO,WAAW,EAAI,EAKtB,IAAM,EAAO,EAAY,CAAE,IAAG,IAAG,QAAO,QAAO,EAAI,KAAK,eAAe,EAAW,EAAG,EAAG,EAAO,CAAM,EAErG,EAAO,KAAK,EAAK,CAAC,EAClB,EAAO,KAAK,EAAK,CAAC,EAClB,EAAO,SAAS,EAAK,KAAK,EAC1B,EAAO,UAAU,EAAK,MAAM,CAChC,CAeA,eAAuB,EAAsB,EAAW,EAAW,EAAe,EAAyE,CACvJ,OAAQ,EAAR,CACI,KAAK,EAAU,MAAO,MAAO,CAAE,IAAG,EAAG,EAAI,EAAY,QAAO,OAAQ,CAAW,EAC/E,KAAK,EAAU,MAAO,MAAO,CAAE,IAAG,EAAG,EAAI,EAAY,QAAO,OAAQ,CAAW,EAC/E,KAAK,EAAU,KAAO,MAAO,CAAE,EAAG,EAAI,EAAW,IAAG,MAAO,EAAY,QAAO,EAC9E,KAAK,EAAU,KAAO,MAAO,CAAE,EAAG,EAAI,EAAY,IAAG,MAAO,EAAY,QAAO,EAC/E,QAAsB,MAAO,CAAE,IAAG,IAAG,QAAO,QAAO,CACvD,CACJ,CAYA,QAAgB,EAA+C,CAC3D,OAAO,GAAa,EAAU,YAAY,EAAI,EAAY,IAC9D,CAOA,kBAAgC,CAC5B,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAAO,KAGX,IAAI,EAAgB,EAAU,iBAAiB,EAE3C,EAAa,EAAc,KAAO,EAAc,MAChD,EAAc,EAAc,IAAM,EAAc,OAEhD,EAAa,EACb,EAAc,EAEd,EAAc,EACd,EAAe,EAGb,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,cAAc,EACzC,EAAS,KAAK,QAAQ,KAAK,gBAAgB,EAC3C,EAAS,KAAK,QAAQ,KAAK,cAAc,EAE/C,GAAI,EAAO,CACP,IAAI,EAAO,EAAM,iBAAiB,EAClC,GAAI,EAAM,CACN,IAAM,EAAgB,KAAK,kBAAkB,EAAK,OAAQ,EAAM,WAAW,EAAG,EAAI,EAClF,EAAa,KAAK,IAAI,EAAY,EAAK,KAAK,EAC5C,GAAe,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,CACnF,CACJ,CAEA,GAAI,EAAO,CACP,IAAI,EAAO,EAAM,iBAAiB,EAClC,GAAI,EAAM,CACN,IAAM,EAAgB,KAAK,kBAAkB,EAAK,OAAQ,EAAM,WAAW,EAAG,EAAI,EAClF,EAAa,KAAK,IAAI,EAAY,EAAK,KAAK,EAC5C,GAAe,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,CACnF,CACJ,CAEA,GAAI,EAAM,CACN,IAAI,EAAO,EAAK,iBAAiB,EACjC,GAAI,EAAM,CACN,IAAM,EAAe,KAAK,kBAAkB,EAAK,MAAO,EAAK,WAAW,EAAG,EAAK,EAChF,GAAe,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAC9E,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,CACrD,CACJ,CAEA,GAAI,EAAQ,CACR,IAAI,EAAO,EAAO,iBAAiB,EAC/B,IACA,GAAe,EAAK,MACpB,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,EAEzD,CAEA,GAAI,EAAM,CACN,IAAI,EAAO,EAAK,iBAAiB,EACjC,GAAI,EAAM,CACN,IAAM,EAAe,KAAK,kBAAkB,EAAK,MAAO,EAAK,WAAW,EAAG,EAAK,EAChF,GAAe,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAC9E,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,CACrD,CACJ,CAKA,MAHA,GAAa,KAAK,IAAI,EAAY,CAAW,EAC7C,GAAe,EAER,CACH,MAAO,EAAa,EACpB,OAAQ,EAAc,CAC1B,CACJ,CAOA,YAA0B,CACtB,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAAO,KAGX,IAAI,EAAgB,EAAU,iBAAiB,EAE3C,EAAa,EAAc,KAAO,EAAc,MAChD,EAAc,EAAc,IAAM,EAAc,OAEhD,EAAa,EACb,EAAc,EAEd,EAAc,EACd,EAAe,EAGb,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,cAAc,EACzC,EAAS,KAAK,QAAQ,KAAK,gBAAgB,EAC3C,EAAS,KAAK,QAAQ,KAAK,cAAc,EAE/C,GAAI,EAAO,CACP,IAAI,EAAO,EAAM,WAAW,EACxB,IACA,EAAa,KAAK,IAAI,EAAY,EAAK,KAAK,EAC5C,GAAe,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,EAAK,OAE5F,CAEA,GAAI,EAAO,CACP,IAAI,EAAO,EAAM,WAAW,EACxB,IACA,EAAa,KAAK,IAAI,EAAY,EAAK,KAAK,EAC5C,GAAe,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,EAAK,OAE5F,CAEA,GAAI,EAAM,CACN,IAAI,EAAO,EAAK,WAAW,EACvB,IACA,GAAe,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAAK,MACnF,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,EAEzD,CAEA,GAAI,EAAQ,CACR,IAAI,EAAO,EAAO,WAAW,EACzB,IACA,GAAe,EAAK,MACpB,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,EAEzD,CAEA,GAAI,EAAM,CACN,IAAI,EAAO,EAAK,WAAW,EACvB,IACA,GAAe,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAAK,MACnF,EAAe,KAAK,IAAI,EAAc,EAAK,MAAM,EAEzD,CAKA,MAHA,GAAa,KAAK,IAAI,EAAY,CAAW,EAC7C,GAAe,EAER,CACH,MAAO,EAAa,EACpB,OAAQ,EAAc,CAC1B,CACJ,CAcA,YAA0B,CACtB,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAAO,KAGX,IAAI,EAAgB,EAAU,iBAAiB,EAE3C,EAAa,EAAc,KAAO,EAAc,MAChD,EAAc,EAAc,IAAM,EAAc,OAI9C,MAAS,GACX,KAAK,QAAQ,CAAS,EAAK,EAAW,WAAW,GAAK,CAAE,MAAO,EAAW,OAAQ,CAAU,EAAK,KAE/F,EAAS,MAAM,KAAK,eAAe,EACnC,EAAS,MAAM,KAAK,eAAe,EACnC,EAAS,MAAM,KAAK,cAAc,EAClC,EAAS,MAAM,KAAK,gBAAgB,EACpC,EAAS,MAAM,KAAK,cAAc,EAIpC,EAAc,EACd,EAAe,EACf,EAAY,GAEhB,IAAK,IAAM,IAAU,CAAC,EAAM,EAAQ,CAAI,EAChC,IACA,EAAY,GACZ,GAAe,EAAO,MACtB,EAAe,KAAK,IAAI,EAAc,EAAO,MAAM,GAK3D,IAAI,EAAa,EACb,IAAa,EAAa,KAAK,IAAI,EAAY,EAAM,KAAK,GAC1D,IAAa,EAAa,KAAK,IAAI,EAAY,EAAM,KAAK,GAC1D,IAAa,EAAa,KAAK,IAAI,EAAY,CAAW,GAG9D,IAAI,EAAc,EAKlB,OAJI,IAAa,GAAe,EAAM,QAClC,IAAa,GAAe,GAC5B,IAAa,GAAe,EAAM,QAE/B,CACH,MAAQ,EAAS,EAAc,CAAU,EACzC,OAAQ,EAAS,EAAc,CAAW,CAC9C,CACJ,CAYA,qBAAsC,CAElC,GAAI,CADc,KAAK,aAClB,EACD,MAAO,CAAE,MAAO,EAAG,OAAQ,CAAE,EAKjC,IAAM,EAAY,KAAK,QAAQ,KAAK,cAAc,CAAC,EAAI,WAAW,EAC5D,EAAY,KAAK,QAAQ,KAAK,gBAAgB,CAAC,EAAE,WAAW,EAC5D,EAAY,KAAK,QAAQ,KAAK,cAAc,CAAC,EAAI,WAAW,EAC5D,EAAY,KAAK,QAAQ,KAAK,eAAe,CAAC,EAAG,WAAW,EAC5D,EAAY,KAAK,QAAQ,KAAK,eAAe,CAAC,EAAG,WAAW,EAO5D,EAAsB,CAAC,EACzB,GAAa,EAAU,KAAK,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAAQ,KAAK,EACxG,GAAa,EAAU,KAAK,EAAU,KAAK,EAC3C,GAAa,EAAU,KAAK,KAAK,kBAAkB,EAAU,IAAI,EAAA,GAA0B,EAAQ,KAAK,EAE5G,IAAM,EAAsB,CAAC,EACzB,GAAa,EAAU,KAAK,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,EAAS,MAAM,EAC3G,GAAa,EAAU,KAAK,EAAU,MAAM,EAC5C,GAAa,EAAU,KAAK,KAAK,kBAAkB,EAAU,KAAK,EAAA,GAA0B,EAAS,MAAM,EAE/G,IAAI,EAAS,EACT,EAAS,EAEb,IAAK,IAAM,KAAK,EACZ,GAAS,EAEb,GAAS,KAAK,IAAI,EAAG,EAAU,OAAS,CAAC,EAAI,KAAK,SAK9C,IACA,EAAQ,KAAK,IAAI,EAAO,EAAS,KAAK,GAEtC,IACA,EAAQ,KAAK,IAAI,EAAO,EAAS,KAAK,GAG1C,IAAK,IAAM,KAAK,EACZ,GAAU,EAId,MAFA,IAAU,KAAK,IAAI,EAAG,EAAU,OAAS,CAAC,EAAI,KAAK,SAE5C,CAAE,QAAO,QAAO,CAC3B,CAWA,yBAAiC,GAAG,EAA4C,CAS5E,CAPI,KAAK,gBACL,KAAK,gBACL,KAAK,eACL,KAAK,iBACL,KAAK,cAGT,CAAA,CAAW,SAAS,EAAW,IAAU,CACjC,GAAa,CAAC,EAAe,IAC7B,EAAU,eAAe,CAEjC,CAAC,CACL,CAQA,UAAW,CACP,IAAI,EAAY,KAAK,aAAa,EAClC,GAAI,CAAC,EACD,OAQJ,IAAI,EAAgB,EAAU,aAAa,EAC3C,GAAI,CAAC,EACD,OAGJ,IAAI,EAAkB,EAAU,iBAAiB,EAKjD,EAAgB,KAAK,mBAAmB,CAAa,EAOrD,IAAM,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,eAAe,EAC1C,EAAS,KAAK,QAAQ,KAAK,cAAc,EACzC,EAAS,KAAK,QAAQ,KAAK,gBAAgB,EAC3C,EAAS,KAAK,QAAQ,KAAK,cAAc,EAO/C,KAAK,yBAAyB,EAAO,EAAO,EAAM,EAAQ,CAAI,EAE9D,IAAI,EAAQ,EAAc,MACtB,EAAS,EAAc,OACvB,EACA,EACA,EACA,EAEJ,GAAI,EAAO,CACP,IAAI,EAAc,KAAK,qBAAqB,CAAK,EACjD,GAAI,CAAC,EACD,MAAU,MAAM,6DAA6D,EAGjF,IAAI,EAAgB,EAAM,iBAAiB,EAC3C,GAAI,CAAC,EACD,MAAU,MAAM,yDAAyD,EAG7E,IAAM,EAAc,KAAK,kBAAkB,EAAc,OAAQ,EAAM,WAAW,EAAG,EAAI,EACrF,EAAc,KAAK,aAAa,EAAU,MAAO,CAAW,EAC5D,EAAS,EAAY,mBAAqB,EAAI,EAAgB,QAAQ,EACtE,EAAS,EAAY,mBAAqB,EAAI,EAAgB,OAAO,EACrE,EAAa,GAAS,EAAY,mBAAqB,EAAgB,QAAQ,EAAI,EAAgB,SAAS,EAAI,GAChH,EAAgB,EAAY,mBAAqB,EAAgB,OAAO,EAAI,EAEhF,EAAU,EAAc,EAOpB,KAAK,oBAAoB,EAAU,KAAK,GAAK,KAAK,aAClD,KAAK,eACD,EACA,EACA,EACA,EACA,EAAc,EACd,EAAS,IACb,EACA,EAAM,eAAe,EACrB,KAAK,gBAAgB,EAAO,EAAU,KAAK,IAO3C,EAAM,YAAY,IAAI,EACtB,EAAM,aAAa,EAAQ,EAAQ,EAAY,EAAc,CAAa,EAC1E,KAAK,aAAa,EAAO,EAAG,EAAG,EAAY,EAAc,CAAa,GAG1E,KAAK,mBAAmB,EAAU,MAAO,EAAQ,EAAQ,EAAY,CAAO,GAExE,GAAQ,GAAU,GAAQ,KAC1B,GAAW,KAAK,SAExB,KACI,GAAU,EAId,GADA,EAAe,EAAS,EACpB,EAAO,CACP,IAAI,EAAgB,EAAM,iBAAiB,EAC3C,GAAI,CAAC,EACD,MAAU,MAAM,yDAAyD,EAG7E,IAAM,EAAc,KAAK,kBAAkB,EAAc,OAAQ,EAAM,WAAW,EAAG,EAAI,EACrF,EAAc,KAAK,aAAa,EAAU,MAAO,CAAW,EAC5D,EAAS,EAAgB,QAAQ,EACjC,EAAS,EAAgB,OAAO,EAAI,EAAS,EAEjD,GAAgB,KAAK,SACrB,GAAgB,EAIhB,IAAI,EAAa,EAAgB,OAAO,EAAI,EAAS,EAEjD,KAAK,oBAAoB,EAAU,KAAK,GAAK,KAAK,aAClD,KAAK,eACD,EACA,EACA,EACA,EACA,EACA,EAAS,IACb,EACA,EAAM,eAAe,EACrB,KAAK,gBAAgB,EAAO,EAAU,KAAK,IAK3C,EAAM,YAAY,IAAI,EACtB,EAAM,aAAa,EAAQ,EAAY,EAAO,CAAW,EACzD,KAAK,aAAa,EAAO,EAAG,EAAG,EAAO,CAAW,GAGrD,KAAK,mBAAmB,EAAU,MAAO,EAAQ,EAAQ,EAAO,CAAW,CAC/E,CAOA,IAAI,EAAqB,EACrB,EAAgB,EACpB,GAAI,EAAM,CACN,IAAI,EAAgB,EAAK,iBAAiB,EAC1C,GAAI,CAAC,EACD,MAAU,MAAM,wDAAwD,EAE5E,IAAM,EAAa,KAAK,kBAAkB,EAAc,MAAO,EAAK,WAAW,EAAG,EAAK,EACvF,EAAgB,EAChB,EAAqB,KAAK,aAAa,EAAU,KAAM,CAAU,CACrE,CAEA,GAAI,EAAM,CACN,IAAI,EAAgB,EAAK,iBAAiB,EAC1C,GAAI,CAAC,EACD,MAAU,MAAM,wDAAwD,EAG5E,IAAM,EAAa,KAAK,kBAAkB,EAAc,MAAO,EAAK,WAAW,EAAG,EAAK,EACnF,EAAY,KAAK,IAAI,EAAG,KAAK,IAAI,KAAK,aAAa,EAAU,KAAM,CAAU,EAAG,EAAQ,CAAkB,CAAC,EAC3G,EAAQ,EAAgB,QAAQ,EAChC,EAAQ,EAAgB,OAAO,EAAI,EAEvC,EAAU,EAIV,IAAI,EAAgB,KAAK,IAAI,EAAG,KAAK,IAAI,EAAY,EAAQ,CAAkB,CAAC,EAE5E,KAAK,oBAAoB,EAAU,IAAI,GAAK,KAAK,aACjD,KAAK,eACD,EACA,EACA,EACA,EACA,EACA,EAAS,IACb,EACA,EAAK,eAAe,EACpB,KAAK,gBAAgB,EAAM,EAAU,IAAI,IAKzC,EAAK,YAAY,IAAI,EACrB,EAAK,aAAa,EAAO,EAAO,EAAe,CAAY,EAC3D,KAAK,aAAa,EAAM,EAAG,EAAG,EAAe,CAAY,GAG7D,KAAK,mBAAmB,EAAU,KAAM,EAAO,EAAO,EAAW,CAAY,EAEzE,IACA,GAAW,KAAK,SAExB,KACI,GAAU,EAKd,GAFA,EAAc,EAAQ,EAElB,EAAM,CACN,GAAe,KAAK,SACpB,GAAe,EAEf,IAAI,EAAQ,EAAgB,QAAQ,EAAI,EAAQ,EAC5C,EAAQ,EAAgB,OAAO,EAAI,EAInC,EAAY,EAAgB,QAAQ,EAAI,EAAQ,EAEhD,KAAK,oBAAoB,EAAU,IAAI,GAAK,KAAK,aACjD,KAAK,eACD,EACA,EACA,EACA,EACA,EACA,EAAS,IACb,EACA,EAAK,eAAe,EACpB,KAAK,gBAAgB,EAAM,EAAU,IAAI,IAKzC,EAAK,YAAY,IAAI,EACrB,EAAK,aAAa,EAAW,EAAO,EAAe,CAAY,EAC/D,KAAK,aAAa,EAAM,EAAG,EAAG,EAAe,CAAY,GAG7D,KAAK,mBAAmB,EAAU,KAAM,EAAO,EAAO,EAAoB,CAAY,CAC1F,CAEA,GAAI,EAAQ,CACR,IAAI,EAAa,EAAgB,QAAQ,EAAI,EACzC,EAAY,EAAgB,OAAO,EAAI,EASvC,KAAK,aACL,KAAK,eAAe,EAAQ,EAAY,EAAW,EAAa,EAAc,EAAS,IAAI,EAC3F,EAAO,eAAe,IAEtB,EAAO,aAAa,EAAY,EAAW,EAAa,CAAY,EACpE,KAAK,aAAa,EAAQ,EAAG,EAAG,EAAa,CAAY,EAEjE,CACJ,CAWA,QAAe,CAIX,KAAK,qBAAqB,EAC1B,KAAK,mBAAqB,KAM1B,KAAK,YAAc,GAQnB,IAAM,GAAY,KAAK,aAAa,CAAC,EAAE,cAAc,CAAC,CAAC,QAAU,GAAK,EAEtE,IAAK,IAAM,KAAc,KAAK,4BACtB,EACA,EAAW,OAAO,EAElB,EAAW,OAAO,EAG1B,KAAK,4BAA4B,OAAS,EAE1C,MAAM,OAAO,EAEb,IAAK,IAAM,KAAU,KAAK,SAAS,OAAO,EAAG,CACzC,IAAM,EAAU,EAAO,WAAW,EAC5B,EAAS,EAAU,EAAI,OAAO,cAAc,CAAO,EAAI,KAEzD,GAAW,GACX,EAAI,KAAK,YAAY,EAAQ,CAAO,EAGxC,EAAO,QAAQ,CACnB,CAEA,KAAK,SAAS,MAAM,EAEpB,IAAK,IAAM,IAAa,CAAC,EAAU,MAAO,EAAU,MAAO,EAAU,KAAM,EAAU,KAAM,EAAU,MAAM,EACvG,KAAK,mBAAmB,CAAS,CAAC,EAAE,eAAe,EAGvD,OAAO,IACX,CACJ,EAEM,EAAiB,EAAS,MAAM"}
|