@dodlhuat/basix 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/README.md +706 -482
  2. package/css/accordion.scss +86 -87
  3. package/css/alert.scss +137 -137
  4. package/css/badge.scss +104 -0
  5. package/css/bottom-sheet.scss +192 -0
  6. package/css/breadcrumb.scss +158 -0
  7. package/css/button.scss +48 -0
  8. package/css/calendar.scss +957 -0
  9. package/css/card.scss +65 -65
  10. package/css/chart.scss +270 -157
  11. package/css/chat-bubbles.scss +134 -68
  12. package/css/chips.scss +109 -19
  13. package/css/colors.scss +32 -32
  14. package/css/context-menu.scss +182 -0
  15. package/css/datepicker.scss +336 -336
  16. package/css/defaults.scss +90 -90
  17. package/css/docs.scss +529 -0
  18. package/css/editor.scss +664 -461
  19. package/css/file-uploader.scss +1 -1
  20. package/css/flyout-menu.scss +361 -361
  21. package/css/form.scss +124 -0
  22. package/css/gallery.scss +65 -6
  23. package/css/grid.scss +41 -40
  24. package/css/group-picker.scss +345 -0
  25. package/css/guitar-chords.css +250 -250
  26. package/css/icons.scss +330 -330
  27. package/css/parameters.scss +3 -3
  28. package/css/placeholder.scss +33 -33
  29. package/css/popover.scss +206 -0
  30. package/css/progress.scss +76 -32
  31. package/css/properties.scss +51 -36
  32. package/css/push-menu.scss +302 -174
  33. package/css/reset.scss +39 -39
  34. package/css/scrollbar.scss +62 -5
  35. package/css/sidebar-nav.scss +92 -0
  36. package/css/spinner.scss +65 -65
  37. package/css/stepper.scss +248 -0
  38. package/css/style.css +4603 -273
  39. package/css/style.css.map +1 -1
  40. package/css/style.min.css +1 -1
  41. package/css/style.scss +51 -39
  42. package/css/table.scss +199 -199
  43. package/css/tabs.scss +154 -123
  44. package/css/timeline.scss +83 -38
  45. package/css/timepicker.scss +100 -5
  46. package/css/toast.scss +81 -81
  47. package/css/typography.scss +194 -161
  48. package/css/virtual-dropdown.scss +35 -29
  49. package/js/bottom-sheet.js +173 -0
  50. package/js/bottom-sheet.ts +222 -0
  51. package/js/calendar.js +532 -0
  52. package/js/calendar.ts +706 -0
  53. package/js/carousel.js +26 -13
  54. package/js/chart.js +573 -257
  55. package/js/chart.ts +692 -0
  56. package/js/code-viewer.js +10 -10
  57. package/js/code-viewer.ts +188 -188
  58. package/js/context-menu.js +212 -0
  59. package/js/context-menu.ts +252 -0
  60. package/js/datepicker.ts +627 -627
  61. package/js/docs-nav.js +204 -0
  62. package/js/dropdown.ts +179 -179
  63. package/js/editor.js +96 -38
  64. package/js/editor.ts +483 -425
  65. package/js/file-uploader.js +1 -0
  66. package/js/file-uploader.ts +1 -0
  67. package/js/flyout-menu.js +14 -14
  68. package/js/flyout-menu.ts +249 -249
  69. package/js/form-builder.js +106 -106
  70. package/js/gallery.js +13 -6
  71. package/js/gallery.ts +245 -236
  72. package/js/group-picker.js +342 -0
  73. package/js/group-picker.ts +447 -0
  74. package/js/guitar-chords.js +268 -268
  75. package/js/lazy-loader.js +121 -121
  76. package/js/modal.ts +166 -166
  77. package/js/popover.js +163 -0
  78. package/js/popover.ts +219 -0
  79. package/js/position.js +108 -0
  80. package/js/position.ts +111 -0
  81. package/js/push-menu.js +226 -113
  82. package/js/push-menu.ts +284 -145
  83. package/js/request.js +50 -50
  84. package/js/scroll.ts +47 -47
  85. package/js/scrollbar.js +13 -0
  86. package/js/scrollbar.ts +324 -307
  87. package/js/select.ts +216 -216
  88. package/js/sidebar-nav.js +41 -0
  89. package/js/sidebar-nav.ts +66 -0
  90. package/js/stepper.js +80 -0
  91. package/js/stepper.ts +104 -0
  92. package/js/table.ts +452 -452
  93. package/js/tabs.ts +279 -279
  94. package/js/theme.js +17 -6
  95. package/js/theme.ts +234 -224
  96. package/js/timepicker.js +21 -8
  97. package/js/toast.ts +137 -137
  98. package/js/tooltip.js +6 -60
  99. package/js/tooltip.ts +184 -251
  100. package/js/tsconfig.json +18 -18
  101. package/js/utils.ts +83 -83
  102. package/js/virtual-dropdown.js +25 -25
  103. package/js/virtual-dropdown.ts +365 -365
  104. package/package.json +39 -39
  105. package/fonts/Outfit-VariableFont_wght.woff +0 -0
  106. package/fonts/material-icons.woff2 +0 -0
  107. package/icons/activity-outline.svg +0 -1
  108. package/icons/alert-circle-outline.svg +0 -1
  109. package/icons/alert-triangle-outline.svg +0 -1
  110. package/icons/archive-outline.svg +0 -1
  111. package/icons/arrow-back-outline.svg +0 -1
  112. package/icons/arrow-circle-down-outline.svg +0 -1
  113. package/icons/arrow-circle-left-outline.svg +0 -1
  114. package/icons/arrow-circle-right-outline.svg +0 -1
  115. package/icons/arrow-circle-up-outline.svg +0 -1
  116. package/icons/arrow-down-outline.svg +0 -1
  117. package/icons/arrow-downward-outline.svg +0 -1
  118. package/icons/arrow-forward-outline.svg +0 -1
  119. package/icons/arrow-ios-back-outline.svg +0 -1
  120. package/icons/arrow-ios-downward-outline.svg +0 -1
  121. package/icons/arrow-ios-forward-outline.svg +0 -1
  122. package/icons/arrow-ios-upward-outline.svg +0 -1
  123. package/icons/arrow-left-outline.svg +0 -1
  124. package/icons/arrow-right-outline.svg +0 -1
  125. package/icons/arrow-up-outline.svg +0 -1
  126. package/icons/arrow-upward-outline.svg +0 -1
  127. package/icons/arrowhead-down-outline.svg +0 -1
  128. package/icons/arrowhead-left-outline.svg +0 -1
  129. package/icons/arrowhead-right-outline.svg +0 -1
  130. package/icons/arrowhead-up-outline.svg +0 -1
  131. package/icons/at-outline.svg +0 -1
  132. package/icons/attach-2-outline.svg +0 -1
  133. package/icons/attach-outline.svg +0 -1
  134. package/icons/award-outline.svg +0 -1
  135. package/icons/backspace-outline.svg +0 -1
  136. package/icons/bar-chart-2-outline.svg +0 -1
  137. package/icons/bar-chart-outline.svg +0 -1
  138. package/icons/battery-outline.svg +0 -1
  139. package/icons/behance-outline.svg +0 -1
  140. package/icons/bell-off-outline.svg +0 -1
  141. package/icons/bell-outline.svg +0 -1
  142. package/icons/bluetooth-outline.svg +0 -1
  143. package/icons/book-open-outline.svg +0 -1
  144. package/icons/book-outline.svg +0 -1
  145. package/icons/bookmark-outline.svg +0 -1
  146. package/icons/briefcase-outline.svg +0 -1
  147. package/icons/browser-outline.svg +0 -1
  148. package/icons/brush-outline.svg +0 -1
  149. package/icons/bulb-outline.svg +0 -1
  150. package/icons/calendar-outline.svg +0 -1
  151. package/icons/camera-outline.svg +0 -1
  152. package/icons/car-outline.svg +0 -1
  153. package/icons/cast-outline.svg +0 -1
  154. package/icons/charging-outline.svg +0 -1
  155. package/icons/checkmark-circle-2-outline.svg +0 -1
  156. package/icons/checkmark-circle-outline.svg +0 -1
  157. package/icons/checkmark-outline.svg +0 -1
  158. package/icons/checkmark-square-2-outline.svg +0 -1
  159. package/icons/checkmark-square-outline.svg +0 -1
  160. package/icons/chevron-down-outline.svg +0 -1
  161. package/icons/chevron-left-outline.svg +0 -1
  162. package/icons/chevron-right-outline.svg +0 -1
  163. package/icons/chevron-up-outline.svg +0 -1
  164. package/icons/clipboard-outline.svg +0 -1
  165. package/icons/clock-outline.svg +0 -1
  166. package/icons/close-circle-outline.svg +0 -1
  167. package/icons/close-outline.svg +0 -1
  168. package/icons/close-square-outline.svg +0 -1
  169. package/icons/cloud-download-outline.svg +0 -1
  170. package/icons/cloud-upload-outline.svg +0 -1
  171. package/icons/code-download-outline.svg +0 -1
  172. package/icons/code-outline.svg +0 -1
  173. package/icons/collapse-outline.svg +0 -1
  174. package/icons/color-palette-outline.svg +0 -1
  175. package/icons/color-picker-outline.svg +0 -1
  176. package/icons/compass-outline.svg +0 -1
  177. package/icons/copy-outline.svg +0 -1
  178. package/icons/corner-down-left-outline.svg +0 -1
  179. package/icons/corner-down-right-outline.svg +0 -1
  180. package/icons/corner-left-down-outline.svg +0 -1
  181. package/icons/corner-left-up-outline.svg +0 -1
  182. package/icons/corner-right-down-outline.svg +0 -1
  183. package/icons/corner-right-up-outline.svg +0 -1
  184. package/icons/corner-up-left-outline.svg +0 -1
  185. package/icons/corner-up-right-outline.svg +0 -1
  186. package/icons/credit-card-outline.svg +0 -1
  187. package/icons/crop-outline.svg +0 -1
  188. package/icons/cube-outline.svg +0 -1
  189. package/icons/diagonal-arrow-left-down-outline.svg +0 -1
  190. package/icons/diagonal-arrow-left-up-outline.svg +0 -1
  191. package/icons/diagonal-arrow-right-down-outline.svg +0 -1
  192. package/icons/diagonal-arrow-right-up-outline.svg +0 -1
  193. package/icons/done-all-outline.svg +0 -1
  194. package/icons/download-outline.svg +0 -1
  195. package/icons/droplet-off-outline.svg +0 -1
  196. package/icons/droplet-outline.svg +0 -1
  197. package/icons/edit-2-outline.svg +0 -1
  198. package/icons/edit-outline.svg +0 -1
  199. package/icons/email-outline.svg +0 -1
  200. package/icons/expand-outline.svg +0 -1
  201. package/icons/external-link-outline.svg +0 -1
  202. package/icons/eye-off-2-outline.svg +0 -1
  203. package/icons/eye-off-outline.svg +0 -1
  204. package/icons/eye-outline.svg +0 -1
  205. package/icons/facebook-outline.svg +0 -1
  206. package/icons/file-add-outline.svg +0 -1
  207. package/icons/file-outline.svg +0 -1
  208. package/icons/file-remove-outline.svg +0 -1
  209. package/icons/file-text-outline.svg +0 -1
  210. package/icons/film-outline.svg +0 -1
  211. package/icons/flag-outline.svg +0 -1
  212. package/icons/flash-off-outline.svg +0 -1
  213. package/icons/flash-outline.svg +0 -1
  214. package/icons/flip-2-outline.svg +0 -1
  215. package/icons/flip-outline.svg +0 -1
  216. package/icons/folder-add-outline.svg +0 -1
  217. package/icons/folder-outline.svg +0 -1
  218. package/icons/folder-remove-outline.svg +0 -1
  219. package/icons/funnel-outline.svg +0 -1
  220. package/icons/gift-outline.svg +0 -1
  221. package/icons/github-outline.svg +0 -1
  222. package/icons/globe-2-outline.svg +0 -1
  223. package/icons/globe-outline.svg +0 -1
  224. package/icons/google-outline.svg +0 -1
  225. package/icons/grid-outline.svg +0 -1
  226. package/icons/hard-drive-outline.svg +0 -1
  227. package/icons/hash-outline.svg +0 -1
  228. package/icons/headphones-outline.svg +0 -1
  229. package/icons/heart-outline.svg +0 -1
  230. package/icons/home-outline.svg +0 -1
  231. package/icons/image-outline.svg +0 -1
  232. package/icons/inbox-outline.svg +0 -1
  233. package/icons/info-outline.svg +0 -1
  234. package/icons/keypad-outline.svg +0 -1
  235. package/icons/layers-outline.svg +0 -1
  236. package/icons/layout-outline.svg +0 -1
  237. package/icons/link-2-outline.svg +0 -1
  238. package/icons/link-outline.svg +0 -1
  239. package/icons/linkedin-outline.svg +0 -1
  240. package/icons/list-outline.svg +0 -1
  241. package/icons/loader-outline.svg +0 -1
  242. package/icons/lock-outline.svg +0 -1
  243. package/icons/log-in-outline.svg +0 -1
  244. package/icons/log-out-outline.svg +0 -1
  245. package/icons/map-outline.svg +0 -1
  246. package/icons/maximize-outline.svg +0 -1
  247. package/icons/menu-2-outline.svg +0 -1
  248. package/icons/menu-arrow-outline.svg +0 -1
  249. package/icons/menu-outline.svg +0 -1
  250. package/icons/message-circle-outline.svg +0 -1
  251. package/icons/message-square-outline.svg +0 -1
  252. package/icons/mic-off-outline.svg +0 -1
  253. package/icons/mic-outline.svg +0 -1
  254. package/icons/minimize-outline.svg +0 -1
  255. package/icons/minus-circle-outline.svg +0 -1
  256. package/icons/minus-outline.svg +0 -1
  257. package/icons/minus-square-outline.svg +0 -1
  258. package/icons/monitor-outline.svg +0 -1
  259. package/icons/moon-outline.svg +0 -1
  260. package/icons/more-horizontal-outline.svg +0 -1
  261. package/icons/more-vertical-outline.svg +0 -1
  262. package/icons/move-outline.svg +0 -1
  263. package/icons/music-outline.svg +0 -1
  264. package/icons/navigation-2-outline.svg +0 -1
  265. package/icons/navigation-outline.svg +0 -1
  266. package/icons/npm-outline.svg +0 -1
  267. package/icons/options-2-outline.svg +0 -1
  268. package/icons/options-outline.svg +0 -1
  269. package/icons/pantone-outline.svg +0 -1
  270. package/icons/paper-plane-outline.svg +0 -1
  271. package/icons/pause-circle-outline.svg +0 -1
  272. package/icons/people-outline.svg +0 -1
  273. package/icons/percent-outline.svg +0 -1
  274. package/icons/person-add-outline.svg +0 -1
  275. package/icons/person-delete-outline.svg +0 -1
  276. package/icons/person-done-outline.svg +0 -1
  277. package/icons/person-outline.svg +0 -1
  278. package/icons/person-remove-outline.svg +0 -1
  279. package/icons/phone-call-outline.svg +0 -1
  280. package/icons/phone-missed-outline.svg +0 -1
  281. package/icons/phone-off-outline.svg +0 -1
  282. package/icons/phone-outline.svg +0 -1
  283. package/icons/pie-chart-outline.svg +0 -1
  284. package/icons/pin-outline.svg +0 -1
  285. package/icons/play-circle-outline.svg +0 -1
  286. package/icons/plus-circle-outline.svg +0 -1
  287. package/icons/plus-outline.svg +0 -1
  288. package/icons/plus-square-outline.svg +0 -1
  289. package/icons/power-outline.svg +0 -1
  290. package/icons/pricetags-outline.svg +0 -1
  291. package/icons/printer-outline.svg +0 -1
  292. package/icons/question-mark-circle-outline.svg +0 -1
  293. package/icons/question-mark-outline.svg +0 -1
  294. package/icons/radio-button-off-outline.svg +0 -1
  295. package/icons/radio-button-on-outline.svg +0 -1
  296. package/icons/radio-outline.svg +0 -1
  297. package/icons/recording-outline.svg +0 -1
  298. package/icons/refresh-outline.svg +0 -1
  299. package/icons/repeat-outline.svg +0 -1
  300. package/icons/rewind-left-outline.svg +0 -1
  301. package/icons/rewind-right-outline.svg +0 -1
  302. package/icons/save-outline.svg +0 -1
  303. package/icons/scissors-outline.svg +0 -1
  304. package/icons/search-outline.svg +0 -1
  305. package/icons/settings-2-outline.svg +0 -1
  306. package/icons/settings-outline.svg +0 -1
  307. package/icons/shake-outline.svg +0 -1
  308. package/icons/share-outline.svg +0 -1
  309. package/icons/shield-off-outline.svg +0 -1
  310. package/icons/shield-outline.svg +0 -1
  311. package/icons/shopping-bag-outline.svg +0 -1
  312. package/icons/shopping-cart-outline.svg +0 -1
  313. package/icons/shuffle-2-outline.svg +0 -1
  314. package/icons/shuffle-outline.svg +0 -1
  315. package/icons/skip-back-outline.svg +0 -1
  316. package/icons/skip-forward-outline.svg +0 -1
  317. package/icons/slash-outline.svg +0 -1
  318. package/icons/smartphone-outline.svg +0 -1
  319. package/icons/smiling-face-outline.svg +0 -1
  320. package/icons/speaker-outline.svg +0 -1
  321. package/icons/square-outline.svg +0 -1
  322. package/icons/star-outline.svg +0 -1
  323. package/icons/stop-circle-outline.svg +0 -1
  324. package/icons/sun-outline.svg +0 -1
  325. package/icons/swap-outline.svg +0 -1
  326. package/icons/sync-outline.svg +0 -1
  327. package/icons/text-outline.svg +0 -1
  328. package/icons/thermometer-minus-outline.svg +0 -1
  329. package/icons/thermometer-outline.svg +0 -1
  330. package/icons/thermometer-plus-outline.svg +0 -1
  331. package/icons/toggle-left-outline.svg +0 -1
  332. package/icons/toggle-right-outline.svg +0 -1
  333. package/icons/trash-2-outline.svg +0 -1
  334. package/icons/trash-outline.svg +0 -1
  335. package/icons/trending-down-outline.svg +0 -1
  336. package/icons/trending-up-outline.svg +0 -1
  337. package/icons/tv-outline.svg +0 -1
  338. package/icons/twitter-outline.svg +0 -1
  339. package/icons/umbrella-outline.svg +0 -1
  340. package/icons/undo-outline.svg +0 -1
  341. package/icons/unlock-outline.svg +0 -1
  342. package/icons/upload-outline.svg +0 -1
  343. package/icons/video-off-outline.svg +0 -1
  344. package/icons/video-outline.svg +0 -1
  345. package/icons/volume-down-outline.svg +0 -1
  346. package/icons/volume-mute-outline.svg +0 -1
  347. package/icons/volume-off-outline.svg +0 -1
  348. package/icons/volume-up-outline.svg +0 -1
  349. package/icons/wifi-off-outline.svg +0 -1
  350. package/icons/wifi-outline.svg +0 -1
  351. package/js/index.js +0 -718
  352. package/js/index.ts +0 -873
package/js/tooltip.ts CHANGED
@@ -1,252 +1,185 @@
1
- // tooltip.ts
2
- interface TooltipOptions {
3
- position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
4
- offset?: number;
5
- delay?: number;
6
- className?: string;
7
- }
8
-
9
- class Tooltip {
10
- private static activeTooltip: Tooltip | null = null;
11
- private static idCounter: number = 0;
12
-
13
- private readonly trigger: HTMLElement;
14
- private readonly content: string;
15
- private readonly options: Required<TooltipOptions>;
16
- private tooltipElement: HTMLDivElement | null = null;
17
- private showTimeout: number | null = null;
18
- private isVisible: boolean = false;
19
-
20
- constructor(trigger: HTMLElement, content: string, options: TooltipOptions = {}) {
21
- this.trigger = trigger;
22
- this.content = content;
23
- this.options = {
24
- position: options.position ?? 'auto',
25
- offset: options.offset ?? 8,
26
- delay: options.delay ?? 0,
27
- className: options.className ?? ''
28
- };
29
-
30
- this.attachEvents();
31
- }
32
-
33
- public static initializeAll(): void {
34
- const triggers = document.querySelectorAll<HTMLElement>('[data-tooltip]');
35
- triggers.forEach(trigger => {
36
- const content = trigger.getAttribute('data-tooltip');
37
- const position = (trigger.getAttribute('data-tooltip-position') as TooltipOptions['position']) ?? 'auto';
38
- const className = trigger.getAttribute('data-tooltip-class') ?? '';
39
-
40
- if (content) {
41
- new Tooltip(trigger, content, { position, className });
42
- }
43
- });
44
-
45
- // Also support content from separate elements
46
- const advancedTriggers = document.querySelectorAll<HTMLElement>('[data-tooltip-id]');
47
- advancedTriggers.forEach(trigger => {
48
- const contentId = trigger.getAttribute('data-tooltip-id');
49
- const position = (trigger.getAttribute('data-tooltip-position') as TooltipOptions['position']) ?? 'auto';
50
- const className = trigger.getAttribute('data-tooltip-class') ?? '';
51
-
52
- if (contentId) {
53
- const contentElement = document.getElementById(contentId);
54
- if (contentElement) {
55
- const content = contentElement.innerHTML;
56
- new Tooltip(trigger, content, { position, className });
57
- }
58
- }
59
- });
60
- }
61
-
62
- public show(): void {
63
- if (this.showTimeout !== null) {
64
- clearTimeout(this.showTimeout);
65
- }
66
-
67
- this.showTimeout = window.setTimeout(() => {
68
- Tooltip.hideActive();
69
- this.createTooltip();
70
- this.position();
71
-
72
- requestAnimationFrame(() => {
73
- this.tooltipElement?.classList.add('visible');
74
- this.isVisible = true;
75
- });
76
-
77
- Tooltip.activeTooltip = this;
78
- }, this.options.delay);
79
- }
80
-
81
- public hide(): void {
82
- if (this.showTimeout !== null) {
83
- clearTimeout(this.showTimeout);
84
- this.showTimeout = null;
85
- }
86
-
87
- if (!this.tooltipElement) return;
88
-
89
- this.tooltipElement.classList.remove('visible');
90
- this.isVisible = false;
91
-
92
- setTimeout(() => {
93
- this.tooltipElement?.remove();
94
- this.tooltipElement = null;
95
-
96
- if (Tooltip.activeTooltip === this) {
97
- Tooltip.activeTooltip = null;
98
- }
99
- }, 200);
100
- }
101
-
102
- private static hideActive(): void {
103
- if (Tooltip.activeTooltip) {
104
- Tooltip.activeTooltip.hide();
105
- }
106
- }
107
-
108
- private createTooltip(): void {
109
- const tooltip = document.createElement('div');
110
- tooltip.className = 'tooltip';
111
- tooltip.id = `tooltip-${++Tooltip.idCounter}`;
112
- tooltip.setAttribute('role', 'tooltip');
113
- tooltip.innerHTML = `<div class="tooltip-content">${this.content}</div>`;
114
-
115
- if (this.options.className) {
116
- tooltip.classList.add(this.options.className);
117
- }
118
-
119
- document.body.appendChild(tooltip);
120
- this.tooltipElement = tooltip;
121
-
122
- const previousDescribedBy = this.trigger.getAttribute('aria-describedby');
123
- this.trigger.setAttribute('aria-describedby', tooltip.id);
124
- this.trigger.setAttribute('data-previous-describedby', previousDescribedBy || '');
125
- }
126
-
127
- private position(): void {
128
- if (!this.tooltipElement) return;
129
-
130
- const triggerRect = this.trigger.getBoundingClientRect();
131
- const tooltipRect = this.tooltipElement.getBoundingClientRect();
132
-
133
- let position = this.options.position;
134
-
135
- if (position === 'auto') {
136
- position = this.determineAutoPosition(triggerRect, tooltipRect);
137
- }
138
-
139
- const coords = this.calculatePosition(position, triggerRect, tooltipRect);
140
-
141
- this.tooltipElement.style.left = `${coords.left}px`;
142
- this.tooltipElement.style.top = `${coords.top}px`;
143
- this.tooltipElement.setAttribute('data-position', position);
144
- }
145
-
146
- private determineAutoPosition(
147
- triggerRect: DOMRect,
148
- tooltipRect: DOMRect
149
- ): 'top' | 'bottom' | 'left' | 'right' {
150
- const spaceTop = triggerRect.top;
151
- const spaceBottom = window.innerHeight - triggerRect.bottom;
152
- const spaceLeft = triggerRect.left;
153
- const spaceRight = window.innerWidth - triggerRect.right;
154
-
155
- const canFitTop = spaceTop >= tooltipRect.height + this.options.offset;
156
- const canFitBottom = spaceBottom >= tooltipRect.height + this.options.offset;
157
- const canFitLeft = spaceLeft >= tooltipRect.width + this.options.offset;
158
- const canFitRight = spaceRight >= tooltipRect.width + this.options.offset;
159
-
160
- if (canFitTop && spaceTop >= Math.max(spaceBottom, spaceLeft, spaceRight)) {
161
- return 'top';
162
- } else if (canFitBottom && spaceBottom >= Math.max(spaceTop, spaceLeft, spaceRight)) {
163
- return 'bottom';
164
- } else if (canFitLeft && spaceLeft >= Math.max(spaceTop, spaceBottom, spaceRight)) {
165
- return 'left';
166
- } else if (canFitRight) {
167
- return 'right';
168
- }
169
-
170
- return spaceBottom > spaceTop ? 'bottom' : 'top';
171
- }
172
-
173
- private calculatePosition(
174
- position: 'top' | 'bottom' | 'left' | 'right',
175
- triggerRect: DOMRect,
176
- tooltipRect: DOMRect
177
- ): { left: number; top: number } {
178
- let left = 0;
179
- let top = 0;
180
-
181
- switch (position) {
182
- case 'top':
183
- left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
184
- top = triggerRect.top - tooltipRect.height - this.options.offset;
185
- break;
186
-
187
- case 'bottom':
188
- left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
189
- top = triggerRect.bottom + this.options.offset;
190
- break;
191
-
192
- case 'left':
193
- left = triggerRect.left - tooltipRect.width - this.options.offset;
194
- top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
195
- break;
196
-
197
- case 'right':
198
- left = triggerRect.right + this.options.offset;
199
- top = triggerRect.top + (triggerRect.height - tooltipRect.height) / 2;
200
- break;
201
- }
202
-
203
- // Clamp to viewport
204
- const margin = 8;
205
- left = Math.max(margin, Math.min(window.innerWidth - tooltipRect.width - margin, left));
206
- top = Math.max(margin, Math.min(window.innerHeight - tooltipRect.height - margin, top));
207
-
208
- return { left, top };
209
- }
210
-
211
- private attachEvents(): void {
212
- this.trigger.addEventListener('mouseenter', this.handleMouseEnter);
213
- this.trigger.addEventListener('mouseleave', this.handleMouseLeave);
214
- this.trigger.addEventListener('focus', this.handleFocus);
215
- this.trigger.addEventListener('blur', this.handleBlur);
216
- }
217
-
218
- private handleMouseEnter = (): void => {
219
- this.show();
220
- };
221
-
222
- private handleMouseLeave = (): void => {
223
- this.hide();
224
- };
225
-
226
- private handleFocus = (): void => {
227
- this.show();
228
- };
229
-
230
- private handleBlur = (): void => {
231
- this.hide();
232
- };
233
-
234
- public destroy(): void {
235
- this.hide();
236
- this.trigger.removeEventListener('mouseenter', this.handleMouseEnter);
237
- this.trigger.removeEventListener('mouseleave', this.handleMouseLeave);
238
- this.trigger.removeEventListener('focus', this.handleFocus);
239
- this.trigger.removeEventListener('blur', this.handleBlur);
240
-
241
- const previousDescribedBy = this.trigger.getAttribute('data-previous-describedby');
242
- if (previousDescribedBy) {
243
- this.trigger.setAttribute('aria-describedby', previousDescribedBy);
244
- } else {
245
- this.trigger.removeAttribute('aria-describedby');
246
- }
247
- this.trigger.removeAttribute('data-previous-describedby');
248
- }
249
- }
250
-
251
- export { Tooltip };
1
+ // tooltip.ts
2
+ import { computePosition } from './position.js';
3
+ import type { Placement } from './position.js';
4
+
5
+ interface TooltipOptions {
6
+ position?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
7
+ offset?: number;
8
+ delay?: number;
9
+ className?: string;
10
+ }
11
+
12
+ class Tooltip {
13
+ private static activeTooltip: Tooltip | null = null;
14
+ private static idCounter: number = 0;
15
+
16
+ private readonly trigger: HTMLElement;
17
+ private readonly content: string;
18
+ private readonly options: Required<TooltipOptions>;
19
+ private tooltipElement: HTMLDivElement | null = null;
20
+ private showTimeout: number | null = null;
21
+ private isVisible: boolean = false;
22
+
23
+ constructor(trigger: HTMLElement, content: string, options: TooltipOptions = {}) {
24
+ this.trigger = trigger;
25
+ this.content = content;
26
+ this.options = {
27
+ position: options.position ?? 'auto',
28
+ offset: options.offset ?? 8,
29
+ delay: options.delay ?? 0,
30
+ className: options.className ?? ''
31
+ };
32
+
33
+ this.attachEvents();
34
+ }
35
+
36
+ public static initializeAll(): void {
37
+ const triggers = document.querySelectorAll<HTMLElement>('[data-tooltip]');
38
+ triggers.forEach(trigger => {
39
+ const content = trigger.getAttribute('data-tooltip');
40
+ const position = (trigger.getAttribute('data-tooltip-position') as TooltipOptions['position']) ?? 'auto';
41
+ const className = trigger.getAttribute('data-tooltip-class') ?? '';
42
+
43
+ if (content) {
44
+ new Tooltip(trigger, content, { position, className });
45
+ }
46
+ });
47
+
48
+ // Also support content from separate elements
49
+ const advancedTriggers = document.querySelectorAll<HTMLElement>('[data-tooltip-id]');
50
+ advancedTriggers.forEach(trigger => {
51
+ const contentId = trigger.getAttribute('data-tooltip-id');
52
+ const position = (trigger.getAttribute('data-tooltip-position') as TooltipOptions['position']) ?? 'auto';
53
+ const className = trigger.getAttribute('data-tooltip-class') ?? '';
54
+
55
+ if (contentId) {
56
+ const contentElement = document.getElementById(contentId);
57
+ if (contentElement) {
58
+ const content = contentElement.innerHTML;
59
+ new Tooltip(trigger, content, { position, className });
60
+ }
61
+ }
62
+ });
63
+ }
64
+
65
+ public show(): void {
66
+ if (this.showTimeout !== null) {
67
+ clearTimeout(this.showTimeout);
68
+ }
69
+
70
+ this.showTimeout = window.setTimeout(() => {
71
+ Tooltip.hideActive();
72
+ this.createTooltip();
73
+ this.position();
74
+
75
+ requestAnimationFrame(() => {
76
+ this.tooltipElement?.classList.add('visible');
77
+ this.isVisible = true;
78
+ });
79
+
80
+ Tooltip.activeTooltip = this;
81
+ }, this.options.delay);
82
+ }
83
+
84
+ public hide(): void {
85
+ if (this.showTimeout !== null) {
86
+ clearTimeout(this.showTimeout);
87
+ this.showTimeout = null;
88
+ }
89
+
90
+ if (!this.tooltipElement) return;
91
+
92
+ this.tooltipElement.classList.remove('visible');
93
+ this.isVisible = false;
94
+
95
+ setTimeout(() => {
96
+ this.tooltipElement?.remove();
97
+ this.tooltipElement = null;
98
+
99
+ if (Tooltip.activeTooltip === this) {
100
+ Tooltip.activeTooltip = null;
101
+ }
102
+ }, 200);
103
+ }
104
+
105
+ private static hideActive(): void {
106
+ if (Tooltip.activeTooltip) {
107
+ Tooltip.activeTooltip.hide();
108
+ }
109
+ }
110
+
111
+ private createTooltip(): void {
112
+ const tooltip = document.createElement('div');
113
+ tooltip.className = 'tooltip';
114
+ tooltip.id = `tooltip-${++Tooltip.idCounter}`;
115
+ tooltip.setAttribute('role', 'tooltip');
116
+ tooltip.innerHTML = `<div class="tooltip-content">${this.content}</div>`;
117
+
118
+ if (this.options.className) {
119
+ tooltip.classList.add(this.options.className);
120
+ }
121
+
122
+ document.body.appendChild(tooltip);
123
+ this.tooltipElement = tooltip;
124
+
125
+ const previousDescribedBy = this.trigger.getAttribute('aria-describedby');
126
+ this.trigger.setAttribute('aria-describedby', tooltip.id);
127
+ this.trigger.setAttribute('data-previous-describedby', previousDescribedBy || '');
128
+ }
129
+
130
+ private position(): void {
131
+ if (!this.tooltipElement) return;
132
+
133
+ const { left, top, placement } = computePosition(
134
+ this.trigger.getBoundingClientRect(),
135
+ this.tooltipElement.getBoundingClientRect(),
136
+ { placement: this.options.position, offset: this.options.offset }
137
+ );
138
+
139
+ this.tooltipElement.style.left = `${left}px`;
140
+ this.tooltipElement.style.top = `${top}px`;
141
+ this.tooltipElement.setAttribute('data-position', placement);
142
+ }
143
+
144
+ private attachEvents(): void {
145
+ this.trigger.addEventListener('mouseenter', this.handleMouseEnter);
146
+ this.trigger.addEventListener('mouseleave', this.handleMouseLeave);
147
+ this.trigger.addEventListener('focus', this.handleFocus);
148
+ this.trigger.addEventListener('blur', this.handleBlur);
149
+ }
150
+
151
+ private handleMouseEnter = (): void => {
152
+ this.show();
153
+ };
154
+
155
+ private handleMouseLeave = (): void => {
156
+ this.hide();
157
+ };
158
+
159
+ private handleFocus = (): void => {
160
+ this.show();
161
+ };
162
+
163
+ private handleBlur = (): void => {
164
+ this.hide();
165
+ };
166
+
167
+ public destroy(): void {
168
+ this.hide();
169
+ this.trigger.removeEventListener('mouseenter', this.handleMouseEnter);
170
+ this.trigger.removeEventListener('mouseleave', this.handleMouseLeave);
171
+ this.trigger.removeEventListener('focus', this.handleFocus);
172
+ this.trigger.removeEventListener('blur', this.handleBlur);
173
+
174
+ const previousDescribedBy = this.trigger.getAttribute('data-previous-describedby');
175
+ if (previousDescribedBy) {
176
+ this.trigger.setAttribute('aria-describedby', previousDescribedBy);
177
+ } else {
178
+ this.trigger.removeAttribute('aria-describedby');
179
+ }
180
+ this.trigger.removeAttribute('data-previous-describedby');
181
+ }
182
+ }
183
+
184
+ export { Tooltip };
252
185
  export type { TooltipOptions };
package/js/tsconfig.json CHANGED
@@ -1,18 +1,18 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "outDir": ".",
6
- "rootDir": ".",
7
- "strict": true,
8
- "types": [],
9
- },
10
- "include": [
11
- "*.ts"
12
- ],
13
- "exclude": [
14
- "dist",
15
- "node_modules",
16
- "../node_modules"
17
- ]
18
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "outDir": ".",
6
+ "rootDir": ".",
7
+ "strict": true,
8
+ "types": [],
9
+ },
10
+ "include": [
11
+ "*.ts"
12
+ ],
13
+ "exclude": [
14
+ "dist",
15
+ "node_modules",
16
+ "../node_modules"
17
+ ]
18
+ }
package/js/utils.ts CHANGED
@@ -1,84 +1,84 @@
1
- /**
2
- * Utility functions for DOM manipulation and element handling
3
- */
4
-
5
- interface Utils {
6
- ready(fn: () => void): void;
7
- value(element: HTMLElement): string;
8
- text(element: HTMLElement): string;
9
- attribute(element: HTMLElement, attribute: string): string | undefined;
10
- isList(element: HTMLElement | NodeList): boolean;
11
- isHidden(element: HTMLElement): boolean;
12
- }
13
-
14
- const utils: Utils = {
15
- /**
16
- * Execute a function when the DOM is ready
17
- * @param fn - Callback function to execute
18
- */
19
- ready(fn: () => void): void {
20
- if (document.readyState === "complete" || document.readyState === "interactive") {
21
- setTimeout(fn, 1);
22
- } else {
23
- document.addEventListener("DOMContentLoaded", fn);
24
- }
25
- },
26
-
27
- /**
28
- * Get the value of an element from various sources
29
- * Priority: value attribute > data-value attribute > innerText
30
- * @param element - HTML element to get value from
31
- * @returns The element's value as a string
32
- */
33
- value(element: HTMLElement): string {
34
- if (element.hasAttribute('value')) {
35
- return element.getAttribute('value') || '';
36
- }
37
- if (element.hasAttribute('data-value')) {
38
- return element.getAttribute('data-value') || '';
39
- }
40
- return element.innerText;
41
- },
42
-
43
- /**
44
- * Get the text content of an element
45
- * @param element - HTML element to get text from
46
- * @returns The element's inner text
47
- */
48
- text(element: HTMLElement): string {
49
- return element.innerText;
50
- },
51
-
52
- /**
53
- * Get an attribute value from an element
54
- * @param element - HTML element to get attribute from
55
- * @param attribute - Name of the attribute to retrieve
56
- * @returns The attribute value or undefined if not present
57
- */
58
- attribute(element: HTMLElement, attribute: string): string | undefined {
59
- if (element.hasAttribute(attribute)) {
60
- return element.getAttribute(attribute) || undefined;
61
- }
62
- return undefined;
63
- },
64
-
65
- /**
66
- * Check if an element is a NodeList
67
- * @param element - Element or NodeList to check
68
- * @returns True if the element is a NodeList
69
- */
70
- isList(element: HTMLElement | NodeList): element is NodeList {
71
- return NodeList.prototype.isPrototypeOf(element);
72
- },
73
-
74
- /**
75
- * Check if an element is hidden
76
- * @param element - HTML element to check
77
- * @returns True if the element is hidden
78
- */
79
- isHidden(element: HTMLElement): boolean {
80
- return element.offsetParent === null;
81
- }
82
- };
83
-
1
+ /**
2
+ * Utility functions for DOM manipulation and element handling
3
+ */
4
+
5
+ interface Utils {
6
+ ready(fn: () => void): void;
7
+ value(element: HTMLElement): string;
8
+ text(element: HTMLElement): string;
9
+ attribute(element: HTMLElement, attribute: string): string | undefined;
10
+ isList(element: HTMLElement | NodeList): boolean;
11
+ isHidden(element: HTMLElement): boolean;
12
+ }
13
+
14
+ const utils: Utils = {
15
+ /**
16
+ * Execute a function when the DOM is ready
17
+ * @param fn - Callback function to execute
18
+ */
19
+ ready(fn: () => void): void {
20
+ if (document.readyState === "complete" || document.readyState === "interactive") {
21
+ setTimeout(fn, 1);
22
+ } else {
23
+ document.addEventListener("DOMContentLoaded", fn);
24
+ }
25
+ },
26
+
27
+ /**
28
+ * Get the value of an element from various sources
29
+ * Priority: value attribute > data-value attribute > innerText
30
+ * @param element - HTML element to get value from
31
+ * @returns The element's value as a string
32
+ */
33
+ value(element: HTMLElement): string {
34
+ if (element.hasAttribute('value')) {
35
+ return element.getAttribute('value') || '';
36
+ }
37
+ if (element.hasAttribute('data-value')) {
38
+ return element.getAttribute('data-value') || '';
39
+ }
40
+ return element.innerText;
41
+ },
42
+
43
+ /**
44
+ * Get the text content of an element
45
+ * @param element - HTML element to get text from
46
+ * @returns The element's inner text
47
+ */
48
+ text(element: HTMLElement): string {
49
+ return element.innerText;
50
+ },
51
+
52
+ /**
53
+ * Get an attribute value from an element
54
+ * @param element - HTML element to get attribute from
55
+ * @param attribute - Name of the attribute to retrieve
56
+ * @returns The attribute value or undefined if not present
57
+ */
58
+ attribute(element: HTMLElement, attribute: string): string | undefined {
59
+ if (element.hasAttribute(attribute)) {
60
+ return element.getAttribute(attribute) || undefined;
61
+ }
62
+ return undefined;
63
+ },
64
+
65
+ /**
66
+ * Check if an element is a NodeList
67
+ * @param element - Element or NodeList to check
68
+ * @returns True if the element is a NodeList
69
+ */
70
+ isList(element: HTMLElement | NodeList): element is NodeList {
71
+ return NodeList.prototype.isPrototypeOf(element);
72
+ },
73
+
74
+ /**
75
+ * Check if an element is hidden
76
+ * @param element - HTML element to check
77
+ * @returns True if the element is hidden
78
+ */
79
+ isHidden(element: HTMLElement): boolean {
80
+ return element.offsetParent === null;
81
+ }
82
+ };
83
+
84
84
  export { utils };