tyrell-components 1.0.0-RC13 → 1.0.0-RC15

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 (358) hide show
  1. package/README.md +10 -2
  2. package/css/tyrell-theme.css +192 -180
  3. package/css/tyrell.css +23 -0
  4. package/dist/tyrell-colors-static.css +1 -316
  5. package/dist/tyrell-theme.css +1 -1454
  6. package/dist/tyrell.css +1 -1371
  7. package/dist/tyrell.js +1 -1
  8. package/lib/base/ty-component.d.ts +20 -10
  9. package/lib/base/ty-component.js +196 -319
  10. package/lib/components/button.d.ts +3 -17
  11. package/lib/components/button.js +261 -295
  12. package/lib/components/calendar-month.d.ts +4 -50
  13. package/lib/components/calendar-month.js +443 -582
  14. package/lib/components/calendar-navigation.d.ts +3 -48
  15. package/lib/components/calendar-navigation.js +239 -362
  16. package/lib/components/calendar.d.ts +8 -83
  17. package/lib/components/calendar.js +616 -829
  18. package/lib/components/checkbox.d.ts +5 -72
  19. package/lib/components/checkbox.js +273 -416
  20. package/lib/components/copy.d.ts +4 -57
  21. package/lib/components/copy.js +280 -397
  22. package/lib/components/date-picker.d.ts +21 -163
  23. package/lib/components/date-picker.js +1143 -1674
  24. package/lib/components/file-upload.d.ts +9 -15
  25. package/lib/components/file-upload.js +404 -426
  26. package/lib/components/icon.d.ts +3 -24
  27. package/lib/components/icon.js +141 -230
  28. package/lib/components/input.d.ts +8 -108
  29. package/lib/components/input.js +593 -784
  30. package/lib/components/modal.d.ts +17 -26
  31. package/lib/components/modal.js +340 -484
  32. package/lib/components/option.d.ts +2 -9
  33. package/lib/components/option.js +168 -216
  34. package/lib/components/popup.d.ts +2 -17
  35. package/lib/components/popup.js +249 -380
  36. package/lib/components/radio.d.ts +5 -25
  37. package/lib/components/radio.js +407 -461
  38. package/lib/components/resize-observer.d.ts +3 -30
  39. package/lib/components/resize-observer.js +69 -103
  40. package/lib/components/scroll-container.d.ts +2 -12
  41. package/lib/components/scroll-container.js +293 -338
  42. package/lib/components/select.d.ts +87 -159
  43. package/lib/components/select.js +1609 -2090
  44. package/lib/components/selected-tags.d.ts +5 -48
  45. package/lib/components/selected-tags.js +188 -276
  46. package/lib/components/step.d.ts +1 -6
  47. package/lib/components/step.js +62 -68
  48. package/lib/components/switch.d.ts +1 -12
  49. package/lib/components/switch.js +214 -247
  50. package/lib/components/tab.d.ts +1 -6
  51. package/lib/components/tab.js +62 -69
  52. package/lib/components/tabs.d.ts +6 -63
  53. package/lib/components/tabs.js +545 -777
  54. package/lib/components/tag.d.ts +3 -37
  55. package/lib/components/tag.js +236 -335
  56. package/lib/components/textarea.d.ts +7 -87
  57. package/lib/components/textarea.js +457 -627
  58. package/lib/components/tooltip.d.ts +3 -11
  59. package/lib/components/tooltip.js +307 -443
  60. package/lib/components/wizard.d.ts +6 -54
  61. package/lib/components/wizard.js +405 -618
  62. package/lib/icons/fontawesome/brands.d.ts +0 -1
  63. package/lib/icons/fontawesome/brands.js +0 -8
  64. package/lib/icons/fontawesome/regular.d.ts +0 -1
  65. package/lib/icons/fontawesome/regular.js +0 -8
  66. package/lib/icons/fontawesome/solid.d.ts +0 -1
  67. package/lib/icons/fontawesome/solid.js +0 -8
  68. package/lib/icons/heroicons/micro.d.ts +0 -1
  69. package/lib/icons/heroicons/micro.js +392 -400
  70. package/lib/icons/heroicons/mini.d.ts +0 -1
  71. package/lib/icons/heroicons/mini.js +382 -390
  72. package/lib/icons/heroicons/outline.d.ts +0 -1
  73. package/lib/icons/heroicons/outline.js +337 -345
  74. package/lib/icons/heroicons/solid.d.ts +0 -1
  75. package/lib/icons/heroicons/solid.js +407 -415
  76. package/lib/icons/lucide.d.ts +0 -1
  77. package/lib/icons/lucide.js +24479 -26351
  78. package/lib/icons/material/filled.d.ts +0 -1
  79. package/lib/icons/material/filled.js +9653 -9663
  80. package/lib/icons/material/outlined.d.ts +0 -1
  81. package/lib/icons/material/outlined.js +10271 -10281
  82. package/lib/icons/material/round.d.ts +0 -1
  83. package/lib/icons/material/round.js +10495 -10505
  84. package/lib/icons/material/sharp.d.ts +0 -1
  85. package/lib/icons/material/sharp.js +9905 -9915
  86. package/lib/icons/material/two-tone.d.ts +0 -1
  87. package/lib/icons/material/two-tone.js +12792 -12802
  88. package/lib/index.d.ts +0 -1
  89. package/lib/index.js +21 -41
  90. package/lib/styles/button.d.ts +2 -20
  91. package/lib/styles/button.js +202 -404
  92. package/lib/styles/calendar-month.d.ts +1 -5
  93. package/lib/styles/calendar-month.js +127 -244
  94. package/lib/styles/calendar-navigation.d.ts +2 -6
  95. package/lib/styles/calendar-navigation.js +64 -104
  96. package/lib/styles/calendar.d.ts +1 -2
  97. package/lib/styles/calendar.js +9 -22
  98. package/lib/styles/checkbox.d.ts +0 -1
  99. package/lib/styles/checkbox.js +45 -94
  100. package/lib/styles/copy.d.ts +0 -1
  101. package/lib/styles/copy.js +67 -106
  102. package/lib/styles/custom-scrollbar.d.ts +1 -2
  103. package/lib/styles/custom-scrollbar.js +80 -115
  104. package/lib/styles/date-picker.d.ts +1 -5
  105. package/lib/styles/date-picker.js +261 -335
  106. package/lib/styles/field-size.d.ts +6 -0
  107. package/lib/styles/field-size.js +91 -0
  108. package/lib/styles/file-upload.d.ts +1 -2
  109. package/lib/styles/file-upload.js +143 -188
  110. package/lib/styles/icon.d.ts +2 -6
  111. package/lib/styles/icon.js +92 -170
  112. package/lib/styles/input.d.ts +1 -6
  113. package/lib/styles/input.js +125 -290
  114. package/lib/styles/modal.d.ts +1 -2
  115. package/lib/styles/modal.js +71 -108
  116. package/lib/styles/option.d.ts +2 -6
  117. package/lib/styles/option.js +49 -64
  118. package/lib/styles/popup.d.ts +1 -2
  119. package/lib/styles/popup.js +42 -77
  120. package/lib/styles/radio.d.ts +0 -1
  121. package/lib/styles/radio.js +69 -110
  122. package/lib/styles/resize-observer.d.ts +1 -2
  123. package/lib/styles/resize-observer.js +2 -12
  124. package/lib/styles/scroll-container.d.ts +1 -2
  125. package/lib/styles/scroll-container.js +100 -149
  126. package/lib/styles/select-base.d.ts +0 -1
  127. package/lib/styles/select-base.js +597 -785
  128. package/lib/styles/select.d.ts +1 -2
  129. package/lib/styles/select.js +140 -236
  130. package/lib/styles/step.d.ts +1 -2
  131. package/lib/styles/step.js +22 -33
  132. package/lib/styles/switch.d.ts +0 -1
  133. package/lib/styles/switch.js +34 -73
  134. package/lib/styles/tab.d.ts +1 -2
  135. package/lib/styles/tab.js +22 -34
  136. package/lib/styles/tabs.d.ts +3 -11
  137. package/lib/styles/tabs.js +190 -222
  138. package/lib/styles/tag.d.ts +1 -5
  139. package/lib/styles/tag.js +136 -218
  140. package/lib/styles/textarea.d.ts +1 -2
  141. package/lib/styles/textarea.js +210 -319
  142. package/lib/styles/tooltip.d.ts +0 -1
  143. package/lib/styles/tooltip.js +3 -13
  144. package/lib/styles/wizard.d.ts +5 -21
  145. package/lib/styles/wizard.js +170 -306
  146. package/lib/types/common.d.ts +2 -2
  147. package/lib/types/common.js +6 -17
  148. package/lib/utils/calendar-utils.d.ts +4 -21
  149. package/lib/utils/calendar-utils.js +100 -273
  150. package/lib/utils/custom-scrollbar.d.ts +6 -20
  151. package/lib/utils/custom-scrollbar.js +273 -317
  152. package/lib/utils/flavor-sheet.d.ts +0 -1
  153. package/lib/utils/flavor-sheet.js +14 -37
  154. package/lib/utils/icon-registry.d.ts +0 -2
  155. package/lib/utils/icon-registry.js +137 -243
  156. package/lib/utils/icons.d.ts +0 -1
  157. package/lib/utils/icons.js +0 -9
  158. package/lib/utils/loader-registry.d.ts +0 -1
  159. package/lib/utils/loader-registry.js +3 -35
  160. package/lib/utils/locale.d.ts +2 -23
  161. package/lib/utils/locale.js +34 -120
  162. package/lib/utils/mobile.d.ts +0 -1
  163. package/lib/utils/mobile.js +1 -18
  164. package/lib/utils/number-format.d.ts +6 -3
  165. package/lib/utils/number-format.js +54 -110
  166. package/lib/utils/positioning.d.ts +50 -7
  167. package/lib/utils/positioning.js +224 -234
  168. package/lib/utils/property-capture.d.ts +5 -27
  169. package/lib/utils/property-capture.js +36 -144
  170. package/lib/utils/property-manager.d.ts +0 -1
  171. package/lib/utils/property-manager.js +126 -196
  172. package/lib/utils/resize-observer.d.ts +0 -1
  173. package/lib/utils/resize-observer.js +23 -59
  174. package/lib/utils/scroll-lock.d.ts +4 -11
  175. package/lib/utils/scroll-lock.js +65 -172
  176. package/lib/utils/styles.d.ts +0 -1
  177. package/lib/utils/styles.js +17 -41
  178. package/lib/version.d.ts +1 -2
  179. package/lib/version.js +1 -11
  180. package/package.json +4 -4
  181. package/lib/base/ty-component.d.ts.map +0 -1
  182. package/lib/base/ty-component.js.map +0 -1
  183. package/lib/components/button.d.ts.map +0 -1
  184. package/lib/components/button.js.map +0 -1
  185. package/lib/components/calendar-month.d.ts.map +0 -1
  186. package/lib/components/calendar-month.js.map +0 -1
  187. package/lib/components/calendar-navigation.d.ts.map +0 -1
  188. package/lib/components/calendar-navigation.js.map +0 -1
  189. package/lib/components/calendar.d.ts.map +0 -1
  190. package/lib/components/calendar.js.map +0 -1
  191. package/lib/components/checkbox.d.ts.map +0 -1
  192. package/lib/components/checkbox.js.map +0 -1
  193. package/lib/components/copy.d.ts.map +0 -1
  194. package/lib/components/copy.js.map +0 -1
  195. package/lib/components/date-picker.d.ts.map +0 -1
  196. package/lib/components/date-picker.js.map +0 -1
  197. package/lib/components/file-upload.d.ts.map +0 -1
  198. package/lib/components/file-upload.js.map +0 -1
  199. package/lib/components/icon.d.ts.map +0 -1
  200. package/lib/components/icon.js.map +0 -1
  201. package/lib/components/input.d.ts.map +0 -1
  202. package/lib/components/input.js.map +0 -1
  203. package/lib/components/modal.d.ts.map +0 -1
  204. package/lib/components/modal.js.map +0 -1
  205. package/lib/components/option.d.ts.map +0 -1
  206. package/lib/components/option.js.map +0 -1
  207. package/lib/components/popup.d.ts.map +0 -1
  208. package/lib/components/popup.js.map +0 -1
  209. package/lib/components/radio.d.ts.map +0 -1
  210. package/lib/components/radio.js.map +0 -1
  211. package/lib/components/resize-observer.d.ts.map +0 -1
  212. package/lib/components/resize-observer.js.map +0 -1
  213. package/lib/components/scroll-container.d.ts.map +0 -1
  214. package/lib/components/scroll-container.js.map +0 -1
  215. package/lib/components/select.d.ts.map +0 -1
  216. package/lib/components/select.js.map +0 -1
  217. package/lib/components/selected-tags.d.ts.map +0 -1
  218. package/lib/components/selected-tags.js.map +0 -1
  219. package/lib/components/step.d.ts.map +0 -1
  220. package/lib/components/step.js.map +0 -1
  221. package/lib/components/switch.d.ts.map +0 -1
  222. package/lib/components/switch.js.map +0 -1
  223. package/lib/components/tab.d.ts.map +0 -1
  224. package/lib/components/tab.js.map +0 -1
  225. package/lib/components/tabs.d.ts.map +0 -1
  226. package/lib/components/tabs.js.map +0 -1
  227. package/lib/components/tag.d.ts.map +0 -1
  228. package/lib/components/tag.js.map +0 -1
  229. package/lib/components/textarea.d.ts.map +0 -1
  230. package/lib/components/textarea.js.map +0 -1
  231. package/lib/components/tooltip.d.ts.map +0 -1
  232. package/lib/components/tooltip.js.map +0 -1
  233. package/lib/components/wizard.d.ts.map +0 -1
  234. package/lib/components/wizard.js.map +0 -1
  235. package/lib/icons/fontawesome/brands.d.ts.map +0 -1
  236. package/lib/icons/fontawesome/brands.js.map +0 -1
  237. package/lib/icons/fontawesome/regular.d.ts.map +0 -1
  238. package/lib/icons/fontawesome/regular.js.map +0 -1
  239. package/lib/icons/fontawesome/solid.d.ts.map +0 -1
  240. package/lib/icons/fontawesome/solid.js.map +0 -1
  241. package/lib/icons/heroicons/micro.d.ts.map +0 -1
  242. package/lib/icons/heroicons/micro.js.map +0 -1
  243. package/lib/icons/heroicons/mini.d.ts.map +0 -1
  244. package/lib/icons/heroicons/mini.js.map +0 -1
  245. package/lib/icons/heroicons/outline.d.ts.map +0 -1
  246. package/lib/icons/heroicons/outline.js.map +0 -1
  247. package/lib/icons/heroicons/solid.d.ts.map +0 -1
  248. package/lib/icons/heroicons/solid.js.map +0 -1
  249. package/lib/icons/lucide.d.ts.map +0 -1
  250. package/lib/icons/lucide.js.map +0 -1
  251. package/lib/icons/material/filled.d.ts.map +0 -1
  252. package/lib/icons/material/filled.js.map +0 -1
  253. package/lib/icons/material/outlined.d.ts.map +0 -1
  254. package/lib/icons/material/outlined.js.map +0 -1
  255. package/lib/icons/material/round.d.ts.map +0 -1
  256. package/lib/icons/material/round.js.map +0 -1
  257. package/lib/icons/material/sharp.d.ts.map +0 -1
  258. package/lib/icons/material/sharp.js.map +0 -1
  259. package/lib/icons/material/two-tone.d.ts.map +0 -1
  260. package/lib/icons/material/two-tone.js.map +0 -1
  261. package/lib/index.d.ts.map +0 -1
  262. package/lib/index.js.map +0 -1
  263. package/lib/styles/button.d.ts.map +0 -1
  264. package/lib/styles/button.js.map +0 -1
  265. package/lib/styles/calendar-month.d.ts.map +0 -1
  266. package/lib/styles/calendar-month.js.map +0 -1
  267. package/lib/styles/calendar-navigation.d.ts.map +0 -1
  268. package/lib/styles/calendar-navigation.js.map +0 -1
  269. package/lib/styles/calendar.d.ts.map +0 -1
  270. package/lib/styles/calendar.js.map +0 -1
  271. package/lib/styles/checkbox.d.ts.map +0 -1
  272. package/lib/styles/checkbox.js.map +0 -1
  273. package/lib/styles/copy.d.ts.map +0 -1
  274. package/lib/styles/copy.js.map +0 -1
  275. package/lib/styles/custom-scrollbar.d.ts.map +0 -1
  276. package/lib/styles/custom-scrollbar.js.map +0 -1
  277. package/lib/styles/date-picker.d.ts.map +0 -1
  278. package/lib/styles/date-picker.js.map +0 -1
  279. package/lib/styles/file-upload.d.ts.map +0 -1
  280. package/lib/styles/file-upload.js.map +0 -1
  281. package/lib/styles/icon.d.ts.map +0 -1
  282. package/lib/styles/icon.js.map +0 -1
  283. package/lib/styles/input.d.ts.map +0 -1
  284. package/lib/styles/input.js.map +0 -1
  285. package/lib/styles/modal.d.ts.map +0 -1
  286. package/lib/styles/modal.js.map +0 -1
  287. package/lib/styles/multiselect.d.ts +0 -8
  288. package/lib/styles/multiselect.d.ts.map +0 -1
  289. package/lib/styles/multiselect.js +0 -849
  290. package/lib/styles/multiselect.js.map +0 -1
  291. package/lib/styles/option.d.ts.map +0 -1
  292. package/lib/styles/option.js.map +0 -1
  293. package/lib/styles/popup.d.ts.map +0 -1
  294. package/lib/styles/popup.js.map +0 -1
  295. package/lib/styles/radio.d.ts.map +0 -1
  296. package/lib/styles/radio.js.map +0 -1
  297. package/lib/styles/resize-observer.d.ts.map +0 -1
  298. package/lib/styles/resize-observer.js.map +0 -1
  299. package/lib/styles/scroll-container.d.ts.map +0 -1
  300. package/lib/styles/scroll-container.js.map +0 -1
  301. package/lib/styles/select-base.d.ts.map +0 -1
  302. package/lib/styles/select-base.js.map +0 -1
  303. package/lib/styles/select.d.ts.map +0 -1
  304. package/lib/styles/select.js.map +0 -1
  305. package/lib/styles/step.d.ts.map +0 -1
  306. package/lib/styles/step.js.map +0 -1
  307. package/lib/styles/switch.d.ts.map +0 -1
  308. package/lib/styles/switch.js.map +0 -1
  309. package/lib/styles/tab.d.ts.map +0 -1
  310. package/lib/styles/tab.js.map +0 -1
  311. package/lib/styles/tabs.d.ts.map +0 -1
  312. package/lib/styles/tabs.js.map +0 -1
  313. package/lib/styles/tag.d.ts.map +0 -1
  314. package/lib/styles/tag.js.map +0 -1
  315. package/lib/styles/textarea.d.ts.map +0 -1
  316. package/lib/styles/textarea.js.map +0 -1
  317. package/lib/styles/tooltip.d.ts.map +0 -1
  318. package/lib/styles/tooltip.js.map +0 -1
  319. package/lib/styles/wizard.d.ts.map +0 -1
  320. package/lib/styles/wizard.js.map +0 -1
  321. package/lib/types/common.d.ts.map +0 -1
  322. package/lib/types/common.js.map +0 -1
  323. package/lib/utils/calendar-utils.d.ts.map +0 -1
  324. package/lib/utils/calendar-utils.js.map +0 -1
  325. package/lib/utils/custom-scrollbar.d.ts.map +0 -1
  326. package/lib/utils/custom-scrollbar.js.map +0 -1
  327. package/lib/utils/flavor-sheet.d.ts.map +0 -1
  328. package/lib/utils/flavor-sheet.js.map +0 -1
  329. package/lib/utils/icon-registry.d.ts.map +0 -1
  330. package/lib/utils/icon-registry.js.map +0 -1
  331. package/lib/utils/icons.d.ts.map +0 -1
  332. package/lib/utils/icons.js.map +0 -1
  333. package/lib/utils/loader-registry.d.ts.map +0 -1
  334. package/lib/utils/loader-registry.js.map +0 -1
  335. package/lib/utils/locale.d.ts.map +0 -1
  336. package/lib/utils/locale.js.map +0 -1
  337. package/lib/utils/mobile.d.ts.map +0 -1
  338. package/lib/utils/mobile.js.map +0 -1
  339. package/lib/utils/number-format.d.ts.map +0 -1
  340. package/lib/utils/number-format.js.map +0 -1
  341. package/lib/utils/parse-boolean.d.ts +0 -39
  342. package/lib/utils/parse-boolean.d.ts.map +0 -1
  343. package/lib/utils/parse-boolean.js +0 -58
  344. package/lib/utils/parse-boolean.js.map +0 -1
  345. package/lib/utils/positioning.d.ts.map +0 -1
  346. package/lib/utils/positioning.js.map +0 -1
  347. package/lib/utils/property-capture.d.ts.map +0 -1
  348. package/lib/utils/property-capture.js.map +0 -1
  349. package/lib/utils/property-manager.d.ts.map +0 -1
  350. package/lib/utils/property-manager.js.map +0 -1
  351. package/lib/utils/resize-observer.d.ts.map +0 -1
  352. package/lib/utils/resize-observer.js.map +0 -1
  353. package/lib/utils/scroll-lock.d.ts.map +0 -1
  354. package/lib/utils/scroll-lock.js.map +0 -1
  355. package/lib/utils/styles.d.ts.map +0 -1
  356. package/lib/utils/styles.js.map +0 -1
  357. package/lib/version.d.ts.map +0 -1
  358. package/lib/version.js.map +0 -1
@@ -1,478 +1,342 @@
1
- /**
2
- * Tooltip Component
3
- *
4
- * Shows helpful content on hover/focus with smart positioning.
5
- * Follows the same shadow DOM pattern as other components.
6
- *
7
- * @example
8
- * <ty-tooltip placement="top" flavor="primary" delay="600">
9
- * Helpful tooltip text
10
- * </ty-tooltip>
11
- */
12
- import { findBestPosition, placementPreferences } from '../utils/positioning.js';
1
+ import { findBestPosition, preferenceChain } from '../utils/positioning.js';
13
2
  import { ensureStyles } from '../utils/styles.js';
14
3
  import { tooltipStyles } from '../styles/tooltip.js';
15
- // ============================================================================
16
- // WeakMaps for State Management
17
- // ============================================================================
18
4
  const autoUpdateCleanup = new WeakMap();
19
5
  const eventCleanup = new WeakMap();
20
6
  const timeoutState = new WeakMap();
21
7
  const popoverElements = new WeakMap();
22
- // Cached separately from getAnchorElement()/el.parentElement — by the time
23
- // disconnectedCallback fires the element has already been removed from the
24
- // DOM, so parentElement is null and cleanup() couldn't otherwise find the
25
- // anchor to strip its aria-describedby.
26
8
  const anchorElements = new WeakMap();
27
- // ============================================================================
28
- // Helper Functions
29
- // ============================================================================
30
- /**
31
- * Normalize the flavor attribute. Any plain identifier (with optional +/-
32
- * shade suffix) is accepted — built-ins and custom flavors alike get their
33
- * colors from tokens in applyFlavorStyles(). Anything else (including
34
- * would-be CSS injection through the attribute) falls back to 'dark'.
35
- */
36
9
  function validateFlavor(flavor) {
37
- const full = flavor || 'dark';
38
- const base = full.replace(/[+-]$/, '');
39
- return /^[A-Za-z][A-Za-z0-9_-]*$/.test(base) ? full : 'dark';
10
+ const full = flavor || 'dark';
11
+ const base = full.replace(/[+-]$/, '');
12
+ return /^[A-Za-z][A-Za-z0-9_-]*$/.test(base) ? full : 'dark';
40
13
  }
41
- /**
42
- * Get timeout state for element
43
- */
44
14
  function getTimeoutState(el) {
45
- let state = timeoutState.get(el);
46
- if (!state) {
47
- state = { showTimeout: null, hideTimeout: null };
48
- timeoutState.set(el, state);
49
- }
50
- return state;
51
- }
52
- /**
53
- * Parse boolean attribute
54
- */
15
+ let state = timeoutState.get(el);
16
+ if (!state) {
17
+ state = { showTimeout: null, hideTimeout: null };
18
+ timeoutState.set(el, state);
19
+ }
20
+ return state;
21
+ }
55
22
  function parseBoolAttr(el, name) {
56
- return el.hasAttribute(name);
23
+ return el.hasAttribute(name);
57
24
  }
58
- /**
59
- * Parse integer attribute
60
- */
61
25
  function parseIntAttr(el, name, defaultValue) {
62
- const value = el.getAttribute(name);
63
- if (value === null)
64
- return defaultValue;
65
- const parsed = parseInt(value, 10);
66
- return isNaN(parsed) ? defaultValue : parsed;
67
- }
68
- /**
69
- * Read all tooltip attributes from element
70
- */
26
+ const value = el.getAttribute(name);
27
+ if (value === null)
28
+ return defaultValue;
29
+ const parsed = parseInt(value, 10);
30
+ return isNaN(parsed) ? defaultValue : parsed;
31
+ }
71
32
  function getTooltipAttributes(el) {
72
- return {
73
- placement: (el.getAttribute('placement') || 'top'),
74
- offset: parseIntAttr(el, 'offset', 8),
75
- delay: parseIntAttr(el, 'delay', 600),
76
- disabled: parseBoolAttr(el, 'disabled'),
77
- flavor: validateFlavor(el.getAttribute('flavor')),
78
- };
79
- }
80
- /**
81
- * Get the parent element (anchor)
82
- */
33
+ return {
34
+ placement: (el.getAttribute('placement') || 'top'),
35
+ offset: parseIntAttr(el, 'offset', 8),
36
+ delay: parseIntAttr(el, 'delay', 600),
37
+ disabled: parseBoolAttr(el, 'disabled'),
38
+ flavor: validateFlavor(el.getAttribute('flavor')),
39
+ };
40
+ }
83
41
  function getAnchorElement(el) {
84
- return el.parentElement;
42
+ return el.parentElement;
85
43
  }
86
- /**
87
- * Add `id` to the anchor's aria-describedby without clobbering a value the
88
- * consumer may already have set for something else (WAI-ARIA APG tooltip
89
- * pattern: append, don't overwrite).
90
- */
91
44
  function addDescribedBy(anchor, id) {
92
- const ids = (anchor.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean);
93
- if (!ids.includes(id)) {
94
- ids.push(id);
95
- anchor.setAttribute('aria-describedby', ids.join(' '));
96
- }
45
+ const ids = (anchor.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean);
46
+ if (!ids.includes(id)) {
47
+ ids.push(id);
48
+ anchor.setAttribute('aria-describedby', ids.join(' '));
49
+ }
97
50
  }
98
- /** Inverse of addDescribedBy — used on teardown. */
99
51
  function removeDescribedBy(anchor, id) {
100
- const ids = (anchor.getAttribute('aria-describedby') || '').split(/\s+/).filter((x) => x && x !== id);
101
- if (ids.length > 0) {
102
- anchor.setAttribute('aria-describedby', ids.join(' '));
103
- }
104
- else {
105
- anchor.removeAttribute('aria-describedby');
106
- }
107
- }
108
- /**
109
- * Get or create popover element using Popover API
110
- * The popover is created in document.body for top-layer placement
111
- */
52
+ const ids = (anchor.getAttribute('aria-describedby') || '').split(/\s+/).filter((x) => x && x !== id);
53
+ if (ids.length > 0) {
54
+ anchor.setAttribute('aria-describedby', ids.join(' '));
55
+ }
56
+ else {
57
+ anchor.removeAttribute('aria-describedby');
58
+ }
59
+ }
60
+ function ensureTooltipMotionStyles() {
61
+ if (document.getElementById('ty-tooltip-motion'))
62
+ return;
63
+ const style = document.createElement('style');
64
+ style.id = 'ty-tooltip-motion';
65
+ style.textContent = `
66
+ .ty-tooltip-popover:popover-open {
67
+ transition:
68
+ opacity var(--ty-tooltip-duration, 120ms) ease-out,
69
+ translate var(--ty-tooltip-duration, 120ms) ease-out;
70
+ }
71
+ @starting-style {
72
+ .ty-tooltip-popover:popover-open { opacity: 0; translate: 0 4px; }
73
+ .ty-tooltip-popover:popover-open[data-side="bottom"] { translate: 0 -4px; }
74
+ .ty-tooltip-popover:popover-open[data-side="left"] { translate: 4px 0; }
75
+ .ty-tooltip-popover:popover-open[data-side="right"] { translate: -4px 0; }
76
+ }
77
+ `;
78
+ document.head.appendChild(style);
79
+ }
112
80
  function getOrCreatePopover(el) {
113
- let popover = popoverElements.get(el);
114
- if (!popover) {
115
- // Create popover element
116
- popover = document.createElement('div');
117
- popover.id = `ty-tooltip-${Math.random().toString(36).slice(2, 11)}`;
118
- popover.setAttribute('popover', 'manual');
119
- // WAI-ARIA APG tooltip pattern: the popover needs role="tooltip" and
120
- // the trigger needs aria-describedby pointing at it, or a keyboard/
121
- // screen-reader user gets no indication the tooltip exists at all —
122
- // hover-only visibility isn't enough on its own.
123
- popover.setAttribute('role', 'tooltip');
124
- popover.className = 'ty-tooltip-popover';
125
- // Apply inline styles (since popover is outside shadow DOM, we need inline styles)
126
- const styles = `
127
- position: fixed;
128
- margin: 0;
129
- padding: 8px 12px;
130
- background: var(--ty-tooltip-bg, #262626);
131
- color: var(--ty-tooltip-color, #f5f5f5);
132
- border: none;
133
- border-radius: 6px;
134
- font-size: var(--ty-font-xs, 12px);
135
- font-weight: var(--ty-font-semibold, 600);
136
- line-height: 1.5;
137
- max-width: 250px;
138
- text-align: center;
139
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
140
- user-select: none;
141
- pointer-events: none;
142
- `;
143
- popover.style.cssText = styles;
144
- // Append to body
145
- document.body.appendChild(popover);
146
- // Store reference
147
- popoverElements.set(el, popover);
148
- const anchor = anchorElements.get(el);
149
- if (anchor)
150
- addDescribedBy(anchor, popover.id);
151
- }
152
- // Resync on every call (not just creation) — content and flavor can
153
- // change between shows, and this is eagerly called from connectedCallback
154
- // (see below) so a keyboard user tabbing straight to the trigger gets a
155
- // real aria-describedby target immediately, not one that only exists
156
- // after the (default 600ms) hover delay has already elapsed.
157
- const { flavor } = getTooltipAttributes(el);
158
- popover.setAttribute('data-flavor', flavor);
159
- // innerHTML, not textContent — the tooltip's own docs promise "Content is
160
- // any HTML nested inside the ty-tooltip element"; textContent silently
161
- // stripped it. Relocating the developer's own authored markup between two
162
- // elements they control isn't a new trust boundary (same model ty-select
163
- // already uses to clone rich option HTML into its trigger).
164
- popover.innerHTML = el.innerHTML;
165
- applyFlavorStyles(popover, flavor);
166
- return popover;
167
- }
168
- /**
169
- * Apply flavor-specific styles to popover.
170
- *
171
- * dark / light / info are hand-written extras; every other flavor —
172
- * built-in semantic or custom — is one token formula, with neutral
173
- * fallbacks so a custom flavor with missing tokens degrades gracefully.
174
- * flavor has passed validateFlavor's identifier guard, so interpolating
175
- * it into var() names is safe.
176
- */
81
+ ensureTooltipMotionStyles();
82
+ let popover = popoverElements.get(el);
83
+ if (!popover) {
84
+ popover = document.createElement('div');
85
+ popover.id = `ty-tooltip-${Math.random().toString(36).slice(2, 11)}`;
86
+ popover.setAttribute('popover', 'manual');
87
+ popover.setAttribute('role', 'tooltip');
88
+ popover.className = 'ty-tooltip-popover';
89
+ const styles = `
90
+ position: fixed;
91
+ margin: 0;
92
+ padding: 8px 12px;
93
+ background: var(--ty-tooltip-bg, #262626);
94
+ color: var(--ty-tooltip-color, #f5f5f5);
95
+ border: none;
96
+ border-radius: 6px;
97
+ font-size: var(--ty-font-xs, 12px);
98
+ font-weight: var(--ty-font-semibold, 600);
99
+ line-height: 1.5;
100
+ max-width: 250px;
101
+ text-align: center;
102
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
103
+ user-select: none;
104
+ pointer-events: none;
105
+ `;
106
+ popover.style.cssText = styles;
107
+ document.body.appendChild(popover);
108
+ popoverElements.set(el, popover);
109
+ const anchor = anchorElements.get(el);
110
+ if (anchor)
111
+ addDescribedBy(anchor, popover.id);
112
+ }
113
+ const { flavor } = getTooltipAttributes(el);
114
+ popover.setAttribute('data-flavor', flavor);
115
+ popover.innerHTML = el.innerHTML;
116
+ applyFlavorStyles(popover, flavor);
117
+ return popover;
118
+ }
177
119
  function applyFlavorStyles(popover, flavor) {
178
- // Reset to defaults first
179
- popover.style.removeProperty('background');
180
- popover.style.removeProperty('color');
181
- popover.style.removeProperty('border-color');
182
- switch (flavor) {
183
- case 'dark':
184
- // Default look — theme-INDEPENDENT on purpose (matches Material/
185
- // Bootstrap/Ant/Shoelace: a tooltip stays a fixed dark chip whether
186
- // the page is light or dark, so it always pops). Routed through the
187
- // --ty-tooltip-* tokens (defined once in :root, not redeclared in
188
- // html.dark) so consumers can retheme without a flavor.
189
- popover.style.background = 'var(--ty-tooltip-bg, #262626)';
190
- popover.style.color = 'var(--ty-tooltip-color, #f5f5f5)';
191
- popover.style.borderColor = 'var(--ty-tooltip-border, #404040)';
192
- break;
193
- case 'light':
194
- popover.style.background = 'var(--ty-surface-elevated, #ffffff)';
195
- popover.style.color = 'var(--ty-text-strong, #111827)';
196
- popover.style.borderColor = 'var(--ty-border, #e5e7eb)';
197
- break;
198
- case 'info':
199
- popover.style.background = 'var(--ty-bg-info, #06b6d4)';
200
- popover.style.color = 'var(--ty-text-strong, #f0f9ff)';
201
- popover.style.borderColor = 'var(--ty-border-info, #22d3ee)';
202
- break;
203
- default: {
204
- const base = flavor.replace(/[+-]$/, '');
205
- const shade = flavor.slice(base.length);
206
- const bgSfx = shade === '+' ? '-bold' : shade === '-' ? '-soft' : '';
207
- popover.style.background = `var(--ty-bg-${base}${bgSfx}, var(--ty-bg-neutral))`;
208
- popover.style.color = `var(--ty-color-${base}-strong, var(--ty-color-neutral-strong))`;
209
- popover.style.borderColor = `var(--ty-border-${base}, var(--ty-color-${base}))`;
210
- break;
211
- }
212
- }
213
- }
214
- /**
215
- * Update tooltip position based on current anchor/popover state
216
- */
120
+ popover.style.removeProperty('background');
121
+ popover.style.removeProperty('color');
122
+ popover.style.removeProperty('border-color');
123
+ switch (flavor) {
124
+ case 'dark':
125
+ popover.style.background = 'var(--ty-tooltip-bg, #262626)';
126
+ popover.style.color = 'var(--ty-tooltip-color, #f5f5f5)';
127
+ popover.style.borderColor = 'var(--ty-tooltip-border, #404040)';
128
+ break;
129
+ case 'light':
130
+ popover.style.background = 'var(--ty-surface-elevated, #ffffff)';
131
+ popover.style.color = 'var(--ty-text-strong, #111827)';
132
+ popover.style.borderColor = 'var(--ty-border, #e5e7eb)';
133
+ break;
134
+ case 'info':
135
+ popover.style.background = 'var(--ty-bg-info, #06b6d4)';
136
+ popover.style.color = 'var(--ty-text-strong, #f0f9ff)';
137
+ popover.style.borderColor = 'var(--ty-border-info, #22d3ee)';
138
+ break;
139
+ default: {
140
+ const base = flavor.replace(/[+-]$/, '');
141
+ const shade = flavor.slice(base.length);
142
+ const bgSfx = shade === '+' ? '-bold' : shade === '-' ? '-soft' : '';
143
+ popover.style.background = `var(--ty-bg-${base}${bgSfx}, var(--ty-bg-neutral))`;
144
+ popover.style.color = `var(--ty-color-${base}-strong, var(--ty-color-neutral-strong))`;
145
+ popover.style.borderColor = `var(--ty-border-${base}, var(--ty-color-${base}))`;
146
+ break;
147
+ }
148
+ }
149
+ }
217
150
  function updatePosition(el) {
218
- const { placement, offset } = getTooltipAttributes(el);
219
- const anchor = getAnchorElement(el);
220
- const popover = popoverElements.get(el);
221
- if (!anchor || !popover) {
222
- console.warn('[ty-tooltip] updatePosition: missing anchor or popover');
223
- return;
224
- }
225
- // Calculate preferences based on placement
226
- const preferences = placement === 'top' ? placementPreferences.tooltip :
227
- placement === 'bottom' ? ['bottom', 'top', 'left', 'right'] :
228
- placement === 'left' ? ['left', 'right', 'top', 'bottom'] :
229
- placement === 'right' ? ['right', 'left', 'top', 'bottom'] :
230
- placementPreferences.tooltip;
231
- // Use positioning engine to find best position
232
- const position = findBestPosition({
233
- targetEl: anchor,
234
- floatingEl: popover,
235
- preferences,
236
- offset,
237
- });
238
- // Apply position directly to popover
239
- popover.style.left = `${position.x}px`;
240
- popover.style.top = `${position.y}px`;
241
- }
242
- /**
243
- * Cleanup auto-update system
244
- */
151
+ const { placement, offset } = getTooltipAttributes(el);
152
+ const anchor = getAnchorElement(el);
153
+ const popover = popoverElements.get(el);
154
+ if (!anchor || !popover) {
155
+ console.warn('[ty-tooltip] updatePosition: missing anchor or popover');
156
+ return;
157
+ }
158
+ const preferences = preferenceChain(placement);
159
+ const position = findBestPosition({
160
+ targetEl: anchor,
161
+ floatingEl: popover,
162
+ preferences,
163
+ offset,
164
+ });
165
+ popover.style.left = `${position.x}px`;
166
+ popover.style.top = `${position.y}px`;
167
+ popover.dataset.side = position.placement.split('-')[0];
168
+ }
245
169
  function cleanupAutoUpdate(el) {
246
- const cleanup = autoUpdateCleanup.get(el);
247
- if (cleanup) {
248
- cleanup();
249
- autoUpdateCleanup.delete(el);
250
- }
251
- }
252
- /**
253
- * Setup auto-update system for position tracking
254
- * Note: This does NOT calculate initial position - call updatePosition() separately
255
- */
170
+ const cleanup = autoUpdateCleanup.get(el);
171
+ if (cleanup) {
172
+ cleanup();
173
+ autoUpdateCleanup.delete(el);
174
+ }
175
+ }
256
176
  function setupAutoUpdate(el) {
257
- const anchor = getAnchorElement(el);
258
- const popover = popoverElements.get(el);
259
- if (!anchor || !popover) {
260
- console.warn('[ty-tooltip] setupAutoUpdate: missing anchor or popover');
261
- return;
262
- }
263
- // Debounced update function
264
- let timeoutId = null;
265
- const debouncedUpdate = () => {
266
- if (timeoutId !== null) {
267
- clearTimeout(timeoutId);
268
- }
269
- timeoutId = window.setTimeout(() => {
270
- timeoutId = null;
271
- updatePosition(el);
272
- }, 10);
273
- };
274
- // Setup ResizeObserver for anchor and popover
275
- const resizeObserver = new ResizeObserver(debouncedUpdate);
276
- resizeObserver.observe(anchor);
277
- resizeObserver.observe(popover);
278
- // Scroll handler with requestAnimationFrame
279
- let scrollRafId = null;
280
- const handleScroll = () => {
281
- if (scrollRafId === null) {
282
- scrollRafId = requestAnimationFrame(() => {
283
- scrollRafId = null;
284
- updatePosition(el);
285
- });
286
- }
287
- };
288
- // Listen for scroll and resize
289
- window.addEventListener('scroll', handleScroll, true);
290
- window.addEventListener('resize', debouncedUpdate);
291
- // Store cleanup function
292
- const cleanup = () => {
293
- resizeObserver.disconnect();
294
- window.removeEventListener('scroll', handleScroll, true);
295
- window.removeEventListener('resize', debouncedUpdate);
296
- if (timeoutId !== null) {
297
- clearTimeout(timeoutId);
298
- }
299
- if (scrollRafId !== null) {
300
- cancelAnimationFrame(scrollRafId);
301
- }
302
- };
303
- autoUpdateCleanup.set(el, cleanup);
304
- }
305
- /**
306
- * Clear all timeouts
307
- */
177
+ const anchor = getAnchorElement(el);
178
+ const popover = popoverElements.get(el);
179
+ if (!anchor || !popover) {
180
+ console.warn('[ty-tooltip] setupAutoUpdate: missing anchor or popover');
181
+ return;
182
+ }
183
+ let timeoutId = null;
184
+ const debouncedUpdate = () => {
185
+ if (timeoutId !== null) {
186
+ clearTimeout(timeoutId);
187
+ }
188
+ timeoutId = window.setTimeout(() => {
189
+ timeoutId = null;
190
+ updatePosition(el);
191
+ }, 10);
192
+ };
193
+ const resizeObserver = new ResizeObserver(debouncedUpdate);
194
+ resizeObserver.observe(anchor);
195
+ resizeObserver.observe(popover);
196
+ let scrollRafId = null;
197
+ const handleScroll = () => {
198
+ if (scrollRafId === null) {
199
+ scrollRafId = requestAnimationFrame(() => {
200
+ scrollRafId = null;
201
+ updatePosition(el);
202
+ });
203
+ }
204
+ };
205
+ window.addEventListener('scroll', handleScroll, true);
206
+ window.addEventListener('resize', debouncedUpdate);
207
+ const cleanup = () => {
208
+ resizeObserver.disconnect();
209
+ window.removeEventListener('scroll', handleScroll, true);
210
+ window.removeEventListener('resize', debouncedUpdate);
211
+ if (timeoutId !== null) {
212
+ clearTimeout(timeoutId);
213
+ }
214
+ if (scrollRafId !== null) {
215
+ cancelAnimationFrame(scrollRafId);
216
+ }
217
+ };
218
+ autoUpdateCleanup.set(el, cleanup);
219
+ }
308
220
  function clearTimeouts(el) {
309
- const state = getTimeoutState(el);
310
- if (state.showTimeout !== null) {
311
- clearTimeout(state.showTimeout);
312
- state.showTimeout = null;
313
- }
314
- if (state.hideTimeout !== null) {
315
- clearTimeout(state.hideTimeout);
316
- state.hideTimeout = null;
317
- }
318
- }
319
- /**
320
- * Show tooltip immediately using Popover API
321
- */
221
+ const state = getTimeoutState(el);
222
+ if (state.showTimeout !== null) {
223
+ clearTimeout(state.showTimeout);
224
+ state.showTimeout = null;
225
+ }
226
+ if (state.hideTimeout !== null) {
227
+ clearTimeout(state.hideTimeout);
228
+ state.hideTimeout = null;
229
+ }
230
+ }
322
231
  function showTooltip(el) {
323
- const { disabled } = getTooltipAttributes(el);
324
- if (disabled)
325
- return;
326
- // Create popover if it doesn't exist
327
- const popover = getOrCreatePopover(el);
328
- try {
329
- // Show using Popover API
330
- popover.showPopover();
331
- el._open = true;
332
- // Position and setup observers
333
- updatePosition(el);
334
- setupAutoUpdate(el);
335
- }
336
- catch (e) {
337
- console.warn('[ty-tooltip] Failed to show popover', e);
338
- }
339
- }
340
- /**
341
- * Hide tooltip immediately using Popover API
342
- */
232
+ const { disabled } = getTooltipAttributes(el);
233
+ if (disabled)
234
+ return;
235
+ const popover = getOrCreatePopover(el);
236
+ try {
237
+ popover.showPopover();
238
+ el._open = true;
239
+ updatePosition(el);
240
+ setupAutoUpdate(el);
241
+ }
242
+ catch (e) {
243
+ console.warn('[ty-tooltip] Failed to show popover', e);
244
+ }
245
+ }
343
246
  function hideTooltip(el) {
344
- const popover = popoverElements.get(el);
345
- if (!popover)
346
- return;
347
- try {
348
- popover.hidePopover();
349
- el._open = false;
350
- cleanupAutoUpdate(el);
351
- }
352
- catch (e) {
353
- // Already hidden, ignore
354
- }
355
- }
356
- /**
357
- * Schedule tooltip to show after delay
358
- */
247
+ const popover = popoverElements.get(el);
248
+ if (!popover)
249
+ return;
250
+ try {
251
+ popover.hidePopover();
252
+ el._open = false;
253
+ cleanupAutoUpdate(el);
254
+ }
255
+ catch (e) {
256
+ }
257
+ }
359
258
  function scheduleShow(el) {
360
- const state = getTimeoutState(el);
361
- const { delay } = getTooltipAttributes(el);
362
- clearTimeouts(el);
363
- state.showTimeout = window.setTimeout(() => showTooltip(el), delay);
364
- }
365
- /**
366
- * Schedule tooltip to hide after delay
367
- */
259
+ const state = getTimeoutState(el);
260
+ const { delay } = getTooltipAttributes(el);
261
+ clearTimeouts(el);
262
+ state.showTimeout = window.setTimeout(() => showTooltip(el), delay);
263
+ }
368
264
  function scheduleHide(el) {
369
- const state = getTimeoutState(el);
370
- clearTimeouts(el);
371
- state.hideTimeout = window.setTimeout(() => hideTooltip(el), 200);
265
+ const state = getTimeoutState(el);
266
+ clearTimeouts(el);
267
+ state.hideTimeout = window.setTimeout(() => hideTooltip(el), 200);
372
268
  }
373
- /**
374
- * Setup event listeners on anchor element
375
- */
376
269
  function setupEvents(el) {
377
- const anchor = getAnchorElement(el);
378
- if (!anchor)
379
- return;
380
- anchorElements.set(el, anchor);
381
- const handleEnter = () => scheduleShow(el);
382
- const handleLeave = () => scheduleHide(el);
383
- const handleFocus = () => scheduleShow(el);
384
- const handleBlur = () => scheduleHide(el);
385
- // Add event listeners
386
- anchor.addEventListener('mouseenter', handleEnter);
387
- anchor.addEventListener('mouseleave', handleLeave);
388
- anchor.addEventListener('focusin', handleFocus);
389
- anchor.addEventListener('focusout', handleBlur);
390
- // Store cleanup function
391
- eventCleanup.set(el, () => {
392
- anchor.removeEventListener('mouseenter', handleEnter);
393
- anchor.removeEventListener('mouseleave', handleLeave);
394
- anchor.removeEventListener('focusin', handleFocus);
395
- anchor.removeEventListener('focusout', handleBlur);
396
- });
397
- }
398
- /**
399
- * Cleanup all resources including popover element
400
- */
270
+ const anchor = getAnchorElement(el);
271
+ if (!anchor)
272
+ return;
273
+ anchorElements.set(el, anchor);
274
+ const handleEnter = () => scheduleShow(el);
275
+ const handleLeave = () => scheduleHide(el);
276
+ const handleFocus = () => scheduleShow(el);
277
+ const handleBlur = () => scheduleHide(el);
278
+ anchor.addEventListener('mouseenter', handleEnter);
279
+ anchor.addEventListener('mouseleave', handleLeave);
280
+ anchor.addEventListener('focusin', handleFocus);
281
+ anchor.addEventListener('focusout', handleBlur);
282
+ eventCleanup.set(el, () => {
283
+ anchor.removeEventListener('mouseenter', handleEnter);
284
+ anchor.removeEventListener('mouseleave', handleLeave);
285
+ anchor.removeEventListener('focusin', handleFocus);
286
+ anchor.removeEventListener('focusout', handleBlur);
287
+ });
288
+ }
401
289
  function cleanup(el) {
402
- clearTimeouts(el);
403
- cleanupAutoUpdate(el);
404
- const eventsCleanup = eventCleanup.get(el);
405
- if (eventsCleanup) {
406
- eventsCleanup();
407
- eventCleanup.delete(el);
408
- }
409
- // Strip aria-describedby before removing the popover it points at — by
410
- // this point (disconnectedCallback) el.parentElement is already null, so
411
- // this must use the cached anchor, not getAnchorElement(el).
412
- const popover = popoverElements.get(el);
413
- const anchor = anchorElements.get(el);
414
- if (popover && anchor) {
415
- removeDescribedBy(anchor, popover.id);
416
- }
417
- if (popover) {
418
- popover.remove();
419
- popoverElements.delete(el);
420
- }
421
- anchorElements.delete(el);
422
- timeoutState.delete(el);
423
- }
424
- // ============================================================================
425
- // Component Definition
426
- // ============================================================================
427
- /**
428
- * TyTooltip Web Component
429
- */
290
+ clearTimeouts(el);
291
+ cleanupAutoUpdate(el);
292
+ const eventsCleanup = eventCleanup.get(el);
293
+ if (eventsCleanup) {
294
+ eventsCleanup();
295
+ eventCleanup.delete(el);
296
+ }
297
+ const popover = popoverElements.get(el);
298
+ const anchor = anchorElements.get(el);
299
+ if (popover && anchor) {
300
+ removeDescribedBy(anchor, popover.id);
301
+ }
302
+ if (popover) {
303
+ popover.remove();
304
+ popoverElements.delete(el);
305
+ }
306
+ anchorElements.delete(el);
307
+ timeoutState.delete(el);
308
+ }
430
309
  export class TyTooltip extends HTMLElement {
431
- /** Observed attributes */
432
- static get observedAttributes() {
433
- return ['placement', 'offset', 'delay', 'disabled', 'flavor'];
434
- }
435
- constructor() {
436
- super();
437
- /** Internal open state */
438
- this._open = false;
439
- this.attachShadow({ mode: 'open' });
440
- }
441
- connectedCallback() {
442
- // Initialize open state
443
- this._open = false;
444
- // Inject styles (for :host display: contents)
445
- ensureStyles(this.shadowRoot, tooltipStyles);
446
- // Setup events on anchor
447
- setupEvents(this);
448
- // Eagerly create the (hidden) popover so role="tooltip" + the anchor's
449
- // aria-describedby exist from connect, not only after the first show —
450
- // a keyboard user tabbing to the trigger must not wait out the hover
451
- // delay just to get an accessible description.
452
- getOrCreatePopover(this);
453
- }
454
- disconnectedCallback() {
455
- cleanup(this);
456
- }
457
- attributeChangedCallback(name, _oldValue, newValue) {
458
- // Restyle the popover on flavor change even while hidden — it's cached
459
- // in popoverElements once created, so a change made while closed would
460
- // otherwise be silently lost until the element is torn down.
461
- if (name === 'flavor') {
462
- const popover = popoverElements.get(this);
463
- if (popover) {
464
- const flavor = validateFlavor(newValue);
465
- applyFlavorStyles(popover, flavor);
466
- }
467
- }
468
- // Close tooltip if disabled
469
- if (name === 'disabled' && newValue !== null) {
470
- hideTooltip(this);
471
- }
472
- }
473
- }
474
- // Register the custom element
310
+ static get observedAttributes() {
311
+ return ['placement', 'offset', 'delay', 'disabled', 'flavor'];
312
+ }
313
+ constructor() {
314
+ super();
315
+ this._open = false;
316
+ this.attachShadow({ mode: 'open' });
317
+ }
318
+ connectedCallback() {
319
+ this._open = false;
320
+ ensureStyles(this.shadowRoot, tooltipStyles);
321
+ setupEvents(this);
322
+ getOrCreatePopover(this);
323
+ }
324
+ disconnectedCallback() {
325
+ cleanup(this);
326
+ }
327
+ attributeChangedCallback(name, _oldValue, newValue) {
328
+ if (name === 'flavor') {
329
+ const popover = popoverElements.get(this);
330
+ if (popover) {
331
+ const flavor = validateFlavor(newValue);
332
+ applyFlavorStyles(popover, flavor);
333
+ }
334
+ }
335
+ if (name === 'disabled' && newValue !== null) {
336
+ hideTooltip(this);
337
+ }
338
+ }
339
+ }
475
340
  if (!customElements.get('ty-tooltip')) {
476
- customElements.define('ty-tooltip', TyTooltip);
341
+ customElements.define('ty-tooltip', TyTooltip);
477
342
  }
478
- //# sourceMappingURL=tooltip.js.map