mtrl 0.2.4 → 0.2.5
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/package.json +6 -3
- package/src/components/slider/_styles.scss +72 -154
- package/src/components/slider/api.ts +36 -101
- package/src/components/slider/config.ts +26 -73
- package/src/components/slider/constants.ts +12 -8
- package/src/components/slider/features/appearance.ts +1 -47
- package/src/components/slider/features/interactions.ts +14 -9
- package/src/components/slider/features/keyboard.ts +0 -2
- package/src/components/slider/features/structure.ts +151 -191
- package/src/components/slider/features/ui.ts +222 -301
- package/src/components/slider/index.ts +11 -1
- package/src/components/slider/slider.ts +1 -1
- package/src/components/slider/types.ts +10 -25
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
createElementConfig
|
|
5
5
|
} from '../../core/config/component-config';
|
|
6
6
|
import { SliderConfig } from './types';
|
|
7
|
-
import { SLIDER_COLORS, SLIDER_SIZES
|
|
7
|
+
import { SLIDER_COLORS, SLIDER_SIZES } from './constants';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Default configuration for the Slider component
|
|
@@ -17,9 +17,7 @@ export const defaultConfig: SliderConfig = {
|
|
|
17
17
|
disabled: false,
|
|
18
18
|
color: SLIDER_COLORS.PRIMARY,
|
|
19
19
|
size: SLIDER_SIZES.MEDIUM,
|
|
20
|
-
orientation: SLIDER_ORIENTATIONS.HORIZONTAL,
|
|
21
20
|
ticks: false,
|
|
22
|
-
tickLabels: false,
|
|
23
21
|
showValue: true,
|
|
24
22
|
snapToSteps: true,
|
|
25
23
|
range: false,
|
|
@@ -49,7 +47,7 @@ export const getElementConfig = (config: SliderConfig) => {
|
|
|
49
47
|
'aria-valuemin': config.min,
|
|
50
48
|
'aria-valuemax': config.max,
|
|
51
49
|
'aria-valuenow': config.value,
|
|
52
|
-
'aria-orientation':
|
|
50
|
+
'aria-orientation': 'horizontal'
|
|
53
51
|
},
|
|
54
52
|
className: config.class
|
|
55
53
|
});
|
|
@@ -61,85 +59,40 @@ export const getElementConfig = (config: SliderConfig) => {
|
|
|
61
59
|
* @returns {Object} API configuration object
|
|
62
60
|
*/
|
|
63
61
|
export const getApiConfig = (comp) => {
|
|
64
|
-
// Create
|
|
65
|
-
const safeCall = (obj, path, fallback = () => {}) => {
|
|
66
|
-
try {
|
|
67
|
-
const parts = path.split('.');
|
|
68
|
-
let current = obj;
|
|
69
|
-
|
|
70
|
-
for (const part of parts) {
|
|
71
|
-
if (current === undefined || current === null) return fallback;
|
|
72
|
-
current = current[part];
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return typeof current === 'function' ? current : fallback;
|
|
76
|
-
} catch {
|
|
77
|
-
return fallback;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const safeGetter = (obj, path, defaultValue = null) => {
|
|
82
|
-
try {
|
|
83
|
-
const parts = path.split('.');
|
|
84
|
-
let current = obj;
|
|
85
|
-
|
|
86
|
-
for (const part of parts) {
|
|
87
|
-
if (current === undefined || current === null) return defaultValue;
|
|
88
|
-
current = current[part];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return current === undefined ? defaultValue : current;
|
|
92
|
-
} catch {
|
|
93
|
-
return defaultValue;
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// Create API configuration using safe accessors
|
|
62
|
+
// Create API configuration using accessor pattern
|
|
98
63
|
return {
|
|
99
64
|
slider: {
|
|
100
|
-
setValue: (value, triggerEvent) =>
|
|
101
|
-
getValue: () =>
|
|
102
|
-
setSecondValue: (value, triggerEvent) =>
|
|
103
|
-
getSecondValue: () =>
|
|
104
|
-
setMin: (min) =>
|
|
105
|
-
getMin: () =>
|
|
106
|
-
setMax: (max) =>
|
|
107
|
-
getMax: () =>
|
|
108
|
-
setStep: (step) =>
|
|
109
|
-
getStep: () =>
|
|
65
|
+
setValue: (value, triggerEvent) => comp.slider?.setValue(value, triggerEvent),
|
|
66
|
+
getValue: () => comp.slider?.getValue() ?? 0,
|
|
67
|
+
setSecondValue: (value, triggerEvent) => comp.slider?.setSecondValue(value, triggerEvent),
|
|
68
|
+
getSecondValue: () => comp.slider?.getSecondValue() ?? null,
|
|
69
|
+
setMin: (min) => comp.slider?.setMin(min),
|
|
70
|
+
getMin: () => comp.slider?.getMin() ?? 0,
|
|
71
|
+
setMax: (max) => comp.slider?.setMax(max),
|
|
72
|
+
getMax: () => comp.slider?.getMax() ?? 100,
|
|
73
|
+
setStep: (step) => comp.slider?.setStep(step),
|
|
74
|
+
getStep: () => comp.slider?.getStep() ?? 1,
|
|
75
|
+
regenerateTicks: () => comp.slider?.regenerateTicks?.()
|
|
110
76
|
},
|
|
111
77
|
disabled: {
|
|
112
|
-
enable: () =>
|
|
113
|
-
disable: () =>
|
|
114
|
-
isDisabled: () =>
|
|
78
|
+
enable: () => comp.disabled?.enable?.(),
|
|
79
|
+
disable: () => comp.disabled?.disable?.(),
|
|
80
|
+
isDisabled: () => comp.disabled?.isDisabled?.() ?? false
|
|
115
81
|
},
|
|
116
82
|
appearance: {
|
|
117
|
-
setColor: (color) =>
|
|
118
|
-
getColor: () =>
|
|
119
|
-
setSize: (size) =>
|
|
120
|
-
getSize: () =>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
showTicks: (show) => safeCall(comp, 'appearance.showTicks')(show),
|
|
124
|
-
showTickLabels: (show) => safeCall(comp, 'appearance.showTickLabels')(show),
|
|
125
|
-
showCurrentValue: (show) => safeCall(comp, 'appearance.showCurrentValue')(show)
|
|
83
|
+
setColor: (color) => comp.appearance?.setColor?.(color),
|
|
84
|
+
getColor: () => comp.appearance?.getColor?.() ?? 'primary',
|
|
85
|
+
setSize: (size) => comp.appearance?.setSize?.(size),
|
|
86
|
+
getSize: () => comp.appearance?.getSize?.() ?? 'medium',
|
|
87
|
+
showTicks: (show) => comp.appearance?.showTicks?.(show),
|
|
88
|
+
showCurrentValue: (show) => comp.appearance?.showCurrentValue?.(show)
|
|
126
89
|
},
|
|
127
90
|
events: {
|
|
128
|
-
on: (event, handler) =>
|
|
129
|
-
|
|
130
|
-
return comp.events.on(event, handler);
|
|
131
|
-
}
|
|
132
|
-
return undefined;
|
|
133
|
-
},
|
|
134
|
-
off: (event, handler) => {
|
|
135
|
-
if (comp && comp.events && typeof comp.events.off === 'function') {
|
|
136
|
-
return comp.events.off(event, handler);
|
|
137
|
-
}
|
|
138
|
-
return undefined;
|
|
139
|
-
}
|
|
91
|
+
on: (event, handler) => comp.on?.(event, handler),
|
|
92
|
+
off: (event, handler) => comp.off?.(event, handler)
|
|
140
93
|
},
|
|
141
94
|
lifecycle: {
|
|
142
|
-
destroy: () =>
|
|
95
|
+
destroy: () => comp.lifecycle?.destroy?.()
|
|
143
96
|
}
|
|
144
97
|
};
|
|
145
98
|
};
|
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
// src/components/slider/constants.ts
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Available slider color variants
|
|
5
|
+
*/
|
|
3
6
|
export const SLIDER_COLORS = {
|
|
4
7
|
PRIMARY: 'primary',
|
|
5
8
|
SECONDARY: 'secondary',
|
|
6
9
|
TERTIARY: 'tertiary',
|
|
7
10
|
ERROR: 'error'
|
|
8
|
-
};
|
|
11
|
+
} as const;
|
|
9
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Available slider size variants
|
|
15
|
+
*/
|
|
10
16
|
export const SLIDER_SIZES = {
|
|
11
17
|
SMALL: 'small',
|
|
12
18
|
MEDIUM: 'medium',
|
|
13
19
|
LARGE: 'large'
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const SLIDER_ORIENTATIONS = {
|
|
17
|
-
HORIZONTAL: 'horizontal',
|
|
18
|
-
VERTICAL: 'vertical'
|
|
19
|
-
};
|
|
20
|
+
} as const;
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Available slider events
|
|
24
|
+
*/
|
|
21
25
|
export const SLIDER_EVENTS = {
|
|
22
26
|
CHANGE: 'change',
|
|
23
27
|
INPUT: 'input',
|
|
@@ -25,4 +29,4 @@ export const SLIDER_EVENTS = {
|
|
|
25
29
|
BLUR: 'blur',
|
|
26
30
|
START: 'start',
|
|
27
31
|
END: 'end'
|
|
28
|
-
};
|
|
32
|
+
} as const;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/slider/features/appearance.ts
|
|
2
|
-
import { SLIDER_COLORS, SLIDER_SIZES
|
|
2
|
+
import { SLIDER_COLORS, SLIDER_SIZES } from '../constants';
|
|
3
3
|
import { SliderConfig } from '../types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -69,39 +69,6 @@ export const withAppearance = (config: SliderConfig) => component => {
|
|
|
69
69
|
return sizeClass || SLIDER_SIZES.MEDIUM;
|
|
70
70
|
},
|
|
71
71
|
|
|
72
|
-
/**
|
|
73
|
-
* Sets slider orientation
|
|
74
|
-
* @param orientation Orientation variant
|
|
75
|
-
*/
|
|
76
|
-
setOrientation(orientation: keyof typeof SLIDER_ORIENTATIONS | SLIDER_ORIENTATIONS) {
|
|
77
|
-
// Clear existing orientation class
|
|
78
|
-
component.element.classList.remove(`${component.getClass('slider')}--${SLIDER_ORIENTATIONS.VERTICAL}`);
|
|
79
|
-
|
|
80
|
-
// Add orientation class if vertical
|
|
81
|
-
if (orientation === SLIDER_ORIENTATIONS.VERTICAL) {
|
|
82
|
-
component.element.classList.add(`${component.getClass('slider')}--${SLIDER_ORIENTATIONS.VERTICAL}`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Update ARIA attribute
|
|
86
|
-
component.element.setAttribute('aria-orientation', orientation);
|
|
87
|
-
|
|
88
|
-
// Update visual elements
|
|
89
|
-
if (component.slider) {
|
|
90
|
-
const eventData = { slider: component, value: component.slider.getValue() };
|
|
91
|
-
component.events.trigger('change', eventData);
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Gets slider orientation
|
|
97
|
-
* @returns Current orientation name
|
|
98
|
-
*/
|
|
99
|
-
getOrientation() {
|
|
100
|
-
return component.element.classList.contains(`${component.getClass('slider')}--${SLIDER_ORIENTATIONS.VERTICAL}`)
|
|
101
|
-
? SLIDER_ORIENTATIONS.VERTICAL
|
|
102
|
-
: SLIDER_ORIENTATIONS.HORIZONTAL;
|
|
103
|
-
},
|
|
104
|
-
|
|
105
72
|
/**
|
|
106
73
|
* Shows or hides tick marks
|
|
107
74
|
* @param show Whether to show ticks
|
|
@@ -115,19 +82,6 @@ export const withAppearance = (config: SliderConfig) => component => {
|
|
|
115
82
|
}
|
|
116
83
|
},
|
|
117
84
|
|
|
118
|
-
/**
|
|
119
|
-
* Shows or hides tick labels
|
|
120
|
-
* @param show Whether to show labels or array of label texts
|
|
121
|
-
*/
|
|
122
|
-
showTickLabels(show: boolean | string[]) {
|
|
123
|
-
config.tickLabels = show;
|
|
124
|
-
|
|
125
|
-
// Regenerate ticks if slider is initialized
|
|
126
|
-
if (component.slider) {
|
|
127
|
-
component.slider.regenerateTicks();
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
|
|
131
85
|
/**
|
|
132
86
|
* Shows or hides current value bubble while dragging
|
|
133
87
|
* @param show Whether to show value bubble
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/slider/features/interactions.ts
|
|
2
|
-
import { SLIDER_EVENTS
|
|
2
|
+
import { SLIDER_EVENTS } from '../constants';
|
|
3
3
|
import { SliderConfig, SliderEvent } from '../types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -44,6 +44,7 @@ export const createInteractionHandlers = (config: SliderConfig, state, handlers)
|
|
|
44
44
|
|
|
45
45
|
// Event handlers
|
|
46
46
|
const handleThumbMouseDown = (e, isSecondThumb = false) => {
|
|
47
|
+
console.log('handleThumbMouseDown', e)
|
|
47
48
|
// Verify component exists and check if disabled
|
|
48
49
|
if (!state.component || (state.component.disabled && state.component.disabled.isDisabled())) {
|
|
49
50
|
return;
|
|
@@ -56,6 +57,9 @@ export const createInteractionHandlers = (config: SliderConfig, state, handlers)
|
|
|
56
57
|
state.activeThumb = isSecondThumb ? secondThumb : thumb;
|
|
57
58
|
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
58
59
|
|
|
60
|
+
// Add dragging class to component element to style the thumb differently
|
|
61
|
+
state.component.element.classList.add(`${state.component.getClass('slider')}--dragging`);
|
|
62
|
+
|
|
59
63
|
// Show value bubble if it exists
|
|
60
64
|
if (state.activeBubble) {
|
|
61
65
|
showValueBubble(state.activeBubble, true);
|
|
@@ -89,15 +93,14 @@ export const createInteractionHandlers = (config: SliderConfig, state, handlers)
|
|
|
89
93
|
try {
|
|
90
94
|
// Get track rect for calculating position
|
|
91
95
|
const trackRect = track.getBoundingClientRect();
|
|
92
|
-
const isVertical = config.orientation === SLIDER_ORIENTATIONS.VERTICAL;
|
|
93
96
|
|
|
94
97
|
// Get position from mouse or touch event
|
|
95
98
|
const position = e.type.includes('touch')
|
|
96
|
-
?
|
|
97
|
-
:
|
|
99
|
+
? e.touches[0].clientX
|
|
100
|
+
: e.clientX;
|
|
98
101
|
|
|
99
102
|
// Calculate value at click position
|
|
100
|
-
let newValue = getValueFromPosition(position
|
|
103
|
+
let newValue = getValueFromPosition(position);
|
|
101
104
|
|
|
102
105
|
// Round to step if needed
|
|
103
106
|
if (config.snapToSteps && state.step > 0) {
|
|
@@ -150,13 +153,12 @@ export const createInteractionHandlers = (config: SliderConfig, state, handlers)
|
|
|
150
153
|
|
|
151
154
|
try {
|
|
152
155
|
// Get position
|
|
153
|
-
const isVertical = config.orientation === SLIDER_ORIENTATIONS.VERTICAL;
|
|
154
156
|
const position = e.type.includes('touch')
|
|
155
|
-
?
|
|
156
|
-
:
|
|
157
|
+
? e.touches[0].clientX
|
|
158
|
+
: e.clientX;
|
|
157
159
|
|
|
158
160
|
// Calculate new value
|
|
159
|
-
let newValue = getValueFromPosition(position
|
|
161
|
+
let newValue = getValueFromPosition(position);
|
|
160
162
|
|
|
161
163
|
// Round to step if needed
|
|
162
164
|
if (config.snapToSteps && state.step > 0) {
|
|
@@ -220,6 +222,9 @@ export const createInteractionHandlers = (config: SliderConfig, state, handlers)
|
|
|
220
222
|
|
|
221
223
|
state.dragging = false;
|
|
222
224
|
|
|
225
|
+
// Remove dragging class from component element
|
|
226
|
+
state.component.element.classList.remove(`${state.component.getClass('slider')}--dragging`);
|
|
227
|
+
|
|
223
228
|
// Hide value bubble
|
|
224
229
|
if (state.activeBubble) {
|
|
225
230
|
showValueBubble(state.activeBubble, false);
|
|
@@ -37,13 +37,11 @@ export const createKeyboardHandlers = (state, handlers) => {
|
|
|
37
37
|
|
|
38
38
|
switch (e.key) {
|
|
39
39
|
case 'ArrowRight':
|
|
40
|
-
case 'ArrowUp':
|
|
41
40
|
e.preventDefault();
|
|
42
41
|
newValue = Math.min(newValue + step, state.max);
|
|
43
42
|
break;
|
|
44
43
|
|
|
45
44
|
case 'ArrowLeft':
|
|
46
|
-
case 'ArrowDown':
|
|
47
45
|
e.preventDefault();
|
|
48
46
|
newValue = Math.max(newValue - step, state.min);
|
|
49
47
|
break;
|