@dodlhuat/basix 1.2.0 → 1.2.2

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 (93) hide show
  1. package/README.md +266 -6
  2. package/css/accordion.scss +86 -87
  3. package/css/alert.scss +137 -137
  4. package/css/button.scss +48 -0
  5. package/css/calendar.scss +957 -0
  6. package/css/card.scss +65 -65
  7. package/css/chart.scss +270 -157
  8. package/css/chat-bubbles.scss +134 -68
  9. package/css/chips.scss +109 -19
  10. package/css/colors.scss +32 -32
  11. package/css/datepicker.scss +336 -336
  12. package/css/defaults.scss +90 -90
  13. package/css/docs.scss +529 -0
  14. package/css/editor.scss +36 -0
  15. package/css/file-uploader.scss +1 -1
  16. package/css/flyout-menu.scss +361 -361
  17. package/css/form.scss +0 -15
  18. package/css/gallery.scss +65 -6
  19. package/css/grid.scss +41 -40
  20. package/css/group-picker.scss +345 -0
  21. package/css/guitar-chords.css +250 -250
  22. package/css/icons.scss +330 -330
  23. package/css/parameters.scss +3 -3
  24. package/css/placeholder.scss +33 -33
  25. package/css/popover.scss +206 -0
  26. package/css/progress.scss +76 -32
  27. package/css/properties.scss +51 -36
  28. package/css/push-menu.scss +302 -174
  29. package/css/reset.scss +39 -39
  30. package/css/scrollbar.scss +62 -5
  31. package/css/sidebar-nav.scss +92 -0
  32. package/css/spinner.scss +65 -65
  33. package/css/stepper.scss +48 -12
  34. package/css/style.css +3155 -254
  35. package/css/style.css.map +1 -1
  36. package/css/style.min.css +1 -1
  37. package/css/style.scss +51 -45
  38. package/css/table.scss +199 -199
  39. package/css/tabs.scss +154 -123
  40. package/css/timeline.scss +83 -38
  41. package/css/timepicker.scss +100 -5
  42. package/css/toast.scss +81 -81
  43. package/css/virtual-dropdown.scss +35 -29
  44. package/js/calendar.js +532 -0
  45. package/js/calendar.ts +706 -0
  46. package/js/chart.js +573 -257
  47. package/js/chart.ts +692 -0
  48. package/js/code-viewer.js +10 -10
  49. package/js/code-viewer.ts +188 -188
  50. package/js/datepicker.ts +627 -627
  51. package/js/docs-nav.js +204 -0
  52. package/js/dropdown.ts +179 -179
  53. package/js/editor.js +50 -6
  54. package/js/editor.ts +483 -444
  55. package/js/file-uploader.js +1 -0
  56. package/js/file-uploader.ts +1 -0
  57. package/js/flyout-menu.js +14 -14
  58. package/js/flyout-menu.ts +249 -249
  59. package/js/form-builder.js +106 -106
  60. package/js/gallery.js +14 -8
  61. package/js/gallery.ts +245 -236
  62. package/js/group-picker.js +342 -0
  63. package/js/group-picker.ts +447 -0
  64. package/js/guitar-chords.js +268 -268
  65. package/js/lazy-loader.js +121 -121
  66. package/js/modal.ts +166 -166
  67. package/js/popover.js +163 -0
  68. package/js/popover.ts +219 -0
  69. package/js/position.js +108 -0
  70. package/js/position.ts +111 -0
  71. package/js/push-menu.js +113 -0
  72. package/js/push-menu.ts +284 -145
  73. package/js/request.js +50 -50
  74. package/js/scroll.ts +47 -47
  75. package/js/scrollbar.js +13 -0
  76. package/js/scrollbar.ts +324 -307
  77. package/js/select.ts +216 -216
  78. package/js/sidebar-nav.js +41 -0
  79. package/js/sidebar-nav.ts +66 -0
  80. package/js/table.ts +452 -452
  81. package/js/tabs.ts +279 -279
  82. package/js/theme.js +17 -6
  83. package/js/theme.ts +234 -224
  84. package/js/toast.ts +137 -137
  85. package/js/tooltip.js +6 -60
  86. package/js/tooltip.ts +184 -251
  87. package/js/tsconfig.json +18 -18
  88. package/js/utils.ts +83 -83
  89. package/js/virtual-dropdown.js +25 -25
  90. package/js/virtual-dropdown.ts +365 -365
  91. package/package.json +37 -39
  92. package/js/index.js +0 -816
  93. package/js/index.ts +0 -987
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 };