@jimka/typescript-ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/README.md +4 -0
  2. package/THIRD-PARTY-NOTICES.md +7 -3
  3. package/dist/lib/{AbstractBooleanInput-BGesvIZy.js → AbstractBooleanInput-C3O4kv7_.js} +2 -2
  4. package/dist/lib/{AbstractBooleanInput-BGesvIZy.js.map → AbstractBooleanInput-C3O4kv7_.js.map} +1 -1
  5. package/dist/lib/{AbstractInput-BxOtFrER.js → AbstractInput-DFWniHqq.js} +2 -2
  6. package/dist/lib/{AbstractInput-BxOtFrER.js.map → AbstractInput-DFWniHqq.js.map} +1 -1
  7. package/dist/lib/AnchorConstraints-CSUcj8Wx.js +2 -0
  8. package/dist/lib/AnchorConstraints-CSUcj8Wx.js.map +1 -0
  9. package/dist/lib/{AnimatedDropdown-CZQEqQi-.js → AnimatedDropdown-e9urCXK1.js} +2 -2
  10. package/dist/lib/{AnimatedDropdown-CZQEqQi-.js.map → AnimatedDropdown-e9urCXK1.js.map} +1 -1
  11. package/dist/lib/Border-Dq6dXkmS.js +2 -0
  12. package/dist/lib/{Border-BgaZkc1R.js.map → Border-Dq6dXkmS.js.map} +1 -1
  13. package/dist/lib/{Button-U1rsP4v8.js → Button-B36rBMKC.js} +2 -2
  14. package/dist/lib/{Button-U1rsP4v8.js.map → Button-B36rBMKC.js.map} +1 -1
  15. package/dist/lib/{Card-BVwOS8AG.js → Card-P8iUH2-C.js} +2 -2
  16. package/dist/lib/{Card-BVwOS8AG.js.map → Card-P8iUH2-C.js.map} +1 -1
  17. package/dist/lib/{ComboBox-B9EDPu6T.js → ComboBox-BjAhXXkY.js} +2 -2
  18. package/dist/lib/{ComboBox-B9EDPu6T.js.map → ComboBox-BjAhXXkY.js.map} +1 -1
  19. package/dist/lib/Component-CHTzJxEf.js +2 -0
  20. package/dist/lib/Component-CHTzJxEf.js.map +1 -0
  21. package/dist/lib/Container-xUbHk6l_.js +2 -0
  22. package/dist/lib/{Container-D5H8VxJK.js.map → Container-xUbHk6l_.js.map} +1 -1
  23. package/dist/lib/DOM-BeR95tE8.js +2 -0
  24. package/dist/lib/DOM-BeR95tE8.js.map +1 -0
  25. package/dist/lib/{DragManager-CI4mZQFy.js → DragManager-T5Oljd0F.js} +2 -2
  26. package/dist/lib/{DragManager-CI4mZQFy.js.map → DragManager-T5Oljd0F.js.map} +1 -1
  27. package/dist/lib/{FieldDecorator-CJs9gwqH.js → FieldDecorator-BaTGfKiW.js} +2 -2
  28. package/dist/lib/{FieldDecorator-CJs9gwqH.js.map → FieldDecorator-BaTGfKiW.js.map} +1 -1
  29. package/dist/lib/{Fit-DjRsiwlg.js → Fit-E-EIZv1k.js} +2 -2
  30. package/dist/lib/{Fit-DjRsiwlg.js.map → Fit-E-EIZv1k.js.map} +1 -1
  31. package/dist/lib/{Glyph-KEf4nIv2.js → Glyph-CnNslL95.js} +2 -2
  32. package/dist/lib/{Glyph-KEf4nIv2.js.map → Glyph-CnNslL95.js.map} +1 -1
  33. package/dist/lib/{Grid-DdL9TVeJ.js → Grid-BXS2T8MT.js} +2 -2
  34. package/dist/lib/{Grid-DdL9TVeJ.js.map → Grid-BXS2T8MT.js.map} +1 -1
  35. package/dist/lib/{GridConstraints-DkLueyrf.js → GridConstraints-D_kbd-h2.js} +2 -2
  36. package/dist/lib/{GridConstraints-DkLueyrf.js.map → GridConstraints-D_kbd-h2.js.map} +1 -1
  37. package/dist/lib/HBox-Dm3xgsDE.js +2 -0
  38. package/dist/lib/{HBox-Ce0GTCJP.js.map → HBox-Dm3xgsDE.js.map} +1 -1
  39. package/dist/lib/{Header-BQIVpBte.js → Header-CqFc2OUx.js} +2 -2
  40. package/dist/lib/{Header-BQIVpBte.js.map → Header-CqFc2OUx.js.map} +1 -1
  41. package/dist/lib/{IconText-Bo4Qcnot.js → IconText-CTM2r0Tv.js} +2 -2
  42. package/dist/lib/{IconText-Bo4Qcnot.js.map → IconText-CTM2r0Tv.js.map} +1 -1
  43. package/dist/lib/{LayoutSerialization-BT66TY83.js → LayoutSerialization-D1OHmxSB.js} +2 -2
  44. package/dist/lib/{LayoutSerialization-BT66TY83.js.map → LayoutSerialization-D1OHmxSB.js.map} +1 -1
  45. package/dist/lib/LayoutSizes-CvMmMgHJ.js +2 -0
  46. package/dist/lib/LayoutSizes-CvMmMgHJ.js.map +1 -0
  47. package/dist/lib/List-DHeOPAK2.js +2 -0
  48. package/dist/lib/List-DHeOPAK2.js.map +1 -0
  49. package/dist/lib/MemoryStore-DT6iWWco.js +2 -0
  50. package/dist/lib/MemoryStore-DT6iWWco.js.map +1 -0
  51. package/dist/lib/{Menu-Dz4L7EKJ.js → Menu-B6ippw-p.js} +2 -2
  52. package/dist/lib/{Menu-Dz4L7EKJ.js.map → Menu-B6ippw-p.js.map} +1 -1
  53. package/dist/lib/{MenuButton-VJ5uC3c1.js → MenuButton-Bjm1OyB-.js} +2 -2
  54. package/dist/lib/{MenuButton-VJ5uC3c1.js.map → MenuButton-Bjm1OyB-.js.map} +1 -1
  55. package/dist/lib/{Panel-DzWdYwq1.js → Panel-D9lTLGqP.js} +2 -2
  56. package/dist/lib/{Panel-DzWdYwq1.js.map → Panel-D9lTLGqP.js.map} +1 -1
  57. package/dist/lib/Position-DRSlWn4Z.js +2 -0
  58. package/dist/lib/Position-DRSlWn4Z.js.map +1 -0
  59. package/dist/lib/{ProgressSpinner-zJKtGyNJ.js → ProgressSpinner-glv-29eK.js} +2 -2
  60. package/dist/lib/{ProgressSpinner-zJKtGyNJ.js.map → ProgressSpinner-glv-29eK.js.map} +1 -1
  61. package/dist/lib/{RadioButton-CYSSv4nV.js → RadioButton-R4S3c9WD.js} +2 -2
  62. package/dist/lib/{RadioButton-CYSSv4nV.js.map → RadioButton-R4S3c9WD.js.map} +1 -1
  63. package/dist/lib/{RovingTabIndex-BSZ31Vp5.js → RovingTabIndex-Dgt01LOE.js} +2 -2
  64. package/dist/lib/{RovingTabIndex-BSZ31Vp5.js.map → RovingTabIndex-Dgt01LOE.js.map} +1 -1
  65. package/dist/lib/{Scrollbar-BhtOjqkG.js → Scrollbar-CiVV3axj.js} +2 -2
  66. package/dist/lib/{Scrollbar-BhtOjqkG.js.map → Scrollbar-CiVV3axj.js.map} +1 -1
  67. package/dist/lib/{Slider-CdXm7E64.js → Slider-_JVvuQ8M.js} +2 -2
  68. package/dist/lib/{Slider-CdXm7E64.js.map → Slider-_JVvuQ8M.js.map} +1 -1
  69. package/dist/lib/{Spacer-D9NGW4QG.js → Spacer-B57i2-_G.js} +2 -2
  70. package/dist/lib/{Spacer-D9NGW4QG.js.map → Spacer-B57i2-_G.js.map} +1 -1
  71. package/dist/lib/{TabButton-CThevdY_.js → TabButton-DEypdlZf.js} +2 -2
  72. package/dist/lib/{TabButton-CThevdY_.js.map → TabButton-DEypdlZf.js.map} +1 -1
  73. package/dist/lib/Text-Bni4icFY.js +2 -0
  74. package/dist/lib/Text-Bni4icFY.js.map +1 -0
  75. package/dist/lib/{Tooltip-tkXDk5Bo.js → Tooltip-BUy6uFKN.js} +2 -2
  76. package/dist/lib/{Tooltip-tkXDk5Bo.js.map → Tooltip-BUy6uFKN.js.map} +1 -1
  77. package/dist/lib/VBox-Dr7Ge9M6.js +2 -0
  78. package/dist/lib/VBox-Dr7Ge9M6.js.map +1 -0
  79. package/dist/lib/{VirtualScroller-DwEEJE1_.js → VirtualScroller-BPy6KmSX.js} +2 -2
  80. package/dist/lib/{VirtualScroller-DwEEJE1_.js.map → VirtualScroller-BPy6KmSX.js.map} +1 -1
  81. package/dist/lib/component/button.es.js +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/diagram.es.js +1 -1
  86. package/dist/lib/component/diagram.es.js.map +1 -1
  87. package/dist/lib/component/display.es.js +1 -1
  88. package/dist/lib/component/editor.es.js +3 -3
  89. package/dist/lib/component/editor.es.js.map +1 -1
  90. package/dist/lib/component/input.es.js +1 -1
  91. package/dist/lib/component/input.es.js.map +1 -1
  92. package/dist/lib/component/list.es.js +1 -1
  93. package/dist/lib/component/menubar.es.js +1 -1
  94. package/dist/lib/component/table.es.js +2 -2
  95. package/dist/lib/component/table.es.js.map +1 -1
  96. package/dist/lib/component/tree.es.js +1 -1
  97. package/dist/lib/component/tree.es.js.map +1 -1
  98. package/dist/lib/core.es.js +1 -1
  99. package/dist/lib/core.es.js.map +1 -1
  100. package/dist/lib/data.es.js +1 -1
  101. package/dist/lib/data.es.js.map +1 -1
  102. package/dist/lib/glyphs/solid/index.es.js +1 -1
  103. package/dist/lib/layout.es.js +1 -1
  104. package/dist/lib/layout.es.js.map +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 +1 -1
  109. package/dist/lib/router.es.js.map +1 -1
  110. package/dist/lib/{VirtualRowView-BxpHQ_u8.js → selectionsEqual-2PJrcimg.js} +2 -2
  111. package/dist/lib/{VirtualRowView-BxpHQ_u8.js.map → selectionsEqual-2PJrcimg.js.map} +1 -1
  112. package/dist/lib/types/component/diagram/DiagramEdgeLayer.d.ts +14 -1
  113. package/dist/lib/types/component/diagram/DiagramModel.d.ts +1 -0
  114. package/dist/lib/types/component/diagram/DiagramNode.d.ts +4 -0
  115. package/dist/lib/types/component/diagram/DiagramView.d.ts +76 -5
  116. package/dist/lib/types/component/diagram/ElkLayoutEngine.d.ts +14 -1
  117. package/dist/lib/types/component/diagram/index.d.ts +2 -2
  118. package/dist/lib/types/component/editor/CodeEditor.d.ts +3 -2
  119. package/dist/lib/types/component/input/Text.d.ts +3 -1
  120. package/dist/lib/types/component/shared/selectionsEqual.d.ts +1 -0
  121. package/dist/lib/types/component/table/Column.d.ts +2 -0
  122. package/dist/lib/types/component/table/ColumnConfig.d.ts +1 -0
  123. package/dist/lib/types/component/table/Header.d.ts +1 -0
  124. package/dist/lib/types/component/table/Table.d.ts +20 -0
  125. package/dist/lib/types/component/table/cell/Header.d.ts +1 -0
  126. package/dist/lib/types/component/table/index.d.ts +1 -1
  127. package/dist/lib/types/component/tree/Tree.d.ts +1 -0
  128. package/dist/lib/types/core/Aria.d.ts +0 -2
  129. package/dist/lib/types/core/Body.d.ts +1 -0
  130. package/dist/lib/types/core/ClassStyleRules.d.ts +17 -0
  131. package/dist/lib/types/core/Component.d.ts +10 -2
  132. package/dist/lib/types/core/ComponentDefaults.d.ts +1 -0
  133. package/dist/lib/types/core/DOM.d.ts +11 -2
  134. package/dist/lib/types/core/ElementAttributes.d.ts +15 -0
  135. package/dist/lib/types/core/PendingTransitions.d.ts +4 -0
  136. package/dist/lib/types/core/StyleTarget.d.ts +1 -0
  137. package/dist/lib/types/core/Util.d.ts +2 -0
  138. package/dist/lib/types/core/index.d.ts +1 -0
  139. package/dist/lib/types/layout/Border.d.ts +1 -0
  140. package/dist/lib/types/layout/Tab.d.ts +4 -1
  141. package/dist/lib/types/layout/Table.d.ts +1 -0
  142. package/dist/lib/types/overlay/AbstractWindow.d.ts +1 -0
  143. package/dist/lib/types/router/RoutePattern.d.ts +7 -0
  144. package/dist/lib/types/router/Router.d.ts +13 -2
  145. package/dist/lib/types/router/index.d.ts +1 -1
  146. package/dist/lib/validation.es.js +1 -1
  147. package/llms.txt +1 -1
  148. package/package.json +4 -8
  149. package/dist/lib/Border-BgaZkc1R.js +0 -2
  150. package/dist/lib/BoxLayout-DrKGfsup.js +0 -2
  151. package/dist/lib/BoxLayout-DrKGfsup.js.map +0 -1
  152. package/dist/lib/Component-DXf5a3g0.js +0 -2
  153. package/dist/lib/Component-DXf5a3g0.js.map +0 -1
  154. package/dist/lib/Container-D5H8VxJK.js +0 -2
  155. package/dist/lib/DOM-CGn7xyTw.js +0 -2
  156. package/dist/lib/DOM-CGn7xyTw.js.map +0 -1
  157. package/dist/lib/HBox-Ce0GTCJP.js +0 -2
  158. package/dist/lib/LayoutSizes-DU3qSq0w.js +0 -2
  159. package/dist/lib/LayoutSizes-DU3qSq0w.js.map +0 -1
  160. package/dist/lib/List-DtTVTyWW.js +0 -2
  161. package/dist/lib/List-DtTVTyWW.js.map +0 -1
  162. package/dist/lib/Position-A39T7-_1.js +0 -2
  163. package/dist/lib/Position-A39T7-_1.js.map +0 -1
  164. package/dist/lib/Text-gz6qjFfP.js +0 -2
  165. package/dist/lib/Text-gz6qjFfP.js.map +0 -1
  166. package/dist/lib/VBox-EIqw85Rh.js +0 -2
  167. package/dist/lib/VBox-EIqw85Rh.js.map +0 -1
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-CGn7xyTw.js";import{n as t}from"./Position-A39T7-_1.js";import{_ as n,f as r,s as i,t as a,y as o}from"./Component-DXf5a3g0.js";import{t as s}from"./ListenerBag-WPdKuuds.js";import{t as c}from"./Panel-DzWdYwq1.js";import{t as l}from"./Tooltip-tkXDk5Bo.js";import{t as u}from"./Fit-DjRsiwlg.js";import{t as d}from"./Text-gz6qjFfP.js";import{t as f}from"./AbstractInput-BxOtFrER.js";import{t as p}from"./VBox-EIqw85Rh.js";var ListItemRenderer=class extends a{constructor(){super()}getContentWidth(){return 0}},LabelListItemRenderer=class extends ListItemRenderer{_label;_measured=!1;constructor(){super(),this.clearInsets(),this._label=new d,this._label.clearInsets(),this._label.setAutoMeasure(!1)}getLabel(){return this._label}update(e){this._label.setText(e.item.label),this._measured=!1}getContentWidth(){return this._measured||=(this._label.measure(),!0),this._label.getPreferredSize()?.width??0}layoutChildren(e,t){this._label.setAutoCommitStyle(!1),this._label.setX(0),this._label.setY(0),this._label.setWidth(e),this._label.setHeight(t),this._label.setLineHeight(t),this._label.setAutoCommitStyle(!0)}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._label.getElement(!0)),this}},m=r(LabelListItemRenderer),h=22,g=8,_=700,v={tag:`div`,backgroundColor:`var(--ts-ui-list-bg, rgb(255, 255, 255))`,foregroundColor:`var(--ts-ui-text-color, black)`,border:`1px solid var(--ts-ui-list-border, rgb(200, 200, 200))`,borderRadius:`var(--ts-ui-border-radius, 4px)`,preferredSize:{width:200,height:200},maxSize:{width:2**53-1,height:2**53-1}};new n({scope:`selector`,name:`.List, .MultiSelectList`,styles:{userSelect:`none`,outline:`none`}}),new n({scope:`selector`,name:`.List:focus::after, .MultiSelectList:focus::after`,styles:{content:`''`,position:`absolute`,inset:`0`,border:`2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))`,borderRadius:`inherit`,boxSizing:`border-box`,pointerEvents:`none`,zIndex:`1`}}),new n({scope:`class`,name:`SelectableListRow`,styles:{lineHeight:`22px`,whiteSpace:`nowrap`,overflow:`hidden`,textOverflow:`ellipsis`,borderBottom:`1px solid var(--ts-ui-list-row-separator, transparent)`,cursor:`pointer`}}),new n({scope:`selector`,name:`.SelectableListRow:hover`,styles:{backgroundColor:`var(--ts-ui-list-row-hover-bg, rgba(30, 100, 200, 0.08))`}}),new n({scope:`selector`,name:`.SelectableListRow.selected`,styles:{backgroundColor:`var(--ts-ui-list-row-selected-bg, rgba(30, 100, 200, 0.18))`,color:`var(--ts-ui-list-row-selected-color, inherit)`}}),new n({scope:`selector`,name:`.SelectableListRow.focused`,styles:{outline:`var(--ts-ui-indicator-selection, 1px dashed rgb(120, 170, 240))`}});var SelectableListRow=class extends a{_selected=!1;_focused=!1;_index;_handlers;_tooltipAttached=!1;_renderer;constructor(e,n,r){super({tag:`div`}),this._handlers=e,this._index=n,this._renderer=r(),this._renderer.setPointerEvents(`none`),this.getAria().setRole(`option`),this.setPreferredSize({width:0,height:h}),this.setPadding(new t(0,g,0,g)),this.setCursor(`pointer`),o.addListener(this,`pointerdown`,this.onPointerDown),o.addListener(this,`click`,this.onClick),o.addListener(this,`contextmenu`,this.onContextMenu),o.addListener(this,`dblclick`,this.onDblClick)}updateItem(e,t){return this._renderer.update({item:e,index:t}),this.applyTooltip(e.tooltip),this}applyTooltip(e){e?(l.attach(this,e),this._tooltipAttached=!0):this._tooltipAttached&&=(l.detach(this),!1)}getNaturalWidth(){return this._renderer.getContentWidth()+g*2}setRenderer(t){let n=this.getElement();if(n){let t=this._renderer.getElement();t&&e.source.getParentNode(t)===n&&e.sink.removeChild(n,t)}return this._renderer=t,this._renderer.setPointerEvents(`none`),n&&e.sink.appendChild(n,this._renderer.getElement(!0)),this}setIndex(e){return this._index=e,this}getIndex(){return this._index}setSelected(e){return this._selected=e,this.getAria().setSelected(e),this.applyRowClass(),this}isSelected(){return this._selected}setFocused(e){return this._focused=e,this.applyRowClass(),this}isFocused(){return this._focused}render(){let e=super.render();return this.applyRowClass(),e}init(t){super.init(t);let n=t||this.getElement();return n&&e.sink.appendChild(n,this._renderer.getElement(!0)),this}doLayout(){super.doLayout();let e=this.getInnerSize();if(!e)return this;let t=this.getPerimeterSize();return this._renderer.setAutoCommitStyle(!1),this._renderer.setX(t.left),this._renderer.setY(t.top),this._renderer.setWidth(e.width),this._renderer.setHeight(e.height),this._renderer.setAutoCommitStyle(!0),this._renderer.layoutChildren(e.width,e.height),this}applyRowClass(){let e=[`SelectableListRow`];this._selected&&e.push(`selected`),this._focused&&e.push(`focused`),this.setElementAttribute(`class`,e.join(` `))}onPointerDown(e){e.preventDefault()}onClick(e){this._handlers.onClick(this._index,e)}onContextMenu(e){this._handlers.onContextMenu(this._index,e)}onDblClick(e){this._handlers.onDblClick(this._index,e)}},ListRowColumn=class extends p{computeTotalMinSize(){let e=super.computeTotalMinSize(),t=this.getContainer();if(!t||!this.isOverflowingX())return e;let n=0;for(let e of t.getLaidOutComponents())e instanceof SelectableListRow&&(n=Math.max(n,e.getNaturalWidth()));return{width:Math.max(e.width,n),height:e.height}}},AbstractSelectableList=class extends f{_items=[];_rowPool=[];_selectedSet=new Set;_anchorIndex=null;_focusedIndex=-1;_typeAheadBuf=``;_typeAheadAt=0;_focusOnRowClick=!0;_selectFollowsFocus=!0;_horizontalScrolling=!1;_innerPanel;_emptyPlaceholder=null;_placeholderAttached=!1;_storeRefresh=null;_rendererFactory=()=>new m;_rowListeners=new s;constructor(e,n){super(e,{...v,layoutManager:new u,...n??{}}),this.getAria().setRole(`listbox`),this.getAria().setTabIndex(0),this._innerPanel=new c({layoutManager:new ListRowColumn({spacing:0,stretching:!0}),autoScroll:`y`,insets:new t(0,0,0,0)}),this.addComponent(this._innerPanel),this._options.minSize===void 0&&this.setMinSize({width:100,height:100}),o.addListener(this,`keydown`,this.handleKeyDown),this._options.rendererFactory!==void 0&&this.setRendererFactory(this._options.rendererFactory),this._options.horizontalScrolling!==void 0&&this.setHorizontalScrolling(this._options.horizontalScrolling),this._options.store!==void 0&&this._options.displayField!==void 0&&this.setStore(this._options.store,this._options.displayField,this._options.valueField,this._options.glyphField,this._options.tooltipField),this._options.items!==void 0&&this.setItems(this._options.items),this._options.enabled!==void 0&&this.applyEnabled(this._options.enabled),this._options.readOnly!==void 0&&this.applyReadOnly(this._options.readOnly),(this._options.emptyText!==void 0||this._options.emptyComponent!==void 0)&&this.syncEmptyPlaceholder()}applyEnabled(e){this.getAria().setDisabled(!e),this.getAria().setTabIndex(e?0:-1),this.setCursor(e?`default`:`not-allowed`),e||(this._focusedIndex=-1,this.refreshRowVisualState(),this.updateActiveDescendant())}applyReadOnly(e){this.getAria().setReadOnly(e)}applyOptions(e){return super.applyOptions(e),e.items!==void 0&&(this._options.items=e.items),e.store!==void 0&&(this._options.store=e.store),e.displayField!==void 0&&(this._options.displayField=e.displayField),e.valueField!==void 0&&(this._options.valueField=e.valueField),e.glyphField!==void 0&&(this._options.glyphField=e.glyphField),e.tooltipField!==void 0&&(this._options.tooltipField=e.tooltipField),e.rendererFactory!==void 0&&(this._options.rendererFactory=e.rendererFactory),e.emptyText!==void 0&&(this._options.emptyText=e.emptyText),e.emptyComponent!==void 0&&(this._options.emptyComponent=e.emptyComponent),e.horizontalScrolling!==void 0&&(this._options.horizontalScrolling=e.horizontalScrolling),this}setHorizontalScrolling(e){return this._horizontalScrolling===e?this:(this._horizontalScrolling=e,this._innerPanel.setAutoScroll(e?`auto`:`y`),this.scheduleLayout(),this)}isHorizontalScrolling(){return this._horizontalScrolling}setEmptyText(e){return this._options.emptyText=e??void 0,this.resetEmptyPlaceholder(),this.syncEmptyPlaceholder(),this}getEmptyText(){return this._options.emptyText??null}setEmptyComponent(e){return this._options.emptyComponent=e??void 0,this.resetEmptyPlaceholder(),this.syncEmptyPlaceholder(),this}getEmptyComponent(){return this._options.emptyComponent??null}syncEmptyPlaceholder(){(this._options.emptyComponent!==void 0||this._options.emptyText!==void 0)&&this._items.length===0?(this._emptyPlaceholder||=this.buildEmptyPlaceholder(),this._placeholderAttached||=(this._innerPanel.addComponent(this._emptyPlaceholder,{weight:1}),!0)):this._placeholderAttached&&this._emptyPlaceholder&&(this._innerPanel.removeComponent(this._emptyPlaceholder),this._placeholderAttached=!1)}buildEmptyPlaceholder(){let e=this._options.emptyComponent;if(e)return e();let t=new d(this._options.emptyText??``,{textAlign:`center`});return t.setForegroundColor(`var(--ts-ui-list-row-disabled-color, rgb(170, 170, 170))`),t}resetEmptyPlaceholder(){this._placeholderAttached&&this._emptyPlaceholder&&(this._innerPanel.removeComponent(this._emptyPlaceholder),this._placeholderAttached=!1),this._emptyPlaceholder=null}getBaseline(){return null}getItems(){return this._items.slice()}setItems(e){i.isArray(e)||(e=[e]);let t=e,n=[];for(let e of t)n.push(typeof e==`string`?{key:e,label:e}:{key:e.key,label:e.label,glyph:e.glyph,tooltip:e.tooltip});return this.setItemsArray(n)}setItemsArray(e){return this._items=e.slice(),this._selectedSet.clear(),this._anchorIndex=null,this._focusedIndex=-1,this.pauseLayout(),this.syncRows(),this.resumeLayout(),this.updateActiveDescendant(),this}addItem(e){return this._items.push(typeof e==`string`?{key:e,label:e}:{key:e.key,label:e.label,glyph:e.glyph,tooltip:e.tooltip}),this.pauseLayout(),this.syncRows(),this.resumeLayout(),this}setStore(e,t,n,r,i){let a=this._options.store;this._storeRefresh&&a&&[`load`,`add`,`remove`,`datachange`,`sync`].forEach(e=>a.off(e,this._storeRefresh)),this._options.store=e,this._options.displayField=t,this._options.valueField=n,this._options.glyphField=r,this._options.tooltipField=i;let refresh=()=>this.refreshFromStore();return this._storeRefresh=refresh,e.on(`load`,refresh),e.on(`add`,refresh),e.on(`remove`,refresh),e.on(`datachange`,refresh),e.on(`sync`,refresh),this.refreshFromStore(),this}getStore(){return this._options.store??null}setRendererFactory(e){this._rendererFactory=e;for(let t of this._rowPool)t.setRenderer(e());return this.pauseLayout(),this.syncRows(),this.resumeLayout(),this}getRendererFactory(){return this._rendererFactory}getSelectedRecord(){let e=this._options.store;if(!e)return;let t=this.getSelectedIndex();if(!(t<0))return e.getRecords()[t]}getSelectedIndex(){return this._anchorIndex!==null&&this._selectedSet.has(this._anchorIndex)?this._anchorIndex:this._selectedSet.size===0?-1:Math.min(...this._selectedSet)}setSelectedIndex(e,t=!0){return this._selectedSet.clear(),e>=0&&e<this._items.length?(this._selectedSet.add(e),this._anchorIndex=e,this._focusedIndex=e):(this._anchorIndex=null,this._focusedIndex=-1),this.refreshRowVisualState(),this.updateActiveDescendant(),t&&this.fireChange(),this}on(e,t){return e===`action`?(o.addListener(this,`change`,t),this):e===`contextmenu`||e===`dblclick`?(this._rowListeners.add(e,t),this):super.on(e,t)}off(e,t){return e===`action`?(o.removeListener(this,`change`,t),this):e===`contextmenu`||e===`dblclick`?(this._rowListeners.remove(e,t),this):super.off(e,t)}refreshFromStore(){let e=this._options.store,t=this._options.displayField,n=this._options.valueField,r=this._options.glyphField,i=this._options.tooltipField;if(!e||!t)return;let a=this._anchorIndex!==null&&this._items[this._anchorIndex]?this._items[this._anchorIndex].key:null;this._items=[],this._selectedSet.clear(),this._anchorIndex=null;let o=e.getRecords(),s=-1;for(let e=0;e<o.length;e++){let c=o[e],l=String(c.get(t)),u=String(n?c.get(n):c.getId()),d=r?String(c.get(r)):void 0,f=i?String(c.get(i)):void 0;this._items.push({key:u,label:l,glyph:d,tooltip:f}),a!==null&&u===a&&(s=e)}s>=0?(this._selectedSet.add(s),this._anchorIndex=s,this._focusedIndex=s):this._focusedIndex=this._items.length>0?0:-1,this.pauseLayout(),this.syncRows(),this.resumeLayout(),this.updateActiveDescendant()}syncRows(){let e=this._items.length,t=this._rowPool.length,n=Math.min(e,t);for(let e=0;e<n;e++){let t=this._rowPool[e];t.updateItem(this._items[e],e),t.setIndex(e),t.setSelected(this._selectedSet.has(e)),t.setFocused(e===this._focusedIndex)}if(e>t)for(let n=t;n<e;n++){let e=new SelectableListRow({onClick:(e,t)=>this.handleRowClick(e,t),onContextMenu:(e,t)=>this.handleRowContextMenu(e,t),onDblClick:(e,t)=>this.handleRowDblClick(e,t)},n,this._rendererFactory);e.updateItem(this._items[n],n),e.setSelected(this._selectedSet.has(n)),e.setFocused(n===this._focusedIndex),this._innerPanel.addComponent(e),this._rowPool.push(e)}else if(e<t){for(let n=e;n<t;n++)l.detach(this._rowPool[n]),this._innerPanel.removeComponent(this._rowPool[n]);this._rowPool.splice(e)}this.syncEmptyPlaceholder()}refreshRowVisualState(){for(let e=0;e<this._rowPool.length;e++){let t=this._rowPool[e];t.setSelected(this._selectedSet.has(e)),t.setFocused(e===this._focusedIndex)}}updateActiveDescendant(){if(this._focusedIndex<0||this._focusedIndex>=this._rowPool.length){this.getAria().setActiveDescendant(``);return}this.getAria().setActiveDescendant(this._rowPool[this._focusedIndex].getId())}fireChange(){this.getElement()&&o.fireEvent(this,`change`),this.notifyChange(this.getValue())}handleRowClick(e,t){!this.isEnabled()||this.isReadOnly()||e<0||e>=this._items.length||(this.reduceSelection(e,{ctrl:t.ctrlKey||t.metaKey,shift:t.shiftKey}),this.refreshRowVisualState(),this.updateActiveDescendant(),this._focusOnRowClick&&this.focus(),this.notifyUserChange())}handleRowContextMenu(e,t){e<0||e>=this._items.length||(t.preventDefault(),this._rowListeners.fire(`contextmenu`,e,t))}handleRowDblClick(e,t){e<0||e>=this._items.length||this._rowListeners.fire(`dblclick`,e,t)}setFocusOnRowClick(e){return this._focusOnRowClick=e,this}setSelectFollowsFocus(e){return this._selectFollowsFocus=e,this}getFocusedIndex(){return this._focusedIndex}getFocusedRowId(){return this._focusedIndex<0||this._focusedIndex>=this._rowPool.length?null:this._rowPool[this._focusedIndex].getId()}handleKey(e){if(!this.isEnabled()||this.isReadOnly()||this._items.length===0||e.key===`Escape`)return!1;let t=e.ctrlKey||e.metaKey;return this.handleNavigationKey(e,t)?!0:e.key===`Enter`||e.key===` `?(e.preventDefault(),this.commitFocusedRow(t,e.shiftKey),!0):!t&&!e.altKey&&e.key.length===1?(this.handleTypeAhead(e.key),!0):!1}handleKeyDown(e){if(!this.isEnabled()||this.isReadOnly()||this._items.length===0)return;let t=e.ctrlKey||e.metaKey;if(e.key===`Escape`){this._typeAheadBuf=``;return}if(!this.handleNavigationKey(e,t)){if(e.key===`Enter`||e.key===` `){e.preventDefault(),this.commitFocusedRow(t,e.shiftKey);return}!t&&!e.altKey&&e.key.length===1&&this.handleTypeAhead(e.key)}}handleNavigationKey(e,t){if(!new Set([`ArrowDown`,`ArrowUp`,`Home`,`End`,`PageDown`,`PageUp`]).has(e.key))return!1;e.preventDefault();let n=this.getHeight()||h,r=Math.max(1,Math.floor(n/h)),i=this._focusedIndex<0?0:this._focusedIndex,a;return a=e.key===`ArrowDown`?Math.min(i+1,this._items.length-1):e.key===`ArrowUp`?Math.max(i-1,0):e.key===`PageDown`?Math.min(i+r,this._items.length-1):e.key===`PageUp`?Math.max(i-r,0):e.key===`Home`?0:this._items.length-1,this.moveFocus(a,t,e.shiftKey),!0}moveFocus(e,t,n){this._focusedIndex=e;let r=!t&&this._selectFollowsFocus;r&&this.reduceSelection(e,{ctrl:!1,shift:n}),this.refreshRowVisualState(),this.updateActiveDescendant(),this.scrollIndexIntoView(e),r&&this.notifyUserChange()}commitFocusedRow(e,t){this._focusedIndex<0||(this.reduceSelection(this._focusedIndex,{ctrl:e,shift:t}),this.refreshRowVisualState(),this.updateActiveDescendant(),this.notifyUserChange())}handleTypeAhead(e){let t=Date.now();t-this._typeAheadAt>_&&(this._typeAheadBuf=``),this._typeAheadBuf+=e.toLowerCase(),this._typeAheadAt=t;let n=this._typeAheadBuf,r=this._items.findIndex(e=>e.label.toLowerCase().startsWith(n));r<0||(this._focusedIndex=r,this.refreshRowVisualState(),this.updateActiveDescendant(),this.scrollIndexIntoView(r))}scrollIndexIntoView(t){if(t<0||t>=this._items.length)return;let n=this._innerPanel.getElement();if(!n)return;let r=e.source.getScrollMetrics(n),i=t*h,a=i+h,o=r.scrollTop,s=o+r.clientHeight;i<o?e.sink.apply(n,{scrollTop:i}):a>s&&e.sink.apply(n,{scrollTop:a-r.clientHeight})}},List=class extends AbstractSelectableList{constructor(e){super(e),this._options.selectedIndex!==void 0&&this.setSelectedIndex(this._options.selectedIndex,!1),this._options.value!==void 0&&this.setValue(this._options.value),this._options.selectedItem!==void 0&&this.setValue(this._options.selectedItem)}applyOptions(e){return super.applyOptions(e),e.selectedIndex!==void 0&&(this._options.selectedIndex=e.selectedIndex),e.value!==void 0&&(this._options.value=e.value),e.selectedItem!==void 0&&(this._options.selectedItem=e.selectedItem),this}setItemsArray(e){return super.setItemsArray(e)}setValue(e){let t=this._items.findIndex(t=>t.key===e);return this.setSelectedIndex(t,!1),this}getValue(){let e=this.getSelectedIndex();return e<0||e>=this._items.length?``:this._items[e].key}reduceSelection(e,t){this._selectedSet.clear(),this._selectedSet.add(e),this._anchorIndex=e,this._focusedIndex=e}notifyUserChange(){this.fireChange()}},y=r(List);export{ListItemRenderer as i,AbstractSelectableList as n,m as r,y as t};
2
- //# sourceMappingURL=List-DtTVTyWW.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"List-DtTVTyWW.js","names":[],"sources":["../../src/typescript/lib/component/list/ListItemRenderer.ts","../../src/typescript/lib/component/list/renderer/Label.ts","../../src/typescript/lib/component/list/AbstractSelectableList.ts","../../src/typescript/lib/component/list/List.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component } from \"~/core/Component.js\";\nimport { ListItemRenderContext } from \"~/component/list/ListItemRenderContext.js\";\n\n/**\n * Abstract base class for list item renderers.\n *\n * @remarks\n * A `ListItemRenderer` owns the content of a single list row — the label, and\n * optionally an icon or other affordance. The owning\n * [`List`](/api/component/list/classes/List) /\n * [`MultiSelectList`](/api/component/list/classes/MultiSelectList) holds a\n * renderer factory; each pooled row calls that factory once at construction and\n * rebinds via {@link update} when the row is remapped to a different item. The\n * collapsed [`ComboBox`](/api/component/input/classes/ComboBox) control hosts\n * one renderer built from the same factory, so the selected entry renders on\n * the closed control exactly as it does in the open dropdown.\n *\n * Selection / focus / hover chrome is applied by the list on the row element\n * directly and never reaches the renderer.\n *\n * Subclasses implement {@link update} and {@link layoutChildren}. See\n * [`LabelListItemRenderer`](/api/component/list/classes/LabelListItemRenderer)\n * for the canonical default. {@link getContentWidth} is optional: it is read\n * only by a list running with `horizontalScrolling` on, and the base\n * implementation already reports \"no intrinsic width\".\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated.\n *\n * @category Components\n */\nexport abstract class ListItemRenderer extends Component {\n\n constructor() {\n super();\n }\n\n /**\n * Rebinds this renderer to new item data.\n *\n * @param context - The bound-item state for this render pass.\n *\n * @remarks Called every time the owning row (or collapsed control) is\n * mapped to a different item.\n */\n abstract update(context: ListItemRenderContext): void;\n\n /**\n * Returns the natural width of the currently bound content — the width at\n * which it renders without clipping.\n *\n * Read only by a list running with\n * [`horizontalScrolling`](/api/component/list/classes/List#sethorizontalscrolling)\n * on, which sizes every row to the widest value across the bound items so\n * over-long content scrolls into view instead of ellipsising. A list with\n * horizontal scrolling off — the default — never calls this, so a renderer\n * that measures lazily pays nothing for it.\n *\n * The base implementation returns 0, meaning \"no intrinsic width\": rows\n * stay at the viewport width and never extend the horizontal scroll extent.\n * That keeps a custom renderer written against the previous contract\n * working unchanged; override it to opt that renderer into horizontal\n * scrolling.\n *\n * @returns The bound content's natural width in pixels, or 0 when unknown.\n */\n getContentWidth(): number {\n return 0;\n }\n\n /**\n * Positions this renderer's internal children within the given box.\n *\n * @param width - The horizontal extent of the renderer in pixels.\n * @param height - The vertical extent of the renderer in pixels.\n *\n * @remarks Called by the owning row after the renderer's own size has been\n * set via `setX` / `setY` / `setWidth` / `setHeight`.\n */\n abstract layoutChildren(width: number, height: number): void;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Text } from \"~/component/input/Text.js\";\nimport { ListItemRenderer } from \"~/component/list/ListItemRenderer.js\";\nimport { ListItemRenderContext } from \"~/component/list/ListItemRenderContext.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * The default [`ListItemRenderer`](/api/component/list/classes/ListItemRenderer) —\n * a single [`Text`](/api/component/input/classes/Text) child carrying the\n * item's label.\n *\n * @remarks\n * Used as the implicit factory by [`List`](/api/component/list/classes/List) /\n * [`MultiSelectList`](/api/component/list/classes/MultiSelectList) and the\n * collapsed [`ComboBox`](/api/component/input/classes/ComboBox) control when no\n * custom renderer is set. The label keeps `Text`'s default `truncate: true`, so\n * a label wider than its row clips with an ellipsis — reproducing the row\n * chrome the list carried before renderers existed. The label is sized to fill\n * the row in {@link layoutChildren} rather than to its natural width: the row\n * is never narrower than {@link getContentWidth}, so filling it lets the\n * selection wash span the whole row without clipping the text.\n *\n * @example\n * ```typescript\n * list.setRendererFactory(() => new LabelListItemRenderer());\n * ```\n *\n * @category Components\n */\nclass LabelListItemRenderer extends ListItemRenderer {\n\n private _label: Text;\n /**\n * Whether `_label`'s cached natural width matches the bound text. The label\n * runs with `autoMeasure(false)`, so the measure is driven from\n * {@link getContentWidth} rather than {@link update} — a list with\n * horizontal scrolling off never asks, and so never pays for it.\n */\n private _measured: boolean = false;\n\n /**\n * Constructs a label renderer with an empty text node. The label is\n * populated on the first {@link update} call.\n */\n constructor() {\n super();\n this.clearInsets();\n\n this._label = new Text();\n this._label.clearInsets();\n this._label.setAutoMeasure(false);\n }\n\n /**\n * Returns the underlying label component so consumers can tweak font /\n * colour properties at construction time.\n *\n * @returns The internal [`Text`](/api/component/input/classes/Text) instance.\n */\n getLabel(): Text {\n return this._label;\n }\n\n /**\n * Updates the rendered label text.\n *\n * @param context - The bound-item state for this render pass.\n */\n update(context: ListItemRenderContext): void {\n this._label.setText(context.item.label);\n this._measured = false;\n }\n\n /**\n * Returns the natural width of the bound label, measuring it on first ask\n * after each {@link update}.\n *\n * @returns The label's natural width in pixels.\n */\n getContentWidth(): number {\n if (!this._measured) {\n this._label.measure();\n this._measured = true;\n }\n\n return this._label.getPreferredSize()?.width ?? 0;\n }\n\n /**\n * Sizes the label to fill the renderer's allocated box and centres its\n * line-box vertically by matching `line-height` to the row height.\n *\n * @param width - The horizontal extent of the row in pixels.\n * @param height - The vertical extent of the row in pixels.\n */\n layoutChildren(width: number, height: number): void {\n this._label.setAutoCommitStyle(false);\n this._label.setX(0);\n this._label.setY(0);\n this._label.setWidth(width);\n this._label.setHeight(height);\n this._label.setLineHeight(height);\n this._label.setAutoCommitStyle(true);\n }\n\n /**\n * Appends the label sub-component element to the renderer's DOM element.\n *\n * @param element - Optional element passed by the rendering pipeline; falls\n * back to getElement().\n *\n * @returns This renderer, for method chaining.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (!el) {\n return this;\n }\n\n DOM.sink.appendChild(el, this._label.getElement(true)!);\n\n return this;\n }\n}\n\nconst LabelListItemRendererCallable = callable(LabelListItemRenderer);\ntype LabelListItemRendererCallable = LabelListItemRenderer;\nexport {\n LabelListItemRenderer as _LabelListItemRenderer,\n LabelListItemRendererCallable as LabelListItemRenderer,\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractInput, AbstractInputOptions } from \"~/component/input/AbstractInput.js\";\nimport { Component } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Panel } from \"~/core/Panel.js\";\nimport { StyleRule } from \"~/core/StyleTarget.js\";\nimport { Event } from \"~/core/Event.js\";\nimport { ListenerBag } from \"~/core/ListenerBag.js\";\nimport { Tooltip } from \"~/overlay/Tooltip.js\";\nimport { Type } from \"~/core/Type.js\";\nimport { Insets } from \"~/primitive/Insets.js\";\nimport { Fit } from \"~/layout/Fit.js\";\nimport { _VBox } from \"~/layout/VBox.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { AbstractStore } from \"~/data/AbstractStore.js\";\nimport { ModelRecord } from \"~/data/ModelRecord.js\";\nimport { ListItemRenderer } from \"~/component/list/ListItemRenderer.js\";\nimport { LabelListItemRenderer } from \"~/component/list/renderer/Label.js\";\nimport { Text } from \"~/component/input/Text.js\";\n\n/**\n * One entry in a [`List`](/api/component/list/classes/List) /\n * [`MultiSelectList`](/api/component/list/classes/MultiSelectList) item\n * array. Plain data — the row pool is the view layer.\n *\n * @category Components\n */\nexport interface SelectableListItem {\n /** Binding identifier — what `getValue` / `setValue` round-trip. */\n key: string;\n /** Display text rendered in the row. */\n label: string;\n /**\n * Optional registry glyph name, read by\n * [`GlyphListItemRenderer`](/api/component/list/classes/GlyphListItemRenderer)\n * to paint an icon beside the label. Ignored by the default label\n * renderer. Array-supplied items carry it directly; store-bound items\n * resolve it from the record field named by the list's `glyphField`.\n */\n glyph?: string;\n /**\n * Optional hover-tooltip text for the row, shown after the standard hover\n * delay via [`Tooltip`](/api/overlay/classes/Tooltip). Lets a host surface\n * the full value behind a truncated label without reaching into the row DOM.\n * Array-supplied items carry it directly; store-bound items resolve it from\n * the record field named by the list's `tooltipField`.\n */\n tooltip?: string;\n}\n\n/**\n * Accepted form for a single item passed to a custom list's `setItems` /\n * `addItem`: either a plain string (which becomes both the item's key and its\n * label, so a selection is written and read back as the string itself) or a\n * pre-formed {@link SelectableListItem} with an explicit caller-supplied key.\n *\n * @category Components\n */\nexport type SelectableListItemSpec = String | SelectableListItem;\n\n/**\n * Pixel height of one rendered row. Matches `SelectableListRow`'s cached\n * `preferredSize(0, 22)` and the `lineHeight: 22px` declaration in the\n * shared `.SelectableListRow` class rule. Keep these three values in lockstep\n * if the row chrome changes — keyboard `PageUp`/`PageDown` derives its\n * page size from this constant divided into the visible viewport height.\n */\nconst ROW_HEIGHT_PX = 22;\n\n/**\n * Horizontal padding on each side of a row, between the row edge and its\n * renderer. Read by {@link SelectableListRow.publishContentWidth} to convert a\n * renderer's content width into the row's own natural width, so keep it in step\n * with the row's `setPadding` call.\n */\nconst ROW_PADDING_X_PX = 8;\n\n/**\n * Maximum time (in milliseconds) between successive printable-character\n * keypresses before the type-ahead search buffer resets. Picked to match\n * the native `<select>` type-ahead window the custom list replaces — a\n * burst of letters within this window builds a single search prefix; a\n * pause longer than this starts a fresh search.\n */\nconst TYPE_AHEAD_TIMEOUT_MS = 700;\n\n/**\n * Construction-time options for {@link AbstractSelectableList}.\n *\n * @category Components\n */\nexport interface AbstractSelectableListOptions extends AbstractInputOptions {\n items?: String | Array<String>;\n store?: AbstractStore;\n displayField?: string;\n valueField?: string;\n /**\n * Record field whose value becomes each store-bound item's `glyph`, read\n * by [`GlyphListItemRenderer`](/api/component/list/classes/GlyphListItemRenderer).\n * Array-supplied items carry their glyph on the item instead.\n */\n glyphField?: string;\n /**\n * Record field whose value becomes each store-bound item's `tooltip` (the\n * hover text). Array-supplied items carry their tooltip on the item instead.\n */\n tooltipField?: string;\n /**\n * Zero-argument factory producing the renderer for each row. Defaults to a\n * label renderer reproducing the plain-text rows. Supply\n * `() => new GlyphListItemRenderer()` to paint each item's `glyph` beside\n * its label.\n */\n rendererFactory?: () => ListItemRenderer;\n /**\n * Construction-time listener bag — the declarative form of `on()`. Adds the\n * list's `action` shorthand to the inherited `change` / `binding`.\n */\n listeners?: {\n action?: () => void;\n change?: (value: any) => void;\n binding?: () => void;\n };\n /**\n * Muted placeholder text shown inside the scroll area when the list is\n * empty. Opt-in: with neither `emptyText` nor `emptyComponent` set, an empty\n * list has no placeholder child.\n */\n emptyText?: string;\n /**\n * Factory for a custom empty-state placeholder, shown inside the scroll area\n * when the list is empty. Takes precedence over `emptyText`. The returned\n * component should report an unbounded max (the `Component` default) so the\n * empty list still fills its region and drag-resizes.\n */\n emptyComponent?: () => Component;\n /**\n * Construction-time shortcut for\n * [`setHorizontalScrolling`](/api/component/list/classes/List#sethorizontalscrolling).\n * Defaults to `false` — a label wider than the row ellipsises.\n */\n horizontalScrolling?: boolean;\n}\n\n/**\n * Shared visual defaults for every {@link AbstractSelectableList} subclass.\n * Layered into the defaults bag passed to `super` from the abstract\n * constructor so {@link List} and {@link MultiSelectList} share row\n * chrome without duplicating the bag at every leaf.\n */\nconst _defaultAbstractSelectableListOptions: Partial<AbstractSelectableListOptions> = {\n tag: \"div\",\n backgroundColor: \"var(--ts-ui-list-bg, rgb(255, 255, 255))\",\n foregroundColor: \"var(--ts-ui-text-color, black)\",\n border: \"1px solid var(--ts-ui-list-border, rgb(200, 200, 200))\",\n borderRadius: \"var(--ts-ui-border-radius, 4px)\",\n preferredSize: { width: 200, height: 200 },\n maxSize: { width: Number.MAX_SAFE_INTEGER, height: Number.MAX_SAFE_INTEGER },\n};\n\n/**\n * Static styling registered once at module init. The container surface\n * carries the focus ring (matched against the framework auto-added\n * `.List` / `.MultiSelectList` classes that `Component.init()` derives\n * from `constructor.name`); `.SelectableListRow` carries the row chrome\n * (single-line text with ellipsis truncation, optional theme-controlled\n * separator); the `.selected` / `.focused` modifier classes layer the\n * selection wash and keyboard-focus outline on top.\n *\n * The `:focus` ring is attached via a compound selector covering both\n * concrete subclass names rather than the abstract base — TypeScript\n * `class.constructor.name` is the leaf class, so the framework adds\n * `\"List\"` / `\"MultiSelectList\"` (not `\"AbstractSelectableList\"`) to the\n * surface's classList. Keep this list in sync if a new concrete\n * subclass extends `AbstractSelectableList`.\n */\n(() => {\n new StyleRule({\n scope: \"selector\",\n name: \".List, .MultiSelectList\",\n styles: {\n userSelect: \"none\",\n outline: \"none\",\n },\n });\n\n // Pseudo-element overlay rather than a plain `outline:` rule so an\n // ancestor with `overflow: hidden` (the framework's Component default)\n // can't clip the focus indicator. `z-index: 1` lifts the ring above the\n // absolutely-positioned rows.\n new StyleRule({\n scope: \"selector\",\n name: \".List:focus::after, .MultiSelectList:focus::after\",\n styles: {\n content: \"''\",\n position: \"absolute\",\n inset: \"0\",\n border: \"2px solid var(--ts-ui-indicator-focus, rgb(30, 100, 200))\",\n borderRadius: \"inherit\",\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n zIndex: \"1\",\n },\n });\n\n // `lineHeight: 22px` centers the single line of label text vertically\n // without `display: flex` — matches `ROW_HEIGHT_PX` and the row's\n // cached `preferredSize(0, 22)`. The whiteSpace/overflow/textOverflow\n // trio truncates long labels with an ellipsis when the row is narrower\n // than the label text.\n new StyleRule({\n scope: \"class\",\n name: \"SelectableListRow\",\n styles: {\n lineHeight: \"22px\",\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n borderBottom: \"1px solid var(--ts-ui-list-row-separator, transparent)\",\n cursor: \"pointer\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".SelectableListRow:hover\",\n styles: {\n backgroundColor: \"var(--ts-ui-list-row-hover-bg, rgba(30, 100, 200, 0.08))\",\n },\n });\n\n new StyleRule({\n scope: \"selector\",\n name: \".SelectableListRow.selected\",\n styles: {\n backgroundColor: \"var(--ts-ui-list-row-selected-bg, rgba(30, 100, 200, 0.18))\",\n color: \"var(--ts-ui-list-row-selected-color, inherit)\",\n },\n });\n\n // The keyboard-focused row is part of the *selection* indicator family\n // (a light per-row mark, distinct from the heavier focus border around\n // the focusable list root itself). Uses the dashed `indicator.selection`\n // shorthand so future themes can re-skin every \"selection mark\" in one\n // place. Rows have no positioned descendants, so the outline draws on\n // top of the row's text without any covering issue.\n new StyleRule({\n scope: \"selector\",\n name: \".SelectableListRow.focused\",\n styles: {\n outline: \"var(--ts-ui-indicator-selection, 1px dashed rgb(120, 170, 240))\",\n },\n });\n})();\n\n/**\n * A single row inside an {@link AbstractSelectableList}. Holds the static\n * row styling via the `.SelectableListRow` / `.SelectableListRow:hover` /\n * `.SelectableListRow.selected` / `.SelectableListRow.focused` class rules and\n * exposes typed setters for the label, the pool index, the selected\n * flag, and the focused flag.\n *\n * Internal — not re-exported from the per-subpath barrel; the public\n * surface lives on `List` / `MultiSelectList`.\n */\nclass SelectableListRow extends Component {\n // Cached so setter calls made before the element renders survive to\n // be applied at render time.\n private _selected: boolean = false;\n private _focused: boolean = false;\n /** Zero-based index in the row pool; forwarded to the handlers on a gesture. */\n private _index: number;\n /** Owner-supplied gesture handlers, each invoked with this row's `_index`. */\n private readonly _handlers: RowHandlers;\n /** Whether a tooltip is currently attached, so `updateItem` can detach it. */\n private _tooltipAttached: boolean = false;\n /**\n * The renderer owning this row's content (label, optional glyph). Built\n * from the owning list's factory, appended straight into the row DOM in\n * {@link init}, and positioned from {@link doLayout}. Rendered\n * `pointer-events: none` so a click on the label falls through to the\n * row element, whose exact-target `click` listener drives selection.\n */\n private _renderer: ListItemRenderer;\n\n /**\n * @param handlers - Owner-supplied gesture callbacks (click, contextmenu,\n * dblclick), each invoked with the row's index and the raw mouse event.\n * @param index - Initial pool index.\n * @param rendererFactory - Zero-argument factory producing this row's\n * content renderer.\n */\n constructor(handlers: RowHandlers, index: number, rendererFactory: () => ListItemRenderer) {\n super({ tag: \"div\" });\n\n this._handlers = handlers;\n this._index = index;\n this._renderer = rendererFactory();\n this._renderer.setPointerEvents(\"none\");\n\n this.getAria().setRole(\"option\");\n this.setPreferredSize({ width: 0, height: ROW_HEIGHT_PX });\n // Do NOT cap the row's max height. A finite per-row height max makes the\n // list's VBox sum to a finite content max (VBox.aggregateMaxSize), which\n // shrink-wraps the whole list to its content and breaks stretch/scroll\n // and the accordion's resizable drag. The row is already pinned to\n // ROW_HEIGHT_PX by its preferredSize above; leave its max unbounded (the\n // Component default).\n this.setPadding(new Insets(0, ROW_PADDING_X_PX, 0, ROW_PADDING_X_PX));\n // Component's framework default writes `cursor: default` as an\n // inline style, which would beat the `.SelectableListRow` class rule\n // — set the inline cursor explicitly so rows show the hand\n // cursor on hover.\n this.setCursor(\"pointer\");\n\n Event.addListener(this, \"pointerdown\", this.onPointerDown);\n Event.addListener(this, \"click\", this.onClick);\n Event.addListener(this, \"contextmenu\", this.onContextMenu);\n Event.addListener(this, \"dblclick\", this.onDblClick);\n }\n\n /**\n * Rebinds this row's renderer to a new item, replacing the plain-text\n * label write the pool sync used before renderers existed.\n *\n * @param item - The item to display.\n * @param index - The item's zero-based index.\n *\n * @returns This row, for method chaining.\n */\n updateItem(item: SelectableListItem, index: number): this {\n this._renderer.update({ item, index });\n this.applyTooltip(item.tooltip);\n\n return this;\n }\n\n /**\n * Attaches (or detaches) the row's hover tooltip to match the item. Called\n * from {@link updateItem} so a pooled row reused for a different item tracks\n * the new item's `tooltip` — attaching when set, detaching when cleared.\n *\n * @param text - The item's tooltip text, or `undefined` for no tooltip.\n */\n private applyTooltip(text: string | undefined): void {\n if (text) {\n // Tooltip.attach replaces any prior attachment, so re-attaching with\n // new text on pool reuse is safe. The renderer is pointer-events:none,\n // so hover events target the row element and the component-level\n // attach matches (no need to reach the label child).\n Tooltip.attach(this, text);\n this._tooltipAttached = true;\n } else if (this._tooltipAttached) {\n Tooltip.detach(this);\n this._tooltipAttached = false;\n }\n }\n\n /**\n * Returns the row's natural width — its renderer's content width plus the\n * row's own horizontal padding — i.e. the width at which the bound item\n * renders without clipping.\n *\n * Read by {@link ListRowColumn.computeTotalMinSize}, and only while the\n * owning list scrolls horizontally, so a list with the setting off never\n * calls this and never makes its renderers measure.\n *\n * Deliberately *not* published as the row's `minSize`: a minimum is a\n * constraint that propagates outward (`VBox.getMinSize` → the inner\n * `Panel` → the list's `Fit` → `Component.clampWidth`), so a wide row would\n * inflate the whole `List` element inside its host rather than scroll\n * within it. The natural width is an input to the column's own overflow\n * inflation only.\n *\n * @returns The row's natural width in pixels.\n */\n getNaturalWidth(): number {\n return this._renderer.getContentWidth() + ROW_PADDING_X_PX * 2;\n }\n\n /**\n * Swaps in a new content renderer, removing the old renderer's element\n * and appending the new one. Used when the owning list's renderer factory\n * changes. The new renderer is left blank until the next\n * {@link updateItem}.\n *\n * @param renderer - The replacement renderer.\n *\n * @returns This row, for method chaining.\n */\n setRenderer(renderer: ListItemRenderer): this {\n const el = this.getElement();\n\n if (el) {\n const oldEl = this._renderer.getElement();\n if (oldEl && DOM.source.getParentNode(oldEl) === el) {\n DOM.sink.removeChild(el, oldEl);\n }\n }\n\n this._renderer = renderer;\n this._renderer.setPointerEvents(\"none\");\n\n if (el) {\n DOM.sink.appendChild(el, this._renderer.getElement(true)!);\n }\n\n return this;\n }\n\n /**\n * Updates the index this row reports through its click callback. Used\n * when the row pool is reconciled against a new item list and an\n * existing row is reused at a new position.\n *\n * @param index - The new zero-based row index.\n *\n * @returns This row, for method chaining.\n */\n setIndex(index: number): this {\n this._index = index;\n\n return this;\n }\n\n /**\n * Returns the row's current pool index.\n *\n * @returns The zero-based index.\n */\n getIndex(): number {\n return this._index;\n }\n\n /**\n * Toggles the `.selected` class and `aria-selected` to reflect\n * membership in the owning list's selection set.\n *\n * @param value - `true` when this row is currently selected.\n *\n * @returns This row, for method chaining.\n */\n setSelected(value: boolean): this {\n this._selected = value;\n this.getAria().setSelected(value);\n this.applyRowClass();\n\n return this;\n }\n\n /**\n * Returns the cached selected state.\n *\n * @returns `true` when this row is currently selected.\n */\n isSelected(): boolean {\n return this._selected;\n }\n\n /**\n * Toggles the `.focused` class to reflect the keyboard-focus position\n * inside the owning list.\n *\n * @param value - `true` when this row currently holds the keyboard\n * focus position.\n *\n * @returns This row, for method chaining.\n */\n setFocused(value: boolean): this {\n this._focused = value;\n this.applyRowClass();\n\n return this;\n }\n\n /**\n * Returns the cached focused state.\n *\n * @returns `true` when this row holds the keyboard-focus position.\n */\n isFocused(): boolean {\n return this._focused;\n }\n\n /**\n * Renders the row's `<div>` with its current class set. The label content\n * lives in the renderer child, appended by {@link init}.\n *\n * @returns The created element handle.\n */\n protected render(): Handle {\n const element = super.render();\n this.applyRowClass();\n\n return element;\n }\n\n /**\n * Appends the renderer's element to the row DOM. The renderer's own\n * children (label, optional glyph) are appended by the renderer's `init`.\n *\n * @param element - Optional element passed by the rendering pipeline;\n * falls back to getElement().\n *\n * @returns This row, for method chaining.\n */\n protected init(element?: Handle): this {\n super.init(element);\n\n const el = element || this.getElement();\n if (el) {\n DOM.sink.appendChild(el, this._renderer.getElement(true)!);\n }\n\n return this;\n }\n\n /**\n * Positions the renderer to fill the row's padding box, then lets it lay\n * out its own children. Only writes setters (no geometry reads), so it is\n * safe under the `commitBounds` auto-commit path that drives it.\n *\n * @returns This row, for method chaining.\n */\n doLayout(): this {\n super.doLayout();\n\n const inner = this.getInnerSize();\n if (!inner) {\n return this;\n }\n\n const perim = this.getPerimeterSize();\n\n this._renderer.setAutoCommitStyle(false);\n this._renderer.setX(perim.left);\n this._renderer.setY(perim.top);\n this._renderer.setWidth(inner.width);\n this._renderer.setHeight(inner.height);\n this._renderer.setAutoCommitStyle(true);\n\n this._renderer.layoutChildren(inner.width, inner.height);\n\n return this;\n }\n\n /**\n * Computes the row's class list from the cached selected/focused\n * state. Writes via `setElementAttribute(\"class\", …)` so the framework\n * defer-write seam owns the DOM write.\n */\n private applyRowClass(): void {\n const classes = [\"SelectableListRow\"];\n\n if (this._selected) {\n classes.push(\"selected\");\n }\n\n if (this._focused) {\n classes.push(\"focused\");\n }\n\n this.setElementAttribute(\"class\", classes.join(\" \"));\n }\n\n /**\n * Suppresses focus loss when the row is pointed at. Without this,\n * clicking a row while the list root has focus would blur the list,\n * and the keyboard model would lose its focus position before the\n * click handler runs. The same pattern guards the AutoComplete row\n * pool against blurring the host input on click.\n *\n * @param e - The pointerdown event.\n */\n private onPointerDown(e: PointerEvent): void {\n e.preventDefault();\n }\n\n /**\n * Forwards the row's index and the raw mouse event to the owner-supplied\n * click callback.\n *\n * @param e - The click event.\n */\n private onClick(e: MouseEvent): void {\n this._handlers.onClick(this._index, e);\n }\n\n /**\n * Forwards the row's index and the raw mouse event to the owner-supplied\n * context-menu callback.\n *\n * @param e - The contextmenu event.\n */\n private onContextMenu(e: MouseEvent): void {\n this._handlers.onContextMenu(this._index, e);\n }\n\n /**\n * Forwards the row's index and the raw mouse event to the owner-supplied\n * double-click callback.\n *\n * @param e - The dblclick event.\n */\n private onDblClick(e: MouseEvent): void {\n this._handlers.onDblClick(this._index, e);\n }\n}\n\n/**\n * The row stack inside a list's scroll panel: a `VBox` that additionally knows\n * how wide its rows want to be.\n *\n * Exists for one reason — the framework's cross-axis overflow inflation reads\n * the children's *minimum* width (`LayoutManager.inflateForOverflow` →\n * {@link computeTotalMinSize}), but a row's natural width must not become a\n * minimum. A minimum propagates outward — `VBox.getMinSize` → the scroll\n * `Panel` → the list's `Fit` → `Component.clampWidth` — and would inflate the\n * `List` element itself inside its host, so a long label would widen the whole\n * rail instead of scrolling inside it.\n *\n * Overriding `computeTotalMinSize` alone separates the two: the inflation\n * target picks up the widest row's natural width, while `getMinSize` (untouched\n * from `VBox`) keeps reporting the rows' real minimum of zero. So the column\n * lays out wide and scrolls, and nothing outside the scroll panel ever learns\n * of the content's width.\n *\n * Inert unless the host has opted into horizontal overflow — `inflateForOverflow`\n * ignores an axis the host does not scroll, so with `horizontalScrolling` off\n * this behaves exactly as a plain `VBox` and never measures a renderer.\n */\nclass ListRowColumn extends _VBox {\n\n /**\n * Widens the inflation target to the widest row's natural width, so a list\n * scrolling horizontally lays its rows out at full content width.\n *\n * @returns The children's combined min size, with the width raised to the\n * widest row's natural width.\n */\n protected computeTotalMinSize(): Size {\n const total = super.computeTotalMinSize();\n const container = this.getContainer();\n\n // Only the X-overflow path consumes the width, and the scan below makes\n // every row measure its renderer — so skip it whenever the host isn't\n // scrolling X. Not merely an optimisation: a list has always scrolled Y,\n // so `inflateForOverflow` calls this on every layout of every list, and\n // an ungated scan would put a per-row text measure into all of them.\n if (!container || !this.isOverflowingX()) {\n return total;\n }\n\n let natural = 0;\n\n for (const component of container.getLaidOutComponents()) {\n // The empty-state placeholder shares the column with the rows and has\n // no natural width to contribute — it tracks the viewport instead.\n if (component instanceof SelectableListRow) {\n natural = Math.max(natural, component.getNaturalWidth());\n }\n }\n\n return { width: Math.max(total.width, natural), height: total.height };\n }\n}\n\n/**\n * Owner-supplied gesture callbacks for a {@link SelectableListRow}, each invoked\n * with the row's current pool index and the originating mouse event. The row\n * owns no selection or event-dispatch logic itself — it forwards to the list.\n */\ninterface RowHandlers {\n /** Invoked on a left-click of the row. */\n onClick: (index: number, event: MouseEvent) => void;\n /** Invoked on a right-click of the row (before the list suppresses the native menu). */\n onContextMenu: (index: number, event: MouseEvent) => void;\n /** Invoked on a double-click of the row. */\n onDblClick: (index: number, event: MouseEvent) => void;\n}\n\n/**\n * Abstract base for the framework's custom selectable list controls.\n *\n * Owns the item array, the store binding, the row pool (one\n * {@link SelectableListRow} per visible item), the selection set, the\n * keyboard model (ArrowUp/Down, Home/End, PageUp/Down, Enter/Space,\n * type-ahead), and the ARIA listbox wiring. Concrete subclasses\n * ({@link List}, {@link MultiSelectList}) supply the\n * {@link AbstractSelectableList.reduceSelection} reducer that translates a\n * click or keyboard gesture into a new selection set, and the\n * {@link AbstractSelectableList.setValue} / `getValue` round-trip used by\n * [`Bindable`](/api/core/interfaces/Bindable).\n *\n * Not wrapped with `callable()` — abstract classes are never instantiated;\n * the wrapping rule applies only to concrete component subclasses.\n *\n * @category Components\n */\nabstract class AbstractSelectableList<\n TValue,\n TOptions extends AbstractSelectableListOptions = AbstractSelectableListOptions\n>\n extends AbstractInput<TValue, TOptions>\n{\n protected _items: Array<SelectableListItem> = [];\n protected _rowPool: Array<SelectableListRow> = [];\n protected _selectedSet: Set<number> = new Set();\n protected _anchorIndex: number | null = null;\n protected _focusedIndex: number = -1;\n /** Lower-cased type-ahead buffer; cleared on Escape or timeout. */\n protected _typeAheadBuf: string = \"\";\n /** Timestamp (ms) of the last printable keypress; used to time out the buffer. */\n protected _typeAheadAt: number = 0;\n /**\n * When true, {@link handleRowClick} pulls DOM focus to the list root\n * after the gesture commits so subsequent keystrokes route through\n * `handleKeyDown`. Hosts that own their own focus surface and forward\n * keystrokes (e.g. the ComboBox dropdown, which calls\n * {@link handleKey} from the ComboBox's own `keydown`) set this to\n * `false` so the embedded list never steals focus from the wrapping\n * input.\n */\n protected _focusOnRowClick: boolean = true;\n /**\n * When true (default), keyboard navigation\n * (ArrowUp/Down/Home/End/PageUp/Down) commits the focused row as the\n * selection — the \"selection follows focus\" pattern most listbox\n * controls use. Hosts that want a navigable highlight without\n * committing the row as the selected value (the WAI-ARIA\n * combobox-with-list-autocomplete pattern, exercised by\n * [`AutoCompleteField`](/api/component/input/classes/AutoCompleteField))\n * call `setSelectFollowsFocus(false)` so ArrowUp/Down moves only the\n * focus highlight; Enter / Space / click still commit.\n */\n protected _selectFollowsFocus: boolean = true;\n /**\n * Whether over-long rows scroll horizontally instead of ellipsising.\n * Written only by {@link setHorizontalScrolling}, dispatched from the\n * constructor body once `_innerPanel` exists, so the field-initializer\n * default survives the `super()` cascade without a `declare`.\n */\n private _horizontalScrolling: boolean = false;\n protected _innerPanel: Panel;\n /** Cached empty-state placeholder, built lazily on first need; null until then. */\n private _emptyPlaceholder: Component | null = null;\n /** Whether `_emptyPlaceholder` is currently a child of `_innerPanel`. */\n private _placeholderAttached: boolean = false;\n private _storeRefresh: (() => void) | null = null;\n /**\n * Factory producing each row's content renderer. Defaults to a label\n * renderer reproducing the plain-text rows. Written only by\n * {@link setRendererFactory}, dispatched from the constructor body, so the\n * field-initializer default survives the `super()` cascade without a\n * `declare`.\n */\n private _rendererFactory: () => ListItemRenderer = () => new LabelListItemRenderer();\n /**\n * Listeners for the row-gesture events that carry a row index payload\n * (`contextmenu`, `dblclick`) — kept off the DOM `Event` bus, which fires\n * bare DOM events without the index. `change` / `action` stay on the DOM\n * bus via {@link on}. Mirrors [`Tree`](/api/component/tree/classes/Tree)'s\n * `contextmenu` / `dblclick` wiring.\n */\n private _rowListeners: ListenerBag<\"contextmenu\" | \"dblclick\"> = new ListenerBag();\n\n /**\n * @param options - Caller-supplied options bag.\n * @param subclassDefaults - Per-subclass default bag layered over this\n * class's defaults; subclasses forward their `_defaultXxxOptions`\n * constant here.\n */\n constructor(options?: TOptions, subclassDefaults?: Partial<TOptions>) {\n // `Fit` makes the inner panel fill the list root; the Component\n // default `Absolute` would size every child to its preferredSize\n // (none here) and collapse the inner panel to 0×0. Layered into\n // the defaults bag so concrete subclass defaults and user options\n // can still override, alongside the shared list chrome.\n super(\n options,\n {\n ..._defaultAbstractSelectableListOptions,\n layoutManager: new Fit(),\n ...(subclassDefaults ?? {}),\n } as Partial<TOptions>,\n );\n\n // Element-level chrome: the list root carries the `listbox` role\n // and is focusable. The framework auto-adds the leaf-class name\n // (`\"List\"` / `\"MultiSelectList\"`) to the surface's classList in\n // `Component.init()`; the shared `.List, .MultiSelectList`\n // style rule registered at module init picks both up without an\n // extra opt-in.\n this.getAria().setRole(\"listbox\");\n this.getAria().setTabIndex(0);\n\n // Inner panel is the scrollable row stack. `autoScroll: \"y\"` opts\n // it into the framework's native-overflow path; `VBox` lays the\n // rows out vertically full-width with no gap.\n this._innerPanel = new Panel({\n layoutManager: new ListRowColumn({ spacing: 0, stretching: true }),\n autoScroll: \"y\",\n insets: new Insets(0, 0, 0, 0),\n });\n this.addComponent(this._innerPanel);\n\n // Default floor, but let a caller-supplied minSize option win. The\n // super() cascade writes `_options.minSize` only when the caller passed\n // one (the class default {0,0} lives in the defaults bag, not `_options`),\n // so its presence means \"caller set it\". maxSize stays unbounded.\n if (this._options.minSize === undefined) {\n // 100×100 keeps a short empty/placeholder list a usable size.\n this.setMinSize({ width: 100, height: 100 });\n }\n\n Event.addListener(this, \"keydown\", this.handleKeyDown);\n\n // Late-built state: `rendererFactory` / `store` / `items` / `enabled` /\n // `readOnly` were written pure to `_options` by the super-time cascade.\n // Dispatch them now that `_innerPanel` and `_rowPool` exist. The\n // factory is dispatched first so the row pool is built (by `setStore` /\n // `setItems` below) with the caller's renderer on first paint.\n if (this._options.rendererFactory !== undefined) {\n this.setRendererFactory(this._options.rendererFactory);\n }\n\n if (this._options.horizontalScrolling !== undefined) {\n this.setHorizontalScrolling(this._options.horizontalScrolling);\n }\n\n if (this._options.store !== undefined && this._options.displayField !== undefined) {\n this.setStore(this._options.store, this._options.displayField, this._options.valueField, this._options.glyphField, this._options.tooltipField);\n }\n\n if (this._options.items !== undefined) {\n this.setItems(this._options.items);\n }\n\n if (this._options.enabled !== undefined) {\n this.applyEnabled(this._options.enabled);\n }\n\n if (this._options.readOnly !== undefined) {\n this.applyReadOnly(this._options.readOnly);\n }\n\n // Dispatch the empty-state options last, after items/store — a list built\n // *with* items must show no placeholder. Needed because an empty list\n // configured with only `emptyText`/`emptyComponent` never calls syncRows\n // during construction.\n if (this._options.emptyText !== undefined || this._options.emptyComponent !== undefined) {\n this.syncEmptyPlaceholder();\n }\n }\n\n /**\n * Reflects the enabled flag on the ARIA tree, the tabindex, and the\n * cursor. Disabling the list parks the focus index at -1 so a\n * subsequent enable starts fresh, mirroring the native `<select>`\n * the framework replaces. Concrete subclasses can still override\n * for additional behaviour.\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.setCursor(value ? \"default\" : \"not-allowed\");\n\n if (!value) {\n this._focusedIndex = -1;\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n }\n }\n\n /**\n * Reflects the read-only flag on the ARIA tree. Read-only lists\n * stay focusable and announce their state; the click / keyboard\n * reducers are gated separately in {@link handleRowClick} /\n * {@link handleKeyDown}.\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 * Applies an {@link AbstractSelectableListOptions} bag. Item / store\n * fields are written pure into `_options` here and dispatched from the\n * constructor body — the row pool and inner panel only exist after\n * `super()` returns.\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.items !== undefined) this._options.items = options.items;\n if (options.store !== undefined) this._options.store = options.store;\n if (options.displayField !== undefined) this._options.displayField = options.displayField;\n if (options.valueField !== undefined) this._options.valueField = options.valueField;\n if (options.glyphField !== undefined) this._options.glyphField = options.glyphField;\n if (options.tooltipField !== undefined) this._options.tooltipField = options.tooltipField;\n if (options.rendererFactory !== undefined) this._options.rendererFactory = options.rendererFactory;\n if (options.emptyText !== undefined) this._options.emptyText = options.emptyText;\n if (options.emptyComponent !== undefined) this._options.emptyComponent = options.emptyComponent;\n\n if (options.horizontalScrolling !== undefined) this._options.horizontalScrolling = options.horizontalScrolling;\n\n return this;\n }\n\n /**\n * Sets whether a row wider than the viewport scrolls horizontally instead of\n * ellipsising.\n *\n * Off by default, which is the behaviour every list has always had: rows track\n * the viewport width and a label too long for its row clips with an ellipsis.\n * That is the right default for a narrow rail, and for the dropdown surfaces\n * (`ComboBox`, `AutoCompleteField`) where a horizontal bar under a popup reads\n * as a glitch. Turn it on for a list whose labels carry meaning past the\n * truncation point — a file path, a query — and whose host is too narrow to\n * show them.\n *\n * When on, every row is sized to the widest bound row's natural width (see\n * {@link ListItemRenderer.getContentWidth}) or the viewport, whichever is\n * larger, and the scroll area raises a horizontal scrollbar once the content\n * exceeds it. Rows stay full-width relative to each other, so the selection\n * wash still spans the whole row when scrolled. A custom renderer that does\n * not override `getContentWidth` reports no intrinsic width, so its rows stay\n * at the viewport width and nothing scrolls.\n *\n * @param value - True to scroll over-long rows horizontally.\n *\n * @returns This component, for method chaining.\n */\n setHorizontalScrolling(value: boolean): this {\n if (this._horizontalScrolling === value) {\n return this;\n }\n\n this._horizontalScrolling = value;\n\n // `\"auto\"` adds the X axis to the Y the list has always scrolled. That\n // alone drives everything: it is what lets `ListRowColumn` inflate past\n // the viewport, and what raises the bar once the rows do.\n this._innerPanel.setAutoScroll(value ? \"auto\" : \"y\");\n this.scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns whether over-long rows scroll horizontally rather than ellipsising.\n *\n * @returns True when horizontal scrolling is on.\n */\n isHorizontalScrolling(): boolean {\n return this._horizontalScrolling;\n }\n\n /**\n * Sets the muted placeholder text shown inside the scroll area when the list\n * is empty. Pass `null` to clear it. Takes effect immediately: an already\n * empty list shows (or drops) the placeholder on the next layout.\n *\n * @param text - The placeholder text, or `null` to remove it.\n *\n * @returns This component, for method chaining.\n */\n setEmptyText(text: string | null): this {\n this._options.emptyText = text ?? undefined;\n this.resetEmptyPlaceholder();\n this.syncEmptyPlaceholder();\n\n return this;\n }\n\n /**\n * Returns the configured empty-state placeholder text.\n *\n * @returns The placeholder text, or `null` if none is set.\n */\n getEmptyText(): string | null {\n return this._options.emptyText ?? null;\n }\n\n /**\n * Sets a factory for a custom empty-state placeholder, shown inside the\n * scroll area when the list is empty. Takes precedence over\n * {@link setEmptyText}. Pass `null` to clear it. The returned component\n * should report an unbounded max so the empty list still fills its region.\n *\n * @param factory - The placeholder factory, or `null` to remove it.\n *\n * @returns This component, for method chaining.\n */\n setEmptyComponent(factory: (() => Component) | null): this {\n this._options.emptyComponent = factory ?? undefined;\n this.resetEmptyPlaceholder();\n this.syncEmptyPlaceholder();\n\n return this;\n }\n\n /**\n * Returns the configured empty-state placeholder factory.\n *\n * @returns The placeholder factory, or `null` if none is set.\n */\n getEmptyComponent(): (() => Component) | null {\n return this._options.emptyComponent ?? null;\n }\n\n /**\n * Adds or removes the empty-state placeholder against the current item\n * count. Attaches the placeholder (building it lazily on first need) to\n * `_innerPanel` when an empty-state is configured and the list is empty;\n * detaches it otherwise. A no-op when no empty-state is configured — an\n * opted-out empty list keeps no placeholder child.\n *\n * Called at the tail of {@link syncRows}, from the empty-state setters, and\n * once at construction for a list built empty with an empty-state option.\n */\n protected syncEmptyPlaceholder(): void {\n const configured = this._options.emptyComponent !== undefined || this._options.emptyText !== undefined;\n const wants = configured && this._items.length === 0;\n\n if (wants) {\n if (!this._emptyPlaceholder) {\n this._emptyPlaceholder = this.buildEmptyPlaceholder();\n }\n\n if (!this._placeholderAttached) {\n // weight: 1 makes the single child absorb all leftover main-axis\n // (height) space so the placeholder fills the scroll area; the\n // inner VBox's stretching:true fills the width.\n this._innerPanel.addComponent(this._emptyPlaceholder, { weight: 1 });\n this._placeholderAttached = true;\n }\n } else if (this._placeholderAttached && this._emptyPlaceholder) {\n this._innerPanel.removeComponent(this._emptyPlaceholder);\n this._placeholderAttached = false;\n }\n }\n\n /**\n * Builds the empty-state placeholder: the `emptyComponent` factory's output\n * if set, otherwise a muted, horizontally-centered single-line `Text` from\n * `emptyText` using the list-scoped disabled token.\n *\n * @returns The placeholder component.\n */\n private buildEmptyPlaceholder(): Component {\n const factory = this._options.emptyComponent;\n if (factory) {\n return factory();\n }\n\n const text = new Text(this._options.emptyText ?? \"\", { textAlign: \"center\" });\n text.setForegroundColor(\"var(--ts-ui-list-row-disabled-color, rgb(170, 170, 170))\");\n\n return text;\n }\n\n /**\n * Detaches the cached placeholder (if attached) and drops it, so the next\n * {@link syncEmptyPlaceholder} rebuilds it from the current options. Used by\n * the empty-state setters when the configuration changes.\n */\n private resetEmptyPlaceholder(): void {\n if (this._placeholderAttached && this._emptyPlaceholder) {\n this._innerPanel.removeComponent(this._emptyPlaceholder);\n this._placeholderAttached = false;\n }\n\n this._emptyPlaceholder = null;\n }\n\n /**\n * Returns `null` so a multi-line list surface is treated as a\n * replaced/graphical element by horizontal layouts — matches the\n * behaviour the prior native `<select>`-backed `List` preserved.\n *\n * @returns Always `null`.\n */\n getBaseline(): number | null {\n return null;\n }\n\n /**\n * Returns a shallow copy of the current item array.\n *\n * @returns The items in display order.\n */\n getItems(): Array<SelectableListItem> {\n return this._items.slice();\n }\n\n /**\n * Replaces all items with the given specs. Each entry is either a plain\n * string — keyed by the string itself (`{ key: label }`), so `getValue` /\n * `setValue` round-trip the visible text for the common \"list of names\"\n * case — or a pre-formed {@link SelectableListItem} whose explicit key is kept\n * verbatim. Selection and focus are reset; the row pool is reconciled\n * against the new length.\n *\n * @param items - A single spec or an array of specs. Each spec is a string\n * (keyed by its own value) or a `{ key, label }` object (explicit key).\n *\n * @remarks The caller owns key uniqueness — repeated strings, or an explicit\n * key colliding with a string value, produce duplicate keys, and\n * `getValue` / `setValue` resolve to the first row whose `key` matches, so\n * a duplicate key is merely addressed by its lowest matching row.\n *\n * @returns This component, for method chaining.\n */\n setItems(items: SelectableListItemSpec | Array<SelectableListItemSpec>): this {\n if (!Type.isArray(items)) {\n items = [items as SelectableListItemSpec];\n }\n\n const list = items as Array<SelectableListItemSpec>;\n const built: Array<SelectableListItem> = [];\n\n for (const entry of list) {\n built.push(\n typeof entry === \"string\"\n ? { key: entry, label: entry }\n : { key: (entry as SelectableListItem).key, label: (entry as SelectableListItem).label, glyph: (entry as SelectableListItem).glyph, tooltip: (entry as SelectableListItem).tooltip },\n );\n }\n\n return this.setItemsArray(built);\n }\n\n /**\n * Replaces all items with the given pre-formed `{key, label}` pairs.\n * Mirrors {@link setItems} but skips the key-from-label step so a host\n * that already owns typed items (e.g. the [`ComboBox`](/api/component/input/classes/ComboBox)\n * dropdown pushing a `SelectableListItem` array) can hand them over\n * without the keys being overwritten by their labels. Selection and focus are reset; the row pool\n * is reconciled against the new length.\n *\n * Protected on the abstract base so each concrete subclass decides\n * whether to widen it into the public surface — {@link List} does;\n * `MultiSelectList` does not (the multi-select consumers haven't\n * needed the typed-array entry point so far).\n *\n * @param items - The pre-formed item pairs, in display order.\n *\n * @returns This component, for method chaining.\n */\n protected setItemsArray(items: Array<SelectableListItem>): this {\n this._items = items.slice();\n\n this._selectedSet.clear();\n this._anchorIndex = null;\n this._focusedIndex = -1;\n\n this.pauseLayout();\n this.syncRows();\n this.resumeLayout();\n this.updateActiveDescendant();\n\n return this;\n }\n\n /**\n * Appends a new item to the end of the list. A plain string is keyed by the\n * string itself (`{ key: label }`), so `getValue` / `setValue` round-trip the\n * visible text; a pre-formed {@link SelectableListItem} keeps its explicit key\n * verbatim.\n *\n * @param item - A string (keyed by its own value) or a `{ key, label }`\n * object (explicit key).\n *\n * @remarks The caller owns key uniqueness — appending a string equal to an\n * earlier string or explicit key produces a duplicate key, and `getValue` /\n * `setValue` resolve to the first matching row.\n *\n * @returns This component, for method chaining.\n */\n addItem(item: SelectableListItemSpec): this {\n this._items.push(\n typeof item === \"string\"\n ? { key: item, label: item }\n : { key: (item as SelectableListItem).key, label: (item as SelectableListItem).label, glyph: (item as SelectableListItem).glyph, tooltip: (item as SelectableListItem).tooltip },\n );\n\n this.pauseLayout();\n this.syncRows();\n this.resumeLayout();\n\n return this;\n }\n\n /**\n * Binds this list to a store. Records are pulled via `displayField` /\n * `valueField` whenever the store fires `load` / `add` / `remove` /\n * `datachange` / `sync`. Re-binding to a new store de-registers the\n * previous handlers first.\n *\n * @param store - The store to bind to.\n * @param displayField - The record field whose value becomes the row label.\n * @param valueField - Optional. The record field used as the row key;\n * defaults to the record's primary key when omitted.\n * @param glyphField - Optional. The record field whose value becomes each\n * item's `glyph` (read by the glyph renderer); omitted leaves items\n * glyph-less.\n * @param tooltipField - Optional. The record field whose value becomes each\n * item's hover `tooltip`; omitted leaves items tooltip-less.\n *\n * @returns This component, for method chaining.\n */\n setStore(store: AbstractStore, displayField: string, valueField?: string, glyphField?: string, tooltipField?: string): this {\n const oldStore = this._options.store;\n\n if (this._storeRefresh && oldStore) {\n (['load', 'add', 'remove', 'datachange', 'sync'] as const)\n .forEach(e => oldStore.off(e, this._storeRefresh!));\n }\n\n this._options.store = store;\n this._options.displayField = displayField;\n this._options.valueField = valueField;\n this._options.glyphField = glyphField;\n this._options.tooltipField = tooltipField;\n\n const refresh = (): void => this.refreshFromStore();\n this._storeRefresh = refresh;\n\n store.on('load', refresh);\n store.on('add', refresh);\n store.on('remove', refresh);\n store.on('datachange', refresh);\n store.on('sync', refresh);\n\n this.refreshFromStore();\n\n return this;\n }\n\n /**\n * Returns the currently bound store, or `null` when none is set.\n *\n * @returns The bound store, or `null`.\n */\n getStore(): AbstractStore | null {\n return this._options.store ?? null;\n }\n\n /**\n * Replaces the renderer factory. Every existing pool row swaps to a fresh\n * renderer from the new factory and the pool is re-synced so each renderer\n * rebinds to its item before the next layout. New rows built afterwards use\n * the new factory too.\n *\n * @param factory - Zero-argument factory producing a renderer per row.\n *\n * @returns This component, for method chaining.\n */\n setRendererFactory(factory: () => ListItemRenderer): this {\n this._rendererFactory = factory;\n\n for (const row of this._rowPool) {\n row.setRenderer(factory());\n }\n\n this.pauseLayout();\n this.syncRows();\n this.resumeLayout();\n\n return this;\n }\n\n /**\n * Returns the renderer factory currently in use.\n *\n * @returns The zero-argument renderer factory.\n */\n getRendererFactory(): () => ListItemRenderer {\n return this._rendererFactory;\n }\n\n /**\n * Returns the store record corresponding to the most recent\n * single-selection anchor — matches the prior `<select>`-backed\n * behaviour where `getSelectedRecord()` returned the active option's\n * record. For {@link MultiSelectList} consumers wanting the full set\n * of selected records, use [`getSelectedRecords`](/api/component/list/classes/MultiSelectList#getselectedrecords).\n *\n * @returns The selected [`ModelRecord`](/api/data/classes/ModelRecord), or `undefined` when no\n * store is bound or nothing is selected.\n */\n getSelectedRecord(): ModelRecord | undefined {\n const store = this._options.store;\n\n if (!store) {\n return undefined;\n }\n\n const idx = this.getSelectedIndex();\n\n if (idx < 0) {\n return undefined;\n }\n\n return store.getRecords()[idx];\n }\n\n /**\n * Returns the index of the most recent single-selection anchor, or\n * `-1` when nothing is selected.\n *\n * @returns The anchor index.\n */\n getSelectedIndex(): number {\n if (this._anchorIndex !== null && this._selectedSet.has(this._anchorIndex)) {\n return this._anchorIndex;\n }\n\n if (this._selectedSet.size === 0) {\n return -1;\n }\n\n // Fallback when the anchor is gone (e.g. after a programmatic\n // setValues that bypassed the click reducer): return the lowest\n // selected index so the contract stays single-valued.\n return Math.min(...this._selectedSet);\n }\n\n /**\n * Sets the single-selection anchor. The selection set becomes\n * exactly `{idx}` (or empty for `idx < 0`); `_focusedIndex` follows.\n * Optionally fires the `change` event so binding listeners run.\n *\n * @param idx - The zero-based index to select, or a negative value\n * to clear the selection.\n * @param fireEvent - When `true` (default), fires the `change` event\n * after updating; pass `false` for programmatic writes.\n *\n * @returns This component, for method chaining.\n */\n setSelectedIndex(idx: number, fireEvent: boolean = true): this {\n this._selectedSet.clear();\n\n if (idx >= 0 && idx < this._items.length) {\n this._selectedSet.add(idx);\n this._anchorIndex = idx;\n this._focusedIndex = idx;\n } else {\n this._anchorIndex = null;\n this._focusedIndex = -1;\n }\n\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n\n if (fireEvent) {\n this.fireChange();\n }\n\n return this;\n }\n\n /**\n * Registers a listener for one of this list's events. `\"action\"` is a\n * typed semantic shorthand over {@link Event.addListener} for the DOM\n * change event — fired only on user-driven (click / keyboard) selection\n * changes, never on programmatic `setValue` / `setValues`, matching the\n * prior native `<select>`-backed semantics. `\"change\"` and `\"binding\"`\n * are the inherited {@link AbstractInput} listener-bag events.\n *\n * `\"contextmenu\"` fires when a row is right-clicked, with the row index and\n * the raw {@link MouseEvent} (the native menu is suppressed); `\"dblclick\"`\n * fires on a row double-click with the same payload. Both carry the row\n * index directly, so hosts need not walk the row DOM to resolve it.\n *\n * @param event - The event name.\n * @param listener - The callback to invoke when the event fires.\n *\n * @returns This component, for method chaining.\n */\n on(event: \"action\", listener: Event.Listener): this;\n on(event: \"change\", listener: (value: TValue) => void): this;\n on(event: \"binding\", listener: () => void): this;\n on(event: \"contextmenu\", listener: (index: number, event: MouseEvent) => void): this;\n on(event: \"dblclick\", listener: (index: number, event: MouseEvent) => void): this;\n on(event: \"action\" | \"change\" | \"binding\" | \"contextmenu\" | \"dblclick\", listener: Function): this {\n if (event === \"action\") {\n Event.addListener(this, \"change\", listener as Event.Listener);\n\n return this;\n }\n\n if (event === \"contextmenu\" || event === \"dblclick\") {\n this._rowListeners.add(event, listener);\n\n return this;\n }\n\n return super.on(event as \"change\", listener as (value: TValue) => void);\n }\n\n /**\n * Removes a previously registered listener. The exact callback\n * reference must match the one passed to {@link on}.\n *\n * @param event - The event the listener was registered for.\n * @param listener - The callback to remove.\n *\n * @returns This component, for method chaining.\n */\n off(event: \"action\" | \"change\" | \"binding\" | \"contextmenu\" | \"dblclick\", listener: Function): this {\n if (event === \"action\") {\n Event.removeListener(this, \"change\", listener as Event.Listener);\n\n return this;\n }\n\n if (event === \"contextmenu\" || event === \"dblclick\") {\n this._rowListeners.remove(event, listener);\n\n return this;\n }\n\n return super.off(event as \"change\" | \"binding\", listener);\n }\n\n /**\n * Subclass hook: translate a click or keyboard gesture at `idx` into\n * a new selection set. The modifier-key flags are normalised so the\n * same reducer runs for mouse and keyboard origins.\n *\n * @param idx - The row index targeted by the gesture.\n * @param ev - Normalised modifier flags. `ctrl` covers both Ctrl and\n * Cmd (macOS).\n */\n protected abstract reduceSelection(idx: number, ev: { ctrl: boolean, shift: boolean }): void;\n\n /**\n * Subclass hook used by user-driven gestures: encode the current\n * selection set into the subclass's `TValue` shape and fire change /\n * binding listeners. Called from the click and keyboard reducers\n * after {@link reduceSelection} mutates the selection set.\n */\n protected abstract notifyUserChange(): void;\n\n /**\n * Rebuilds `_items` from the bound store's current records. Preserves\n * the previously-selected key when possible — if the key still maps\n * to an item, the selection survives; otherwise the selection is\n * cleared and the focus collapses to row 0 (matching the native\n * `<select>` refresh behaviour the prior `List` inherited).\n */\n protected refreshFromStore(): void {\n const store = this._options.store;\n const displayField = this._options.displayField;\n const valueField = this._options.valueField;\n const glyphField = this._options.glyphField;\n const tooltipField = this._options.tooltipField;\n\n if (!store || !displayField) {\n return;\n }\n\n // Remember the active selection key so we can re-locate it in\n // the new item set; survives partial reorderings / additions.\n const previousAnchorKey = this._anchorIndex !== null && this._items[this._anchorIndex]\n ? this._items[this._anchorIndex].key\n : null;\n\n this._items = [];\n this._selectedSet.clear();\n this._anchorIndex = null;\n\n const records = store.getRecords();\n let restoredAnchor = -1;\n\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const label = String(record.get(displayField));\n const key = valueField\n ? String(record.get(valueField))\n : String(record.getId());\n const glyph = glyphField ? String(record.get(glyphField)) : undefined;\n const tooltip = tooltipField ? String(record.get(tooltipField)) : undefined;\n\n this._items.push({ key, label, glyph, tooltip });\n\n if (previousAnchorKey !== null && key === previousAnchorKey) {\n restoredAnchor = i;\n }\n }\n\n if (restoredAnchor >= 0) {\n this._selectedSet.add(restoredAnchor);\n this._anchorIndex = restoredAnchor;\n this._focusedIndex = restoredAnchor;\n } else {\n this._focusedIndex = this._items.length > 0 ? 0 : -1;\n }\n\n this.pauseLayout();\n this.syncRows();\n this.resumeLayout();\n this.updateActiveDescendant();\n }\n\n /**\n * Reconciles the row pool with `_items`. Overlapping rows have their\n * label, index, selected, and focused state updated; surplus items\n * spawn new rows; surplus rows are removed.\n */\n protected syncRows(): void {\n const newLen = this._items.length;\n const oldLen = this._rowPool.length;\n const overlap = Math.min(newLen, oldLen);\n\n for (let i = 0; i < overlap; i++) {\n const row = this._rowPool[i];\n row.updateItem(this._items[i], i);\n row.setIndex(i);\n row.setSelected(this._selectedSet.has(i));\n row.setFocused(i === this._focusedIndex);\n }\n\n if (newLen > oldLen) {\n for (let i = oldLen; i < newLen; i++) {\n const row = new SelectableListRow(\n {\n onClick: (idx, e) => this.handleRowClick(idx, e),\n onContextMenu: (idx, e) => this.handleRowContextMenu(idx, e),\n onDblClick: (idx, e) => this.handleRowDblClick(idx, e),\n },\n i,\n this._rendererFactory,\n );\n row.updateItem(this._items[i], i);\n row.setSelected(this._selectedSet.has(i));\n row.setFocused(i === this._focusedIndex);\n this._innerPanel.addComponent(row);\n this._rowPool.push(row);\n }\n } else if (newLen < oldLen) {\n for (let i = newLen; i < oldLen; i++) {\n // Drop the row's tooltip attachment (a static id-keyed map) before\n // discarding the row, so a shrinking pool doesn't leak entries.\n Tooltip.detach(this._rowPool[i]);\n this._innerPanel.removeComponent(this._rowPool[i]);\n }\n this._rowPool.splice(newLen);\n }\n\n // Toggle the empty-state placeholder against the new item count. Runs\n // after the row reconciliation, so on a 0→N transition the rows are in\n // place before the placeholder is dropped (and on N→0, dropped rows are\n // gone before the placeholder attaches). syncRows runs inside a paused\n // layout, so the transient coexistence never renders.\n this.syncEmptyPlaceholder();\n }\n\n /**\n * Pushes the cached selection / focus state into every pool row.\n * Called after a selection mutation (click / keyboard reducer or\n * programmatic write) so the visible chrome catches up without a\n * full `syncRows` reconciliation.\n */\n protected refreshRowVisualState(): void {\n for (let i = 0; i < this._rowPool.length; i++) {\n const row = this._rowPool[i];\n row.setSelected(this._selectedSet.has(i));\n row.setFocused(i === this._focusedIndex);\n }\n }\n\n /**\n * Mirrors `_focusedIndex` onto `aria-activedescendant` so assistive\n * tech tracks the keyboard-focus row. Clears the attribute when no\n * row holds focus. Points at the row's framework-generated id — the\n * Event system already keys listeners off that id, so rewriting the\n * DOM id to a synthetic value (e.g. `ListRow-N`) would break row\n * click / pointerdown delivery.\n */\n protected updateActiveDescendant(): void {\n if (this._focusedIndex < 0 || this._focusedIndex >= this._rowPool.length) {\n this.getAria().setActiveDescendant(\"\");\n\n return;\n }\n\n this.getAria().setActiveDescendant(this._rowPool[this._focusedIndex].getId());\n }\n\n /**\n * Fires the `change` event so `on(\"change\", fn)` subscribers and\n * `notifyChange`-fed bindings run. Subclasses route their own\n * `notifyUserChange` through this after the reducer commits.\n */\n protected fireChange(): void {\n const element = this.getElement();\n\n if (element) {\n Event.fireEvent(this, \"change\");\n }\n\n this.notifyChange(this.getValue());\n }\n\n /**\n * Handles a click on a pool row: dispatches the gesture through the\n * subclass's {@link reduceSelection}, syncs the visible chrome, and\n * fires user-change notifications. The list root takes focus on\n * click (rows are not focusable) so subsequent keyboard navigation\n * starts from the clicked row.\n *\n * @param idx - The row index that was clicked.\n * @param e - The original mouse event — modifier-key flags drive the\n * reducer's multi-select branch.\n */\n protected handleRowClick(idx: number, e: MouseEvent): void {\n if (!this.isEnabled() || this.isReadOnly()) {\n return;\n }\n\n if (idx < 0 || idx >= this._items.length) {\n return;\n }\n\n this.reduceSelection(idx, { ctrl: e.ctrlKey || e.metaKey, shift: e.shiftKey });\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n\n if (this._focusOnRowClick) {\n // Pull DOM focus back to the list root so subsequent keystrokes\n // route through `handleKeyDown` — rows themselves are not\n // focusable, only the listbox surface is. Suppressed when the\n // list is hosted by a focus-managing parent (e.g. the\n // ComboBox dropdown) so a programmatic focus shift can't\n // tear down a wrapping cell editor's input.\n this.focus();\n }\n\n this.notifyUserChange();\n }\n\n /**\n * Handles a right-click on a pool row: suppresses the browser's native\n * context menu and fires the `\"contextmenu\"` event with the row index and\n * the raw event. Deliberately does not change the selection — a host that\n * wants the right-clicked row highlighted calls {@link setSelectedIndex}\n * from its listener (mirrors [`Tree`](/api/component/tree/classes/Tree)'s\n * contextmenu contract). Out-of-range indices are ignored.\n *\n * @param idx - The row index that was right-clicked.\n * @param e - The original contextmenu event.\n */\n protected handleRowContextMenu(idx: number, e: MouseEvent): void {\n if (idx < 0 || idx >= this._items.length) {\n return;\n }\n\n e.preventDefault();\n this._rowListeners.fire(\"contextmenu\", idx, e);\n }\n\n /**\n * Handles a double-click on a pool row: fires the `\"dblclick\"` event with\n * the row index and the raw event. The first click of the pair already ran\n * through {@link handleRowClick} and set the selection, so this only layers\n * an activation signal on top. Out-of-range indices are ignored.\n *\n * @param idx - The row index that was double-clicked.\n * @param e - The original dblclick event.\n */\n protected handleRowDblClick(idx: number, e: MouseEvent): void {\n if (idx < 0 || idx >= this._items.length) {\n return;\n }\n\n this._rowListeners.fire(\"dblclick\", idx, e);\n }\n\n /**\n * Toggles whether a row-click gesture pulls DOM focus to the list\n * root after the commit. Hosts that own their own focus surface\n * (the ComboBox dropdown is the canonical example) call\n * `setFocusOnRowClick(false)` so the embedded list never steals\n * focus from a wrapping input or cell editor.\n *\n * @param value - `false` to suppress the focus call.\n *\n * @returns This component, for method chaining.\n */\n setFocusOnRowClick(value: boolean): this {\n this._focusOnRowClick = value;\n\n return this;\n }\n\n /**\n * Toggles whether keyboard navigation (ArrowUp/Down/Home/End/PageUp/Down)\n * commits the focused row as the selection. When `false`, the focus\n * highlight moves but the selection set is untouched and the `change`\n * event does not fire. Enter / Space / click still commit. The\n * [`AutoCompleteField`](/api/component/input/classes/AutoCompleteField)\n * dropdown sets this to `false` so ArrowUp/Down previews a row\n * without writing it into the host TextField.\n *\n * @param value - `false` to disable the selection-follows-focus\n * coupling on keyboard navigation.\n *\n * @returns This component, for method chaining.\n */\n setSelectFollowsFocus(value: boolean): this {\n this._selectFollowsFocus = value;\n\n return this;\n }\n\n /**\n * Returns the current keyboard-focus index, or `-1` when no row\n * holds focus.\n *\n * @returns The zero-based focus index, or `-1`.\n */\n getFocusedIndex(): number {\n return this._focusedIndex;\n }\n\n /**\n * Returns the framework-generated DOM element id of the keyboard-focus\n * row, suitable for writing into a host input's `aria-activedescendant`.\n * Returns `null` when no row holds focus or the focused row hasn't\n * been instantiated in the pool yet (rows materialise lazily as the\n * pool reconciles against the item array).\n *\n * @returns The focused row's element id, or `null`.\n */\n getFocusedRowId(): string | null {\n if (this._focusedIndex < 0 || this._focusedIndex >= this._rowPool.length) {\n return null;\n }\n\n return this._rowPool[this._focusedIndex].getId();\n }\n\n /**\n * Public entry point used by hosts that keep DOM focus on their own\n * surface while embedding this list (e.g. the [`ComboBox`](/api/component/input/classes/ComboBox)\n * dropdown forwarding keystrokes from the ComboBox surface).\n * Returns `true` when the list consumed the key — the caller\n * should then `e.preventDefault()` and stop further processing.\n * Escape is intentionally NOT consumed here so the host can use\n * it to close the wrapping overlay; the list-focused entry point\n * (the protected `handleKeyDown` registered as the list's own\n * `keydown` listener) still handles Escape inline.\n *\n * @param e - The keyboard event captured by the host.\n *\n * @returns `true` when the list consumed the key.\n */\n handleKey(e: KeyboardEvent): boolean {\n if (!this.isEnabled() || this.isReadOnly()) {\n return false;\n }\n\n if (this._items.length === 0) {\n return false;\n }\n\n if (e.key === \"Escape\") {\n return false;\n }\n\n const ctrl = e.ctrlKey || e.metaKey;\n\n if (this.handleNavigationKey(e, ctrl)) {\n return true;\n }\n\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n this.commitFocusedRow(ctrl, e.shiftKey);\n\n return true;\n }\n\n if (!ctrl && !e.altKey && e.key.length === 1) {\n this.handleTypeAhead(e.key);\n\n return true;\n }\n\n return false;\n }\n\n /**\n * Handles keydown on the list root: ArrowUp/Down/Home/End move the\n * focus index, PageUp/Down move by visible-row count, Enter/Space\n * commits the focused row, Ctrl+A in subclasses extends to select\n * all (handled in {@link MultiSelectList}), Escape clears the\n * type-ahead buffer, and printable characters feed the type-ahead\n * search.\n *\n * @param e - The keyboard event.\n */\n protected handleKeyDown(e: KeyboardEvent): void {\n if (!this.isEnabled() || this.isReadOnly()) {\n return;\n }\n\n if (this._items.length === 0) {\n return;\n }\n\n const ctrl = e.ctrlKey || e.metaKey;\n\n if (e.key === \"Escape\") {\n this._typeAheadBuf = \"\";\n\n return;\n }\n\n if (this.handleNavigationKey(e, ctrl)) {\n return;\n }\n\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n this.commitFocusedRow(ctrl, e.shiftKey);\n\n return;\n }\n\n // Printable single-character key — feed the type-ahead buffer.\n // `key.length === 1` filters out named keys (`\"Tab\"`, `\"Shift\"`,\n // `\"ArrowDown\"`, …) without an explicit allow-list.\n if (!ctrl && !e.altKey && e.key.length === 1) {\n this.handleTypeAhead(e.key);\n }\n }\n\n /**\n * Subset of `handleKeyDown` that processes the arrow / Home / End /\n * Page-* navigation keys. Returns `true` when a key was handled so\n * the caller can skip the remaining branches.\n *\n * @param e - The keyboard event.\n * @param ctrl - Pre-computed Ctrl-or-Cmd flag.\n *\n * @returns `true` when the key was handled.\n */\n protected handleNavigationKey(e: KeyboardEvent, ctrl: boolean): boolean {\n const navigable = new Set([\n \"ArrowDown\", \"ArrowUp\", \"Home\", \"End\", \"PageDown\", \"PageUp\",\n ]);\n\n if (!navigable.has(e.key)) {\n return false;\n }\n\n e.preventDefault();\n\n const viewportH = this.getHeight() || ROW_HEIGHT_PX;\n const pageSize = Math.max(1, Math.floor(viewportH / ROW_HEIGHT_PX));\n const curr = this._focusedIndex < 0 ? 0 : this._focusedIndex;\n let next: number;\n\n if (e.key === \"ArrowDown\") {\n next = Math.min(curr + 1, this._items.length - 1);\n } else if (e.key === \"ArrowUp\") {\n next = Math.max(curr - 1, 0);\n } else if (e.key === \"PageDown\") {\n next = Math.min(curr + pageSize, this._items.length - 1);\n } else if (e.key === \"PageUp\") {\n next = Math.max(curr - pageSize, 0);\n } else if (e.key === \"Home\") {\n next = 0;\n } else {\n next = this._items.length - 1;\n }\n\n this.moveFocus(next, ctrl, e.shiftKey);\n\n return true;\n }\n\n /**\n * Moves the keyboard focus to `idx`. By default the move also runs\n * the subclass's {@link reduceSelection} so single-select lists track\n * the focus highlight; pass `ctrl: true` to move the focus without\n * touching the selection (the standard \"browse without committing\"\n * gesture). `shift: true` forwards the range-extend hint to the\n * reducer. When the list-wide {@link setSelectFollowsFocus} flag is\n * `false`, the commit branch is suppressed entirely — the focus\n * highlight moves but the selection set is untouched and\n * `notifyUserChange` does not fire.\n *\n * @param idx - The new focus index.\n * @param ctrl - When `true`, skip the selection update.\n * @param shift - When `true`, ask the reducer to extend the\n * selection from `_anchorIndex` to `idx`.\n */\n protected moveFocus(idx: number, ctrl: boolean, shift: boolean): void {\n this._focusedIndex = idx;\n\n const commit = !ctrl && this._selectFollowsFocus;\n\n if (commit) {\n this.reduceSelection(idx, { ctrl: false, shift });\n }\n\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n this.scrollIndexIntoView(idx);\n\n if (commit) {\n this.notifyUserChange();\n }\n }\n\n /**\n * Commits the focused row through {@link reduceSelection}. Mirrors\n * the gesture of clicking that row with the same modifier keys.\n *\n * @param ctrl - Ctrl-or-Cmd modifier flag at the time of the keypress.\n * @param shift - Shift modifier flag at the time of the keypress.\n */\n protected commitFocusedRow(ctrl: boolean, shift: boolean): void {\n if (this._focusedIndex < 0) {\n return;\n }\n\n this.reduceSelection(this._focusedIndex, { ctrl, shift });\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n this.notifyUserChange();\n }\n\n /**\n * Appends `ch` to the type-ahead buffer (after timing out the\n * previous buffer when more than {@link TYPE_AHEAD_TIMEOUT_MS}\n * elapsed since the last key) and jumps the focus to the first item\n * whose lower-cased label starts with the buffer.\n *\n * @param ch - The character key pressed.\n */\n protected handleTypeAhead(ch: string): void {\n const now = Date.now();\n\n if (now - this._typeAheadAt > TYPE_AHEAD_TIMEOUT_MS) {\n this._typeAheadBuf = \"\";\n }\n\n this._typeAheadBuf += ch.toLowerCase();\n this._typeAheadAt = now;\n\n const buf = this._typeAheadBuf;\n const idx = this._items.findIndex(item => item.label.toLowerCase().startsWith(buf));\n\n if (idx < 0) {\n return;\n }\n\n // Type-ahead moves only the focus highlight; selection is\n // unaffected (same behaviour as the native `<select>` it\n // replaces — typing a letter previews the row without\n // committing).\n this._focusedIndex = idx;\n this.refreshRowVisualState();\n this.updateActiveDescendant();\n this.scrollIndexIntoView(idx);\n }\n\n /**\n * Scrolls the inner panel so the row at `idx` is fully visible, with\n * no movement when it already is. Reads / writes the panel's native\n * `scrollTop` directly — the framework's typed scroll setter only\n * lives on the `VirtualScroller`-backed components (`Table.Body`,\n * `Tree`); the `Panel`-with-`autoScroll: \"y\"` surface relies on\n * native browser overflow and exposes no setter.\n *\n * @param idx - The row index to scroll into view.\n */\n protected scrollIndexIntoView(idx: number): void {\n if (idx < 0 || idx >= this._items.length) {\n return;\n }\n\n const panelEl = this._innerPanel.getElement();\n\n if (!panelEl) {\n return;\n }\n\n const metrics = DOM.source.getScrollMetrics(panelEl);\n const top = idx * ROW_HEIGHT_PX;\n const bottom = top + ROW_HEIGHT_PX;\n const scrollTop = metrics.scrollTop;\n const visibleBottom = scrollTop + metrics.clientHeight;\n\n if (top < scrollTop) {\n DOM.sink.apply(panelEl, { scrollTop: top });\n } else if (bottom > visibleBottom) {\n DOM.sink.apply(panelEl, { scrollTop: bottom - metrics.clientHeight });\n }\n }\n}\n\nexport { AbstractSelectableList, SelectableListRow };\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { AbstractSelectableList, AbstractSelectableListOptions, SelectableListItem } from \"~/component/list/AbstractSelectableList.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link List}.\n *\n * @category Components\n */\nexport interface ListOptions extends AbstractSelectableListOptions {\n selectedIndex?: number;\n value?: string;\n selectedItem?: string;\n}\n\n/**\n * A scrollable single-selection list box.\n *\n * Rendered as a `<div role=\"listbox\">` populated with `<div role=\"option\">`\n * rows. Implements [`Bindable<string>`](/api/core/interfaces/Bindable) so it can be plugged into a\n * [`Binding`](/api/core/classes/Binding) directly. Keyboard model mirrors the WAI-ARIA listbox\n * pattern: ArrowUp/Down moves and selects, Home/End jump to the\n * extremes, PageUp/Down jump by viewport-row count, Enter / Space\n * commits the focused row, and printable characters drive a 700ms\n * type-ahead search.\n *\n * @category Components\n */\nclass List extends AbstractSelectableList<string, ListOptions> {\n\n /**\n * @param options - Optional. Construction-time options applied to\n * the list.\n */\n constructor(options?: ListOptions) {\n super(options);\n\n // Late-built state: `selectedIndex` / `value` / `selectedItem`\n // were written pure to `_options` by the super-time cascade.\n // Dispatch them now that the row pool and selection set exist\n // (`super()` already populated `_items` from `items` / `store`,\n // and applied `enabled` / `readOnly`).\n if (this._options.selectedIndex !== undefined) {\n this.setSelectedIndex(this._options.selectedIndex, false);\n }\n\n if (this._options.value !== undefined) {\n this.setValue(this._options.value);\n }\n\n if (this._options.selectedItem !== undefined) {\n this.setValue(this._options.selectedItem);\n }\n }\n\n /**\n * Applies a {@link ListOptions} bag. Single-select state fields are\n * written pure into `_options` here and dispatched from the constructor\n * body after the row pool is built.\n *\n * @param options - The options bag carrying the values to apply.\n *\n * @returns This component, for method chaining.\n */\n protected applyOptions(options: ListOptions): this {\n super.applyOptions(options);\n\n if (options.selectedIndex !== undefined) this._options.selectedIndex = options.selectedIndex;\n if (options.value !== undefined) this._options.value = options.value;\n if (options.selectedItem !== undefined) this._options.selectedItem = options.selectedItem;\n\n return this;\n }\n\n /**\n * Pushes pre-formed {@link SelectableListItem} pairs into the list,\n * bypassing the auto-keying that {@link setItems} applies to a\n * label-only array. Intended for hosts that already own typed\n * `{key, label}` data (e.g. the [`ComboBox`](/api/component/input/classes/ComboBox)\n * dropdown forwarding its item array). Selection and focus are\n * reset; the row pool is reconciled against the new length.\n *\n * @param items - The pre-formed item pairs, in display order.\n *\n * @returns This component, for method chaining.\n */\n setItemsArray(items: Array<SelectableListItem>): this {\n return super.setItemsArray(items);\n }\n\n /**\n * Selects the row whose `key` matches `value`. No-op when the value\n * doesn't appear in the current item set — same behaviour the prior\n * native `<select>` had when assigned an unknown `value`.\n *\n * @param value - The row key to select.\n *\n * @returns This component, for method chaining.\n */\n setValue(value: string): this {\n const idx = this._items.findIndex(item => item.key === value);\n\n this.setSelectedIndex(idx, false);\n\n return this;\n }\n\n /**\n * Returns the key of the currently selected row.\n *\n * @returns The selected row's key, or an empty string when nothing\n * is selected.\n */\n getValue(): string {\n const idx = this.getSelectedIndex();\n\n if (idx < 0 || idx >= this._items.length) {\n return \"\";\n }\n\n return this._items[idx].key;\n }\n\n /**\n * Reduces a click / keyboard gesture into the single-select shape:\n * the modifier keys are ignored, the selection becomes exactly\n * `{idx}`, and the anchor / focus collapse to the clicked row.\n *\n * @param idx - The row index the gesture targeted.\n * @param _ev - Ignored; single-select doesn't branch on modifier keys.\n */\n protected reduceSelection(idx: number, _ev: { ctrl: boolean, shift: boolean }): void {\n this._selectedSet.clear();\n this._selectedSet.add(idx);\n this._anchorIndex = idx;\n this._focusedIndex = idx;\n }\n\n /**\n * User-driven selection commit. Mirrors the prior native `<select>`\n * `change` event semantics — fired from the click / keyboard\n * reducers, not from programmatic `setValue` / `setSelectedIndex(idx,\n * false)`.\n */\n protected notifyUserChange(): void {\n this.fireChange();\n }\n\n}\n\nconst ListCallable = callable(List);\ntype ListCallable = List;\nexport {\n List as _List,\n ListCallable as List,\n};\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-CGn7xyTw.js";var t;(function(n){let r=-1,i=-1,a=-1,o=-1;function measureTextSize(t,n={}){let r=e.source.measureText(t,n);return{width:r.width,height:r.height}}n.measureTextSize=measureTextSize;function measureTextWidth(e,t){return measureTextSize(e,t).width}n.measureTextWidth=measureTextWidth;function linePaddingPx(){if(r>=0)return r;let t=e.source.getThemeVar(`--ts-ui-line-padding`),n=parseFloat(t);return r=isNaN(n)?2:n,r}function rootFontSizePx(){if(i>=0)return i;let t=e.source.getThemeVar(`--ts-ui-font-size`),n=parseFloat(t);return i=isNaN(n)?14:n,i}function lineHeightPx(e={}){let t=e.fontSizePx??rootFontSizePx(),n=e.linePadding??!0;return n===!0?t+=linePaddingPx():typeof n==`number`&&(t+=n),Math.round(t)}n.lineHeightPx=lineHeightPx;function measureTextBaseline(){if(a>=0)return a;let t=e.source.measureFontMetrics(),n=lineHeightPx()-(t.ascent+t.descent);return a=Math.round(n/2+t.ascent),a}n.measureTextBaseline=measureTextBaseline;function singleLineBoxHeight(e,t,n){let r=e.getTop()+e.getBottom()+(t?t.getTop()+t.getBottom():0)+n.top+n.bottom;return lineHeightPx()+r}n.singleLineBoxHeight=singleLineBoxHeight;function opticalCenterOffset(){if(o>=0)return o;let t=e.source.measureFontMetrics(),n=(t.ascent-t.descent)/2,r=t.capTop/2;return o=Math.max(0,Math.round(n-r)),o}n.opticalCenterOffset=opticalCenterOffset;function invalidateTextMetricsCache(){r=-1,i=-1,a=-1,o=-1}n.invalidateTextMetricsCache=invalidateTextMetricsCache;function generateUUID(){let e=`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,function(e){let t=Math.random()*16|0;return(e==`x`?t:t&3|8).toString(16)}),n=parseInt(e[0]);return t.isInteger(n)&&(e=`a`+e.substring(1,e.length)),e}n.generateUUID=generateUUID;function isInteger(e){return Number.isInteger(e)}n.isInteger=isInteger;function clamp(e,t,n){return Math.min(Math.max(e,t),n)}n.clamp=clamp;function kebabToCamel(e){return e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}n.kebabToCamel=kebabToCamel})(t||={});var BaseObject=class{_id;constructor(){this._id=t.generateUUID()}getId(){return this._id}setId(e){return this._id=e,this}getClassName(){return this.constructor.name}},n=2**53-1;function isUnbounded(e){return e>=2**53-1}function saturate(e){return Math.min(e,n)}function borderToStyle(e){let t=e.border??`none`;return{borderTop:e.borderTop??t,borderRight:e.borderRight??t,borderBottom:e.borderBottom??t,borderLeft:e.borderLeft??t}}function borderSideWidth(e){if(!e)return 0;let t=e.trim().match(/^([\d.]+)px\b/i);return t?parseFloat(t[1]):0}var Insets=class extends BaseObject{_top;_right;_bottom;_left;constructor(e,t,n,r){super(),this._top=e||0,this._right=t||0,this._bottom=n||0,this._left=r||0}getTop(){return this._top||0}setTop(e){return this._top=e,this}getRight(){return this._right||0}setRight(e){return this._right=e,this}getBottom(){return this._bottom||0}setBottom(e){return this._bottom=e,this}getLeft(){return this._left||0}setLeft(e){return this._left=e,this}set(e,t,n,r){return this._top=e,this._right=t,this._bottom=n,this._left=r,this}render(){return this.getTop()+`px `+this.getRight()+`px `+this.getBottom()+`px `+this.getLeft()+`px`}},r=function(e){return e.STATIC=`static`,e.FIXED=`fixed`,e.ABSOLUTE=`absolute`,e}({});export{n as a,BaseObject as c,borderToStyle as i,t as l,Insets as n,isUnbounded as o,borderSideWidth as r,saturate as s,r as t};
2
- //# sourceMappingURL=Position-A39T7-_1.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Position-A39T7-_1.js","names":[],"sources":["../../src/typescript/lib/core/Util.ts","../../src/typescript/lib/core/BaseObject.ts","../../src/typescript/lib/primitive/Size.ts","../../src/typescript/lib/primitive/Border.ts","../../src/typescript/lib/primitive/Insets.ts","../../src/typescript/lib/primitive/Position.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Size } from \"~/primitive/Size.js\";\nimport type { Insets } from \"~/primitive/Insets.js\";\nimport { DOM } from \"~/core/DOM.js\";\n\n/**\n * Font options for off-screen text measurement.\n * All properties default to the active theme variables when omitted.\n */\nexport interface TextMeasureOptions {\n fontFamily?: string;\n fontSize? : string;\n fontWeight?: string;\n fontStyle? : string;\n fontVariant?: string;\n fontStretch?: string;\n lineHeight?: string\n /**\n * When set, the probe wraps at this pixel width (using `pre-wrap`) instead of\n * measuring on a single `nowrap` line. The returned `height` then reflects the\n * wrapped, multi-line box. Omit to measure the natural single-line size.\n */\n maxWidth?: number;\n}\n\n/**\n * Result of an off-screen text measurement that also reports the typographic baseline.\n *\n * @remarks `baseline` is the offset from the top of the measured box to the font baseline,\n * in pixels — analogous to CSS `vertical-align: baseline` on an inline-block element.\n */\nexport interface TextMetrics {\n width: number;\n height: number;\n baseline: number;\n}\n\n/**\n * General-purpose utility functions for DOM interaction and browser environment queries.\n *\n * @category Util\n */\nexport namespace Util {\n\n // Cached text-metric results, invalidated together on theme change via\n // `invalidateTextMetricsCache`. `-1` is the \"not yet measured\" sentinel\n // (a real padding / font size / baseline / offset is always >= 0).\n let linePaddingCache: number = -1;\n let rootFontSizeCache: number = -1;\n let textBaselineCache: number = -1;\n let opticalOffsetCache: number = -1;\n\n /**\n * Measures the rendered size of a text string using an off-screen probe `<span>`.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured `{width, height}` in pixels, ceiled to whole pixels.\n */\n export function measureTextSize(text: string, options: TextMeasureOptions = {}): Size {\n const metrics = DOM.source.measureText(text, options);\n\n return { width: metrics.width, height: metrics.height };\n }\n\n /**\n * Returns the rendered pixel width of a text string.\n *\n * @param text - The string to measure.\n * @param options - Font properties to apply. Defaults to the active theme variables.\n * @returns The measured width in pixels, ceiled to a whole pixel.\n */\n export function measureTextWidth(text: string, options?: TextMeasureOptions): number {\n return measureTextSize(text, options).width;\n }\n\n /**\n * Returns the active theme's leading (`--ts-ui-line-padding`) in pixels.\n *\n * @returns The integer-pixel value of `--ts-ui-line-padding`, or `4` as a\n * fallback when the variable is missing or unparseable.\n */\n function linePaddingPx(): number {\n if (linePaddingCache >= 0) {\n return linePaddingCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-line-padding\");\n const parsed = parseFloat(raw);\n\n // 2 mirrors the `--ts-ui-line-padding` default shipped by every theme\n // (see ModernTheme/DarkTheme/ClassicTheme `font.linePadding: '2px'`);\n // it only applies when the var is absent (e.g. pre-theme-apply probe).\n linePaddingCache = isNaN(parsed) ? 2 : parsed;\n\n return linePaddingCache;\n }\n\n /**\n * Returns the document root font size (`--ts-ui-font-size`) in pixels, the\n * default font size for a control that doesn't override it.\n *\n * @returns The integer-pixel root font size, or `14` as a fallback.\n */\n function rootFontSizePx(): number {\n if (rootFontSizeCache >= 0) {\n return rootFontSizeCache;\n }\n\n const raw = DOM.source.getThemeVar(\"--ts-ui-font-size\");\n const parsed = parseFloat(raw);\n\n rootFontSizeCache = isNaN(parsed) ? 14 : parsed;\n\n return rootFontSizeCache;\n }\n\n /**\n * Returns a vertical text metric in integer pixels: a control's font size,\n * plus the theme leading (`--ts-ui-line-padding`) by default.\n *\n * @param options - Measurement options.\n * @param options.fontSizePx - The control's font size in pixels. Omit to use\n * the document root font size (`--ts-ui-font-size`), which is what the\n * native `<input>`-backed controls render at.\n * @param options.linePadding - Controls the leading added to the font size:\n * `true` (the default) adds the theme `--ts-ui-line-padding`, giving the\n * full rendered line box (matching the `calc(1em + …)` line-height controls\n * render at); `false` adds nothing, returning the bare font size to size a\n * box from its font without leading; a number adds that exact pixel padding.\n * @returns `round(fontSize + leading)`, where leading is the theme padding,\n * `0`, or the given number.\n *\n * @remarks With the default leading the line box scales with font size, so\n * 12px and 14px text get proportionate line boxes from the one token. Text\n * components, table rows, and the baseline computation use the default so\n * their measurement matches the rendered line box; the native input box\n * heights pass `false` so the box hugs the font size plus their own chrome.\n * The padding and root font size are cached; call\n * {@link invalidateTextMetricsCache} after a theme change to force a\n * re-read.\n */\n export function lineHeightPx(options: { fontSizePx?: number, linePadding?: boolean | number } = {}): number {\n let fs = options.fontSizePx ?? rootFontSizePx();\n\n const linePadding = options.linePadding ?? true;\n\n if (linePadding === true) {\n fs += linePaddingPx();\n } else if (typeof linePadding === \"number\") {\n fs += linePadding;\n }\n\n return Math.round(fs);\n }\n\n /**\n * Returns the content-relative text baseline for the unified line-height\n * model: the offset from the top of the `lineHeightPx()` line box to the\n * font baseline.\n *\n * @returns The baseline offset in pixels, rounded to the nearest integer.\n *\n * @remarks Computed from the canvas 2D `measureText` font metrics rather\n * than a DOM probe, so it is deterministic and UA-independent. A CSS line\n * box centres the font's ascent+descent within `line-height`; this\n * reproduces that centring with the known px line box —\n * `round(lineGap / 2 + ascent)` where `lineGap = lineHeightPx - (ascent +\n * descent)` — so the measured baseline matches where the browser paints the\n * glyph in both a native `<input>` and a `Text`/`Label`. `fontBoundingBox*`\n * (font-intrinsic, string-independent) is used in preference to\n * `actualBoundingBox*` (glyph-ink specific) so the baseline does not shift\n * per measured string; `\"X\"` is passed only to satisfy `measureText`. The\n * result is cached; call {@link invalidateTextMetricsCache} after a theme\n * change to force re-measurement.\n */\n export function measureTextBaseline(): number {\n if (textBaselineCache >= 0) {\n return textBaselineCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const gap = lineHeightPx() - (m.ascent + m.descent);\n\n textBaselineCache = Math.round(gap / 2 + m.ascent);\n\n return textBaselineCache;\n }\n\n /**\n * Returns the pixel height of a single-line input box: the theme line-box\n * height ({@link lineHeightPx}) plus the component's own vertical chrome\n * (insets + optional padding + border).\n *\n * @param insets - The component's layout insets (top/bottom read).\n * @param padding - The component's CSS padding, or `null` when it has none.\n * @param border - The component's border widths (top/bottom read).\n * @returns The single-line box height in pixels.\n *\n * @remarks Factors out the `chrome = insets + padding + border; h =\n * lineHeightPx() + chrome` idiom shared by every single-line native-input\n * box height (`TextField` / `PasswordField` / `ComboBox` / the picker fields\n * / `NumberSpinner`). Only the vertical (top/bottom) edges contribute; the\n * horizontal edges are the caller's width concern. `NumberSpinner` uniquely\n * passes its *inner input's* padding rather than its own.\n */\n export function singleLineBoxHeight(\n insets: Insets,\n padding: Insets | null,\n border: { top: number; bottom: number },\n ): number {\n const chrome = insets.getTop() + insets.getBottom()\n + (padding ? padding.getTop() + padding.getBottom() : 0)\n + border.top + border.bottom;\n\n return lineHeightPx() + chrome;\n }\n\n /**\n * Returns the downward pixel offset that moves a single line of text from\n * its line-box (geometric) centre to its optical (cap-height) centre.\n *\n * @returns The downward offset in pixels (`>= 0`), rounded to the nearest\n * integer.\n *\n * @remarks A label's visible glyphs occupy cap-top→baseline; the descender\n * band below the baseline is empty ink, so the ink's visual centre sits\n * above the font box's geometric centre and a geometrically-centred label\n * reads as too high. This returns roughly half the unused descender space —\n * `round(boxMid - inkMid)` where `boxMid = (ascent - descent) / 2` and\n * `inkMid = capTop / 2` with `capTop = actualBoundingBoxAscent` (the cap-top\n * ink of `\"X\"`) — so a consumer ([`Button`](/api/component/button/classes/Button))\n * can nudge single-line text down onto its true optical centre. Derived\n * from the same cached canvas\n * metrics as {@link measureTextBaseline}; cached and invalidated together\n * via {@link invalidateTextMetricsCache}.\n */\n export function opticalCenterOffset(): number {\n if (opticalOffsetCache >= 0) {\n return opticalOffsetCache;\n }\n\n const m = DOM.source.measureFontMetrics();\n const boxMid = (m.ascent - m.descent) / 2;\n const inkMid = m.capTop / 2;\n\n opticalOffsetCache = Math.max(0, Math.round(boxMid - inkMid));\n\n return opticalOffsetCache;\n }\n\n /**\n * Discards every cached text metric (line box, baseline, optical offset) so\n * the next read re-measures against the active theme font.\n *\n * @remarks Call this whenever the active theme's font size, family, or\n * line-height changes, since the cached values reflect the font in use at\n * the time of the first measurement and would otherwise mis-align controls\n * against each other after a theme swap.\n */\n export function invalidateTextMetricsCache(): void {\n linePaddingCache = -1;\n rootFontSizeCache = -1;\n textBaselineCache = -1;\n opticalOffsetCache = -1;\n }\n\n /**\n * Generates a UUID string, ensuring the first character is never a digit.\n *\n * @returns A UUID v4 string with a guaranteed non-numeric first character.\n *\n * @remarks If the standard UUID generation produces a leading digit, it is replaced\n * with the letter \"a\" so the result is safe to use as a DOM id or CSS identifier.\n */\n export function generateUUID() {\n let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n let r = Math.random() * 16 | 0,\n v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n\n let first = parseInt(uuid[0]);\n if (Util.isInteger(first)) {\n uuid = \"a\" + uuid.substring(1, uuid.length);\n }\n\n return uuid;\n }\n\n /**\n * Returns true if value is an integer.\n *\n * @param value - The value to test.\n *\n * @returns `true` if `value` is an integer, `false` otherwise.\n */\n export function isInteger(value: Object) {\n return Number.isInteger(value);\n }\n\n /**\n * Clamps a number into an inclusive `[min, max]` range.\n *\n * @param value - The number to clamp.\n * @param min - The lower bound.\n * @param max - The upper bound.\n *\n * @returns `value` when it lies within the range, otherwise the nearer bound.\n *\n * @remarks Assumes `min <= max` (the framework's `min <= preferred <= max`\n * size invariant). When `min > max` the maximum wins (`clamp(v, 10, 0) === 0`)\n * — the low-first `Math.min(Math.max(...))` tie-break; callers must not rely\n * on it. `NaN` propagates (a `NaN` input returns `NaN`), matching the inlined\n * `Math.min`/`Math.max` expressions this replaces.\n */\n export function clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n }\n\n /**\n * Converts a hyphen-separated identifier (e.g. `\"border-top-width\"`) to its\n * camelCase equivalent (`\"borderTopWidth\"`). Useful for translating\n * CSS-style kebab-case property names into the camelCase form expected by\n * `CSSStyleDeclaration` bracket-indexed assignment.\n *\n * @param value - The kebab-case input string.\n * @returns The camelCase equivalent.\n */\n export function kebabToCamel(value: string): string {\n return value.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n }\n\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Util } from \"~/core/Util.js\"\n\n/**\n * Base class for all library objects.\n * Automatically assigns a unique identifier on construction.\n *\n * @category Core\n */\nexport class BaseObject {\n\n private _id: string;\n\n constructor() {\n this._id = Util.generateUUID();\n }\n\n /**\n * Returns the unique identifier for this object.\n *\n * @returns The UUID string assigned at construction time.\n */\n getId() {\n return this._id;\n }\n\n /**\n * Sets the unique identifier for this object.\n *\n * @param id - The new identifier string to assign.\n */\n setId(id: string) : this {\n this._id = id;\n\n return this;\n }\n\n /**\n * Returns the runtime class name of this object.\n *\n * @returns The name of the constructor function as a string.\n */\n getClassName() {\n return this.constructor.name;\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * Represents a two-dimensional size with width and height in pixels.\n *\n * @category Util\n */\nexport interface Size {\n width: number,\n height: number\n}\n\n/**\n * The sentinel extent meaning \"no upper bound\" on a size axis.\n *\n * @category Util\n */\nexport const UNBOUNDED: number = Number.MAX_SAFE_INTEGER;\n\n/**\n * True when an extent is at or above the unbounded sentinel (recognises the\n * legacy `Number.MAX_VALUE` too).\n *\n * @param n - The extent to test.\n * @returns `true` when `n` is at or above {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function isUnbounded(n: number): boolean {\n return n >= Number.MAX_SAFE_INTEGER;\n}\n\n/**\n * Caps an extent at the unbounded sentinel so an unbounded sum cannot overflow\n * it.\n *\n * @param n - The extent to cap.\n * @returns `n`, capped at {@link UNBOUNDED}.\n *\n * @category Util\n */\nexport function saturate(n: number): number {\n return Math.min(n, UNBOUNDED);\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * A border specification built from complete CSS border strings.\n * `border` is the all-sides fallback; each per-side field overrides it for\n * that side. An unspecified side falls back to `border`, then to `\"none\"`.\n *\n * @category Util\n */\nexport interface BorderOptions {\n /** CSS `border` shorthand applied to all four sides (e.g. `\"1px solid rgb(...)\"`, `\"none\"`, `\"var(--x)\"`). */\n border?: string;\n /** CSS `border-top` value; overrides `border` for the top side. */\n borderTop?: string;\n /** CSS `border-right` value; overrides `border` for the right side. */\n borderRight?: string;\n /** CSS `border-bottom` value; overrides `border` for the bottom side. */\n borderBottom?: string;\n /** CSS `border-left` value; overrides `border` for the left side. */\n borderLeft?: string;\n}\n\n/**\n * Expands a {@link BorderOptions} into the four camelCase longhand style keys\n * (`borderTop`/`borderRight`/`borderBottom`/`borderLeft`) that `StyleRule.setMany`\n * consumes. Each side resolves via `side ?? border ?? \"none\"`, so a pure-longhand\n * map replays deterministically regardless of what else touched the rule.\n *\n * @param border - The border specification to expand.\n *\n * @returns A map of the four longhand keys to their resolved CSS values.\n *\n * @category Util\n */\nexport function borderToStyle(border: BorderOptions): Record<string, string | null> {\n const all = border.border ?? \"none\";\n\n return {\n borderTop: border.borderTop ?? all,\n borderRight: border.borderRight ?? all,\n borderBottom: border.borderBottom ?? all,\n borderLeft: border.borderLeft ?? all,\n };\n}\n\n/**\n * Best-effort leading-`<n>px` width of one side's CSS value. Returns `0` for\n * `undefined`, `none`, `0`, `var(...)`, or any non-`px` leading token. Used both\n * to parse the always-`<n>px` values `getComputedStyle` returns (authoritative,\n * post-render) and to estimate a width from a spec string before an element exists.\n *\n * @param value - A single side's CSS border value, or `undefined`.\n *\n * @returns The leading pixel width, or `0` when none can be parsed.\n *\n * @category Util\n */\nexport function borderSideWidth(value: string | undefined): number {\n if (!value) {\n return 0;\n }\n\n const match = value.trim().match(/^([\\d.]+)px\\b/i);\n\n return match ? parseFloat(match[1]) : 0;\n}\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { BaseObject } from \"~/core/BaseObject.js\";\n\n/**\n * Represents the four directional inset (padding/margin) values for a rectangular area.\n * All values are expressed in pixels.\n *\n * @example\n * ```typescript\n * import { Insets } from '@jimka/typescript-ui/primitive';\n*\n * component.setInsets(new Insets(8, 12, 8, 12)); // top, right, bottom, left\n * ```\n *\n * @category Util\n */\nexport class Insets extends BaseObject {\n\n private _top: number;\n private _right: number;\n private _bottom: number;\n private _left: number;\n\n /**\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n constructor(top: number, right: number, bottom: number, left: number) {\n super();\n\n this._top = top || 0;\n this._right = right || 0;\n this._bottom = bottom || 0;\n this._left = left || 0;\n }\n\n /**\n * Returns the top inset in pixels.\n *\n * @returns The top inset value, defaulting to `0` if unset.\n */\n getTop() {\n return this._top || 0;\n }\n\n /**\n * Sets the top inset in pixels.\n *\n * @param value - The new top inset value in pixels.\n */\n setTop(value: number) : this {\n this._top = value;\n\n return this;\n }\n\n /**\n * Returns the right inset in pixels.\n *\n * @returns The right inset value, defaulting to `0` if unset.\n */\n getRight() {\n return this._right || 0;\n }\n\n /**\n * Sets the right inset in pixels.\n *\n * @param value - The new right inset value in pixels.\n */\n setRight(value: number) : this {\n this._right = value;\n\n return this;\n }\n\n /**\n * Returns the bottom inset in pixels.\n *\n * @returns The bottom inset value, defaulting to `0` if unset.\n */\n getBottom() {\n return this._bottom || 0;\n }\n\n /**\n * Sets the bottom inset in pixels.\n *\n * @param value - The new bottom inset value in pixels.\n */\n setBottom(value: number) : this {\n this._bottom = value;\n\n return this;\n }\n\n /**\n * Returns the left inset in pixels.\n *\n * @returns The left inset value, defaulting to `0` if unset.\n */\n getLeft() {\n return this._left || 0;\n }\n\n /**\n * Sets the left inset in pixels.\n *\n * @param value - The new left inset value in pixels.\n */\n setLeft(value: number) : this {\n this._left = value;\n\n return this;\n }\n\n /**\n * Sets all four inset values at once.\n *\n * @param top - Top inset in pixels.\n * @param right - Right inset in pixels.\n * @param bottom - Bottom inset in pixels.\n * @param left - Left inset in pixels.\n */\n set(top: number, right: number, bottom: number, left: number) : this {\n this._top = top;\n this._right = right;\n this._bottom = bottom;\n this._left = left;\n\n return this;\n }\n\n /**\n * Returns the insets as a CSS shorthand string (e.g. `\"4px 4px 4px 4px\"`).\n *\n * @returns A CSS margin/padding shorthand string with all four sides in top-right-bottom-left order.\n */\n render() {\n return this.getTop() + \"px \" + this.getRight() + \"px \" + this.getBottom() + \"px \" + this.getLeft() + \"px\";\n }\n};\n","// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\n/**\n * CSS `position` values used by the framework.\n *\n * The framework positions every component absolutely (see\n * [ARCHITECTURE.md](/ARCHITECTURE.md) §Positioning). Only three values\n * are exposed:\n *\n * - `ABSOLUTE` — the universal default for every framework component.\n * - `FIXED` — the documented exception for floating overlays that anchor to\n * the viewport (`AnimatedDropdown`, `Popover`, `Notification`, `Dialog`,\n * `DialogBackdrop`). Set internally by these subclasses; never by callers.\n * - `STATIC` — the documented exception for an HTML element whose native\n * semantics require in-flow rendering (currently only `Legend`, which needs\n * the notch in its parent `<fieldset>`'s border).\n *\n * Other CSS values (`relative`, `sticky`, `initial`, `inherit`) are\n * intentionally **not** members. Application code does not call\n * `setPosition` — that setter is `protected` on `Component`.\n *\n * @category Util\n */\nexport enum Position {\n STATIC = \"static\",\n FIXED = \"fixed\",\n ABSOLUTE = \"absolute\",\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{t as e}from"./DOM-CGn7xyTw.js";import{l as t}from"./Position-A39T7-_1.js";import{f as n,t as r}from"./Component-DXf5a3g0.js";var i={tag:`span`,textAlign:`left`,fontKerning:`auto`,fontSize:14,fontSizeAdjust:`none`,fontStretch:`normal`,fontStyle:`normal`,fontVariant:`normal`,fontWeight:`normal`,truncate:!0},a=100,o=`calc(1em + var(--ts-ui-line-padding, 2px))`,Text=class extends r{_hasExplicitPreferredSize=!1;_fontSizeCSSVar=`--ts-ui-font-size`;_fontSizeCSSRule=`var(--ts-ui-font-size, 14px)`;_lineHeightCSSVar=null;_lineHeightCSSRule=o;_measuredBaseline=null;_measuredMinSize=null;_autoMeasure=!0;_measurementDirty=!0;_wordBreak=null;_lineClamp=null;_textOverflow=null;_truncate=!0;constructor(e,t,n){super(t,{...i,...n??{}}),this._defaultOptions.fontFamily=`var(--ts-ui-font-family, system-ui, sans-serif)`,this.clearInsets(),this.setElementCSSRule(`lineHeight`,this._lineHeightCSSRule),this.subscribeTheme(()=>{if(this._fontSizeCSSVar){let e=this.resolveBoundFontSizePx();e!==null&&(this._options.fontSize=e)}this._lineHeightCSSVar&&(this._defaultOptions.lineHeight=this.readThemeLineHeightPx()),this.calculateSize()}),e!==void 0&&this._options.text===void 0&&this.setText(e),this._measurementDirty=!0}applyOptions(e){return super.applyOptions(e),e.text!==void 0&&this.setText(e.text),e.textAlign!==void 0&&this.setTextAlign(e.textAlign),e.textShadow!==void 0&&this.setTextShadow(e.textShadow),e.fontFamily!==void 0&&this.setFontFamily(e.fontFamily),e.fontSize!==void 0&&this.setFontSize(e.fontSize),e.fontWeight!==void 0&&this.setFontWeight(e.fontWeight),e.fontStyle!==void 0&&this.setFontStyle(e.fontStyle),e.fontVariant!==void 0&&this.setFontVariant(e.fontVariant),e.fontStretch!==void 0&&this.setFontStretch(e.fontStretch),e.fontKerning!==void 0&&this.setFontKerning(e.fontKerning),e.fontSizeAdjust!==void 0&&this.setFontSizeAdjust(e.fontSizeAdjust),e.lineHeight!==void 0&&this.setLineHeight(e.lineHeight),e.textOverflow!==void 0&&this.setTextOverflow(e.textOverflow),e.whiteSpace!==void 0&&this.setWhiteSpace(e.whiteSpace),this.setTruncate(e.truncate??this._defaultOptions.truncate),this}readThemeLineHeightPx(){let n=this._options.fontSize??this._defaultOptions.fontSize??14;if(this._lineHeightCSSVar){let t=e.source.getThemeVar(this._lineHeightCSSVar),n=parseFloat(t);if(!isNaN(n))return n}return t.lineHeightPx({fontSizePx:n})}getElement(e=!1){return super.getElement(e)}resolveBoundFontSizePx(){if(!this._fontSizeCSSVar)return null;let t=parseFloat(e.source.getThemeVar(this._fontSizeCSSVar));return isNaN(t)?e.source.resolveFontSizePx(this._fontSizeCSSRule??`var(${this._fontSizeCSSVar})`):t}setPreferredSize(e){return this._hasExplicitPreferredSize=!0,super.setPreferredSize(e),this}setCalculatedSize(e,t){this._hasExplicitPreferredSize||super.setPreferredSize({width:e,height:t})}calculateSize(){if(this._measurementDirty=!1,this._defaultOptions.lineHeight===void 0&&(this._defaultOptions.lineHeight=this.readThemeLineHeightPx()),!this._autoMeasure)return;let t=this.getLineHeight()??this.readThemeLineHeightPx(),n=Math.ceil(t),r=this._options.text;if(r){let t=e.source.measureText(r.toString(),this.measureOptions()),i=this.measuredHeight(r.toString(),t.width,t.height);this._measuredBaseline=t.baseline,this.setCalculatedSize(t.width,i);let o=this._truncate?Math.min(t.width,a):t.width;this._measuredMinSize={width:o,height:Math.max(i,n)}}else this._measuredBaseline=null,this.setCalculatedSize(0,0),this._measuredMinSize={width:0,height:0}}measure(){let e=this._autoMeasure;this._autoMeasure=!0,this.calculateSize(),this._autoMeasure=e}getBaseline(){return this._measurementDirty&&this.calculateSize(),this.wrapInnerBaseline(this._measuredBaseline)}measureOptions(){let e=this.getFontSize(),t=this.getLineHeight();return{fontFamily:this.getFontFamily()??void 0,fontSize:this._fontSizeCSSRule??(e===null?void 0:`${e}px`),fontWeight:this.getFontWeight()??void 0,fontStyle:this.getFontStyle()??void 0,fontVariant:this.getFontVariant()??void 0,fontStretch:this.getFontStretch()??void 0,lineHeight:this._lineHeightCSSRule??(t===null?void 0:`${t}px`)}}isWrapping(){let e=this.getWhiteSpace();return e===`normal`||e===`pre-wrap`||e===`pre-line`||e===`break-spaces`}measuredHeight(t,n,r){if(!this.isWrapping()||this.isVerticalWritingMode())return r;let i=this.getWidth();if(Number.isNaN(i))return r;let a=this.getPerimeterSize(),o=i-a.left-a.right;if(o>=n)return r;let s=e.source.measureText(t,{...this.measureOptions(),maxWidth:o}),c=Math.ceil(this.getLineHeight()??this.readThemeLineHeightPx());return Math.max(s.height,c)}setWidth(e){let t=this.getWidth();return super.setWidth(e),this.isWrapping()&&this.getWidth()!==t&&(this._measurementDirty=!0,this.calculateSize()),this}getPreferredSize(){this._measurementDirty&&this.calculateSize();let e=super.getPreferredSize();return e&&this.isVerticalWritingMode()?{width:e.height,height:e.width}:e}isVerticalWritingMode(){let e=this.getWritingMode();return e!==null&&(e.startsWith(`vertical`)||e.startsWith(`sideways`))}getMinSize(){this._measurementDirty&&this.calculateSize();let e=this._measuredMinSize,t=super.getMinSize();return e?this.isVerticalWritingMode()?t?{width:Math.max(t.width,e.height),height:t.height}:{width:e.height,height:0}:t?{width:t.width,height:Math.max(t.height,e.height)}:{width:0,height:e.height}:t}getText(){return this._options.text||``}setText(t){this._options.text=t||``,this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout();let n=this.getElement();return n&&e.sink.apply(n,{text:t.valueOf()}),this}setAutoMeasure(e){return this._autoMeasure=e,this}getTextAlign(){return this._options.textAlign??this._defaultOptions.textAlign??null}setTextAlign(e){return this._options.textAlign=e,this.setElementCSSRule(`textAlign`,e),this}getTextShadow(){return this._options.textShadow??null}setTextShadow(e){return this._options.textShadow=e,this.setElementCSSRule(`textShadow`,e),this}clearTextShadow(){return this._options.textShadow===void 0?this:(this._options.textShadow=void 0,this.setElementCSSRule(`textShadow`,null),this)}getFontFamily(){return this._options.fontFamily??this._defaultOptions.fontFamily??null}setFontFamily(e){return this._options.fontFamily=e,this.setElementCSSRule(`fontFamily`,e),this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this}getFontKerning(){return this._options.fontKerning??this._defaultOptions.fontKerning??null}setFontKerning(e){return this._options.fontKerning=e,this.setElementCSSRule(`fontKerning`,e),this}getFontSize(){return this._options.fontSize??this._defaultOptions.fontSize??null}setFontSize(e){if(typeof e==`number`)this._options.fontSize=e,this._fontSizeCSSVar=null,this._fontSizeCSSRule=null,this.setElementCSSRule(`fontSize`,e+`px`);else{let t=this.getFontSize()??14;this._fontSizeCSSVar=e,this._fontSizeCSSRule=`var(${e}, ${t}px)`,this.setElementCSSRule(`fontSize`,this._fontSizeCSSRule);let n=this.resolveBoundFontSizePx();n!==null&&(this._options.fontSize=n)}return this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this}getFontSizeAdjust(){return this._options.fontSizeAdjust??this._defaultOptions.fontSizeAdjust??null}setFontSizeAdjust(e){return this._options.fontSizeAdjust=e,this.setElementCSSRule(`fontSizeAdjust`,e),this}getFontStretch(){return this._options.fontStretch??this._defaultOptions.fontStretch??null}setFontStretch(e){return this._options.fontStretch=e,this.setElementCSSRule(`fontStretch`,e),this}getFontStyle(){return this._options.fontStyle??this._defaultOptions.fontStyle??null}setFontStyle(e){return this._options.fontStyle=e,this.setElementCSSRule(`fontStyle`,e),this}getFontVariant(){return this._options.fontVariant??this._defaultOptions.fontVariant??null}setFontVariant(e){return this._options.fontVariant=e,this.setElementCSSRule(`fontVariant`,e),this}getFontWeight(){return this._options.fontWeight??this._defaultOptions.fontWeight??null}setFontWeight(e){return this._options.fontWeight=e,this.setElementCSSRule(`fontWeight`,e),this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this}getLineHeight(){return this._options.lineHeight??this._defaultOptions.lineHeight??null}setLineHeight(e){if(typeof e==`number`){if(this._options.lineHeight===e&&this._lineHeightCSSVar===null&&this._lineHeightCSSRule===null)return this;this._options.lineHeight=e,this._lineHeightCSSVar=null,this._lineHeightCSSRule=null,this.setElementCSSRule(`lineHeight`,e+`px`)}else this._lineHeightCSSVar=e,this._lineHeightCSSRule=`var(${e}, ${o})`,this._options.lineHeight=this.readThemeLineHeightPx(),this.setElementCSSRule(`lineHeight`,this._lineHeightCSSRule);return this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this}centerInHeight(e){return e===null?(this._lineHeightCSSVar=null,this._lineHeightCSSRule=o,this._options.lineHeight=this.readThemeLineHeightPx(),this.setElementCSSRule(`lineHeight`,this._lineHeightCSSRule),this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this):this.setLineHeight(e)}getTextOverflow(){return this._textOverflow}setTextOverflow(e){return this._textOverflow=e,this.setElementCSSRule(`textOverflow`,e),this}clearTextOverflow(){return this._textOverflow===null?this:(this._textOverflow=null,this.setElementCSSRule(`textOverflow`,null),this)}isTruncate(){return this._truncate}setTruncate(e){return this._truncate=e,e?(this.setWhiteSpace(`nowrap`),this.setOverflow(`hidden`),this.setTextOverflow(`ellipsis`)):(this.setElementCSSRule(`whiteSpace`,null),this.setOverflow(`visible`),this.setElementCSSRule(`textOverflow`,null),this._textOverflow=null),this._measurementDirty=!0,(this.getParentComponent()??this).scheduleLayout(),this}getWordBreak(){return this._wordBreak}setWordBreak(e){return this._wordBreak===e?this:(this._wordBreak=e,this.setElementCSSRule(`wordBreak`,e),this)}getLineClamp(){return this._lineClamp}setLineClamp(e){return this._lineClamp===e?this:(this._lineClamp=e,this.setElementCSSRules({display:`-webkit-box`,webkitBoxOrient:`vertical`,webkitLineClamp:String(e),overflow:`hidden`,textOverflow:`ellipsis`}),this)}clearLineClamp(){return this._lineClamp===null?this:(this._lineClamp=null,this.setElementCSSRules({display:null,webkitBoxOrient:null,webkitLineClamp:null,overflow:null,textOverflow:null}),this)}applyStyle(e){super.applyStyle(e);let t=this.getFontSize(),n=this.getLineHeight();return this.setElementCSSRules({fontFamily:this.getFontFamily()??``,textAlign:this.getTextAlign()??``,textShadow:this.getTextShadow()??``,fontKerning:this.getFontKerning()??``,fontSize:this._fontSizeCSSRule??(t===null?``:`${t}px`),fontSizeAdjust:this.getFontSizeAdjust()??``,fontStretch:this.getFontStretch()??``,fontStyle:this.getFontStyle()??``,fontVariant:this.getFontVariant()??``,fontWeight:this.getFontWeight()??``,lineHeight:this._lineHeightCSSRule??(n===null?``:`${n}px`)}),this}render(){let t=super.render();return e.sink.apply(t,{text:this.getText().valueOf()}),t}},s=n(Text);export{s as t};
2
- //# sourceMappingURL=Text-gz6qjFfP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Text-gz6qjFfP.js","names":[],"sources":["../../src/typescript/lib/component/input/Text.ts"],"sourcesContent":["// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0\n\nimport { Component, ComponentOptions } from \"~/core/Component.js\";\nimport { DOM } from \"~/core/DOM.js\";\nimport type { Handle } from \"~/core/DOM.js\";\nimport { Util } from \"~/core/Util.js\";\nimport { Size } from \"~/primitive/Size.js\";\nimport { callable } from \"~/core/Callable.js\";\n\n/**\n * Construction-time options for {@link Text}.\n *\n * @category Components\n */\nexport interface TextOptions extends ComponentOptions {\n tag?: string;\n text?: string;\n textAlign?: string;\n textShadow?: string;\n fontFamily?: string;\n fontSize?: number | string;\n fontWeight?: string;\n fontStyle?: string;\n fontVariant?: string;\n fontStretch?: string;\n fontKerning?: string;\n fontSizeAdjust?: string;\n lineHeight?: number | string;\n textOverflow?: string;\n whiteSpace?: string;\n /**\n * When `true` (default), the text is single-line + clipped + ellipsised\n * when its rendered width is below its natural width, and `minSize.width`\n * is capped at `100` so parent layouts can shrink the text past its\n * natural width.\n *\n * When `false`, no ellipsis is applied and `minSize.width` reports the\n * full natural width — the text refuses to be squeezed, forcing the\n * parent to widen (used by [`Button`](/api/component/button/classes/Button)\n * for the label so the button grows to fit its text instead of clipping).\n */\n truncate?: boolean;\n}\n\n/**\n * Module-level class defaults forwarded to `super` via the options bag so the\n * `applyOptions` cascade dispatches each setter once with the final value.\n *\n * `fontFamily` and `lineHeight` are intentionally **omitted**:\n *\n * - `fontFamily` must remain a getter-fallback only. Routing it through\n * `setFontFamily(...)` would write the literal `var(--ts-ui-font-family, …)`\n * onto every Text's CSS rule, blocking a parent's `font-family` override\n * from cascading through.\n * - `lineHeight` is theme-derived (`readThemeLineHeightPx()`), so the value\n * isn't known at module load. It is resolved lazily on first\n * `calculateSize()` (post-attach), keeping construction JS-only per\n * ARCHITECTURE.md \"Defer DOM work to render time\".\n */\nconst _defaultTextOptions: Partial<TextOptions> = {\n tag: \"span\",\n textAlign: \"left\",\n fontKerning: \"auto\",\n fontSize: 14,\n fontSizeAdjust: \"none\",\n fontStretch: \"normal\",\n fontStyle: \"normal\",\n fontVariant: \"normal\",\n fontWeight: \"normal\",\n truncate: true,\n};\n\n// Upper bound for the auto-derived `minSize.width` from text measurement —\n// short labels report their full measured width (so they're never truncated\n// when the container has room), longer text caps here so the parent layout\n// always has room to shrink the Text below its natural width.\nconst TEXT_AUTO_MIN_WIDTH_CAP_PX = 100;\n\n// Default theme-tracking line-height rule: the control's own font size plus the\n// `--ts-ui-line-padding` leading, so the line box scales per font size. `1em`\n// resolves against the element's own font-size at both render and measure time.\n// `2px` is the shipped `--ts-ui-line-padding` default, used only if the var is\n// absent. A control overrides this with an explicit px via `setLineHeight`.\nconst ADDITIVE_LINE_HEIGHT_RULE = \"calc(1em + var(--ts-ui-line-padding, 2px))\";\n\n/**\n * A text-displaying component with comprehensive font and layout controls.\n *\n * Uses an off-screen probe element to measure text dimensions and automatically\n * updates the preferred size whenever the text or a font property changes.\n *\n * `Text` subscribes to [`ThemeManager`](/api/core/classes/ThemeManager) on construction so it re-measures itself\n * on every theme change, through the base class's `subscribeTheme` — released\n * automatically on `dispose()`.\n *\n * @category Components\n */\nclass Text<TOptions extends TextOptions = TextOptions> extends Component<TOptions> {\n\n private _hasExplicitPreferredSize: boolean = false;\n private _fontSizeCSSVar : string | null = \"--ts-ui-font-size\";\n private _fontSizeCSSRule: string | null = \"var(--ts-ui-font-size, 14px)\";\n private _lineHeightCSSVar : string | null = null;\n private _lineHeightCSSRule: string | null = ADDITIVE_LINE_HEIGHT_RULE;\n private _measuredBaseline: number | null = null;\n private _measuredMinSize: Size | null = null;\n private _autoMeasure: boolean = true;\n private _measurementDirty: boolean = true;\n private _wordBreak: string | null = null;\n private _lineClamp: number | null = null;\n private _textOverflow: string | null = null;\n private _truncate: boolean = true;\n\n // `NoInfer` on `options` keeps a partial options literal from narrowing\n // TOptions to just the keys it carries: `new Text(\"x\", { fontWeight: \"600\" })`\n // must stay a `Text<TextOptions>` (assignable to Component), not a\n // `Text<{ fontWeight: string }>` (whose narrowed option type is not). Subclasses\n // still fix TOptions through `extends Text<MyOptions>`, not argument inference.\n constructor(text?: String, options?: NoInfer<TOptions>, subclassDefaults?: Partial<TOptions>) {\n super(\n options,\n { ..._defaultTextOptions, ...(subclassDefaults ?? {}) } as Partial<TOptions>,\n );\n\n // Carve-out fallbacks — see `_defaultTextOptions` for why these two\n // don't ride the merge-defaults cascade. Both are consulted by their\n // getters as a fallback when `_options.X` is undefined.\n //\n // Note: the cascade-driven `setFontSize(14)` clobbers `fontSizeCSSVar`\n // and `fontSizeCSSRule` to null, but Text's field initializers (which\n // run after super returns) restore both to their var-binding values —\n // so theme reactivity is preserved by the DOM `var(...)` binding even\n // though the cascade temporarily writes a literal.\n //\n // `_defaultOptions.lineHeight` is resolved lazily on first\n // `calculateSize()` (post-attach) — see ARCHITECTURE.md \"Defer DOM\n // work to render time\".\n this._defaultOptions.fontFamily = \"var(--ts-ui-font-family, system-ui, sans-serif)\";\n\n this.clearInsets();\n this.setElementCSSRule(\"lineHeight\", this._lineHeightCSSRule);\n\n this.subscribeTheme(() => {\n if (this._fontSizeCSSVar) {\n // Resolve from the element's computed font-size (the cascade has\n // applied the new var by the time onThemeChange fires); the root\n // custom property reads back as an unevaluated calc() string.\n const resolved = this.resolveBoundFontSizePx();\n\n if (resolved !== null) {\n // Route to `_options` so the post-cascade explicit value\n // (set by `setFontSize(14)` during applyOptions) is\n // overwritten on theme change. Writing to `_defaultOptions`\n // here would be shadowed by `_options.fontSize = 14` in\n // the `getFontSize` fallback, breaking re-flow.\n this._options.fontSize = resolved as TOptions[\"fontSize\"];\n }\n }\n\n if (this._lineHeightCSSVar) {\n this._defaultOptions.lineHeight = this.readThemeLineHeightPx();\n }\n\n this.calculateSize();\n });\n\n // Positional `text` constructor argument: write to the bag only when\n // the caller didn't also pass `options.text` (which would have been\n // dispatched via super's applyOptions cascade and should win).\n if (text !== undefined && this._options.text === undefined) {\n this.setText(text);\n }\n\n // Off-screen text measurement is deferred until the first\n // getPreferredSize / getBaseline call so construction stays JS-only\n // (no forced layout from `DOM.source.measureText`).\n this._measurementDirty = true;\n }\n\n /**\n * Applies a {@link TextOptions} bag to this component, dispatching font and\n * text properties to their corresponding setters after the inherited\n * Component fields have been applied.\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 // Dispatch only caller-supplied values. Class-level font defaults (e.g.\n // the 14px size, a subclass's bold weight) are resolved lazily by the\n // font getters' `_defaultOptions` fallback, which `applyStyle` re-reads\n // at render — so they never enter `_options`.\n if (options.text !== undefined) {\n this.setText(options.text);\n }\n\n if (options.textAlign !== undefined) {\n this.setTextAlign(options.textAlign);\n }\n\n if (options.textShadow !== undefined) {\n this.setTextShadow(options.textShadow);\n }\n\n if (options.fontFamily !== undefined) {\n this.setFontFamily(options.fontFamily);\n }\n\n if (options.fontSize !== undefined) {\n this.setFontSize(options.fontSize);\n }\n\n if (options.fontWeight !== undefined) {\n this.setFontWeight(options.fontWeight);\n }\n\n if (options.fontStyle !== undefined) {\n this.setFontStyle(options.fontStyle);\n }\n\n if (options.fontVariant !== undefined) {\n this.setFontVariant(options.fontVariant);\n }\n\n if (options.fontStretch !== undefined) {\n this.setFontStretch(options.fontStretch);\n }\n\n if (options.fontKerning !== undefined) {\n this.setFontKerning(options.fontKerning);\n }\n\n if (options.fontSizeAdjust !== undefined) {\n this.setFontSizeAdjust(options.fontSizeAdjust);\n }\n\n if (options.lineHeight !== undefined) {\n this.setLineHeight(options.lineHeight);\n }\n\n if (options.textOverflow !== undefined) {\n this.setTextOverflow(options.textOverflow);\n }\n\n if (options.whiteSpace !== undefined) {\n this.setWhiteSpace(options.whiteSpace);\n }\n\n // `truncate` carries a class default (true) and applies its CSS\n // (white-space / overflow / text-overflow) imperatively via the setter\n // with no render re-read, so always dispatch the caller value or the\n // default — otherwise a default-truncating Text never gets the CSS.\n this.setTruncate(options.truncate ?? this._defaultOptions.truncate!);\n\n return this;\n }\n\n /**\n * Resolves this `Text`'s line box height in pixels under the additive\n * leading model.\n *\n * @returns `Util.lineHeightPx(fontSize)` — the control's own font size plus\n * the `--ts-ui-line-padding` leading — for the default theme-tracking case.\n * A legacy custom line-height var binding resolves that var as a fixed line\n * box instead, falling back to the additive value when it is unparseable.\n *\n * @remarks `_options.fontSize` is always a resolved px number here (a CSS\n * var passed to `setFontSize` is resolved and stored as a number), so the\n * leading scales with the control's actual font size — a 12px button title\n * and a 14px label get proportionate line boxes from the one token. This is\n * the same arithmetic `Util.lineHeightPx` applies for input box heights, so\n * a `Text` measures and renders at the line height a sibling input expects.\n */\n private readThemeLineHeightPx(): number {\n // `_options.fontSize` is the resolved px the bound var evaluates to —\n // `setFontSize`/`onThemeChange` populate it through the probe-backed\n // `resolveBoundFontSizePx`, so it is correct even pre-attach (a calc()\n // token included). No element read here: a parent reads this at\n // construction, before this Text's own element is styled.\n const fs = (this._options.fontSize as number | undefined) ?? (this._defaultOptions.fontSize as number | undefined) ?? 14;\n\n if (this._lineHeightCSSVar) {\n const raw = DOM.source.getThemeVar(this._lineHeightCSSVar);\n const parsed = parseFloat(raw);\n\n if (!isNaN(parsed)) {\n return parsed;\n }\n }\n\n return Util.lineHeightPx({ fontSizePx: fs });\n }\n\n /**\n * Returns the DOM element handle.\n *\n * @param createIfMissing - Optional. When true, renders the element if it does not yet exist.\n *\n * @returns The component's element handle.\n */\n getElement(createIfMissing: boolean = false): Handle | undefined {\n return super.getElement(createIfMissing);\n }\n\n /**\n * Resolves the bound font-size var to a px number. A simple var (e.g. the\n * `--ts-ui-font-size` base) parses straight off the document root; a relative\n * font token's var holds a `calc(...)` that `getPropertyValue` returns\n * unevaluated (so `parseFloat` reads `NaN`), so it falls back to a\n * cascade-evaluating probe via `DOM.source.resolveFontSizePx`. The probe path\n * works **pre-attach** — before this component's own element is styled —\n * which is when a parent (e.g. a `Header`) first reads the line-box size.\n *\n * @returns The resolved font size in px, or `null` when no var is bound (an\n * explicit numeric size was set instead) — callers keep the cached number.\n */\n private resolveBoundFontSizePx(): number | null {\n if (!this._fontSizeCSSVar) return null; // explicit px size — no var bound\n\n const raw = parseFloat(DOM.source.getThemeVar(this._fontSizeCSSVar));\n if (!isNaN(raw)) return raw; // simple var — cheap, no probe\n\n return DOM.source.resolveFontSizePx(this._fontSizeCSSRule ?? `var(${this._fontSizeCSSVar})`);\n }\n\n /**\n * Sets the preferred size from an explicit caller, locking it against automatic recalculation.\n *\n * @param size - The preferred size in pixels.\n *\n * @returns This component, for method chaining.\n */\n setPreferredSize(size: Size): this {\n this._hasExplicitPreferredSize = true;\n super.setPreferredSize(size);\n\n return this;\n }\n\n /**\n * Updates the preferred size from a measurement only when no explicit size has been set.\n */\n private setCalculatedSize(width: number, height: number): void {\n if (!this._hasExplicitPreferredSize) {\n super.setPreferredSize({ width: width, height: height });\n }\n }\n\n /**\n * Measures the text using an off-screen probe element and sets the preferred size.\n *\n * @remarks Creates a temporary fixed-positioned invisible `<span>`, appends it to the body\n * to obtain its bounding rect, then removes it. Sets preferred size to (0, 0) when no text is set.\n * No-op when {@link setAutoMeasure} is `false` — the parent layout is expected to size this Text.\n */\n private calculateSize(): void {\n this._measurementDirty = false;\n\n // First-read deferral: populate the default line-height the first\n // time we measure, when the component is attached and\n // `getComputedStyle` is safe. Subsequent reads come through the\n // `ThemeManager.onThemeChange` callback above. Placed before the\n // `_autoMeasure` gate so non-measuring `Text` instances still get\n // a resolved value populated for `getLineHeight()` callers.\n if (this._defaultOptions.lineHeight === undefined) {\n this._defaultOptions.lineHeight = this.readThemeLineHeightPx();\n }\n\n if (!this._autoMeasure) {\n return;\n }\n\n // Floor the reported minimum height to one line so a single-line label\n // is never squeezed below its line box (the measured height is 0 for\n // empty text and unset before the first probe).\n const lineHeightPx = this.getLineHeight() ?? this.readThemeLineHeightPx();\n const minLineHeight = Math.ceil(lineHeightPx);\n\n const text = this._options.text;\n if (text) {\n // Natural (single-line) measurement establishes the preferred WIDTH\n // and the baseline; the height then follows the box's current width,\n // growing when a wrapping run has been laid out narrower than natural.\n const natural = DOM.source.measureText(text.toString(), this.measureOptions());\n const height = this.measuredHeight(text.toString(), natural.width, natural.height);\n\n this._measuredBaseline = natural.baseline;\n this.setCalculatedSize(natural.width, height);\n // Store the measured floor as per-instance derived state (like\n // `_measuredBaseline`), kept out of `_defaultOptions`, which holds\n // the class-level Text defaults rather than per-instance\n // measurements. `getMinSize` folds this into the inherited min.\n // When truncation is disabled, report the full natural width so the\n // parent layout widens to fit instead of squeezing the text;\n // otherwise cap it so the parent can shrink the text past its\n // natural width.\n const autoMinWidth = this._truncate\n ? Math.min(natural.width, TEXT_AUTO_MIN_WIDTH_CAP_PX)\n : natural.width;\n this._measuredMinSize = {\n width: autoMinWidth,\n height: Math.max(height, minLineHeight),\n };\n } else {\n // No glyphs means no baseline — report null so HBox doesn't try\n // to baseline-align surrounding components against an empty box.\n // Reserve no line height either: an empty Text (e.g. the label slot\n // of an icon-only button) must collapse so it doesn't inflate the\n // container and knock the icon off-centre. The one-line floor only\n // applies once there is text to keep on its line.\n this._measuredBaseline = null;\n this.setCalculatedSize(0, 0);\n this._measuredMinSize = { width: 0, height: 0 };\n }\n }\n\n /**\n * Forces a one-off text measurement that ignores {@link setAutoMeasure}.\n * Use when the caller has opted out of auto-measure but needs an up-to-date\n * preferred size after a programmatic text change.\n */\n measure(): void {\n const wasAuto = this._autoMeasure;\n this._autoMeasure = true;\n this.calculateSize();\n this._autoMeasure = wasAuto;\n }\n\n /**\n * Returns the visual baseline of the rendered text, accounting for any\n * border, padding, or framework insets on this component.\n *\n * @returns The baseline offset from the component's outer top, in pixels,\n * or `null` when no text has been measured yet.\n *\n * @remarks Forces a measurement when the cached value is stale — the\n * off-screen probe is deferred from construction so first-call timing\n * shifts to whoever asks for a size first (usually `doLayout`).\n */\n getBaseline(): number | null {\n if (this._measurementDirty) {\n this.calculateSize();\n }\n\n return this.wrapInnerBaseline(this._measuredBaseline);\n }\n\n /**\n * Builds the font/line-height option bag for a {@link DOM.measureText} probe\n * from this Text's resolved styling. Shared by the natural (single-line)\n * measurement and the wrap-aware height re-measurement in\n * {@link measuredHeight}, which adds a `maxWidth`.\n *\n * @returns The measure options (font family/size/weight/style/variant/stretch\n * and line height), each `undefined` when unset so the probe's own default\n * applies.\n */\n private measureOptions() {\n const fontSize = this.getFontSize();\n const lineHeight = this.getLineHeight();\n\n return {\n fontFamily : this.getFontFamily() ?? undefined,\n fontSize : this._fontSizeCSSRule ?? (fontSize !== null ? `${fontSize}px` : undefined),\n fontWeight : this.getFontWeight() ?? undefined,\n fontStyle : this.getFontStyle() ?? undefined,\n fontVariant: this.getFontVariant() ?? undefined,\n fontStretch: this.getFontStretch() ?? undefined,\n lineHeight : this._lineHeightCSSRule ?? (lineHeight !== null ? `${lineHeight}px` : undefined),\n };\n }\n\n /**\n * Whether this Text wraps onto multiple lines — i.e. its `white-space` is a\n * wrapping value rather than `nowrap`/`pre`. Only a wrapping Text's height\n * depends on the width it is given.\n *\n * @returns `true` when the text soft-wraps at its box width.\n */\n private isWrapping(): boolean {\n const ws = this.getWhiteSpace();\n\n return ws === \"normal\" || ws === \"pre-wrap\" || ws === \"pre-line\" || ws === \"break-spaces\";\n }\n\n /**\n * The height the text needs given its current laid-out width.\n *\n * A `nowrap` label — or one not yet given a width, or in a vertical writing\n * mode — is width-independent, so its natural single-line height stands. A\n * wrapping label whose box is narrower than its natural run re-measures at\n * the current inner width (its own border/insets removed): the extra lines\n * make it taller. The re-measure uses the same line-height as the render, so\n * the reported height matches what is drawn — line-height is the per-line\n * unit the whole calculation stacks.\n *\n * @param text - The text run being measured.\n * @param naturalWidth - The natural single-line width (nowrap), the wrap threshold.\n * @param naturalHeight - The natural single-line height, used when it does not wrap.\n * @returns The height (px) at the current width; floored at one line.\n */\n private measuredHeight(text: string, naturalWidth: number, naturalHeight: number): number {\n if (!this.isWrapping() || this.isVerticalWritingMode()) {\n return naturalHeight;\n }\n\n const width = this.getWidth();\n\n if (Number.isNaN(width)) {\n return naturalHeight;\n }\n\n const perimeter = this.getPerimeterSize();\n const innerWidth = width - perimeter.left - perimeter.right;\n\n // Wide enough for the whole run on one line → no wrapping; keep the exact\n // single-line height and skip a redundant probe.\n if (innerWidth >= naturalWidth) {\n return naturalHeight;\n }\n\n const wrapped = DOM.source.measureText(text, { ...this.measureOptions(), maxWidth: innerWidth });\n const minLineHeight = Math.ceil(this.getLineHeight() ?? this.readThemeLineHeightPx());\n\n return Math.max(wrapped.height, minLineHeight);\n }\n\n /**\n * Sets the laid-out width and, for a wrapping Text, re-measures at the new\n * width so its preferred height tracks the number of wrapped lines.\n *\n * A wrapping run's height depends on the width it is given, but the\n * preferred-size protocol resolves heights bottom-up before widths are\n * assigned top-down — so the height is only knowable once the box has a\n * width. Re-measuring here updates the preferred height, and\n * `Component.setPreferredSize` fires the ancestor notify, so the parent\n * re-lays-out one pass later at the taller height (the box's own min height\n * also rises, so the current pass already reserves the room rather than\n * clipping). A `nowrap` label's height is width-independent, so its width\n * changes need no re-measure. Idempotent once the width settles: an\n * unchanged width re-measures to the same height and the notify is suppressed.\n *\n * @param width - The new outer width in pixels.\n * @returns This component, for chaining.\n */\n override setWidth(width: number): this {\n const previous = this.getWidth();\n\n super.setWidth(width);\n\n if (this.isWrapping() && this.getWidth() !== previous) {\n this._measurementDirty = true;\n // Re-measure now (at the new width) so the updated preferred height\n // propagates before the next layout pass reads it.\n this.calculateSize();\n }\n\n return this;\n }\n\n /**\n * Returns the preferred size, lazily measuring the text on the first call.\n *\n * @returns The preferred Size, or `null` per the inherited contract.\n *\n * @remarks Construction no longer eagerly probes `document.body` for text\n * dimensions; the first reader of the preferred size pays the measurement\n * cost. After attach this is `doLayout`, so the probe happens at layout\n * time rather than construction time.\n */\n getPreferredSize() {\n if (this._measurementDirty) {\n this.calculateSize();\n }\n\n const size = super.getPreferredSize();\n\n // `measureTextMetrics` always measures the run horizontally. A vertical\n // writing mode rotates it onto the block axis, so the natural text length\n // becomes the height and the line box becomes the width — swap to report\n // the on-screen extents.\n if (size && this.isVerticalWritingMode()) {\n return { width: size.height, height: size.width };\n }\n\n return size;\n }\n\n /**\n * Whether the active {@link Component.setWritingMode | writing mode} rotates\n * the text run onto the block (vertical) axis, so the measured horizontal\n * extents must be swapped to describe the on-screen size.\n *\n * @returns `true` for a `vertical-*` or `sideways-*` writing mode.\n */\n private isVerticalWritingMode(): boolean {\n const mode = this.getWritingMode();\n\n return mode !== null && (mode.startsWith(\"vertical\") || mode.startsWith(\"sideways\"));\n }\n\n /**\n * Returns the effective minimum size, folding the measured one-line height\n * floor (from `calculateSize`) into the inherited component/layout minimum.\n *\n * @returns The minimum `{width, height}`, never shorter than one line of\n * text, or `null` only when neither a measurement nor an inherited minimum\n * exists.\n *\n * @remarks Only the **height** floor participates in the hard minimum —\n * text cannot render below its line box without clipping. The measured\n * width is deliberately *not* folded in: surfacing each label's natural\n * width as a hard minimum would stop parent layouts (e.g. an equal-mode tab\n * bar) from compressing short labels to fit, which is why `Text.minSize`\n * has historically reported a zero width. The floor is per-instance derived\n * state held in `_measuredMinSize`, not a class default, so it lives outside\n * `_defaultOptions`. An explicit caller `setMinSize` taller than the floor\n * still wins via `Math.max`; a value shorter than one line is lifted to it.\n */\n getMinSize(): Size | null {\n if (this._measurementDirty) {\n this.calculateSize();\n }\n\n const measured = this._measuredMinSize;\n const base = super.getMinSize();\n\n if (!measured) {\n return base;\n }\n\n // Vertical writing mode: the one-line floor guards the line *thickness*,\n // which is now the width rather than the height (the length runs down the\n // block axis and stays freely compressible).\n if (this.isVerticalWritingMode()) {\n if (!base) {\n return { width: measured.height, height: 0 };\n }\n\n return {\n width: Math.max(base.width, measured.height),\n height: base.height,\n };\n }\n\n if (!base) {\n return { width: 0, height: measured.height };\n }\n\n return {\n width: base.width,\n height: Math.max(base.height, measured.height),\n };\n }\n\n /**\n * Returns the current text content, or an empty string if none is set.\n *\n * @returns The current text string, or \"\" if no text is set.\n */\n getText() {\n return this._options.text || \"\";\n }\n\n /**\n * Sets the text content, recalculates the preferred size, and updates the DOM element.\n *\n * @param text - The new text to display.\n *\n * @returns This component, for method chaining.\n */\n setText(text: String): this {\n this._options.text = (text || \"\") as TOptions[\"text\"];\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n let element = this.getElement();\n if (!element) {\n return this;\n }\n\n DOM.sink.apply(element, { text: text.valueOf() });\n\n return this;\n }\n\n /**\n * Enables or disables automatic text measurement on `setText`.\n *\n * @param enabled - When `false`, `setText` skips the off-screen probe and\n * leaves preferred size and baseline unchanged. Use only when\n * the parent layout (e.g. [`Fit`](/api/layout/classes/Fit)) sizes this Text from\n * the container, so the measured preferred size is unused.\n *\n * @returns This component, for method chaining.\n */\n setAutoMeasure(enabled: boolean): this {\n this._autoMeasure = enabled;\n\n return this;\n }\n\n /**\n * Returns the current CSS text-align value.\n *\n * @returns The CSS text-align string, or null if not set.\n */\n getTextAlign() {\n return this._options.textAlign ?? this._defaultOptions.textAlign ?? null;\n }\n\n /**\n * Sets the CSS text-align and updates the component's CSS rule.\n *\n * @param align - A CSS text-align value (e.g. \"left\", \"center\", \"right\").\n *\n * @returns This component, for method chaining.\n */\n setTextAlign(align: string): this {\n this._options.textAlign = align;\n\n this.setElementCSSRule(\"textAlign\", align);\n\n return this;\n }\n\n /**\n * Returns the CSS text-shadow value.\n *\n * @returns The CSS text-shadow string, or null if not set.\n */\n getTextShadow() {\n return this._options.textShadow ?? null;\n }\n\n /**\n * Sets the CSS text-shadow and updates the component's CSS rule.\n *\n * @param shadow - A CSS text-shadow value.\n *\n * @returns This component, for method chaining.\n */\n setTextShadow(shadow: string): this {\n this._options.textShadow = shadow;\n\n this.setElementCSSRule(\"textShadow\", shadow);\n\n return this;\n }\n\n /**\n * Removes the text-shadow CSS property from the component's CSS rule.\n *\n * @returns This component, for method chaining.\n */\n clearTextShadow(): this {\n if (this._options.textShadow === undefined) {\n return this;\n }\n\n this._options.textShadow = undefined;\n this.setElementCSSRule(\"textShadow\", null);\n\n return this;\n }\n\n /**\n * Returns the CSS font-family value.\n *\n * @returns The CSS font-family string, or null if not set.\n */\n getFontFamily() {\n return this._options.fontFamily ?? this._defaultOptions.fontFamily ?? null;\n }\n\n /**\n * Sets the CSS font-family, updates the rule, and recalculates preferred size.\n *\n * @param value - The CSS font-family string (e.g. \"sans-serif\", \"'Arial', sans-serif\").\n *\n * @returns This component, for method chaining.\n */\n setFontFamily(value: string): this {\n this._options.fontFamily = value;\n\n this.setElementCSSRule(\"fontFamily\", value);\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the CSS font-kerning value.\n *\n * @returns The CSS font-kerning string, or null if not set.\n */\n getFontKerning() {\n return this._options.fontKerning ?? this._defaultOptions.fontKerning ?? null;\n }\n\n /**\n * Sets the CSS font-kerning and updates the component's CSS rule.\n *\n * @param value - A CSS font-kerning value (e.g. \"auto\", \"normal\", \"none\").\n *\n * @returns This component, for method chaining.\n */\n setFontKerning(value: string): this {\n this._options.fontKerning = value;\n\n this.setElementCSSRule(\"fontKerning\", value);\n\n return this;\n }\n\n /**\n * Returns the font size in pixels.\n *\n * @returns The font size as a number, or null if not set.\n */\n getFontSize() {\n return (this._options.fontSize as number | undefined) ?? (this._defaultOptions.fontSize as number | undefined) ?? null;\n }\n\n /**\n * Sets the font size. Pass a number for an explicit pixel value, or a CSS variable name\n * (e.g. `\"--ts-ui-header-font-size\"`) to bind to a theme token.\n *\n * @param value - Pixel size as a number, or a CSS custom property name as a string.\n *\n * @returns This component, for method chaining.\n */\n setFontSize(value: number | string): this {\n if (typeof value === 'number') {\n this._options.fontSize = value as TOptions[\"fontSize\"];\n this._fontSizeCSSVar = null;\n this._fontSizeCSSRule = null;\n this.setElementCSSRule(\"fontSize\", value + \"px\");\n } else {\n const fallbackPx = (this.getFontSize() as number | undefined) ?? 14;\n this._fontSizeCSSVar = value;\n this._fontSizeCSSRule = `var(${value}, ${fallbackPx}px)`;\n this.setElementCSSRule(\"fontSize\", this._fontSizeCSSRule);\n\n // Cache the resolved px so line-box/baseline math has the real size\n // even pre-attach — resolveBoundFontSizePx probes the cascade for a\n // calc()-valued token rather than parseFloat-ing its raw var string.\n const resolved = this.resolveBoundFontSizePx();\n if (resolved !== null) {\n this._options.fontSize = resolved as TOptions[\"fontSize\"];\n }\n }\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the CSS font-size-adjust value.\n *\n * @returns The CSS font-size-adjust string, or null if not set.\n */\n getFontSizeAdjust() {\n return this._options.fontSizeAdjust ?? this._defaultOptions.fontSizeAdjust ?? null;\n }\n\n /**\n * Sets the CSS font-size-adjust and updates the component's CSS rule.\n *\n * @param value - A CSS font-size-adjust value.\n *\n * @returns This component, for method chaining.\n */\n setFontSizeAdjust(value: string): this {\n this._options.fontSizeAdjust = value;\n\n this.setElementCSSRule(\"fontSizeAdjust\", value);\n\n return this;\n }\n\n /**\n * Returns the CSS font-stretch value.\n *\n * @returns The CSS font-stretch string, or null if not set.\n */\n getFontStretch() {\n return this._options.fontStretch ?? this._defaultOptions.fontStretch ?? null;\n }\n\n /**\n * Sets the CSS font-stretch and updates the component's CSS rule.\n *\n * @param value - A CSS font-stretch value (e.g. \"normal\", \"condensed\", \"expanded\").\n *\n * @returns This component, for method chaining.\n */\n setFontStretch(value: string): this {\n this._options.fontStretch = value;\n\n this.setElementCSSRule(\"fontStretch\", value);\n\n return this;\n }\n\n /**\n * Returns the CSS font-style value (e.g. \"normal\", \"italic\").\n *\n * @returns The CSS font-style string, or null if not set.\n */\n getFontStyle() {\n return this._options.fontStyle ?? this._defaultOptions.fontStyle ?? null;\n }\n\n /**\n * Sets the CSS font-style and updates the component's CSS rule.\n *\n * @param value - A CSS font-style value (e.g. \"normal\", \"italic\", \"oblique\").\n *\n * @returns This component, for method chaining.\n */\n setFontStyle(value: string): this {\n this._options.fontStyle = value;\n\n this.setElementCSSRule(\"fontStyle\", value);\n\n return this;\n }\n\n /**\n * Returns the CSS font-variant value.\n *\n * @returns The CSS font-variant string, or null if not set.\n */\n getFontVariant() {\n return this._options.fontVariant ?? this._defaultOptions.fontVariant ?? null;\n }\n\n /**\n * Sets the CSS font-variant and updates the component's CSS rule.\n *\n * @param value - A CSS font-variant value (e.g. \"normal\", \"small-caps\").\n *\n * @returns This component, for method chaining.\n */\n setFontVariant(value: string): this {\n this._options.fontVariant = value;\n\n this.setElementCSSRule(\"fontVariant\", value);\n\n return this;\n }\n\n /**\n * Returns the CSS font-weight value.\n *\n * @returns The CSS font-weight string, or null if not set.\n */\n getFontWeight() {\n return this._options.fontWeight ?? this._defaultOptions.fontWeight ?? null;\n }\n\n /**\n * Sets the CSS font-weight, updates the rule, and recalculates preferred size.\n *\n * @param value - A CSS font-weight value (e.g. \"normal\", \"bold\", \"700\").\n *\n * @returns This component, for method chaining.\n */\n setFontWeight(value: string): this {\n this._options.fontWeight = value;\n\n this.setElementCSSRule(\"fontWeight\", value);\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the line height in pixels, or null if not set.\n *\n * @returns The line height as a number, or null if not set.\n */\n getLineHeight() {\n return (this._options.lineHeight as number | undefined) ?? (this._defaultOptions.lineHeight as number | undefined) ?? null;\n }\n\n /**\n * Sets the line height. Pass a number for an explicit fixed pixel value\n * (which stops tracking the theme — this is the per-control override of the\n * additive default), or a CSS variable name to bind the line box to a\n * custom token, resolved as a fixed line box for measurement.\n *\n * @param value - Pixel value as a number, or a CSS custom property name as a string.\n *\n * @returns This component, for method chaining.\n */\n setLineHeight(value: number | string): this {\n if (typeof value === 'number') {\n // Idempotent re-apply: a no-op numeric line-height must not re-arm\n // the layout flush. CellRenderer.doLayout syncs the Text child's\n // line-height to the cell height on every pass; without this guard\n // that unconditional scheduleLayout below re-dirtied the renderer\n // each frame, spinning a silent CPU-pinning relayout loop. Only skip\n // when already in pure-numeric mode with the same value (the initial\n // additive-rule state has a non-null _lineHeightCSSRule, so the first\n // apply still runs). Mirrors the framework's \"unchanged value → early\n // return before scheduleLayout\" idiom (Card.setVisibleComponentId).\n if (this._options.lineHeight === value && this._lineHeightCSSVar === null && this._lineHeightCSSRule === null) {\n return this;\n }\n\n this._options.lineHeight = value as TOptions[\"lineHeight\"];\n this._lineHeightCSSVar = null;\n this._lineHeightCSSRule = null;\n this.setElementCSSRule(\"lineHeight\", value + \"px\");\n } else {\n this._lineHeightCSSVar = value;\n this._lineHeightCSSRule = `var(${value}, ${ADDITIVE_LINE_HEIGHT_RULE})`;\n this._options.lineHeight = this.readThemeLineHeightPx() as TOptions[\"lineHeight\"];\n this.setElementCSSRule(\"lineHeight\", this._lineHeightCSSRule);\n }\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n /**\n * Sets the line-height equal to the given pixel height so a single-line\n * text sits vertically centred in a fixed-height inline box.\n *\n * @param px - Pixel value matching the container's height, or `null` to\n * revert to the theme's additive line box (font size +\n * `--ts-ui-line-padding`).\n *\n * @returns This component, for method chaining.\n *\n * @example\n * ```typescript\n * const label = new Text(\"File\");\n * label.centerInHeight(28);\n * ```\n */\n centerInHeight(px: number | null): this {\n if (px === null) {\n this._lineHeightCSSVar = null;\n this._lineHeightCSSRule = ADDITIVE_LINE_HEIGHT_RULE;\n this._options.lineHeight = this.readThemeLineHeightPx() as TOptions[\"lineHeight\"];\n this.setElementCSSRule(\"lineHeight\", this._lineHeightCSSRule);\n\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n return this.setLineHeight(px);\n }\n\n /**\n * Returns the CSS text-overflow value last passed to {@link setTextOverflow},\n * or `null` if not set.\n *\n * @returns The text-overflow string, or null.\n */\n getTextOverflow(): string | null {\n return this._textOverflow;\n }\n\n /**\n * Sets the CSS text-overflow property and updates the component's CSS rule.\n *\n * @param value - A CSS text-overflow value (e.g. \"clip\", \"ellipsis\").\n *\n * @returns This component, for method chaining.\n */\n setTextOverflow(value: string): this {\n this._textOverflow = value;\n\n this.setElementCSSRule(\"textOverflow\", value);\n\n return this;\n }\n\n /**\n * Removes the text-overflow CSS property from the component's CSS rule.\n *\n * @returns This component, for method chaining.\n */\n clearTextOverflow(): this {\n if (this._textOverflow === null) {\n return this;\n }\n\n this._textOverflow = null;\n this.setElementCSSRule(\"textOverflow\", null);\n\n return this;\n }\n\n /**\n * Returns whether single-line truncation + ellipsis is enabled (default `true`).\n *\n * @returns `true` when the text clips with \"…\" once narrower than its\n * natural width; `false` when the text refuses to shrink past its\n * natural width.\n */\n isTruncate(): boolean {\n return this._truncate;\n }\n\n /**\n * Toggles single-line truncation mode. When `true`, the text renders as\n * single-line + `overflow: hidden` + `text-overflow: ellipsis` and reports\n * `minSize.width = Math.min(natural, 100)`. When `false`, those CSS\n * properties are cleared and the text reports its full natural width as\n * `minSize.width` so parent layouts widen to fit instead of clipping.\n *\n * @param value - `true` to enable ellipsised truncation, `false` to\n * disable (the text expands to its natural width).\n *\n * @returns This component, for method chaining.\n */\n setTruncate(value: boolean): this {\n this._truncate = value;\n\n if (value) {\n this.setWhiteSpace(\"nowrap\");\n this.setOverflow(\"hidden\");\n this.setTextOverflow(\"ellipsis\");\n } else {\n this.setElementCSSRule(\"whiteSpace\", null);\n this.setOverflow(\"visible\");\n this.setElementCSSRule(\"textOverflow\", null);\n this._textOverflow = null;\n }\n\n // The auto-min cap depends on `_truncate`; re-measure so the parent\n // layout sees the new floor on the next layout pass.\n this._measurementDirty = true;\n (this.getParentComponent() ?? this).scheduleLayout();\n\n return this;\n }\n\n /**\n * Returns the current CSS `word-break` value, or null if not set.\n *\n * @returns The word-break string, or null.\n */\n getWordBreak(): string | null {\n return this._wordBreak;\n }\n\n /**\n * Sets the CSS `word-break` property on the component's CSS rule.\n *\n * @param value - A CSS word-break value (e.g. \"break-word\", \"normal\", \"keep-all\").\n *\n * @returns This component, for method chaining.\n */\n setWordBreak(value: string): this {\n if (this._wordBreak === value) {\n return this;\n }\n\n this._wordBreak = value;\n this.setElementCSSRule(\"wordBreak\", value);\n\n return this;\n }\n\n /**\n * Returns the current line-clamp line count, or null if no clamp is applied.\n *\n * @returns The maximum line count, or null.\n */\n getLineClamp(): number | null {\n return this._lineClamp;\n }\n\n /**\n * Clamps the rendered text to a maximum line count via CSS line-clamp.\n *\n * Writes `display: -webkit-box`, `-webkit-box-orient: vertical`,\n * `-webkit-line-clamp`, `overflow: hidden`, and `text-overflow: ellipsis`\n * in a single call. Use {@link clearLineClamp} to remove the clamp.\n *\n * @param lines - The maximum number of lines to display before the ellipsis.\n *\n * @returns This component, for method chaining.\n */\n setLineClamp(lines: number): this {\n if (this._lineClamp === lines) {\n return this;\n }\n\n this._lineClamp = lines;\n this.setElementCSSRules({\n display: \"-webkit-box\",\n webkitBoxOrient: \"vertical\",\n webkitLineClamp: String(lines),\n overflow: \"hidden\",\n textOverflow: \"ellipsis\"\n });\n\n return this;\n }\n\n /**\n * Removes the line-clamp styling previously applied by {@link setLineClamp}.\n *\n * @returns This component, for method chaining.\n */\n clearLineClamp(): this {\n if (this._lineClamp === null) {\n return this;\n }\n\n this._lineClamp = null;\n this.setElementCSSRules({\n display: null,\n webkitBoxOrient: null,\n webkitLineClamp: null,\n overflow: null,\n textOverflow: null\n });\n\n return this;\n }\n\n /**\n * Applies all text-specific style properties to the element's CSS rule in addition to base styles.\n *\n * @param element - The element handle to apply styles to.\n */\n applyStyle(element: Handle): this {\n super.applyStyle(element);\n\n const fontSize = this.getFontSize();\n const lineHeight = this.getLineHeight();\n\n this.setElementCSSRules({\n fontFamily: this.getFontFamily() ?? '',\n textAlign: this.getTextAlign() ?? '',\n textShadow: this.getTextShadow() ?? '',\n fontKerning: this.getFontKerning() ?? '',\n fontSize: this._fontSizeCSSRule ?? (fontSize !== null ? `${fontSize}px` : ''),\n fontSizeAdjust: this.getFontSizeAdjust() ?? '',\n fontStretch: this.getFontStretch() ?? '',\n fontStyle: this.getFontStyle() ?? '',\n fontVariant: this.getFontVariant() ?? '',\n fontWeight: this.getFontWeight() ?? '',\n lineHeight: this._lineHeightCSSRule ?? (lineHeight !== null ? `${lineHeight}px` : '')\n });\n\n return this;\n }\n\n /**\n * Renders the element and sets its text content.\n *\n * @returns The created element with textContent initialised.\n */\n protected render() {\n let element = super.render();\n\n DOM.sink.apply(element, { text: this.getText().valueOf() });\n\n return element;\n }\n}\n\nconst TextCallable = callable(Text);\ntype TextCallable<TOptions extends TextOptions = TextOptions> = Text<TOptions>;\nexport {\n Text as _Text,\n TextCallable as Text\n};\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{a as e,o as t}from"./Position-A39T7-_1.js";import{d as n,f as r}from"./Component-DXf5a3g0.js";import{t as i}from"./BoxLayout-DrKGfsup.js";var VBox=class extends i{_defaultComponentHeight=100;getContentBaseline(){let e=this.getContainer();if(!e)return null;let t=e.getLaidOutComponents();return t.length===0?null:t[0].getBaseline()}getPreferredSize(){let n=this.getContainer();if(!n)return null;let r=n.getPerimeterSize(),i=n.getLaidOutComponents();if(this._mode===`equal`){let e=0,t=0;for(let n in i){let r=i[n].getPreferredSize();r&&(e=Math.max(e,r.width),t=Math.max(t,r.height))}return{width:e+r.left+r.right,height:i.length*(t+this._spacing)-this._spacing+r.top+r.bottom}}let a=e,o=r.top+r.bottom;for(let e in i){let n=i[e].getPreferredSize();n&&(a=t(a)?Math.min(a,n.width):Math.max(a,n.width),o+=n.height)}return a+=r.left+r.right,o+=this._spacing*(i.length-1),{width:a,height:o}}getMinSize(){let e=this.getContainer();if(!e)return null;let t=e.getPerimeterSize(),n=e.getLaidOutComponents();if(this._mode===`equal`){let e=0,r=0;for(let t in n){let i=n[t].getMinSize();i&&(e=Math.max(e,i.width),r=Math.max(r,i.height))}return{width:e+t.left+t.right,height:n.length*(r+this._spacing)-this._spacing+t.top+t.bottom}}let r=0,i=t.top+t.bottom;for(let e in n){let t=n[e].getMinSize();t&&(r=Math.max(r,t.width),i+=t.height)}return r+=t.left+t.right,i+=this._spacing*(n.length-1),{width:r,height:i}}getMaxSize(){return this.aggregateMaxSize(!1)}computeTotalMinSize(){let e=this.getContainer();if(!e)return{width:0,height:0};let t=e.getLaidOutComponents();if(t.length===0)return{width:0,height:0};let n=0;if(this._mode===`equal`){let e=0;for(let r of t){let t=r.getMinSize();t&&(n=Math.max(n,t.width),e=Math.max(e,t.height))}return{width:n,height:t.length*(e+this._spacing)-this._spacing}}let r=this._spacing*(t.length-1);for(let e of t){let t=e.getMinSize();t&&(n=Math.max(n,t.width),r+=t.height)}return{width:n,height:r}}doLayout(){let e=this.getContainer();if(!e)return;let t=e.getInnerSize();if(!t)return;let n=e.getLaidOutComponents(),r=e.getContentInsets(),i=this.getComponentSpacing(),a=this.inflateForOverflow(t);this._mode===`equal`?this.layoutEqualMode(n,t,a,r,i):this.layoutPreferredMode(n,a,r,i),this.reserveContentFrame()}layoutEqualMode(e,t,r,i,a){let o=this.computeEqualCellHeight(e,t.height,a),s=i.getLeft(),c=i.getTop();if(this.isStretching()){let t=r.width;for(let r of e)this.placeComponent(r,s,c,t,o,n.BOTH),c+=o+a;return}let l=i.getLeft(),u=r.width;for(let t of e){let e=t.getPreferredSize(),r=e?e.width:0,i=this.crossPlacement(t,l,u,r,!1);i?this.placeComponent(t,i.offset,c,i.extent,o,n.BOTH):this.placeComponent(t,s,c,r,o,n.BOTH),c+=o+a}}computeEqualCellHeight(e,t,n){let r=0,i=0;for(let t of e){let e=t.getMinSize();e&&(r=Math.max(r,e.height));let n=t.getPreferredSize();n&&(i=Math.max(i,n.height))}let a=(t-n*(e.length-1))/e.length;return a>=r?a:this.isOverflowingY()&&this._overflowSizing===`preferred`?Math.max(r,i):r}layoutPreferredMode(e,t,r,i){let{totalWeight:a,fixedPreferred:o,fixedMin:s}=this.measureFixedHeights(e,i),{remaining:c,shrinkRatio:l}=this.computeShrink(o,s,t.height,this.isOverflowingY()),u=[];for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0,n=t.getPreferredSize(),r=t.getMinSize(),i=t.getMaxSize();u.push(this.resolveChildHeight(n,r,i,e,a,c,l))}let d=0,f=0;if(a===0){let n=i*(e.length-1);for(let e of u)n+=e;let a=t.height-(r.getTop()+r.getBottom());({lead:d,gap:f}=this.justifyOffsets(n,a,e.length))}let p=r.getLeft(),m=t.width-(r.getLeft()+r.getRight()),h=r.getLeft(),g=r.getTop()+d;for(let r=0;r<e.length;r+=1){let a=e[r],o=a.getPreferredSize(),s=a.getMaxSize(),c;c=!o||this.isStretching()?t.width:Math.min(o.width,t.width),s&&(c=Math.min(c,s.width));let l=o?Math.min(o.width,m):m;s&&(l=Math.min(l,s.width));let d=this.crossPlacement(a,p,m,l,!1);d?this.placeComponent(a,d.offset,g,d.extent,u[r],n.BOTH):this.placeComponent(a,h,g,c,u[r],n.BOTH),g+=u[r],g+=i+f}}measureFixedHeights(e,t){let n=0,r=t*(e.length-1),i=t*(e.length-1);for(let t of e){let e=this.getLayoutConstraints(t)?.weight??0;if(e>0)n+=e;else{let e=t.getPreferredSize(),n=t.getMinSize();r+=this.preferredChildHeight(e,n),i+=n?n.height:0}}return{totalWeight:n,fixedPreferred:r,fixedMin:i}}preferredChildHeight(e,t){let n=(e?e.height:void 0)??(t&&t.height>0?t.height:void 0)??this._defaultComponentHeight;return t?Math.max(n,t.height):n}resolveChildHeight(e,t,n,r,i,a,o){let s;if(r>0&&i>0)s=r/i*a;else{let n=this.preferredChildHeight(e,t);s=n-o*(n-(t?t.height:0))}return t&&(s=Math.max(s,t.height)),n&&(s=Math.min(s,n.height)),s}},a=r(VBox);export{a as n,VBox as t};
2
- //# sourceMappingURL=VBox-EIqw85Rh.js.map