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,414 +1,283 @@
1
- /**
2
- * Popup Component
3
- *
4
- * Interactive popup component with dropdown-like behavior and tooltip positioning.
5
- * Uses parent-child relationship - popup opens on click, stays open for interaction,
6
- * closes on outside click or ESC key.
7
- *
8
- * @example
9
- * <button>
10
- * Click me
11
- * <ty-popup placement="bottom" offset="8">
12
- * <div class="ty-elevated p-4 rounded-lg">
13
- * Popup content here
14
- * </div>
15
- * </ty-popup>
16
- * </button>
17
- */
18
- import { findBestPosition } from '../utils/positioning.js';
1
+ import { findBestPosition, preferenceChain } from '../utils/positioning.js';
19
2
  import { lockScroll, unlockScroll } from '../utils/scroll-lock.js';
20
3
  import { ensureStyles } from '../utils/styles.js';
21
4
  import { popupStyles } from '../styles/popup.js';
22
- // ============================================================================
23
- // WeakMaps for State Management
24
- // ============================================================================
25
5
  const anchorClickHandlers = new WeakMap();
26
6
  const anchorKeyClickHandlers = new WeakMap();
27
7
  const outsideClickHandlers = new WeakMap();
28
8
  const escapeHandlers = new WeakMap();
29
9
  const closeRequestHandlers = new WeakMap();
30
- const popupIds = new WeakMap(); // Store popup ID for scroll locking
31
- // ============================================================================
32
- // Helper Functions
33
- // ============================================================================
34
- /**
35
- * Parse boolean attribute
36
- */
10
+ const popupIds = new WeakMap();
37
11
  function parseBoolAttr(el, name) {
38
- return el.hasAttribute(name);
12
+ return el.hasAttribute(name);
39
13
  }
40
- /**
41
- * Parse integer attribute
42
- */
43
14
  function parseIntAttr(el, name, defaultValue) {
44
- const value = el.getAttribute(name);
45
- if (value === null)
46
- return defaultValue;
47
- const parsed = parseInt(value, 10);
48
- return isNaN(parsed) ? defaultValue : parsed;
49
- }
50
- /**
51
- * Read popup attributes with simplified API
52
- */
15
+ const value = el.getAttribute(name);
16
+ if (value === null)
17
+ return defaultValue;
18
+ const parsed = parseInt(value, 10);
19
+ return isNaN(parsed) ? defaultValue : parsed;
20
+ }
53
21
  function getPopupAttributes(el) {
54
- return {
55
- manual: parseBoolAttr(el, 'manual'),
56
- disableClose: parseBoolAttr(el, 'disable-close'),
57
- placement: (el.getAttribute('placement') || 'bottom'),
58
- offset: parseIntAttr(el, 'offset', 8),
59
- };
60
- }
61
- /**
62
- * Get the parent element as anchor (like tooltip)
63
- */
22
+ return {
23
+ manual: parseBoolAttr(el, 'manual'),
24
+ disableClose: parseBoolAttr(el, 'disable-close'),
25
+ placement: (el.getAttribute('placement') || 'bottom'),
26
+ offset: parseIntAttr(el, 'offset', 8),
27
+ };
28
+ }
64
29
  function getAnchorElement(el) {
65
- return el.parentElement;
30
+ return el.parentElement;
66
31
  }
67
- /**
68
- * Get the popup dialog element
69
- */
70
32
  function getPopupDialog(shadowRoot) {
71
- return shadowRoot.querySelector('.popup-dialog');
33
+ return shadowRoot.querySelector('.popup-dialog');
72
34
  }
73
- /**
74
- * Get or create a unique popup ID for scroll locking
75
- */
76
35
  function getPopupId(el) {
77
- let id = popupIds.get(el);
78
- if (!id) {
79
- id = `popup-${el.id || Math.random().toString(36).substr(2, 9)}`;
80
- popupIds.set(el, id);
81
- }
82
- return id;
83
- }
84
- /**
85
- * Calculate and update popup position based on anchor (tooltip style)
86
- */
36
+ let id = popupIds.get(el);
37
+ if (!id) {
38
+ id = `popup-${el.id || Math.random().toString(36).substr(2, 9)}`;
39
+ popupIds.set(el, id);
40
+ }
41
+ return id;
42
+ }
87
43
  function updatePosition(el) {
88
- const { placement, offset } = getPopupAttributes(el);
89
- const shadowRoot = el.shadowRoot;
90
- const anchor = getAnchorElement(el);
91
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
92
- if (!anchor || !dialog)
93
- return;
94
- // Calculate preferred placements based on placement attribute (like tooltip)
95
- const preferences = placement === 'top' ? ['top', 'bottom', 'left', 'right'] :
96
- placement === 'bottom' ? ['bottom', 'top', 'left', 'right'] :
97
- placement === 'left' ? ['left', 'right', 'top', 'bottom'] :
98
- placement === 'right' ? ['right', 'left', 'top', 'bottom'] :
99
- ['bottom', 'top', 'right', 'left']; // Default popup placement
100
- // Use positioning engine to find best position
101
- const positionData = findBestPosition({
102
- targetEl: anchor,
103
- floatingEl: dialog,
104
- preferences,
105
- offset,
106
- padding: 8,
107
- containerPadding: 16,
108
- });
109
- // Update CSS variables with compensated coordinates
110
- el.style.setProperty('--popup-x', `${positionData.x}px`);
111
- el.style.setProperty('--popup-y', `${positionData.y}px`);
112
- // Add position class like dropdown does (this applies the variables)
113
- dialog.classList.add('position-calculated');
114
- }
115
- /**
116
- * Close popup with clean animation -> position reset -> hide sequence
117
- */
44
+ const { placement, offset } = getPopupAttributes(el);
45
+ const shadowRoot = el.shadowRoot;
46
+ const anchor = getAnchorElement(el);
47
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
48
+ if (!anchor || !dialog)
49
+ return;
50
+ const preferences = preferenceChain(placement);
51
+ const positionData = findBestPosition({
52
+ targetEl: anchor,
53
+ floatingEl: dialog,
54
+ preferences,
55
+ offset,
56
+ padding: 8,
57
+ containerPadding: 16,
58
+ });
59
+ el.style.setProperty('--popup-x', `${positionData.x}px`);
60
+ el.style.setProperty('--popup-y', `${positionData.y}px`);
61
+ dialog.dataset.side = positionData.placement.split('-')[0];
62
+ dialog.classList.add('position-calculated');
63
+ }
118
64
  function closePopup(el, force = false) {
119
- const { disableClose } = getPopupAttributes(el);
120
- if (!force && disableClose)
121
- return;
122
- const shadowRoot = el.shadowRoot;
123
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
124
- if (!dialog)
125
- return;
126
- // Don't unlock scroll here - let the dialog 'close' event handler do it
127
- // This prevents double-unlock issues
128
- dialog.classList.remove('open');
129
- dialog.classList.remove('preparing-animation');
130
- const anchor = getAnchorElement(el);
131
- if (anchor?.hasAttribute('aria-haspopup'))
132
- anchor.setAttribute('aria-expanded', 'false');
133
- setTimeout(() => {
134
- dialog.classList.remove('position-calculated');
135
- dialog.close(); // This will trigger 'close' event which unlocks scroll
136
- }, 150);
137
- // Dispatch close event
138
- el.dispatchEvent(new CustomEvent('close', { bubbles: true }));
139
- }
140
- /**
141
- * Open popup with dialog open but hidden → position → animate sequence
142
- */
65
+ const { disableClose } = getPopupAttributes(el);
66
+ if (!force && disableClose)
67
+ return;
68
+ const shadowRoot = el.shadowRoot;
69
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
70
+ if (!dialog)
71
+ return;
72
+ dialog.classList.remove('open');
73
+ dialog.classList.remove('preparing-animation');
74
+ const anchor = getAnchorElement(el);
75
+ if (anchor?.hasAttribute('aria-haspopup'))
76
+ anchor.setAttribute('aria-expanded', 'false');
77
+ setTimeout(() => {
78
+ dialog.classList.remove('position-calculated');
79
+ dialog.close();
80
+ }, 200);
81
+ }
143
82
  function openPopup(el) {
144
- // Lock scroll using the stored popup ID
145
- const popupId = getPopupId(el);
146
- lockScroll(popupId);
147
- const shadowRoot = el.shadowRoot;
148
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
149
- if (!dialog)
150
- return;
151
- // Step 1: showModal() immediately - dialog gets [open] attribute and proper layout
152
- dialog.showModal();
153
- const anchor = getAnchorElement(el);
154
- if (anchor?.hasAttribute('aria-haspopup'))
155
- anchor.setAttribute('aria-expanded', 'true');
156
- // Step 2: Wait for layout to settle, then measure and position
157
- requestAnimationFrame(() => {
158
- // Now dialog has [open] and accurate dimensions
159
- // Calculate and apply position while dialog is hidden by CSS
160
- updatePosition(el);
161
- // Step 3: Add scale transform for animation prep
162
- dialog.classList.add('preparing-animation');
163
- // Step 4: Third RAF - THEN add open class for smooth scale animation
164
- requestAnimationFrame(() => {
165
- // Now animate: scale(0.95) → scale(1) + opacity + visibility
166
- dialog.classList.add('open');
167
- // Dispatch open event
168
- el.dispatchEvent(new CustomEvent('open', { bubbles: true }));
169
- });
170
- });
171
- }
172
- /**
173
- * Toggle popup visibility
174
- */
83
+ const popupId = getPopupId(el);
84
+ lockScroll(popupId);
85
+ const shadowRoot = el.shadowRoot;
86
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
87
+ if (!dialog)
88
+ return;
89
+ dialog.showModal();
90
+ const anchor = getAnchorElement(el);
91
+ if (anchor?.hasAttribute('aria-haspopup'))
92
+ anchor.setAttribute('aria-expanded', 'true');
93
+ requestAnimationFrame(() => {
94
+ updatePosition(el);
95
+ dialog.classList.add('preparing-animation');
96
+ requestAnimationFrame(() => {
97
+ dialog.classList.add('open');
98
+ el.dispatchEvent(new CustomEvent('open'));
99
+ });
100
+ });
101
+ }
175
102
  function togglePopup(el) {
176
- const shadowRoot = el.shadowRoot;
177
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
178
- if (!dialog)
179
- return;
180
- if (dialog.classList.contains('open')) {
181
- closePopup(el);
182
- }
183
- else {
184
- openPopup(el);
185
- }
186
- }
187
- /**
188
- * Handle click on anchor element
189
- */
103
+ const shadowRoot = el.shadowRoot;
104
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
105
+ if (!dialog)
106
+ return;
107
+ if (dialog.classList.contains('open')) {
108
+ closePopup(el);
109
+ }
110
+ else {
111
+ openPopup(el);
112
+ }
113
+ }
190
114
  function handleAnchorClick(el, event) {
191
- event.preventDefault();
192
- event.stopPropagation();
193
- togglePopup(el);
115
+ event.preventDefault();
116
+ event.stopPropagation();
117
+ togglePopup(el);
194
118
  }
195
- /**
196
- * Handle clicks on the dialog element (backdrop clicks)
197
- */
198
119
  function handleOutsideClick(el, event) {
199
- event.stopPropagation();
200
- const shadowRoot = el.shadowRoot;
201
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
202
- // Close if clicking on dialog backdrop (not popup content)
203
- if (dialog && event.target === dialog) {
204
- event.preventDefault();
205
- closePopup(el);
206
- }
207
- }
208
- /**
209
- * Handle escape key press
210
- */
120
+ event.stopPropagation();
121
+ const shadowRoot = el.shadowRoot;
122
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
123
+ if (dialog && event.target === dialog) {
124
+ event.preventDefault();
125
+ closePopup(el);
126
+ }
127
+ }
211
128
  function handleEscape(el, event) {
212
- event.stopPropagation();
213
- if (event.key === 'Escape') {
214
- const { disableClose } = getPopupAttributes(el);
215
- if (disableClose) {
216
- event.preventDefault();
217
- }
218
- else {
219
- closePopup(el);
220
- }
221
- }
222
- }
223
- /**
224
- * Handle close requests from inside popup content
225
- */
129
+ event.stopPropagation();
130
+ if (event.key === 'Escape') {
131
+ const { disableClose } = getPopupAttributes(el);
132
+ if (disableClose) {
133
+ event.preventDefault();
134
+ }
135
+ else {
136
+ closePopup(el);
137
+ }
138
+ }
139
+ }
226
140
  function handleCloseRequest(el, event) {
227
- event.stopPropagation();
228
- closePopup(el, true);
141
+ event.stopPropagation();
142
+ closePopup(el, true);
229
143
  }
230
- /**
231
- * Setup click listener on anchor element (unless manual=true)
232
- */
233
144
  function setupAnchorEvents(el) {
234
- const { manual } = getPopupAttributes(el);
235
- const anchor = getAnchorElement(el);
236
- if (!anchor || manual)
237
- return;
238
- // Screen reader gets no other signal that clicking this opens something —
239
- // the popup itself is a real <dialog> (showModal()), which already gives
240
- // it role="dialog" + focus-trap for free, so only the trigger needs this.
241
- anchor.setAttribute('aria-haspopup', 'dialog');
242
- if (!anchor.hasAttribute('aria-expanded'))
243
- anchor.setAttribute('aria-expanded', 'false');
244
- // Remove any existing listeners first
245
- const existingHandler = anchorClickHandlers.get(el);
246
- if (existingHandler) {
247
- anchor.removeEventListener('pointerdown', existingHandler);
248
- }
249
- const existingKeyHandler = anchorKeyClickHandlers.get(el);
250
- if (existingKeyHandler) {
251
- anchor.removeEventListener('click', existingKeyHandler);
252
- }
253
- // Create new handlers and store references
254
- const handler = (e) => handleAnchorClick(el, e);
255
- anchorClickHandlers.set(el, handler);
256
- anchor.addEventListener('pointerdown', handler);
257
- // pointerdown covers mouse/touch; native keyboard activation (Enter/Space
258
- // on a focused anchor) fires 'click' with detail === 0, which pointerdown
259
- // never sees — without this, a keyboard-only user could focus the anchor
260
- // but had no way to open the popup (same gap fixed in ty-tabs).
261
- const keyHandler = (e) => {
262
- if (e.detail === 0)
263
- handleAnchorClick(el, e);
264
- };
265
- anchorKeyClickHandlers.set(el, keyHandler);
266
- anchor.addEventListener('click', keyHandler);
267
- }
268
- /**
269
- * Cleanup anchor event listeners
270
- */
145
+ const { manual } = getPopupAttributes(el);
146
+ const anchor = getAnchorElement(el);
147
+ if (!anchor || manual)
148
+ return;
149
+ anchor.setAttribute('aria-haspopup', 'dialog');
150
+ if (!anchor.hasAttribute('aria-expanded'))
151
+ anchor.setAttribute('aria-expanded', 'false');
152
+ const existingHandler = anchorClickHandlers.get(el);
153
+ if (existingHandler) {
154
+ anchor.removeEventListener('pointerdown', existingHandler);
155
+ }
156
+ const existingKeyHandler = anchorKeyClickHandlers.get(el);
157
+ if (existingKeyHandler) {
158
+ anchor.removeEventListener('click', existingKeyHandler);
159
+ }
160
+ const handler = (e) => handleAnchorClick(el, e);
161
+ anchorClickHandlers.set(el, handler);
162
+ anchor.addEventListener('pointerdown', handler);
163
+ const keyHandler = (e) => {
164
+ if (e.detail === 0)
165
+ handleAnchorClick(el, e);
166
+ };
167
+ anchorKeyClickHandlers.set(el, keyHandler);
168
+ anchor.addEventListener('click', keyHandler);
169
+ }
271
170
  function cleanupAnchorEvents(el) {
272
- const anchor = getAnchorElement(el);
273
- const handler = anchorClickHandlers.get(el);
274
- if (anchor && handler) {
275
- anchor.removeEventListener('pointerdown', handler);
276
- anchorClickHandlers.delete(el);
277
- }
278
- const keyHandler = anchorKeyClickHandlers.get(el);
279
- if (anchor && keyHandler) {
280
- anchor.removeEventListener('click', keyHandler);
281
- anchorKeyClickHandlers.delete(el);
282
- }
283
- anchor?.removeAttribute('aria-haspopup');
284
- anchor?.removeAttribute('aria-expanded');
285
- }
286
- /**
287
- * Render the popup structure
288
- */
171
+ const anchor = getAnchorElement(el);
172
+ const handler = anchorClickHandlers.get(el);
173
+ if (anchor && handler) {
174
+ anchor.removeEventListener('pointerdown', handler);
175
+ anchorClickHandlers.delete(el);
176
+ }
177
+ const keyHandler = anchorKeyClickHandlers.get(el);
178
+ if (anchor && keyHandler) {
179
+ anchor.removeEventListener('click', keyHandler);
180
+ anchorKeyClickHandlers.delete(el);
181
+ }
182
+ anchor?.removeAttribute('aria-haspopup');
183
+ anchor?.removeAttribute('aria-expanded');
184
+ }
289
185
  function render(el) {
290
- const shadowRoot = el.shadowRoot;
291
- if (!shadowRoot)
292
- return;
293
- const existingDialog = getPopupDialog(shadowRoot);
294
- // Ensure styles are loaded
295
- ensureStyles(shadowRoot, { css: popupStyles, id: 'ty-popup' });
296
- // Create structure if it doesn't exist
297
- if (!existingDialog) {
298
- const dialog = document.createElement('dialog');
299
- const container = document.createElement('div');
300
- const content = document.createElement('slot');
301
- dialog.className = 'popup-dialog';
302
- container.className = 'popup-container';
303
- content.id = 'popup-content';
304
- shadowRoot.appendChild(dialog);
305
- dialog.appendChild(container);
306
- container.appendChild(content);
307
- // Initialize position
308
- el.style.setProperty('--popup-x', '0px');
309
- el.style.setProperty('--popup-y', '0px');
310
- // Setup event listeners
311
- const outsideHandler = (e) => handleOutsideClick(el, e);
312
- outsideClickHandlers.set(el, outsideHandler);
313
- dialog.addEventListener('pointerdown', outsideHandler);
314
- const escapeHandler = (e) => handleEscape(el, e);
315
- escapeHandlers.set(el, escapeHandler);
316
- el.addEventListener('keydown', escapeHandler);
317
- // Handle native dialog close event
318
- dialog.addEventListener('close', () => {
319
- const popupId = getPopupId(el);
320
- unlockScroll(popupId);
321
- dialog.classList.remove('open');
322
- dialog.classList.remove('preparing-animation');
323
- el.dispatchEvent(new CustomEvent('close', { bubbles: true }));
324
- });
325
- }
326
- // Add close method to element for programmatic access
327
- el.closePopup = () => closePopup(el, true);
328
- el.openPopup = () => openPopup(el);
329
- el.togglePopup = () => togglePopup(el);
330
- // Add event listener for close requests from content
331
- const closeRequestHandler = (e) => handleCloseRequest(el, e);
332
- closeRequestHandlers.set(el, closeRequestHandler);
333
- el.addEventListener('ty:close-popup', closeRequestHandler);
334
- // Setup anchor events
335
- setupAnchorEvents(el);
336
- }
337
- /**
338
- * Cleanup all resources when component disconnects
339
- */
186
+ const shadowRoot = el.shadowRoot;
187
+ if (!shadowRoot)
188
+ return;
189
+ const existingDialog = getPopupDialog(shadowRoot);
190
+ ensureStyles(shadowRoot, { css: popupStyles, id: 'ty-popup' });
191
+ if (!existingDialog) {
192
+ const dialog = document.createElement('dialog');
193
+ const container = document.createElement('div');
194
+ const content = document.createElement('slot');
195
+ dialog.className = 'popup-dialog';
196
+ container.className = 'popup-container';
197
+ content.id = 'popup-content';
198
+ shadowRoot.appendChild(dialog);
199
+ dialog.appendChild(container);
200
+ container.appendChild(content);
201
+ el.style.setProperty('--popup-x', '0px');
202
+ el.style.setProperty('--popup-y', '0px');
203
+ const outsideHandler = (e) => handleOutsideClick(el, e);
204
+ outsideClickHandlers.set(el, outsideHandler);
205
+ dialog.addEventListener('pointerdown', outsideHandler);
206
+ const escapeHandler = (e) => handleEscape(el, e);
207
+ escapeHandlers.set(el, escapeHandler);
208
+ el.addEventListener('keydown', escapeHandler);
209
+ dialog.addEventListener('close', () => {
210
+ const popupId = getPopupId(el);
211
+ unlockScroll(popupId);
212
+ dialog.classList.remove('open');
213
+ dialog.classList.remove('preparing-animation');
214
+ el.dispatchEvent(new CustomEvent('close'));
215
+ });
216
+ }
217
+ el.closePopup = () => closePopup(el, true);
218
+ el.openPopup = () => openPopup(el);
219
+ el.togglePopup = () => togglePopup(el);
220
+ const closeRequestHandler = (e) => handleCloseRequest(el, e);
221
+ closeRequestHandlers.set(el, closeRequestHandler);
222
+ el.addEventListener('ty:close-popup', closeRequestHandler);
223
+ setupAnchorEvents(el);
224
+ }
340
225
  function cleanup(el) {
341
- // Force unlock scroll if popup is being removed
342
- const popupId = popupIds.get(el);
343
- if (popupId) {
344
- unlockScroll(popupId);
345
- popupIds.delete(el);
346
- }
347
- // Cleanup anchor events
348
- cleanupAnchorEvents(el);
349
- // Cleanup dialog events
350
- const shadowRoot = el.shadowRoot;
351
- const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
352
- if (dialog) {
353
- const outsideHandler = outsideClickHandlers.get(el);
354
- if (outsideHandler) {
355
- dialog.removeEventListener('pointerdown', outsideHandler);
356
- outsideClickHandlers.delete(el);
357
- }
358
- }
359
- const escapeHandler = escapeHandlers.get(el);
360
- if (escapeHandler) {
361
- el.removeEventListener('keydown', escapeHandler);
362
- escapeHandlers.delete(el);
363
- }
364
- const closeRequestHandler = closeRequestHandlers.get(el);
365
- if (closeRequestHandler) {
366
- el.removeEventListener('ty:close-popup', closeRequestHandler);
367
- closeRequestHandlers.delete(el);
368
- }
369
- }
370
- // ============================================================================
371
- // Component Definition
372
- // ============================================================================
373
- /**
374
- * TyPopup Web Component
375
- */
226
+ const popupId = popupIds.get(el);
227
+ if (popupId) {
228
+ unlockScroll(popupId);
229
+ popupIds.delete(el);
230
+ }
231
+ cleanupAnchorEvents(el);
232
+ const shadowRoot = el.shadowRoot;
233
+ const dialog = shadowRoot ? getPopupDialog(shadowRoot) : null;
234
+ if (dialog) {
235
+ const outsideHandler = outsideClickHandlers.get(el);
236
+ if (outsideHandler) {
237
+ dialog.removeEventListener('pointerdown', outsideHandler);
238
+ outsideClickHandlers.delete(el);
239
+ }
240
+ }
241
+ const escapeHandler = escapeHandlers.get(el);
242
+ if (escapeHandler) {
243
+ el.removeEventListener('keydown', escapeHandler);
244
+ escapeHandlers.delete(el);
245
+ }
246
+ const closeRequestHandler = closeRequestHandlers.get(el);
247
+ if (closeRequestHandler) {
248
+ el.removeEventListener('ty:close-popup', closeRequestHandler);
249
+ closeRequestHandlers.delete(el);
250
+ }
251
+ }
376
252
  export class TyPopup extends HTMLElement {
377
- /** Observed attributes */
378
- static get observedAttributes() {
379
- return ['manual', 'disable-close', 'placement', 'offset'];
380
- }
381
- constructor() {
382
- super();
383
- this.attachShadow({ mode: 'open' });
384
- }
385
- connectedCallback() {
386
- render(this);
387
- }
388
- disconnectedCallback() {
389
- cleanup(this);
390
- }
391
- attributeChangedCallback(name, _oldValue, _newValue) {
392
- // Re-render on attribute changes
393
- render(this);
394
- // Handle specific attribute changes
395
- switch (name) {
396
- case 'placement':
397
- case 'offset':
398
- // Update position immediately if open and placement-related attributes change
399
- render(this);
400
- break;
401
- case 'manual':
402
- case 'disable-close':
403
- // Recreate anchor events if manual changes
404
- cleanupAnchorEvents(this);
405
- setupAnchorEvents(this);
406
- break;
407
- }
408
- }
409
- }
410
- // Register the custom element
253
+ static get observedAttributes() {
254
+ return ['manual', 'disable-close', 'placement', 'offset'];
255
+ }
256
+ constructor() {
257
+ super();
258
+ this.attachShadow({ mode: 'open' });
259
+ }
260
+ connectedCallback() {
261
+ render(this);
262
+ }
263
+ disconnectedCallback() {
264
+ cleanup(this);
265
+ }
266
+ attributeChangedCallback(name, _oldValue, _newValue) {
267
+ render(this);
268
+ switch (name) {
269
+ case 'placement':
270
+ case 'offset':
271
+ render(this);
272
+ break;
273
+ case 'manual':
274
+ case 'disable-close':
275
+ cleanupAnchorEvents(this);
276
+ setupAnchorEvents(this);
277
+ break;
278
+ }
279
+ }
280
+ }
411
281
  if (!customElements.get('ty-popup')) {
412
- customElements.define('ty-popup', TyPopup);
282
+ customElements.define('ty-popup', TyPopup);
413
283
  }
414
- //# sourceMappingURL=popup.js.map