mtrl 0.2.2 → 0.2.3

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 (92) hide show
  1. package/.typedocignore +11 -0
  2. package/DOCS.md +153 -0
  3. package/index.ts +18 -3
  4. package/package.json +7 -2
  5. package/src/components/badge/_styles.scss +174 -0
  6. package/src/components/badge/api.ts +292 -0
  7. package/src/components/badge/badge.ts +52 -0
  8. package/src/components/badge/config.ts +68 -0
  9. package/src/components/badge/constants.ts +30 -0
  10. package/src/components/badge/features.ts +185 -0
  11. package/src/components/badge/index.ts +4 -0
  12. package/src/components/badge/types.ts +105 -0
  13. package/src/components/button/types.ts +174 -29
  14. package/src/components/carousel/_styles.scss +645 -0
  15. package/src/components/carousel/api.ts +147 -0
  16. package/src/components/carousel/carousel.ts +178 -0
  17. package/src/components/carousel/config.ts +91 -0
  18. package/src/components/carousel/constants.ts +95 -0
  19. package/src/components/carousel/features/drag.ts +388 -0
  20. package/src/components/carousel/features/index.ts +8 -0
  21. package/src/components/carousel/features/slides.ts +682 -0
  22. package/src/components/carousel/index.ts +38 -0
  23. package/src/components/carousel/types.ts +327 -0
  24. package/src/components/dialog/_styles.scss +213 -0
  25. package/src/components/dialog/api.ts +283 -0
  26. package/src/components/dialog/config.ts +113 -0
  27. package/src/components/dialog/constants.ts +32 -0
  28. package/src/components/dialog/dialog.ts +56 -0
  29. package/src/components/dialog/features.ts +713 -0
  30. package/src/components/dialog/index.ts +15 -0
  31. package/src/components/dialog/types.ts +221 -0
  32. package/src/components/progress/_styles.scss +13 -1
  33. package/src/components/progress/api.ts +2 -2
  34. package/src/components/progress/progress.ts +2 -2
  35. package/src/components/progress/types.ts +3 -0
  36. package/src/components/radios/_styles.scss +232 -0
  37. package/src/components/radios/api.ts +100 -0
  38. package/src/components/radios/config.ts +60 -0
  39. package/src/components/radios/constants.ts +28 -0
  40. package/src/components/radios/index.ts +4 -0
  41. package/src/components/radios/radio.ts +269 -0
  42. package/src/components/radios/radios.ts +42 -0
  43. package/src/components/radios/types.ts +232 -0
  44. package/src/components/sheet/_styles.scss +236 -0
  45. package/src/components/sheet/api.ts +96 -0
  46. package/src/components/sheet/config.ts +66 -0
  47. package/src/components/sheet/constants.ts +20 -0
  48. package/src/components/sheet/features/content.ts +51 -0
  49. package/src/components/sheet/features/gestures.ts +177 -0
  50. package/src/components/sheet/features/index.ts +6 -0
  51. package/src/components/sheet/features/position.ts +42 -0
  52. package/src/components/sheet/features/state.ts +116 -0
  53. package/src/components/sheet/features/title.ts +86 -0
  54. package/src/components/sheet/index.ts +4 -0
  55. package/src/components/sheet/sheet.ts +57 -0
  56. package/src/components/sheet/types.ts +266 -0
  57. package/src/components/slider/_styles.scss +518 -0
  58. package/src/components/slider/api.ts +336 -0
  59. package/src/components/slider/config.ts +145 -0
  60. package/src/components/slider/constants.ts +28 -0
  61. package/src/components/slider/features/appearance.ts +140 -0
  62. package/src/components/slider/features/disabled.ts +43 -0
  63. package/src/components/slider/features/events.ts +164 -0
  64. package/src/components/slider/features/index.ts +5 -0
  65. package/src/components/slider/features/interactions.ts +256 -0
  66. package/src/components/slider/features/keyboard.ts +114 -0
  67. package/src/components/slider/features/slider.ts +336 -0
  68. package/src/components/slider/features/structure.ts +264 -0
  69. package/src/components/slider/features/ui.ts +518 -0
  70. package/src/components/slider/index.ts +9 -0
  71. package/src/components/slider/slider.ts +58 -0
  72. package/src/components/slider/types.ts +166 -0
  73. package/src/components/tabs/_styles.scss +224 -0
  74. package/src/components/tabs/api.ts +443 -0
  75. package/src/components/tabs/config.ts +80 -0
  76. package/src/components/tabs/constants.ts +12 -0
  77. package/src/components/tabs/index.ts +4 -0
  78. package/src/components/tabs/tabs.ts +52 -0
  79. package/src/components/tabs/types.ts +247 -0
  80. package/src/components/textfield/_styles.scss +97 -4
  81. package/src/components/tooltip/_styles.scss +241 -0
  82. package/src/components/tooltip/api.ts +411 -0
  83. package/src/components/tooltip/config.ts +78 -0
  84. package/src/components/tooltip/constants.ts +27 -0
  85. package/src/components/tooltip/index.ts +4 -0
  86. package/src/components/tooltip/tooltip.ts +60 -0
  87. package/src/components/tooltip/types.ts +178 -0
  88. package/src/index.ts +9 -1
  89. package/src/styles/abstract/_variables.scss +24 -12
  90. package/tsconfig.json +22 -0
  91. package/typedoc.json +28 -0
  92. package/typedoc.simple.json +14 -0
@@ -0,0 +1,411 @@
1
+ // src/components/tooltip/api.ts
2
+ import { TooltipComponent } from './types';
3
+ import { TOOLTIP_POSITIONS, DEFAULT_OFFSET, DEFAULT_ARROW_SIZE } from './constants';
4
+
5
+ interface ApiOptions {
6
+ lifecycle: {
7
+ destroy: () => void;
8
+ };
9
+ }
10
+
11
+ interface ComponentWithElements {
12
+ element: HTMLElement;
13
+ getClass: (name: string) => string;
14
+ }
15
+
16
+ /**
17
+ * Enhances a tooltip component with API methods
18
+ * @param {ApiOptions} options - API configuration options
19
+ * @returns {Function} Higher-order function that adds API methods to component
20
+ * @internal This is an internal utility for the Tooltip component
21
+ */
22
+ export const withAPI = ({ lifecycle }: ApiOptions) =>
23
+ (component: ComponentWithElements): TooltipComponent => {
24
+ // Set up internal state
25
+ let target: HTMLElement | null = null;
26
+ let position = TOOLTIP_POSITIONS.BOTTOM;
27
+ let isVisible = false;
28
+ let showTimer: number | null = null;
29
+ let hideTimer: number | null = null;
30
+ let showDelay = 300;
31
+ let hideDelay = 100;
32
+ let showOnFocus = true;
33
+ let showOnHover = true;
34
+
35
+ // Create arrow element
36
+ const arrowElement = document.createElement('div');
37
+ arrowElement.className = `${component.getClass('tooltip')}__arrow`;
38
+ component.element.appendChild(arrowElement);
39
+
40
+ // Add to body (but hidden initially)
41
+ document.body.appendChild(component.element);
42
+ component.element.setAttribute('aria-hidden', 'true');
43
+
44
+ /**
45
+ * Calculate position based on target element and desired position
46
+ */
47
+ const calculatePosition = (): { top: number; left: number; arrowPosition?: string } => {
48
+ if (!target) return { top: 0, left: 0 };
49
+
50
+ const tooltipRect = component.element.getBoundingClientRect();
51
+ const targetRect = target.getBoundingClientRect();
52
+ const scrollY = window.scrollY || window.pageYOffset;
53
+ const scrollX = window.scrollX || window.pageXOffset;
54
+
55
+ // Default offset
56
+ const offset = DEFAULT_OFFSET;
57
+ const arrowSize = DEFAULT_ARROW_SIZE;
58
+
59
+ let top = 0;
60
+ let left = 0;
61
+ let arrowPosition: string | undefined;
62
+
63
+ // Calculate position based on position value
64
+ switch (position) {
65
+ case TOOLTIP_POSITIONS.TOP:
66
+ top = targetRect.top + scrollY - tooltipRect.height - offset;
67
+ left = targetRect.left + scrollX + (targetRect.width / 2) - (tooltipRect.width / 2);
68
+ arrowPosition = 'bottom';
69
+ break;
70
+
71
+ case TOOLTIP_POSITIONS.TOP_START:
72
+ top = targetRect.top + scrollY - tooltipRect.height - offset;
73
+ left = targetRect.left + scrollX;
74
+ arrowPosition = 'bottom-start';
75
+ break;
76
+
77
+ case TOOLTIP_POSITIONS.TOP_END:
78
+ top = targetRect.top + scrollY - tooltipRect.height - offset;
79
+ left = targetRect.left + scrollX + targetRect.width - tooltipRect.width;
80
+ arrowPosition = 'bottom-end';
81
+ break;
82
+
83
+ case TOOLTIP_POSITIONS.RIGHT:
84
+ top = targetRect.top + scrollY + (targetRect.height / 2) - (tooltipRect.height / 2);
85
+ left = targetRect.left + scrollX + targetRect.width + offset;
86
+ arrowPosition = 'left';
87
+ break;
88
+
89
+ case TOOLTIP_POSITIONS.RIGHT_START:
90
+ top = targetRect.top + scrollY;
91
+ left = targetRect.left + scrollX + targetRect.width + offset;
92
+ arrowPosition = 'left-start';
93
+ break;
94
+
95
+ case TOOLTIP_POSITIONS.RIGHT_END:
96
+ top = targetRect.top + scrollY + targetRect.height - tooltipRect.height;
97
+ left = targetRect.left + scrollX + targetRect.width + offset;
98
+ arrowPosition = 'left-end';
99
+ break;
100
+
101
+ case TOOLTIP_POSITIONS.BOTTOM:
102
+ top = targetRect.top + scrollY + targetRect.height + offset;
103
+ left = targetRect.left + scrollX + (targetRect.width / 2) - (tooltipRect.width / 2);
104
+ arrowPosition = 'top';
105
+ break;
106
+
107
+ case TOOLTIP_POSITIONS.BOTTOM_START:
108
+ top = targetRect.top + scrollY + targetRect.height + offset;
109
+ left = targetRect.left + scrollX;
110
+ arrowPosition = 'top-start';
111
+ break;
112
+
113
+ case TOOLTIP_POSITIONS.BOTTOM_END:
114
+ top = targetRect.top + scrollY + targetRect.height + offset;
115
+ left = targetRect.left + scrollX + targetRect.width - tooltipRect.width;
116
+ arrowPosition = 'top-end';
117
+ break;
118
+
119
+ case TOOLTIP_POSITIONS.LEFT:
120
+ top = targetRect.top + scrollY + (targetRect.height / 2) - (tooltipRect.height / 2);
121
+ left = targetRect.left + scrollX - tooltipRect.width - offset;
122
+ arrowPosition = 'right';
123
+ break;
124
+
125
+ case TOOLTIP_POSITIONS.LEFT_START:
126
+ top = targetRect.top + scrollY;
127
+ left = targetRect.left + scrollX - tooltipRect.width - offset;
128
+ arrowPosition = 'right-start';
129
+ break;
130
+
131
+ case TOOLTIP_POSITIONS.LEFT_END:
132
+ top = targetRect.top + scrollY + targetRect.height - tooltipRect.height;
133
+ left = targetRect.left + scrollX - tooltipRect.width - offset;
134
+ arrowPosition = 'right-end';
135
+ break;
136
+
137
+ default:
138
+ top = targetRect.top + scrollY + targetRect.height + offset;
139
+ left = targetRect.left + scrollX + (targetRect.width / 2) - (tooltipRect.width / 2);
140
+ arrowPosition = 'top';
141
+ }
142
+
143
+ // Constrain to window boundaries
144
+ const windowWidth = window.innerWidth;
145
+ const windowHeight = window.innerHeight;
146
+
147
+ // Adjust horizontal position
148
+ if (left < 0) {
149
+ left = 0;
150
+ } else if (left + tooltipRect.width > windowWidth) {
151
+ left = windowWidth - tooltipRect.width;
152
+ }
153
+
154
+ return { top, left, arrowPosition };
155
+ };
156
+
157
+ /**
158
+ * Handle events on target element
159
+ */
160
+ const addTargetEvents = (targetEl: HTMLElement) => {
161
+ if (showOnHover) {
162
+ targetEl.addEventListener('mouseenter', handleTargetMouseEnter);
163
+ targetEl.addEventListener('mouseleave', handleTargetMouseLeave);
164
+ }
165
+
166
+ if (showOnFocus) {
167
+ targetEl.addEventListener('focus', handleTargetFocus);
168
+ targetEl.addEventListener('blur', handleTargetBlur);
169
+ }
170
+ };
171
+
172
+ const removeTargetEvents = (targetEl: HTMLElement) => {
173
+ if (targetEl) {
174
+ targetEl.removeEventListener('mouseenter', handleTargetMouseEnter);
175
+ targetEl.removeEventListener('mouseleave', handleTargetMouseLeave);
176
+ targetEl.removeEventListener('focus', handleTargetFocus);
177
+ targetEl.removeEventListener('blur', handleTargetBlur);
178
+ }
179
+ };
180
+
181
+ // Event handlers
182
+ const handleTargetMouseEnter = () => api.show();
183
+ const handleTargetMouseLeave = () => api.hide();
184
+ const handleTargetFocus = () => api.show();
185
+ const handleTargetBlur = () => api.hide();
186
+
187
+ // Create the API object
188
+ const api: TooltipComponent = {
189
+ element: component.element,
190
+ target,
191
+ lifecycle,
192
+
193
+ getClass: component.getClass,
194
+
195
+ setText(text) {
196
+ // Create a text node
197
+ const contentNode = document.createTextNode(text);
198
+
199
+ // Clear existing content
200
+ while (component.element.firstChild !== arrowElement) {
201
+ component.element.removeChild(component.element.firstChild);
202
+ }
203
+
204
+ // Add new content before the arrow
205
+ component.element.insertBefore(contentNode, arrowElement);
206
+
207
+ // Update position if visible
208
+ if (isVisible) {
209
+ this.updatePosition();
210
+ }
211
+
212
+ return this;
213
+ },
214
+
215
+ getText() {
216
+ // Return text content excluding the arrow element
217
+ const clone = component.element.cloneNode(true) as HTMLElement;
218
+ const arrowClone = clone.querySelector(`.${component.getClass('tooltip')}__arrow`);
219
+ if (arrowClone) {
220
+ arrowClone.remove();
221
+ }
222
+ return clone.textContent || '';
223
+ },
224
+
225
+ setPosition(newPosition) {
226
+ // Update position value
227
+ position = newPosition;
228
+
229
+ // Update position class
230
+ const baseClass = component.getClass('tooltip');
231
+
232
+ // Remove existing position classes
233
+ const positionClasses = Object.values(TOOLTIP_POSITIONS).map(p => `${baseClass}--${p}`);
234
+ component.element.classList.remove(...positionClasses);
235
+
236
+ // Add new position class
237
+ component.element.classList.add(`${baseClass}--${newPosition}`);
238
+
239
+ // Update position if visible
240
+ if (isVisible) {
241
+ this.updatePosition();
242
+ }
243
+
244
+ return this;
245
+ },
246
+
247
+ getPosition() {
248
+ return position;
249
+ },
250
+
251
+ setTarget(newTarget) {
252
+ // Remove events from old target
253
+ if (target) {
254
+ removeTargetEvents(target);
255
+ }
256
+
257
+ // Set new target
258
+ target = newTarget;
259
+ this.target = newTarget;
260
+
261
+ // Set target's aria attributes
262
+ target.setAttribute('aria-describedby', component.element.id);
263
+
264
+ // Add events to new target
265
+ addTargetEvents(target);
266
+
267
+ // Update position if visible
268
+ if (isVisible) {
269
+ this.updatePosition();
270
+ }
271
+
272
+ return this;
273
+ },
274
+
275
+ show(immediate = false) {
276
+ // Clear any existing timers
277
+ if (showTimer !== null) {
278
+ window.clearTimeout(showTimer);
279
+ showTimer = null;
280
+ }
281
+
282
+ if (hideTimer !== null) {
283
+ window.clearTimeout(hideTimer);
284
+ hideTimer = null;
285
+ }
286
+
287
+ const showTooltip = () => {
288
+ if (!target) return this;
289
+
290
+ // Show the tooltip
291
+ component.element.setAttribute('aria-hidden', 'false');
292
+ component.element.classList.add(`${component.getClass('tooltip')}--visible`);
293
+ isVisible = true;
294
+
295
+ // Update position
296
+ this.updatePosition();
297
+
298
+ // Add resize listener
299
+ window.addEventListener('resize', handleWindowResize);
300
+ window.addEventListener('scroll', handleWindowScroll);
301
+ };
302
+
303
+ if (immediate) {
304
+ showTooltip();
305
+ } else {
306
+ showTimer = window.setTimeout(showTooltip, showDelay);
307
+ }
308
+
309
+ return this;
310
+ },
311
+
312
+ hide(immediate = false) {
313
+ // Clear any existing timers
314
+ if (hideTimer !== null) {
315
+ window.clearTimeout(hideTimer);
316
+ hideTimer = null;
317
+ }
318
+
319
+ if (showTimer !== null) {
320
+ window.clearTimeout(showTimer);
321
+ showTimer = null;
322
+ }
323
+
324
+ const hideTooltip = () => {
325
+ // Hide the tooltip
326
+ component.element.setAttribute('aria-hidden', 'true');
327
+ component.element.classList.remove(`${component.getClass('tooltip')}--visible`);
328
+ isVisible = false;
329
+
330
+ // Remove resize and scroll listeners
331
+ window.removeEventListener('resize', handleWindowResize);
332
+ window.removeEventListener('scroll', handleWindowScroll);
333
+ };
334
+
335
+ if (immediate) {
336
+ hideTooltip();
337
+ } else {
338
+ hideTimer = window.setTimeout(hideTooltip, hideDelay);
339
+ }
340
+
341
+ return this;
342
+ },
343
+
344
+ isVisible() {
345
+ return isVisible;
346
+ },
347
+
348
+ updatePosition() {
349
+ if (!target) return this;
350
+
351
+ // Calculate position
352
+ const { top, left, arrowPosition } = calculatePosition();
353
+
354
+ // Update tooltip position
355
+ component.element.style.top = `${Math.round(top)}px`;
356
+ component.element.style.left = `${Math.round(left)}px`;
357
+
358
+ // Update arrow position
359
+ if (arrowPosition) {
360
+ // Remove existing arrow position classes
361
+ arrowElement.className = `${component.getClass('tooltip')}__arrow`;
362
+ // Add new position class
363
+ arrowElement.classList.add(`${component.getClass('tooltip')}__arrow--${arrowPosition}`);
364
+ }
365
+
366
+ return this;
367
+ },
368
+
369
+ destroy() {
370
+ // Clear timers
371
+ if (showTimer !== null) {
372
+ window.clearTimeout(showTimer);
373
+ }
374
+
375
+ if (hideTimer !== null) {
376
+ window.clearTimeout(hideTimer);
377
+ }
378
+
379
+ // Remove target events
380
+ if (target) {
381
+ removeTargetEvents(target);
382
+ target.removeAttribute('aria-describedby');
383
+ }
384
+
385
+ // Remove window events
386
+ window.removeEventListener('resize', handleWindowResize);
387
+ window.removeEventListener('scroll', handleWindowScroll);
388
+
389
+ // Remove from DOM
390
+ if (component.element.parentNode) {
391
+ component.element.parentNode.removeChild(component.element);
392
+ }
393
+
394
+ // Call lifecycle destroy
395
+ lifecycle.destroy();
396
+ }
397
+ };
398
+
399
+ // Window event handlers
400
+ const handleWindowResize = () => {
401
+ api.updatePosition();
402
+ };
403
+
404
+ const handleWindowScroll = () => {
405
+ api.updatePosition();
406
+ };
407
+
408
+ return api;
409
+ };
410
+
411
+ export default withAPI;
@@ -0,0 +1,78 @@
1
+ // src/components/tooltip/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig
5
+ } from '../../core/config/component-config';
6
+ import { TooltipConfig } from './types';
7
+ import {
8
+ TOOLTIP_POSITIONS,
9
+ TOOLTIP_VARIANTS,
10
+ DEFAULT_SHOW_DELAY,
11
+ DEFAULT_HIDE_DELAY
12
+ } from './constants';
13
+
14
+ /**
15
+ * Default configuration for the Tooltip component
16
+ */
17
+ export const defaultConfig: TooltipConfig = {
18
+ position: TOOLTIP_POSITIONS.BOTTOM,
19
+ variant: TOOLTIP_VARIANTS.DEFAULT,
20
+ visible: false,
21
+ showDelay: DEFAULT_SHOW_DELAY,
22
+ hideDelay: DEFAULT_HIDE_DELAY,
23
+ showOnFocus: true,
24
+ showOnHover: true,
25
+ rich: false
26
+ };
27
+
28
+ /**
29
+ * Creates the base configuration for Tooltip component
30
+ * @param {TooltipConfig} config - User provided configuration
31
+ * @returns {TooltipConfig} Complete configuration with defaults applied
32
+ */
33
+ export const createBaseConfig = (config: TooltipConfig = {}): TooltipConfig =>
34
+ createComponentConfig(defaultConfig, config, 'tooltip') as TooltipConfig;
35
+
36
+ /**
37
+ * Generates element configuration for the Tooltip component
38
+ * @param {TooltipConfig} config - Tooltip configuration
39
+ * @returns {Object} Element configuration object for withElement
40
+ */
41
+ export const getElementConfig = (config: TooltipConfig) => {
42
+ // Create the attributes object
43
+ const attrs: Record<string, any> = {
44
+ role: 'tooltip',
45
+ 'aria-hidden': 'true'
46
+ };
47
+
48
+ // Add z-index if provided
49
+ if (config.zIndex !== undefined) {
50
+ attrs['style'] = `z-index: ${config.zIndex};`;
51
+ }
52
+
53
+ const extraClasses: string[] = [
54
+ `--${config.position}`,
55
+ `--${config.variant}`
56
+ ];
57
+
58
+ return createElementConfig(config, {
59
+ tag: 'div',
60
+ attrs,
61
+ className: config.class,
62
+ extraClasses,
63
+ content: config.text || ''
64
+ });
65
+ };
66
+
67
+ /**
68
+ * Creates API configuration for the Tooltip component
69
+ * @param {Object} comp - Component with lifecycle feature
70
+ * @returns {Object} API configuration object
71
+ */
72
+ export const getApiConfig = (comp) => ({
73
+ lifecycle: {
74
+ destroy: () => comp.lifecycle.destroy()
75
+ }
76
+ });
77
+
78
+ export default defaultConfig;
@@ -0,0 +1,27 @@
1
+ // src/components/tooltip/constants.ts
2
+
3
+ export const TOOLTIP_POSITIONS = {
4
+ TOP: 'top',
5
+ RIGHT: 'right',
6
+ BOTTOM: 'bottom',
7
+ LEFT: 'left',
8
+ TOP_START: 'top-start',
9
+ TOP_END: 'top-end',
10
+ RIGHT_START: 'right-start',
11
+ RIGHT_END: 'right-end',
12
+ BOTTOM_START: 'bottom-start',
13
+ BOTTOM_END: 'bottom-end',
14
+ LEFT_START: 'left-start',
15
+ LEFT_END: 'left-end'
16
+ }
17
+
18
+ export const TOOLTIP_VARIANTS = {
19
+ DEFAULT: 'default',
20
+ RICH: 'rich',
21
+ PLAIN: 'plain'
22
+ }
23
+
24
+ export const DEFAULT_SHOW_DELAY = 300
25
+ export const DEFAULT_HIDE_DELAY = 100
26
+ export const DEFAULT_OFFSET = 8
27
+ export const DEFAULT_ARROW_SIZE = 8
@@ -0,0 +1,4 @@
1
+ // src/components/tooltip/index.ts
2
+ export { default } from './tooltip';
3
+ export { TOOLTIP_POSITIONS, TOOLTIP_VARIANTS } from './constants';
4
+ export { TooltipConfig, TooltipComponent } from './types';
@@ -0,0 +1,60 @@
1
+ // src/components/tooltip/tooltip.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import { withLifecycle } from '../../core/compose/features';
6
+ import { withAPI } from './api';
7
+ import { TooltipConfig } from './types';
8
+ import { createBaseConfig, getElementConfig, getApiConfig } from './config';
9
+
10
+ /**
11
+ * Creates a unique ID for the tooltip
12
+ * @returns {string} Unique ID
13
+ */
14
+ const createTooltipId = (): string => {
15
+ return `${PREFIX}-tooltip-${Math.random().toString(36).substring(2, 9)}`;
16
+ };
17
+
18
+ /**
19
+ * Creates a new Tooltip component
20
+ * @param {TooltipConfig} config - Tooltip configuration object
21
+ * @returns {TooltipComponent} Tooltip component instance
22
+ */
23
+ const createTooltip = (config: TooltipConfig = {}) => {
24
+ const baseConfig = createBaseConfig(config);
25
+
26
+ try {
27
+ // Create the tooltip element
28
+ const tooltip = pipe(
29
+ createBase,
30
+ withElement(getElementConfig(baseConfig)),
31
+ withLifecycle(),
32
+ comp => withAPI(getApiConfig(comp))(comp)
33
+ )(baseConfig);
34
+
35
+ // Generate a unique ID
36
+ tooltip.element.id = createTooltipId();
37
+
38
+ // Set target if provided
39
+ if (baseConfig.target) {
40
+ tooltip.setTarget(baseConfig.target);
41
+ }
42
+
43
+ // Set text if provided
44
+ if (baseConfig.text) {
45
+ tooltip.setText(baseConfig.text);
46
+ }
47
+
48
+ // Show tooltip if initially visible
49
+ if (baseConfig.visible) {
50
+ tooltip.show(true);
51
+ }
52
+
53
+ return tooltip;
54
+ } catch (error) {
55
+ console.error('Tooltip creation error:', error);
56
+ throw new Error(`Failed to create tooltip: ${(error as Error).message}`);
57
+ }
58
+ };
59
+
60
+ export default createTooltip;