@jimka/typescript-ui 0.1.0 → 0.1.1

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.
Files changed (123) hide show
  1. package/README.md +5 -18
  2. package/dist/lib/AbstractBooleanInput-C6CidMMX.js +2 -0
  3. package/dist/lib/AbstractBooleanInput-C6CidMMX.js.map +1 -0
  4. package/dist/lib/AbstractInput-CfjW_HM2.js +2 -0
  5. package/dist/lib/AbstractInput-CfjW_HM2.js.map +1 -0
  6. package/dist/lib/AnimatedDropdown-BFz-DO7R.js +2 -0
  7. package/dist/lib/AnimatedDropdown-BFz-DO7R.js.map +1 -0
  8. package/dist/lib/Border-5Ki2DCWz.js +2 -0
  9. package/dist/lib/Border-5Ki2DCWz.js.map +1 -0
  10. package/dist/lib/BoxLayout-8ryMD4j5.js +2 -0
  11. package/dist/lib/BoxLayout-8ryMD4j5.js.map +1 -0
  12. package/dist/lib/Button-Cdq2ySPL.js +2 -0
  13. package/dist/lib/Button-Cdq2ySPL.js.map +1 -0
  14. package/dist/lib/Card-AKIUAWYS.js +2 -0
  15. package/dist/lib/Card-AKIUAWYS.js.map +1 -0
  16. package/dist/lib/ComboBox-e_YVsWBr.js +2 -0
  17. package/dist/lib/ComboBox-e_YVsWBr.js.map +1 -0
  18. package/dist/lib/Component-Bs6TvaGZ.js +2 -0
  19. package/dist/lib/Component-Bs6TvaGZ.js.map +1 -0
  20. package/dist/lib/Container-CzyZeMyZ.js +2 -0
  21. package/dist/lib/Container-CzyZeMyZ.js.map +1 -0
  22. package/dist/lib/DOM-DeF_dWe2.js +2 -0
  23. package/dist/lib/DOM-DeF_dWe2.js.map +1 -0
  24. package/dist/lib/DragManager-c6M_mE3e.js +2 -0
  25. package/dist/lib/DragManager-c6M_mE3e.js.map +1 -0
  26. package/dist/lib/FieldDecorator-Bl0h9UEF.js +2 -0
  27. package/dist/lib/FieldDecorator-Bl0h9UEF.js.map +1 -0
  28. package/dist/lib/Fit-CUS1JXy3.js +2 -0
  29. package/dist/lib/Fit-CUS1JXy3.js.map +1 -0
  30. package/dist/lib/Glyph-6Ki3A1_a.js +2 -0
  31. package/dist/lib/Glyph-6Ki3A1_a.js.map +1 -0
  32. package/dist/lib/Grid-D8luwRPI.js +2 -0
  33. package/dist/lib/Grid-D8luwRPI.js.map +1 -0
  34. package/dist/lib/GridConstraints-CzC0w4i-.js +2 -0
  35. package/dist/lib/GridConstraints-CzC0w4i-.js.map +1 -0
  36. package/dist/lib/HBox-BWMf9h6r.js +2 -0
  37. package/dist/lib/HBox-BWMf9h6r.js.map +1 -0
  38. package/dist/lib/Header-CQjomjo0.js +2 -0
  39. package/dist/lib/Header-CQjomjo0.js.map +1 -0
  40. package/dist/lib/IconText-BXJK0MOq.js +2 -0
  41. package/dist/lib/IconText-BXJK0MOq.js.map +1 -0
  42. package/dist/lib/LayoutSerialization-C_zcwaN3.js +2 -0
  43. package/dist/lib/LayoutSerialization-C_zcwaN3.js.map +1 -0
  44. package/dist/lib/LayoutSizes-XdhpAOmc.js +2 -0
  45. package/dist/lib/LayoutSizes-XdhpAOmc.js.map +1 -0
  46. package/dist/lib/List-BgxnLWnl.js +2 -0
  47. package/dist/lib/List-BgxnLWnl.js.map +1 -0
  48. package/dist/lib/Menu-BdnwRY0M.js +2 -0
  49. package/dist/lib/Menu-BdnwRY0M.js.map +1 -0
  50. package/dist/lib/MenuButton-D15cSbMf.js +2 -0
  51. package/dist/lib/MenuButton-D15cSbMf.js.map +1 -0
  52. package/dist/lib/Panel-DApa7vA6.js +2 -0
  53. package/dist/lib/Panel-DApa7vA6.js.map +1 -0
  54. package/dist/lib/Position-DJKB0N3l.js +2 -0
  55. package/dist/lib/Position-DJKB0N3l.js.map +1 -0
  56. package/dist/lib/ProgressSpinner-CNYcsBhw.js +2 -0
  57. package/dist/lib/ProgressSpinner-CNYcsBhw.js.map +1 -0
  58. package/dist/lib/RadioButton-CepkneSA.js +2 -0
  59. package/dist/lib/RadioButton-CepkneSA.js.map +1 -0
  60. package/dist/lib/RovingTabIndex-D-zOuptw.js +2 -0
  61. package/dist/lib/RovingTabIndex-D-zOuptw.js.map +1 -0
  62. package/dist/lib/Scrollbar-DQdCdj94.js +2 -0
  63. package/dist/lib/Scrollbar-DQdCdj94.js.map +1 -0
  64. package/dist/lib/Slider-DvDdVvRm.js +2 -0
  65. package/dist/lib/Slider-DvDdVvRm.js.map +1 -0
  66. package/dist/lib/Spacer-BqiPiCqz.js +2 -0
  67. package/dist/lib/Spacer-BqiPiCqz.js.map +1 -0
  68. package/dist/lib/TabButton-DqYDfN7P.js +2 -0
  69. package/dist/lib/TabButton-DqYDfN7P.js.map +1 -0
  70. package/dist/lib/Text-DJoUHukb.js +2 -0
  71. package/dist/lib/Text-DJoUHukb.js.map +1 -0
  72. package/dist/lib/Tooltip-5BR7yYEX.js +3 -0
  73. package/dist/lib/Tooltip-5BR7yYEX.js.map +1 -0
  74. package/dist/lib/VBox-CdV9VGxR.js +2 -0
  75. package/dist/lib/VBox-CdV9VGxR.js.map +1 -0
  76. package/dist/lib/VirtualRowView-C18j90n5.js +2 -0
  77. package/dist/lib/VirtualRowView-C18j90n5.js.map +1 -0
  78. package/dist/lib/VirtualScroller-BKMvTisA.js +2 -0
  79. package/dist/lib/VirtualScroller-BKMvTisA.js.map +1 -0
  80. package/dist/lib/component/button.es.js +1 -1
  81. package/dist/lib/component/button.es.js.map +1 -1
  82. package/dist/lib/component/chart.es.js +1 -1
  83. package/dist/lib/component/chart.es.js.map +1 -1
  84. package/dist/lib/component/container.es.js +1 -1
  85. package/dist/lib/component/container.es.js.map +1 -1
  86. package/dist/lib/component/diagram.es.js +1 -1
  87. package/dist/lib/component/diagram.es.js.map +1 -1
  88. package/dist/lib/component/display.es.js +1 -1
  89. package/dist/lib/component/display.es.js.map +1 -1
  90. package/dist/lib/component/editor.es.js +3 -1
  91. package/dist/lib/component/editor.es.js.map +1 -1
  92. package/dist/lib/component/input.es.js +1 -1
  93. package/dist/lib/component/input.es.js.map +1 -1
  94. package/dist/lib/component/list.es.js +1 -1
  95. package/dist/lib/component/list.es.js.map +1 -1
  96. package/dist/lib/component/menubar.es.js +1 -1
  97. package/dist/lib/component/menubar.es.js.map +1 -1
  98. package/dist/lib/component/table.es.js +2 -2
  99. package/dist/lib/component/table.es.js.map +1 -1
  100. package/dist/lib/component/tree.es.js +1 -1
  101. package/dist/lib/component/tree.es.js.map +1 -1
  102. package/dist/lib/core.es.js +1 -1
  103. package/dist/lib/core.es.js.map +1 -1
  104. package/dist/lib/layout.es.js +1 -1
  105. package/dist/lib/overlay.es.js +1 -1
  106. package/dist/lib/overlay.es.js.map +1 -1
  107. package/dist/lib/primitive.es.js +1 -1
  108. package/dist/lib/router.es.js +2 -0
  109. package/dist/lib/router.es.js.map +1 -0
  110. package/dist/lib/types/component/container/SplitGutter.d.ts +1 -1
  111. package/dist/lib/types/component/container/WindowBorder.d.ts +1 -1
  112. package/dist/lib/types/component/display/Markdown.d.ts +10 -0
  113. package/dist/lib/types/component/display/index.d.ts +1 -1
  114. package/dist/lib/types/component/editor/MarkdownEditor.d.ts +6 -0
  115. package/dist/lib/types/component/editor/markdownTableTransformer.d.ts +2 -0
  116. package/dist/lib/types/core/DOM.d.ts +6 -0
  117. package/dist/lib/types/overlay/AbstractWindow.d.ts +1 -1
  118. package/dist/lib/types/router/RoutePattern.d.ts +18 -0
  119. package/dist/lib/types/router/Router.d.ts +36 -0
  120. package/dist/lib/types/router/index.d.ts +2 -0
  121. package/dist/lib/validation.es.js +1 -1
  122. package/llms.txt +8 -4
  123. package/package.json +6 -1
package/README.md CHANGED
@@ -60,27 +60,14 @@ new Glyph("plus"); // renders the plus icon
60
60
 
61
61
  The string passed to `new Glyph(name)` is the upstream Font Awesome name (with hyphens). The JS identifier is sanitized: `-` becomes `_` and identifiers starting with a digit get a leading `_` (so `arrow-right` exports as `arrow_right`, `500px` as `_500px`, `try` as `_try`).
62
62
 
63
- ### Migration from the previous curated registry
64
-
65
- If you were using the previous 19-icon curated registry, switch to these latest-FA names:
66
-
67
- | Old | New |
68
- |-----|-----|
69
- | `times`, `close` | `xmark` |
70
- | `edit` | `pen-to-square` |
71
- | `info-circle` | `circle-info` |
72
- | `check-circle` | `circle-check` |
73
- | `exclamation-triangle`, `warning` | `triangle-exclamation` |
74
- | `exclamation-circle`, `error` | `circle-exclamation` |
75
- | `question-circle` | `circle-question` |
76
- | `search` | `magnifying-glass` |
77
- | `cog` | `gear` |
78
- | `home` | `house` |
79
-
80
63
  Library components that internally use glyphs (Tree row chevrons, Notification badges) register their own dependencies automatically — consumers only need to register the glyphs they reference directly.
81
64
 
82
65
  ## License
83
66
 
84
- Licensed under the [PolyForm Noncommercial License 1.0.0](LICENSE). Free for personal and educational use; commercial use is not permitted.
67
+ Licensed under the [PolyForm Noncommercial License 1.0.0](LICENSE) — source-available, not OSI-approved. Free for personal, educational, and other noncommercial use.
68
+
69
+ **Commercial use is not permitted by default, and "commercial" is read broadly.** The license covers any purpose related to running a business — including internal tools, and use at a company whose product has nothing to do with this library — not just redistributing or reselling it.
70
+
71
+ **Commercial licenses are available on request.** If you want to use this commercially, or you are not sure whether your use qualifies, open an issue at [github.com/jimka/typescript-ui/issues](https://github.com/jimka/typescript-ui/issues) — I would rather answer the question than have you guess.
85
72
 
86
73
  Third-party material redistributed with this project (Font Awesome Free icons, the Manrope font, and d3 charting math) is covered by its own license — see [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md) for the full attributions and license texts, and [LICENSE-FONTAWESOME.md](LICENSE-FONTAWESOME.md) for the Font Awesome specifics.
@@ -0,0 +1,2 @@
1
+ import{l as e}from"./Position-DJKB0N3l.js";import{y as t}from"./Component-Bs6TvaGZ.js";import{t as n}from"./Text-DJoUHukb.js";import{t as r}from"./AbstractInput-CfjW_HM2.js";var AbstractBooleanInput=class extends r{_label=null;getLabel(){return this._options.label??null}setLabel(e){return this._options.label=e,this.applyLabel(e),this}getBaseline(){return this._label===null?this.wrapInnerBaseline(e.measureTextBaseline()):this.wrapInnerBaseline(this._label.getBaseline())}applyLabel(e){if(e===null){this._label!==null&&(super.removeComponent(this._label),this._label=null);return}this._label===null?(this._label=new n(e),this._label.setPointerEvents(`none`),super.addComponent(this._label)):this._label.setText(e)}applyEnabled(e){this.getAria().setDisabled(!e),this.getAria().setTabIndex(e?0:-1),this.getInteractiveSurface().setCursor(e?`pointer`:`default`)}applyReadOnly(e){this.getAria().setReadOnly(e)}handleActivationKey(e){this.activationKeys().includes(e.key)&&(e.preventDefault(),this.isEnabled()&&!this.isReadOnly()&&this.activate())}installKeyboard(){t.addListener(this,`keydown`,this.handleActivationKey)}activateFromPointer(){this.isEnabled()&&!this.isReadOnly()&&this.activate()}activationKeys(){return[` `]}};export{AbstractBooleanInput as t};
2
+ //# sourceMappingURL=AbstractBooleanInput-C6CidMMX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractBooleanInput-C6CidMMX.js","names":[],"sources":["../../src/typescript/lib/component/input/AbstractBooleanInput.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { Util } from \"~/core/Util.js\";\n\n/**\n * Construction-time options shared by the boolean-valued controls\n * ({@link Checkbox}, {@link RadioButton}, {@link Toggle}). Concrete subclasses\n * extend this with their own value / selected / indeterminate fields.\n *\n * @category Components\n */\nexport interface AbstractBooleanInputOptions extends AbstractInputOptions {\n label?: string | null;\n}\n\n/**\n * Abstract base for the three boolean-valued form controls — {@link Checkbox},\n * {@link RadioButton}, {@link Toggle}. Owns the mechanics they share verbatim:\n * the optional inline `_label` {@link Text} (mount / replace / remove), the\n * enabled / read-only ARIA + tabindex + interactive-surface cursor reflection,\n * the label-or-text baseline, and the keyboard-activation wiring routed through\n * the same enabled/read-only guard as pointer activation.\n *\n * Each subclass supplies only what differs: its inner graphic (the interactive\n * surface), the value mutation performed on activation, and — for {@link Toggle}\n * — the activation keys and a pill-centred baseline override. The value\n * semantics (`isSelected` /\n * `setSelected` / `getValue` / `setValue`, indeterminate handling, `ButtonGroup`\n * change firing, synthetic-click behaviour) stay in the subclasses.\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated.\n *\n * @category Components\n */\nabstract class AbstractBooleanInput<\n TOptions extends AbstractBooleanInputOptions = AbstractBooleanInputOptions\n>\n extends AbstractInput<boolean, TOptions>\n{\n // Written by `applyLabel` from the subclass constructor body (after\n // super()), never by a cascade-dispatched setter, so a plain `= null`\n // initializer is safe.\n protected _label: Text | null = null;\n\n /**\n * Returns the label text, or `null` when none was set.\n *\n * @returns The label string, or `null`.\n */\n getLabel(): string | null {\n return this._options.label ?? null;\n }\n\n /**\n * Sets the inline label text. Pass `null` to remove the label entirely.\n *\n * @param text - The label text, or `null` to clear.\n *\n * @returns This component, for method chaining.\n */\n setLabel(text: string | null): this {\n this._options.label = text;\n this.applyLabel(text);\n\n return this;\n }\n\n /**\n * Returns the offset from the top of the control to its inline label's text\n * baseline, or — when there is no label — to the text baseline the graphic\n * would share with a label, so a label-less graphic still sits on a row's\n * baseline.\n *\n * @returns The baseline offset in pixels.\n *\n * @remarks A `null` baseline auto-centres the graphic within the row's\n * text-line height, which floats a small graphic to the row centre once a\n * tall sibling (e.g. a `TextArea`) inflates the row's descent. Returning the\n * text-line baseline keeps the graphic aligned exactly as a labelled\n * control's graphic would be. {@link Toggle} overrides this for its taller\n * pill.\n */\n getBaseline(): number | null {\n if (this._label === null) {\n return this.wrapInnerBaseline(Util.measureTextBaseline());\n }\n\n return this.wrapInnerBaseline(this._label.getBaseline());\n }\n\n /**\n * Mounts, replaces, or removes the inline label.\n *\n * @param text - The label text, or `null` to remove the label.\n */\n protected applyLabel(text: string | null): void {\n if (text === null) {\n if (this._label !== null) {\n super.removeComponent(this._label);\n this._label = null;\n }\n\n return;\n }\n\n if (this._label === null) {\n this._label = new Text(text);\n this._label.setPointerEvents(\"none\");\n super.addComponent(this._label);\n } else {\n this._label.setText(text);\n }\n }\n\n /**\n * Reflects the enabled flag in the ARIA tree, the tabindex, and the\n * interactive surface's cursor.\n *\n * @param value - The new enabled state.\n */\n protected applyEnabled(value: boolean): void {\n this.getAria().setDisabled(!value);\n this.getAria().setTabIndex(value ? 0 : -1);\n this.getInteractiveSurface().setCursor(value ? \"pointer\" : \"default\");\n }\n\n /**\n * Reflects the read-only flag in the ARIA tree.\n *\n * @param value - The new read-only state.\n */\n protected applyReadOnly(value: boolean): void {\n this.getAria().setReadOnly(value);\n }\n\n /**\n * Keydown handler: activates the control when the pressed key is one of\n * {@link activationKeys} and the control is enabled and not read-only.\n *\n * @param e - The keyboard event.\n */\n private handleActivationKey(e: KeyboardEvent): void {\n if (!this.activationKeys().includes(e.key)) {\n return;\n }\n\n e.preventDefault();\n\n if (this.isEnabled() && !this.isReadOnly()) {\n this.activate();\n }\n }\n\n /**\n * Wires the keyboard-activation listener on the focused root. Called from\n * each subclass constructor after its graphic is built.\n */\n protected installKeyboard(): void {\n Event.addListener(this, \"keydown\", this.handleActivationKey);\n }\n\n /**\n * Activates the control from a pointer click, subject to the same\n * enabled/read-only guard as the keyboard path. Wired by each subclass\n * onto its interactive surface (so the hit area is exactly the visible\n * graphic).\n */\n protected activateFromPointer(): void {\n if (this.isEnabled() && !this.isReadOnly()) {\n this.activate();\n }\n }\n\n /**\n * Keys that activate the control. Defaults to Space; {@link Toggle} widens\n * it to Space and Enter.\n *\n * @returns The activation key strings.\n */\n protected activationKeys(): string[] {\n return [\" \"];\n }\n\n /**\n * Subclass hook: perform the value mutation for an activation (click or\n * key). Called only after the enabled/read-only guard has passed.\n */\n protected abstract activate(): void;\n\n /**\n * Subclass hook: the inner graphic that owns the click + cursor surface\n * ({@link Checkbox}'s box, {@link RadioButton}'s ring, {@link Toggle}'s\n * track).\n *\n * @returns The interactive surface component.\n */\n protected abstract getInteractiveSurface(): Component;\n}\n\nexport { AbstractBooleanInput };\n"],"mappings":"8KAsCA,IAAe,qBAAf,cAGY,CACZ,CAII,OAAgC,KAOhC,UAA0B,CACtB,OAAO,KAAK,SAAS,OAAS,IAClC,CASA,SAAS,EAA2B,CAIhC,MAHA,MAAK,SAAS,MAAQ,EACtB,KAAK,WAAW,CAAI,EAEb,IACX,CAiBA,aAA6B,CAKzB,OAJI,KAAK,SAAW,KACT,KAAK,kBAAkB,EAAK,oBAAoB,CAAC,EAGrD,KAAK,kBAAkB,KAAK,OAAO,YAAY,CAAC,CAC3D,CAOA,WAAqB,EAA2B,CAC5C,GAAI,IAAS,KAAM,CACX,KAAK,SAAW,OAChB,MAAM,gBAAgB,KAAK,MAAM,EACjC,KAAK,OAAS,MAGlB,MACJ,CAEI,KAAK,SAAW,MAChB,KAAK,OAAS,IAAI,EAAK,CAAI,EAC3B,KAAK,OAAO,iBAAiB,MAAM,EACnC,MAAM,aAAa,KAAK,MAAM,GAE9B,KAAK,OAAO,QAAQ,CAAI,CAEhC,CAQA,aAAuB,EAAsB,CACzC,KAAK,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAK,EACjC,KAAK,QAAQ,CAAC,CAAC,YAAY,EAAQ,EAAI,EAAE,EACzC,KAAK,sBAAsB,CAAC,CAAC,UAAU,EAAQ,UAAY,SAAS,CACxE,CAOA,cAAwB,EAAsB,CAC1C,KAAK,QAAQ,CAAC,CAAC,YAAY,CAAK,CACpC,CAQA,oBAA4B,EAAwB,CAC3C,KAAK,eAAe,CAAC,CAAC,SAAS,EAAE,GAAG,IAIzC,EAAE,eAAe,EAEb,KAAK,UAAU,GAAK,CAAC,KAAK,WAAW,GACrC,KAAK,SAAS,EAEtB,CAMA,iBAAkC,CAC9B,EAAM,YAAY,KAAM,UAAW,KAAK,mBAAmB,CAC/D,CAQA,qBAAsC,CAC9B,KAAK,UAAU,GAAK,CAAC,KAAK,WAAW,GACrC,KAAK,SAAS,CAEtB,CAQA,gBAAqC,CACjC,MAAO,CAAC,GAAG,CACf,CAgBJ"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./Component-Bs6TvaGZ.js";import{t}from"./ListenerBag-WPdKuuds.js";var AbstractInput=class extends e{_listeners=new t;constructor(e,t){super(e,t),this.applyListeners(e?.listeners)}isEnabled(){return this._options.enabled??!0}setEnabled(e){return this._options.enabled=!!e,this.applyEnabled(this._options.enabled),this}isReadOnly(){return this._options.readOnly??!1}setReadOnly(e){return this._options.readOnly=!!e,this.applyReadOnly(this._options.readOnly),this}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}notifyChange(e){this.emit(`change`,e),this.emit(`binding`)}applyOptions(e){return super.applyOptions(e),e.enabled!==void 0&&(this._options.enabled=e.enabled),e.readOnly!==void 0&&(this._options.readOnly=e.readOnly),this}};export{AbstractInput as t};
2
+ //# sourceMappingURL=AbstractInput-CfjW_HM2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractInput-CfjW_HM2.js","names":[],"sources":["../../src/typescript/lib/component/input/AbstractInput.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { Bindable } from \"~/core/Bindable.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\n\n/**\n * String-literal union of the events emitted by every {@link AbstractInput}\n * subclass.\n *\n * @category Components\n */\nexport type AbstractInputEvent = \"change\" | \"binding\";\n\n/**\n * Construction-time options for {@link AbstractInput}. Extended by every\n * value-bearing input control so the `enabled` / `readOnly` flags share a\n * single options surface.\n *\n * @category Components\n */\nexport interface AbstractInputOptions extends ComponentOptions {\n enabled?: boolean;\n readOnly?: boolean;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Each\n * entry is wired as if `on(event, fn)` had been called. Concrete subclasses\n * that expose `on(\"action\", …)` widen this with their own `action?` key.\n */\n listeners?: {\n change?: (value: any) => void;\n binding?: () => void;\n };\n}\n\n/**\n * Abstract base for every value-bearing input control in the framework.\n *\n * Owns the [`Bindable`](/api/core/interfaces/Bindable) value contract, the\n * change/binding listener bookkeeping, and the cached `_options.enabled` /\n * `_options.readOnly` state. Concrete subclasses own their value storage\n * and implement the `applyEnabled` / `applyReadOnly` hooks for their own\n * visual + ARIA wiring.\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated;\n * the [ARCHITECTURE.md](/ARCHITECTURE.md) rule about callable-wrapping\n * applies only to concrete component subclasses.\n *\n * @category Components\n */\nabstract class AbstractInput<\n TValue,\n TOptions extends AbstractInputOptions = AbstractInputOptions\n>\n extends Component<TOptions>\n implements Bindable<TValue>\n{\n private _listeners: ListenerBag<AbstractInputEvent> = new ListenerBag<AbstractInputEvent>();\n\n /**\n * @param options - Caller-supplied options bag.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; forwarded to `Component` so the cascade can merge\n * it before dispatching setters.\n */\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n super(options, subclassDefaults);\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. Wiring\n // after super() guarantees `_listeners` exists. A subclass that adds\n // `action` to its bag is wired by this same call (it iterates every\n // key), so leaves must not call `applyListeners` again.\n this.applyListeners(options?.listeners);\n }\n\n /**\n * Returns the current value. Concrete subclasses define the storage —\n * `Checkbox` aliases `isSelected`, `Slider` reads `_options.value`,\n * picker fields keep a private `_value` outside the options bag.\n *\n * @returns The current value.\n */\n abstract getValue(): TValue;\n\n /**\n * Sets the current value. Concrete subclasses implement the storage\n * write, normalisation, and any listener-firing for user-driven\n * commits.\n *\n * @param value - The new value.\n *\n * @returns This component, for method chaining.\n */\n abstract setValue(value: TValue): this;\n\n /**\n * Returns whether the control is enabled.\n *\n * @returns `true` when enabled (defaults to `true` when unset).\n */\n isEnabled(): boolean {\n return this._options.enabled ?? true;\n }\n\n /**\n * Enables or disables the control. Dispatches `applyEnabled` so the\n * subclass can reflect the state in its visuals + ARIA tree.\n *\n * @param value - `true` to enable, `false` to disable.\n *\n * @returns This component, for method chaining.\n */\n setEnabled(value: boolean): this {\n this._options.enabled = !!value;\n this.applyEnabled(this._options.enabled);\n\n return this;\n }\n\n /**\n * Returns whether the control is read-only.\n *\n * @returns `true` when read-only (defaults to `false` when unset).\n */\n isReadOnly(): boolean {\n return this._options.readOnly ?? false;\n }\n\n /**\n * Marks the control as read-only. Dispatches `applyReadOnly` so the\n * subclass can reflect the state in its visuals + ARIA tree.\n *\n * @param value - `true` to mark read-only.\n *\n * @returns This component, for method chaining.\n */\n setReadOnly(value: boolean): this {\n this._options.readOnly = !!value;\n this.applyReadOnly(this._options.readOnly);\n\n return this;\n }\n\n /**\n * Registers a listener for one of this input's events.\n *\n * @param event - `\"change\"` fires on every committed value change with\n * the new value; `\"binding\"` fires on every user-driven change with\n * no arguments (consumed by [`Binding`](/api/core/classes/Binding)).\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"change\", listener: (value: TValue) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: AbstractInputEvent, 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\n * reference must match.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: AbstractInputEvent, listener: Function): this {\n this._listeners.remove(event, listener);\n\n return this;\n }\n\n /**\n * Fires every registered listener for `event` with `payload`, in\n * registration order. Subclasses call this after committing a\n * user-driven value change.\n *\n * @param event - The event to emit.\n * @param payload - Forwarded to each listener.\n */\n protected emit(event: \"change\", value: TValue): void;\n protected emit(event: \"binding\"): void;\n protected emit(event: AbstractInputEvent, ...payload: unknown[]): void {\n this._listeners.fire(event, ...payload);\n }\n\n /**\n * Fires `\"change\"` listeners with `value` and `\"binding\"` listeners\n * with no arguments. Subclasses call this after committing a\n * user-driven value change.\n *\n * @param value - The newly committed value.\n */\n protected notifyChange(value: TValue): void {\n this.emit(\"change\", value);\n this.emit(\"binding\");\n }\n\n /**\n * Subclass hook: reflect the enabled state in visuals + ARIA. Called\n * from {@link setEnabled} after the cached state is updated.\n *\n * @param value - The new enabled state.\n */\n protected abstract applyEnabled(value: boolean): void;\n\n /**\n * Subclass hook: reflect the read-only state in visuals + ARIA. Called\n * from {@link setReadOnly} after the cached state is updated.\n *\n * @param value - The new read-only state.\n */\n protected abstract applyReadOnly(value: boolean): void;\n\n /**\n * Applies an {@link AbstractInputOptions} bag, caching the `enabled` /\n * `readOnly` flags on `_options`. The setters are intentionally NOT\n * dispatched here: subclasses build their children after `super()`\n * returns and dispatch `applyEnabled` / `applyReadOnly` themselves from\n * the constructor tail once those children exist (otherwise the abstract\n * `applyX` hooks would fire against half-built state).\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @returns This component, for method chaining.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n if (options.enabled !== undefined) this._options.enabled = options.enabled;\n if (options.readOnly !== undefined) this._options.readOnly = options.readOnly;\n\n return this;\n }\n}\n\nexport { AbstractInput };\n"],"mappings":"qFAkDA,IAAe,cAAf,cAIY,CAEZ,CACI,WAAsD,IAAI,EAQ1D,YAAY,EAAoB,EAAsC,CAClE,MAAM,EAAS,CAAgB,EAQ/B,KAAK,eAAe,GAAS,SAAS,CAC1C,CA2BA,WAAqB,CACjB,OAAO,KAAK,SAAS,SAAW,EACpC,CAUA,WAAW,EAAsB,CAI7B,MAHA,MAAK,SAAS,QAAU,CAAC,CAAC,EAC1B,KAAK,aAAa,KAAK,SAAS,OAAO,EAEhC,IACX,CAOA,YAAsB,CAClB,OAAO,KAAK,SAAS,UAAY,EACrC,CAUA,YAAY,EAAsB,CAI9B,MAHA,MAAK,SAAS,SAAW,CAAC,CAAC,EAC3B,KAAK,cAAc,KAAK,SAAS,QAAQ,EAElC,IACX,CAcA,GAAG,EAA2B,EAA0B,CAGpD,OAFA,KAAK,WAAW,IAAI,EAAO,CAAQ,EAE5B,IACX,CAWA,IAAI,EAA2B,EAA0B,CAGrD,OAFA,KAAK,WAAW,OAAO,EAAO,CAAQ,EAE/B,IACX,CAYA,KAAe,EAA2B,GAAG,EAA0B,CACnE,KAAK,WAAW,KAAK,EAAO,GAAG,CAAO,CAC1C,CASA,aAAuB,EAAqB,CACxC,KAAK,KAAK,SAAU,CAAK,EACzB,KAAK,KAAK,SAAS,CACvB,CA8BA,aAAuB,EAAyB,CAM5C,OALA,MAAM,aAAa,CAAO,EAEtB,EAAQ,UAAa,IAAA,KAAW,KAAK,SAAS,QAAW,EAAQ,SACjE,EAAQ,WAAa,IAAA,KAAW,KAAK,SAAS,SAAW,EAAQ,UAE9D,IACX,CACJ"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./DOM-DeF_dWe2.js";import{t}from"./Position-DJKB0N3l.js";import{f as n,h as r,t as i}from"./Component-Bs6TvaGZ.js";import{a,r as o}from"./Tooltip-5BR7yYEX.js";var s=120,c=4,l=new WeakMap,u={visible:!1,animated:!0,durationMs:s,translatePx:c},AnimatedDropdown=class extends i{_dismissing=!1;_open=!1;_closeHandler=null;_anchorElement=null;constructor(e,n){super(e,{...u,...n??{}}),this.setPosition(t.FIXED)}applyOptions(e){return super.applyOptions(e),this.setAnimated(e.animated??this.isAnimated()),this.setDurationMs(e.durationMs??this.getDurationMs()),this.setTranslatePx(e.translatePx??this.getTranslatePx()),this}setAnimated(e){return this._options.animated=e,this}isAnimated(){return this._options.animated??this._defaultOptions.animated}setDurationMs(e){return this._options.durationMs=e,this}getDurationMs(){return this._options.durationMs??this._defaultOptions.durationMs}setTranslatePx(e){return this._options.translatePx=e,this}getTranslatePx(){return this._options.translatePx??this._defaultOptions.translatePx}showAnimated(){a.register(this),this.setZIndex(a.getZIndex(this)),this._dismissing=!1,this._open=!0;let e=this.getElement(!0);return a.mount(e),this.setVisible(!0),this.isAnimated()?(this.setWillChange(`opacity, transform`),r.play(e,{from:{opacity:`0`,transform:`translateY(-${this.getTranslatePx()}px)`},to:{opacity:`1`,transform:`translateY(0)`},durationMs:this.getDurationMs(),properties:[`opacity`,`transform`],onComplete:()=>{this.setWillChange(null),this.onShowComplete()}}),this):(this.onShowComplete(),this)}hideAnimated(){this._open=!1;let e=this.getElement(),finalize=()=>{this.setVisible(!1),this.removeElement(),a.unregister(this),this.onHideComplete()};return!e||!this.isAnimated()?(finalize(),this):(this._dismissing=!0,this.setWillChange(`opacity, transform`),r.play(e,{to:{opacity:`0`,transform:`translateY(-${this.getTranslatePx()}px)`},durationMs:this.getDurationMs(),properties:[`opacity`,`transform`],onComplete:()=>{if(!this._dismissing){this.setWillChange(null);return}this._dismissing=!1,this.setWillChange(null),finalize()}}),this)}onZIndexChanged(e){this.setZIndex(e)}isOpen(){return this._open}handleKey(e){return!1}placeAnchored(t){let{x:n,y:r}=o(t,{width:this.getWidth(),height:this.getHeight()},e.source.getViewportSize(),{axis:`vertical`});return this.setX(n),this.setY(r),this}onShowComplete(){}onHideComplete(){}getLayerElement(){return this.getElement()??null}getDismissMode(){return`click-outside`}requestClose(){if(this._closeHandler){this._closeHandler();return}this.hideAnimated()}getAnchorElement(){return this._anchorElement}getBand(){return a.Band.Dropdown}setCloseHandler(e){return this._closeHandler=e,this}setAnchorElement(e){return this._anchorElement=e,this}};function fadeShow(e,t){let n=t?.durationMs??s,i=t?.translatePx??c,a=t?.animated??!0;l.set(e,!1);let o=e.getElement();if(!o){t?.onComplete?.();return}if(!a){t?.onComplete?.();return}e.setWillChange(`opacity, transform`),r.play(o,{from:{opacity:`0`,transform:`translateY(-${i}px)`},to:{opacity:`1`,transform:`translateY(0)`},durationMs:n,properties:[`opacity`,`transform`],onComplete:()=>{e.setWillChange(null),t?.onComplete?.()}})}function fadeHideAndDetach(e,t){let n=t?.durationMs??s,i=t?.translatePx??c,a=t?.animated??!0,o=e.getElement(),finalize=()=>{e.setVisible(!1),e.removeElement(),t?.onComplete?.()};if(!o||!a){finalize();return}l.set(e,!0),e.setWillChange(`opacity, transform`),r.play(o,{to:{opacity:`0`,transform:`translateY(-${i}px)`},durationMs:n,properties:[`opacity`,`transform`],onComplete:()=>{if(!l.get(e)){e.setWillChange(null);return}l.set(e,!1),e.setWillChange(null),finalize()}})}var d=n(AnimatedDropdown);export{fadeHideAndDetach as n,fadeShow as r,d as t};
2
+ //# sourceMappingURL=AnimatedDropdown-BFz-DO7R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnimatedDropdown-BFz-DO7R.js","names":[],"sources":["../../src/typescript/lib/core/AnimatedDropdown.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { Animation } from \"~/core/Animation.js\";\nimport { Position } from \"~/primitive/Position.js\";\nimport { LayerManager, DismissableLayer, LayerDismissMode } from \"~/core/LayerManager.js\";\nimport { positionAnchored } from \"~/core/OverlayPosition.js\";\nimport { callable } from \"~/core/Callable.js\";\nimport { DOM, type Rect, type Handle } from \"~/core/DOM.js\";\n\n/** Default fade duration in milliseconds. Matches `MENU_ANIM_DURATION_MS` from `Menu`. */\nconst DEFAULT_DURATION_MS: number = 120;\n\n/** Default entrance vertical-offset distance in pixels. */\nconst DEFAULT_TRANSLATE_PX: number = 4;\n\n/**\n * Per-component `_dismissing` flag used by the free-function form\n * (`fadeShow` / `fadeHideAndDetach`). `WeakMap`-keyed so a `Component` that\n * never opts into the helper carries no extra state.\n */\nconst _dismissingByComponent: WeakMap<Component, boolean> = new WeakMap();\n\n/**\n * Construction-time options for {@link AnimatedDropdown}.\n *\n * @category Core\n */\nexport interface AnimatedDropdownOptions extends ComponentOptions {\n /** When false, `showAnimated` / `hideAnimated` skip the transition. Default: true. */\n animated?: boolean;\n /** Fade duration in milliseconds. Default: 120. */\n durationMs?: number;\n /** Vertical translation distance in pixels for the entrance. Default: 4. */\n translatePx?: number;\n}\n\n/**\n * Options forwarded to the free-function forms `fadeShow` / `fadeHideAndDetach`.\n *\n * @category Core\n */\nexport interface FadeOptions {\n /** Fade duration in milliseconds. Default: 120. */\n durationMs?: number;\n /** Vertical translation distance in pixels for the entrance. Default: 4. */\n translatePx?: number;\n /** When false, the helper bypasses the transition and applies the end state synchronously. Default: true. */\n animated?: boolean;\n /** Called once the fade completes (or immediately when animation is disabled). */\n onComplete?: () => void;\n}\n\n/**\n * User-overridable visual defaults forwarded to `super` via the options bag.\n * These are a pure fallback: a caller value wins, otherwise the getters\n * (`isVisible`, `isAnimated`, `getDurationMs`, `getTranslatePx`) resolve the\n * default — `visible: false` is folded by `Component.isVisible`, the rest are\n * dispatched from `applyOptions` as `options.X ?? this.getX()`.\n */\nconst _defaultAnimatedDropdownOptions: Partial<AnimatedDropdownOptions> = {\n visible: false,\n animated: true,\n durationMs: DEFAULT_DURATION_MS,\n translatePx: DEFAULT_TRANSLATE_PX,\n};\n\n/**\n * Floating panel that fades in on `showAnimated` and fades out + detaches on\n * `hideAnimated`. Subclasses (e.g. picker dropdowns for `ComboBox`, `DateField`,\n * `TimeField`, `DateTimeField`) own the panel's interactive content; this base\n * class owns only the open/close lifecycle, the `opacity + translateY`\n * transition, the dismissing-flag re-entrancy guard, and the `will-change`\n * pre-promotion.\n *\n * Positioning math (anchor rect, viewport clamping, flip-above-anchor) lives\n * in the host component or in a subclass — `AnimatedDropdown` does not\n * presume anything about where it should appear.\n *\n * ## Pointer-down contract for hosts mounted under a re-used input element\n *\n * Hosts that compose this dropdown alongside a focusable element whose `blur`\n * commits state (e.g. [`CellEditorPool`](/api/component/table/classes/CellEditorPool)'s pooled editors) must call\n * `event.preventDefault()` on **`pointerdown`** inside the dropdown so the\n * host element keeps focus while the dropdown's selection callback runs. The\n * callback then explicitly drives commit. If the dropdown does not suppress\n * the blur, the editor's blur listener fires first, commits the stale value,\n * and the dropdown's later write goes to a no-longer-active editor.\n *\n * @category Core\n */\nclass AnimatedDropdown<TOptions extends AnimatedDropdownOptions = AnimatedDropdownOptions> extends Component<TOptions> implements DismissableLayer {\n\n // Set true while a fade-out is in flight; reset to false either when the\n // fade completes (so the deferred detach runs) or when a fresh `showAnimated`\n // re-displays the dropdown mid-fade (the deferred detach skips because the\n // dropdown is back on screen).\n private _dismissing: boolean = false;\n private _open: boolean = false;\n\n // Host-supplied close thunk invoked from `requestClose` instead of the\n // bare `hideAnimated`, so the host (a picker field, a ComboBox) can run\n // its own teardown (caret rotation, aria-expanded, commit) when the\n // manager dismisses the layer on an outside click. Null until a host\n // opts into the `\"click-outside\"` dismiss path.\n private _closeHandler: (() => void) | null = null;\n\n // Anchor element (the trigger) excluded from the manager's outside-click\n // test so the click that toggles the dropdown does not immediately\n // re-close it. Null for dropdowns whose host owns the toggle gating.\n private _anchorElement: Handle | null = null;\n\n /**\n * @param options - Optional construction-time options.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults. Subclasses-of-subclasses forward their own defaults\n * here so the deepest class's values win.\n */\n constructor(options?: AnimatedDropdownOptions, subclassDefaults?: Partial<AnimatedDropdownOptions>) {\n super(\n options as TOptions,\n { ..._defaultAnimatedDropdownOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n // Floating overlays anchor to the viewport, not to a layout-managed\n // ancestor — `Position.FIXED` is the documented exception to the\n // framework's \"every component is absolute\" rule. See\n // ARCHITECTURE.md §Positioning.\n this.setPosition(Position.FIXED);\n }\n\n /**\n * Applies an {@link AnimatedDropdownOptions} bag, dispatching dropdown-specific\n * fields after inherited Component fields.\n *\n * @param options - The options bag carrying the values to apply.\n */\n protected applyOptions(options: TOptions): this {\n super.applyOptions(options);\n\n // These carry a class default and seed construction-time state, so\n // always dispatch the caller value or the class default.\n this.setAnimated(options.animated ?? this.isAnimated());\n this.setDurationMs(options.durationMs ?? this.getDurationMs());\n this.setTranslatePx(options.translatePx ?? this.getTranslatePx());\n\n return this;\n }\n\n /**\n * Enables or disables the fade transition. When false, `showAnimated` /\n * `hideAnimated` apply visibility synchronously.\n *\n * @param value - true to enable the fade; false for instant show/hide.\n */\n setAnimated(value: boolean): this {\n this._options.animated = value;\n\n return this;\n }\n\n /**\n * Returns whether the fade transition is enabled.\n *\n * @returns true when the fade transition runs on show/hide.\n */\n isAnimated(): boolean {\n return this._options.animated ?? this._defaultOptions.animated!;\n }\n\n /**\n * Sets the fade duration in milliseconds.\n *\n * @param ms - Duration in milliseconds.\n */\n setDurationMs(ms: number): this {\n this._options.durationMs = ms;\n\n return this;\n }\n\n /**\n * Returns the configured fade duration in milliseconds.\n *\n * @returns The duration in milliseconds.\n */\n getDurationMs(): number {\n return this._options.durationMs ?? this._defaultOptions.durationMs!;\n }\n\n /**\n * Sets the entrance vertical-offset distance in pixels.\n *\n * @param px - Translation distance in pixels.\n */\n setTranslatePx(px: number): this {\n this._options.translatePx = px;\n\n return this;\n }\n\n /**\n * Returns the configured entrance vertical-offset distance.\n *\n * @returns The translation distance in pixels.\n */\n getTranslatePx(): number {\n return this._options.translatePx ?? this._defaultOptions.translatePx!;\n }\n\n /**\n * Mounts the dropdown on `document.documentElement` (if not already mounted)\n * and plays the entrance fade. Cancels any in-flight fade-out so a fresh\n * show mid-dismiss keeps the panel on screen.\n */\n showAnimated(): this {\n // Register on the central layer tree. `LayerManager.register` is a\n // no-op when this layer is already registered (a `_dismissing`-\n // cancelled mid-fade re-show), so the tree never double-pushes.\n LayerManager.register(this);\n\n // Mirror the manager's band-based z-stamp onto the element so the\n // dropdown lands above its opener (which registered earlier).\n this.setZIndex(LayerManager.getZIndex(this));\n\n this._dismissing = false;\n this._open = true;\n\n const el = this.getElement(true)!;\n\n LayerManager.mount(el);\n\n this.setVisible(true);\n\n if (!this.isAnimated()) {\n this.onShowComplete();\n return this;\n }\n\n this.setWillChange(\"opacity, transform\");\n\n Animation.play(el, {\n from: { opacity: \"0\", transform: `translateY(-${this.getTranslatePx()}px)` },\n to: { opacity: \"1\", transform: \"translateY(0)\" },\n durationMs: this.getDurationMs(),\n properties: [\"opacity\", \"transform\"],\n onComplete: () => {\n this.setWillChange(null);\n this.onShowComplete();\n },\n });\n\n return this;\n }\n\n /**\n * Plays the exit fade, then hides and detaches the dropdown when the\n * transition completes. A fresh `showAnimated` during the fade cancels the\n * deferred detach by flipping the `_dismissing` flag, so the panel stays\n * mounted.\n */\n hideAnimated(): this {\n this._open = false;\n\n const el = this.getElement();\n const finalize = (): void => {\n this.setVisible(false);\n this.removeElement();\n\n // Pop from the central layer tree. `onHideComplete` runs after\n // this so a subclass override sees the layer as already-closed.\n LayerManager.unregister(this);\n\n this.onHideComplete();\n };\n\n if (!el || !this.isAnimated()) {\n finalize();\n return this;\n }\n\n this._dismissing = true;\n this.setWillChange(\"opacity, transform\");\n\n Animation.play(el, {\n to: { opacity: \"0\", transform: `translateY(-${this.getTranslatePx()}px)` },\n durationMs: this.getDurationMs(),\n properties: [\"opacity\", \"transform\"],\n onComplete: () => {\n if (!this._dismissing) {\n this.setWillChange(null);\n return;\n }\n this._dismissing = false;\n this.setWillChange(null);\n finalize();\n },\n });\n\n return this;\n }\n\n /**\n * Mirrors a manager-allocated z-index onto the element when the dropdown —\n * or the window / surface it was opened inside — is raised via\n * {@link LayerManager.bringToFront}. Without this, the dropdown reads its\n * z once in {@link showAnimated} and never updates; raising its host window\n * (a `mousedown` brings the window to front) would then re-stamp the host\n * above the dropdown's stale z, hiding the open panel — and its fade-out —\n * behind the window.\n *\n * @param zIndex - The fresh z-index assigned by the manager.\n */\n onZIndexChanged(zIndex: number): void {\n this.setZIndex(zIndex);\n }\n\n /**\n * Returns whether the dropdown is currently open (showing or fading in).\n *\n * @returns true when the dropdown is open.\n */\n isOpen(): boolean {\n return this._open;\n }\n\n /**\n * Subclass hook: handle a keystroke arriving via the host input's `keydown`\n * listener while the dropdown is open. Subclasses with a navigation surface\n * (e.g. [`DatePickerDropdown`](/api/component/input/classes/DatePickerDropdown))\n * override to consume arrows / Page / Home / End / type-ahead. The base\n * implementation returns `false` so plain dropdowns without keyboard\n * semantics let the host input's contract run.\n *\n * @param _e - The keyboard event forwarded from the host input.\n * @returns True when the dropdown consumed the keystroke (caller should `preventDefault`).\n */\n handleKey(_e: KeyboardEvent): boolean {\n return false;\n }\n\n /**\n * Places the dropdown relative to an anchor rect at its current\n * width/height. Picks the better of \"below\" or \"above\" the anchor\n * vertically (more available space wins when neither side fully fits).\n * Horizontally the panel left-aligns to the anchor, flipping to\n * right-align with the anchor's right edge when the left alignment\n * would overflow the viewport, and clamping only when neither alignment\n * fits.\n *\n * Callers set `setWidth`/`setHeight` first, then invoke this helper.\n *\n * @param rect - The anchor element's bounding rect (typically from\n * `DOM.source.getElementRect(anchorEl)`).\n */\n placeAnchored(rect: Rect): this {\n const size = { width: this.getWidth(), height: this.getHeight() };\n const vp = DOM.source.getViewportSize();\n\n // Vertical growth: prefer below, flip above when below overflows and\n // above has room. Horizontally: align to the anchor's left, flip to\n // its right when that overflows, clamp only as a last resort. The\n // flip/align/clamp geometry lives in the shared pure primitive.\n const { x, y } = positionAnchored(rect, size, vp, { axis: \"vertical\" });\n\n this.setX(x);\n this.setY(y);\n\n return this;\n }\n\n /**\n * Hook invoked after the entrance fade completes (or immediately when\n * animation is disabled). Override to wire post-show state.\n */\n protected onShowComplete(): void {\n // default: no-op\n }\n\n /**\n * Hook invoked after the exit fade completes (or immediately when\n * animation is disabled). Override to wire post-hide cleanup.\n */\n protected onHideComplete(): void {\n // default: no-op\n }\n\n // ----- DismissableLayer -----\n\n /**\n * Returns the dropdown's root element for the central layer tree.\n *\n * @returns The dropdown's element, or null when not yet rendered.\n */\n getLayerElement(): Handle | null {\n return this.getElement() ?? null;\n }\n\n /**\n * Returns the dismiss mode the document-level handlers consult. The\n * dropdown is `\"click-outside\"`: the manager closes it when a\n * `pointerdown` lands outside both the dropdown's layer subtree and its\n * anchor. A click inside a descendant layer counts as inside, so a nested\n * dropdown keeps its opener open.\n *\n * @returns The layer dismiss mode.\n */\n getDismissMode(): LayerDismissMode {\n return \"click-outside\";\n }\n\n /**\n * Advisory close request from the manager. Runs the host-supplied close\n * thunk when one is set (so the host can rotate a caret, clear\n * aria-expanded, or commit), otherwise the standard exit fade + detach.\n */\n requestClose(): void {\n if (this._closeHandler) {\n this._closeHandler();\n\n return;\n }\n\n this.hideAnimated();\n }\n\n /**\n * Returns the anchor element excluded from the manager's outside-click\n * test, or null when the host gates the toggle itself.\n *\n * @returns The anchor element, or null.\n */\n getAnchorElement(): Handle | null {\n return this._anchorElement;\n }\n\n /**\n * Returns the dropdown's z-index band so an unrelated top-level dropdown\n * stacks in the dropdown family.\n *\n * @returns The dropdown band base.\n */\n getBand(): number {\n return LayerManager.Band.Dropdown;\n }\n\n /**\n * Installs the close thunk the manager calls from {@link requestClose}\n * when this dropdown is dismissed by an outside click. The host passes its\n * own close routine so the dropdown's teardown and the host's UI state\n * (caret, aria-expanded, commit) stay in lockstep.\n *\n * @param handler - The host's close routine, or null to fall back to\n * {@link hideAnimated}.\n * @returns This dropdown, for method chaining.\n */\n setCloseHandler(handler: (() => void) | null): this {\n this._closeHandler = handler;\n\n return this;\n }\n\n /**\n * Records the anchor (trigger) element excluded from the manager's\n * outside-click test, so the gesture that opened the dropdown does not\n * immediately re-close it.\n *\n * @param el - The anchor element, or null to clear it.\n * @returns This dropdown, for method chaining.\n */\n setAnchorElement(el: Handle | null): this {\n this._anchorElement = el;\n\n return this;\n }\n\n}\n\n/**\n * Plays the standard dropdown-style entrance fade on the given component's\n * element. Mirror of {@link AnimatedDropdown.showAnimated} for components that\n * extend `Component` directly and cannot re-parent to `AnimatedDropdown`.\n *\n * Cancels any in-flight fade-out queued by {@link fadeHideAndDetach} so a\n * fresh show mid-dismiss keeps the panel on screen.\n *\n * @param component - The component to fade in.\n * @param options - Optional duration / translate / animated overrides.\n */\nexport function fadeShow(component: Component, options?: FadeOptions): void {\n const durationMs = options?.durationMs ?? DEFAULT_DURATION_MS;\n const translatePx = options?.translatePx ?? DEFAULT_TRANSLATE_PX;\n const animated = options?.animated ?? true;\n\n _dismissingByComponent.set(component, false);\n\n const el = component.getElement();\n\n if (!el) {\n options?.onComplete?.();\n return;\n }\n\n if (!animated) {\n options?.onComplete?.();\n return;\n }\n\n component.setWillChange(\"opacity, transform\");\n\n Animation.play(el, {\n from: { opacity: \"0\", transform: `translateY(-${translatePx}px)` },\n to: { opacity: \"1\", transform: \"translateY(0)\" },\n durationMs: durationMs,\n properties: [\"opacity\", \"transform\"],\n onComplete: () => {\n component.setWillChange(null);\n options?.onComplete?.();\n },\n });\n}\n\n/**\n * Plays the standard dropdown-style exit fade on the given component's\n * element, then hides and detaches it from the DOM when the transition\n * completes.\n *\n * A fresh {@link fadeShow} during the fade cancels the deferred detach so the\n * panel stays mounted.\n *\n * @param component - The component to fade out and detach.\n * @param options - Optional duration / translate / animated overrides; `onComplete` fires after detach.\n */\nexport function fadeHideAndDetach(component: Component, options?: FadeOptions): void {\n const durationMs = options?.durationMs ?? DEFAULT_DURATION_MS;\n const translatePx = options?.translatePx ?? DEFAULT_TRANSLATE_PX;\n const animated = options?.animated ?? true;\n\n const el = component.getElement();\n const finalize = (): void => {\n component.setVisible(false);\n component.removeElement();\n options?.onComplete?.();\n };\n\n if (!el || !animated) {\n finalize();\n return;\n }\n\n _dismissingByComponent.set(component, true);\n component.setWillChange(\"opacity, transform\");\n\n Animation.play(el, {\n to: { opacity: \"0\", transform: `translateY(-${translatePx}px)` },\n durationMs: durationMs,\n properties: [\"opacity\", \"transform\"],\n onComplete: () => {\n if (!_dismissingByComponent.get(component)) {\n component.setWillChange(null);\n return;\n }\n _dismissingByComponent.set(component, false);\n component.setWillChange(null);\n finalize();\n },\n });\n}\n\nconst AnimatedDropdownCallable = callable(AnimatedDropdown);\ntype AnimatedDropdownCallable<TOptions extends AnimatedDropdownOptions = AnimatedDropdownOptions> = AnimatedDropdown<TOptions>;\nexport {\n AnimatedDropdown as _AnimatedDropdown,\n AnimatedDropdownCallable as AnimatedDropdown\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{t as e}from"./DOM-DeF_dWe2.js";import{a as t,s as n}from"./Position-DJKB0N3l.js";import{_ as r,d as i,f as a,h as o,l as s,t as c,y as l}from"./Component-Bs6TvaGZ.js";import{t as u}from"./ListenerBag-WPdKuuds.js";import{t as d}from"./Tooltip-5BR7yYEX.js";import{t as f}from"./Placement-7kqdaK4Z.js";import{t as p}from"./LayoutConstraints-CHI2lhPd.js";function beginPointerDrag(t){e.sink.apply(e.source.getBody(),{style:{pointerEvents:`none`}}),e.sink.apply(e.source.getDocumentElement(),{style:{cursor:t}})}function endPointerDrag(){e.sink.apply(e.source.getBody(),{style:{pointerEvents:``}}),e.sink.apply(e.source.getDocumentElement(),{style:{cursor:``}})}var m=200,h=`cubic-bezier(0.4, 0, 0.6, 1)`;function primeCollapse(e,t,n,r){if(o.isReducedMotion())return;let i=t.map(e=>`${e} ${m}ms ${h}`).join(`, `);for(let e of n)e.setTransition(i);e.setWillChange(t.join(`, `)),o.afterTransition({component:e,property:r??t[0],durationMs:m,fallbackBufferMs:40,onComplete:()=>{for(let e of n)e.setTransition(null);e.setWillChange(null)}})}function captureRect(e){return{x:e.getX(),y:e.getY(),width:e.getWidth(),height:e.getHeight()}}function parseCubicBezier(e){let t=e.match(/cubic-bezier\(([^)]+)\)/);if(!t)return e=>e;let[n,r,i,a]=t[1].split(`,`).map(e=>parseFloat(e)),o=3*n,s=3*(i-n)-o,c=1-o-s,l=3*r,u=3*(a-r)-l,d=1-l-u,sampleX=e=>((c*e+s)*e+o)*e,sampleY=e=>((d*e+u)*e+l)*e,sampleDX=e=>(3*c*e+2*s)*e+o;return e=>{let t=e;for(let n=0;n<8;n+=1){let n=sampleX(t)-e;if(Math.abs(n)<1e-6)return sampleY(t);let r=sampleDX(t);if(Math.abs(r)<1e-6)break;t-=n/r}let n=0,r=1;for(t=e;n<r;){let i=sampleX(t);if(Math.abs(i-e)<1e-6)break;i<e?n=t:r=t,t=(n+r)/2}return sampleY(t)}}var g=parseCubicBezier(h),lerp=(e,t,n)=>e+(t-e)*n,lerpRect=(e,t,n)=>({x:lerp(e.x,t.x,n),y:lerp(e.y,t.y,n),width:lerp(e.width,t.width,n),height:lerp(e.height,t.height,n)});function commitRect(e,t,n){e.setAutoCommitStyle(!1),e.setX(t.x),e.setY(t.y),e.setWidth(t.width),e.setHeight(t.height),n&&e.doLayout(),e.setAutoCommitStyle(!0)}function animateLayout(t,n){if(o.isReducedMotion()){for(let e of t)commitRect(e.component,e.end,e.relayout);return n?.(),()=>{}}let r=!1,i=0;for(let e of t)commitRect(e.component,e.start,e.relayout);let a=performance.now(),frame=o=>{if(r)return;let s=Math.min(1,(o-a)/m),c=g(s);for(let e of t)commitRect(e.component,s>=1?e.end:lerpRect(e.start,e.end,c),e.relayout);s<1?i=e.sink.requestAnimationFrame(frame):n?.()};return i=e.sink.requestAnimationFrame(frame),()=>{r=!0,i&&e.sink.cancelAnimationFrame(i)}}function runCollapse(e,t,n,r,i){r?.(),primeCollapse(t,[`clip-path`],[t],`clip-path`);let a=n.filter(e=>!e.relayout).map(e=>e.component);a.length>0&&primeCollapse(a[0],[`background-color`],a,`background-color`);let o=n.map(e=>captureRect(e.component));return e.doLayout(),animateLayout(n.map((e,t)=>({component:e.component,relayout:e.relayout,start:o[t],end:captureRect(e.component)})),i)}var _=10,v=40,y={east:0,south:90,west:180,north:-90},b=null;function ensureCollapseButtonClassRule(){b||=new r({scope:`class`,name:`CollapseButton`,styles:{position:`absolute`,top:`50%`,left:`50%`,transform:`translate(-50%, -50%)`,boxSizing:`border-box`,width:`${_}px`,height:`${v}px`,borderRadius:`2px`,background:`var(--ts-ui-button-bg, #e8e8e8)`,border:`1px solid var(--ts-ui-button-border, #c8c8c8)`,boxShadow:`var(--ts-ui-button-shadow, 0 1px 2px rgba(0, 0, 0, 0.2))`,textAlign:`center`,fontSize:`9px`,lineHeight:`${v-2}px`,color:`var(--ts-ui-collapse-button-color, rgb(100,100,100))`,pointerEvents:`auto`,userSelect:`none`}})}var CollapseButton=class extends c{_listeners=new u;constructor(e){ensureCollapseButtonClassRule(),super({tag:`span`,cursor:`pointer`,...e??{}}),this._direction??=`east`,this.applyRotation(),this.applyListeners(e?.listeners),l.addListener(this,`dblclick`,this.onDoubleClick),l.addListener(this,`mousedown`,this.onMouseDown)}applyOptions(e){return super.applyOptions(e),e.direction!==void 0&&this.setDirection(e.direction),this}render(){let t=super.render();return e.sink.apply(t,{text:`▶`}),t}applyRotation(){let e=y[this._direction];this.createStyleRule(``).set(`transform`,`translate(-50%, -50%) rotate(${e}deg)`)}setStripMode(e){return this.createStyleRule(``).set(`width`,`${e?18:_}px`),this}getDirection(){return this._direction}setDirection(e){return this._direction=e,this.applyRotation(),this}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e){this._listeners.fire(e)}onDoubleClick(e){e.stopPropagation(),this.emit(`collapse`)}onMouseDown(e){e.stopPropagation()}destroy(){l.removeListener(this,`dblclick`,this.onDoubleClick),l.removeListener(this,`mousedown`,this.onMouseDown)}},x=a(CollapseButton),S={west:`east`,east:`west`,north:`south`,south:`north`},C={orientation:`horizontal`,collapsible:!0,movable:!0},SplitGutter=class extends c{_opaque=!1;_collapseDirection=`west`;_expandedBackground=`var(--ts-ui-gutter-bg, #AAAAAA)`;_tooltipText=``;_listeners=new u;constructor(e,t){super(t,C),e&&t?.orientation===void 0&&(this._direction=e),this._expandedBackground=t?.expandedBackground??`var(--ts-ui-gutter-bg, #AAAAAA)`,this.setBackgroundColor(this._expandedBackground),this._collapseDirection=t?.collapseDirection??(this._direction===`horizontal`?`west`:`north`),this._collapseButton=new x({direction:this._collapseDirection,listeners:{collapse:()=>this.emit(`collapse`)}}),this._collapseButton.setVisible(this._collapsible),t?.opaque&&this.setOpaque(!0),this._movable||this.setPointerEvents(`none`),this._movable&&l.addListener(this,`mousedown`,this.onDragStart),this.applyListeners(t?.listeners),this.updateTooltip()}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._collapseButton.getElement(!0)),this}isCollapsible(){return this._collapsible??this._defaultOptions.collapsible}setCollapsible(e){return this._collapsible=e,this._collapseButton?.setVisible(e),this._collapseButton&&this.updateTooltip(),this}applyOptions(e){return super.applyOptions(e),this.setDirection(e.orientation??this.getDirection()),this.setCollapsible(e.collapsible??this.isCollapsible()),this.setMovable(e.movable??this.isMovable()),this}isMovable(){return this._movable??this._defaultOptions.movable}setMovable(e){return this._movable=e,this}isOpaque(){return this._opaque}setOpaque(e){return this._opaque=e,e?(this.setBackgroundColor(`var(--ts-ui-button-bg, #e8e8e8)`),this.setBackgroundImage(`var(--ts-ui-button-bg, linear-gradient(rgb(241, 241, 241), rgb(200, 200, 200)))`),this.setBorder(`1px solid var(--ts-ui-button-border, #c8c8c8)`),this._collapseButton?.setDirection(S[this._collapseDirection])):(this.clearBackgroundImage(),this.clearBorder(),this.setBackgroundColor(this._expandedBackground),this._collapseButton?.setDirection(this._collapseDirection)),this._collapseButton?.setStripMode(e),this.applyCursor(),this.updateTooltip(),this}getCollapseDirection(){return this._collapseDirection}setCollapseDirection(e){return this._collapseDirection=e,this._collapseButton?.setDirection(this._opaque?S[e]:e),this.updateTooltip(),this}updateTooltip(){if(!this._collapsible){this._tooltipText!==``&&(d.detach(this),this._collapseButton&&d.detach(this._collapseButton),this._tooltipText=``);return}let e=`Double-click to ${this._opaque?`expand`:`collapse`} ${this._opaque?S[this._collapseDirection]:this._collapseDirection}ward`;e!==this._tooltipText&&(this._tooltipText=e,d.attach(this,e),this._collapseButton&&d.attach(this._collapseButton,e))}getDirection(){return this._direction??this._defaultOptions.orientation}setDirection(e){return e||=`horizontal`,this._direction=e,this}on(e,t){return this._listeners.add(e,t),this}off(e,t){return this._listeners.remove(e,t),this}emit(e,...t){this._listeners.fire(e,...t)}destroy(){l.removeListener(this,`mousedown`,this.onDragStart),this._collapseButton?.destroy()}_dispatchDrag(e){this.emit(`drag`,e)}onDragStart(e){if(this._opaque)return;let t=this._direction===`horizontal`?e.clientX:e.clientY;this.emit(`dragstart`,t),l.addViewportListener(this,`mouseup`,this.onDragStop),l.addViewportListener(this,`touchend`,this.onDragStop),l.addViewportListener(this,`touchcancel`,this.onDragStop),l.addViewportListener(this,`mousemove`,this.onDrag),l.addViewportListener(this,`touchmove`,this.onDrag),beginPointerDrag(this.dragCursor())}onDragStop(e){e?.stopPropagation(),l.removeViewportListener(this,`mouseup`,this.onDragStop),l.removeViewportListener(this,`touchend`,this.onDragStop),l.removeViewportListener(this,`touchcancel`,this.onDragStop),l.removeViewportListener(this,`mousemove`,this.onDrag),l.removeViewportListener(this,`touchmove`,this.onDrag),endPointerDrag(),this.emit(`dragend`)}onDrag(e){e.stopPropagation();let t;t=this._direction===`horizontal`?e.clientX:e.clientY,this._dispatchDrag(t)}dragCursor(){return this._direction==`horizontal`?`ew-resize`:`ns-resize`}applyCursor(){this._movable&&!this._opaque?this.setCursor(this.dragCursor()):this.setCursor(`default`)}render(){let e=super.render();return this.applyCursor(),e}},w=a(SplitGutter),T=4,E={[f.NORTH]:`north`,[f.SOUTH]:`south`,[f.WEST]:`west`,[f.EAST]:`east`},Border=class extends s{_northComponent=null;_southComponent=null;_westComponent=null;_eastComponent=null;_centerComponent=null;_spacing=5;_collapsed=new Map;_collapsible=new Map;_gutters=new Map;_collapseAnimation=null;_collapsing=!1;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.spacing!==void 0&&this.setComponentSpacing(e.spacing)}setLayoutConstraints(e,t){switch(t||(t=new p,t.placement=f.CENTER),t.placement||=f.CENTER,t.placement){case f.NORTH:this._northComponent=e;break;case f.SOUTH:this._southComponent=e;break;case f.WEST:this._westComponent=e;break;case f.EAST:this._eastComponent=e;break;case f.CENTER:this._centerComponent=e;break}return t.placement===f.CENTER?this._collapsible.set(f.CENTER,!1):this._collapsible.set(t.placement,t.collapsible??!1),super.setLayoutConstraints(e,t)}delLayoutConstraints(e){return this._northComponent===e?this._northComponent=null:this._southComponent===e?this._southComponent=null:this._westComponent===e?this._westComponent=null:this._eastComponent===e?this._eastComponent=null:this._centerComponent===e&&(this._centerComponent=null),super.delLayoutConstraints(e)}getComponentSpacing(){return this._spacing}setComponentSpacing(e){return this._spacing=e,this}getRegionComponent(e){switch(e){case f.NORTH:return this._northComponent;case f.SOUTH:return this._southComponent;case f.WEST:return this._westComponent;case f.EAST:return this._eastComponent;case f.CENTER:return this._centerComponent}}isRegionCollapsed(e){return this._collapsed.get(e)??!1}setRegionCollapsed(e,t){if(e===f.CENTER||!this.isRegionCollapsible(e))return this;let n=this.getRegionComponent(e);if(!n||(this._collapsed.get(e)??!1)===t)return this;let r=this.getContainer();if(!r)return this;let i=this._collapsing;this._collapsing=!0,i||r.doLayout(),this._collapsed.set(e,t),this.ensureGutter(e);let a=[...[this._northComponent,this._southComponent,this._westComponent,this._eastComponent,this._centerComponent].filter(e=>e!=null).map(e=>({component:e,relayout:!0})),...[...this._gutters.values()].map(e=>({component:e,relayout:!1}))];return this._collapseAnimation=runCollapse(r,n,a,this._collapseAnimation,()=>{this._collapseAnimation=null,this._collapsing=!1,r.doLayout()}),this}isRegionCollapsible(e){return e===f.CENTER?!1:this._collapsible.get(e)??!1}setRegionCollapsible(e,t){return e===f.CENTER?this:(this._collapsible.set(e,t),this.getContainer()?.scheduleLayout(),this)}ensureGutter(t){let n=this._gutters.get(t);if(n)return n;let r=this.getContainer();return n=new w(t===f.NORTH||t===f.SOUTH?`vertical`:`horizontal`,{movable:!1,opaque:!1,collapseDirection:E[t],expandedBackground:`transparent`,listeners:{collapse:()=>this.setRegionCollapsed(t,!this.isRegionCollapsed(t))}}),n.setVisible(!1),e.sink.appendChild(r.getElement(),n.getElement(!0)),this._gutters.set(t,n),n}regionExtent(e,t){return this.isRegionCollapsed(e)?18:t}applyRegionClip(e,t){if(this.isRegionCollapsible(t)){if(!this.isRegionCollapsed(t)){e.setClipPath(`inset(0 0 0 0)`);return}switch(t){case f.WEST:e.setClipPath(`inset(0 100% 0 0)`);break;case f.EAST:e.setClipPath(`inset(0 0 0 100%)`);break;case f.NORTH:e.setClipPath(`inset(0 0 100% 0)`);break;case f.SOUTH:e.setClipPath(`inset(100% 0 0 0)`);break}}}updateRegionGutter(e,t,n,r,i){let a=this.getRegionComponent(e);if(!a)return;if(!this.isRegionCollapsible(e)){a.setVisible(!0),this._gutters.get(e)?.setVisible(!1);return}let o=this.isRegionCollapsed(e),s=this.ensureGutter(e);a.setVisible(!0),s.setOpaque(o),s.setVisible(!0);let c=o?{x:t,y:n,width:r,height:i}:this.innerEdgeTrack(e,t,n,r,i);s.setX(c.x),s.setY(c.y),s.setWidth(c.width),s.setHeight(c.height)}innerEdgeTrack(e,t,n,r,i){switch(e){case f.NORTH:return{x:t,y:n+i,width:r,height:T};case f.SOUTH:return{x:t,y:n-T,width:r,height:T};case f.WEST:return{x:t+r,y:n,width:T,height:i};case f.EAST:return{x:t-T,y:n,width:T,height:i};default:return{x:t,y:n,width:r,height:i}}}laidOut(e){return e&&e.isDisplayed()?e:null}getPreferredSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=t.left+t.right,r=t.top+t.bottom,i=0,a=0,o=0,s=0,c=this.laidOut(this._northComponent),l=this.laidOut(this._southComponent),u=this.laidOut(this._westComponent),d=this.laidOut(this._centerComponent),p=this.laidOut(this._eastComponent);if(c){let e=c.getPreferredSize();e&&(i=Math.max(i,e.width),a+=this.isRegionCollapsed(f.NORTH)?18:e.height)}if(l){let e=l.getPreferredSize();e&&(i=Math.max(i,e.width),a+=this.isRegionCollapsed(f.SOUTH)?18:e.height)}if(u){let e=u.getPreferredSize();e&&(o+=this.isRegionCollapsed(f.WEST)?18:e.width,s+=Math.max(s,e.height))}if(d){let e=d.getPreferredSize();e&&(o+=e.width,s+=Math.max(s,e.height))}if(p){let e=p.getPreferredSize();e&&(o+=this.isRegionCollapsed(f.EAST)?18:e.width,s+=Math.max(s,e.height))}return i=Math.max(i,o),a+=s,{width:i+n,height:a+r}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=t.left+t.right,r=t.top+t.bottom,i=0,a=0,o=0,s=0,c=this.laidOut(this._northComponent),l=this.laidOut(this._southComponent),u=this.laidOut(this._westComponent),d=this.laidOut(this._centerComponent),p=this.laidOut(this._eastComponent);if(c){let e=c.getMinSize();e&&(i=Math.max(i,e.width),a+=this.isRegionCollapsed(f.NORTH)?18:e.height)}if(l){let e=l.getMinSize();e&&(i=Math.max(i,e.width),a+=this.isRegionCollapsed(f.SOUTH)?18:e.height)}if(u){let e=u.getMinSize();e&&(o+=this.isRegionCollapsed(f.WEST)?18:e.width,s+=Math.max(s,e.height))}if(d){let e=d.getMinSize();e&&(o+=e.width,s+=Math.max(s,e.height))}if(p){let e=p.getMinSize();e&&(o+=this.isRegionCollapsed(f.EAST)?18:e.width,s+=Math.max(s,e.height))}return i=Math.max(i,o),a+=s,{width:i+n,height:a+r}}getMaxSize(){let e=this.getContainer();if(!e)return null;let r=e.getPerimeterSize(),i=r.left+r.right,a=r.top+r.bottom,maxOf=e=>this.laidOut(e)?e.getMaxSize()??{width:t,height:t}:null,o=maxOf(this._northComponent),s=maxOf(this._southComponent),c=maxOf(this._westComponent),l=maxOf(this._centerComponent),u=maxOf(this._eastComponent),d=0,f=0,p=!1;for(let e of[c,l,u])e&&(p=!0,d+=e.width,f=Math.max(f,e.height));let m=t;o&&(m=Math.min(m,o.width)),s&&(m=Math.min(m,s.width)),p&&(m=Math.min(m,d));let h=0;return o&&(h+=o.height),p&&(h+=f),s&&(h+=s.height),{width:n(m+i),height:n(h+a)}}computeTotalMinSize(){if(!this.getContainer())return{width:0,height:0};let e=this.laidOut(this._westComponent)?.getMinSize(),t=this.laidOut(this._centerComponent)?.getMinSize(),n=this.laidOut(this._eastComponent)?.getMinSize(),r=this.laidOut(this._northComponent)?.getMinSize(),i=this.laidOut(this._southComponent)?.getMinSize(),a=[];e&&a.push(this.isRegionCollapsed(f.WEST)?18:e.width),t&&a.push(t.width),n&&a.push(this.isRegionCollapsed(f.EAST)?18:n.width);let o=[];r&&o.push(this.isRegionCollapsed(f.NORTH)?18:r.height),t&&o.push(t.height),i&&o.push(this.isRegionCollapsed(f.SOUTH)?18:i.height);let s=0,c=0;for(let e of a)s+=e;s+=Math.max(0,a.length-1)*this._spacing,r&&(s=Math.max(s,r.width)),i&&(s=Math.max(s,i.width));for(let e of o)c+=e;return c+=Math.max(0,o.length-1)*this._spacing,{width:s,height:c}}clearSkippedRegionFrames(...e){[this._northComponent,this._southComponent,this._westComponent,this._centerComponent,this._eastComponent].forEach((t,n)=>{t&&!e[n]&&t.clearClipFrame()})}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)throw Error(`Unable to determine component size.`);let n=e.getContentInsets();if(!n)throw Error(`Unable to determine component insets.`);t=this.inflateForOverflow(t);let r=this.laidOut(this._northComponent),a=this.laidOut(this._southComponent),o=this.laidOut(this._westComponent),s=this.laidOut(this._centerComponent),c=this.laidOut(this._eastComponent);this.clearSkippedRegionFrames(r,a,o,s,c);let l=t.width,u=t.height,d,p,m,h;if(r){let e=this.getLayoutConstraints(r);if(!e)throw Error(`Unable to determine layout constraints for north component.`);let t=r.getPreferredSize();if(!t)throw Error(`Unable to determine preferred size for north component.`);let u=this.regionExtent(f.NORTH,t.height),d=e.ignoreParentInsets?0:n.getLeft(),m=e.ignoreParentInsets?0:n.getTop(),h=l+(e.ignoreParentInsets?n.getLeft()+n.getRight():0),g=e.ignoreParentInsets?n.getTop():0;p=u+g,this.isRegionCollapsible(f.NORTH)||this._collapsing?(this.placeComponent(r,d,m,h,t.height+g,i.BOTH),r.clearClipFrame(),this.applyRegionClip(r,f.NORTH)):(r.setClipPath(null),r.setClipFrame(d,m,h,t.height+g),this.commitBounds(r,0,0,h,t.height+g)),this.updateRegionGutter(f.NORTH,d,m,h,p),(o||s||c||a)&&(p+=this._spacing)}else p=0;if(h=u-p,a){let e=a.getPreferredSize();if(!e)throw Error(`Unable to determine preferred size for south component.`);let t=this.regionExtent(f.SOUTH,e.height),r=n.getLeft(),o=n.getTop()+u-t;h-=this._spacing,h-=t;let s=n.getTop()+u-e.height;this.isRegionCollapsible(f.SOUTH)||this._collapsing?(this.placeComponent(a,r,s,l,e.height,i.BOTH),a.clearClipFrame(),this.applyRegionClip(a,f.SOUTH)):(a.setClipPath(null),a.setClipFrame(r,s,l,e.height),this.commitBounds(a,0,0,l,e.height)),this.updateRegionGutter(f.SOUTH,r,o,l,t)}let g=0,_=0;if(c){let e=c.getPreferredSize();if(!e)throw Error(`Unable to determine preferred size for east component.`);_=e.width,g=this.regionExtent(f.EAST,e.width)}if(o){let e=o.getPreferredSize();if(!e)throw Error(`Unable to determine preferred size for west component.`);let t=Math.max(0,Math.min(this.regionExtent(f.WEST,e.width),l-g)),r=n.getLeft(),a=n.getTop()+p;d=t;let c=Math.max(0,Math.min(e.width,l-g));this.isRegionCollapsible(f.WEST)||this._collapsing?(this.placeComponent(o,r,a,c,h,i.BOTH),o.clearClipFrame(),this.applyRegionClip(o,f.WEST)):(o.setClipPath(null),o.setClipFrame(r,a,c,h),this.commitBounds(o,0,0,c,h)),this.updateRegionGutter(f.WEST,r,a,t,h),s&&(d+=this._spacing)}else d=0;if(m=l-d,c){m-=this._spacing,m-=g;let e=n.getLeft()+l-g,t=n.getTop()+p,r=n.getLeft()+l-_;this.isRegionCollapsible(f.EAST)||this._collapsing?(this.placeComponent(c,r,t,_,h,i.BOTH),c.clearClipFrame(),this.applyRegionClip(c,f.EAST)):(c.setClipPath(null),c.setClipFrame(r,t,_,h),this.commitBounds(c,0,0,_,h)),this.updateRegionGutter(f.EAST,e,t,g,h)}if(s){let e=n.getLeft()+d,t=n.getTop()+p;this._collapsing?(this.placeComponent(s,e,t,m,h,i.BOTH),s.clearClipFrame()):(s.setClipFrame(e,t,m,h),this.commitBounds(s,0,0,m,h))}}detach(){super.detach();for(let t of this._gutters.values()){let n=t.getElement(),r=n?e.source.getParentNode(n):null;n&&r&&e.sink.removeChild(r,n),t.destroy()}this._gutters.clear();for(let e of[f.NORTH,f.SOUTH,f.WEST,f.EAST,f.CENTER])this.getRegionComponent(e)?.clearClipFrame();return this}},D=a(Border);export{beginPointerDrag as a,runCollapse as i,w as n,endPointerDrag as o,x as r,D as t};
2
+ //# sourceMappingURL=Border-5Ki2DCWz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Border-5Ki2DCWz.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/**\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 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(animating: Component, properties: string[], participants: Component[], completionProperty?: string): void {\n if (Animation.isReducedMotion()) {\n return;\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 Animation.afterTransition({\n component: animating,\n property: completionProperty ?? properties[0],\n durationMs: COLLAPSE_DURATION,\n fallbackBufferMs: 40,\n onComplete: () => {\n for (const participant of participants) {\n participant.setTransition(null);\n }\n\n animating.setWillChange(null);\n },\n });\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 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 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.\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 primeCollapse(toggled, [\"clip-path\"], [toggled], \"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 primeCollapse(gutters[0], [\"background-color\"], gutters, \"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; its propagation is stopped so the host\n * never also reacts.\n */\n private onDoubleClick(evnt: MouseEvent): void {\n evnt.stopPropagation();\n\n this.emit(\"collapse\");\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 */\n private onMouseDown(evnt: MouseEvent): void {\n evnt.stopPropagation();\n }\n\n /**\n * Removes the double-click and mousedown listeners.\n */\n destroy(): void {\n Event.removeListener(this, \"dblclick\", this.onDoubleClick);\n Event.removeListener(this, \"mousedown\", this.onMouseDown);\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 constructor(direction: String, options?: SplitGutterOptions) {\n super(options, _defaultSplitGutterOptions);\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 * Removes the mousedown listener and tears down the collapse button.\n */\n destroy() {\n Event.removeListener(this, 'mousedown', this.onDragStart);\n\n this._collapseButton?.destroy();\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`.\n *\n * @param e - The mouseup/touchend/touchcancel event ending the drag, when\n * invoked as a viewport listener. Optional so tests can call it directly\n * to simulate a drag end.\n */\n onDragStop(e?: Event) {\n e?.stopPropagation();\n\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\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 */\n onDrag(evnt: MouseEvent) {\n evnt.stopPropagation();\n\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\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 } 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 // 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, () => {\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 * 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 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.getPreferredSize();\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.getPreferredSize();\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.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 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 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 let containerSize = container.getInnerSize();\n if (!containerSize) {\n throw new Error(\"Unable to determine component size.\");\n }\n\n let containerInsets = container.getContentInsets();\n if (!containerInsets) {\n throw new Error(\"Unable to determine component insets.\");\n }\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 let northHeight = this.regionExtent(Placement.NORTH, preferredSize.height);\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 preferredSize.height + 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, preferredSize.height + northInsetTop);\n this.commitBounds(north, 0, 0, northWidth, preferredSize.height + 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 let southHeight = this.regionExtent(Placement.SOUTH, preferredSize.height);\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 - preferredSize.height;\n\n if (this.isRegionCollapsible(Placement.SOUTH) || this._collapsing) {\n this.placeComponent(\n south,\n southX,\n southFullY,\n width,\n preferredSize.height,\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, preferredSize.height);\n this.commitBounds(south, 0, 0, width, preferredSize.height);\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 eastFullWidth = eastPreferred.width;\n eastPreferredWidth = this.regionExtent(Placement.EAST, eastPreferred.width);\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 let westWidth = Math.max(0, Math.min(this.regionExtent(Placement.WEST, preferredSize.width), 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(preferredSize.width, 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 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.destroy();\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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"}
@@ -0,0 +1,2 @@
1
+ import{a as e,o as t}from"./Position-DJKB0N3l.js";import{d as n,l as r,u as i}from"./Component-Bs6TvaGZ.js";var BoxLayout=class extends r{_spacing=5;_stretching=!1;_mode=`preferred`;_overflowSizing=`preferred`;_justify=`start`;constructor(e){super(),e&&this.applyOptions(e)}applyOptions(e){super.applyOptions(e),e.mode!==void 0&&this.setMode(e.mode),e.spacing!==void 0&&this.setComponentSpacing(e.spacing),e.stretching!==void 0&&this.setStretching(e.stretching),e.overflowSizing!==void 0&&this.setOverflowSizing(e.overflowSizing),e.justify!==void 0&&this.setJustify(e.justify)}getComponentSpacing(){return this._spacing||0}setComponentSpacing(e){return this._spacing=e||0,this}isStretching(){return this._stretching||!1}setStretching(e){return this._stretching=!!e,this}getMode(){return this._mode}setMode(e){return this._mode=e,this}getOverflowSizing(){return this._overflowSizing}setOverflowSizing(e){return this._overflowSizing=e,this}getJustify(){return this._justify}setJustify(e){return this._justify=e,this}aggregateMaxSize(n){let r=this.getContainer();if(!r)return null;let i=r.getPerimeterSize(),a=r.getLaidOutComponents(),o=n?i.left+i.right:i.top+i.bottom,s=n?i.top+i.bottom:i.left+i.right,c=o,l=0,u=!1,d=!1,f=0;for(let e of a){let r=e.getMaxSize();if(!r){u=!0,d=!0;continue}let i=n?r.width:r.height,a=n?r.height:r.width;t(i)?u=!0:this._mode===`equal`?f=Math.max(f,i):c+=i,t(a)?d=!0:l=Math.max(l,a)}this._mode===`equal`?c+=a.length*f+this._spacing*Math.max(0,a.length-1):c+=this._spacing*Math.max(0,a.length-1),l+=s;let p=u?e:c,m=d?e:l;return{width:n?p:m,height:n?m:p}}computeShrink(e,t,n,r){if(e<=n||r)return{remaining:Math.max(0,n-e),shrinkRatio:0};let i=e-n,a=e-t;return{remaining:0,shrinkRatio:a>0?Math.min(1,i/a):1}}justifyOffsets(e,t,n){let r=Math.max(0,t-e);return r===0||this._justify===`start`?{lead:0,gap:0}:this._justify===`center`?{lead:r/2,gap:0}:this._justify===`end`?{lead:r,gap:0}:this._justify===`between`?{lead:0,gap:n>1?r/(n-1):0}:{lead:n>0?r/(2*n):0,gap:n>0?r/n:0}}crossPlacement(e,t,r,i,a){let o=this.getLayoutConstraints(e),s=o?.fill??null,c=o?.anchor??null;if(a?s===n.VERTICAL||s===n.BOTH:s===n.HORIZONTAL||s===n.BOTH)return{offset:t,extent:r};let l=this.crossAnchorEdge(c,a);if(l===null)return null;let u=Math.min(i,r);return{offset:l===`lead`?t:t+(r-u),extent:u}}crossAnchorEdge(e,t){return e===null?null:t?e===i.NORTH||e===i.NORTHWEST||e===i.NORTHEAST?`lead`:e===i.SOUTH||e===i.SOUTHWEST||e===i.SOUTHEAST?`trail`:null:e===i.WEST||e===i.NORTHWEST||e===i.SOUTHWEST?`lead`:e===i.EAST||e===i.NORTHEAST||e===i.SOUTHEAST?`trail`:null}};export{BoxLayout as t};
2
+ //# sourceMappingURL=BoxLayout-8ryMD4j5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoxLayout-8ryMD4j5.js","names":[],"sources":["../../src/typescript/lib/layout/BoxLayout.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { LayoutManager, LayoutManagerOptions } from \"~/layout/LayoutManager.js\";\nimport { FillType } from \"~/layout/FillType.js\";\nimport { AnchorType } from \"~/layout/AnchorType.js\";\nimport type { AxisPosition, AxisSpread } from \"~/primitive/Axis.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { Size, UNBOUNDED, isUnbounded } from \"~/primitive/Size.js\";\n\n/**\n * Sizing strategy along an {@link HBox} or {@link VBox}'s main axis.\n *\n * - `\"preferred\"` — each child gets its preferred width (height for VBox);\n * `weight`-constrained children split the remaining space; an overflow\n * shrinks non-weighted children proportionally toward their min sizes.\n * - `\"equal\"` — children split the container's inner extent equally; the\n * per-cell floor is `max(child.minSize.width)` (height for VBox);\n * `weight` constraints are ignored.\n *\n * @category Layouts\n */\nexport type BoxMode = \"preferred\" | \"equal\";\n\n/**\n * How an `\"equal\"`-mode {@link HBox}/{@link VBox} sizes its cells when the\n * row/column overflows the host's inner extent and the host has opted into\n * scrolling (`Panel.setAutoScroll`).\n *\n * - `\"preferred\"` (the default) — every cell takes the widest/tallest child's\n * preferred extent, so cells keep their preferred size and the host scrolls.\n * - `\"min\"` — every cell stays at the min floor (`max(child.minSize)`), so the\n * row/column scrolls at the minimum cell size instead of growing.\n *\n * Has no effect outside `\"equal\"` mode, nor when the cells fit (the equal share\n * clears the min floor), nor when the host does not scroll (cells always clamp\n * to the min floor and the host's `overflow: hidden` clips the surplus).\n *\n * @category Layouts\n */\nexport type BoxOverflowSizing = \"preferred\" | \"min\";\n\n/**\n * How a `\"preferred\"`-mode {@link HBox}/{@link VBox} distributes the leftover\n * main-axis space when its children are shorter than the inner main extent and\n * no `weight` cells consume the slack. Mirrors CSS `justify-content`.\n *\n * A single line makes exactly one main-axis slack decision, so the two shared\n * axis concepts fuse into this one field: the {@link AxisPosition} half\n * (`\"start\"`/`\"center\"`/`\"end\"`) positions the whole child block as a unit,\n * while the {@link AxisSpread} half (`\"between\"`/`\"around\"`) spreads the slack\n * into the inter-child gaps. `justifyOffsets` reflects the split — position\n * values yield a leading offset (`lead`, `gap: 0`) and spread values yield an\n * inter-child `gap`. `\"start\"` is the shared identity of both halves, so the\n * union collapses to these five distinct values.\n *\n * - `\"start\"` (the default) — children pack at the leading edge; the slack sits\n * at the trailing edge.\n * - `\"center\"` — the child block is centred; equal slack on both ends.\n * - `\"end\"` — children pack at the trailing edge; the slack sits at the leading\n * edge.\n * - `\"between\"` — the first child sits at the leading edge, the last at the\n * trailing edge, and the slack is split evenly into the gaps between them.\n * - `\"around\"` — every child gets equal space around it: a half-unit before the\n * first and after the last, a full unit between neighbours.\n *\n * Has no effect outside `\"preferred\"` mode, nor when `weight` cells absorb the\n * slack, nor when the content fills or overflows the inner extent (the row\n * clamps to `\"start\"` so the leading child is never pushed out of view).\n *\n * @category Layouts\n */\nexport type BoxJustify = AxisPosition | AxisSpread;\n\n/**\n * Construction-time options shared by {@link HBox} and {@link VBox}.\n *\n * @remarks `mode` selects the sizing strategy along the box's main axis.\n * `\"preferred\"` (the default) honours each child's preferred main-axis extent\n * and supports `weight` cells. `\"equal\"` divides the container's main axis\n * equally and ignores `weight`. `mode` is independent of `stretching`, which\n * governs the cross axis: `stretching` defaults to `false` in both modes, so\n * `\"equal\"` divides the main axis but leaves children at their preferred\n * cross-axis extent unless `stretching: true` is passed.\n *\n * @category Layouts\n */\nexport interface BoxLayoutOptions extends LayoutManagerOptions {\n spacing?: number;\n stretching?: boolean;\n mode?: BoxMode;\n overflowSizing?: BoxOverflowSizing;\n justify?: BoxJustify;\n}\n\n/**\n * Abstract base for the single-axis box layouts {@link HBox} and {@link VBox}.\n * Holds the axis-agnostic configuration plumbing — spacing, stretching, sizing\n * mode, and overflow sizing — and dispatches a {@link BoxLayoutOptions} bag.\n * The geometric algorithms (`getPreferredSize`, `getMinSize`, `getMaxSize`,\n * `computeTotalMinSize`, `doLayout`) are mirror-image per axis and stay\n * concrete on each subclass.\n *\n * @category Layouts\n */\nexport abstract class BoxLayout extends LayoutManager {\n\n // `protected`, not `private`: the subclasses' geometric methods\n // (getPreferredSize/getMinSize/getMaxSize/computeTotalMinSize/doLayout)\n // read these fields directly, so they must be visible to HBox/VBox.\n protected _spacing: number = 5;\n protected _stretching: boolean = false;\n protected _mode: BoxMode = \"preferred\";\n protected _overflowSizing: BoxOverflowSizing = \"preferred\";\n protected _justify: BoxJustify = \"start\";\n\n constructor(options?: BoxLayoutOptions) {\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 BoxLayoutOptions} bag, dispatching mode, spacing, and\n * stretching after the inherited LayoutManager defaults.\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @remarks `mode` and `stretching` are independent axes: `mode` governs the\n * main-axis sizing strategy, `stretching` governs whether children fill the\n * cross axis. Neither defaults from the other — `stretching` is `false`\n * unless the options bag passes it explicitly, in both `\"preferred\"` and\n * `\"equal\"` mode.\n */\n protected applyOptions(options: BoxLayoutOptions): void {\n super.applyOptions(options);\n\n if (options.mode !== undefined) {\n this.setMode(options.mode);\n }\n\n if (options.spacing !== undefined) {\n this.setComponentSpacing(options.spacing);\n }\n\n if (options.stretching !== undefined) {\n this.setStretching(options.stretching);\n }\n\n if (options.overflowSizing !== undefined) {\n this.setOverflowSizing(options.overflowSizing);\n }\n\n if (options.justify !== undefined) {\n this.setJustify(options.justify);\n }\n }\n\n /**\n * Returns the pixel spacing between child components.\n *\n * @returns The current spacing in pixels.\n */\n getComponentSpacing(): number {\n return this._spacing || 0;\n }\n\n /**\n * Sets the pixel spacing between child components.\n *\n * @param spacing - Spacing in pixels.\n *\n * @returns This layout manager, for method chaining.\n */\n setComponentSpacing(spacing: number): this {\n this._spacing = spacing || 0;\n\n return this;\n }\n\n /**\n * Returns whether children stretch to fill the container's cross axis.\n *\n * @returns `true` if stretching is enabled.\n */\n isStretching(): boolean {\n return this._stretching || false;\n }\n\n /**\n * Sets whether children stretch to fill the container's cross axis.\n *\n * @param stretching - Pass `true` to enable cross-axis stretching.\n *\n * @returns This layout manager, for method chaining.\n */\n setStretching(stretching: boolean): this {\n this._stretching = !!stretching;\n\n return this;\n }\n\n /**\n * Returns the current sizing mode along the main axis.\n *\n * @returns Either `\"preferred\"` or `\"equal\"`.\n */\n getMode(): BoxMode {\n return this._mode;\n }\n\n /**\n * Sets the sizing mode along the main axis.\n *\n * @param mode - `\"preferred\"` honours each child's preferred main-axis\n * extent; `\"equal\"` divides the container's main axis equally among\n * children.\n *\n * @returns This layout manager, for method chaining.\n */\n setMode(mode: BoxMode): this {\n this._mode = mode;\n\n return this;\n }\n\n /**\n * Returns the cell-sizing strategy used when an `\"equal\"`-mode row/column\n * overflows a scrolling host.\n *\n * @returns Either `\"preferred\"` or `\"min\"`.\n */\n getOverflowSizing(): BoxOverflowSizing {\n return this._overflowSizing;\n }\n\n /**\n * Sets the cell-sizing strategy used when an `\"equal\"`-mode row/column\n * overflows a scrolling host.\n *\n * @param overflowSizing - `\"preferred\"` grows every cell to the largest\n * child's preferred extent and scrolls; `\"min\"` keeps cells at the min\n * floor and scrolls at the minimum cell size. See {@link BoxOverflowSizing}.\n *\n * @returns This layout manager, for method chaining.\n */\n setOverflowSizing(overflowSizing: BoxOverflowSizing): this {\n this._overflowSizing = overflowSizing;\n\n return this;\n }\n\n /**\n * Returns how leftover main-axis space is distributed in `\"preferred\"` mode.\n *\n * @returns The current {@link BoxJustify} mode.\n */\n getJustify(): BoxJustify {\n return this._justify;\n }\n\n /**\n * Sets how leftover main-axis space is distributed in `\"preferred\"` mode.\n *\n * @param justify - `\"start\"` packs children at the leading edge (the\n * default), `\"center\"`/`\"end\"` shift the block, and `\"between\"`/`\"around\"`\n * spread the slack into the inter-child gaps. See {@link BoxJustify}.\n *\n * @returns This layout manager, for method chaining.\n */\n setJustify(justify: BoxJustify): this {\n this._justify = justify;\n\n return this;\n }\n\n /**\n * Aggregates the children's maximum sizes per the box contract: main axis =\n * sum of child maxima (+ spacing; in `\"equal\"` mode count * widest-child-max),\n * cross axis = max of child maxima, a null or unbounded child max making that\n * axis unbounded. Saturated to {@link UNBOUNDED}. Includes the container\n * perimeter.\n *\n * @param horizontal - `true` for {@link HBox} (main = width), `false` for\n * {@link VBox} (main = height).\n * @returns The aggregated maximum `{width, height}`, or `null` if no\n * container is attached.\n */\n protected aggregateMaxSize(horizontal: boolean): Size | null {\n const container = this.getContainer();\n if (!container) {\n return null;\n }\n\n const perimeterSize = container.getPerimeterSize();\n const components = container.getLaidOutComponents();\n\n const mainStart = horizontal ? perimeterSize.left + perimeterSize.right : perimeterSize.top + perimeterSize.bottom;\n const crossExtra = horizontal ? perimeterSize.top + perimeterSize.bottom : perimeterSize.left + perimeterSize.right;\n\n let main = mainStart;\n let cross = 0;\n let mainUnbounded = false;\n let crossUnbounded = false;\n let maxChildMain = 0;\n\n for (const component of components) {\n const size = component.getMaxSize();\n\n if (!size) {\n mainUnbounded = true;\n crossUnbounded = true;\n continue;\n }\n\n const mainExtent = horizontal ? size.width : size.height;\n const crossExtent = horizontal ? size.height : size.width;\n\n if (isUnbounded(mainExtent)) {\n mainUnbounded = true;\n } else if (this._mode === \"equal\") {\n maxChildMain = Math.max(maxChildMain, mainExtent);\n } else {\n main += mainExtent;\n }\n\n if (isUnbounded(crossExtent)) {\n crossUnbounded = true;\n } else {\n cross = Math.max(cross, crossExtent);\n }\n }\n\n if (this._mode === \"equal\") {\n main += components.length * maxChildMain + this._spacing * Math.max(0, components.length - 1);\n } else {\n main += this._spacing * Math.max(0, components.length - 1);\n }\n\n cross += crossExtra;\n\n const mainValue = mainUnbounded ? UNBOUNDED : main;\n const crossValue = crossUnbounded ? UNBOUNDED : cross;\n\n return {\n width: horizontal ? mainValue : crossValue,\n height: horizontal ? crossValue : mainValue\n };\n }\n\n /**\n * Resolves how much main-axis space the weight cells share and how hard the\n * non-weighted children must shrink. When the non-weighted children's\n * preferred extents fit (or the host scrolls on this axis), nothing shrinks\n * and the leftover is the weight remainder. Otherwise the children shrink\n * proportionally toward their min extents so the last child's far edge lands\n * inside the container.\n *\n * @param fixedPreferred - Summed preferred main-axis extent of the\n * non-weighted children, including inter-child spacing.\n * @param fixedMin - Summed minimum main-axis extent of the same children,\n * including spacing.\n * @param available - The working container's inner extent on the main axis.\n * @param overflowing - Whether the host has opted into scrolling on this\n * axis; when `true` the shrink is skipped so the host's CSS overflow\n * engages instead.\n * @returns `remaining` — the main-axis space left for weight cells — and\n * `shrinkRatio` — `0` (no shrink) through `1` (shrink fully to min).\n */\n protected computeShrink(fixedPreferred: number, fixedMin: number, available: number, overflowing: boolean): { remaining: number; shrinkRatio: number } {\n if (fixedPreferred <= available || overflowing) {\n return { remaining: Math.max(0, available - fixedPreferred), shrinkRatio: 0 };\n }\n\n const excess = fixedPreferred - available;\n const shrinkable = fixedPreferred - fixedMin;\n\n return { remaining: 0, shrinkRatio: shrinkable > 0 ? Math.min(1, excess / shrinkable) : 1 };\n }\n\n /**\n * Distributes the trailing main-axis slack per {@link BoxJustify}, returning\n * a leading offset and an extra inter-child gap. The subclass adds `lead` to\n * the placement cursor's start and `gap` to the inter-child spacing. A row\n * that fills or overflows the inner extent (`residual === 0`) and the\n * `\"start\"` fast path both return `{ lead: 0, gap: 0 }`, leaving placement\n * byte-identical to the un-justified loop. Generalises\n * {@link FlowLayout.alignLead}, which only produces a leading offset, by also\n * spreading slack into the gaps for `\"between\"`/`\"around\"`.\n *\n * @param contentMain - Summed placed child main-extents plus inter-child\n * spacing — the block's total main extent.\n * @param innerMain - The container's inner extent along the main axis.\n * @param count - The number of children sharing the axis.\n * @returns `lead` — pixels added before the first child — and `gap` — pixels\n * added to the spacing after each child. Both are non-negative.\n */\n protected justifyOffsets(contentMain: number, innerMain: number, count: number): { lead: number; gap: number } {\n const residual = Math.max(0, innerMain - contentMain);\n\n if (residual === 0 || this._justify === \"start\") {\n return { lead: 0, gap: 0 };\n }\n\n if (this._justify === \"center\") {\n return { lead: residual / 2, gap: 0 };\n }\n\n if (this._justify === \"end\") {\n return { lead: residual, gap: 0 };\n }\n\n if (this._justify === \"between\") {\n return { lead: 0, gap: count > 1 ? residual / (count - 1) : 0 };\n }\n\n // \"around\"\n return { lead: count > 0 ? residual / (2 * count) : 0, gap: count > 0 ? residual / count : 0 };\n }\n\n /**\n * Resolves a child's cross-axis offset and extent within the full cross\n * band, honouring an explicit per-child cross `fill`/`anchor` (align-self).\n * A cross-axis `fill` (`VERTICAL`/`BOTH` in an {@link HBox}, `HORIZONTAL`/\n * `BOTH` in a {@link VBox}) stretches the child to the whole band; a\n * cross-axis `anchor` edge (NORTH/SOUTH for HBox, WEST/EAST for VBox, plus\n * the corners carrying that component) pins the child's natural cross extent\n * to the leading or trailing edge. The main-axis `anchor` component and\n * `CENTER` are deliberately inert — the box owns main-axis sequencing and\n * each box's default cross placement (HBox baseline, VBox WEST origin) is\n * more specific than geometric centring.\n *\n * @param component - The child whose constraints supply the cross intent.\n * @param crossLead - The band's leading edge (`insets.top` for HBox,\n * `insets.left` for VBox).\n * @param crossExtent - The full cross band extent.\n * @param naturalCross - The child's preferred cross extent, already capped to\n * the band and the child's maximum; the anchored child sits at this extent.\n * @param horizontal - `true` for {@link HBox} (cross axis is vertical),\n * `false` for {@link VBox} (cross axis is horizontal).\n * @returns `{ offset, extent }` when the child sets an explicit cross intent,\n * or `null` to signal the caller to keep its default cross placement.\n */\n protected crossPlacement(component: Component, crossLead: number, crossExtent: number, naturalCross: number, horizontal: boolean): { offset: number; extent: number } | null {\n const constraints = this.getLayoutConstraints(component);\n const fill = constraints?.fill ?? null;\n const anchor = constraints?.anchor ?? null;\n\n const crossFill = horizontal\n ? (fill === FillType.VERTICAL || fill === FillType.BOTH)\n : (fill === FillType.HORIZONTAL || fill === FillType.BOTH);\n\n if (crossFill) {\n return { offset: crossLead, extent: crossExtent };\n }\n\n const edge = this.crossAnchorEdge(anchor, horizontal);\n\n if (edge === null) {\n return null;\n }\n\n const extent = Math.min(naturalCross, crossExtent);\n const offset = edge === \"lead\"\n ? crossLead\n : crossLead + (crossExtent - extent);\n\n return { offset, extent };\n }\n\n /**\n * Projects a child's `anchor` onto the cross axis as a leading/trailing edge.\n * CENTER and pure main-axis anchors carry no cross component and return\n * `null`, leaving the caller on its default cross placement.\n *\n * @param anchor - The child's anchor constraint, or `null`.\n * @param horizontal - `true` for {@link HBox} (cross = vertical: NORTH=lead,\n * SOUTH=trail), `false` for {@link VBox} (cross = horizontal: WEST=lead,\n * EAST=trail).\n * @returns `\"lead\"`/`\"trail\"` for an anchor with a cross component, else `null`.\n */\n private crossAnchorEdge(anchor: AnchorType | null, horizontal: boolean): \"lead\" | \"trail\" | null {\n if (anchor === null) {\n return null;\n }\n\n if (horizontal) {\n if (anchor === AnchorType.NORTH || anchor === AnchorType.NORTHWEST || anchor === AnchorType.NORTHEAST) {\n return \"lead\";\n }\n\n if (anchor === AnchorType.SOUTH || anchor === AnchorType.SOUTHWEST || anchor === AnchorType.SOUTHEAST) {\n return \"trail\";\n }\n\n return null;\n }\n\n if (anchor === AnchorType.WEST || anchor === AnchorType.NORTHWEST || anchor === AnchorType.SOUTHWEST) {\n return \"lead\";\n }\n\n if (anchor === AnchorType.EAST || anchor === AnchorType.NORTHEAST || anchor === AnchorType.SOUTHEAST) {\n return \"trail\";\n }\n\n return null;\n }\n}\n"],"mappings":"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"}