@ixfx/components 0.5.18 → 0.5.20

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 (225) hide show
  1. package/bundle/index.d.ts +107 -112
  2. package/bundle/index.d.ts.map +1 -1
  3. package/bundle/index.js +736 -361
  4. package/bundle/index.js.map +1 -1
  5. package/bundle/style.css +4 -2
  6. package/dist/ac-text.d.ts +7 -12
  7. package/dist/ac-text.d.ts.map +1 -1
  8. package/dist/ac-text.js +5 -4
  9. package/dist/ac-text.js.map +1 -1
  10. package/dist/{button-CphdEaZd.js → button-pcDaCemT.js} +2 -2
  11. package/dist/{button-CphdEaZd.js.map → button-pcDaCemT.js.map} +1 -1
  12. package/dist/button.d.ts +2 -1
  13. package/dist/button.d.ts.map +1 -1
  14. package/dist/button.js +1 -1
  15. package/dist/checkbox.d.ts +1 -0
  16. package/dist/checkbox.d.ts.map +1 -1
  17. package/dist/checkbox.js +2 -2
  18. package/dist/checkbox.js.map +1 -1
  19. package/dist/{colour-picker-DbypcEp6.js → colour-picker-D43Q96r0.js} +29 -16
  20. package/dist/colour-picker-D43Q96r0.js.map +1 -0
  21. package/dist/colour-picker.d.ts +1 -1
  22. package/dist/colour-picker.js +1 -1
  23. package/dist/{crumb-navigation-DTwJ8468.js → crumb-navigation-Pif-kupA.js} +125 -27
  24. package/dist/crumb-navigation-Pif-kupA.js.map +1 -0
  25. package/dist/crumbs.d.ts +4 -4
  26. package/dist/crumbs.d.ts.map +1 -1
  27. package/dist/crumbs.js +1 -1
  28. package/dist/data-display.d.ts +2 -1
  29. package/dist/data-display.d.ts.map +1 -1
  30. package/dist/data-display.js +23 -25
  31. package/dist/data-display.js.map +1 -1
  32. package/dist/{decorate-VRK8rslU.js → decorate-DdjvVHS-.js} +2 -2
  33. package/dist/{decorate-VRK8rslU.js.map → decorate-DdjvVHS-.js.map} +1 -1
  34. package/dist/{defaults-DcE8RQJc.js → defaults-BkWCPJFL.js} +7 -1
  35. package/dist/{defaults-DcE8RQJc.js.map → defaults-BkWCPJFL.js.map} +1 -1
  36. package/dist/editable-label.d.ts +2 -1
  37. package/dist/editable-label.d.ts.map +1 -1
  38. package/dist/editable-label.js +2 -2
  39. package/dist/editable-label.js.map +1 -1
  40. package/dist/fallbacks-DEE1nCTt.js +406 -0
  41. package/dist/fallbacks-DEE1nCTt.js.map +1 -0
  42. package/dist/{hex-editor-Bk6rxhfg.js → hex-editor-B-UI4OZu.js} +8 -6
  43. package/dist/{hex-editor-Bk6rxhfg.js.map → hex-editor-B-UI4OZu.js.map} +1 -1
  44. package/dist/{hex-editor-Caq8vNQk.d.ts → hex-editor-CMIxtNgT.d.ts} +3 -2
  45. package/dist/hex-editor-CMIxtNgT.d.ts.map +1 -0
  46. package/dist/hex.d.ts +1 -1
  47. package/dist/hex.js +1 -1
  48. package/dist/highlight-B-eQrhhb.js.map +1 -1
  49. package/dist/{icon-BUwP1CZ1.d.ts → icon-Bd5BiU4b.d.ts} +4 -3
  50. package/dist/icon-Bd5BiU4b.d.ts.map +1 -0
  51. package/dist/{icon-DG9Lm3LT.js → icon-CK14NUcE.js} +5 -7
  52. package/dist/{icon-DG9Lm3LT.js.map → icon-CK14NUcE.js.map} +1 -1
  53. package/dist/icons.d.ts +2 -2
  54. package/dist/icons.js +2 -2
  55. package/dist/{incr-search-2pz21xtR.js → incr-search-CeERfijK.js} +6 -9
  56. package/dist/{incr-search-2pz21xtR.js.map → incr-search-CeERfijK.js.map} +1 -1
  57. package/dist/incr-search.d.ts +1 -1
  58. package/dist/incr-search.js +1 -1
  59. package/dist/{index-D9u_Q7-b.d.ts → index-BslNaMLo.d.ts} +3 -3
  60. package/dist/index-BslNaMLo.d.ts.map +1 -0
  61. package/dist/{index-DkhBGHgF.d.ts → index-Cdmrn0SZ.d.ts} +11 -11
  62. package/dist/index-Cdmrn0SZ.d.ts.map +1 -0
  63. package/dist/{index-BUB5SICW.d.ts → index-CkMIKEWp.d.ts} +4 -3
  64. package/dist/index-CkMIKEWp.d.ts.map +1 -0
  65. package/dist/{index-RqMh1i-O.d.ts → index-D87kRcEs.d.ts} +1 -2
  66. package/dist/index-D87kRcEs.d.ts.map +1 -0
  67. package/dist/{index-BKAlRgbq.d.ts → index-DrKRD8_a.d.ts} +7 -4
  68. package/dist/index-DrKRD8_a.d.ts.map +1 -0
  69. package/dist/{index-BeuCXtiO.d.ts → index-tX6fKF8m.d.ts} +3 -3
  70. package/dist/index-tX6fKF8m.d.ts.map +1 -0
  71. package/dist/index.d.ts +48 -53
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +155 -122
  74. package/dist/index.js.map +1 -1
  75. package/dist/interaction-_Y2qO3QI.js +1 -0
  76. package/dist/{labelled-input-base-hoKGwyKT.js → labelled-input-base-9K_w3oLj.js} +2 -2
  77. package/dist/{labelled-input-base-hoKGwyKT.js.map → labelled-input-base-9K_w3oLj.js.map} +1 -1
  78. package/dist/{labelled-input-base-Dp_9KP0G.d.ts → labelled-input-base-ORb1rGq6.d.ts} +3 -2
  79. package/dist/labelled-input-base-ORb1rGq6.d.ts.map +1 -0
  80. package/dist/labelled-radial-input.d.ts +5 -4
  81. package/dist/labelled-radial-input.d.ts.map +1 -1
  82. package/dist/labelled-radial-input.js +4 -4
  83. package/dist/labelled-radial-input.js.map +1 -1
  84. package/dist/labelled-range-input.d.ts +1 -1
  85. package/dist/labelled-range-input.js +2 -2
  86. package/dist/labelled-range-input.js.map +1 -1
  87. package/dist/led.d.ts +2 -2
  88. package/dist/led.d.ts.map +1 -1
  89. package/dist/led.js +3 -5
  90. package/dist/led.js.map +1 -1
  91. package/dist/{menu-CdwSe_XN.js → menu-BiFarLUA.js} +9 -8
  92. package/dist/{menu-CdwSe_XN.js.map → menu-BiFarLUA.js.map} +1 -1
  93. package/dist/{menu-item-BG5w7fi4.d.ts → menu-item-AtoP6bD4.d.ts} +4 -4
  94. package/dist/menu-item-AtoP6bD4.d.ts.map +1 -0
  95. package/dist/{menu-item-CrmUwIoJ.js → menu-item-yHSPV8nS.js} +10 -9
  96. package/dist/{menu-item-CrmUwIoJ.js.map → menu-item-yHSPV8nS.js.map} +1 -1
  97. package/dist/menu.d.ts +2 -2
  98. package/dist/menu.js +2 -2
  99. package/dist/miller.d.ts +5 -7
  100. package/dist/miller.d.ts.map +1 -1
  101. package/dist/miller.js +26 -24
  102. package/dist/miller.js.map +1 -1
  103. package/dist/narrowed-text.d.ts +2 -1
  104. package/dist/narrowed-text.d.ts.map +1 -1
  105. package/dist/narrowed-text.js +14 -15
  106. package/dist/narrowed-text.js.map +1 -1
  107. package/dist/panel.d.ts +1 -1
  108. package/dist/panel.d.ts.map +1 -1
  109. package/dist/panel.js +3 -3
  110. package/dist/panel.js.map +1 -1
  111. package/dist/plots.d.ts +1 -1
  112. package/dist/plots.js +1 -1
  113. package/dist/polar-pad.d.ts +2 -1
  114. package/dist/polar-pad.d.ts.map +1 -1
  115. package/dist/polar-pad.js +3 -3
  116. package/dist/polar-pad.js.map +1 -1
  117. package/dist/{radial-input-CVxGH-Cp.js → radial-input-C4f-2Bya.js} +15 -25
  118. package/dist/{radial-input-CVxGH-Cp.js.map → radial-input-C4f-2Bya.js.map} +1 -1
  119. package/dist/{radial-input-BhZeyyP-.d.ts → radial-input-Dhu5ZGP5.d.ts} +3 -2
  120. package/dist/radial-input-Dhu5ZGP5.d.ts.map +1 -0
  121. package/dist/radial-input.d.ts +1 -1
  122. package/dist/radial-input.js +1 -1
  123. package/dist/range-input.d.ts +3 -2
  124. package/dist/range-input.d.ts.map +1 -1
  125. package/dist/range-input.js +3 -3
  126. package/dist/range-input.js.map +1 -1
  127. package/dist/range.d.ts +3 -2
  128. package/dist/range.d.ts.map +1 -1
  129. package/dist/range.js +3 -3
  130. package/dist/range.js.map +1 -1
  131. package/dist/selecthorizontal.d.ts +2 -1
  132. package/dist/selecthorizontal.d.ts.map +1 -1
  133. package/dist/selecthorizontal.js +2 -2
  134. package/dist/selecthorizontal.js.map +1 -1
  135. package/dist/{slider-input-TidGhvXt.d.ts → slider-input-BEaztT-g.d.ts} +3 -2
  136. package/dist/slider-input-BEaztT-g.d.ts.map +1 -0
  137. package/dist/{slider-input-CzmSVgm7.js → slider-input-SW7e2Ac2.js} +28 -31
  138. package/dist/{slider-input-CzmSVgm7.js.map → slider-input-SW7e2Ac2.js.map} +1 -1
  139. package/dist/slider-input.d.ts +1 -1
  140. package/dist/slider-input.js +1 -1
  141. package/dist/snap-container.d.ts +2 -1
  142. package/dist/snap-container.d.ts.map +1 -1
  143. package/dist/snap-container.js +5 -6
  144. package/dist/snap-container.js.map +1 -1
  145. package/dist/split-layout.d.ts +9 -2
  146. package/dist/split-layout.d.ts.map +1 -1
  147. package/dist/split-layout.js +88 -20
  148. package/dist/split-layout.js.map +1 -1
  149. package/dist/style.css +4 -2
  150. package/dist/swipe.d.ts +2 -1
  151. package/dist/swipe.d.ts.map +1 -1
  152. package/dist/swipe.js +4 -5
  153. package/dist/swipe.js.map +1 -1
  154. package/dist/{tab-list-CLqlPnX-.d.ts → tab-list-B8v9KntS.d.ts} +12 -5
  155. package/dist/tab-list-B8v9KntS.d.ts.map +1 -0
  156. package/dist/{tab-list-6W5CgXix.js → tab-list-CR0v53KJ.js} +22 -4
  157. package/dist/tab-list-CR0v53KJ.js.map +1 -0
  158. package/dist/tabs.d.ts +1 -1
  159. package/dist/tabs.js +1 -1
  160. package/dist/{tickled-controller-BF2Ea0DE.d.ts → tickled-controller-JDOR9B8V.d.ts} +9 -6
  161. package/dist/tickled-controller-JDOR9B8V.d.ts.map +1 -0
  162. package/dist/{tickled-styles-fNDdqf6l.js → tickled-styles-Bgo_Lpw-.js} +28 -28
  163. package/dist/tickled-styles-Bgo_Lpw-.js.map +1 -0
  164. package/dist/{timeline-B2fgDL4U.js → timeline-CdSI003L.js} +3 -3
  165. package/dist/{timeline-B2fgDL4U.js.map → timeline-CdSI003L.js.map} +1 -1
  166. package/dist/timeline.d.ts +1 -1
  167. package/dist/timeline.js +1 -1
  168. package/dist/{tooltip-BlvBUQxx.d.ts → tooltip-BMTSUPBU.d.ts} +3 -2
  169. package/dist/tooltip-BMTSUPBU.d.ts.map +1 -0
  170. package/dist/{tree-BtiiDX1a.js → tree-CqPhQRHo.js} +11 -10
  171. package/dist/{tree-BtiiDX1a.js.map → tree-CqPhQRHo.js.map} +1 -1
  172. package/dist/{tree-component-DQ9vzdy5.d.ts → tree-component-CDLO1ITF.d.ts} +124 -8
  173. package/dist/tree-component-CDLO1ITF.d.ts.map +1 -0
  174. package/dist/tree.d.ts +4 -9
  175. package/dist/tree.d.ts.map +1 -1
  176. package/dist/tree.js +1 -1
  177. package/dist/types-DSfbtHs3.d.ts +8 -0
  178. package/dist/types-DSfbtHs3.d.ts.map +1 -0
  179. package/dist/{wheel-nudge-DgMTRYlh.d.ts → wheel-nudge-C-ra_1os.d.ts} +2 -1
  180. package/dist/wheel-nudge-C-ra_1os.d.ts.map +1 -0
  181. package/dist/{wheel-nudge-BlSCe_hD.js → wheel-nudge-Dhzi5nHc.js} +2 -2
  182. package/dist/{wheel-nudge-BlSCe_hD.js.map → wheel-nudge-Dhzi5nHc.js.map} +1 -1
  183. package/dist/{xy-axis-CxHC8z5E.js → xy-axis-BpA2eJq6.js} +4 -6
  184. package/dist/{xy-axis-CxHC8z5E.js.map → xy-axis-BpA2eJq6.js.map} +1 -1
  185. package/dist/{xy-axis-5KhVTNoX.d.ts → xy-axis-CtDDQzGZ.d.ts} +6 -8
  186. package/dist/xy-axis-CtDDQzGZ.d.ts.map +1 -0
  187. package/dist/xy-pad.d.ts +2 -1
  188. package/dist/xy-pad.d.ts.map +1 -1
  189. package/dist/xy-pad.js +3 -3
  190. package/dist/xy-pad.js.map +1 -1
  191. package/docs-user/ac-token.md +7 -1
  192. package/docs-user/colour-picker.md +8 -4
  193. package/docs-user/crumbs.md +4 -0
  194. package/docs-user/menu.md +11 -8
  195. package/docs-user/split-layout.md +29 -7
  196. package/package.json +3 -1
  197. package/dist/colour-picker-DbypcEp6.js.map +0 -1
  198. package/dist/crumb-navigation-DTwJ8468.js.map +0 -1
  199. package/dist/fallbacks-DPgPEqo8.js +0 -218
  200. package/dist/fallbacks-DPgPEqo8.js.map +0 -1
  201. package/dist/hex-editor-Caq8vNQk.d.ts.map +0 -1
  202. package/dist/icon-BUwP1CZ1.d.ts.map +0 -1
  203. package/dist/index-BKAlRgbq.d.ts.map +0 -1
  204. package/dist/index-BUB5SICW.d.ts.map +0 -1
  205. package/dist/index-BeuCXtiO.d.ts.map +0 -1
  206. package/dist/index-D9u_Q7-b.d.ts.map +0 -1
  207. package/dist/index-DkhBGHgF.d.ts.map +0 -1
  208. package/dist/index-RqMh1i-O.d.ts.map +0 -1
  209. package/dist/interaction-D6efrBLo.js +0 -1
  210. package/dist/labelled-input-base-Dp_9KP0G.d.ts.map +0 -1
  211. package/dist/menu-item-BG5w7fi4.d.ts.map +0 -1
  212. package/dist/radial-input-BhZeyyP-.d.ts.map +0 -1
  213. package/dist/slider-input-TidGhvXt.d.ts.map +0 -1
  214. package/dist/tab-list-6W5CgXix.js.map +0 -1
  215. package/dist/tab-list-CLqlPnX-.d.ts.map +0 -1
  216. package/dist/tickled-controller-BF2Ea0DE.d.ts.map +0 -1
  217. package/dist/tickled-styles-fNDdqf6l.js.map +0 -1
  218. package/dist/tooltip-BlvBUQxx.d.ts.map +0 -1
  219. package/dist/tree-component-DQ9vzdy5.d.ts.map +0 -1
  220. package/dist/types-DO3gt5vg.d.ts +0 -130
  221. package/dist/types-DO3gt5vg.d.ts.map +0 -1
  222. package/dist/wheel-nudge-DgMTRYlh.d.ts.map +0 -1
  223. package/dist/xy-axis-5KhVTNoX.d.ts.map +0 -1
  224. /package/bundle/{rolldown-runtime-D7D4PA-g.js → chunk-D7D4PA-g.js} +0 -0
  225. /package/dist/{rolldown-runtime-D7D4PA-g.js → chunk-D7D4PA-g.js} +0 -0
package/dist/swipe.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"swipe.js","names":["#removeWindowListeners","#emitInput","#scheduleRetraction","#cancelAnimation","#onWindowPointerUp","#onWindowPointerCancel","#startRetraction","#renderBars","customElement"],"sources":["../src/swipe/swipe.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\n/**\n * <ixfx-swipe> — Touch-friendly swipe/nudge component.\n *\n * User taps and drags to generate a value in range [-1, 1].\n * A drag of full component width = ±1. Value is emitted only on pointerup.\n *\n * Properties\n * barSpacing – center-to-center pixel distance between bars (default 20)\n * barWidth – pixel width of each bar (default 14)\n * debounceMs – ms pause after release before retraction begins (default 200)\n * retractDurationMs – ms for the spring-back animation (default 400)\n * lighttouch – boolean — wheel adjusts the value on hover instead of requiring focus\n *\n * Mouse wheel: up = +0.1, down = -0.1; Shift halves to ±0.05. Each tick fires\n * `input` and triggers the same retraction animation as a drag release. See\n * `docs/infra-mousewheel.md`.\n *\n * CSS custom properties\n * --swipe-color-a – fill for even-indexed bars (default var(--surface-4))\n * --swipe-color-b – fill for odd-indexed bars (default var(--surface-5))\n * --swipe-border-color – border color (default var(--border))\n *\n * Events\n * input – CustomEvent<{ detail: { value: number } }>, bubbles + composed\n */\nimport type { CSSResultGroup } from 'lit';\nimport type { WheelDirection } from '../mixins/wheel-nudge.js';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { WheelNudgeMixin } from '../mixins/wheel-nudge.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { prominenceStyles } from '../styles/prominence.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type SwipeInputDetail = { readonly value: number };\nexport type SwipeInputEvent = CustomEvent<SwipeInputDetail>;\n\nexport interface SwipeElementEventMap {\n input: SwipeInputEvent;\n}\n\nexport interface SwipeElement {\n addEventListener: (<K extends keyof SwipeElementEventMap>(\n type: K,\n listener: (this: SwipeElement, event: SwipeElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-swipe': SwipeElement;\n }\n}\n\n@customElement(`ixfx-swipe`)\nexport class SwipeElement extends WheelNudgeMixin(LitElement) {\n @property({ type: Number }) barSpacing = 20;\n @property({ type: Number }) barWidth = 14;\n @property({ type: Number }) debounceMs = 200;\n @property({ type: Number }) retractDurationMs = 400;\n\n private _startX = 0;\n private _currentX = 0;\n private _pointerId: number | null = null;\n private _componentWidth = 0;\n private _isDragging = false;\n\n private _offset = 0;\n private _width = 0;\n private _height = 0;\n\n private _animRafId: number | null = null;\n private _debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private _animStartOffset = 0;\n private _animStartTime: number | null = null;\n private _resizeObserver: ResizeObserver | null = null;\n\n #onWindowPointerUp = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n\n const rect = this.getBoundingClientRect();\n const inside = e.clientX >= rect.left && e.clientX <= rect.right\n && e.clientY >= rect.top && e.clientY <= rect.bottom;\n\n if (inside) {\n const deltaX = this._currentX - this._startX;\n const value = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this.#emitInput(value);\n }\n\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #onWindowPointerCancel = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #emitInput(value: number): void {\n this.dispatchEvent(\n new CustomEvent<SwipeInputDetail>(`input`, {\n detail: { value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Wheel handler — installed by WheelNudgeMixin on the host. Emits `input`\n * synchronously on each tick (matching the user-confirmed \"mirror drag\"\n * semantic) and schedules the same retraction animation the drag releases\n * with, so the visual resets after a short idle.\n *\n * Step size: 10% of the [-1, 1] value range (= 0.1). Shift halves to 0.05.\n */\n override _applyWheelDelta(direction: WheelDirection, event: WheelEvent): void {\n this.#cancelAnimation();\n const step = event.shiftKey ? 0.05 : 0.1;\n const value = Math.max(-1, Math.min(1, direction * step));\n this.#emitInput(value);\n this._offset = value * this._height * 0.5;\n this.requestUpdate();\n this.#scheduleRetraction();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry)\n return;\n this._width = entry.contentRect.width;\n this._height = entry.contentRect.height;\n this.requestUpdate();\n });\n this._resizeObserver.observe(this);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._resizeObserver?.disconnect();\n this._resizeObserver = null;\n this.#cancelAnimation();\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n }\n\n private _onPointerDown = (e: PointerEvent): void => {\n e.preventDefault();\n this.#cancelAnimation();\n const target = e.target as HTMLElement;\n target.setPointerCapture(e.pointerId);\n this._pointerId = e.pointerId;\n this._startX = e.clientX;\n this._currentX = e.clientX;\n this._componentWidth = this.getBoundingClientRect().width;\n this._isDragging = true;\n window.addEventListener(`pointerup`, this.#onWindowPointerUp);\n window.addEventListener(`pointercancel`, this.#onWindowPointerCancel);\n };\n\n private _onPointerMove = (e: PointerEvent): void => {\n if (!this._isDragging || e.pointerId !== this._pointerId)\n return;\n this._currentX = e.clientX;\n const deltaX = this._currentX - this._startX;\n const ratio = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this._offset = ratio * this._height * 0.5;\n this.requestUpdate();\n };\n\n #removeWindowListeners(): void {\n window.removeEventListener(`pointerup`, this.#onWindowPointerUp);\n window.removeEventListener(`pointercancel`, this.#onWindowPointerCancel);\n }\n\n #scheduleRetraction(): void {\n if (this._debounceTimer !== null)\n clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = null;\n this.#startRetraction();\n }, this.debounceMs);\n }\n\n #startRetraction(): void {\n this._animStartOffset = this._offset;\n this._animStartTime = null;\n\n const animate = (time: number): void => {\n if (this._animStartTime === null)\n this._animStartTime = time;\n const elapsed = time - this._animStartTime;\n const t = Math.min(elapsed / this.retractDurationMs, 1);\n const eased = 1 - (1 - t) ** 3;\n this._offset = this._animStartOffset * (1 - eased);\n this.requestUpdate();\n\n if (t < 1) {\n this._animRafId = requestAnimationFrame(animate);\n } else {\n this._offset = 0;\n this._animRafId = null;\n this.requestUpdate();\n }\n };\n\n this._animRafId = requestAnimationFrame(animate);\n }\n\n #cancelAnimation(): void {\n if (this._animRafId !== null) {\n cancelAnimationFrame(this._animRafId);\n this._animRafId = null;\n }\n if (this._debounceTimer !== null) {\n clearTimeout(this._debounceTimer);\n this._debounceTimer = null;\n }\n }\n\n #renderBars(): ReturnType<typeof svg> {\n const w = this._width;\n const h = this._height;\n const off = this._offset;\n const { barSpacing, barWidth } = this;\n if (w === 0 || h === 0)\n return svg``;\n\n const half = barWidth / 2;\n const mid = h / 2;\n const count = Math.ceil(w / barSpacing) + 1;\n\n return svg`${Array.from({ length: count }, (_, i) => {\n const cx = i * barSpacing;\n const x0 = cx - half;\n const x1 = cx + half;\n const colorVar = i % 2 === 0\n ? `var(--swipe-color-a, var(--surface-4))`\n : `var(--swipe-color-b, var(--surface-5))`;\n const d = `M${x0},0 L${x1},0 L${x1 + off},${mid} L${x1},${h} L${x0},${h} L${x0 + off},${mid}Z`;\n return svg`<path d=${d} style=\"fill:${colorVar}\"></path>`;\n })}`;\n }\n\n static override styles: CSSResultGroup = [themeFallbacks, prominenceStyles, css`\n :host {\n display: block;\n user-select: none;\n touch-action: none;\n width: 100%;\n height: 2.5rem;\n --swipe-border-color: var(--border);\n }\n\n .swipe-area {\n position: relative;\n width: 100%;\n height: 100%;\n cursor: grab;\n border: var(--swipe-border-color);\n overflow: hidden;\n }\n\n .swipe-area:active {\n cursor: grabbing;\n }\n\n svg {\n display: block;\n width: 100%;\n height: 100%;\n }\n `];\n\n override render(): ReturnType<typeof html> {\n return html`\n <div\n class=\"swipe-area\"\n @pointerdown=${this._onPointerDown}\n @pointermove=${this._onPointerMove}\n >\n <svg aria-hidden=\"true\">${this.#renderBars()}</svg>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"swipe.js","names":["#removeWindowListeners","#emitInput","#scheduleRetraction","#cancelAnimation","#onWindowPointerUp","#onWindowPointerCancel","#startRetraction","#renderBars","customElement"],"sources":["../src/swipe/swipe.ts"],"sourcesContent":["/* eslint-disable ts/no-unsafe-declaration-merging */\n/**\n * <ixfx-swipe> — Touch-friendly swipe/nudge component.\n *\n * User taps and drags to generate a value in range [-1, 1].\n * A drag of full component width = ±1. Value is emitted only on pointerup.\n *\n * Properties\n * barSpacing – center-to-center pixel distance between bars (default 20)\n * barWidth – pixel width of each bar (default 14)\n * debounceMs – ms pause after release before retraction begins (default 200)\n * retractDurationMs – ms for the spring-back animation (default 400)\n * lighttouch – boolean — wheel adjusts the value on hover instead of requiring focus\n *\n * Mouse wheel: up = +0.1, down = -0.1; Shift halves to ±0.05. Each tick fires\n * `input` and triggers the same retraction animation as a drag release. See\n * `docs/infra-mousewheel.md`.\n *\n * CSS custom properties\n * --swipe-color-a – fill for even-indexed bars (default var(--surface-4))\n * --swipe-color-b – fill for odd-indexed bars (default var(--surface-5))\n * --swipe-border-color – border color (default var(--border))\n *\n * Events\n * input – CustomEvent<{ detail: { value: number } }>, bubbles + composed\n */\nimport type { CSSResultGroup } from 'lit';\nimport type { WheelDirection } from '../mixins/wheel-nudge.js';\nimport { css, html, LitElement, svg } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { WheelNudgeMixin } from '../mixins/wheel-nudge.js';\nimport { themeFallbacks } from '../styles/fallbacks.js';\nimport { prominenceStyles } from '../styles/prominence.js';\nimport { safeCustomElement as customElement } from '../util/custom-elements.js';\n\nexport type SwipeInputDetail = { readonly value: number };\nexport type SwipeInputEvent = CustomEvent<SwipeInputDetail>;\n\nexport interface SwipeElementEventMap {\n input: SwipeInputEvent;\n}\n\nexport interface SwipeElement {\n addEventListener: (<K extends keyof SwipeElementEventMap>(\n type: K,\n listener: (this: SwipeElement, event: SwipeElementEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ) => void) & ((\n type: string,\n listener: EventListenerOrEventListenerObject,\n options?: boolean | AddEventListenerOptions,\n ) => void);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'ixfx-swipe': SwipeElement;\n }\n}\n\n@customElement(`ixfx-swipe`)\nexport class SwipeElement extends WheelNudgeMixin(LitElement) {\n @property({ type: Number }) barSpacing = 20;\n @property({ type: Number }) barWidth = 14;\n @property({ type: Number }) debounceMs = 200;\n @property({ type: Number }) retractDurationMs = 400;\n\n private _startX = 0;\n private _currentX = 0;\n private _pointerId: number | null = null;\n private _componentWidth = 0;\n private _isDragging = false;\n\n private _offset = 0;\n private _width = 0;\n private _height = 0;\n\n private _animRafId: number | null = null;\n private _debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private _animStartOffset = 0;\n private _animStartTime: number | null = null;\n private _resizeObserver: ResizeObserver | null = null;\n\n #onWindowPointerUp = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n\n const rect = this.getBoundingClientRect();\n const inside = e.clientX >= rect.left && e.clientX <= rect.right\n && e.clientY >= rect.top && e.clientY <= rect.bottom;\n\n if (inside) {\n const deltaX = this._currentX - this._startX;\n const value = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this.#emitInput(value);\n }\n\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #onWindowPointerCancel = (e: PointerEvent): void => {\n if (e.pointerId !== this._pointerId)\n return;\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n this.#scheduleRetraction();\n };\n\n #emitInput(value: number): void {\n this.dispatchEvent(\n new CustomEvent<SwipeInputDetail>(`input`, {\n detail: { value },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /**\n * Wheel handler — installed by WheelNudgeMixin on the host. Emits `input`\n * synchronously on each tick (matching the user-confirmed \"mirror drag\"\n * semantic) and schedules the same retraction animation the drag releases\n * with, so the visual resets after a short idle.\n *\n * Step size: 10% of the [-1, 1] value range (= 0.1). Shift halves to 0.05.\n */\n override _applyWheelDelta(direction: WheelDirection, event: WheelEvent): void {\n this.#cancelAnimation();\n const step = event.shiftKey ? 0.05 : 0.1;\n const value = Math.max(-1, Math.min(1, direction * step));\n this.#emitInput(value);\n this._offset = value * this._height * 0.5;\n this.requestUpdate();\n this.#scheduleRetraction();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry)\n return;\n this._width = entry.contentRect.width;\n this._height = entry.contentRect.height;\n this.requestUpdate();\n });\n this._resizeObserver.observe(this);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._resizeObserver?.disconnect();\n this._resizeObserver = null;\n this.#cancelAnimation();\n this.#removeWindowListeners();\n this._isDragging = false;\n this._pointerId = null;\n }\n\n private _onPointerDown = (e: PointerEvent): void => {\n e.preventDefault();\n this.#cancelAnimation();\n const target = e.target as HTMLElement;\n target.setPointerCapture(e.pointerId);\n this._pointerId = e.pointerId;\n this._startX = e.clientX;\n this._currentX = e.clientX;\n this._componentWidth = this.getBoundingClientRect().width;\n this._isDragging = true;\n window.addEventListener(`pointerup`, this.#onWindowPointerUp);\n window.addEventListener(`pointercancel`, this.#onWindowPointerCancel);\n };\n\n private _onPointerMove = (e: PointerEvent): void => {\n if (!this._isDragging || e.pointerId !== this._pointerId)\n return;\n this._currentX = e.clientX;\n const deltaX = this._currentX - this._startX;\n const ratio = Math.max(-1, Math.min(1, deltaX / this._componentWidth));\n this._offset = ratio * this._height * 0.5;\n this.requestUpdate();\n };\n\n #removeWindowListeners(): void {\n window.removeEventListener(`pointerup`, this.#onWindowPointerUp);\n window.removeEventListener(`pointercancel`, this.#onWindowPointerCancel);\n }\n\n #scheduleRetraction(): void {\n if (this._debounceTimer !== null)\n clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = null;\n this.#startRetraction();\n }, this.debounceMs);\n }\n\n #startRetraction(): void {\n this._animStartOffset = this._offset;\n this._animStartTime = null;\n\n const animate = (time: number): void => {\n if (this._animStartTime === null)\n this._animStartTime = time;\n const elapsed = time - this._animStartTime;\n const t = Math.min(elapsed / this.retractDurationMs, 1);\n const eased = 1 - (1 - t) ** 3;\n this._offset = this._animStartOffset * (1 - eased);\n this.requestUpdate();\n\n if (t < 1) {\n this._animRafId = requestAnimationFrame(animate);\n } else {\n this._offset = 0;\n this._animRafId = null;\n this.requestUpdate();\n }\n };\n\n this._animRafId = requestAnimationFrame(animate);\n }\n\n #cancelAnimation(): void {\n if (this._animRafId !== null) {\n cancelAnimationFrame(this._animRafId);\n this._animRafId = null;\n }\n if (this._debounceTimer !== null) {\n clearTimeout(this._debounceTimer);\n this._debounceTimer = null;\n }\n }\n\n #renderBars(): ReturnType<typeof svg> {\n const w = this._width;\n const h = this._height;\n const off = this._offset;\n const { barSpacing, barWidth } = this;\n if (w === 0 || h === 0)\n return svg``;\n\n const half = barWidth / 2;\n const mid = h / 2;\n const count = Math.ceil(w / barSpacing) + 1;\n\n return svg`${Array.from({ length: count }, (_, i) => {\n const cx = i * barSpacing;\n const x0 = cx - half;\n const x1 = cx + half;\n const colorVar = i % 2 === 0\n ? `var(--swipe-color-a, var(--surface-4))`\n : `var(--swipe-color-b, var(--surface-5))`;\n const d = `M${x0},0 L${x1},0 L${x1 + off},${mid} L${x1},${h} L${x0},${h} L${x0 + off},${mid}Z`;\n return svg`<path d=${d} style=\"fill:${colorVar}\"></path>`;\n })}`;\n }\n\n static override styles: CSSResultGroup = [themeFallbacks, prominenceStyles, css`\n :host {\n display: block;\n user-select: none;\n touch-action: none;\n width: 100%;\n height: 2.5rem;\n --swipe-border-color: var(--border);\n }\n\n .swipe-area {\n position: relative;\n width: 100%;\n height: 100%;\n cursor: grab;\n border: var(--swipe-border-color);\n overflow: hidden;\n }\n\n .swipe-area:active {\n cursor: grabbing;\n }\n\n svg {\n display: block;\n width: 100%;\n height: 100%;\n }\n `];\n\n override render(): ReturnType<typeof html> {\n return html`\n <div\n class=\"swipe-area\"\n @pointerdown=${this._onPointerDown}\n @pointermove=${this._onPointerMove}\n >\n <svg aria-hidden=\"true\">${this.#renderBars()}</svg>\n </div>\n `;\n }\n}\n"],"mappings":"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"}
@@ -1,20 +1,23 @@
1
- import "./icon-BUwP1CZ1.js";
2
1
  import { LitElement, PropertyValues } from "lit";
3
2
  import { CommandRegistry } from "@clinth/ui-commands";
3
+
4
4
  //#region src/tabs/tab-list-item.d.ts
5
5
  /**
6
6
  * CSS vars (can be overridden per-instance):
7
7
  * --selected-colour: text colour when selected
8
8
  * --selected-border-width: border width
9
- * --ixfx-tab-padding: padding for the tab content (default: var(--space-m))
9
+ * --ixfx-tab-padding: vertical padding for the tab content (default: var(--space-m))
10
+ * --ixfx-tab-padding-horizontal: horizontal padding (default: same as --ixfx-tab-padding)
10
11
  */
11
12
  declare class TabListItemElement extends LitElement {
12
13
  closeable: boolean;
14
+ hideLabels: boolean;
13
15
  iconName: string | undefined;
14
16
  description: string | undefined;
15
17
  commandActive: string | undefined;
16
18
  registry: CommandRegistry<unknown> | undefined;
17
19
  private _compact;
20
+ private _hasToolbarContent;
18
21
  private _resizeObserver?;
19
22
  private _commandCleanup?;
20
23
  connectedCallback(): void;
@@ -22,6 +25,9 @@ declare class TabListItemElement extends LitElement {
22
25
  updated(changed: PropertyValues): void;
23
26
  private _syncTooltipAttrs;
24
27
  private _syncCommandListener;
28
+ private _onToolbarSlotChange;
29
+ private _updateToolbarContent;
30
+ firstUpdated(): void;
25
31
  render(): import("lit").TemplateResult<1>;
26
32
  private _onCloseClick;
27
33
  static styles: import("lit").CSSResult[];
@@ -30,7 +36,7 @@ declare global {
30
36
  interface HTMLElementTagNameMap {
31
37
  "ixfx-tab-list-item": TabListItemElement;
32
38
  }
33
- }
39
+ } //# sourceMappingURL=tab-list-item.d.ts.map
34
40
  //#endregion
35
41
  //#region src/tabs/tab-list.d.ts
36
42
  /**
@@ -56,6 +62,7 @@ declare class TabListElement extends LitElement {
56
62
  orientation: `horizontal` | `vertical-stack` | `vertical-side`;
57
63
  flip: boolean;
58
64
  scrollable: boolean;
65
+ hideLabels: boolean;
59
66
  dragMode: TabListDragMode;
60
67
  render(): import("lit").TemplateResult<1>;
61
68
  firstUpdated(): void;
@@ -68,7 +75,7 @@ declare global {
68
75
  interface HTMLElementTagNameMap {
69
76
  "ixfx-tab-list": TabListElement;
70
77
  }
71
- }
78
+ } //# sourceMappingURL=tab-list.d.ts.map
72
79
  //#endregion
73
80
  export { TabListReorderDetail as a, TabListElement as i, TabListChangeEvent as n, TabListReorderEvent as o, TabListDragMode as r, TabListItemElement as s, TabListChangeDetail as t };
74
- //# sourceMappingURL=tab-list-CLqlPnX-.d.ts.map
81
+ //# sourceMappingURL=tab-list-B8v9KntS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-list-B8v9KntS.d.ts","names":[],"sources":["../src/tabs/tab-list-item.ts","../src/tabs/tab-list.ts"],"mappings":";;;;;AAgBA;;;;;;cACa,kBAAA,SAA2B,UAAA;EAEtC,SAAA;EAGA,UAAA;EAGA,QAAA;EAGA,WAAA;EAGA,aAAA;EAGA,QAAA,EAAU,eAAA;EAAA,QAEO,QAAA;EAAA,QACA,kBAAA;EAAA,QACT,eAAA;EAAA,QACA,eAAA;EAEC,iBAAA;EAUA,oBAAA;EAUA,OAAA,CAAQ,OAAA,EAAS,cAAA;EAAA,QAQlB,iBAAA;EAAA,QAUA,oBAAA;EAAA,QAWA,oBAAA;EAAA,QAIA,qBAAA;EAKC,YAAA;EAIA,MAAA,kBAAM,cAAA;EAAA,QA8BP,aAAA;EAAA,OAWQ,MAAA,gBAAM,SAAA;AAAA;AAAA,QA+GhB,MAAA;EAAA,UACI,qBAAA;IACR,oBAAA,EAAsB,kBAAkB;EAAA;AAAA;;;;;AAjP5C;;;KCFY,mBAAA;EAAA,SACD,QAAA;EAAA,SACA,QAAA;EAAA,SACA,GAAA;AAAA;AAAA,KAGC,kBAAA,GAAqB,WAAW,CAAC,mBAAA;AAAA,KAEjC,oBAAA;EAAA,SACD,EAAA;EAAA,SACA,SAAA;EAAA,SACA,OAAA;AAAA;AAAA,KAGC,mBAAA,GAAsB,WAAW,CAAC,oBAAA;AAAA,KAElC,eAAA;AAAA,cAMC,cAAA,SAAuB,UAAA;EAAA;EAElC,WAAA;EAGA,IAAA;EAGA,UAAA;EAGA,UAAA;EAGA,QAAA,EAAU,eAAA;EA2BD,MAAA,kBAAM,cAAA;EA6BN,YAAA;EASA,OAAA,CAAQ,iBAAA,EAAmB,cAAA;EA2GpC,kBAAA,IAAkB,kBAAA;EAwBlB,aAAA,CAAc,EAAA,EAAI,WAAA;EAAA,OAwaX,MAAA,gBAAM,SAAA;AAAA;AAAA,QAoGP,MAAA;EAAA,UACI,qBAAA;IACR,eAAA,EAAiB,cAAc;EAAA;AAAA"}
@@ -1,5 +1,5 @@
1
- import { t as themeFallbacks } from "./fallbacks-DPgPEqo8.js";
2
- import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
1
+ import { t as themeFallbacks } from "./fallbacks-DEE1nCTt.js";
2
+ import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
3
3
  import { LitElement, css, html, nothing } from "lit";
4
4
  import { property } from "lit/decorators.js";
5
5
  //#region src/util/drag-ghost.ts
@@ -93,6 +93,7 @@ let TabListElement = class TabListElement extends LitElement {
93
93
  this.orientation = `horizontal`;
94
94
  this.flip = false;
95
95
  this.scrollable = false;
96
+ this.hideLabels = false;
96
97
  this.dragMode = `off`;
97
98
  this.#items = [];
98
99
  this.#dragState = null;
@@ -101,6 +102,7 @@ let TabListElement = class TabListElement extends LitElement {
101
102
  this.updateComplete.then(() => {
102
103
  this.#items = (this.shadowRoot?.querySelector(`slot`))?.assignedElements({ flatten: true }) ?? [];
103
104
  this.#syncIndicatorColors();
105
+ this.#syncHideLabels();
104
106
  });
105
107
  };
106
108
  this.#onKeyUp = (event) => {
@@ -242,13 +244,21 @@ let TabListElement = class TabListElement extends LitElement {
242
244
  #onSlotChange;
243
245
  firstUpdated() {
244
246
  this.updateComplete.then(() => {
245
- if (this.#items.length > 0) this.#syncIndicatorColors();
247
+ if (this.#items.length > 0) {
248
+ this.#syncIndicatorColors();
249
+ this.#syncHideLabels();
250
+ }
246
251
  });
247
252
  }
248
253
  updated(changedProperties) {
249
254
  super.updated(changedProperties);
250
255
  this.classList.toggle(`scrollable`, this.scrollable);
251
256
  if (changedProperties.has(`dragMode`)) this.toggleAttribute(`drag-mode`, this.dragMode !== `off`);
257
+ if (changedProperties.has(`hideLabels`)) this.#syncHideLabels();
258
+ }
259
+ #syncHideLabels() {
260
+ for (const item of this.#items) if (this.hideLabels) item.setAttribute(`hide-labels`, ``);
261
+ else item.removeAttribute(`hide-labels`);
252
262
  }
253
263
  #syncIndicatorColors() {
254
264
  for (const item of this.#items) {
@@ -503,6 +513,10 @@ let TabListElement = class TabListElement extends LitElement {
503
513
  :host(.scrollable) {
504
514
  max-height: var(--scroll-max-height);
505
515
  }
516
+ :host([hide-labels]) {
517
+ display: inline-flex;
518
+ width: auto;
519
+ }
506
520
  text {
507
521
  user-select:none;
508
522
  }
@@ -586,6 +600,10 @@ let TabListElement = class TabListElement extends LitElement {
586
600
  __decorate([property({ type: String })], TabListElement.prototype, "orientation", void 0);
587
601
  __decorate([property({ type: Boolean })], TabListElement.prototype, "flip", void 0);
588
602
  __decorate([property({ type: Boolean })], TabListElement.prototype, "scrollable", void 0);
603
+ __decorate([property({
604
+ type: Boolean,
605
+ attribute: `hide-labels`
606
+ })], TabListElement.prototype, "hideLabels", void 0);
589
607
  __decorate([property({
590
608
  type: String,
591
609
  attribute: `drag-mode`
@@ -594,4 +612,4 @@ TabListElement = __decorate([safeCustomElement(`ixfx-tab-list`)], TabListElement
594
612
  //#endregion
595
613
  export { TabListElement as t };
596
614
 
597
- //# sourceMappingURL=tab-list-6W5CgXix.js.map
615
+ //# sourceMappingURL=tab-list-CR0v53KJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tab-list-CR0v53KJ.js","names":["#items","#syncIndicatorColors","#syncHideLabels","#isVertical","#selectPrevious","#selectNext","#dragState","#abortDrag","#endDrag","#containerEl","#suppressNextClick","#findDragTarget","#onPointerMove","#onPointerUp","#onPointerCancel","#beginDrag","#computeGapIndex","#commitDrag","#containerClass","#computeCaretStyle","#onKeyUp","#onSlotClick","#onPointerDown","#onKeyDown","#onWheel","#onSlotChange","#isSelected","#createGhost","customElement"],"sources":["../src/util/drag-ghost.ts","../src/tabs/tab-list.ts"],"sourcesContent":["/**\n * Theme-aware floating element helper.\n *\n * Creates a `position: fixed`, `pointer-events: none` element anchored to a\n * source element's theme container, then exposes imperative `move` / `destroy`\n * hooks. Used by `ixfx-tab-list` for its drag-ghost; intended to be reusable\n * by future drag/detach features.\n *\n * Theme container lookup mirrors `tooltip-controller.ts` so the floating\n * element still inherits the right CSS custom properties when the source lives\n * inside a `.theme-dark` / `.theme-light` subtree (used by the loader iframes).\n */\nlet stylesInjected = false;\n\nfunction injectGhostStyles(): void {\n if (stylesInjected)\n return;\n stylesInjected = true;\n const style = document.createElement(`style`);\n style.textContent = `\n .ixfx-drag-ghost {\n position: fixed;\n top: 0;\n left: 0;\n pointer-events: none;\n z-index: 10000;\n will-change: transform;\n opacity: 0.9;\n display: inline-flex;\n align-items: center;\n gap: var(--space-xs, 4px);\n padding: var(--padding, var(--space-m, 8px)) calc(2 * var(--padding, var(--space-m, 8px)));\n background: var(--surface-4);\n color: var(--surface-4-text);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-m, 6px);\n font-family: inherit;\n font-size: inherit;\n font-weight: 500;\n white-space: nowrap;\n max-width: 240px;\n overflow: hidden;\n text-overflow: ellipsis;\n box-shadow: var(--shadow-m);\n }\n .ixfx-drag-ghost ixfx-icon {\n flex-shrink: 0;\n }\n `;\n document.head.appendChild(style);\n}\n\nexport interface DragGhost {\n /** Position the ghost at (x, y) viewport coords, anchored around the source center. */\n move: (x: number, y: number) => void;\n /** Remove the ghost from the DOM. Idempotent. */\n destroy: () => void;\n /** The underlying ghost element (rarely needed outside this module). */\n readonly element: HTMLElement;\n}\n\nexport interface CreateDragGhostOptions {\n /** Content element to mount inside the ghost. Will be appended on create. */\n content: HTMLElement;\n /**\n * Anchor element — used to find the theme container and to compute the\n * initial offset so the ghost appears centered under the source on first move.\n */\n anchor: HTMLElement;\n /** Optional class name appended to the ghost wrapper for custom styling. */\n className?: string;\n}\n\n/**\n * Create a theme-aware floating ghost element.\n *\n * The ghost is appended to the closest `.theme-dark` / `.theme-light` ancestor\n * of `anchor`, falling back to `document.body`. This preserves CSS variable\n * inheritance for theming.\n */\nexport function createDragGhost(opts: CreateDragGhostOptions): DragGhost {\n injectGhostStyles();\n\n const ghost = document.createElement(`div`);\n ghost.className = `ixfx-drag-ghost`;\n if (opts.className)\n ghost.classList.add(opts.className);\n ghost.appendChild(opts.content);\n\n // Place ghost off-screen until first `move()` call\n ghost.style.transform = `translate3d(-9999px, -9999px, 0)`;\n\n const targetDoc = opts.anchor.ownerDocument;\n const themeContainer = opts.anchor.closest(`.theme-dark, .theme-light`);\n if (themeContainer) {\n themeContainer.appendChild(ghost);\n } else {\n targetDoc.body.appendChild(ghost);\n }\n\n // Anchor offset: distance from the source's top-left to its center.\n const anchorRect = opts.anchor.getBoundingClientRect();\n const offsetX = anchorRect.width / 2;\n const offsetY = anchorRect.height / 2;\n\n return {\n element: ghost,\n move(x: number, y: number): void {\n ghost.style.transform = `translate3d(${x - offsetX}px, ${y - offsetY}px, 0)`;\n },\n destroy(): void {\n ghost.remove();\n },\n };\n}\n","import type { PropertyValues } from \"lit\";\nimport type { DragGhost } from \"../util/drag-ghost.js\";\nimport type { TabListItemElement } from \"./tab-list-item.js\";\nimport { css, html, LitElement, nothing } from \"lit\";\nimport { property } from \"lit/decorators.js\";\nimport { themeFallbacks } from \"../styles/fallbacks.js\";\nimport { safeCustomElement as customElement } from \"../util/custom-elements.js\";\nimport { createDragGhost } from \"../util/drag-ghost.js\";\n\n/**\n * Events\n * 'change' - new tab selected { previous:string, selected:string, for:string }\n * 'reorder' - tab moved within the list { id:string, fromIndex:number, toIndex:number }\n */\nexport type TabListChangeDetail = {\n readonly previous: string | undefined;\n readonly selected: string;\n readonly for: string;\n};\n\nexport type TabListChangeEvent = CustomEvent<TabListChangeDetail>;\n\nexport type TabListReorderDetail = {\n readonly id: string;\n readonly fromIndex: number;\n readonly toIndex: number;\n};\n\nexport type TabListReorderEvent = CustomEvent<TabListReorderDetail>;\n\nexport type TabListDragMode = `off` | `reorder`;\n\n/** Pointer movement threshold (px) before a press becomes a drag. */\nconst DRAG_THRESHOLD_PX = 5;\n\n@customElement(`ixfx-tab-list`)\nexport class TabListElement extends LitElement {\n @property({ type: String })\n orientation: `horizontal` | `vertical-stack` | `vertical-side` = `horizontal`;\n\n @property({ type: Boolean })\n flip = false;\n\n @property({ type: Boolean })\n scrollable = false;\n\n @property({ type: Boolean, attribute: `hide-labels` })\n hideLabels = false;\n\n @property({ type: String, attribute: `drag-mode` })\n dragMode: TabListDragMode = `off`;\n\n #items: TabListItemElement[] = [];\n\n // ── Drag state (not reactive) ────────────────────────────────────────\n #dragState: {\n pointerId: number;\n source: TabListItemElement;\n fromIndex: number;\n startX: number;\n startY: number;\n active: boolean;\n ghost: DragGhost | null;\n gapIndex: number | undefined;\n } | null = null;\n\n #suppressNextClick = false;\n\n get #isVertical(): boolean {\n return this.orientation === `vertical-stack` || this.orientation === `vertical-side`;\n }\n\n get #containerClass(): string {\n const base = this.scrollable ? `${this.orientation} scrollable` : this.orientation;\n return this.dragMode === `reorder` ? `${base} reorder` : base;\n }\n\n override render() {\n const caretStyle = this.#computeCaretStyle();\n return html`\n <div\n tabindex=0\n @keyup=${this.#onKeyUp}\n @click=${this.#onSlotClick}\n @pointerdown=${this.#onPointerDown}\n @keydown=${this.#onKeyDown}\n @wheel=${this.#onWheel}\n id=\"container\"\n class=${this.#containerClass}\n >\n <slot @slotchange=${this.#onSlotChange}></slot>\n ${caretStyle\n ? html`<div class=\"drop-caret\" style=${caretStyle}></div>`\n : nothing}\n </div>`;\n }\n\n #onSlotChange = () => {\n this.updateComplete.then(() => {\n this.#items = (this.shadowRoot?.querySelector(`slot`) as HTMLSlotElement)\n ?.assignedElements({ flatten: true }) as TabListItemElement[] ?? [];\n this.#syncIndicatorColors();\n this.#syncHideLabels();\n });\n };\n\n override firstUpdated() {\n this.updateComplete.then(() => {\n if (this.#items.length > 0) {\n this.#syncIndicatorColors();\n this.#syncHideLabels();\n }\n });\n }\n\n override updated(changedProperties: PropertyValues): void {\n super.updated(changedProperties);\n this.classList.toggle(`scrollable`, this.scrollable);\n if (changedProperties.has(`dragMode`)) {\n this.toggleAttribute(`drag-mode`, this.dragMode !== `off`);\n }\n if (changedProperties.has(`hideLabels`)) {\n this.#syncHideLabels();\n }\n }\n\n #syncHideLabels() {\n for (const item of this.#items) {\n if (this.hideLabels) {\n item.setAttribute(`hide-labels`, ``);\n } else {\n item.removeAttribute(`hide-labels`);\n }\n }\n }\n\n #syncIndicatorColors() {\n for (const item of this.#items) {\n item.style.setProperty(`--indicator-color-bottom`, `transparent`);\n item.style.setProperty(`--indicator-color-top`, `transparent`);\n item.style.setProperty(`--indicator-color-left`, `transparent`);\n item.style.setProperty(`--indicator-color-right`, `transparent`);\n\n if (item.hasAttribute(`selected`)) {\n if (this.orientation === `horizontal` && !this.flip) {\n item.style.setProperty(`--indicator-color-bottom`, `var(--accent)`);\n } else if (this.orientation === `horizontal` && this.flip) {\n item.style.setProperty(`--indicator-color-top`, `var(--accent)`);\n } else if (this.#isVertical && !this.flip) {\n item.style.setProperty(`--indicator-color-right`, `var(--accent)`);\n } else if (this.#isVertical && this.flip) {\n item.style.setProperty(`--indicator-color-left`, `var(--accent)`);\n }\n }\n }\n }\n\n #onKeyUp = (event: KeyboardEvent) => {\n const key = event.key;\n if (this.#isVertical) {\n if (key === `ArrowUp`) {\n this.#selectPrevious();\n } else if (key === `ArrowDown`) {\n this.#selectNext();\n }\n } else {\n if (key === `ArrowRight`) {\n this.#selectNext();\n } else if (key === `ArrowLeft`) {\n this.#selectPrevious();\n }\n }\n };\n\n // Escape during drag aborts it (and tears down listeners / releases capture)\n #onKeyDown = (event: KeyboardEvent): void => {\n const state = this.#dragState;\n if (event.key !== `Escape` || !state?.active)\n return;\n event.preventDefault();\n const pointerId = state.pointerId;\n this.#abortDrag();\n this.#endDrag(pointerId);\n };\n\n /**\n * Translate vertical wheel deltas into horizontal scroll on a scrollable\n * horizontal list (and vice-versa for vertical lists). Without this, the\n * default browser behaviour only scrolls horizontally with Shift+wheel or a\n * physical horizontal wheel — neither of which most users reach for on a\n * VS Code-style tab strip.\n *\n * Only kicks in when the list is actually scrollable (overflow content\n * present), and is a no-op when nothing is scrollable in that direction.\n */\n #onWheel = (event: WheelEvent): void => {\n if (!this.scrollable)\n return;\n const el = this.#containerEl;\n if (!el)\n return;\n\n if (!this.#isVertical) {\n // Horizontal list: vertical wheel → horizontal scroll.\n if (event.deltaY === 0 || el.scrollWidth <= el.clientWidth)\n return;\n const prev = el.scrollLeft;\n el.scrollLeft = prev + event.deltaY;\n if (el.scrollLeft !== prev)\n event.preventDefault();\n } else {\n // Vertical list: vertical wheel is already native; only intervene when\n // a horizontal wheel is supplied (e.g. trackpad two-finger horizontal).\n if (event.deltaX === 0 || el.scrollHeight <= el.clientHeight)\n return;\n const prev = el.scrollTop;\n el.scrollTop = prev + event.deltaX;\n if (el.scrollTop !== prev)\n event.preventDefault();\n }\n };\n\n getSelectedElement() {\n for (const el of this.#items) {\n if (this.#isSelected(el))\n return el;\n }\n // Fallback: #items may not be populated yet (slotchange hasn't fired).\n // Query the slot directly to find the selected element.\n const slot = this.shadowRoot?.querySelector(`slot`);\n if (slot) {\n const els = (slot as HTMLSlotElement).assignedElements({ flatten: true });\n for (const el of els) {\n if (this.#isSelected(el as HTMLElement))\n return el as TabListItemElement;\n }\n }\n }\n\n #isSelected(el: HTMLElement) {\n const v = el.getAttribute(`selected`);\n if (v === null)\n return false;\n return (el.hasAttribute(`selected`));\n }\n\n selectElement(el: HTMLElement) {\n const existing = this.getSelectedElement();\n if (existing) {\n existing.removeAttribute(`selected`);\n existing.style.setProperty(`--indicator-color-bottom`, `transparent`);\n existing.style.setProperty(`--indicator-color-top`, `transparent`);\n existing.style.setProperty(`--indicator-color-left`, `transparent`);\n existing.style.setProperty(`--indicator-color-right`, `transparent`);\n }\n\n el.setAttribute(`selected`, ``);\n\n if (this.orientation === `horizontal` && !this.flip) {\n el.style.setProperty(`--indicator-color-bottom`, `var(--accent)`);\n } else if (this.orientation === `horizontal` && this.flip) {\n el.style.setProperty(`--indicator-color-top`, `var(--accent)`);\n } else if (this.#isVertical && !this.flip) {\n el.style.setProperty(`--indicator-color-right`, `var(--accent)`);\n } else if (this.#isVertical && this.flip) {\n el.style.setProperty(`--indicator-color-left`, `var(--accent)`);\n }\n }\n\n #selectNext() {\n let found = false;\n for (const el of this.#items) {\n if (this.#isSelected(el) && !found) {\n found = true;\n } else if (found) {\n this.selectElement(el);\n break;\n }\n }\n }\n\n #selectPrevious() {\n let prev: HTMLElement | undefined;\n for (const el of this.#items) {\n if (this.#isSelected(el) && prev) {\n this.selectElement(prev);\n } else {\n prev = el;\n }\n }\n }\n\n #onSlotClick = (event: MouseEvent) => {\n if (this.#suppressNextClick) {\n this.#suppressNextClick = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n this.focus();\n const t = (event.target as HTMLElement).closest(`ixfx-tab-list-item`);\n if (!t)\n return;\n const previous = this.getSelectedElement();\n this.selectElement(t);\n\n const forId = t.getAttribute(`for`);\n const previousId = previous?.id;\n this.dispatchEvent(new CustomEvent<TabListChangeDetail>(`change`, {\n bubbles: true,\n detail: {\n previous: previousId,\n selected: t.id,\n for: forId ?? ``,\n },\n }));\n };\n\n // ── Drag handling ────────────────────────────────────────────────────\n\n /**\n * Walk composedPath looking for the nearest ancestor tab-list-item, but bail\n * if the path goes through a `.close-btn` or `.toolbar` (so close/toolbar\n * buttons always win — same delegation pattern used by tooltip-controller).\n */\n #findDragTarget(event: PointerEvent): TabListItemElement | null {\n if (this.dragMode === `off`)\n return null;\n\n const path = event.composedPath();\n let item: TabListItemElement | null = null;\n for (const node of path) {\n if (!(node instanceof HTMLElement))\n continue;\n if (node.classList.contains(`close-btn`) || node.classList.contains(`toolbar`)) {\n return null;\n }\n if (!item && node.tagName === `IXFX-TAB-LIST-ITEM`) {\n item = node as TabListItemElement;\n }\n }\n return item;\n }\n\n #onPointerDown = (event: PointerEvent): void => {\n if (this.dragMode !== `reorder`)\n return;\n if (event.button !== 0)\n return;\n const target = this.#findDragTarget(event);\n if (!target)\n return;\n\n const fromIndex = this.#items.indexOf(target);\n if (fromIndex < 0)\n return;\n\n // Don't capture the pointer yet — doing so on pointerdown would redirect\n // the trailing click event to the capture target (the container), so the\n // click handler would see a container DIV as its target instead of the\n // tab-list-item and `closest('ixfx-tab-list-item')` would return null.\n // We capture only once the drag actually activates (#beginDrag). Until\n // then, an ordinary press still produces a normal click on the tab.\n\n this.#dragState = {\n pointerId: event.pointerId,\n source: target,\n fromIndex,\n startX: event.clientX,\n startY: event.clientY,\n active: false,\n ghost: null,\n gapIndex: undefined,\n };\n\n // Listen at window level for move/up so we don't lose events if the\n // pointer exits the host before pointerup fires.\n window.addEventListener(`pointermove`, this.#onPointerMove);\n window.addEventListener(`pointerup`, this.#onPointerUp);\n window.addEventListener(`pointercancel`, this.#onPointerCancel);\n };\n\n #onPointerMove = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n\n const dx = event.clientX - state.startX;\n const dy = event.clientY - state.startY;\n const distance = Math.hypot(dx, dy);\n\n if (!state.active) {\n if (distance < DRAG_THRESHOLD_PX)\n return;\n this.#beginDrag(event);\n }\n\n state.ghost?.move(event.clientX, event.clientY);\n\n const gap = this.#computeGapIndex(event.clientX, event.clientY);\n if (gap !== state.gapIndex) {\n state.gapIndex = gap;\n this.requestUpdate();\n }\n };\n\n #onPointerUp = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n\n if (state.active) {\n const gap = this.#computeGapIndex(event.clientX, event.clientY);\n this.#commitDrag(state.source, state.fromIndex, gap);\n }\n this.#endDrag(event.pointerId);\n };\n\n #onPointerCancel = (event: PointerEvent): void => {\n const state = this.#dragState;\n if (!state || event.pointerId !== state.pointerId)\n return;\n this.#abortDrag();\n this.#endDrag(event.pointerId);\n };\n\n #beginDrag(event: PointerEvent): void {\n const state = this.#dragState;\n if (!state || state.active)\n return;\n\n // Now that we know we're dragging, capture the pointer so pointermove/up\n // events keep flowing even if the pointer leaves the host element.\n try {\n this.#containerEl?.setPointerCapture(event.pointerId);\n } catch {\n // setPointerCapture can throw if pointer is already captured elsewhere;\n // fall through — window listeners still catch move/up.\n }\n\n state.active = true;\n state.source.setAttribute(`drag-source`, ``);\n\n state.ghost = this.#createGhost(state.source);\n if (state.ghost) {\n state.ghost.move(event.clientX, event.clientY);\n }\n }\n\n #abortDrag(): void {\n const state = this.#dragState;\n if (!state)\n return;\n state.source.removeAttribute(`drag-source`);\n if (state.gapIndex !== undefined) {\n state.gapIndex = undefined;\n this.requestUpdate();\n }\n // Caller is responsible for invoking #endDrag to release pointer capture,\n // tear down listeners, and destroy the ghost.\n }\n\n #endDrag(pointerId: number): void {\n const state = this.#dragState;\n if (!state)\n return;\n\n state.ghost?.destroy();\n state.ghost = null;\n this.#dragState = null;\n\n window.removeEventListener(`pointermove`, this.#onPointerMove);\n window.removeEventListener(`pointerup`, this.#onPointerUp);\n window.removeEventListener(`pointercancel`, this.#onPointerCancel);\n\n try {\n this.#containerEl?.releasePointerCapture(pointerId);\n } catch { /* already released */ }\n\n // #dragState is a private field, not a Lit-reactive property — setting it\n // to null doesn't trigger a re-render on its own. Without this, the caret\n // (and any other drag-time UI) would remain in the DOM after the drag\n // ends, even though the next render would clear them.\n this.requestUpdate();\n }\n\n #commitDrag(source: TabListItemElement, fromIndex: number, gapIndex: number | undefined): void {\n source.removeAttribute(`drag-source`);\n\n // gapIndex is an index into the without-source siblings array: 0 = before\n // the first sibling, siblings.length = after the last. The siblings array\n // already excludes source, so we can insert directly at that position\n // using siblings[gapIndex] as the reference (or null to append).\n const siblings = this.#items.filter(el => el !== source);\n const target = gapIndex === undefined\n ? siblings.length\n : Math.max(0, Math.min(gapIndex, siblings.length));\n\n const parent = source.parentNode;\n if (!parent)\n return;\n\n const ref = siblings[target] ?? null;\n parent.insertBefore(source, ref);\n\n const toIndex = Array.prototype.indexOf.call(parent.children, source);\n if (toIndex === fromIndex) {\n // Dropped in the same gap the item already occupies — no reorder, and no\n // click suppression (a real click on the same tab is still meaningful).\n return;\n }\n\n // Refresh cached #items so subsequent drags / queries see the new order\n // (slotchange does NOT fire on reorder, only on add/remove).\n this.#items = (this.shadowRoot?.querySelector(`slot`) as HTMLSlotElement)\n ?.assignedElements({ flatten: true }) as TabListItemElement[] ?? [];\n this.#syncIndicatorColors();\n\n // A real reorder just happened. The trailing click event (which the\n // browser still fires after pointerup) would re-select whatever is under\n // the release point — not what the user wanted. Suppress it.\n this.#suppressNextClick = true;\n\n this.dispatchEvent(new CustomEvent<TabListReorderDetail>(`reorder`, {\n bubbles: true,\n detail: {\n id: source.id,\n fromIndex,\n toIndex,\n },\n }));\n }\n\n #createGhost(source: TabListItemElement): DragGhost | null {\n const content = document.createElement(`span`);\n content.style.display = `inline-flex`;\n content.style.alignItems = `center`;\n content.style.gap = `var(--space-xs, 4px)`;\n content.style.minWidth = `0`;\n\n const iconName = source.iconName;\n if (iconName) {\n const icon = document.createElement(`ixfx-icon`) as HTMLElement & { name: string };\n icon.name = iconName;\n content.appendChild(icon);\n }\n\n // Reconstruct label text from light-DOM children that aren't slotted.\n // We want the text content of the source item, excluding `slot=\"toolbar\"`\n // descendants (the close button lives inside the item's shadow DOM, not\n // its light DOM, so it isn't part of childNodes here).\n const label = document.createElement(`span`);\n label.textContent = (source.textContent ?? ``).trim();\n label.style.overflow = `hidden`;\n label.style.textOverflow = `ellipsis`;\n label.style.whiteSpace = `nowrap`;\n content.appendChild(label);\n\n try {\n return createDragGhost({ anchor: source, content });\n } catch {\n return null;\n }\n }\n\n /**\n * Compute the index of the gap nearest the pointer, ignoring the source item.\n * Returns 0..#items.length-1; undefined if no siblings.\n *\n * Per the plan: drag-mode=\"reorder\" has \"no sense of breaking out\", so the\n * perpendicular axis is ignored — the pointer always resolves to some gap.\n */\n #computeGapIndex(clientX: number, clientY: number): number | undefined {\n const state = this.#dragState;\n if (!state)\n return undefined;\n const siblings = this.#items.filter(el => el !== state.source);\n if (siblings.length === 0)\n return 0;\n\n const useX = !this.#isVertical;\n\n let bestGap = 0;\n let bestDist = Infinity;\n\n // For each sibling, decide: gap is \"before this sibling\" or \"after\" based\n // on which side of the midpoint the pointer is on. Pick the gap whose\n // position (the midpoint if \"before\", the edge if \"after\") is closest to\n // the pointer on the relevant axis.\n for (let i = 0; i < siblings.length; i++) {\n const rect = siblings[i].getBoundingClientRect();\n const start = useX ? rect.left : rect.top;\n const end = useX ? rect.right : rect.bottom;\n const mid = (start + end) / 2;\n const pos = useX ? clientX : clientY;\n\n // Two candidate gaps: before this sibling (at `start`) and after (at `end`).\n // \"Before\" gap index = i; \"after\" gap index = i + 1.\n const dStart = Math.abs(pos - start);\n const dMid = Math.abs(pos - mid);\n const dEnd = Math.abs(pos - end);\n\n // Heuristic: if pointer is left/above midpoint, prefer the \"before\" gap;\n // otherwise prefer the \"after\" gap. Within those, the closer edge wins.\n const preferBefore = pos < mid;\n if (preferBefore) {\n // Gap i (before this sibling)\n if (dStart < bestDist) {\n bestDist = dStart;\n bestGap = i;\n }\n } else {\n // Gap i+1 (after this sibling)\n if (dEnd < bestDist) {\n bestDist = dEnd;\n bestGap = i + 1;\n }\n }\n // The midpoint-distance is mostly redundant with the above but handles\n // ties near the boundary cleanly — no-op for the chosen gap.\n void dMid;\n }\n\n return bestGap;\n }\n\n #computeCaretStyle(): string | undefined {\n const state = this.#dragState;\n if (!state?.active || state.gapIndex === undefined)\n return undefined;\n\n const siblings = this.#items.filter(el => el !== state.source);\n if (siblings.length === 0)\n return undefined;\n\n const useX = !this.#isVertical;\n const containerRect = this.#containerEl?.getBoundingClientRect();\n if (!containerRect)\n return undefined;\n\n const gap = Math.max(0, Math.min(state.gapIndex, siblings.length));\n let rect: DOMRect | null = null;\n if (gap < siblings.length) {\n rect = siblings[gap].getBoundingClientRect();\n } else {\n // After the last sibling: use its trailing edge\n const last = siblings[siblings.length - 1].getBoundingClientRect();\n rect = last;\n }\n\n if (useX) {\n const x = (gap < siblings.length ? rect.left : rect.right) - containerRect.left;\n const y = 0;\n const h = containerRect.height;\n const w = 2;\n return `transform: translate(${x - w / 2}px, ${y}px); width: ${w}px; height: ${h}px;`;\n } else {\n const y = (gap < siblings.length ? rect.top : rect.bottom) - containerRect.top;\n const x = 0;\n const w = containerRect.width;\n const h = 2;\n return `transform: translate(${x}px, ${y - h / 2}px); width: ${w}px; height: ${h}px;`;\n }\n }\n\n get #containerEl(): HTMLElement | null {\n return this.shadowRoot?.getElementById(`container`) ?? null;\n }\n\n static styles = [themeFallbacks, css`\n :host {\n display: inline-block;\n --activated-colour: var(--accent);\n --colour: var(--surface-3-text);\n --scroll-max-height: 200px;\n --allow-overflow: hidden;\n color: var(--colour);\n border: var(--border, none);\n border-color: var(--surface-5);\n border-radius: var(--radius-l, 8px) var(--radius-l, 8px) 0 0;\n\n }\n :host(.scrollable) {\n max-height: var(--scroll-max-height);\n }\n :host([hide-labels]) {\n display: inline-flex;\n width: auto;\n }\n text {\n user-select:none;\n }\n #container {\n display:flex;\n position: relative;\n }\n #container.horizontal {\n flex-direction: row;\n overflow: hidden;\n }\n #container.horizontal.scrollable {\n overflow-x: auto;\n --allow-overflow: visible;\n }\n #container.horizontal.scrollable ::slotted(ixfx-tab-list-item) {\n flex-shrink: 0;\n }\n #container.vertical-stack {\n flex-direction: column;\n }\n #container.vertical-stack.flip {\n flex-direction: column-reverse;\n }\n #container.vertical-stack.scrollable {\n overflow-y: auto;\n max-height: var(--scroll-max-height);\n --allow-overflow: visible;\n }\n #container.vertical-side {\n flex-direction: column;\n }\n #container.vertical-side.flip {\n flex-direction: column-reverse;\n }\n #container.vertical-side.scrollable {\n overflow-y: auto;\n max-height: var(--scroll-max-height);\n --allow-overflow: visible;\n }\n\n ::slotted(ixfx-tab-list-item) {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n #container.vertical-side ::slotted(ixfx-tab-list-item) {\n writing-mode: vertical-lr;\n text-orientation: mixed;\n }\n #container.vertical-side.flip ::slotted(ixfx-tab-list-item) {\n writing-mode: vertical-rl;\n text-orientation: mixed;\n }\n\n /* Drag affordances — opt-in via drag-mode=\"reorder\" on the host (list). */\n #container.reorder ::slotted(ixfx-tab-list-item) {\n cursor: grab;\n }\n :host([drag-mode]) ::slotted(ixfx-tab-list-item[drag-source]) {\n cursor: grabbing;\n opacity: 0.4;\n transition: opacity var(--transition, 0.15s ease-out);\n }\n\n /* Insertion caret shown during an active drag. */\n .drop-caret {\n position: absolute;\n background: var(--accent);\n border-radius: 1px;\n pointer-events: none;\n z-index: 1;\n }\n\n ::slotted(.activated) {\n --colour: var(--activated-colour);\n }\n `];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"ixfx-tab-list\": TabListElement;\n }\n}\n"],"mappings":"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"}
package/dist/tabs.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as TabListReorderDetail, i as TabListElement, n as TabListChangeEvent, o as TabListReorderEvent, r as TabListDragMode, t as TabListChangeDetail } from "./tab-list-CLqlPnX-.js";
1
+ import { a as TabListReorderDetail, i as TabListElement, n as TabListChangeEvent, o as TabListReorderEvent, r as TabListDragMode, t as TabListChangeDetail } from "./tab-list-B8v9KntS.js";
2
2
  export { TabListChangeDetail, TabListChangeEvent, TabListDragMode, TabListElement, TabListReorderDetail, TabListReorderEvent };
package/dist/tabs.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as TabListElement } from "./tab-list-6W5CgXix.js";
1
+ import { t as TabListElement } from "./tab-list-CR0v53KJ.js";
2
2
  export { TabListElement };
@@ -1,4 +1,5 @@
1
1
  import { ReactiveController, ReactiveControllerHost } from "lit";
2
+
2
3
  //#region src/interaction/tickled-controller.d.ts
3
4
  /**
4
5
  * Represents an item that can be tickled (highlighted via hover or keyboard navigation)
@@ -74,10 +75,11 @@ type TickledControllerConfig<T> = {
74
75
  *
75
76
  * ## Global Mouse Tracking
76
77
  *
77
- * This controller uses a singleton global `pointermove` listener to track actual
78
- * mouse movement. This prevents `pointerenter` events caused by content scrolling
79
- * from incorrectly switching to mouse mode when the user is actually using keyboard
80
- * navigation.
78
+ * This controller uses a single, ref-counted global `pointermove` listener (shared
79
+ * across all instances) to track actual mouse movement. This prevents `pointerenter`
80
+ * events caused by content scrolling from incorrectly switching to mouse mode when
81
+ * the user is actually using keyboard navigation. The listener is attached when the
82
+ * first host connects and removed once the last host disconnects.
81
83
  *
82
84
  * @example
83
85
  * ```ts
@@ -121,7 +123,8 @@ declare class TickledController<T = number> implements ReactiveController {
121
123
  private static _lastMouseClientX;
122
124
  private static _lastMouseClientY;
123
125
  private static _mouseMovedSinceKeyboard;
124
- private static _globalListenerAttached;
126
+ private static _listenerRefCount;
127
+ private static readonly _onGlobalPointerMove;
125
128
  constructor(host: ReactiveControllerHost, config: TickledControllerConfig<T>);
126
129
  hostConnected(): void;
127
130
  hostDisconnected(): void;
@@ -186,4 +189,4 @@ declare class TickledController<T = number> implements ReactiveController {
186
189
  }
187
190
  //#endregion
188
191
  export { TickledController as t };
189
- //# sourceMappingURL=tickled-controller-BF2Ea0DE.d.ts.map
192
+ //# sourceMappingURL=tickled-controller-JDOR9B8V.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tickled-controller-JDOR9B8V.d.ts","names":[],"sources":["../src/interaction/tickled-controller.ts"],"mappings":";;;;;AAKA;KAAY,WAAA;EAAW;;;EAAA,SAIZ,EAAA,EAAI,CAAC;EAAD;;;EAAA,SAKJ,OAAA;AAAA;;;;KAMC,SAAA;AAKZ;;;AAAA,KAAY,uBAAA;EAIoB;;;EAA9B,QAAA,QAAgB,aAAA,CAAc,WAAA,CAAY,CAAA;EAoCd;;;;;EA7B5B,QAAA,IAAY,EAAA,EAAI,CAAA;EAP0B;;;;;;;;AAoCd;AA0D9B;;;;;;;;;;;;;EA/DE,aAAA;EA+DoD;;;EA1DpD,gBAAA,GAAmB,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8RS;;;;;;;;;;;;cApOjB,iBAAA,wBAAyC,kBAAA;EAAA,QAC5C,IAAA;EAAA,QACA,MAAA;EAAA,QACA,UAAA;EAAA,QACA,UAAA;EAAA,eAEO,iBAAA;EAAA,eACA,iBAAA;EAAA,eACA,wBAAA;EAAA,eACA,iBAAA;EAAA,wBAES,oBAAA;cAIZ,IAAA,EAAM,sBAAA,EAAwB,MAAA,EAAQ,uBAAA,CAAwB,CAAA;EAO1E,aAAA;EAOA,gBAAA;;;;MAUI,SAAA,IAAa,SAAA;;;;MAOb,SAAA,IAAa,CAAA;;;;EAOjB,SAAA,CAAU,EAAA,EAAI,CAAA;;;;;;iBASC,uBAAA;;;;;aAiBJ,0BAAA;;;;;;EASX,kBAAA,CAAmB,EAAA,EAAI,CAAA;;;;;;EAiCvB,kBAAA,CAAmB,EAAA,EAAI,YAAA;;;;;;;EAYvB,wBAAA,CAAyB,SAAA,2CAAoD,CAAA;;;;;EAyD7E,UAAA,CAAW,EAAA,EAAI,CAAA;;;;;;EAmBf,YAAA;;;;;EAmBA,YAAA,CAAa,IAAA,EAAM,SAAA;AAAA"}
@@ -15,10 +15,11 @@ import { css } from "lit";
15
15
  *
16
16
  * ## Global Mouse Tracking
17
17
  *
18
- * This controller uses a singleton global `pointermove` listener to track actual
19
- * mouse movement. This prevents `pointerenter` events caused by content scrolling
20
- * from incorrectly switching to mouse mode when the user is actually using keyboard
21
- * navigation.
18
+ * This controller uses a single, ref-counted global `pointermove` listener (shared
19
+ * across all instances) to track actual mouse movement. This prevents `pointerenter`
20
+ * events caused by content scrolling from incorrectly switching to mouse mode when
21
+ * the user is actually using keyboard navigation. The listener is attached when the
22
+ * first host connects and removed once the last host disconnects.
22
23
  *
23
24
  * @example
24
25
  * ```ts
@@ -65,7 +66,12 @@ var TickledController = class TickledController {
65
66
  this._mouseMovedSinceKeyboard = true;
66
67
  }
67
68
  static {
68
- this._globalListenerAttached = false;
69
+ this._listenerRefCount = 0;
70
+ }
71
+ static {
72
+ this._onGlobalPointerMove = (e) => {
73
+ TickledController.handleGlobalPointerMove(e.clientX, e.clientY);
74
+ };
69
75
  }
70
76
  constructor(host, config) {
71
77
  this._tickledId = void 0;
@@ -75,14 +81,13 @@ var TickledController = class TickledController {
75
81
  host.addController(this);
76
82
  }
77
83
  hostConnected() {
78
- if (!TickledController._globalListenerAttached) {
79
- document.addEventListener(`pointermove`, (e) => {
80
- TickledController.handleGlobalPointerMove(e.clientX, e.clientY);
81
- }, { passive: true });
82
- TickledController._globalListenerAttached = true;
83
- }
84
+ if (TickledController._listenerRefCount === 0) document.addEventListener(`pointermove`, TickledController._onGlobalPointerMove, { passive: true });
85
+ TickledController._listenerRefCount++;
86
+ }
87
+ hostDisconnected() {
88
+ TickledController._listenerRefCount--;
89
+ if (TickledController._listenerRefCount === 0) document.removeEventListener(`pointermove`, TickledController._onGlobalPointerMove);
84
90
  }
85
- hostDisconnected() {}
86
91
  /**
87
92
  * Get the current input mode
88
93
  */
@@ -225,19 +230,14 @@ var TickledController = class TickledController {
225
230
  *
226
231
  * ## CSS Variable Contract
227
232
  *
228
- * **Style variables (default values defined in `tickledItemStyles`):**
229
- * - `--item-bg`: Default background (default: transparent)
230
- * - `--item-bg-tickled`: Background when tickled (default: rgba(0, 0, 0, 0.06))
231
- * - `--item-bg-selected`: Background when selected (default: rgba(25, 118, 210, 1))
232
- * - `--item-bg-selected-tickled`: Background when selected AND tickled (default: rgba(21, 101, 192, 1))
233
- * - `--item-border`: Border style (default: 1px solid transparent)
234
- * - `--item-border-tickled`: Border when tickled (default: 1px solid var(--accent))
235
- * - `--item-border-selected`: Border when selected (default: 1px solid rgba(25, 118, 210, 1))
236
- * - `--item-text-tickled`: Text color when tickled (default: inherit)
237
- * - `--item-text-selected`: Text color when selected (default: #fff)
238
- * - `--item-padding`: Item padding (default: 4px 8px)
239
- * - `--item-border-radius`: Border radius (default: 4px)
240
- * - `--item-icon-spacing`: Gap between icon and text (default: 4px)
233
+ * **Style variables** `tickledItemStyles` only consumes these via `var()`; it
234
+ * defines no defaults itself. Fallback values (used when no theme CSS is loaded)
235
+ * are registered in `themeFallbacks` (`../styles/fallbacks.ts`) and mirror the
236
+ * documented base theme in `user-theming.md`:
237
+ * - `--item-bg`, `--item-bg-tickled`, `--item-bg-selected`, `--item-bg-selected-tickled`
238
+ * - `--item-border`, `--item-border-tickled`, `--item-border-selected` (full border shorthands, not colours)
239
+ * - `--item-text-tickled`, `--item-text-selected`
240
+ * - `--item-padding`, `--item-border-radius`, `--item-icon-spacing`
241
241
  *
242
242
  * ## Usage
243
243
  *
@@ -289,13 +289,13 @@ const tickledItemStyles = css`
289
289
 
290
290
  .item.tickled {
291
291
  background: var(--item-bg-tickled);
292
- border-color: var(--item-border-tickled);
292
+ border: var(--item-border-tickled);
293
293
  color: var(--item-text-tickled);
294
294
  }
295
295
 
296
296
  .item.selected {
297
297
  background: var(--item-bg-selected);
298
- border-color: var(--item-border-selected);
298
+ border: var(--item-border-selected);
299
299
  color: var(--item-text-selected);
300
300
  }
301
301
 
@@ -308,4 +308,4 @@ const tickledItemStyles = css`
308
308
  //#endregion
309
309
  export { tickledStyles as n, TickledController as r, tickledItemStyles as t };
310
310
 
311
- //# sourceMappingURL=tickled-styles-fNDdqf6l.js.map
311
+ //# sourceMappingURL=tickled-styles-Bgo_Lpw-.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tickled-styles-Bgo_Lpw-.js","names":[],"sources":["../src/interaction/tickled-controller.ts","../src/interaction/tickled-styles.ts"],"sourcesContent":["import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\n/**\n * Represents an item that can be tickled (highlighted via hover or keyboard navigation)\n */\nexport type TickledItem<T = unknown> = {\n /**\n * Unique identifier for the item (e.g., index, id, path)\n */\n readonly id: T;\n\n /**\n * Whether the item is currently enabled/interactive\n */\n readonly enabled?: boolean;\n};\n\n/**\n * Input mode determines which mechanism controls the tickled state\n */\nexport type InputMode = `keyboard` | `mouse`;\n\n/**\n * Configuration for TickledController\n */\nexport type TickledControllerConfig<T> = {\n /**\n * Function to retrieve all items that can be tickled\n */\n getItems: () => ReadonlyArray<TickledItem<T>>;\n\n /**\n * Optional callback when an item becomes tickled\n * Use this for side effects like opening submenus\n * @param id - The id of the newly tickled item, or undefined if nothing is tickled\n */\n onTickle?: (id: T | undefined) => void;\n\n /**\n * Optional callback fired after any state change (tickled id or input mode)\n * Use this to sync DOM attributes for slotted content that can't use reactive rendering\n *\n * For components that render items directly, this is usually not needed as\n * Lit's reactive rendering will handle updates automatically via requestUpdate()\n *\n * @example\n * ```ts\n * onStateChange: () => {\n * // Sync data-tickled attributes for slotted items\n * const items = this.getItems();\n * items.forEach((item, i) => {\n * if (this.tickled.isTickled(i)) {\n * item.setAttribute('data-tickled', '');\n * } else {\n * item.removeAttribute('data-tickled');\n * }\n * });\n * }\n * ```\n */\n onStateChange?: () => void;\n\n /**\n * Optional initial input mode (defaults to 'mouse')\n */\n initialInputMode?: InputMode;\n};\n\n/**\n * ReactiveController that manages \"tickled\" state for interactive lists.\n *\n * A \"tickled\" item is one that is under active attention via hover (mouse mode)\n * or keyboard focus (keyboard mode). Only one item can be tickled at a time.\n *\n * The input mode determines which mechanism controls tickled state:\n * - Mouse mode: hover controls tickled, keyboard navigation ignored\n * - Keyboard mode: keyboard navigation controls tickled, hover ignored\n *\n * Last interaction wins - any mouse hover switches to mouse mode, any keyboard\n * navigation switches to keyboard mode.\n *\n * ## Global Mouse Tracking\n *\n * This controller uses a single, ref-counted global `pointermove` listener (shared\n * across all instances) to track actual mouse movement. This prevents `pointerenter`\n * events caused by content scrolling from incorrectly switching to mouse mode when\n * the user is actually using keyboard navigation. The listener is attached when the\n * first host connects and removed once the last host disconnects.\n *\n * @example\n * ```ts\n * class MyList extends LitElement {\n * private tickled = new TickledController(this, {\n * getItems: () => this.items.map((item, i) => ({ id: i, enabled: !item.disabled })),\n * onTickle: (id) => {\n * // Optional: perform side effect when item is tickled\n * console.log('Tickled item:', id);\n * }\n * });\n *\n * render() {\n * return html`\n * <ul @pointerleave=${(e) => this.tickled.handlePointerLeave(e)}>\n * ${this.items.map((item, i) => html`\n * <li\n * class=\"item ${this.tickled.isTickled(i) ? 'tickled' : ''}\"\n * @pointerenter=${() => this.tickled.handlePointerEnter(i)}\n * >${item.label}</li>\n * `)}\n * </ul>\n * `;\n * }\n *\n * private handleKeyDown(e: KeyboardEvent) {\n * if (e.key === 'ArrowDown') {\n * this.tickled.handleKeyboardNavigation('next');\n * } else if (e.key === 'ArrowUp') {\n * this.tickled.handleKeyboardNavigation('previous');\n * }\n * }\n * }\n * ```\n */\nexport class TickledController<T = number> implements ReactiveController {\n private host: ReactiveControllerHost;\n private config: TickledControllerConfig<T>;\n private _tickledId: T | undefined = undefined;\n private _inputMode: InputMode;\n\n private static _lastMouseClientX: number = Number.NaN;\n private static _lastMouseClientY: number = Number.NaN;\n private static _mouseMovedSinceKeyboard: boolean = true;\n private static _listenerRefCount: number = 0;\n\n private static readonly _onGlobalPointerMove = (e: PointerEvent): void => {\n TickledController.handleGlobalPointerMove(e.clientX, e.clientY);\n };\n\n constructor(host: ReactiveControllerHost, config: TickledControllerConfig<T>) {\n this.host = host;\n this.config = config;\n this._inputMode = config.initialInputMode ?? `mouse`;\n host.addController(this);\n }\n\n hostConnected(): void {\n if (TickledController._listenerRefCount === 0) {\n document.addEventListener(`pointermove`, TickledController._onGlobalPointerMove, { passive: true });\n }\n TickledController._listenerRefCount++;\n }\n\n hostDisconnected(): void {\n TickledController._listenerRefCount--;\n if (TickledController._listenerRefCount === 0) {\n document.removeEventListener(`pointermove`, TickledController._onGlobalPointerMove);\n }\n }\n\n /**\n * Get the current input mode\n */\n get inputMode(): InputMode {\n return this._inputMode;\n }\n\n /**\n * Get the currently tickled item id\n */\n get tickledId(): T | undefined {\n return this._tickledId;\n }\n\n /**\n * Check if a specific item is tickled\n */\n isTickled(id: T): boolean {\n return this._tickledId === id;\n }\n\n /**\n * Handle global pointer move event.\n * Called automatically by the global listener.\n * Tracks mouse movement to distinguish real hover from content scrolling.\n */\n private static handleGlobalPointerMove(clientX: number, clientY: number): void {\n if (!Number.isNaN(TickledController._lastMouseClientX)) {\n if (\n clientX !== TickledController._lastMouseClientX\n || clientY !== TickledController._lastMouseClientY\n ) {\n TickledController._mouseMovedSinceKeyboard = true;\n }\n }\n TickledController._lastMouseClientX = clientX;\n TickledController._lastMouseClientY = clientY;\n }\n\n /**\n * Check if actual mouse movement has occurred since last keyboard interaction.\n * Used to distinguish real hover/leave from content-scrolling-induced events.\n */\n static get hasMouseMovedSinceKeyboard(): boolean {\n return TickledController._mouseMovedSinceKeyboard;\n }\n\n /**\n * Handle pointer enter event on an item (mouse hover).\n * Only processes if actual mouse movement is detected (not content scrolling).\n * Switches to mouse mode and tickles the item.\n */\n handlePointerEnter(id: T): void {\n if (!TickledController._mouseMovedSinceKeyboard) {\n return;\n }\n\n const items = this.config.getItems();\n const item = items.find(item => item.id === id);\n if (item && item.enabled === false) {\n return;\n }\n\n const modeChanged = this._inputMode !== `mouse`;\n this._inputMode = `mouse`;\n\n const previousId = this._tickledId;\n this._tickledId = id;\n\n this.host.requestUpdate();\n\n if (previousId !== id && this.config.onTickle) {\n this.config.onTickle(id);\n }\n\n if ((previousId !== id || modeChanged) && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n\n /**\n * Handle pointer leave event on an item.\n * Only clears tickled state if actual mouse movement is detected.\n * @param _e The pointer event (not used, but kept for API compatibility)\n */\n handlePointerLeave(_e: PointerEvent): void {\n if (TickledController._mouseMovedSinceKeyboard) {\n this.clearTickled();\n }\n }\n\n /**\n * Handle keyboard navigation.\n * Switches to keyboard mode and moves tickled state.\n *\n * @param direction - 'next', 'previous', 'first', 'last', or specific id\n */\n handleKeyboardNavigation(direction: `next` | `previous` | `first` | `last` | T): void {\n const modeChanged = this._inputMode !== `keyboard`;\n this._inputMode = `keyboard`;\n\n const items = this.config.getItems();\n const enabledItems = items.filter(item => item.enabled !== false);\n\n if (enabledItems.length === 0) {\n return;\n }\n\n let newId: T | undefined;\n\n if (direction === `first`) {\n newId = enabledItems[0].id;\n } else if (direction === `last`) {\n newId = enabledItems.at(-1)?.id;\n } else if (direction === `next` || direction === `previous`) {\n const currentIndex = enabledItems.findIndex(item => item.id === this._tickledId);\n\n if (currentIndex === -1) {\n newId = direction === `next` ? enabledItems[0].id : enabledItems.at(-1)?.id;\n } else {\n const delta = direction === `next` ? 1 : -1;\n const newIndex = currentIndex + delta;\n\n if (newIndex >= 0 && newIndex < enabledItems.length) {\n newId = enabledItems[newIndex].id;\n }\n // If newIndex is out of bounds, keep current tickled item\n }\n } else {\n const item = enabledItems.find(item => item.id === direction);\n if (item) {\n newId = item.id;\n }\n }\n\n if (newId !== undefined) {\n const previousId = this._tickledId;\n this._tickledId = newId;\n this.host.requestUpdate();\n\n if (previousId !== newId && this.config.onTickle) {\n this.config.onTickle(newId);\n }\n\n if ((previousId !== newId || modeChanged) && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n\n /**\n * Manually set the tickled item (useful for programmatic control).\n * Does NOT change input mode.\n */\n setTickled(id: T | undefined): void {\n const previousId = this._tickledId;\n this._tickledId = id;\n this.host.requestUpdate();\n\n if (previousId !== id && this.config.onTickle) {\n this.config.onTickle(id);\n }\n\n if (previousId !== id && this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n\n /**\n * Clear the tickled state (e.g., on pointer leave).\n * Note: For pointer leave events, prefer using handlePointerLeave() which\n * checks for actual mouse movement.\n */\n clearTickled(): void {\n if (this._tickledId !== undefined) {\n this._tickledId = undefined;\n this.host.requestUpdate();\n\n if (this.config.onTickle) {\n this.config.onTickle(undefined);\n }\n\n if (this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n\n /**\n * Manually set the input mode.\n * When switching to keyboard mode, resets the mouse movement tracking.\n */\n setInputMode(mode: InputMode): void {\n if (this._inputMode !== mode) {\n this._inputMode = mode;\n this.host.requestUpdate();\n\n if (mode === `keyboard`) {\n TickledController._mouseMovedSinceKeyboard = false;\n }\n\n if (this.config.onStateChange) {\n this.config.onStateChange();\n }\n }\n }\n}\n","import { css } from 'lit';\n\n/**\n * Shared CSS styles for tickled interaction pattern.\n *\n * Tickled state is controlled via the `.tickled` CSS class (applied by TickledController).\n * The `tickledItemStyles` provides base styling that all tickled components should use.\n *\n * ## CSS Variable Contract\n *\n * **Style variables** — `tickledItemStyles` only consumes these via `var()`; it\n * defines no defaults itself. Fallback values (used when no theme CSS is loaded)\n * are registered in `themeFallbacks` (`../styles/fallbacks.ts`) and mirror the\n * documented base theme in `user-theming.md`:\n * - `--item-bg`, `--item-bg-tickled`, `--item-bg-selected`, `--item-bg-selected-tickled`\n * - `--item-border`, `--item-border-tickled`, `--item-border-selected` (full border shorthands, not colours)\n * - `--item-text-tickled`, `--item-text-selected`\n * - `--item-padding`, `--item-border-radius`, `--item-icon-spacing`\n *\n * ## Usage\n *\n * Components should import both `tickledStyles` and `tickledItemStyles`:\n *\n * ```ts\n * import { tickledStyles, tickledItemStyles } from '../interaction/index.js';\n *\n * class MyComponent extends LitElement {\n * static styles = [\n * tickledStyles,\n * tickledItemStyles,\n * css`\n * :host {\n * --item-bg-tickled: #e0e0e0;\n * --item-bg-selected: #1976d2;\n * }\n * `\n * ];\n * }\n * ```\n */\n\nexport const tickledStyles = css`\n /**\n * No suppression needed - tickled styling is always active.\n */\n`;\n\n/**\n * Shared item styling for tickled components.\n *\n * Provides base styles for interactive items with tickled and selected states.\n * Components should import this in addition to `tickledStyles` and can override\n * CSS variables to customize appearance.\n */\nexport const tickledItemStyles = css`\n .item {\n display: inline-flex;\n align-items: center;\n gap: var(--item-icon-spacing);\n padding: var(--item-padding);\n background: var(--item-bg);\n border: var(--item-border);\n border-radius: var(--item-border-radius);\n cursor: pointer;\n user-select: none;\n white-space: nowrap;\n transition: background var(--transition, 0.1s ease-out), border-color var(--transition, 0.1s ease-out);\n }\n\n .item.tickled {\n background: var(--item-bg-tickled);\n border: var(--item-border-tickled);\n color: var(--item-text-tickled);\n }\n\n .item.selected {\n background: var(--item-bg-selected);\n border: var(--item-border-selected);\n color: var(--item-text-selected);\n }\n\n .item.selected.tickled {\n background: var(--item-bg-selected-tickled);\n outline: 2px dashed var(--surface-3);\n outline-offset: -2px;\n }\n`;"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
1
+ import { n as safeCustomElement, t as __decorate } from "./decorate-DdjvVHS-.js";
2
2
  import { LitElement, css, html, nothing } from "lit";
3
3
  import { property, state } from "lit/decorators.js";
4
4
  import "@clinth/vcanvas";
@@ -256,7 +256,7 @@ function drawEventRects(ctx, region, events, trackLayout, selectedIds, tickledId
256
256
  const x = evt.start * ppu;
257
257
  const w = (evt.end - evt.start) * ppu;
258
258
  const y = layout.y + padding;
259
- const h = layout.height - 6;
259
+ const h = layout.height - padding * 2;
260
260
  if (w < 1) continue;
261
261
  const isSelected = selectedIds.has(evt.id);
262
262
  const isTickled = tickledId === evt.id;
@@ -1749,4 +1749,4 @@ IxfxTimelineElement = __decorate([safeCustomElement(`ixfx-timeline`)], IxfxTimel
1749
1749
  //#endregion
1750
1750
  export { resolveCssVars as a, attachTimelineInteractions as i, TimelineTrackTabElement as n, resolveGrid as o, timelineStyles as r, TimelineController as s, IxfxTimelineElement as t };
1751
1751
 
1752
- //# sourceMappingURL=timeline-B2fgDL4U.js.map
1752
+ //# sourceMappingURL=timeline-CdSI003L.js.map