mtrl 0.2.7 → 0.2.9
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.
- package/index.ts +2 -0
- package/package.json +14 -3
- package/src/components/badge/api.ts +23 -14
- package/src/components/badge/badge.ts +2 -2
- package/src/components/badge/config.ts +10 -11
- package/src/components/badge/features.ts +15 -10
- package/src/components/badge/index.ts +27 -2
- package/src/components/badge/types.ts +28 -8
- package/src/components/bottom-app-bar/bottom-app-bar.ts +2 -44
- package/src/components/bottom-app-bar/config.ts +1 -45
- package/src/components/bottom-app-bar/index.ts +7 -1
- package/src/components/bottom-app-bar/types.ts +7 -1
- package/src/components/button/button.ts +0 -1
- package/src/components/button/config.ts +1 -2
- package/src/components/button/index.ts +10 -2
- package/src/components/button/types.ts +14 -2
- package/src/components/card/config.ts +17 -9
- package/src/components/card/content.ts +8 -10
- package/src/components/card/features.ts +4 -6
- package/src/components/card/index.ts +29 -2
- package/src/components/card/types.ts +6 -23
- package/src/components/checkbox/config.ts +3 -4
- package/src/components/checkbox/index.ts +1 -2
- package/src/components/checkbox/types.ts +12 -3
- package/src/components/chip/api.ts +170 -221
- package/src/components/chip/chip.ts +34 -302
- package/src/components/chip/config.ts +1 -2
- package/src/components/chip/index.ts +10 -2
- package/src/components/chip/types.ts +224 -35
- package/src/components/datepicker/api.ts +18 -25
- package/src/components/datepicker/config.ts +9 -12
- package/src/components/datepicker/datepicker.ts +7 -12
- package/src/components/datepicker/index.ts +10 -7
- package/src/components/datepicker/render.ts +16 -18
- package/src/components/datepicker/types.ts +164 -35
- package/src/components/datepicker/utils.ts +1 -2
- package/src/components/dialog/api.ts +7 -8
- package/src/components/dialog/config.ts +3 -4
- package/src/components/dialog/features.ts +56 -22
- package/src/components/dialog/index.ts +38 -8
- package/src/components/dialog/types.ts +33 -10
- package/src/components/divider/index.ts +5 -1
- package/src/components/extended-fab/config.ts +6 -2
- package/src/components/extended-fab/index.ts +7 -2
- package/src/components/extended-fab/types.ts +21 -4
- package/src/components/fab/config.ts +3 -4
- package/src/components/fab/fab.ts +1 -1
- package/src/components/fab/index.ts +7 -2
- package/src/components/fab/types.ts +21 -4
- package/src/components/list/config.ts +4 -5
- package/src/components/list/features.ts +6 -7
- package/src/components/list/index.ts +7 -9
- package/src/components/list/list-item.ts +12 -13
- package/src/components/list/types.ts +50 -5
- package/src/components/list/utils.ts +30 -3
- package/src/components/menu/features/items-manager.ts +9 -9
- package/src/components/menu/features/positioning.ts +7 -7
- package/src/components/menu/features/visibility.ts +7 -7
- package/src/components/menu/index.ts +7 -9
- package/src/components/menu/menu-item.ts +6 -6
- package/src/components/menu/menu.ts +22 -0
- package/src/components/menu/types.ts +29 -10
- package/src/components/menu/utils.ts +67 -0
- package/src/components/navigation/api.ts +131 -96
- package/src/components/navigation/config.ts +22 -10
- package/src/components/navigation/features/controller.ts +273 -0
- package/src/components/navigation/features/items.ts +160 -87
- package/src/components/navigation/index.ts +0 -6
- package/src/components/navigation/nav-item.ts +12 -24
- package/src/components/navigation/navigation.ts +21 -8
- package/src/components/navigation/system-types.ts +124 -0
- package/src/components/navigation/system.ts +776 -0
- package/src/components/navigation/types.ts +228 -203
- package/src/components/progress/api.ts +2 -3
- package/src/components/progress/config.ts +2 -3
- package/src/components/progress/index.ts +0 -1
- package/src/components/progress/progress.ts +1 -2
- package/src/components/progress/types.ts +186 -33
- package/src/components/radios/config.ts +1 -1
- package/src/components/radios/index.ts +0 -1
- package/src/components/radios/types.ts +0 -7
- package/src/components/search/config.ts +1 -2
- package/src/components/search/features/search.ts +14 -15
- package/src/components/search/features/states.ts +5 -1
- package/src/components/search/features/structure.ts +3 -4
- package/src/components/search/index.ts +0 -3
- package/src/components/search/types.ts +18 -6
- package/src/components/segmented-button/config.ts +20 -7
- package/src/components/segmented-button/segment.ts +6 -7
- package/src/components/segmented-button/segmented-button.ts +4 -5
- package/src/components/segmented-button/types.ts +37 -2
- package/src/components/slider/config.ts +20 -2
- package/src/components/slider/features/controller.ts +761 -0
- package/src/components/slider/features/handlers.ts +18 -15
- package/src/components/slider/features/index.ts +3 -2
- package/src/components/slider/features/range.ts +104 -0
- package/src/components/slider/slider.ts +34 -14
- package/src/components/slider/structure.ts +152 -0
- package/src/components/slider/types.ts +34 -8
- package/src/components/snackbar/config.ts +2 -3
- package/src/components/snackbar/constants.ts +0 -32
- package/src/components/snackbar/index.ts +0 -1
- package/src/components/snackbar/position.ts +9 -1
- package/src/components/snackbar/types.ts +122 -46
- package/src/components/switch/config.ts +2 -3
- package/src/components/switch/index.ts +0 -1
- package/src/components/switch/types.ts +3 -2
- package/src/components/tabs/config.ts +3 -4
- package/src/components/tabs/index.ts +0 -15
- package/src/components/tabs/tab-api.ts +12 -4
- package/src/components/tabs/tab.ts +18 -6
- package/src/components/tabs/types.ts +13 -3
- package/src/components/textfield/api.ts +53 -0
- package/src/components/textfield/config.ts +2 -3
- package/src/components/textfield/features.ts +322 -0
- package/src/components/textfield/index.ts +0 -1
- package/src/components/textfield/textfield.ts +8 -0
- package/src/components/textfield/types.ts +29 -6
- package/src/components/timepicker/api.ts +1 -1
- package/src/components/timepicker/clockdial.ts +2 -5
- package/src/components/timepicker/config.ts +102 -4
- package/src/components/timepicker/index.ts +1 -6
- package/src/components/timepicker/render.ts +1 -1
- package/src/components/timepicker/timepicker.ts +1 -1
- package/src/components/tooltip/api.ts +1 -1
- package/src/components/tooltip/config.ts +27 -6
- package/src/components/tooltip/index.ts +0 -1
- package/src/components/tooltip/types.ts +13 -3
- package/src/core/compose/features/textinput.ts +15 -2
- package/src/core/compose/features/textlabel.ts +0 -3
- package/src/core/composition/features/dom.ts +33 -0
- package/src/core/composition/features/icon.ts +131 -0
- package/src/core/composition/features/index.ts +11 -0
- package/src/core/composition/features/label.ts +156 -0
- package/src/core/composition/features/structure.ts +22 -0
- package/src/core/composition/index.ts +26 -0
- package/src/core/index.ts +1 -1
- package/src/core/structure.ts +288 -0
- package/src/index.ts +1 -0
- package/src/styles/components/_navigation-mobile.scss +244 -0
- package/src/styles/components/_navigation-system.scss +151 -0
- package/src/{components/tabs/_styles.scss → styles/components/_tabs.scss} +1 -1
- package/src/{components/textfield/_styles.scss → styles/components/_textfield.scss} +314 -72
- package/src/styles/main.scss +98 -49
- package/src/components/badge/constants.ts +0 -40
- package/src/components/button/constants.ts +0 -11
- package/src/components/card/constants.ts +0 -84
- package/src/components/datepicker/constants.ts +0 -98
- package/src/components/dialog/constants.ts +0 -32
- package/src/components/extended-fab/constants.ts +0 -36
- package/src/components/fab/constants.ts +0 -41
- package/src/components/menu/constants.ts +0 -154
- package/src/components/navigation/constants.ts +0 -200
- package/src/components/progress/constants.ts +0 -29
- package/src/components/search/constants.ts +0 -21
- package/src/components/segmented-button/constants.ts +0 -42
- package/src/components/slider/features/slider.ts +0 -318
- package/src/components/slider/features/structure.ts +0 -181
- package/src/components/slider/features/ui.ts +0 -388
- package/src/components/switch/constants.ts +0 -80
- package/src/components/tabs/constants.ts +0 -89
- package/src/components/textfield/constants.ts +0 -100
- package/src/components/timepicker/constants.ts +0 -138
- /package/src/{components/badge/_styles.scss → styles/components/_badge.scss} +0 -0
- /package/src/{components/bottom-app-bar/_styles.scss → styles/components/_bottom-app-bar.scss} +0 -0
- /package/src/{components/button/_styles.scss → styles/components/_button.scss} +0 -0
- /package/src/{components/card/_styles.scss → styles/components/_card.scss} +0 -0
- /package/src/{components/carousel/_styles.scss → styles/components/_carousel.scss} +0 -0
- /package/src/{components/checkbox/_styles.scss → styles/components/_checkbox.scss} +0 -0
- /package/src/{components/chip/_styles.scss → styles/components/_chip.scss} +0 -0
- /package/src/{components/datepicker/_styles.scss → styles/components/_datepicker.scss} +0 -0
- /package/src/{components/dialog/_styles.scss → styles/components/_dialog.scss} +0 -0
- /package/src/{components/divider/_styles.scss → styles/components/_divider.scss} +0 -0
- /package/src/{components/extended-fab/_styles.scss → styles/components/_extended-fab.scss} +0 -0
- /package/src/{components/fab/_styles.scss → styles/components/_fab.scss} +0 -0
- /package/src/{components/list/_styles.scss → styles/components/_list.scss} +0 -0
- /package/src/{components/menu/_styles.scss → styles/components/_menu.scss} +0 -0
- /package/src/{components/navigation/_styles.scss → styles/components/_navigation.scss} +0 -0
- /package/src/{components/progress/_styles.scss → styles/components/_progress.scss} +0 -0
- /package/src/{components/radios/_styles.scss → styles/components/_radios.scss} +0 -0
- /package/src/{components/search/_styles.scss → styles/components/_search.scss} +0 -0
- /package/src/{components/segmented-button/_styles.scss → styles/components/_segmented-button.scss} +0 -0
- /package/src/{components/sheet/_styles.scss → styles/components/_sheet.scss} +0 -0
- /package/src/{components/slider/_styles.scss → styles/components/_slider.scss} +0 -0
- /package/src/{components/snackbar/_styles.scss → styles/components/_snackbar.scss} +0 -0
- /package/src/{components/switch/_styles.scss → styles/components/_switch.scss} +0 -0
- /package/src/{components/timepicker/_styles.scss → styles/components/_timepicker.scss} +0 -0
- /package/src/{components/tooltip/_styles.scss → styles/components/_tooltip.scss} +0 -0
- /package/src/{components/top-app-bar/_styles.scss → styles/components/_top-app-bar.scss} +0 -0
- /package/src/styles/utilities/{_color.scss → _colors.scss} +0 -0
|
@@ -7,20 +7,23 @@ import { SliderConfig, SliderEvent } from '../types';
|
|
|
7
7
|
*
|
|
8
8
|
* @param config Slider configuration
|
|
9
9
|
* @param state Slider state object
|
|
10
|
-
* @param
|
|
10
|
+
* @param uiRenderer UI renderer interface from controller
|
|
11
11
|
* @param eventHelpers Event helper methods
|
|
12
12
|
* @returns Event handlers for all slider interactions
|
|
13
13
|
*/
|
|
14
|
-
export const createHandlers = (config: SliderConfig, state,
|
|
14
|
+
export const createHandlers = (config: SliderConfig, state, uiRenderer, eventHelpers) => {
|
|
15
15
|
// Get required elements from structure (with fallbacks)
|
|
16
|
+
const components = state.component?.components || {};
|
|
17
|
+
|
|
18
|
+
// Extract needed components
|
|
16
19
|
const {
|
|
17
20
|
container = null,
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
handle = null,
|
|
22
|
+
track = null,
|
|
20
23
|
valueBubble = null,
|
|
21
24
|
secondHandle = null,
|
|
22
25
|
secondValueBubble = null
|
|
23
|
-
} =
|
|
26
|
+
} = components;
|
|
24
27
|
|
|
25
28
|
// Get required helper methods (with fallbacks)
|
|
26
29
|
const {
|
|
@@ -28,8 +31,8 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
28
31
|
roundToStep = value => value,
|
|
29
32
|
clamp = (value, min, max) => value,
|
|
30
33
|
showValueBubble = () => {},
|
|
31
|
-
|
|
32
|
-
} =
|
|
34
|
+
render = () => {}
|
|
35
|
+
} = uiRenderer;
|
|
33
36
|
|
|
34
37
|
const { triggerEvent = () => ({ defaultPrevented: false }) } = eventHelpers;
|
|
35
38
|
|
|
@@ -127,7 +130,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
127
130
|
document.addEventListener('touchmove', handleMouseMove, { passive: false });
|
|
128
131
|
document.addEventListener('touchend', handleMouseUp);
|
|
129
132
|
|
|
130
|
-
|
|
133
|
+
render();
|
|
131
134
|
triggerEvent(SLIDER_EVENTS.START, e);
|
|
132
135
|
};
|
|
133
136
|
|
|
@@ -169,7 +172,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
// Update UI and trigger events
|
|
172
|
-
|
|
175
|
+
render();
|
|
173
176
|
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
174
177
|
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
175
178
|
} catch (error) {
|
|
@@ -244,7 +247,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
244
247
|
state.value = newValue;
|
|
245
248
|
}
|
|
246
249
|
|
|
247
|
-
|
|
250
|
+
render();
|
|
248
251
|
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
249
252
|
} catch (error) {
|
|
250
253
|
console.warn('Error during slider drag:', error);
|
|
@@ -274,7 +277,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
274
277
|
|
|
275
278
|
// Reset active handle and update UI
|
|
276
279
|
state.activeHandle = null;
|
|
277
|
-
|
|
280
|
+
render();
|
|
278
281
|
|
|
279
282
|
// Trigger events
|
|
280
283
|
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
@@ -355,7 +358,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
355
358
|
}
|
|
356
359
|
|
|
357
360
|
// Update UI and trigger events
|
|
358
|
-
|
|
361
|
+
render();
|
|
359
362
|
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
360
363
|
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
361
364
|
};
|
|
@@ -406,7 +409,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
406
409
|
* Set up all event listeners
|
|
407
410
|
*/
|
|
408
411
|
const setupEventListeners = () => {
|
|
409
|
-
if (!state.component || !state.component.
|
|
412
|
+
if (!state.component || !state.component.components) {
|
|
410
413
|
console.warn('Cannot set up event listeners: missing component structure');
|
|
411
414
|
return;
|
|
412
415
|
}
|
|
@@ -436,7 +439,7 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
436
439
|
* Clean up all event listeners
|
|
437
440
|
*/
|
|
438
441
|
const cleanupEventListeners = () => {
|
|
439
|
-
if (!state.component || !state.component.
|
|
442
|
+
if (!state.component || !state.component.components) return;
|
|
440
443
|
|
|
441
444
|
// Clean up container listeners
|
|
442
445
|
if (container) {
|
|
@@ -492,4 +495,4 @@ export const createHandlers = (config: SliderConfig, state, uiHelpers, eventHelp
|
|
|
492
495
|
hideAllBubbles,
|
|
493
496
|
clearKeyboardFocus
|
|
494
497
|
};
|
|
495
|
-
}
|
|
498
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/components/slider/features/index.ts
|
|
2
|
-
|
|
2
|
+
// Export slider-specific features
|
|
3
|
+
export { withRange } from './range';
|
|
3
4
|
export { withStates } from './states';
|
|
4
|
-
export {
|
|
5
|
+
export { withController } from './controller';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/components/slider/features/range.ts
|
|
2
|
+
import { SliderConfig } from '../types';
|
|
3
|
+
import { createElement } from '../../../core/dom/create';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Enhances structure definition with range slider elements
|
|
7
|
+
*
|
|
8
|
+
* @param config Slider configuration
|
|
9
|
+
* @returns Component enhancer that adds range slider to structure
|
|
10
|
+
*/
|
|
11
|
+
export const withRange = (config: SliderConfig) => component => {
|
|
12
|
+
// If not a range slider or missing structure definition, return unmodified
|
|
13
|
+
if (!config.range || !config.secondValue || !component.structureDefinition) {
|
|
14
|
+
return component;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// Calculate values for second handle
|
|
19
|
+
const min = config.min || 0;
|
|
20
|
+
const max = config.max || 100;
|
|
21
|
+
const secondValue = config.secondValue;
|
|
22
|
+
const secondValuePercent = ((secondValue - min) / (max - min)) * 100;
|
|
23
|
+
const formatter = config.valueFormatter || (val => val.toString());
|
|
24
|
+
const isDisabled = config.disabled === true;
|
|
25
|
+
const getClass = component.getClass;
|
|
26
|
+
|
|
27
|
+
// Clone the structure definition (deep copy)
|
|
28
|
+
const structureDefinition = JSON.parse(JSON.stringify(component.structureDefinition));
|
|
29
|
+
|
|
30
|
+
// Add range class to root element
|
|
31
|
+
const rootClasses = structureDefinition.element.options.className || [];
|
|
32
|
+
if (Array.isArray(rootClasses)) {
|
|
33
|
+
rootClasses.push(getClass('slider--range'));
|
|
34
|
+
} else {
|
|
35
|
+
structureDefinition.element.options.className = `${rootClasses} ${getClass('slider--range')}`.trim();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Add start track segment to track children
|
|
39
|
+
const trackChildren = structureDefinition.element.children.container.children.track.children;
|
|
40
|
+
trackChildren.startTrack = {
|
|
41
|
+
name: 'startTrack',
|
|
42
|
+
creator: createElement,
|
|
43
|
+
options: {
|
|
44
|
+
tag: 'div',
|
|
45
|
+
className: getClass('slider-start-track'),
|
|
46
|
+
style: {
|
|
47
|
+
width: '0%'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Add second handle to container children
|
|
53
|
+
const containerChildren = structureDefinition.element.children.container.children;
|
|
54
|
+
containerChildren.secondHandle = {
|
|
55
|
+
name: 'secondHandle',
|
|
56
|
+
creator: createElement,
|
|
57
|
+
options: {
|
|
58
|
+
tag: 'div',
|
|
59
|
+
className: getClass('slider-handle'),
|
|
60
|
+
attrs: {
|
|
61
|
+
role: 'slider',
|
|
62
|
+
'aria-valuemin': String(min),
|
|
63
|
+
'aria-valuemax': String(max),
|
|
64
|
+
'aria-valuenow': String(secondValue),
|
|
65
|
+
'aria-orientation': 'horizontal',
|
|
66
|
+
tabindex: isDisabled ? '-1' : '0',
|
|
67
|
+
'aria-disabled': isDisabled ? 'true' : 'false',
|
|
68
|
+
'data-value': String(secondValue),
|
|
69
|
+
'data-handle-index': '1'
|
|
70
|
+
},
|
|
71
|
+
style: {
|
|
72
|
+
left: `${secondValuePercent}%`
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Add second value bubble to container children
|
|
78
|
+
containerChildren.secondValueBubble = {
|
|
79
|
+
name: 'secondValueBubble',
|
|
80
|
+
creator: createElement,
|
|
81
|
+
options: {
|
|
82
|
+
tag: 'div',
|
|
83
|
+
className: getClass('slider-value'),
|
|
84
|
+
attrs: {
|
|
85
|
+
'aria-hidden': 'true',
|
|
86
|
+
'data-handle-index': '1'
|
|
87
|
+
},
|
|
88
|
+
text: formatter(secondValue),
|
|
89
|
+
style: {
|
|
90
|
+
left: `${secondValuePercent}%`
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// Return component with updated structure definition
|
|
96
|
+
return {
|
|
97
|
+
...component,
|
|
98
|
+
structureDefinition
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn('Error enhancing structure with range functionality:', error);
|
|
102
|
+
return component;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
@@ -1,42 +1,62 @@
|
|
|
1
1
|
// src/components/slider/slider.ts
|
|
2
2
|
import { pipe } from '../../core/compose/pipe';
|
|
3
|
-
import { createBase
|
|
4
|
-
import { withEvents, withLifecycle
|
|
5
|
-
import { withStructure,
|
|
6
|
-
import {
|
|
3
|
+
import { createBase } from '../../core/compose/component';
|
|
4
|
+
import { withEvents, withLifecycle } from '../../core/compose/features';
|
|
5
|
+
import { withStructure, withIcon, withLabel, withDom } from '../../core/composition/features';
|
|
6
|
+
import {
|
|
7
|
+
withRange,
|
|
8
|
+
withStates,
|
|
9
|
+
withController
|
|
10
|
+
} from './features';
|
|
7
11
|
import { withAPI } from './api';
|
|
8
12
|
import { SliderConfig, SliderComponent } from './types';
|
|
9
|
-
import { createBaseConfig,
|
|
10
|
-
|
|
13
|
+
import { createBaseConfig, getApiConfig } from './config';
|
|
11
14
|
/**
|
|
12
15
|
* Creates a new Slider component
|
|
16
|
+
*
|
|
17
|
+
* Slider follows a clear architectural pattern:
|
|
18
|
+
* 1. Structure definition - Describes the DOM structure declaratively
|
|
19
|
+
* 2. Feature enhancement - Adds specific capabilities (range, icons, labels)
|
|
20
|
+
* 3. DOM creation - Turns the structure into actual DOM elements
|
|
21
|
+
* 4. State management - Handles visual states and appearance
|
|
22
|
+
* 5. Controller - Manages behavior, events, and UI rendering
|
|
23
|
+
* 6. Lifecycle - Handles component lifecycle events
|
|
24
|
+
* 7. Public API - Exposes a clean, consistent API
|
|
25
|
+
*
|
|
13
26
|
* @param {SliderConfig} config - Slider configuration object
|
|
14
27
|
* @returns {SliderComponent} Slider component instance
|
|
15
28
|
*/
|
|
16
29
|
const createSlider = (config: SliderConfig = {}): SliderComponent => {
|
|
30
|
+
// Process configuration with defaults
|
|
17
31
|
const baseConfig = createBaseConfig(config);
|
|
18
32
|
|
|
19
33
|
try {
|
|
20
|
-
// Create the component
|
|
34
|
+
// Create the component by composing features in a specific order
|
|
21
35
|
const component = pipe(
|
|
36
|
+
// Base component with event system
|
|
22
37
|
createBase,
|
|
23
38
|
withEvents(),
|
|
24
|
-
withElement(getElementConfig(baseConfig)),
|
|
25
|
-
withIcon(baseConfig),
|
|
26
|
-
withTextLabel(baseConfig),
|
|
27
39
|
withStructure(baseConfig),
|
|
40
|
+
withIcon(baseConfig),
|
|
41
|
+
withLabel(baseConfig),
|
|
42
|
+
withRange(baseConfig),
|
|
43
|
+
|
|
44
|
+
// Now create the actual DOM elements from the complete structure
|
|
45
|
+
withDom(),
|
|
46
|
+
|
|
47
|
+
// Add state management and behavior
|
|
28
48
|
withStates(baseConfig),
|
|
29
|
-
|
|
49
|
+
withController(baseConfig),
|
|
30
50
|
withLifecycle()
|
|
31
51
|
)(baseConfig);
|
|
32
52
|
|
|
33
|
-
// Generate the API configuration
|
|
53
|
+
// Generate the API configuration based on the enhanced component
|
|
34
54
|
const apiOptions = getApiConfig(component);
|
|
35
55
|
|
|
36
|
-
// Apply the API layer
|
|
56
|
+
// Apply the public API layer
|
|
37
57
|
const slider = withAPI(apiOptions)(component);
|
|
38
58
|
|
|
39
|
-
// Register event handlers from config
|
|
59
|
+
// Register event handlers from config for convenience
|
|
40
60
|
if (baseConfig.on && typeof slider.on === 'function') {
|
|
41
61
|
Object.entries(baseConfig.on).forEach(([event, handler]) => {
|
|
42
62
|
if (typeof handler === 'function') {
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// src/components/slider/structure.ts
|
|
2
|
+
import { SliderConfig } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates the base slider structure definition
|
|
6
|
+
*
|
|
7
|
+
* @param component Component for class name generation
|
|
8
|
+
* @param config Slider configuration
|
|
9
|
+
* @returns Structure definition object
|
|
10
|
+
*/
|
|
11
|
+
export function createSliderDefinition(component, config: SliderConfig) {
|
|
12
|
+
// Get prefixed class names
|
|
13
|
+
const getClass = (className) => component.getClass(className);
|
|
14
|
+
|
|
15
|
+
// Set default values
|
|
16
|
+
const min = config.min || 0;
|
|
17
|
+
const max = config.max || 100;
|
|
18
|
+
const value = config.value !== undefined ? config.value : min;
|
|
19
|
+
const isDisabled = config.disabled === true;
|
|
20
|
+
const formatter = config.valueFormatter || (val => val.toString());
|
|
21
|
+
|
|
22
|
+
// Calculate initial position
|
|
23
|
+
const valuePercent = ((value - min) / (max - min)) * 100;
|
|
24
|
+
|
|
25
|
+
// Return base structure definition formatted for createStructure
|
|
26
|
+
return {
|
|
27
|
+
element: {
|
|
28
|
+
options: {
|
|
29
|
+
tag: 'div',
|
|
30
|
+
className: [getClass('slider'), config.class].filter(Boolean),
|
|
31
|
+
attrs: {
|
|
32
|
+
tabindex: '-1',
|
|
33
|
+
role: 'none',
|
|
34
|
+
'aria-disabled': isDisabled ? 'true' : 'false'
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
children: {
|
|
38
|
+
// Container with all slider elements
|
|
39
|
+
container: {
|
|
40
|
+
options: {
|
|
41
|
+
tag: 'div',
|
|
42
|
+
className: getClass('slider-container')
|
|
43
|
+
},
|
|
44
|
+
children: {
|
|
45
|
+
// Track with segments
|
|
46
|
+
track: {
|
|
47
|
+
options: {
|
|
48
|
+
tag: 'div',
|
|
49
|
+
className: getClass('slider-track')
|
|
50
|
+
},
|
|
51
|
+
children: {
|
|
52
|
+
activeTrack: {
|
|
53
|
+
options: {
|
|
54
|
+
tag: 'div',
|
|
55
|
+
className: getClass('slider-active-track'),
|
|
56
|
+
style: {
|
|
57
|
+
width: `${valuePercent}%`
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
startTrack: {
|
|
62
|
+
options: {
|
|
63
|
+
tag: 'div',
|
|
64
|
+
className: getClass('slider-start-track'),
|
|
65
|
+
style: {
|
|
66
|
+
display: 'none', // Initially hidden for single slider
|
|
67
|
+
width: '0%'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
remainingTrack: {
|
|
72
|
+
options: {
|
|
73
|
+
tag: 'div',
|
|
74
|
+
className: getClass('slider-remaining-track'),
|
|
75
|
+
style: {
|
|
76
|
+
width: `${100 - valuePercent}%`
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
// Ticks container
|
|
84
|
+
ticksContainer: {
|
|
85
|
+
options: {
|
|
86
|
+
tag: 'div',
|
|
87
|
+
className: getClass('slider-ticks-container')
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
// Dots for ends
|
|
92
|
+
startDot: {
|
|
93
|
+
options: {
|
|
94
|
+
tag: 'div',
|
|
95
|
+
className: [
|
|
96
|
+
getClass('slider-dot'),
|
|
97
|
+
getClass('slider-dot--start')
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
endDot: {
|
|
102
|
+
options: {
|
|
103
|
+
tag: 'div',
|
|
104
|
+
className: [
|
|
105
|
+
getClass('slider-dot'),
|
|
106
|
+
getClass('slider-dot--end')
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Main handle
|
|
112
|
+
handle: {
|
|
113
|
+
options: {
|
|
114
|
+
tag: 'div',
|
|
115
|
+
className: getClass('slider-handle'),
|
|
116
|
+
attrs: {
|
|
117
|
+
role: 'slider',
|
|
118
|
+
'aria-valuemin': String(min),
|
|
119
|
+
'aria-valuemax': String(max),
|
|
120
|
+
'aria-valuenow': String(value),
|
|
121
|
+
'aria-orientation': 'horizontal',
|
|
122
|
+
tabindex: isDisabled ? '-1' : '0',
|
|
123
|
+
'aria-disabled': isDisabled ? 'true' : 'false',
|
|
124
|
+
'data-value': String(value),
|
|
125
|
+
'data-handle-index': '0'
|
|
126
|
+
},
|
|
127
|
+
style: {
|
|
128
|
+
left: `${valuePercent}%`
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
// Main value bubble
|
|
133
|
+
valueBubble: {
|
|
134
|
+
options: {
|
|
135
|
+
tag: 'div',
|
|
136
|
+
className: getClass('slider-value'),
|
|
137
|
+
attrs: {
|
|
138
|
+
'aria-hidden': 'true',
|
|
139
|
+
'data-handle-index': '0'
|
|
140
|
+
},
|
|
141
|
+
text: formatter(value),
|
|
142
|
+
style: {
|
|
143
|
+
left: `${valuePercent}%`
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
// src/components/slider/types.ts
|
|
2
|
-
import { SLIDER_COLORS, SLIDER_SIZES, SLIDER_EVENTS } from './constants';
|
|
3
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Available slider color variants
|
|
5
|
+
*/
|
|
6
|
+
export type SliderColor = 'primary' | 'secondary' | 'tertiary' | 'error';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Available slider size variants
|
|
10
|
+
*/
|
|
11
|
+
export type SliderSize = 'small' | 'medium' | 'large';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Available slider event types
|
|
15
|
+
*/
|
|
16
|
+
export type SliderEventType = 'change' | 'input' | 'focus' | 'blur' | 'start' | 'end';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Configuration options for the slider component
|
|
20
|
+
* @interface SliderConfig
|
|
21
|
+
*/
|
|
4
22
|
export interface SliderConfig {
|
|
5
23
|
/** Minimum value of the slider */
|
|
6
24
|
min?: number;
|
|
@@ -21,10 +39,10 @@ export interface SliderConfig {
|
|
|
21
39
|
disabled?: boolean;
|
|
22
40
|
|
|
23
41
|
/** Color variant of the slider */
|
|
24
|
-
color?:
|
|
42
|
+
color?: SliderColor;
|
|
25
43
|
|
|
26
44
|
/** Size variant of the slider */
|
|
27
|
-
size?:
|
|
45
|
+
size?: SliderSize;
|
|
28
46
|
|
|
29
47
|
/** Whether to show tick marks */
|
|
30
48
|
ticks?: boolean;
|
|
@@ -58,10 +76,14 @@ export interface SliderConfig {
|
|
|
58
76
|
|
|
59
77
|
/** Event handlers for slider events */
|
|
60
78
|
on?: {
|
|
61
|
-
[key in
|
|
79
|
+
[key in SliderEventType]?: (event: SliderEvent) => void;
|
|
62
80
|
};
|
|
63
81
|
}
|
|
64
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Slider event data
|
|
85
|
+
* @interface SliderEvent
|
|
86
|
+
*/
|
|
65
87
|
export interface SliderEvent {
|
|
66
88
|
/** The slider component that triggered the event */
|
|
67
89
|
slider: any;
|
|
@@ -82,6 +104,10 @@ export interface SliderEvent {
|
|
|
82
104
|
defaultPrevented: boolean;
|
|
83
105
|
}
|
|
84
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Slider component public API interface
|
|
109
|
+
* @interface SliderComponent
|
|
110
|
+
*/
|
|
85
111
|
export interface SliderComponent {
|
|
86
112
|
/** The root element of the slider */
|
|
87
113
|
element: HTMLElement;
|
|
@@ -126,13 +152,13 @@ export interface SliderComponent {
|
|
|
126
152
|
isDisabled: () => boolean;
|
|
127
153
|
|
|
128
154
|
/** Sets slider color */
|
|
129
|
-
setColor: (color:
|
|
155
|
+
setColor: (color: SliderColor) => SliderComponent;
|
|
130
156
|
|
|
131
157
|
/** Gets slider color */
|
|
132
158
|
getColor: () => string;
|
|
133
159
|
|
|
134
160
|
/** Sets slider size */
|
|
135
|
-
setSize: (size:
|
|
161
|
+
setSize: (size: SliderSize) => SliderComponent;
|
|
136
162
|
|
|
137
163
|
/** Gets slider size */
|
|
138
164
|
getSize: () => string;
|
|
@@ -156,10 +182,10 @@ export interface SliderComponent {
|
|
|
156
182
|
getIcon: () => string;
|
|
157
183
|
|
|
158
184
|
/** Adds event listener */
|
|
159
|
-
on: (event:
|
|
185
|
+
on: (event: SliderEventType, handler: (event: SliderEvent) => void) => SliderComponent;
|
|
160
186
|
|
|
161
187
|
/** Removes event listener */
|
|
162
|
-
off: (event:
|
|
188
|
+
off: (event: SliderEventType, handler: (event: SliderEvent) => void) => SliderComponent;
|
|
163
189
|
|
|
164
190
|
/** Destroys the slider component and cleans up resources */
|
|
165
191
|
destroy: () => void;
|
|
@@ -5,14 +5,13 @@ import {
|
|
|
5
5
|
BaseComponentConfig
|
|
6
6
|
} from '../../core/config/component-config';
|
|
7
7
|
import { SnackbarConfig, BaseComponent, ApiOptions } from './types';
|
|
8
|
-
import { SNACKBAR_VARIANTS, SNACKBAR_POSITIONS } from './constants';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Default configuration for the Snackbar component
|
|
12
11
|
*/
|
|
13
12
|
export const defaultConfig: SnackbarConfig = {
|
|
14
|
-
variant:
|
|
15
|
-
position:
|
|
13
|
+
variant: 'basic',
|
|
14
|
+
position: 'center',
|
|
16
15
|
duration: 4000
|
|
17
16
|
};
|
|
18
17
|
|
|
@@ -17,38 +17,6 @@ export const SNACKBAR_POSITIONS = {
|
|
|
17
17
|
END: 'end'
|
|
18
18
|
} as const;
|
|
19
19
|
|
|
20
|
-
/**
|
|
21
|
-
* Validation schema for snackbar configuration
|
|
22
|
-
*/
|
|
23
|
-
export const SNACKBAR_SCHEMA = {
|
|
24
|
-
variant: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
enum: Object.values(SNACKBAR_VARIANTS),
|
|
27
|
-
required: false
|
|
28
|
-
},
|
|
29
|
-
position: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
enum: Object.values(SNACKBAR_POSITIONS),
|
|
32
|
-
required: false
|
|
33
|
-
},
|
|
34
|
-
message: {
|
|
35
|
-
type: 'string',
|
|
36
|
-
required: true
|
|
37
|
-
},
|
|
38
|
-
action: {
|
|
39
|
-
type: 'string',
|
|
40
|
-
required: false
|
|
41
|
-
},
|
|
42
|
-
duration: {
|
|
43
|
-
type: 'number',
|
|
44
|
-
required: false
|
|
45
|
-
},
|
|
46
|
-
class: {
|
|
47
|
-
type: 'string',
|
|
48
|
-
required: false
|
|
49
|
-
}
|
|
50
|
-
} as const;
|
|
51
|
-
|
|
52
20
|
/**
|
|
53
21
|
* Snackbar state classes
|
|
54
22
|
*/
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
// src/components/snackbar/position.ts
|
|
2
|
-
import { SNACKBAR_POSITIONS } from './constants';
|
|
3
2
|
import { BaseComponent } from './types';
|
|
4
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Snackbar display positions
|
|
6
|
+
*/
|
|
7
|
+
const SNACKBAR_POSITIONS = {
|
|
8
|
+
CENTER: 'center',
|
|
9
|
+
START: 'start',
|
|
10
|
+
END: 'end'
|
|
11
|
+
}
|
|
12
|
+
|
|
5
13
|
/**
|
|
6
14
|
* Position configuration for the withPosition function
|
|
7
15
|
*/
|