mtrl 0.2.2 → 0.2.4

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 (97) 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/core/build/_ripple.scss +79 -0
  89. package/src/core/build/constants.ts +48 -0
  90. package/src/core/build/icon.ts +137 -0
  91. package/src/core/build/ripple.ts +216 -0
  92. package/src/core/build/text.ts +91 -0
  93. package/src/index.ts +9 -1
  94. package/src/styles/abstract/_variables.scss +24 -12
  95. package/tsconfig.json +22 -0
  96. package/typedoc.json +28 -0
  97. package/typedoc.simple.json +14 -0
@@ -0,0 +1,443 @@
1
+ // src/components/tabs/api.ts
2
+ import { TabsComponent, TabItem, TabChangeEventData } from './types';
3
+ import { ANIMATION_DURATION } from './constants';
4
+
5
+ interface ApiOptions {
6
+ disabled: {
7
+ enable: () => void;
8
+ disable: () => void;
9
+ isDisabled: () => boolean;
10
+ };
11
+ lifecycle: {
12
+ destroy: () => void;
13
+ };
14
+ }
15
+
16
+ interface ComponentWithElements {
17
+ element: HTMLElement;
18
+ getClass: (name: string) => string;
19
+ events: {
20
+ emit: (name: string, data?: any) => void;
21
+ on: (name: string, handler: Function) => any;
22
+ off: (name: string, handler: Function) => any;
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Creates DOM elements for the tabs component
28
+ * @param component - Base component with element and class getter
29
+ * @returns Component with tabs-specific elements
30
+ */
31
+ const setupElements = (component: ComponentWithElements) => {
32
+ const baseClass = component.getClass('tabs');
33
+
34
+ // Create tabs list container
35
+ const tabsListElement = document.createElement('div');
36
+ tabsListElement.className = `${baseClass}__list`;
37
+ tabsListElement.setAttribute('role', 'none');
38
+
39
+ // Create tabs indicator
40
+ const indicatorElement = document.createElement('span');
41
+ indicatorElement.className = `${baseClass}__indicator`;
42
+
43
+ // Append elements to container
44
+ component.element.appendChild(tabsListElement);
45
+ component.element.appendChild(indicatorElement);
46
+
47
+ return {
48
+ ...component,
49
+ tabsListElement,
50
+ indicatorElement
51
+ };
52
+ };
53
+
54
+ /**
55
+ * Enhances a tabs component with API methods
56
+ * @param {ApiOptions} options - API configuration options
57
+ * @returns {Function} Higher-order function that adds API methods to component
58
+ * @internal This is an internal utility for the Tabs component
59
+ */
60
+ export const withAPI = ({ disabled, lifecycle }: ApiOptions) =>
61
+ (component: ReturnType<typeof setupElements>): TabsComponent => {
62
+ // Set up internal state
63
+ let items: TabItem[] = [];
64
+ let activeIndex = -1;
65
+
66
+ // Set up the component with DOM elements
67
+ const enhancedComponent = setupElements(component);
68
+
69
+ // Function to create a tab element
70
+ const createTabElement = (item: TabItem, index: number) => {
71
+ const baseClass = component.getClass('tabs');
72
+ const tabElement = document.createElement('button');
73
+
74
+ tabElement.className = `${baseClass}__tab`;
75
+ tabElement.setAttribute('role', 'tab');
76
+ tabElement.setAttribute('type', 'button');
77
+ tabElement.setAttribute('data-tab-id', item.id);
78
+ tabElement.setAttribute('data-tab-index', index.toString());
79
+ tabElement.setAttribute('aria-selected', 'false');
80
+
81
+ if (item.disabled) {
82
+ tabElement.disabled = true;
83
+ tabElement.setAttribute('aria-disabled', 'true');
84
+ }
85
+
86
+ // Create content container
87
+ const contentElement = document.createElement('div');
88
+ contentElement.className = `${baseClass}__tab-content`;
89
+
90
+ // Add icon if provided
91
+ if (item.icon) {
92
+ const iconElement = document.createElement('div');
93
+ iconElement.className = `${baseClass}__tab-icon`;
94
+ iconElement.innerHTML = item.icon;
95
+ contentElement.appendChild(iconElement);
96
+ }
97
+
98
+ // Add label
99
+ const labelElement = document.createElement('div');
100
+ labelElement.className = `${baseClass}__tab-label`;
101
+ labelElement.textContent = item.label;
102
+ contentElement.appendChild(labelElement);
103
+
104
+ tabElement.appendChild(contentElement);
105
+
106
+ // Add click event
107
+ tabElement.addEventListener('click', () => {
108
+ if (!tabElement.disabled && !disabled.isDisabled()) {
109
+ const clickedIndex = parseInt(tabElement.getAttribute('data-tab-index') || '0', 10);
110
+ api.setActiveTab(clickedIndex);
111
+ }
112
+ });
113
+
114
+ return tabElement;
115
+ };
116
+
117
+ // Function to update the indicator position
118
+ const updateIndicator = (animate = true) => {
119
+ if (activeIndex < 0 || !items.length) {
120
+ // Hide indicator if no active tab
121
+ enhancedComponent.indicatorElement.style.transform = 'translateX(-100%)';
122
+ return;
123
+ }
124
+
125
+ // Find the active tab element
126
+ const tabElement = enhancedComponent.tabsListElement.querySelector(
127
+ `[data-tab-index="${activeIndex}"]`
128
+ ) as HTMLElement;
129
+
130
+ if (!tabElement) return;
131
+
132
+ // Calculate position
133
+ const tabRect = tabElement.getBoundingClientRect();
134
+ const listRect = enhancedComponent.tabsListElement.getBoundingClientRect();
135
+
136
+ const left = tabElement.offsetLeft;
137
+ const width = tabRect.width;
138
+
139
+ // Update indicator style
140
+ enhancedComponent.indicatorElement.style.transition = animate ?
141
+ `transform ${ANIMATION_DURATION}ms cubic-bezier(0.4, 0, 0.2, 1)` : 'none';
142
+ enhancedComponent.indicatorElement.style.transform = `translateX(${left}px)`;
143
+ enhancedComponent.indicatorElement.style.width = `${width}px`;
144
+
145
+ // Scroll into view if needed
146
+ if (enhancedComponent.element.classList.contains(`${component.getClass('tabs')}--scrollable`)) {
147
+ const scrollLeft = enhancedComponent.tabsListElement.scrollLeft;
148
+ const listWidth = listRect.width;
149
+
150
+ if (left < scrollLeft) {
151
+ enhancedComponent.tabsListElement.scrollTo({
152
+ left: left,
153
+ behavior: animate ? 'smooth' : 'auto'
154
+ });
155
+ } else if (left + width > scrollLeft + listWidth) {
156
+ enhancedComponent.tabsListElement.scrollTo({
157
+ left: left + width - listWidth,
158
+ behavior: animate ? 'smooth' : 'auto'
159
+ });
160
+ }
161
+ }
162
+ };
163
+
164
+ // Function to update tab elements' states
165
+ const updateTabStates = () => {
166
+ // Update aria-selected for all tabs
167
+ const tabElements = enhancedComponent.tabsListElement.querySelectorAll('[role="tab"]');
168
+
169
+ tabElements.forEach((tab: Element) => {
170
+ const index = parseInt(tab.getAttribute('data-tab-index') || '-1', 10);
171
+ tab.setAttribute('aria-selected', index === activeIndex ? 'true' : 'false');
172
+
173
+ if (index === activeIndex) {
174
+ tab.classList.add(`${component.getClass('tabs')}__tab--active`);
175
+ } else {
176
+ tab.classList.remove(`${component.getClass('tabs')}__tab--active`);
177
+ }
178
+ });
179
+ };
180
+
181
+ // Create the API object
182
+ const api: TabsComponent = {
183
+ ...enhancedComponent as any,
184
+ element: enhancedComponent.element,
185
+ tabsListElement: enhancedComponent.tabsListElement,
186
+ indicatorElement: enhancedComponent.indicatorElement,
187
+ disabled,
188
+ lifecycle,
189
+
190
+ getClass: component.getClass,
191
+
192
+ enable() {
193
+ disabled.enable();
194
+ this.element.removeAttribute('aria-disabled');
195
+ return this;
196
+ },
197
+
198
+ disable() {
199
+ disabled.disable();
200
+ this.element.setAttribute('aria-disabled', 'true');
201
+ return this;
202
+ },
203
+
204
+ getItems() {
205
+ return [...items];
206
+ },
207
+
208
+ setItems(newItems) {
209
+ // Clear existing tabs
210
+ while (this.tabsListElement.firstChild) {
211
+ this.tabsListElement.removeChild(this.tabsListElement.firstChild);
212
+ }
213
+
214
+ // Store items and create elements
215
+ items = [...newItems];
216
+
217
+ // Create tab elements
218
+ items.forEach((item, index) => {
219
+ const tabElement = createTabElement(item, index);
220
+ this.tabsListElement.appendChild(tabElement);
221
+ });
222
+
223
+ // Reset active tab if needed
224
+ if (activeIndex >= items.length) {
225
+ activeIndex = items.length > 0 ? 0 : -1;
226
+ }
227
+
228
+ // Update UI
229
+ updateTabStates();
230
+ updateIndicator(false);
231
+
232
+ return this;
233
+ },
234
+
235
+ addTab(item, index) {
236
+ const newItems = [...items];
237
+
238
+ if (index !== undefined && index >= 0 && index <= items.length) {
239
+ // Insert at specific position
240
+ newItems.splice(index, 0, item);
241
+
242
+ // Adjust active index if needed
243
+ if (activeIndex >= index) {
244
+ activeIndex++;
245
+ }
246
+ } else {
247
+ // Append to end
248
+ newItems.push(item);
249
+ }
250
+
251
+ return this.setItems(newItems);
252
+ },
253
+
254
+ removeTab(idOrIndex) {
255
+ if (items.length === 0) return this;
256
+
257
+ let index = -1;
258
+
259
+ if (typeof idOrIndex === 'number') {
260
+ index = idOrIndex;
261
+ } else {
262
+ // Find by ID
263
+ index = items.findIndex(item => item.id === idOrIndex);
264
+ }
265
+
266
+ if (index < 0 || index >= items.length) return this;
267
+
268
+ const newItems = items.filter((_, i) => i !== index);
269
+
270
+ // Handle active index adjustment
271
+ let newActiveIndex = activeIndex;
272
+
273
+ if (activeIndex === index) {
274
+ // Removed active tab, select a new one
275
+ if (newItems.length > 0) {
276
+ newActiveIndex = Math.min(activeIndex, newItems.length - 1);
277
+ } else {
278
+ newActiveIndex = -1;
279
+ }
280
+ } else if (activeIndex > index) {
281
+ // Active tab is after removed tab, adjust index
282
+ newActiveIndex--;
283
+ }
284
+
285
+ // Update items
286
+ items = newItems;
287
+
288
+ // Rebuild the tabs
289
+ this.setItems(newItems);
290
+
291
+ // Set the correct active tab
292
+ if (newActiveIndex >= 0) {
293
+ this.setActiveTab(newActiveIndex);
294
+ }
295
+
296
+ return this;
297
+ },
298
+
299
+ getActiveTab() {
300
+ return activeIndex >= 0 && activeIndex < items.length ? items[activeIndex] : null;
301
+ },
302
+
303
+ getActiveIndex() {
304
+ return activeIndex;
305
+ },
306
+
307
+ setActiveTab(index) {
308
+ if (
309
+ index < 0 ||
310
+ index >= items.length ||
311
+ items[index].disabled ||
312
+ disabled.isDisabled() ||
313
+ index === activeIndex
314
+ ) {
315
+ return this;
316
+ }
317
+
318
+ const previousIndex = activeIndex;
319
+ const previousTab = this.getActiveTab();
320
+
321
+ activeIndex = index;
322
+ const currentTab = items[index];
323
+
324
+ // Update DOM
325
+ updateTabStates();
326
+ updateIndicator();
327
+
328
+ // Emit change event
329
+ component.events.emit('change', {
330
+ index,
331
+ tab: currentTab,
332
+ previousIndex,
333
+ previousTab
334
+ } as TabChangeEventData);
335
+
336
+ return this;
337
+ },
338
+
339
+ setActiveTabById(id) {
340
+ const index = items.findIndex(item => item.id === id);
341
+ if (index >= 0) {
342
+ this.setActiveTab(index);
343
+ }
344
+ return this;
345
+ },
346
+
347
+ destroy() {
348
+ // Clean up event listeners
349
+ const tabElements = enhancedComponent.tabsListElement.querySelectorAll('[role="tab"]');
350
+ tabElements.forEach(tab => {
351
+ tab.replaceWith(tab.cloneNode(true));
352
+ });
353
+
354
+ // Call lifecycle destroy
355
+ lifecycle.destroy();
356
+ },
357
+
358
+ on(event, handler) {
359
+ component.events.on(event, handler);
360
+ return this;
361
+ },
362
+
363
+ off(event, handler) {
364
+ component.events.off(event, handler);
365
+ return this;
366
+ }
367
+ };
368
+
369
+ // Set up keyboard navigation
370
+ enhancedComponent.element.addEventListener('keydown', (e: KeyboardEvent) => {
371
+ if (disabled.isDisabled() || !items.length) return;
372
+
373
+ const key = e.key;
374
+ let newIndex = activeIndex;
375
+
376
+ switch (key) {
377
+ case 'ArrowRight':
378
+ case 'ArrowDown':
379
+ // Move to next non-disabled tab
380
+ for (let i = 1; i <= items.length; i++) {
381
+ const index = (activeIndex + i) % items.length;
382
+ if (!items[index].disabled) {
383
+ newIndex = index;
384
+ break;
385
+ }
386
+ }
387
+ break;
388
+
389
+ case 'ArrowLeft':
390
+ case 'ArrowUp':
391
+ // Move to previous non-disabled tab
392
+ for (let i = 1; i <= items.length; i++) {
393
+ const index = (activeIndex - i + items.length) % items.length;
394
+ if (!items[index].disabled) {
395
+ newIndex = index;
396
+ break;
397
+ }
398
+ }
399
+ break;
400
+
401
+ case 'Home':
402
+ // Move to first non-disabled tab
403
+ for (let i = 0; i < items.length; i++) {
404
+ if (!items[i].disabled) {
405
+ newIndex = i;
406
+ break;
407
+ }
408
+ }
409
+ break;
410
+
411
+ case 'End':
412
+ // Move to last non-disabled tab
413
+ for (let i = items.length - 1; i >= 0; i--) {
414
+ if (!items[i].disabled) {
415
+ newIndex = i;
416
+ break;
417
+ }
418
+ }
419
+ break;
420
+
421
+ default:
422
+ return;
423
+ }
424
+
425
+ if (newIndex !== activeIndex) {
426
+ e.preventDefault();
427
+ api.setActiveTab(newIndex);
428
+
429
+ // Focus the tab
430
+ const tabElement = enhancedComponent.tabsListElement.querySelector(
431
+ `[data-tab-index="${newIndex}"]`
432
+ ) as HTMLElement;
433
+
434
+ if (tabElement) {
435
+ tabElement.focus();
436
+ }
437
+ }
438
+ });
439
+
440
+ return api;
441
+ };
442
+
443
+ export default withAPI;
@@ -0,0 +1,80 @@
1
+ // src/components/tabs/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig
5
+ } from '../../core/config/component-config';
6
+ import { TabsConfig } from './types';
7
+ import { TABS_VARIANTS } from './constants';
8
+
9
+ /**
10
+ * Default configuration for the Tabs component
11
+ */
12
+ export const defaultConfig: TabsConfig = {
13
+ variant: TABS_VARIANTS.PRIMARY,
14
+ showIndicator: true,
15
+ animated: true,
16
+ scrollable: true,
17
+ activeIndex: 0
18
+ };
19
+
20
+ /**
21
+ * Creates the base configuration for Tabs component
22
+ * @param {TabsConfig} config - User provided configuration
23
+ * @returns {TabsConfig} Complete configuration with defaults applied
24
+ */
25
+ export const createBaseConfig = (config: TabsConfig = {}): TabsConfig =>
26
+ createComponentConfig(defaultConfig, config, 'tabs') as TabsConfig;
27
+
28
+ /**
29
+ * Generates element configuration for the Tabs component
30
+ * @param {TabsConfig} config - Tabs configuration
31
+ * @returns {Object} Element configuration object for withElement
32
+ */
33
+ export const getElementConfig = (config: TabsConfig) => {
34
+ // Create the attributes object
35
+ const attrs: Record<string, any> = {
36
+ role: 'tablist'
37
+ };
38
+
39
+ // Only add disabled attribute if it's explicitly true
40
+ if (config.disabled === true) {
41
+ attrs['aria-disabled'] = 'true';
42
+ }
43
+
44
+ const extraClasses: string[] = [];
45
+
46
+ if (config.scrollable) {
47
+ extraClasses.push('--scrollable');
48
+ }
49
+
50
+ if (config.animated) {
51
+ extraClasses.push('--animated');
52
+ }
53
+
54
+ return createElementConfig(config, {
55
+ tag: 'div',
56
+ attrs,
57
+ className: config.class,
58
+ extraClasses,
59
+ forwardEvents: {
60
+ keydown: true
61
+ }
62
+ });
63
+ };
64
+
65
+ /**
66
+ * Creates API configuration for the Tabs component
67
+ * @param {Object} comp - Component with disabled and lifecycle features
68
+ * @returns {Object} API configuration object
69
+ */
70
+ export const getApiConfig = (comp) => ({
71
+ disabled: {
72
+ enable: () => comp.disabled.enable(),
73
+ disable: () => comp.disabled.disable()
74
+ },
75
+ lifecycle: {
76
+ destroy: () => comp.lifecycle.destroy()
77
+ }
78
+ });
79
+
80
+ export default defaultConfig;
@@ -0,0 +1,12 @@
1
+ // src/components/tabs/constants.ts
2
+
3
+ export const TABS_VARIANTS = {
4
+ PRIMARY: 'primary',
5
+ SECONDARY: 'secondary',
6
+ SEGMENTED: 'segmented',
7
+ NEUTRAL: 'neutral'
8
+ }
9
+
10
+ export const ANIMATION_DURATION = 250
11
+ export const DEFAULT_TAB_MIN_WIDTH = 90
12
+ export const DEFAULT_TAB_MAX_WIDTH = 360
@@ -0,0 +1,4 @@
1
+ // src/components/tabs/index.ts
2
+ export { default } from './tabs';
3
+ export { TABS_VARIANTS } from './constants';
4
+ export { TabsConfig, TabsComponent, TabItem, TabChangeEventData } from './types';
@@ -0,0 +1,52 @@
1
+ // src/components/tabs/tabs.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import {
6
+ withEvents,
7
+ withVariant,
8
+ withDisabled,
9
+ withLifecycle
10
+ } from '../../core/compose/features';
11
+ import { withAPI } from './api';
12
+ import { TabsConfig } from './types';
13
+ import { TABS_VARIANTS } from './constants';
14
+ import { createBaseConfig, getElementConfig, getApiConfig } from './config';
15
+
16
+ /**
17
+ * Creates a new Tabs component
18
+ * @param {TabsConfig} config - Tabs configuration object
19
+ * @returns {TabsComponent} Tabs component instance
20
+ */
21
+ const createTabs = (config: TabsConfig = {}) => {
22
+ const baseConfig = createBaseConfig(config);
23
+
24
+ try {
25
+ const tabs = pipe(
26
+ createBase,
27
+ withEvents(),
28
+ withElement(getElementConfig(baseConfig)),
29
+ withVariant(baseConfig),
30
+ withDisabled(baseConfig),
31
+ withLifecycle(),
32
+ comp => withAPI(getApiConfig(comp))(comp)
33
+ )(baseConfig);
34
+
35
+ // Initialize tabs
36
+ if (baseConfig.items && baseConfig.items.length > 0) {
37
+ tabs.setItems(baseConfig.items);
38
+ }
39
+
40
+ // Set active tab if specified
41
+ if (baseConfig.activeIndex !== undefined) {
42
+ tabs.setActiveTab(baseConfig.activeIndex);
43
+ }
44
+
45
+ return tabs;
46
+ } catch (error) {
47
+ console.error('Tabs creation error:', error);
48
+ throw new Error(`Failed to create tabs: ${(error as Error).message}`);
49
+ }
50
+ };
51
+
52
+ export default createTabs;