@mustib/web-components 0.0.0-alpha.0
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/README.md +17 -0
- package/components/mu-element.d.ts +107 -0
- package/components/mu-element.js +4 -0
- package/components/mu-icon.d.ts +25 -0
- package/components/mu-icon.js +65 -0
- package/components/mu-range-fill.d.ts +48 -0
- package/components/mu-range-fill.js +94 -0
- package/components/mu-range-thumb-value.d.ts +48 -0
- package/components/mu-range-thumb-value.js +137 -0
- package/components/mu-range-thumb.d.ts +120 -0
- package/components/mu-range-thumb.js +305 -0
- package/components/mu-range.d.ts +206 -0
- package/components/mu-range.js +661 -0
- package/components/mu-select-item.d.ts +29 -0
- package/components/mu-select-item.js +124 -0
- package/components/mu-select-items.d.ts +218 -0
- package/components/mu-select-items.js +570 -0
- package/components/mu-select-label-content.d.ts +38 -0
- package/components/mu-select-label-content.js +159 -0
- package/components/mu-select-label.d.ts +52 -0
- package/components/mu-select-label.js +352 -0
- package/components/mu-select.d.ts +63 -0
- package/components/mu-select.js +347 -0
- package/components/mu-transparent.d.ts +56 -0
- package/components/mu-transparent.js +75 -0
- package/components/mu-trigger.d.ts +129 -0
- package/components/mu-trigger.js +175 -0
- package/decorators.d.ts +34 -0
- package/decorators.js +50 -0
- package/index.d.ts +15 -0
- package/index.js +17 -0
- package/mu-element-CZDI_RCY.js +1117 -0
- package/package.json +45 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
import { M as MUElement, _ as __decorate, t as throttle, d as debounce, w as wait, g as getElementBoundaries } from '../mu-element-CZDI_RCY.js';
|
|
2
|
+
import { css, html } from 'lit';
|
|
3
|
+
import { property } from 'lit/decorators.js';
|
|
4
|
+
import { MuRangeThumb } from './mu-range-thumb.js';
|
|
5
|
+
import { MuTransparent } from './mu-transparent.js';
|
|
6
|
+
import { MuRangeFill } from './mu-range-fill.js';
|
|
7
|
+
import '../decorators.js';
|
|
8
|
+
import './mu-range-thumb-value.js';
|
|
9
|
+
|
|
10
|
+
class MuRange extends MUElement {
|
|
11
|
+
get isControlled() {
|
|
12
|
+
return this.value !== undefined;
|
|
13
|
+
}
|
|
14
|
+
set activeThumb(thumb) {
|
|
15
|
+
if (thumb && (thumb.element.transparent || thumb.element.disabled || thumb.element.readonly))
|
|
16
|
+
return;
|
|
17
|
+
const prev = this._activeThumb;
|
|
18
|
+
if (prev)
|
|
19
|
+
prev.element.focused = false;
|
|
20
|
+
this._activeThumb = thumb;
|
|
21
|
+
}
|
|
22
|
+
get activeThumb() {
|
|
23
|
+
return this._activeThumb;
|
|
24
|
+
}
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this.eventActionData = undefined;
|
|
28
|
+
this._addEventActionAttributes = undefined;
|
|
29
|
+
/**
|
|
30
|
+
* The axis of the range.
|
|
31
|
+
*
|
|
32
|
+
* `x` - horizontal axis auto matching the direction
|
|
33
|
+
*
|
|
34
|
+
* `-x` - horizontal axis reversed
|
|
35
|
+
*
|
|
36
|
+
* `y` - vertical axis
|
|
37
|
+
*
|
|
38
|
+
* `-y` - vertical axis reversed
|
|
39
|
+
*/
|
|
40
|
+
this.axis = 'x';
|
|
41
|
+
/**
|
|
42
|
+
* The minimum value of the range.
|
|
43
|
+
*/
|
|
44
|
+
this.min = 0;
|
|
45
|
+
/**
|
|
46
|
+
* The maximum value of the range.
|
|
47
|
+
*/
|
|
48
|
+
this.max = 100;
|
|
49
|
+
/**
|
|
50
|
+
* Thumb behavior when pointerdown on a non-thumb element.
|
|
51
|
+
*
|
|
52
|
+
* - `prevent` - don't do anything
|
|
53
|
+
*
|
|
54
|
+
* - `dispatch` - dispatch the {@link Events['mu-range-empty-area']} event
|
|
55
|
+
*
|
|
56
|
+
* - `nearest` - move the nearest thumb to the pointer position
|
|
57
|
+
*
|
|
58
|
+
* @default `nearest`
|
|
59
|
+
*/
|
|
60
|
+
this.emptyArea = 'nearest';
|
|
61
|
+
this._isReadyPromise = this.generateIsReadyPromise();
|
|
62
|
+
this._thumbs = [];
|
|
63
|
+
this._thumbsElementsMap = new Map();
|
|
64
|
+
this._thumbsNamesMap = new Map();
|
|
65
|
+
/**
|
|
66
|
+
* this is used to prevent focus listener from running when the pointer is down otherwise active thumb will gain focus when the pointer is down
|
|
67
|
+
*/
|
|
68
|
+
this._isPointerDown = false;
|
|
69
|
+
this._slotChangeHandler = async () => {
|
|
70
|
+
const previousThumbsElementsMap = new Map(this._thumbsElementsMap);
|
|
71
|
+
this._thumbs = [];
|
|
72
|
+
this._thumbsElementsMap.clear();
|
|
73
|
+
this._thumbsNamesMap.clear();
|
|
74
|
+
const previousActiveThumb = this.activeThumb;
|
|
75
|
+
this.activeThumb = undefined;
|
|
76
|
+
const fillElements = [];
|
|
77
|
+
const assignElement = (element) => {
|
|
78
|
+
if (element instanceof MuRangeThumb) {
|
|
79
|
+
element.range = [this.min, this.max];
|
|
80
|
+
element.axis = this.axis;
|
|
81
|
+
const previousThumb = previousThumbsElementsMap.get(element);
|
|
82
|
+
const thumb = previousThumb ?? {
|
|
83
|
+
element,
|
|
84
|
+
name: element.name ?? element.id,
|
|
85
|
+
linkedFillElements: undefined,
|
|
86
|
+
value: element.value,
|
|
87
|
+
index: this._thumbs.length,
|
|
88
|
+
};
|
|
89
|
+
this._thumbs.push(thumb);
|
|
90
|
+
this._thumbsElementsMap.set(element, thumb);
|
|
91
|
+
this._thumbsNamesMap.set(thumb.name, thumb);
|
|
92
|
+
if (previousActiveThumb?.element === element)
|
|
93
|
+
this.activeThumb = thumb;
|
|
94
|
+
}
|
|
95
|
+
else if (element instanceof MuRangeFill) {
|
|
96
|
+
fillElements.push(element);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
this.renderRoot.querySelector('slot')?.assignedElements({ flatten: true }).forEach(el => {
|
|
100
|
+
if (el instanceof MuTransparent) {
|
|
101
|
+
el.contents.forEach(assignElement);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
assignElement(el);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
if (this._thumbs.length === 0) {
|
|
108
|
+
console.warn('mu-range should have at least one mu-range-thumb', this);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.sortThumbs();
|
|
112
|
+
}
|
|
113
|
+
fillElements.forEach((element, i) => {
|
|
114
|
+
const thumbsNames = element.for ? element.for.split(',') : [this._thumbs[i]?.name];
|
|
115
|
+
if (thumbsNames.length === 0) {
|
|
116
|
+
console.warn(`mu-range-fill has no thumb names`, element);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
element.setAxis(this.axis);
|
|
120
|
+
const thumbs = thumbsNames.reduce((thumbs, name) => {
|
|
121
|
+
const thumb = this._thumbsNamesMap.get(name || '');
|
|
122
|
+
if (!thumb) {
|
|
123
|
+
console.warn(`no thumb found with name (${name}) for mu-range-fill`, element);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
thumbs.push(thumb);
|
|
127
|
+
}
|
|
128
|
+
return thumbs;
|
|
129
|
+
}, []);
|
|
130
|
+
const rangeFill = {
|
|
131
|
+
element,
|
|
132
|
+
linkedThumbs: thumbs
|
|
133
|
+
};
|
|
134
|
+
thumbs.forEach(thumb => {
|
|
135
|
+
if (thumb.linkedFillElements)
|
|
136
|
+
thumb.linkedFillElements.push(rangeFill);
|
|
137
|
+
else
|
|
138
|
+
thumb.linkedFillElements = [rangeFill];
|
|
139
|
+
this.updateRangeFill(rangeFill);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
if (!this._isReadyPromise.resolved) {
|
|
143
|
+
this._isReadyPromise.resolve();
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const deletedThumbs = [...previousThumbsElementsMap.values()].filter(thumb => !this._thumbsElementsMap.has(thumb.element));
|
|
147
|
+
const newThumbs = this._thumbs.filter(thumb => !previousThumbsElementsMap.has(thumb.element));
|
|
148
|
+
if (newThumbs.length) {
|
|
149
|
+
const eventName = 'mu-range-added-thumbs';
|
|
150
|
+
const event = new CustomEvent(eventName, {
|
|
151
|
+
bubbles: true,
|
|
152
|
+
cancelable: true,
|
|
153
|
+
composed: true,
|
|
154
|
+
detail: {
|
|
155
|
+
data: newThumbs.map(thumb => ({ name: thumb.name, value: thumb.value }))
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
this.dispatchEvent(event);
|
|
159
|
+
}
|
|
160
|
+
if (deletedThumbs.length) {
|
|
161
|
+
const eventName = 'mu-range-removed-thumbs';
|
|
162
|
+
const event = new CustomEvent(eventName, {
|
|
163
|
+
bubbles: true,
|
|
164
|
+
cancelable: true,
|
|
165
|
+
composed: true,
|
|
166
|
+
detail: {
|
|
167
|
+
data: deletedThumbs.map(thumb => ({ name: thumb.name, value: thumb.value }))
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
this.dispatchEvent(event);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
this._keydownHandler = (e) => {
|
|
175
|
+
const thumb = this.activeThumb;
|
|
176
|
+
if (this.disabled || this.readonly || !thumb || e.defaultPrevented)
|
|
177
|
+
return;
|
|
178
|
+
let increaseKey = 'ArrowRight';
|
|
179
|
+
let decreaseKey = 'ArrowLeft';
|
|
180
|
+
switch (this.axis) {
|
|
181
|
+
case 'x':
|
|
182
|
+
increaseKey = 'ArrowRight';
|
|
183
|
+
decreaseKey = 'ArrowLeft';
|
|
184
|
+
break;
|
|
185
|
+
case "-x":
|
|
186
|
+
decreaseKey = 'ArrowRight';
|
|
187
|
+
increaseKey = 'ArrowLeft';
|
|
188
|
+
break;
|
|
189
|
+
case "y":
|
|
190
|
+
decreaseKey = 'ArrowDown';
|
|
191
|
+
increaseKey = 'ArrowUp';
|
|
192
|
+
break;
|
|
193
|
+
case "-y":
|
|
194
|
+
decreaseKey = 'ArrowUp';
|
|
195
|
+
increaseKey = 'ArrowDown';
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
this.axis;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
const setValue = (value) => {
|
|
202
|
+
e.preventDefault();
|
|
203
|
+
this.focus();
|
|
204
|
+
thumb.element.focused = true;
|
|
205
|
+
this._setThumbValue(thumb, value);
|
|
206
|
+
};
|
|
207
|
+
const jumpPercentage = 10;
|
|
208
|
+
const jumpStepValue = (thumb.element.maxValue - thumb.element.minValue) / jumpPercentage;
|
|
209
|
+
switch (e.key) {
|
|
210
|
+
case increaseKey:
|
|
211
|
+
setValue(thumb.value + thumb.element.step);
|
|
212
|
+
break;
|
|
213
|
+
case decreaseKey:
|
|
214
|
+
setValue(thumb.value - thumb.element.step);
|
|
215
|
+
break;
|
|
216
|
+
case 'Home':
|
|
217
|
+
setValue(thumb.element.minValue);
|
|
218
|
+
break;
|
|
219
|
+
case 'End':
|
|
220
|
+
setValue(thumb.element.maxValue);
|
|
221
|
+
case 'PageUp':
|
|
222
|
+
setValue(thumb.value + jumpStepValue);
|
|
223
|
+
break;
|
|
224
|
+
case 'PageDown':
|
|
225
|
+
setValue(thumb.value - jumpStepValue);
|
|
226
|
+
break;
|
|
227
|
+
case 'Tab':
|
|
228
|
+
{
|
|
229
|
+
this.switchNavigationActiveItem(e.shiftKey ? 'prev' : 'next') && e.preventDefault();
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
this._pointerdownHandler = ((e) => {
|
|
235
|
+
if (this.disabled || this.readonly || e.defaultPrevented)
|
|
236
|
+
return;
|
|
237
|
+
this._isPointerDown = true;
|
|
238
|
+
document.addEventListener('pointermove', this._documentPointermoveHandler);
|
|
239
|
+
document.addEventListener('pointerup', this._documentPointerupHandler);
|
|
240
|
+
const thumbEl = MUElement.closestPierce('mu-range-thumb', e.target);
|
|
241
|
+
if ((thumbEl && (thumbEl.disabled || thumbEl.readonly) || this.emptyArea === 'prevent'))
|
|
242
|
+
return;
|
|
243
|
+
if (thumbEl && !thumbEl.transparent) {
|
|
244
|
+
const activeThumb = this._thumbsElementsMap.get(thumbEl);
|
|
245
|
+
this.activeThumb = activeThumb;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (this.emptyArea === 'dispatch') {
|
|
249
|
+
const eventName = 'mu-range-empty-area';
|
|
250
|
+
const event = new CustomEvent(eventName, {
|
|
251
|
+
bubbles: true,
|
|
252
|
+
cancelable: true,
|
|
253
|
+
composed: true,
|
|
254
|
+
detail: { values: this._getValuesFromEvent(e) }
|
|
255
|
+
});
|
|
256
|
+
this.dispatchEvent(event);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this.emptyArea;
|
|
260
|
+
const { value } = this._getValuesFromEvent(e);
|
|
261
|
+
const shouldBreak = (item) => {
|
|
262
|
+
return ((item.element.disabled || item.element.readonly) && !(item.element.intersectBehavior === 'pass-over' || item.element.transparent));
|
|
263
|
+
};
|
|
264
|
+
const isNavigable = (item) => {
|
|
265
|
+
return !(item.element.transparent || item.element.disabled || item.element.readonly);
|
|
266
|
+
};
|
|
267
|
+
const leftThumb = this.getNavigationItem({
|
|
268
|
+
direction: 'next',
|
|
269
|
+
items: this._thumbs,
|
|
270
|
+
shouldBreak(item) {
|
|
271
|
+
return item.value > value && shouldBreak(item);
|
|
272
|
+
},
|
|
273
|
+
isNavigable: (item) => {
|
|
274
|
+
return item.value > value && isNavigable(item);
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
const rightThumb = this.getNavigationItem({
|
|
278
|
+
direction: 'prev',
|
|
279
|
+
items: this._thumbs,
|
|
280
|
+
fromIndex: leftThumb?.index || this._thumbs.length,
|
|
281
|
+
shouldBreak(item) {
|
|
282
|
+
return item.value < value && shouldBreak(item);
|
|
283
|
+
},
|
|
284
|
+
isNavigable: (item) => {
|
|
285
|
+
return item.value < value && isNavigable(item);
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
let candidateThumb;
|
|
289
|
+
if (!rightThumb)
|
|
290
|
+
candidateThumb = leftThumb;
|
|
291
|
+
else if (!leftThumb)
|
|
292
|
+
candidateThumb = rightThumb;
|
|
293
|
+
else {
|
|
294
|
+
candidateThumb = value - rightThumb.value > leftThumb.value - value ? leftThumb : rightThumb;
|
|
295
|
+
}
|
|
296
|
+
if (candidateThumb) {
|
|
297
|
+
this._setThumbValue(candidateThumb, value);
|
|
298
|
+
this.activeThumb = candidateThumb;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
this._documentPointerupHandler = (e) => {
|
|
302
|
+
this._isPointerDown = false;
|
|
303
|
+
document.removeEventListener('pointermove', this._documentPointermoveHandler);
|
|
304
|
+
document.removeEventListener('pointerup', this._documentPointerupHandler);
|
|
305
|
+
if (!this.activeThumb)
|
|
306
|
+
return;
|
|
307
|
+
const { value } = this._getValuesFromEvent(e);
|
|
308
|
+
this._setThumbValue(this.activeThumb, value);
|
|
309
|
+
};
|
|
310
|
+
this._pointermoveHandler = (e) => {
|
|
311
|
+
if (!this.activeThumb)
|
|
312
|
+
return;
|
|
313
|
+
const { value } = this._getValuesFromEvent(e);
|
|
314
|
+
this._setThumbValue(this.activeThumb, value);
|
|
315
|
+
};
|
|
316
|
+
this._documentPointermoveHandler = throttle((e) => {
|
|
317
|
+
this._pointermoveHandler(e);
|
|
318
|
+
this._debouncedPointermoveHandler(e);
|
|
319
|
+
}, 50);
|
|
320
|
+
this._debouncedPointermoveHandler = debounce(this._pointermoveHandler, 50);
|
|
321
|
+
this.addEventListener('keydown', this._keydownHandler);
|
|
322
|
+
this.updateComplete.then(() => {
|
|
323
|
+
this.addEventListener('blur', () => {
|
|
324
|
+
if (this._activeThumb) {
|
|
325
|
+
this._activeThumb.element.focused = false;
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
this.addEventListener('focus', (e) => {
|
|
329
|
+
if (this._isPointerDown || this.disabled || this.readonly || e.defaultPrevented)
|
|
330
|
+
return;
|
|
331
|
+
if (this._activeThumb) {
|
|
332
|
+
e.preventDefault();
|
|
333
|
+
this._activeThumb.element.focused = true;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
this.switchNavigationActiveItem('next') && e.preventDefault();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
this.renderRoot.addEventListener('slotchange', this._slotChangeHandler);
|
|
340
|
+
this.addEventListener('mu-transparent-slotchange', this._slotChangeHandler);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
disconnectedCallback() {
|
|
344
|
+
document.removeEventListener('pointermove', this._documentPointermoveHandler);
|
|
345
|
+
document.removeEventListener('pointerup', this._documentPointerupHandler);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
*
|
|
349
|
+
* @returns an array of objects containing the name and value of each thumb
|
|
350
|
+
*/
|
|
351
|
+
getValue() {
|
|
352
|
+
return this._thumbs.map(thumb => ({ name: thumb.name, value: thumb.value }));
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Programmatically insert a thumb element
|
|
356
|
+
*/
|
|
357
|
+
async insertThumbElement(thumbEl) {
|
|
358
|
+
this.appendChild(thumbEl);
|
|
359
|
+
await wait();
|
|
360
|
+
await this.updateComplete;
|
|
361
|
+
const thumb = this._thumbsElementsMap.get(thumbEl);
|
|
362
|
+
if (!thumb)
|
|
363
|
+
return;
|
|
364
|
+
this._setThumbValue(thumb, thumbEl.value);
|
|
365
|
+
this.activeThumb = thumb;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Switches the active thumb for keyboard navigation
|
|
369
|
+
*/
|
|
370
|
+
switchNavigationActiveItem(direction) {
|
|
371
|
+
const navigationThumb = this.getNavigationItem({
|
|
372
|
+
direction,
|
|
373
|
+
items: this._thumbs,
|
|
374
|
+
fromIndex: this._activeThumb?.index,
|
|
375
|
+
isNavigable(item) {
|
|
376
|
+
return !(item.element.transparent || item.element.disabled || item.element.readonly);
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
if (!navigationThumb)
|
|
380
|
+
return false;
|
|
381
|
+
this.activeThumb = navigationThumb;
|
|
382
|
+
this.focus();
|
|
383
|
+
navigationThumb.element.focused = true;
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
dispatchChangeEvent(thumbs = this._thumbs) {
|
|
387
|
+
const eventName = 'mu-range-change';
|
|
388
|
+
const data = thumbs.map(thumb => ({ name: thumb.name, value: thumb.value }));
|
|
389
|
+
this.dispatchEvent(new CustomEvent(eventName, { bubbles: true, composed: true, detail: { data: data }, cancelable: true }));
|
|
390
|
+
}
|
|
391
|
+
_setThumbValue(thumb, value) {
|
|
392
|
+
const stepValue = this._getThumbStepValue(thumb, value);
|
|
393
|
+
if (stepValue === thumb.value)
|
|
394
|
+
return;
|
|
395
|
+
if (this.isControlled) {
|
|
396
|
+
this.sortThumbs();
|
|
397
|
+
const sortedThumbs = this._thumbs.map(_thumb => ({ name: _thumb.name, value: _thumb.name === thumb.name ? stepValue : thumb.value }));
|
|
398
|
+
console.table(sortedThumbs);
|
|
399
|
+
// this.dispatchChangeEvent(sortedThumbs)
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const success = thumb.element.setValue(stepValue);
|
|
403
|
+
if (success) {
|
|
404
|
+
thumb.value = stepValue;
|
|
405
|
+
this.sortThumbs();
|
|
406
|
+
thumb.linkedFillElements?.forEach(this.updateRangeFill);
|
|
407
|
+
this.dispatchChangeEvent();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Updates the range fill element
|
|
412
|
+
*/
|
|
413
|
+
async updateRangeFill(range) {
|
|
414
|
+
const { element: rangeFillEl, linkedThumbs } = range;
|
|
415
|
+
const [firstThumb, secondThumb] = linkedThumbs;
|
|
416
|
+
if (firstThumb && !secondThumb) {
|
|
417
|
+
await firstThumb.element.updateComplete;
|
|
418
|
+
let start = 0;
|
|
419
|
+
let end = 0;
|
|
420
|
+
switch (rangeFillEl.type) {
|
|
421
|
+
case 'start':
|
|
422
|
+
start = firstThumb.element.minValue;
|
|
423
|
+
end = firstThumb.element.value;
|
|
424
|
+
break;
|
|
425
|
+
case "end":
|
|
426
|
+
start = firstThumb.element.value;
|
|
427
|
+
end = firstThumb.element.maxValue;
|
|
428
|
+
break;
|
|
429
|
+
case "both":
|
|
430
|
+
start = firstThumb.element.minValue;
|
|
431
|
+
end = firstThumb.element.maxValue;
|
|
432
|
+
break;
|
|
433
|
+
default:
|
|
434
|
+
rangeFillEl.type;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
rangeFillEl.setPercentage([firstThumb.element.getPercentageFromValue(start), firstThumb.element.getPercentageFromValue(end)]);
|
|
438
|
+
}
|
|
439
|
+
else if (firstThumb && secondThumb) {
|
|
440
|
+
await firstThumb.element.updateComplete;
|
|
441
|
+
await secondThumb.element.updateComplete;
|
|
442
|
+
rangeFillEl.setPercentage([firstThumb.element.getPercentageFromValue(firstThumb.element.value), secondThumb.element.getPercentageFromValue(secondThumb.element.value)]);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Takes a thumb and a value and returns the step value to be set
|
|
447
|
+
*/
|
|
448
|
+
_getThumbStepValue(thumb, value) {
|
|
449
|
+
const isAdd = value > thumb.value;
|
|
450
|
+
const step = thumb.element.step;
|
|
451
|
+
const numOfSteps = Math.round(value / step);
|
|
452
|
+
let stepValue;
|
|
453
|
+
if (isAdd) {
|
|
454
|
+
stepValue = Math.min(thumb.element.maxValue, Math.max(thumb.element.minValue, (numOfSteps * step)));
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
stepValue = Math.min(thumb.element.maxValue, Math.max(thumb.element.minValue, (numOfSteps * step)));
|
|
458
|
+
}
|
|
459
|
+
const nextThumb = this.getNavigationItem({
|
|
460
|
+
direction: 'next',
|
|
461
|
+
items: this._thumbs,
|
|
462
|
+
fromIndex: thumb.index,
|
|
463
|
+
isNavigable(item) {
|
|
464
|
+
return !(item.element.transparent || item.element.intersectBehavior === 'pass-over');
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
const prevThumb = this.getNavigationItem({
|
|
468
|
+
direction: 'prev',
|
|
469
|
+
items: this._thumbs,
|
|
470
|
+
fromIndex: thumb.index,
|
|
471
|
+
isNavigable(item) {
|
|
472
|
+
return !(item.element.transparent || item.element.intersectBehavior === 'pass-over');
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
if (isAdd && nextThumb && nextThumb.element.intersectBehavior === 'prevent') {
|
|
476
|
+
const nextRemainder = nextThumb.value % step;
|
|
477
|
+
if (thumb.element.forceStep && stepValue > nextThumb.value && nextRemainder !== 0) {
|
|
478
|
+
const newStep = nextThumb.value - nextRemainder;
|
|
479
|
+
const newStepRemainder = newStep % step;
|
|
480
|
+
stepValue = newStep - newStepRemainder;
|
|
481
|
+
}
|
|
482
|
+
else
|
|
483
|
+
stepValue = Math.min(nextThumb.value, stepValue);
|
|
484
|
+
}
|
|
485
|
+
else if (!isAdd && prevThumb && prevThumb.element.intersectBehavior === 'prevent') {
|
|
486
|
+
const prevRemainder = prevThumb.value % step;
|
|
487
|
+
if (thumb.element.forceStep && stepValue < prevThumb.value && prevRemainder !== 0) {
|
|
488
|
+
const newStep = prevRemainder + prevThumb.value;
|
|
489
|
+
const newStepRemainder = newStep % step;
|
|
490
|
+
stepValue = newStep - newStepRemainder;
|
|
491
|
+
}
|
|
492
|
+
else
|
|
493
|
+
stepValue = Math.max(prevThumb.value, stepValue);
|
|
494
|
+
}
|
|
495
|
+
return thumb.element.isValidValue(stepValue) ? stepValue : thumb.value;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* gets the value and percentage from pointer event
|
|
499
|
+
*/
|
|
500
|
+
_getValuesFromEvent(e) {
|
|
501
|
+
const direction = getComputedStyle(this).direction;
|
|
502
|
+
const boundaries = getElementBoundaries(this);
|
|
503
|
+
const xPoint = (e.clientX - boundaries.elementLeft);
|
|
504
|
+
const yPoint = (e.clientY - boundaries.elementTop);
|
|
505
|
+
const mousePoint = this.axis === 'x' ? xPoint : this.axis === '-x' ? boundaries.width - xPoint : this.axis === 'y' ? yPoint : boundaries.height - yPoint;
|
|
506
|
+
const elementSize = this.axis === 'x' || this.axis === '-x' ? boundaries.width : boundaries.height;
|
|
507
|
+
const rawPercentage = Math.max(0, Math.min(((mousePoint / elementSize) * 100), 100));
|
|
508
|
+
const percentage = direction === 'rtl' || this.axis === 'y' || this.axis === '-y' ? 100 - rawPercentage : rawPercentage;
|
|
509
|
+
const minValue = this.min;
|
|
510
|
+
const maxValue = this.max;
|
|
511
|
+
const roundedPercentage = (Math.round(percentage * 100)) / 100;
|
|
512
|
+
const value = (percentage / 100) * (maxValue - minValue) + minValue;
|
|
513
|
+
return { roundedPercentage, value, percentage, rawPercentage };
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* sorts the thumbs
|
|
517
|
+
*/
|
|
518
|
+
sortThumbs() {
|
|
519
|
+
this._thumbs.sort((a, b) => a.value - b.value).forEach((thumb, i) => {
|
|
520
|
+
thumb.index = i;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* @param valueString
|
|
525
|
+
*
|
|
526
|
+
* a comma separated string without spaces of (thumb values) or (an optional thumb name followed by a colon then the value) or a mix of both
|
|
527
|
+
*
|
|
528
|
+
* make sure to only use one format where all has names or no names, because if there is no names, the order of the values will be the same as the order of the thumbs.
|
|
529
|
+
* so you might end up with a thumb with a different value (named and not named).
|
|
530
|
+
*
|
|
531
|
+
* @example "0,50,100"
|
|
532
|
+
* @example "thumb1:0,thumb2:50,thumb3:100"
|
|
533
|
+
* @example "0,thumb2:50,100"
|
|
534
|
+
*
|
|
535
|
+
*/
|
|
536
|
+
async setValueFromString(valueString) {
|
|
537
|
+
await this.updateComplete;
|
|
538
|
+
if (!valueString)
|
|
539
|
+
return;
|
|
540
|
+
const separator = ',';
|
|
541
|
+
const values = valueString.split(separator);
|
|
542
|
+
const valuesNames = new Set();
|
|
543
|
+
let usedCharacterIndexInValueString = -1;
|
|
544
|
+
values.forEach((_value, i) => {
|
|
545
|
+
const arr = _value.split(':');
|
|
546
|
+
const thumbName = arr.length > 1 ? arr[0] : this._thumbs[i]?.name;
|
|
547
|
+
const valueNumber = Number(arr.length > 1 ? arr[1] : arr[0]);
|
|
548
|
+
usedCharacterIndexInValueString += _value.length;
|
|
549
|
+
if (!thumbName)
|
|
550
|
+
return;
|
|
551
|
+
if (valuesNames.has(thumbName)) {
|
|
552
|
+
console.warn(`The thumb named (${thumbName}) repeated multiple times in the value string (${valueString}), when trying to set range value from string, you can find that duplication with the value (${_value}) in that string from index (${usedCharacterIndexInValueString - i + 1}) to index (${usedCharacterIndexInValueString + i})`, this);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
valuesNames.add(thumbName);
|
|
556
|
+
if (Number.isNaN(valueNumber))
|
|
557
|
+
return;
|
|
558
|
+
const thumb = this._thumbsNamesMap.get(thumbName);
|
|
559
|
+
if (!thumb)
|
|
560
|
+
return;
|
|
561
|
+
const isValid = thumb.element.isValidValue(valueNumber);
|
|
562
|
+
if (!isValid) {
|
|
563
|
+
console.warn(`Trying to set invalid value (${valueNumber}) for the thumb named (${thumb.name}) from the string (${valueString})`, thumb.element, this);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
const success = thumb.element.setValue(valueNumber);
|
|
567
|
+
if (success) {
|
|
568
|
+
thumb.value = valueNumber;
|
|
569
|
+
thumb.linkedFillElements?.forEach(this.updateRangeFill);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
this.sortThumbs();
|
|
573
|
+
}
|
|
574
|
+
async getUpdateComplete() {
|
|
575
|
+
const result = await super.getUpdateComplete();
|
|
576
|
+
await this._isReadyPromise.promise;
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
async firstUpdated(_changedProperties) {
|
|
580
|
+
this._slotChangeHandler();
|
|
581
|
+
await this.updateComplete;
|
|
582
|
+
if (_changedProperties.has('defaultValue') && !this.isControlled)
|
|
583
|
+
this.setValueFromString(this.defaultValue || '');
|
|
584
|
+
}
|
|
585
|
+
async updated(_changedProperties) {
|
|
586
|
+
await this.updateComplete;
|
|
587
|
+
this.tabIndex = this.disabled || this.readonly ? -1 : 0;
|
|
588
|
+
if (_changedProperties.has('value')) {
|
|
589
|
+
this.setValueFromString(this.value || '');
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
render() {
|
|
593
|
+
return html `
|
|
594
|
+
<div tabindex='-1' id='container' part='container' @pointerdown='${this._pointerdownHandler}'>
|
|
595
|
+
<slot>
|
|
596
|
+
</slot>
|
|
597
|
+
</div>
|
|
598
|
+
`;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
MuRange.styles = [MUElement.cssBase, css `
|
|
602
|
+
#container {
|
|
603
|
+
--range-background-color: var(--mu-range-background-color, var(--mu-color-100));
|
|
604
|
+
--range-thickness: var(--mu-range-thickness, calc(var(--mu-base-rem) * .7));
|
|
605
|
+
position: relative;
|
|
606
|
+
border-radius: 9999px;
|
|
607
|
+
background-color: var(--range-background-color);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
:host(:focus-visible) #container::after {
|
|
611
|
+
content: '';
|
|
612
|
+
position: absolute;
|
|
613
|
+
inset: -4px;
|
|
614
|
+
border-radius: inherit;
|
|
615
|
+
${MUElement.css.focus}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
:host([axis='x']) #container,
|
|
619
|
+
:host([axis='-x']) #container
|
|
620
|
+
{
|
|
621
|
+
height: var(--range-thickness);
|
|
622
|
+
width: var(--range-distance, 100%);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
:host([axis='y']) #container,
|
|
626
|
+
:host([axis='-y']) #container
|
|
627
|
+
{
|
|
628
|
+
width: var(--range-thickness);
|
|
629
|
+
height: var(--range-distance, 150px);
|
|
630
|
+
max-height: 100%;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
@media (prefers-color-scheme: light) {
|
|
634
|
+
#container {
|
|
635
|
+
--range-background-color: var(--mu-range-background-color, var(--mu-color-200));
|
|
636
|
+
color: red;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
`];
|
|
641
|
+
__decorate([
|
|
642
|
+
property({ reflect: true, type: String })
|
|
643
|
+
], MuRange.prototype, "axis", void 0);
|
|
644
|
+
__decorate([
|
|
645
|
+
property({ reflect: true, type: Number })
|
|
646
|
+
], MuRange.prototype, "min", void 0);
|
|
647
|
+
__decorate([
|
|
648
|
+
property({ reflect: true, type: Number })
|
|
649
|
+
], MuRange.prototype, "max", void 0);
|
|
650
|
+
__decorate([
|
|
651
|
+
property()
|
|
652
|
+
], MuRange.prototype, "value", void 0);
|
|
653
|
+
__decorate([
|
|
654
|
+
property({ attribute: 'default-value' })
|
|
655
|
+
], MuRange.prototype, "defaultValue", void 0);
|
|
656
|
+
__decorate([
|
|
657
|
+
property({ reflect: true, type: String, attribute: 'empty-area' })
|
|
658
|
+
], MuRange.prototype, "emptyArea", void 0);
|
|
659
|
+
MuRange.register('mu-range');
|
|
660
|
+
|
|
661
|
+
export { MuRange };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MUElement } from './mu-element.js';
|
|
2
|
+
import { PropertyValues } from 'lit';
|
|
3
|
+
import '@mustib/utils/browser';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This element is designed to be stateless, its purpose is to provide a means of adding custom markup and attributes
|
|
7
|
+
* without the need for controlling its state externally. It should not be modified by other parties, and its state is
|
|
8
|
+
* solely controlled by its controller.
|
|
9
|
+
*/
|
|
10
|
+
declare class MuSelectItem extends MUElement {
|
|
11
|
+
static styles: any[];
|
|
12
|
+
eventActionData: undefined;
|
|
13
|
+
value: any;
|
|
14
|
+
selected: boolean;
|
|
15
|
+
active: boolean;
|
|
16
|
+
filteredOut: boolean;
|
|
17
|
+
protected firstUpdated(_changedProperties: PropertyValues): void;
|
|
18
|
+
connectedCallback(): void;
|
|
19
|
+
protected _addEventActionAttributes(): void;
|
|
20
|
+
updated(changed: PropertyValues<this>): void;
|
|
21
|
+
protected render(): unknown;
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface HTMLElementTagNameMap {
|
|
25
|
+
"mu-select-item": MuSelectItem;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export { MuSelectItem };
|