mtrl 0.2.6 → 0.2.7
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 +18 -0
- package/package.json +1 -1
- package/src/components/badge/_styles.scss +117 -109
- package/src/components/badge/api.ts +57 -59
- package/src/components/badge/badge.ts +16 -2
- package/src/components/badge/config.ts +65 -11
- package/src/components/badge/constants.ts +22 -12
- package/src/components/badge/features.ts +44 -40
- package/src/components/badge/types.ts +42 -30
- package/src/components/bottom-app-bar/_styles.scss +103 -0
- package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
- package/src/components/bottom-app-bar/config.ts +73 -0
- package/src/components/bottom-app-bar/index.ts +11 -0
- package/src/components/bottom-app-bar/types.ts +108 -0
- package/src/components/button/_styles.scss +0 -10
- package/src/components/button/api.ts +5 -0
- package/src/components/button/config.ts +5 -0
- package/src/components/button/types.ts +6 -0
- package/src/components/card/card.ts +13 -25
- package/src/components/card/config.ts +67 -22
- package/src/components/card/features.ts +3 -0
- package/src/components/card/types.ts +28 -0
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/datepicker/_styles.scss +358 -0
- package/src/components/datepicker/api.ts +272 -0
- package/src/components/datepicker/config.ts +144 -0
- package/src/components/datepicker/constants.ts +98 -0
- package/src/components/datepicker/datepicker.ts +346 -0
- package/src/components/datepicker/index.ts +9 -0
- package/src/components/datepicker/render.ts +452 -0
- package/src/components/datepicker/types.ts +268 -0
- package/src/components/datepicker/utils.ts +290 -0
- package/src/components/dialog/_styles.scss +174 -128
- package/src/components/dialog/api.ts +48 -13
- package/src/components/dialog/config.ts +9 -5
- package/src/components/dialog/dialog.ts +6 -3
- package/src/components/dialog/features.ts +290 -130
- package/src/components/dialog/types.ts +7 -4
- package/src/components/divider/_styles.scss +57 -0
- package/src/components/divider/config.ts +81 -0
- package/src/components/divider/divider.ts +37 -0
- package/src/components/divider/features.ts +207 -0
- package/src/components/divider/index.ts +5 -0
- package/src/components/divider/types.ts +55 -0
- package/src/components/extended-fab/_styles.scss +267 -0
- package/src/components/extended-fab/api.ts +141 -0
- package/src/components/extended-fab/config.ts +108 -0
- package/src/components/extended-fab/constants.ts +36 -0
- package/src/components/extended-fab/extended-fab.ts +125 -0
- package/src/components/extended-fab/index.ts +4 -0
- package/src/components/extended-fab/types.ts +287 -0
- package/src/components/fab/_styles.scss +225 -0
- package/src/components/fab/api.ts +97 -0
- package/src/components/fab/config.ts +94 -0
- package/src/components/fab/constants.ts +41 -0
- package/src/components/fab/fab.ts +67 -0
- package/src/components/fab/index.ts +4 -0
- package/src/components/fab/types.ts +234 -0
- package/src/components/navigation/_styles.scss +1 -0
- package/src/components/navigation/api.ts +78 -50
- package/src/components/navigation/features/items.ts +280 -0
- package/src/components/navigation/nav-item.ts +72 -23
- package/src/components/navigation/navigation.ts +54 -2
- package/src/components/navigation/types.ts +210 -188
- package/src/components/search/_styles.scss +306 -0
- package/src/components/search/api.ts +203 -0
- package/src/components/search/config.ts +87 -0
- package/src/components/search/constants.ts +21 -0
- package/src/components/search/features/index.ts +4 -0
- package/src/components/search/features/search.ts +718 -0
- package/src/components/search/features/states.ts +165 -0
- package/src/components/search/features/structure.ts +198 -0
- package/src/components/search/index.ts +10 -0
- package/src/components/search/search.ts +52 -0
- package/src/components/search/types.ts +163 -0
- package/src/components/segmented-button/_styles.scss +117 -0
- package/src/components/segmented-button/config.ts +67 -0
- package/src/components/segmented-button/constants.ts +42 -0
- package/src/components/segmented-button/index.ts +4 -0
- package/src/components/segmented-button/segment.ts +155 -0
- package/src/components/segmented-button/segmented-button.ts +250 -0
- package/src/components/segmented-button/types.ts +219 -0
- package/src/components/slider/_styles.scss +83 -24
- package/src/components/slider/accessibility.md +5 -5
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -47
- package/src/components/slider/features/handlers.ts +495 -0
- package/src/components/slider/features/index.ts +1 -2
- package/src/components/slider/features/slider.ts +66 -84
- package/src/components/slider/features/states.ts +195 -0
- package/src/components/slider/features/structure.ts +136 -206
- package/src/components/slider/features/ui.ts +145 -206
- package/src/components/slider/index.ts +2 -11
- package/src/components/slider/slider.ts +9 -12
- package/src/components/slider/types.ts +39 -24
- package/src/components/switch/_styles.scss +0 -2
- package/src/components/tabs/_styles.scss +94 -32
- package/src/components/tabs/features.ts +4 -2
- package/src/components/tabs/indicator.ts +73 -13
- package/src/components/tabs/types.ts +10 -2
- package/src/components/timepicker/README.md +277 -0
- package/src/components/timepicker/_styles.scss +451 -0
- package/src/components/timepicker/api.ts +632 -0
- package/src/components/timepicker/clockdial.ts +482 -0
- package/src/components/timepicker/config.ts +130 -0
- package/src/components/timepicker/constants.ts +138 -0
- package/src/components/timepicker/index.ts +8 -0
- package/src/components/timepicker/render.ts +613 -0
- package/src/components/timepicker/timepicker.ts +117 -0
- package/src/components/timepicker/types.ts +336 -0
- package/src/components/timepicker/utils.ts +241 -0
- package/src/components/top-app-bar/_styles.scss +225 -0
- package/src/components/top-app-bar/config.ts +83 -0
- package/src/components/top-app-bar/index.ts +11 -0
- package/src/components/top-app-bar/top-app-bar.ts +316 -0
- package/src/components/top-app-bar/types.ts +140 -0
- package/src/core/build/_ripple.scss +6 -6
- package/src/core/build/ripple.ts +72 -95
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/ripple.ts +4 -1
- package/src/core/compose/features/textlabel.ts +26 -2
- package/src/core/dom/create.ts +5 -0
- package/src/index.ts +9 -0
- package/src/styles/abstract/_theme.scss +9 -1
- package/src/styles/themes/_autumn.scss +21 -0
- package/src/styles/themes/_base-theme.scss +61 -0
- package/src/styles/themes/_baseline.scss +58 -0
- package/src/styles/themes/_bluekhaki.scss +125 -0
- package/src/styles/themes/_brownbeige.scss +125 -0
- package/src/styles/themes/_browngreen.scss +125 -0
- package/src/styles/themes/_forest.scss +6 -0
- package/src/styles/themes/_greenbeige.scss +125 -0
- package/src/styles/themes/_material.scss +125 -0
- package/src/styles/themes/_ocean.scss +6 -0
- package/src/styles/themes/_sageivory.scss +125 -0
- package/src/styles/themes/_spring.scss +6 -0
- package/src/styles/themes/_summer.scss +5 -0
- package/src/styles/themes/_sunset.scss +5 -0
- package/src/styles/themes/_tealcaramel.scss +125 -0
- package/src/styles/themes/_winter.scss +6 -0
- package/src/components/navigation/features/items.js +0 -192
- package/src/components/slider/features/appearance.ts +0 -94
- package/src/components/slider/features/disabled.ts +0 -68
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -396
- package/src/components/slider/features/keyboard.ts +0 -233
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
// src/components/slider/features/interactions.ts
|
|
2
|
-
import { SLIDER_EVENTS } 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
|
-
/**
|
|
46
|
-
* Clear any existing bubble hide timers
|
|
47
|
-
*/
|
|
48
|
-
const clearBubbleHideTimer = () => {
|
|
49
|
-
if (state.valueHideTimer) {
|
|
50
|
-
clearTimeout(state.valueHideTimer);
|
|
51
|
-
state.valueHideTimer = null;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Hide all bubbles immediately
|
|
57
|
-
*/
|
|
58
|
-
const hideAllBubbles = () => {
|
|
59
|
-
// Clear any pending hide timers
|
|
60
|
-
clearBubbleHideTimer();
|
|
61
|
-
|
|
62
|
-
// Hide both bubbles immediately
|
|
63
|
-
if (valueBubble) {
|
|
64
|
-
showValueBubble(valueBubble, false);
|
|
65
|
-
}
|
|
66
|
-
if (secondValueBubble) {
|
|
67
|
-
showValueBubble(secondValueBubble, false);
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Clear keyboard focus indicators across all sliders in the document
|
|
73
|
-
* Not just for this instance, but for any slider thumb
|
|
74
|
-
*/
|
|
75
|
-
const clearGlobalKeyboardFocus = () => {
|
|
76
|
-
// First clear local focus indicators
|
|
77
|
-
if (thumb) {
|
|
78
|
-
thumb.classList.remove(`${state.component.getClass('slider-thumb')}--focused`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (secondThumb) {
|
|
82
|
-
secondThumb.classList.remove(`${state.component.getClass('slider-thumb')}--focused`);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Now look for all slider thumbs in the document with the focused class
|
|
86
|
-
// This covers cases where we switch between sliders
|
|
87
|
-
try {
|
|
88
|
-
const focusClass = state.component.getClass('slider-thumb--focused');
|
|
89
|
-
const allFocusedThumbs = document.querySelectorAll(`.${focusClass}`);
|
|
90
|
-
|
|
91
|
-
// Remove focus class from all thumbs
|
|
92
|
-
allFocusedThumbs.forEach(element => {
|
|
93
|
-
element.classList.remove(focusClass);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Also blur the active element if it's a thumb
|
|
97
|
-
if (document.activeElement &&
|
|
98
|
-
document.activeElement.classList.contains(state.component.getClass('slider-thumb'))) {
|
|
99
|
-
(document.activeElement as HTMLElement).blur();
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
console.warn('Error clearing global keyboard focus:', error);
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Show the active bubble with consistent behavior
|
|
108
|
-
* @param bubble Bubble element to show
|
|
109
|
-
*/
|
|
110
|
-
const showActiveBubble = (bubble) => {
|
|
111
|
-
// First hide all bubbles
|
|
112
|
-
hideAllBubbles();
|
|
113
|
-
|
|
114
|
-
// Then show the active bubble if allowed by config
|
|
115
|
-
if (bubble && config.showValue) {
|
|
116
|
-
showValueBubble(bubble, true);
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Hide the active bubble with optional delay
|
|
122
|
-
* @param bubble Bubble element to hide
|
|
123
|
-
* @param delay Delay in milliseconds before hiding
|
|
124
|
-
*/
|
|
125
|
-
const hideActiveBubble = (bubble, delay = 0) => {
|
|
126
|
-
// Clear any existing timers first
|
|
127
|
-
clearBubbleHideTimer();
|
|
128
|
-
|
|
129
|
-
if (!bubble || !config.showValue) return;
|
|
130
|
-
|
|
131
|
-
if (delay > 0) {
|
|
132
|
-
// Set delayed hide
|
|
133
|
-
state.valueHideTimer = setTimeout(() => {
|
|
134
|
-
showValueBubble(bubble, false);
|
|
135
|
-
}, delay);
|
|
136
|
-
} else {
|
|
137
|
-
// Hide immediately
|
|
138
|
-
showValueBubble(bubble, false);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Handle thumb mouse down with improved bubble handling
|
|
144
|
-
*/
|
|
145
|
-
const handleThumbMouseDown = (e, isSecondThumb = false) => {
|
|
146
|
-
// Verify component exists and check if disabled
|
|
147
|
-
if (!state.component || (state.component.disabled && state.component.disabled.isDisabled())) {
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
e.preventDefault();
|
|
152
|
-
e.stopPropagation();
|
|
153
|
-
|
|
154
|
-
// First hide any existing visible bubbles
|
|
155
|
-
hideAllBubbles();
|
|
156
|
-
|
|
157
|
-
// Clear any keyboard focus indicators globally
|
|
158
|
-
clearGlobalKeyboardFocus();
|
|
159
|
-
|
|
160
|
-
state.dragging = true;
|
|
161
|
-
state.activeThumb = isSecondThumb ? secondThumb : thumb;
|
|
162
|
-
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
163
|
-
|
|
164
|
-
// Add dragging class to component element to style the thumb differently
|
|
165
|
-
state.component.element.classList.add(`${state.component.getClass('slider')}--dragging`);
|
|
166
|
-
|
|
167
|
-
// Show active bubble
|
|
168
|
-
showActiveBubble(state.activeBubble);
|
|
169
|
-
|
|
170
|
-
// Add global event listeners
|
|
171
|
-
document.addEventListener('mousemove', handleMouseMove);
|
|
172
|
-
document.addEventListener('mouseup', handleMouseUp);
|
|
173
|
-
document.addEventListener('touchmove', handleMouseMove, { passive: false });
|
|
174
|
-
document.addEventListener('touchend', handleMouseUp);
|
|
175
|
-
|
|
176
|
-
// Try to trigger start event (with error handling)
|
|
177
|
-
try {
|
|
178
|
-
triggerEvent(SLIDER_EVENTS.START, e);
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.warn('Error triggering START event:', error);
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Handle track mouse down with improved bubble handling
|
|
186
|
-
*/
|
|
187
|
-
const handleTrackMouseDown = (e) => {
|
|
188
|
-
// Verify component exists and check if disabled
|
|
189
|
-
if (!state.component || (state.component.disabled && state.component.disabled.isDisabled()) || !track) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
e.preventDefault();
|
|
194
|
-
|
|
195
|
-
// Hide any existing visible bubbles
|
|
196
|
-
hideAllBubbles();
|
|
197
|
-
|
|
198
|
-
// Clear any keyboard focus indicators globally
|
|
199
|
-
clearGlobalKeyboardFocus();
|
|
200
|
-
|
|
201
|
-
// Determine which thumb to move based on click position
|
|
202
|
-
let isSecondThumb = false;
|
|
203
|
-
|
|
204
|
-
try {
|
|
205
|
-
// Get track rect for calculating position
|
|
206
|
-
const trackRect = track.getBoundingClientRect();
|
|
207
|
-
|
|
208
|
-
// Get position from mouse or touch event
|
|
209
|
-
const position = e.type.includes('touch')
|
|
210
|
-
? e.touches[0].clientX
|
|
211
|
-
: e.clientX;
|
|
212
|
-
|
|
213
|
-
// Calculate value at click position
|
|
214
|
-
let newValue = getValueFromPosition(position);
|
|
215
|
-
|
|
216
|
-
// Round to step if needed
|
|
217
|
-
if (config.snapToSteps && state.step > 0) {
|
|
218
|
-
newValue = roundToStep(newValue);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Clamp value to min/max
|
|
222
|
-
newValue = clamp(newValue, state.min, state.max);
|
|
223
|
-
|
|
224
|
-
if (config.range && state.secondValue !== null) {
|
|
225
|
-
// For range slider, determine which thumb to move (closest to click position)
|
|
226
|
-
const distToFirst = Math.abs(newValue - state.value);
|
|
227
|
-
const distToSecond = Math.abs(newValue - state.secondValue);
|
|
228
|
-
|
|
229
|
-
isSecondThumb = distToSecond < distToFirst;
|
|
230
|
-
|
|
231
|
-
// Update the appropriate value
|
|
232
|
-
if (isSecondThumb) {
|
|
233
|
-
state.secondValue = newValue;
|
|
234
|
-
} else {
|
|
235
|
-
state.value = newValue;
|
|
236
|
-
}
|
|
237
|
-
} else {
|
|
238
|
-
// Single thumb slider - just update the value
|
|
239
|
-
state.value = newValue;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Update UI immediately
|
|
243
|
-
updateUi();
|
|
244
|
-
|
|
245
|
-
// Trigger events
|
|
246
|
-
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
247
|
-
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
248
|
-
} catch (error) {
|
|
249
|
-
console.warn('Error handling track click:', error);
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Set active elements
|
|
253
|
-
state.activeThumb = isSecondThumb ? secondThumb : thumb;
|
|
254
|
-
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
255
|
-
|
|
256
|
-
// Call thumb mouse down to start dragging
|
|
257
|
-
handleThumbMouseDown(e, isSecondThumb);
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Handle mouse move with improved thumb and bubble switching
|
|
262
|
-
*/
|
|
263
|
-
const handleMouseMove = (e) => {
|
|
264
|
-
if (!state.dragging || !state.activeThumb) return;
|
|
265
|
-
|
|
266
|
-
e.preventDefault();
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
// Get position
|
|
270
|
-
const position = e.type.includes('touch')
|
|
271
|
-
? e.touches[0].clientX
|
|
272
|
-
: e.clientX;
|
|
273
|
-
|
|
274
|
-
// Calculate new value
|
|
275
|
-
let newValue = getValueFromPosition(position);
|
|
276
|
-
|
|
277
|
-
// Round to step if needed
|
|
278
|
-
if (config.snapToSteps && state.step > 0) {
|
|
279
|
-
newValue = roundToStep(newValue);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Clamp value to min/max
|
|
283
|
-
newValue = clamp(newValue, state.min, state.max);
|
|
284
|
-
|
|
285
|
-
// Check if this is the second thumb
|
|
286
|
-
const isSecondThumb = state.activeThumb === secondThumb;
|
|
287
|
-
|
|
288
|
-
// For range slider, ensure thumbs don't cross
|
|
289
|
-
if (config.range && state.secondValue !== null) {
|
|
290
|
-
if (isSecondThumb) {
|
|
291
|
-
// Second thumb is active
|
|
292
|
-
|
|
293
|
-
// Don't allow second thumb to go below first thumb
|
|
294
|
-
if (newValue >= state.value) {
|
|
295
|
-
state.secondValue = newValue;
|
|
296
|
-
} else {
|
|
297
|
-
// Thumbs are crossed, need to swap them
|
|
298
|
-
|
|
299
|
-
// First hide current bubble
|
|
300
|
-
hideActiveBubble(state.activeBubble, 0);
|
|
301
|
-
|
|
302
|
-
// Swap values
|
|
303
|
-
state.secondValue = state.value;
|
|
304
|
-
state.value = newValue;
|
|
305
|
-
|
|
306
|
-
// Swap active elements
|
|
307
|
-
state.activeThumb = thumb;
|
|
308
|
-
state.activeBubble = valueBubble;
|
|
309
|
-
|
|
310
|
-
// Show new active bubble
|
|
311
|
-
showActiveBubble(state.activeBubble);
|
|
312
|
-
}
|
|
313
|
-
} else {
|
|
314
|
-
// First thumb is active
|
|
315
|
-
|
|
316
|
-
// Don't allow first thumb to go above second thumb
|
|
317
|
-
if (newValue <= state.secondValue) {
|
|
318
|
-
state.value = newValue;
|
|
319
|
-
} else {
|
|
320
|
-
// Thumbs are crossed, need to swap them
|
|
321
|
-
|
|
322
|
-
// First hide current bubble
|
|
323
|
-
hideActiveBubble(state.activeBubble, 0);
|
|
324
|
-
|
|
325
|
-
// Swap values
|
|
326
|
-
state.value = state.secondValue;
|
|
327
|
-
state.secondValue = newValue;
|
|
328
|
-
|
|
329
|
-
// Swap active elements
|
|
330
|
-
state.activeThumb = secondThumb;
|
|
331
|
-
state.activeBubble = secondValueBubble;
|
|
332
|
-
|
|
333
|
-
// Show new active bubble
|
|
334
|
-
showActiveBubble(state.activeBubble);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
} else {
|
|
338
|
-
// Regular slider
|
|
339
|
-
state.value = newValue;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Update UI
|
|
343
|
-
updateUi();
|
|
344
|
-
|
|
345
|
-
// Trigger input event (continuously while dragging)
|
|
346
|
-
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
347
|
-
} catch (error) {
|
|
348
|
-
console.warn('Error during slider drag:', error);
|
|
349
|
-
}
|
|
350
|
-
};
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Handle mouse up with consistent bubble hiding
|
|
354
|
-
*/
|
|
355
|
-
const handleMouseUp = (e) => {
|
|
356
|
-
if (!state.dragging) return;
|
|
357
|
-
|
|
358
|
-
e.preventDefault();
|
|
359
|
-
|
|
360
|
-
state.dragging = false;
|
|
361
|
-
|
|
362
|
-
// Remove dragging class from component element
|
|
363
|
-
state.component.element.classList.remove(`${state.component.getClass('slider')}--dragging`);
|
|
364
|
-
|
|
365
|
-
// Hide bubble with delay
|
|
366
|
-
const currentBubble = state.activeBubble;
|
|
367
|
-
hideActiveBubble(currentBubble, 1000); // Hide after 1 second
|
|
368
|
-
|
|
369
|
-
// Remove global event listeners
|
|
370
|
-
document.removeEventListener('mousemove', handleMouseMove);
|
|
371
|
-
document.removeEventListener('mouseup', handleMouseUp);
|
|
372
|
-
document.removeEventListener('touchmove', handleMouseMove);
|
|
373
|
-
document.removeEventListener('touchend', handleMouseUp);
|
|
374
|
-
|
|
375
|
-
// Reset active thumb
|
|
376
|
-
state.activeThumb = null;
|
|
377
|
-
|
|
378
|
-
try {
|
|
379
|
-
// Trigger change event (only when done dragging)
|
|
380
|
-
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
381
|
-
|
|
382
|
-
// Trigger end event
|
|
383
|
-
triggerEvent(SLIDER_EVENTS.END, e);
|
|
384
|
-
} catch (error) {
|
|
385
|
-
console.warn('Error triggering events on mouse up:', error);
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
|
|
389
|
-
// Return handlers
|
|
390
|
-
return {
|
|
391
|
-
handleThumbMouseDown,
|
|
392
|
-
handleTrackMouseDown,
|
|
393
|
-
handleMouseMove,
|
|
394
|
-
handleMouseUp
|
|
395
|
-
};
|
|
396
|
-
};
|
|
@@ -1,233 +0,0 @@
|
|
|
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
|
-
// Last focused thumb tracker to handle tab sequences properly
|
|
25
|
-
let lastFocusedThumb = null;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Clear any existing bubble hide timers
|
|
29
|
-
*/
|
|
30
|
-
const clearBubbleHideTimer = () => {
|
|
31
|
-
if (state.valueHideTimer) {
|
|
32
|
-
clearTimeout(state.valueHideTimer);
|
|
33
|
-
state.valueHideTimer = null;
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Hide all bubbles immediately
|
|
39
|
-
*/
|
|
40
|
-
const hideAllBubbles = () => {
|
|
41
|
-
// Clear any pending hide timers
|
|
42
|
-
clearBubbleHideTimer();
|
|
43
|
-
|
|
44
|
-
// Hide both bubbles immediately
|
|
45
|
-
if (valueBubble) {
|
|
46
|
-
showValueBubble(valueBubble, false);
|
|
47
|
-
}
|
|
48
|
-
if (secondValueBubble) {
|
|
49
|
-
showValueBubble(secondValueBubble, false);
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Shows a bubble element with consistent behavior
|
|
55
|
-
*/
|
|
56
|
-
const showBubble = (bubble) => {
|
|
57
|
-
// First hide all bubbles
|
|
58
|
-
hideAllBubbles();
|
|
59
|
-
|
|
60
|
-
// Then show the active bubble
|
|
61
|
-
if (bubble) {
|
|
62
|
-
showValueBubble(bubble, true);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Hides a bubble element with optional delay
|
|
68
|
-
*/
|
|
69
|
-
const hideBubble = (bubble, delay = 0) => {
|
|
70
|
-
// Clear any existing timers
|
|
71
|
-
clearBubbleHideTimer();
|
|
72
|
-
|
|
73
|
-
if (!bubble) return;
|
|
74
|
-
|
|
75
|
-
if (delay > 0) {
|
|
76
|
-
state.valueHideTimer = setTimeout(() => {
|
|
77
|
-
showValueBubble(bubble, false);
|
|
78
|
-
}, delay);
|
|
79
|
-
} else {
|
|
80
|
-
showValueBubble(bubble, false);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
// Event handlers
|
|
85
|
-
const handleKeyDown = (e, isSecondThumb = false) => {
|
|
86
|
-
if (state.component.disabled && state.component.disabled.isDisabled()) return;
|
|
87
|
-
|
|
88
|
-
const step = state.step || 1;
|
|
89
|
-
let newValue;
|
|
90
|
-
let stepSize = step;
|
|
91
|
-
|
|
92
|
-
// Determine which value to modify
|
|
93
|
-
if (isSecondThumb) {
|
|
94
|
-
newValue = state.secondValue;
|
|
95
|
-
} else {
|
|
96
|
-
newValue = state.value;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Handle tab key specifically for range sliders
|
|
100
|
-
if (e.key === 'Tab') {
|
|
101
|
-
// Let the browser handle the tab navigation
|
|
102
|
-
// We'll deal with showing/hiding bubbles in the focus/blur handlers
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Determine step size based on modifier keys
|
|
107
|
-
if (e.shiftKey) {
|
|
108
|
-
stepSize = step * 10; // Large step when Shift is pressed
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
let valueChanged = false;
|
|
112
|
-
|
|
113
|
-
switch (e.key) {
|
|
114
|
-
case 'ArrowRight':
|
|
115
|
-
case 'ArrowUp':
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
newValue = Math.min(newValue + stepSize, state.max);
|
|
118
|
-
valueChanged = true;
|
|
119
|
-
break;
|
|
120
|
-
|
|
121
|
-
case 'ArrowLeft':
|
|
122
|
-
case 'ArrowDown':
|
|
123
|
-
e.preventDefault();
|
|
124
|
-
newValue = Math.max(newValue - stepSize, state.min);
|
|
125
|
-
valueChanged = true;
|
|
126
|
-
break;
|
|
127
|
-
|
|
128
|
-
case 'Home':
|
|
129
|
-
e.preventDefault();
|
|
130
|
-
newValue = state.min;
|
|
131
|
-
valueChanged = true;
|
|
132
|
-
break;
|
|
133
|
-
|
|
134
|
-
case 'End':
|
|
135
|
-
e.preventDefault();
|
|
136
|
-
newValue = state.max;
|
|
137
|
-
valueChanged = true;
|
|
138
|
-
break;
|
|
139
|
-
|
|
140
|
-
case 'PageUp':
|
|
141
|
-
e.preventDefault();
|
|
142
|
-
newValue = Math.min(newValue + (step * 10), state.max);
|
|
143
|
-
valueChanged = true;
|
|
144
|
-
break;
|
|
145
|
-
|
|
146
|
-
case 'PageDown':
|
|
147
|
-
e.preventDefault();
|
|
148
|
-
newValue = Math.max(newValue - (step * 10), state.min);
|
|
149
|
-
valueChanged = true;
|
|
150
|
-
break;
|
|
151
|
-
|
|
152
|
-
default:
|
|
153
|
-
return; // Exit if not a handled key
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (!valueChanged) return;
|
|
157
|
-
|
|
158
|
-
// Update active bubble reference
|
|
159
|
-
state.activeBubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
160
|
-
|
|
161
|
-
// Show value bubble during keyboard interaction
|
|
162
|
-
showBubble(state.activeBubble);
|
|
163
|
-
|
|
164
|
-
// Update the value
|
|
165
|
-
if (isSecondThumb) {
|
|
166
|
-
state.secondValue = newValue;
|
|
167
|
-
} else {
|
|
168
|
-
state.value = newValue;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Update UI
|
|
172
|
-
updateUi();
|
|
173
|
-
|
|
174
|
-
// Trigger events
|
|
175
|
-
triggerEvent(SLIDER_EVENTS.INPUT, e);
|
|
176
|
-
triggerEvent(SLIDER_EVENTS.CHANGE, e);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const handleFocus = (e, isSecondThumb = false) => {
|
|
180
|
-
if (state.component.disabled && state.component.disabled.isDisabled()) return;
|
|
181
|
-
|
|
182
|
-
// Track the currently focused thumb for tab sequence handling
|
|
183
|
-
const currentThumb = isSecondThumb ? secondThumb : state.component.structure.thumb;
|
|
184
|
-
|
|
185
|
-
// If we're tabbing between thumbs, hide the previous bubble immediately
|
|
186
|
-
if (lastFocusedThumb && lastFocusedThumb !== currentThumb) {
|
|
187
|
-
hideAllBubbles();
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Update the last focused thumb
|
|
191
|
-
lastFocusedThumb = currentThumb;
|
|
192
|
-
|
|
193
|
-
// Add a class to indicate keyboard focus
|
|
194
|
-
currentThumb.classList.add(`${state.component.getClass('slider-thumb')}--focused`);
|
|
195
|
-
|
|
196
|
-
// Show value bubble on focus
|
|
197
|
-
const bubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
198
|
-
showBubble(bubble);
|
|
199
|
-
|
|
200
|
-
// Update active bubble reference
|
|
201
|
-
state.activeBubble = bubble;
|
|
202
|
-
|
|
203
|
-
// Trigger focus event
|
|
204
|
-
triggerEvent(SLIDER_EVENTS.FOCUS, e);
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const handleBlur = (e, isSecondThumb = false) => {
|
|
208
|
-
// Remove keyboard focus class
|
|
209
|
-
const thumb = isSecondThumb ? secondThumb : state.component.structure.thumb;
|
|
210
|
-
thumb.classList.remove(`${state.component.getClass('slider-thumb')}--focused`);
|
|
211
|
-
|
|
212
|
-
// Only hide the bubble if we're not tabbing to another thumb
|
|
213
|
-
// This check prevents the bubble from flickering when tabbing between thumbs
|
|
214
|
-
const relatedTarget = e.relatedTarget;
|
|
215
|
-
const otherThumb = isSecondThumb ? state.component.structure.thumb : secondThumb;
|
|
216
|
-
|
|
217
|
-
if (!relatedTarget || relatedTarget !== otherThumb) {
|
|
218
|
-
// We're not tabbing to the other thumb, so we can hide the bubble
|
|
219
|
-
const bubble = isSecondThumb ? secondValueBubble : valueBubble;
|
|
220
|
-
hideBubble(bubble, 200);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Trigger blur event
|
|
224
|
-
triggerEvent(SLIDER_EVENTS.BLUR, e);
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
// Return handlers
|
|
228
|
-
return {
|
|
229
|
-
handleKeyDown,
|
|
230
|
-
handleFocus,
|
|
231
|
-
handleBlur
|
|
232
|
-
};
|
|
233
|
-
};
|