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,336 @@
1
+ // src/components/slider/features/slider.ts - Added initialization code
2
+ import { SLIDER_EVENTS } from '../constants';
3
+ import { SliderConfig } from '../types';
4
+ import { createUiHelpers } from './ui';
5
+ import { createInteractionHandlers } from './interactions';
6
+ import { createKeyboardHandlers } from './keyboard';
7
+ import { createEventHelpers } from './events';
8
+
9
+ /**
10
+ * Add main slider functionality to component
11
+ * @param config Slider configuration
12
+ * @returns Component enhancer with slider functionality
13
+ */
14
+ export const withSlider = (config: SliderConfig) => component => {
15
+ // Ensure component has events
16
+ if (!component.events) {
17
+ component.events = {
18
+ listeners: {},
19
+ on: function(event, handler) {
20
+ if (!this.listeners[event]) {
21
+ this.listeners[event] = [];
22
+ }
23
+ this.listeners[event].push(handler);
24
+ return this;
25
+ },
26
+ off: function(event, handler) {
27
+ if (this.listeners[event]) {
28
+ this.listeners[event] = this.listeners[event].filter(h => h !== handler);
29
+ }
30
+ return this;
31
+ },
32
+ trigger: function(event, data) {
33
+ if (this.listeners[event]) {
34
+ this.listeners[event].forEach(handler => handler(data));
35
+ }
36
+ return this;
37
+ }
38
+ };
39
+ }
40
+
41
+ // Initialize state
42
+ const state = {
43
+ value: config.value !== undefined ? config.value : 0,
44
+ secondValue: config.secondValue !== undefined ? config.secondValue : null,
45
+ min: config.min !== undefined ? config.min : 0,
46
+ max: config.max !== undefined ? config.max : 100,
47
+ step: config.step !== undefined ? config.step : 1,
48
+ dragging: false,
49
+ activeBubble: null,
50
+ activeThumb: null,
51
+ ticks: [],
52
+ tickLabels: [],
53
+ component
54
+ };
55
+
56
+ // Create helper functions
57
+ const uiHelpers = createUiHelpers(config, state);
58
+ const eventHelpers = createEventHelpers(state);
59
+
60
+ // Combine helpers for event handlers
61
+ const handlers = {
62
+ ...uiHelpers,
63
+ triggerEvent: eventHelpers.triggerEvent
64
+ };
65
+
66
+ // Create event handlers
67
+ const interactionHandlers = createInteractionHandlers(config, state, handlers);
68
+ const keyboardHandlers = createKeyboardHandlers(state, handlers);
69
+
70
+ // Initialize slider
71
+ const initSlider = () => {
72
+ // Set ARIA attributes
73
+ component.element.setAttribute('aria-valuemin', String(state.min));
74
+ component.element.setAttribute('aria-valuemax', String(state.max));
75
+ component.element.setAttribute('aria-valuenow', String(state.value));
76
+
77
+ if (!component.structure) {
78
+ console.warn('Cannot initialize slider: missing structure');
79
+ return;
80
+ }
81
+
82
+ const { thumb, secondThumb } = component.structure;
83
+
84
+ if (!thumb) {
85
+ console.warn('Cannot initialize slider: missing thumb');
86
+ return;
87
+ }
88
+
89
+ thumb.setAttribute('aria-valuemin', String(state.min));
90
+ thumb.setAttribute('aria-valuemax', String(state.max));
91
+ thumb.setAttribute('aria-valuenow', String(state.value));
92
+
93
+ if (config.range && secondThumb && state.secondValue !== null) {
94
+ secondThumb.setAttribute('aria-valuemin', String(state.min));
95
+ secondThumb.setAttribute('aria-valuemax', String(state.max));
96
+ secondThumb.setAttribute('aria-valuenow', String(state.secondValue));
97
+ }
98
+
99
+ // Setup initial positions
100
+ uiHelpers.updateUi();
101
+
102
+ // Generate ticks if needed
103
+ if (config.ticks || config.tickLabels) {
104
+ uiHelpers.generateTicks();
105
+ uiHelpers.updateTicks();
106
+ }
107
+
108
+ // Setup event listeners
109
+ eventHelpers.setupEventListeners(interactionHandlers, keyboardHandlers);
110
+
111
+ // Force one more UI update after a delay to ensure everything is properly positioned
112
+ // This is especially important for range sliders
113
+ setTimeout(() => {
114
+ uiHelpers.updateUi();
115
+ }, 50);
116
+ };
117
+
118
+ // Cleanup event listeners
119
+ const cleanup = () => {
120
+ eventHelpers.cleanupEventListeners(interactionHandlers, keyboardHandlers);
121
+ };
122
+
123
+ // Register with lifecycle
124
+ if (component.lifecycle) {
125
+ const originalDestroy = component.lifecycle.destroy || (() => {});
126
+ component.lifecycle.destroy = () => {
127
+ cleanup();
128
+ originalDestroy();
129
+ };
130
+ }
131
+
132
+ // Initialize slider
133
+ initSlider();
134
+
135
+ // Return enhanced component with the slider functionality
136
+ const enhancedComponent = {
137
+ ...component,
138
+ slider: {
139
+ /**
140
+ * Sets slider value
141
+ * @param value New value
142
+ * @param triggerEvent Whether to trigger change event
143
+ */
144
+ setValue(value, triggerEvent = true) {
145
+ // Validate and set value
146
+ const newValue = uiHelpers.clamp(value, state.min, state.max);
147
+ state.value = newValue;
148
+
149
+ // Update UI
150
+ uiHelpers.updateUi();
151
+
152
+ // Trigger events if needed
153
+ if (triggerEvent) {
154
+ eventHelpers.triggerEvent(SLIDER_EVENTS.CHANGE);
155
+ }
156
+
157
+ return this;
158
+ },
159
+
160
+ /**
161
+ * Gets slider value
162
+ * @returns Current value
163
+ */
164
+ getValue() {
165
+ return state.value;
166
+ },
167
+
168
+ /**
169
+ * Sets secondary slider value (for range slider)
170
+ * @param value New secondary value
171
+ * @param triggerEvent Whether to trigger change event
172
+ */
173
+ setSecondValue(value, triggerEvent = true) {
174
+ if (!config.range) return this;
175
+
176
+ // Validate and set value
177
+ const newValue = uiHelpers.clamp(value, state.min, state.max);
178
+ state.secondValue = newValue;
179
+
180
+ // Update UI
181
+ uiHelpers.updateUi();
182
+
183
+ // Trigger events if needed
184
+ if (triggerEvent) {
185
+ eventHelpers.triggerEvent(SLIDER_EVENTS.CHANGE);
186
+ }
187
+
188
+ return this;
189
+ },
190
+
191
+ /**
192
+ * Gets secondary slider value
193
+ * @returns Current secondary value or null
194
+ */
195
+ getSecondValue() {
196
+ return config.range ? state.secondValue : null;
197
+ },
198
+
199
+ /**
200
+ * Sets slider minimum value
201
+ * @param min New minimum value
202
+ */
203
+ setMin(min) {
204
+ state.min = min;
205
+
206
+ // Update ARIA attributes
207
+ component.element.setAttribute('aria-valuemin', String(min));
208
+ component.structure.thumb.setAttribute('aria-valuemin', String(min));
209
+
210
+ if (config.range && component.structure.secondThumb) {
211
+ component.structure.secondThumb.setAttribute('aria-valuemin', String(min));
212
+ }
213
+
214
+ // Clamp values to new min
215
+ if (state.value < min) {
216
+ state.value = min;
217
+ }
218
+
219
+ if (config.range && state.secondValue !== null && state.secondValue < min) {
220
+ state.secondValue = min;
221
+ }
222
+
223
+ // Regenerate ticks if needed
224
+ if (config.ticks || config.tickLabels) {
225
+ uiHelpers.generateTicks();
226
+ }
227
+
228
+ // Update UI
229
+ uiHelpers.updateUi();
230
+
231
+ return this;
232
+ },
233
+
234
+ /**
235
+ * Gets slider minimum value
236
+ * @returns Current minimum value
237
+ */
238
+ getMin() {
239
+ return state.min;
240
+ },
241
+
242
+ /**
243
+ * Sets slider maximum value
244
+ * @param max New maximum value
245
+ */
246
+ setMax(max) {
247
+ state.max = max;
248
+
249
+ // Update ARIA attributes
250
+ component.element.setAttribute('aria-valuemax', String(max));
251
+ component.structure.thumb.setAttribute('aria-valuemax', String(max));
252
+
253
+ if (config.range && component.structure.secondThumb) {
254
+ component.structure.secondThumb.setAttribute('aria-valuemax', String(max));
255
+ }
256
+
257
+ // Clamp values to new max
258
+ if (state.value > max) {
259
+ state.value = max;
260
+ }
261
+
262
+ if (config.range && state.secondValue !== null && state.secondValue > max) {
263
+ state.secondValue = max;
264
+ }
265
+
266
+ // Regenerate ticks if needed
267
+ if (config.ticks || config.tickLabels) {
268
+ uiHelpers.generateTicks();
269
+ }
270
+
271
+ // Update UI
272
+ uiHelpers.updateUi();
273
+
274
+ return this;
275
+ },
276
+
277
+ /**
278
+ * Gets slider maximum value
279
+ * @returns Current maximum value
280
+ */
281
+ getMax() {
282
+ return state.max;
283
+ },
284
+
285
+ /**
286
+ * Sets slider step size
287
+ * @param step New step size
288
+ */
289
+ setStep(step) {
290
+ state.step = step;
291
+
292
+ // Add or remove discrete class
293
+ if (step > 0) {
294
+ component.element.classList.add(`${component.getClass('slider')}--discrete`);
295
+ } else {
296
+ component.element.classList.remove(`${component.getClass('slider')}--discrete`);
297
+ }
298
+
299
+ // Regenerate ticks if needed
300
+ if (config.ticks || config.tickLabels) {
301
+ uiHelpers.generateTicks();
302
+ uiHelpers.updateTicks();
303
+ }
304
+
305
+ return this;
306
+ },
307
+
308
+ /**
309
+ * Gets slider step size
310
+ * @returns Current step size
311
+ */
312
+ getStep() {
313
+ return state.step;
314
+ },
315
+
316
+ /**
317
+ * Regenerate tick marks and labels
318
+ */
319
+ regenerateTicks() {
320
+ uiHelpers.generateTicks();
321
+ uiHelpers.updateTicks();
322
+ return this;
323
+ },
324
+
325
+ /**
326
+ * Update all UI elements
327
+ */
328
+ updateUi() {
329
+ uiHelpers.updateUi();
330
+ return this;
331
+ }
332
+ }
333
+ };
334
+
335
+ return enhancedComponent;
336
+ };
@@ -0,0 +1,264 @@
1
+ // src/components/slider/features/structure.ts - Fixed track initialization
2
+ import { SLIDER_COLORS, SLIDER_SIZES, SLIDER_ORIENTATIONS } from '../constants';
3
+ import { SliderConfig } from '../types';
4
+
5
+ /**
6
+ * Creates the slider DOM structure following MD3 principles
7
+ * @param config Slider configuration
8
+ * @returns Component enhancer with DOM structure
9
+ */
10
+ export const withStructure = (config: SliderConfig) => component => {
11
+ // Create track element
12
+ const track = document.createElement('div');
13
+ track.classList.add(component.getClass('slider-track'));
14
+
15
+ // Calculate initial percentages based on values
16
+ const min = config.min || 0;
17
+ const max = config.max || 100;
18
+ const range = max - min;
19
+
20
+ // Set default values
21
+ const value = config.value !== undefined ? config.value : min;
22
+ const secondValue = config.secondValue !== undefined ? config.secondValue : null;
23
+
24
+ // Calculate percentages
25
+ const getPercentage = (val) => ((val - min) / range) * 100;
26
+ const valuePercent = getPercentage(value);
27
+
28
+ // Create remaining track element (fills entire width initially)
29
+ const remainingTrack = document.createElement('div');
30
+ remainingTrack.classList.add(component.getClass('slider-remaining-track'));
31
+
32
+ // Create start track element (for range slider)
33
+ const startTrack = document.createElement('div');
34
+ startTrack.classList.add(component.getClass('slider-start-track'));
35
+
36
+ // Create active track element (filled part)
37
+ const activeTrack = document.createElement('div');
38
+ activeTrack.classList.add(component.getClass('slider-active-track'));
39
+
40
+ // Calculate padding adjustment (8px equivalent as percentage)
41
+ // We'll do a rough estimate initially, then recalculate once rendered
42
+ const paddingAdjustment = 8; // 8px padding
43
+ const estimatedTrackSize = 300; // A reasonable guess at track width
44
+ const paddingPercent = (paddingAdjustment / estimatedTrackSize) * 100;
45
+
46
+ // Set initial dimensions for all track segments
47
+ if (config.range && secondValue !== null) {
48
+ // Range slider
49
+ const lowerValue = Math.min(value, secondValue);
50
+ const higherValue = Math.max(value, secondValue);
51
+ const lowerPercent = getPercentage(lowerValue);
52
+ const higherPercent = getPercentage(higherValue);
53
+
54
+ // Adjust positions and width to account for spacing
55
+ let adjustedLowerPercent = lowerPercent + paddingPercent;
56
+ let adjustedHigherPercent = higherPercent - paddingPercent;
57
+
58
+ if (adjustedHigherPercent <= adjustedLowerPercent) {
59
+ adjustedLowerPercent = (lowerPercent + higherPercent) / 2 - 1;
60
+ adjustedHigherPercent = (lowerPercent + higherPercent) / 2 + 1;
61
+ }
62
+
63
+ // Calculate track segment sizes
64
+ const startWidth = Math.max(0, lowerPercent - paddingPercent);
65
+ const activeWidth = Math.max(0, adjustedHigherPercent - adjustedLowerPercent);
66
+ const remainingWidth = Math.max(0, 100 - higherPercent - paddingPercent);
67
+
68
+ if (config.orientation === SLIDER_ORIENTATIONS.VERTICAL) {
69
+ // Vertical orientation
70
+ startTrack.style.display = 'block';
71
+ startTrack.style.height = `${startWidth}%`;
72
+ startTrack.style.bottom = '0';
73
+ startTrack.style.width = '100%';
74
+
75
+ activeTrack.style.display = 'block';
76
+ activeTrack.style.height = `${activeWidth}%`;
77
+ activeTrack.style.bottom = `${adjustedLowerPercent}%`;
78
+ activeTrack.style.width = '100%';
79
+
80
+ remainingTrack.style.display = 'block';
81
+ remainingTrack.style.height = `${remainingWidth}%`;
82
+ remainingTrack.style.bottom = `${higherPercent + paddingPercent}%`;
83
+ remainingTrack.style.width = '100%';
84
+ } else {
85
+ // Horizontal orientation
86
+ startTrack.style.display = 'block';
87
+ startTrack.style.width = `${startWidth}%`;
88
+ startTrack.style.left = '0';
89
+ startTrack.style.height = '100%';
90
+
91
+ activeTrack.style.display = 'block';
92
+ activeTrack.style.width = `${activeWidth}%`;
93
+ activeTrack.style.left = `${adjustedLowerPercent}%`;
94
+ activeTrack.style.height = '100%';
95
+
96
+ remainingTrack.style.display = 'block';
97
+ remainingTrack.style.width = `${remainingWidth}%`;
98
+ remainingTrack.style.left = `${higherPercent + paddingPercent}%`;
99
+ remainingTrack.style.height = '100%';
100
+ }
101
+ } else {
102
+ // Single thumb slider
103
+ const adjustedWidth = Math.max(0, valuePercent - paddingPercent);
104
+ const remainingWidth = Math.max(0, 100 - valuePercent - paddingPercent);
105
+
106
+ if (config.orientation === SLIDER_ORIENTATIONS.VERTICAL) {
107
+ // Vertical orientation
108
+ startTrack.style.display = 'none';
109
+
110
+ activeTrack.style.display = 'block';
111
+ activeTrack.style.height = `${adjustedWidth}%`;
112
+ activeTrack.style.bottom = '0';
113
+ activeTrack.style.width = '100%';
114
+
115
+ remainingTrack.style.display = 'block';
116
+ remainingTrack.style.height = `${remainingWidth}%`;
117
+ remainingTrack.style.bottom = `${valuePercent + paddingPercent}%`;
118
+ remainingTrack.style.width = '100%';
119
+ } else {
120
+ // Horizontal orientation
121
+ startTrack.style.display = 'none';
122
+
123
+ activeTrack.style.display = 'block';
124
+ activeTrack.style.width = `${adjustedWidth}%`;
125
+ activeTrack.style.left = '0';
126
+ activeTrack.style.height = '100%';
127
+
128
+ remainingTrack.style.display = 'block';
129
+ remainingTrack.style.width = `${remainingWidth}%`;
130
+ remainingTrack.style.left = `${valuePercent + paddingPercent}%`;
131
+ remainingTrack.style.height = '100%';
132
+ }
133
+ }
134
+
135
+ // Add tracks to container
136
+ track.appendChild(remainingTrack);
137
+ track.appendChild(startTrack);
138
+ track.appendChild(activeTrack);
139
+
140
+ // Create thumb element
141
+ const thumb = document.createElement('div');
142
+ thumb.classList.add(component.getClass('slider-thumb'));
143
+ thumb.setAttribute('tabindex', '0');
144
+ thumb.setAttribute('role', 'slider');
145
+
146
+ // Set initial thumb position
147
+ if (config.orientation === SLIDER_ORIENTATIONS.VERTICAL) {
148
+ thumb.style.bottom = `${valuePercent}%`;
149
+ thumb.style.left = '50%';
150
+ thumb.style.top = 'auto';
151
+ } else {
152
+ thumb.style.left = `${valuePercent}%`;
153
+ }
154
+
155
+ // Create dots for the track ends
156
+ const startDot = document.createElement('div');
157
+ startDot.classList.add(component.getClass('slider-dot'));
158
+ startDot.classList.add(component.getClass('slider-dot--start'));
159
+
160
+ const endDot = document.createElement('div');
161
+ endDot.classList.add(component.getClass('slider-dot'));
162
+ endDot.classList.add(component.getClass('slider-dot--end'));
163
+
164
+ // Create value bubble element
165
+ const valueBubble = document.createElement('div');
166
+ valueBubble.classList.add(component.getClass('slider-value'));
167
+
168
+ // Format value and set initial bubble text
169
+ const formatter = config.valueFormatter || (val => val.toString());
170
+ valueBubble.textContent = formatter(value);
171
+
172
+ // For range slider: Create second thumb and value bubble
173
+ let secondThumb = null;
174
+ let secondValueBubble = null;
175
+
176
+ if (config.range && secondValue !== null) {
177
+ // Create second thumb
178
+ secondThumb = document.createElement('div');
179
+ secondThumb.classList.add(component.getClass('slider-thumb'));
180
+ secondThumb.setAttribute('tabindex', '0');
181
+ secondThumb.setAttribute('role', 'slider');
182
+
183
+ // Set initial second thumb position
184
+ const secondPercent = getPercentage(secondValue);
185
+ if (config.orientation === SLIDER_ORIENTATIONS.VERTICAL) {
186
+ secondThumb.style.bottom = `${secondPercent}%`;
187
+ secondThumb.style.left = '50%';
188
+ secondThumb.style.top = 'auto';
189
+ } else {
190
+ secondThumb.style.left = `${secondPercent}%`;
191
+ }
192
+
193
+ // Create second value bubble
194
+ secondValueBubble = document.createElement('div');
195
+ secondValueBubble.classList.add(component.getClass('slider-value'));
196
+ secondValueBubble.textContent = formatter(secondValue);
197
+ }
198
+
199
+ // Add elements to the slider
200
+ component.element.classList.add(component.getClass('slider'));
201
+ component.element.appendChild(track);
202
+ component.element.appendChild(startDot);
203
+ component.element.appendChild(endDot);
204
+ component.element.appendChild(thumb);
205
+ component.element.appendChild(valueBubble);
206
+
207
+ if (config.range && secondThumb && secondValueBubble) {
208
+ component.element.classList.add(`${component.getClass('slider')}--range`);
209
+ component.element.appendChild(secondThumb);
210
+ component.element.appendChild(secondValueBubble);
211
+ }
212
+
213
+ // Apply size class
214
+ const size = config.size || SLIDER_SIZES.MEDIUM;
215
+ if (size !== SLIDER_SIZES.MEDIUM) {
216
+ component.element.classList.add(`${component.getClass('slider')}--${size}`);
217
+ }
218
+
219
+ // Apply color class
220
+ const color = config.color || SLIDER_COLORS.PRIMARY;
221
+ if (color !== SLIDER_COLORS.PRIMARY) {
222
+ component.element.classList.add(`${component.getClass('slider')}--${color}`);
223
+ }
224
+
225
+ // Apply orientation class
226
+ const orientation = config.orientation || SLIDER_ORIENTATIONS.HORIZONTAL;
227
+ if (orientation === SLIDER_ORIENTATIONS.VERTICAL) {
228
+ component.element.classList.add(`${component.getClass('slider')}--vertical`);
229
+ }
230
+
231
+ // Apply discrete class if step is specified
232
+ if (config.step !== undefined && config.step > 0) {
233
+ component.element.classList.add(`${component.getClass('slider')}--discrete`);
234
+ }
235
+
236
+ // Apply disabled class if needed
237
+ if (config.disabled) {
238
+ component.element.classList.add(`${component.getClass('slider')}--disabled`);
239
+ }
240
+
241
+ // Ensure proper initialization after DOM is attached by scheduling a UI update
242
+ setTimeout(() => {
243
+ if (component.slider && typeof component.slider.updateUi === 'function') {
244
+ component.slider.updateUi();
245
+ }
246
+ }, 0);
247
+
248
+ // Store elements in component
249
+ return {
250
+ ...component,
251
+ structure: {
252
+ track,
253
+ activeTrack,
254
+ startTrack,
255
+ remainingTrack,
256
+ thumb,
257
+ valueBubble,
258
+ secondThumb,
259
+ secondValueBubble,
260
+ startDot,
261
+ endDot
262
+ }
263
+ };
264
+ };