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.
- package/.typedocignore +11 -0
- package/DOCS.md +153 -0
- package/index.ts +18 -3
- package/package.json +7 -2
- package/src/components/badge/_styles.scss +174 -0
- package/src/components/badge/api.ts +292 -0
- package/src/components/badge/badge.ts +52 -0
- package/src/components/badge/config.ts +68 -0
- package/src/components/badge/constants.ts +30 -0
- package/src/components/badge/features.ts +185 -0
- package/src/components/badge/index.ts +4 -0
- package/src/components/badge/types.ts +105 -0
- package/src/components/button/types.ts +174 -29
- package/src/components/carousel/_styles.scss +645 -0
- package/src/components/carousel/api.ts +147 -0
- package/src/components/carousel/carousel.ts +178 -0
- package/src/components/carousel/config.ts +91 -0
- package/src/components/carousel/constants.ts +95 -0
- package/src/components/carousel/features/drag.ts +388 -0
- package/src/components/carousel/features/index.ts +8 -0
- package/src/components/carousel/features/slides.ts +682 -0
- package/src/components/carousel/index.ts +38 -0
- package/src/components/carousel/types.ts +327 -0
- package/src/components/dialog/_styles.scss +213 -0
- package/src/components/dialog/api.ts +283 -0
- package/src/components/dialog/config.ts +113 -0
- package/src/components/dialog/constants.ts +32 -0
- package/src/components/dialog/dialog.ts +56 -0
- package/src/components/dialog/features.ts +713 -0
- package/src/components/dialog/index.ts +15 -0
- package/src/components/dialog/types.ts +221 -0
- package/src/components/progress/_styles.scss +13 -1
- package/src/components/progress/api.ts +2 -2
- package/src/components/progress/progress.ts +2 -2
- package/src/components/progress/types.ts +3 -0
- package/src/components/radios/_styles.scss +232 -0
- package/src/components/radios/api.ts +100 -0
- package/src/components/radios/config.ts +60 -0
- package/src/components/radios/constants.ts +28 -0
- package/src/components/radios/index.ts +4 -0
- package/src/components/radios/radio.ts +269 -0
- package/src/components/radios/radios.ts +42 -0
- package/src/components/radios/types.ts +232 -0
- package/src/components/sheet/_styles.scss +236 -0
- package/src/components/sheet/api.ts +96 -0
- package/src/components/sheet/config.ts +66 -0
- package/src/components/sheet/constants.ts +20 -0
- package/src/components/sheet/features/content.ts +51 -0
- package/src/components/sheet/features/gestures.ts +177 -0
- package/src/components/sheet/features/index.ts +6 -0
- package/src/components/sheet/features/position.ts +42 -0
- package/src/components/sheet/features/state.ts +116 -0
- package/src/components/sheet/features/title.ts +86 -0
- package/src/components/sheet/index.ts +4 -0
- package/src/components/sheet/sheet.ts +57 -0
- package/src/components/sheet/types.ts +266 -0
- package/src/components/slider/_styles.scss +518 -0
- package/src/components/slider/api.ts +336 -0
- package/src/components/slider/config.ts +145 -0
- package/src/components/slider/constants.ts +28 -0
- package/src/components/slider/features/appearance.ts +140 -0
- package/src/components/slider/features/disabled.ts +43 -0
- package/src/components/slider/features/events.ts +164 -0
- package/src/components/slider/features/index.ts +5 -0
- package/src/components/slider/features/interactions.ts +256 -0
- package/src/components/slider/features/keyboard.ts +114 -0
- package/src/components/slider/features/slider.ts +336 -0
- package/src/components/slider/features/structure.ts +264 -0
- package/src/components/slider/features/ui.ts +518 -0
- package/src/components/slider/index.ts +9 -0
- package/src/components/slider/slider.ts +58 -0
- package/src/components/slider/types.ts +166 -0
- package/src/components/tabs/_styles.scss +224 -0
- package/src/components/tabs/api.ts +443 -0
- package/src/components/tabs/config.ts +80 -0
- package/src/components/tabs/constants.ts +12 -0
- package/src/components/tabs/index.ts +4 -0
- package/src/components/tabs/tabs.ts +52 -0
- package/src/components/tabs/types.ts +247 -0
- package/src/components/textfield/_styles.scss +97 -4
- package/src/components/tooltip/_styles.scss +241 -0
- package/src/components/tooltip/api.ts +411 -0
- package/src/components/tooltip/config.ts +78 -0
- package/src/components/tooltip/constants.ts +27 -0
- package/src/components/tooltip/index.ts +4 -0
- package/src/components/tooltip/tooltip.ts +60 -0
- package/src/components/tooltip/types.ts +178 -0
- package/src/index.ts +9 -1
- package/src/styles/abstract/_variables.scss +24 -12
- package/tsconfig.json +22 -0
- package/typedoc.json +28 -0
- package/typedoc.simple.json +14 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// src/components/slider/features/events.ts
|
|
2
|
+
import { SliderEvent } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create event helper functions for the slider component
|
|
6
|
+
*
|
|
7
|
+
* @param state Slider state object
|
|
8
|
+
* @returns Event helper methods
|
|
9
|
+
*/
|
|
10
|
+
export const createEventHelpers = (state) => {
|
|
11
|
+
/**
|
|
12
|
+
* Triggers a slider event
|
|
13
|
+
* @param eventName Name of the event to trigger
|
|
14
|
+
* @param originalEvent Original DOM event if applicable
|
|
15
|
+
* @returns Event data object
|
|
16
|
+
*/
|
|
17
|
+
const triggerEvent = (eventName, originalEvent = null) => {
|
|
18
|
+
// Create event data object
|
|
19
|
+
const eventData: SliderEvent = {
|
|
20
|
+
slider: state.component,
|
|
21
|
+
value: state.value,
|
|
22
|
+
secondValue: state.secondValue,
|
|
23
|
+
originalEvent,
|
|
24
|
+
preventDefault: () => { eventData.defaultPrevented = true; },
|
|
25
|
+
defaultPrevented: false
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Add a component events facade if it doesn't exist
|
|
29
|
+
if (!state.component.events) {
|
|
30
|
+
state.component.events = {
|
|
31
|
+
trigger: () => {},
|
|
32
|
+
on: () => {},
|
|
33
|
+
off: () => {}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Now we can safely trigger the event
|
|
38
|
+
state.component.events.trigger(eventName, eventData);
|
|
39
|
+
|
|
40
|
+
return eventData;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set up event listeners for slider elements
|
|
45
|
+
* @param interactionHandlers Mouse/touch interaction handlers
|
|
46
|
+
* @param keyboardHandlers Keyboard interaction handlers
|
|
47
|
+
*/
|
|
48
|
+
const setupEventListeners = (interactionHandlers, keyboardHandlers) => {
|
|
49
|
+
// Ensure needed component parts exist
|
|
50
|
+
if (!state.component || !state.component.structure) {
|
|
51
|
+
console.warn('Cannot set up event listeners: component structure is missing');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
track = null,
|
|
57
|
+
thumb = null,
|
|
58
|
+
secondThumb = null
|
|
59
|
+
} = state.component.structure;
|
|
60
|
+
|
|
61
|
+
if (!track || !thumb) {
|
|
62
|
+
console.warn('Cannot set up event listeners: track or thumb is missing');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
handleThumbMouseDown,
|
|
68
|
+
handleTrackMouseDown
|
|
69
|
+
} = interactionHandlers;
|
|
70
|
+
|
|
71
|
+
const {
|
|
72
|
+
handleKeyDown,
|
|
73
|
+
handleFocus,
|
|
74
|
+
handleBlur
|
|
75
|
+
} = keyboardHandlers;
|
|
76
|
+
|
|
77
|
+
// Track events
|
|
78
|
+
track.addEventListener('mousedown', handleTrackMouseDown);
|
|
79
|
+
track.addEventListener('touchstart', handleTrackMouseDown, { passive: false });
|
|
80
|
+
|
|
81
|
+
// Thumb events
|
|
82
|
+
thumb.addEventListener('mousedown', (e) => handleThumbMouseDown(e, false));
|
|
83
|
+
thumb.addEventListener('touchstart', (e) => handleThumbMouseDown(e, false), { passive: false });
|
|
84
|
+
thumb.addEventListener('keydown', (e) => handleKeyDown(e, false));
|
|
85
|
+
thumb.addEventListener('focus', (e) => handleFocus(e, false));
|
|
86
|
+
thumb.addEventListener('blur', (e) => handleBlur(e, false));
|
|
87
|
+
|
|
88
|
+
// Second thumb events for range slider
|
|
89
|
+
if (state.component.config && state.component.config.range && secondThumb) {
|
|
90
|
+
secondThumb.addEventListener('mousedown', (e) => handleThumbMouseDown(e, true));
|
|
91
|
+
secondThumb.addEventListener('touchstart', (e) => handleThumbMouseDown(e, true), { passive: false });
|
|
92
|
+
secondThumb.addEventListener('keydown', (e) => handleKeyDown(e, true));
|
|
93
|
+
secondThumb.addEventListener('focus', (e) => handleFocus(e, true));
|
|
94
|
+
secondThumb.addEventListener('blur', (e) => handleBlur(e, true));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Clean up event listeners
|
|
100
|
+
* @param interactionHandlers Mouse/touch interaction handlers
|
|
101
|
+
* @param keyboardHandlers Keyboard interaction handlers
|
|
102
|
+
*/
|
|
103
|
+
const cleanupEventListeners = (interactionHandlers, keyboardHandlers) => {
|
|
104
|
+
// Ensure needed component parts exist
|
|
105
|
+
if (!state.component || !state.component.structure) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const {
|
|
110
|
+
track = null,
|
|
111
|
+
thumb = null,
|
|
112
|
+
secondThumb = null
|
|
113
|
+
} = state.component.structure;
|
|
114
|
+
|
|
115
|
+
if (!track || !thumb) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const {
|
|
120
|
+
handleThumbMouseDown,
|
|
121
|
+
handleTrackMouseDown,
|
|
122
|
+
handleMouseMove,
|
|
123
|
+
handleMouseUp
|
|
124
|
+
} = interactionHandlers;
|
|
125
|
+
|
|
126
|
+
const {
|
|
127
|
+
handleKeyDown,
|
|
128
|
+
handleFocus,
|
|
129
|
+
handleBlur
|
|
130
|
+
} = keyboardHandlers;
|
|
131
|
+
|
|
132
|
+
// Track events
|
|
133
|
+
track.removeEventListener('mousedown', handleTrackMouseDown);
|
|
134
|
+
track.removeEventListener('touchstart', handleTrackMouseDown);
|
|
135
|
+
|
|
136
|
+
// Thumb events
|
|
137
|
+
thumb.removeEventListener('mousedown', (e) => handleThumbMouseDown(e, false));
|
|
138
|
+
thumb.removeEventListener('touchstart', (e) => handleThumbMouseDown(e, false));
|
|
139
|
+
thumb.removeEventListener('keydown', (e) => handleKeyDown(e, false));
|
|
140
|
+
thumb.removeEventListener('focus', (e) => handleFocus(e, false));
|
|
141
|
+
thumb.removeEventListener('blur', (e) => handleBlur(e, false));
|
|
142
|
+
|
|
143
|
+
// Second thumb events
|
|
144
|
+
if (state.component.config && state.component.config.range && secondThumb) {
|
|
145
|
+
secondThumb.removeEventListener('mousedown', (e) => handleThumbMouseDown(e, true));
|
|
146
|
+
secondThumb.removeEventListener('touchstart', (e) => handleThumbMouseDown(e, true));
|
|
147
|
+
secondThumb.removeEventListener('keydown', (e) => handleKeyDown(e, true));
|
|
148
|
+
secondThumb.removeEventListener('focus', (e) => handleFocus(e, true));
|
|
149
|
+
secondThumb.removeEventListener('blur', (e) => handleBlur(e, true));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Global events
|
|
153
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
154
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
155
|
+
document.removeEventListener('touchmove', handleMouseMove);
|
|
156
|
+
document.removeEventListener('touchend', handleMouseUp);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
triggerEvent,
|
|
161
|
+
setupEventListeners,
|
|
162
|
+
cleanupEventListeners
|
|
163
|
+
};
|
|
164
|
+
};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// src/components/slider/features/interactions.ts
|
|
2
|
+
import { SLIDER_EVENTS, SLIDER_ORIENTATIONS } from '../constants';
|
|
3
|
+
import { SliderConfig, SliderEvent } from '../types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Add interaction event handlers to slider component
|
|
7
|
+
* This function contains the core event handlers for mouse/touch interactions
|
|
8
|
+
*
|
|
9
|
+
* @param config Slider configuration
|
|
10
|
+
* @param state Slider state object
|
|
11
|
+
* @param handlers Object containing handler methods
|
|
12
|
+
* @returns Event handlers for slider interactions
|
|
13
|
+
*/
|
|
14
|
+
export const createInteractionHandlers = (config: SliderConfig, state, handlers) => {
|
|
15
|
+
// Ensure state and handlers exist
|
|
16
|
+
if (!state || !handlers) {
|
|
17
|
+
console.error('Cannot create interaction handlers: state or handlers missing');
|
|
18
|
+
return {
|
|
19
|
+
handleThumbMouseDown: () => {},
|
|
20
|
+
handleTrackMouseDown: () => {},
|
|
21
|
+
handleMouseMove: () => {},
|
|
22
|
+
handleMouseUp: () => {}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Get required elements from structure (with fallbacks)
|
|
27
|
+
const {
|
|
28
|
+
track = null,
|
|
29
|
+
thumb = null,
|
|
30
|
+
valueBubble = null,
|
|
31
|
+
secondThumb = null,
|
|
32
|
+
secondValueBubble = null
|
|
33
|
+
} = state.component?.structure || {};
|
|
34
|
+
|
|
35
|
+
// Get required handler methods (with fallbacks)
|
|
36
|
+
const {
|
|
37
|
+
getValueFromPosition = () => 0,
|
|
38
|
+
roundToStep = value => value,
|
|
39
|
+
clamp = (value, min, max) => value,
|
|
40
|
+
showValueBubble = () => {},
|
|
41
|
+
updateUi = () => {},
|
|
42
|
+
triggerEvent = () => ({ defaultPrevented: false })
|
|
43
|
+
} = handlers;
|
|
44
|
+
|
|
45
|
+
// Event handlers
|
|
46
|
+
const handleThumbMouseDown = (e, isSecondThumb = false) => {
|
|
47
|
+
// Verify component exists and check if disabled
|
|
48
|
+
if (!state.component || (state.component.disabled && state.component.disabled.isDisabled())) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
e.stopPropagation();
|
|
54
|
+
|
|
55
|
+
state.dragging = true;
|
|
56
|
+
state.activeThumb = isSecondThumb ? secondThumb : thumb;
|
|
57
|
+
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
58
|
+
|
|
59
|
+
// Show value bubble if it exists
|
|
60
|
+
if (state.activeBubble) {
|
|
61
|
+
showValueBubble(state.activeBubble, true);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Add global event listeners
|
|
65
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
66
|
+
document.addEventListener('mouseup', handleMouseUp);
|
|
67
|
+
document.addEventListener('touchmove', handleMouseMove, { passive: false });
|
|
68
|
+
document.addEventListener('touchend', handleMouseUp);
|
|
69
|
+
|
|
70
|
+
// Try to trigger start event (with error handling)
|
|
71
|
+
try {
|
|
72
|
+
triggerEvent(SLIDER_EVENTS.START, e);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.warn('Error triggering START event:', error);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const handleTrackMouseDown = (e) => {
|
|
79
|
+
// Verify component exists and check if disabled
|
|
80
|
+
if (!state.component || (state.component.disabled && state.component.disabled.isDisabled()) || !track) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
e.preventDefault();
|
|
85
|
+
|
|
86
|
+
// Determine which thumb to move based on click position
|
|
87
|
+
let isSecondThumb = false;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
// Get track rect for calculating position
|
|
91
|
+
const trackRect = track.getBoundingClientRect();
|
|
92
|
+
const isVertical = config.orientation === SLIDER_ORIENTATIONS.VERTICAL;
|
|
93
|
+
|
|
94
|
+
// Get position from mouse or touch event
|
|
95
|
+
const position = e.type.includes('touch')
|
|
96
|
+
? isVertical ? e.touches[0].clientY : e.touches[0].clientX
|
|
97
|
+
: isVertical ? e.clientY : e.clientX;
|
|
98
|
+
|
|
99
|
+
// Calculate value at click position
|
|
100
|
+
let newValue = getValueFromPosition(position, isVertical);
|
|
101
|
+
|
|
102
|
+
// Round to step if needed
|
|
103
|
+
if (config.snapToSteps && state.step > 0) {
|
|
104
|
+
newValue = roundToStep(newValue);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Clamp value to min/max
|
|
108
|
+
newValue = clamp(newValue, state.min, state.max);
|
|
109
|
+
|
|
110
|
+
if (config.range && state.secondValue !== null) {
|
|
111
|
+
// For range slider, determine which thumb to move (closest to click position)
|
|
112
|
+
const distToFirst = Math.abs(newValue - state.value);
|
|
113
|
+
const distToSecond = Math.abs(newValue - state.secondValue);
|
|
114
|
+
|
|
115
|
+
isSecondThumb = distToSecond < distToFirst;
|
|
116
|
+
|
|
117
|
+
// Update the appropriate value
|
|
118
|
+
if (isSecondThumb) {
|
|
119
|
+
state.secondValue = newValue;
|
|
120
|
+
} else {
|
|
121
|
+
state.value = newValue;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// Single thumb slider - just update the value
|
|
125
|
+
state.value = newValue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Update UI immediately
|
|
129
|
+
updateUi();
|
|
130
|
+
|
|
131
|
+
// Trigger events
|
|
132
|
+
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
133
|
+
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.warn('Error handling track click:', error);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Set active elements
|
|
139
|
+
state.activeThumb = isSecondThumb ? secondThumb : thumb;
|
|
140
|
+
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
141
|
+
|
|
142
|
+
// Call thumb mouse down to start dragging
|
|
143
|
+
handleThumbMouseDown(e, isSecondThumb);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const handleMouseMove = (e) => {
|
|
147
|
+
if (!state.dragging || !state.activeThumb) return;
|
|
148
|
+
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
// Get position
|
|
153
|
+
const isVertical = config.orientation === SLIDER_ORIENTATIONS.VERTICAL;
|
|
154
|
+
const position = e.type.includes('touch')
|
|
155
|
+
? isVertical ? e.touches[0].clientY : e.touches[0].clientX
|
|
156
|
+
: isVertical ? e.clientY : e.clientX;
|
|
157
|
+
|
|
158
|
+
// Calculate new value
|
|
159
|
+
let newValue = getValueFromPosition(position, isVertical);
|
|
160
|
+
|
|
161
|
+
// Round to step if needed
|
|
162
|
+
if (config.snapToSteps && state.step > 0) {
|
|
163
|
+
newValue = roundToStep(newValue);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Clamp value to min/max
|
|
167
|
+
newValue = clamp(newValue, state.min, state.max);
|
|
168
|
+
|
|
169
|
+
// Check if this is the second thumb
|
|
170
|
+
const isSecondThumb = state.activeThumb === secondThumb;
|
|
171
|
+
|
|
172
|
+
// For range slider, ensure thumbs don't cross
|
|
173
|
+
if (config.range && state.secondValue !== null) {
|
|
174
|
+
if (isSecondThumb) {
|
|
175
|
+
// Don't allow second thumb to go below first thumb
|
|
176
|
+
if (newValue < state.value) {
|
|
177
|
+
state.secondValue = newValue;
|
|
178
|
+
} else {
|
|
179
|
+
// Thumbs are crossed, swap them
|
|
180
|
+
state.secondValue = state.value;
|
|
181
|
+
state.value = newValue;
|
|
182
|
+
|
|
183
|
+
// Swap active thumb and bubble
|
|
184
|
+
state.activeThumb = thumb;
|
|
185
|
+
state.activeBubble = valueBubble;
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
// Don't allow first thumb to go above second thumb
|
|
189
|
+
if (newValue > state.secondValue) {
|
|
190
|
+
state.value = newValue;
|
|
191
|
+
} else {
|
|
192
|
+
// Thumbs are crossed, swap them
|
|
193
|
+
state.value = state.secondValue;
|
|
194
|
+
state.secondValue = newValue;
|
|
195
|
+
|
|
196
|
+
// Swap active thumb and bubble
|
|
197
|
+
state.activeThumb = secondThumb;
|
|
198
|
+
state.activeBubble = secondValueBubble;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
// Regular slider
|
|
203
|
+
state.value = newValue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Update UI
|
|
207
|
+
updateUi();
|
|
208
|
+
|
|
209
|
+
// Trigger input event (continuously while dragging)
|
|
210
|
+
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.warn('Error during slider drag:', error);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const handleMouseUp = (e) => {
|
|
217
|
+
if (!state.dragging) return;
|
|
218
|
+
|
|
219
|
+
e.preventDefault();
|
|
220
|
+
|
|
221
|
+
state.dragging = false;
|
|
222
|
+
|
|
223
|
+
// Hide value bubble
|
|
224
|
+
if (state.activeBubble) {
|
|
225
|
+
showValueBubble(state.activeBubble, false);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Remove global event listeners
|
|
229
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
230
|
+
document.removeEventListener('mouseup', handleMouseUp);
|
|
231
|
+
document.removeEventListener('touchmove', handleMouseMove);
|
|
232
|
+
document.removeEventListener('touchend', handleMouseUp);
|
|
233
|
+
|
|
234
|
+
// Reset active elements
|
|
235
|
+
state.activeThumb = null;
|
|
236
|
+
state.activeBubble = null;
|
|
237
|
+
|
|
238
|
+
try {
|
|
239
|
+
// Trigger change event (only when done dragging)
|
|
240
|
+
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
241
|
+
|
|
242
|
+
// Trigger end event
|
|
243
|
+
triggerEvent(SLIDER_EVENTS.END, e);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.warn('Error triggering events on mouse up:', error);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Return handlers
|
|
250
|
+
return {
|
|
251
|
+
handleThumbMouseDown,
|
|
252
|
+
handleTrackMouseDown,
|
|
253
|
+
handleMouseMove,
|
|
254
|
+
handleMouseUp
|
|
255
|
+
};
|
|
256
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// src/components/slider/features/keyboard.ts
|
|
2
|
+
import { SLIDER_EVENTS } from '../constants';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Add keyboard interaction handlers to slider component
|
|
6
|
+
*
|
|
7
|
+
* @param state Slider state object
|
|
8
|
+
* @param handlers Object containing handler methods
|
|
9
|
+
* @returns Event handlers for keyboard interactions
|
|
10
|
+
*/
|
|
11
|
+
export const createKeyboardHandlers = (state, handlers) => {
|
|
12
|
+
const {
|
|
13
|
+
secondThumb,
|
|
14
|
+
secondValueBubble,
|
|
15
|
+
valueBubble
|
|
16
|
+
} = state.component.structure;
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
showValueBubble,
|
|
20
|
+
updateUi,
|
|
21
|
+
triggerEvent
|
|
22
|
+
} = handlers;
|
|
23
|
+
|
|
24
|
+
// Event handlers
|
|
25
|
+
const handleKeyDown = (e, isSecondThumb = false) => {
|
|
26
|
+
if (state.component.disabled && state.component.disabled.isDisabled()) return;
|
|
27
|
+
|
|
28
|
+
const step = state.step || 1;
|
|
29
|
+
let newValue;
|
|
30
|
+
|
|
31
|
+
// Determine which value to modify
|
|
32
|
+
if (isSecondThumb) {
|
|
33
|
+
newValue = state.secondValue;
|
|
34
|
+
} else {
|
|
35
|
+
newValue = state.value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
switch (e.key) {
|
|
39
|
+
case 'ArrowRight':
|
|
40
|
+
case 'ArrowUp':
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
newValue = Math.min(newValue + step, state.max);
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
case 'ArrowLeft':
|
|
46
|
+
case 'ArrowDown':
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
newValue = Math.max(newValue - step, state.min);
|
|
49
|
+
break;
|
|
50
|
+
|
|
51
|
+
case 'Home':
|
|
52
|
+
e.preventDefault();
|
|
53
|
+
newValue = state.min;
|
|
54
|
+
break;
|
|
55
|
+
|
|
56
|
+
case 'End':
|
|
57
|
+
e.preventDefault();
|
|
58
|
+
newValue = state.max;
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
case 'PageUp':
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
newValue = Math.min(newValue + (step * 10), state.max);
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
case 'PageDown':
|
|
67
|
+
e.preventDefault();
|
|
68
|
+
newValue = Math.max(newValue - (step * 10), state.min);
|
|
69
|
+
break;
|
|
70
|
+
|
|
71
|
+
default:
|
|
72
|
+
return; // Exit if not a handled key
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Update the value
|
|
76
|
+
if (isSecondThumb) {
|
|
77
|
+
state.secondValue = newValue;
|
|
78
|
+
} else {
|
|
79
|
+
state.value = newValue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Update UI
|
|
83
|
+
updateUi();
|
|
84
|
+
|
|
85
|
+
// Trigger events
|
|
86
|
+
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
87
|
+
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const handleFocus = (e, isSecondThumb = false) => {
|
|
91
|
+
if (state.component.disabled && state.component.disabled.isDisabled()) return;
|
|
92
|
+
|
|
93
|
+
// Show value bubble
|
|
94
|
+
showValueBubble(isSecondThumb ? secondValueBubble : valueBubble, true);
|
|
95
|
+
|
|
96
|
+
// Trigger focus event
|
|
97
|
+
triggerEvent(SLIDER_EVENTS.FOCUS, e);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const handleBlur = (e, isSecondThumb = false) => {
|
|
101
|
+
// Hide value bubble
|
|
102
|
+
showValueBubble(isSecondThumb ? secondValueBubble : valueBubble, false);
|
|
103
|
+
|
|
104
|
+
// Trigger blur event
|
|
105
|
+
triggerEvent(SLIDER_EVENTS.BLUR, e);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Return handlers
|
|
109
|
+
return {
|
|
110
|
+
handleKeyDown,
|
|
111
|
+
handleFocus,
|
|
112
|
+
handleBlur
|
|
113
|
+
};
|
|
114
|
+
};
|