@antadesign/anta 0.3.32 → 0.3.33
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/dist/avatar-core.d.ts +7 -2
- package/dist/bundle.css +1 -1
- package/dist/bundle.js +47 -37
- package/dist/components/Input.d.ts +9 -3
- package/dist/components/Input.js +2 -0
- package/dist/components/Slider.d.ts +22 -10
- package/dist/components/Slider.js +9 -5
- package/dist/elements/a-button.js +2 -4
- package/dist/elements/a-input-time.js +1 -2
- package/dist/elements/a-input.css +1 -1
- package/dist/elements/a-input.js +11 -8
- package/dist/elements/a-menu.d.ts +1 -1
- package/dist/elements/a-menu.js +17 -4
- package/dist/elements/a-slider.d.ts +7 -5
- package/dist/elements/a-slider.js +256 -59
- package/dist/general_types.d.ts +9 -4
- package/dist/index.d.ts +1 -1
- package/dist/theme-antune.css +1 -1
- package/docs/changelog.md +25 -0
- package/docs/components/button.md +9 -6
- package/docs/components/input.md +29 -9
- package/docs/components/panel.md +3 -2
- package/docs/components/select-faceted.md +19 -19
- package/docs/components/slider.md +139 -4
- package/docs/packages/plot.md +158 -19
- package/package.json +4 -2
|
@@ -4,6 +4,16 @@ const precisionOf = (value) => {
|
|
|
4
4
|
const exponent = value.toString().match(/(?:\.(\d+))?(?:e([+-]?\d+))?$/i);
|
|
5
5
|
return Math.max(0, (exponent?.[1]?.length ?? 0) - Number(exponent?.[2] ?? 0));
|
|
6
6
|
};
|
|
7
|
+
const parseSliderValue = (source, fallback) => {
|
|
8
|
+
if (source === null || !source.trim()) return fallback;
|
|
9
|
+
const parts = source.trim().split(/\s+/);
|
|
10
|
+
if (parts.length !== 1 && parts.length !== 2) return fallback;
|
|
11
|
+
const numbers = parts.map(Number);
|
|
12
|
+
if (!numbers.every(Number.isFinite)) return fallback;
|
|
13
|
+
return numbers.length === 2 ? [numbers[0], numbers[1]] : numbers[0];
|
|
14
|
+
};
|
|
15
|
+
const serializeSliderValue = (value) => Array.isArray(value) ? value.join(" ") : String(value);
|
|
16
|
+
const sameSliderValue = (left, right) => Array.isArray(left) && Array.isArray(right) ? left[0] === right[0] && left[1] === right[1] : !Array.isArray(left) && !Array.isArray(right) && left === right;
|
|
7
17
|
class ASliderElement extends HTMLElementBase {
|
|
8
18
|
static formAssociated = true;
|
|
9
19
|
static observedAttributes = [
|
|
@@ -16,13 +26,19 @@ class ASliderElement extends HTMLElementBase {
|
|
|
16
26
|
"track-click",
|
|
17
27
|
"value-display",
|
|
18
28
|
"value-prefix",
|
|
19
|
-
"value-suffix"
|
|
29
|
+
"value-suffix",
|
|
30
|
+
"inverted",
|
|
31
|
+
"name",
|
|
32
|
+
"aria-label",
|
|
33
|
+
"aria-labelledby"
|
|
20
34
|
];
|
|
21
35
|
internals;
|
|
22
36
|
#control;
|
|
23
37
|
#railArea;
|
|
24
38
|
#fill;
|
|
39
|
+
#fillEnd;
|
|
25
40
|
#thumb;
|
|
41
|
+
#thumbEnd;
|
|
26
42
|
#header;
|
|
27
43
|
#label;
|
|
28
44
|
#inlineValue;
|
|
@@ -32,25 +48,31 @@ class ASliderElement extends HTMLElementBase {
|
|
|
32
48
|
#endValuePrefix;
|
|
33
49
|
#endValueSuffix;
|
|
34
50
|
#thumbValue;
|
|
51
|
+
#thumbValueEnd;
|
|
35
52
|
#thumbValuePrefix;
|
|
36
53
|
#thumbValueSuffix;
|
|
54
|
+
#thumbValueEndPrefix;
|
|
55
|
+
#thumbValueEndSuffix;
|
|
37
56
|
#markers;
|
|
38
57
|
#extras;
|
|
39
58
|
#value = 0;
|
|
59
|
+
#physicalValues = [0, 0];
|
|
60
|
+
#orderReversed = false;
|
|
61
|
+
#lastActiveThumb = 0;
|
|
40
62
|
#seeded = false;
|
|
41
63
|
#dirty = false;
|
|
42
64
|
#drag;
|
|
43
65
|
get value() {
|
|
44
|
-
return this.#value;
|
|
66
|
+
return Array.isArray(this.#value) ? [...this.#value] : this.#value;
|
|
45
67
|
}
|
|
46
68
|
set value(value) {
|
|
47
|
-
this.setAttribute("value", String(value));
|
|
69
|
+
this.setAttribute("value", Array.isArray(value) ? value.join(" ") : String(value));
|
|
48
70
|
}
|
|
49
71
|
get defaultValue() {
|
|
50
|
-
return
|
|
72
|
+
return parseSliderValue(this.getAttribute("defaultvalue"), this.#fallbackValue());
|
|
51
73
|
}
|
|
52
74
|
set defaultValue(value) {
|
|
53
|
-
this.setAttribute("defaultvalue", String(value));
|
|
75
|
+
this.setAttribute("defaultvalue", Array.isArray(value) ? value.join(" ") : String(value));
|
|
54
76
|
}
|
|
55
77
|
constructor() {
|
|
56
78
|
super();
|
|
@@ -113,7 +135,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
113
135
|
}
|
|
114
136
|
:host([track-click="jump"]) .control { cursor: pointer; }
|
|
115
137
|
.control[data-dragging] { cursor: grabbing; }
|
|
116
|
-
.control[data-dragging] .thumb { background: var(--slider-thumb-active); }
|
|
138
|
+
.control[data-dragging] .thumb[data-active] { background: var(--slider-thumb-active); }
|
|
117
139
|
:host(:focus-visible) .control:not([data-pointer-focus]) {
|
|
118
140
|
outline: 1px solid var(--focus-ring);
|
|
119
141
|
outline-offset: 0;
|
|
@@ -137,9 +159,9 @@ class ASliderElement extends HTMLElementBase {
|
|
|
137
159
|
background: var(--slider-track);
|
|
138
160
|
}
|
|
139
161
|
.fill {
|
|
140
|
-
inset-inline-start: calc(var(--
|
|
162
|
+
inset-inline-start: calc(var(--_fill-start, 0%) + var(--_fill-start-edge, 0px));
|
|
141
163
|
inset-inline-end: auto;
|
|
142
|
-
inline-size: calc(var(--
|
|
164
|
+
inline-size: calc(var(--_fill-end, 0%) - var(--_fill-start, 0%) + var(--_fill-end-edge, 0px) - var(--_fill-start-edge, 0px));
|
|
143
165
|
background: var(--slider-fill);
|
|
144
166
|
}
|
|
145
167
|
.thumb {
|
|
@@ -155,6 +177,12 @@ class ASliderElement extends HTMLElementBase {
|
|
|
155
177
|
transition: background-color 75ms ease-out, border-color 75ms ease-out;
|
|
156
178
|
transform: translate(-50%, -50%);
|
|
157
179
|
}
|
|
180
|
+
.thumb[data-last-active] { z-index: 1; }
|
|
181
|
+
.thumb:focus-visible {
|
|
182
|
+
outline: 1px solid var(--focus-ring);
|
|
183
|
+
outline-offset: 2px;
|
|
184
|
+
z-index: 2;
|
|
185
|
+
}
|
|
158
186
|
.thumb-value {
|
|
159
187
|
display: none;
|
|
160
188
|
position: absolute;
|
|
@@ -176,6 +204,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
176
204
|
));
|
|
177
205
|
}
|
|
178
206
|
:host([value-display="thumb"]) .thumb-value { display: block; }
|
|
207
|
+
:host([value-display="thumb"]) .thumb-value[hidden] { display: none !important; }
|
|
179
208
|
slot[name="markers"] {
|
|
180
209
|
display: block;
|
|
181
210
|
position: relative;
|
|
@@ -204,6 +233,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
204
233
|
.fill { background: Highlight; }
|
|
205
234
|
.thumb { background: Canvas; border-color: CanvasText; }
|
|
206
235
|
:host(:focus-visible) .control { outline: 2px solid Highlight; }
|
|
236
|
+
.thumb:focus-visible { outline: 2px solid Highlight; }
|
|
207
237
|
}
|
|
208
238
|
@media (prefers-reduced-motion: reduce) {
|
|
209
239
|
.rail,
|
|
@@ -248,9 +278,15 @@ class ASliderElement extends HTMLElementBase {
|
|
|
248
278
|
this.#fill = document.createElement("div");
|
|
249
279
|
this.#fill.className = "fill";
|
|
250
280
|
this.#fill.part.add("fill");
|
|
281
|
+
this.#fillEnd = document.createElement("div");
|
|
282
|
+
this.#fillEnd.className = "fill";
|
|
283
|
+
this.#fillEnd.part.add("fill", "fill-end");
|
|
251
284
|
this.#thumb = document.createElement("div");
|
|
252
285
|
this.#thumb.className = "thumb";
|
|
253
|
-
this.#thumb.part.add("thumb");
|
|
286
|
+
this.#thumb.part.add("thumb", "thumb-1");
|
|
287
|
+
this.#thumbEnd = document.createElement("div");
|
|
288
|
+
this.#thumbEnd.className = "thumb";
|
|
289
|
+
this.#thumbEnd.part.add("thumb", "thumb-2");
|
|
254
290
|
this.#thumbValue = document.createElement("span");
|
|
255
291
|
this.#thumbValue.className = "thumb-value";
|
|
256
292
|
this.#thumbValue.part.add("thumb-value");
|
|
@@ -259,7 +295,15 @@ class ASliderElement extends HTMLElementBase {
|
|
|
259
295
|
this.#thumbValueSuffix = document.createElement("span");
|
|
260
296
|
this.#thumbValueSuffix.className = "value-affix";
|
|
261
297
|
this.#thumbValue.append(this.#thumbValuePrefix, this.#thumbValueSuffix);
|
|
262
|
-
this.#
|
|
298
|
+
this.#thumbValueEnd = document.createElement("span");
|
|
299
|
+
this.#thumbValueEnd.className = "thumb-value";
|
|
300
|
+
this.#thumbValueEnd.part.add("thumb-value", "thumb-value-2");
|
|
301
|
+
this.#thumbValueEndPrefix = document.createElement("span");
|
|
302
|
+
this.#thumbValueEndPrefix.className = "value-affix";
|
|
303
|
+
this.#thumbValueEndSuffix = document.createElement("span");
|
|
304
|
+
this.#thumbValueEndSuffix.className = "value-affix";
|
|
305
|
+
this.#thumbValueEnd.append(this.#thumbValueEndPrefix, this.#thumbValueEndSuffix);
|
|
306
|
+
this.#railArea.append(rail, this.#fill, this.#fillEnd, this.#thumb, this.#thumbEnd, this.#thumbValue, this.#thumbValueEnd);
|
|
263
307
|
this.#control.append(this.#railArea);
|
|
264
308
|
this.#markers = document.createElement("slot");
|
|
265
309
|
this.#markers.name = "markers";
|
|
@@ -267,7 +311,17 @@ class ASliderElement extends HTMLElementBase {
|
|
|
267
311
|
this.#extras = document.createElement("slot");
|
|
268
312
|
this.#extras.part.add("extras");
|
|
269
313
|
for (const slot of [this.#label, this.#markers, this.#extras]) {
|
|
270
|
-
slot.addEventListener("slotchange", () =>
|
|
314
|
+
slot.addEventListener("slotchange", () => {
|
|
315
|
+
this.#syncSlotVisibility();
|
|
316
|
+
if (slot === this.#label) this.#paintAccessibility();
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
for (const [index, thumb] of [this.#thumb, this.#thumbEnd].entries()) {
|
|
320
|
+
thumb.addEventListener("focus", () => {
|
|
321
|
+
if (!Array.isArray(this.#value)) return;
|
|
322
|
+
this.#lastActiveThumb = index;
|
|
323
|
+
this.#paint();
|
|
324
|
+
});
|
|
271
325
|
}
|
|
272
326
|
this.#control.addEventListener("pointerdown", (event) => this.#beginDrag(event));
|
|
273
327
|
this.#control.addEventListener("pointermove", (event) => this.#moveDrag(event));
|
|
@@ -280,7 +334,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
280
334
|
}
|
|
281
335
|
connectedCallback() {
|
|
282
336
|
if (!this.#seeded) {
|
|
283
|
-
this.#
|
|
337
|
+
this.#applyValue(this.#initialValue());
|
|
284
338
|
this.#seeded = true;
|
|
285
339
|
}
|
|
286
340
|
this.#paint();
|
|
@@ -290,29 +344,29 @@ class ASliderElement extends HTMLElementBase {
|
|
|
290
344
|
if (!this.#seeded) return;
|
|
291
345
|
if (name === "value") {
|
|
292
346
|
if (this.hasAttribute("value")) {
|
|
293
|
-
this.#
|
|
347
|
+
this.#applyValue(parseSliderValue(this.getAttribute("value"), this.#fallbackValue()));
|
|
294
348
|
this.#dirty = false;
|
|
295
349
|
} else if (!this.#dirty) {
|
|
296
|
-
this.#
|
|
350
|
+
this.#applyValue(this.#initialValue());
|
|
297
351
|
}
|
|
298
352
|
} else if (name === "defaultvalue" && !this.hasAttribute("value") && !this.#dirty) {
|
|
299
|
-
this.#
|
|
353
|
+
this.#applyValue(this.#initialValue());
|
|
300
354
|
} else if (name === "min" || name === "max" || name === "step") {
|
|
301
|
-
this.#
|
|
355
|
+
this.#applyValue(this.#value);
|
|
302
356
|
}
|
|
303
357
|
this.#paint();
|
|
304
358
|
if (name === "value-display") this.#syncSlotVisibility();
|
|
305
359
|
}
|
|
306
360
|
formResetCallback() {
|
|
307
361
|
const previous = this.#value;
|
|
308
|
-
this.#
|
|
362
|
+
this.#applyValue(this.defaultValue);
|
|
309
363
|
this.#dirty = false;
|
|
310
364
|
this.#paint();
|
|
311
|
-
if (this.#value
|
|
365
|
+
if (!sameSliderValue(this.#value, previous)) this.#emitInputAndChange();
|
|
312
366
|
}
|
|
313
367
|
formStateRestoreCallback(state) {
|
|
314
368
|
if (typeof state !== "string") return;
|
|
315
|
-
this.#
|
|
369
|
+
this.#applyValue(parseSliderValue(state, this.#fallbackValue()));
|
|
316
370
|
this.#dirty = true;
|
|
317
371
|
this.#paint();
|
|
318
372
|
}
|
|
@@ -332,9 +386,13 @@ class ASliderElement extends HTMLElementBase {
|
|
|
332
386
|
get #isDisabled() {
|
|
333
387
|
return this.hasAttribute("disabled") || this.matches(":disabled");
|
|
334
388
|
}
|
|
389
|
+
#fallbackValue() {
|
|
390
|
+
const range = Array.isArray(this.#value) || Array.isArray(parseSliderValue(this.getAttribute("value"), this.#min));
|
|
391
|
+
return range ? [this.#min, this.#max] : this.#min;
|
|
392
|
+
}
|
|
335
393
|
#initialValue() {
|
|
336
394
|
const source = this.getAttribute("value") ?? this.getAttribute("defaultvalue");
|
|
337
|
-
return
|
|
395
|
+
return parseSliderValue(source, this.#fallbackValue());
|
|
338
396
|
}
|
|
339
397
|
#normalize(value) {
|
|
340
398
|
const min = this.#min;
|
|
@@ -344,38 +402,145 @@ class ASliderElement extends HTMLElementBase {
|
|
|
344
402
|
const precision = Math.min(12, Math.max(precisionOf(min), precisionOf(max), precisionOf(step)));
|
|
345
403
|
return Number(Math.min(max, Math.max(min, stepped)).toFixed(precision));
|
|
346
404
|
}
|
|
347
|
-
#
|
|
405
|
+
#normalizeValue(value) {
|
|
406
|
+
if (!Array.isArray(value)) return this.#normalize(value);
|
|
407
|
+
const low = this.#normalize(value[0]);
|
|
408
|
+
const high = this.#normalize(value[1]);
|
|
409
|
+
return low <= high ? [low, high] : [high, low];
|
|
410
|
+
}
|
|
411
|
+
#applyValue(value) {
|
|
412
|
+
const next = this.#normalizeValue(value);
|
|
413
|
+
const wasRange = Array.isArray(this.#value);
|
|
414
|
+
this.#value = next;
|
|
415
|
+
if (Array.isArray(next)) {
|
|
416
|
+
if (!wasRange) this.#orderReversed = false;
|
|
417
|
+
this.#physicalValues = this.#orderReversed ? [next[1], next[0]] : [next[0], next[1]];
|
|
418
|
+
} else {
|
|
419
|
+
this.#physicalValues = [next, next];
|
|
420
|
+
this.#orderReversed = false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
#percent(value) {
|
|
348
424
|
const range = this.#max - this.#min;
|
|
349
425
|
return range > 0 ? (value - this.#min) / range * 100 : 0;
|
|
350
426
|
}
|
|
351
427
|
#paint() {
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
const
|
|
428
|
+
const currentValue = this.#value;
|
|
429
|
+
const range = Array.isArray(currentValue);
|
|
430
|
+
const low = range ? currentValue[0] : this.#min;
|
|
431
|
+
const high = range ? currentValue[1] : currentValue;
|
|
432
|
+
const lowPercent = `${this.#percent(low)}%`;
|
|
433
|
+
const highPercent = `${this.#percent(high)}%`;
|
|
434
|
+
const [first, second] = range ? this.#physicalValues : [high, high];
|
|
435
|
+
this.#thumb.style.setProperty("--_percent", `${this.#percent(first)}%`);
|
|
436
|
+
this.#thumbEnd.style.setProperty("--_percent", `${this.#percent(second)}%`);
|
|
437
|
+
this.#thumb.toggleAttribute("data-last-active", this.#lastActiveThumb === 0);
|
|
438
|
+
this.#thumbEnd.toggleAttribute("data-last-active", this.#lastActiveThumb === 1);
|
|
439
|
+
this.#thumbValue.style.setProperty("--_percent", `${this.#percent(first)}%`);
|
|
440
|
+
this.#thumbValueEnd.style.setProperty("--_percent", `${this.#percent(second)}%`);
|
|
441
|
+
this.#thumbEnd.hidden = !range;
|
|
442
|
+
const coincident = range && first === second;
|
|
443
|
+
this.#thumbValue.hidden = coincident && this.#lastActiveThumb !== 0;
|
|
444
|
+
this.#thumbValueEnd.hidden = !range || coincident && this.#lastActiveThumb !== 1;
|
|
445
|
+
const edgeStart = "calc(var(--slider-track-inset) - var(--anta-slider-thumb-size) / 2)";
|
|
446
|
+
const edgeEnd = "calc(var(--anta-slider-thumb-size) / 2 - var(--slider-track-inset))";
|
|
447
|
+
const setFill = (fill, start, end, startEdge = "0px", endEdge = "0px") => {
|
|
448
|
+
fill.style.setProperty("--_fill-start", start);
|
|
449
|
+
fill.style.setProperty("--_fill-end", end);
|
|
450
|
+
fill.style.setProperty("--_fill-start-edge", startEdge);
|
|
451
|
+
fill.style.setProperty("--_fill-end-edge", endEdge);
|
|
452
|
+
};
|
|
453
|
+
if (this.hasAttribute("inverted")) {
|
|
454
|
+
this.#fill.hidden = range ? low === this.#min : high === this.#max;
|
|
455
|
+
setFill(this.#fill, range ? "0%" : highPercent, range ? lowPercent : "100%", range ? edgeStart : high === this.#min ? edgeStart : "0px", range ? "0px" : edgeEnd);
|
|
456
|
+
this.#fillEnd.hidden = !range || high === this.#max;
|
|
457
|
+
if (range) setFill(this.#fillEnd, highPercent, "100%", "0px", edgeEnd);
|
|
458
|
+
} else {
|
|
459
|
+
this.#fill.hidden = range ? low === high : high === this.#min;
|
|
460
|
+
setFill(this.#fill, range ? lowPercent : "0%", highPercent, range && low !== this.#min ? "0px" : edgeStart, range && high === this.#max ? edgeEnd : "0px");
|
|
461
|
+
this.#fillEnd.hidden = true;
|
|
462
|
+
}
|
|
463
|
+
this.#renderValue(this.#inlineValue, this.#inlineValuePrefix, this.#inlineValueSuffix, range ? low : high, range ? high : void 0);
|
|
464
|
+
this.#renderValue(this.#endValue, this.#endValuePrefix, this.#endValueSuffix, range ? low : high, range ? high : void 0);
|
|
465
|
+
this.#renderValue(this.#thumbValue, this.#thumbValuePrefix, this.#thumbValueSuffix, first);
|
|
466
|
+
if (range) this.#renderValue(this.#thumbValueEnd, this.#thumbValueEndPrefix, this.#thumbValueEndSuffix, second);
|
|
467
|
+
this.#paintAccessibility();
|
|
468
|
+
this.#paintFormValue();
|
|
469
|
+
}
|
|
470
|
+
#renderValue(element, prefixElement, suffixElement, first, second) {
|
|
471
|
+
const prefix = this.getAttribute("value-prefix") ?? "";
|
|
472
|
+
const suffix = this.getAttribute("value-suffix") ?? "";
|
|
473
|
+
element.textContent = String(first);
|
|
474
|
+
prefixElement.textContent = prefix;
|
|
475
|
+
suffixElement.textContent = suffix;
|
|
476
|
+
element.prepend(prefixElement);
|
|
477
|
+
element.append(suffixElement);
|
|
478
|
+
if (second === void 0) return;
|
|
479
|
+
const secondPrefix = prefixElement.cloneNode(true);
|
|
480
|
+
const secondSuffix = suffixElement.cloneNode(true);
|
|
481
|
+
element.append("\u2013", secondPrefix, String(second), secondSuffix);
|
|
482
|
+
}
|
|
483
|
+
#formatValue(value) {
|
|
356
484
|
const prefix = this.getAttribute("value-prefix") ?? "";
|
|
357
485
|
const suffix = this.getAttribute("value-suffix") ?? "";
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
486
|
+
return `${prefix}${value}${suffix}`;
|
|
487
|
+
}
|
|
488
|
+
#paintAccessibility() {
|
|
489
|
+
const range = Array.isArray(this.#value);
|
|
490
|
+
const slottedLabel = this.#label.assignedNodes({ flatten: true }).map((node) => node.textContent ?? "").join("").trim();
|
|
491
|
+
const root = this.getRootNode();
|
|
492
|
+
const referencedLabel = (this.getAttribute("aria-labelledby") ?? "").split(/\s+/).map((id) => root.getElementById(id)?.textContent?.trim() ?? "").filter(Boolean).join(" ");
|
|
493
|
+
const base = (this.getAttribute("aria-label") ?? referencedLabel ?? slottedLabel).trim() || slottedLabel;
|
|
494
|
+
const internals = this.internals;
|
|
495
|
+
if (internals) {
|
|
496
|
+
internals.role = range ? "group" : "slider";
|
|
497
|
+
internals.ariaLabel = !this.hasAttribute("aria-label") && !this.hasAttribute("aria-labelledby") ? slottedLabel || null : null;
|
|
498
|
+
internals.ariaValueMin = range ? null : String(this.#min);
|
|
499
|
+
internals.ariaValueMax = range ? null : String(this.#max);
|
|
500
|
+
internals.ariaValueNow = range ? null : String(this.#value);
|
|
501
|
+
internals.ariaValueText = range ? null : this.#formatValue(this.#value);
|
|
502
|
+
}
|
|
503
|
+
for (const [index, thumb] of [this.#thumb, this.#thumbEnd].entries()) {
|
|
504
|
+
if (!range) {
|
|
505
|
+
thumb.removeAttribute("role");
|
|
506
|
+
thumb.tabIndex = -1;
|
|
507
|
+
thumb.removeAttribute("aria-label");
|
|
508
|
+
thumb.removeAttribute("aria-valuemin");
|
|
509
|
+
thumb.removeAttribute("aria-valuemax");
|
|
510
|
+
thumb.removeAttribute("aria-valuenow");
|
|
511
|
+
thumb.removeAttribute("aria-valuetext");
|
|
512
|
+
thumb.removeAttribute("aria-disabled");
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
const endpoint = index === 0 !== this.#orderReversed ? "minimum" : "maximum";
|
|
516
|
+
const value = this.#physicalValues[index];
|
|
517
|
+
thumb.role = "slider";
|
|
518
|
+
thumb.tabIndex = this.#isDisabled ? -1 : 0;
|
|
519
|
+
thumb.ariaLabel = base ? `${base} ${endpoint}` : `${endpoint[0].toUpperCase()}${endpoint.slice(1)} value`;
|
|
520
|
+
thumb.ariaValueMin = String(this.#min);
|
|
521
|
+
thumb.ariaValueMax = String(this.#max);
|
|
522
|
+
thumb.ariaValueNow = String(value);
|
|
523
|
+
thumb.ariaValueText = this.#formatValue(value);
|
|
524
|
+
thumb.ariaDisabled = this.#isDisabled ? "true" : null;
|
|
368
525
|
}
|
|
526
|
+
}
|
|
527
|
+
#paintFormValue() {
|
|
369
528
|
const internals = this.internals;
|
|
370
529
|
if (!internals) return;
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
530
|
+
const state = serializeSliderValue(this.#value);
|
|
531
|
+
if (this.#isDisabled) {
|
|
532
|
+
internals.setFormValue(null, state);
|
|
533
|
+
} else if (Array.isArray(this.#value)) {
|
|
534
|
+
const formValue = new FormData();
|
|
535
|
+
const name = this.getAttribute("name");
|
|
536
|
+
if (name) {
|
|
537
|
+
formValue.append(name, String(this.#value[0]));
|
|
538
|
+
formValue.append(name, String(this.#value[1]));
|
|
539
|
+
}
|
|
540
|
+
internals.setFormValue(formValue, state);
|
|
541
|
+
} else {
|
|
542
|
+
internals.setFormValue(state, state);
|
|
543
|
+
}
|
|
379
544
|
}
|
|
380
545
|
#syncSlotVisibility() {
|
|
381
546
|
const assigned = (slot) => slot.assignedNodes({ flatten: true }).length > 0;
|
|
@@ -383,12 +548,25 @@ class ASliderElement extends HTMLElementBase {
|
|
|
383
548
|
this.#markers.hidden = !assigned(this.#markers);
|
|
384
549
|
this.#extras.hidden = !assigned(this.#extras);
|
|
385
550
|
}
|
|
386
|
-
#setValue(value) {
|
|
551
|
+
#setValue(value, thumb = 0) {
|
|
387
552
|
const next = this.#normalize(value);
|
|
388
|
-
if (
|
|
389
|
-
|
|
553
|
+
if (Array.isArray(this.#value)) {
|
|
554
|
+
const previous = this.#value;
|
|
555
|
+
this.#physicalValues[thumb] = next;
|
|
556
|
+
if (this.#physicalValues[0] !== this.#physicalValues[1]) {
|
|
557
|
+
this.#orderReversed = this.#physicalValues[0] > this.#physicalValues[1];
|
|
558
|
+
}
|
|
559
|
+
this.#value = this.#orderReversed ? [this.#physicalValues[1], this.#physicalValues[0]] : [this.#physicalValues[0], this.#physicalValues[1]];
|
|
560
|
+
this.#lastActiveThumb = thumb;
|
|
561
|
+
this.#paint();
|
|
562
|
+
if (sameSliderValue(previous, this.#value)) return false;
|
|
563
|
+
} else {
|
|
564
|
+
if (next === this.#value) return false;
|
|
565
|
+
this.#value = next;
|
|
566
|
+
this.#physicalValues = [next, next];
|
|
567
|
+
this.#paint();
|
|
568
|
+
}
|
|
390
569
|
this.#dirty = true;
|
|
391
|
-
this.#paint();
|
|
392
570
|
this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
393
571
|
return true;
|
|
394
572
|
}
|
|
@@ -398,19 +576,33 @@ class ASliderElement extends HTMLElementBase {
|
|
|
398
576
|
}
|
|
399
577
|
#valueAt(clientX) {
|
|
400
578
|
const rect = this.#railArea.getBoundingClientRect();
|
|
401
|
-
if (rect.width <= 0) return this.#value;
|
|
579
|
+
if (rect.width <= 0) return Array.isArray(this.#value) ? this.#physicalValues[this.#lastActiveThumb] : this.#value;
|
|
402
580
|
return this.#min + (clientX - rect.left) / rect.width * (this.#max - this.#min);
|
|
403
581
|
}
|
|
582
|
+
#thumbAt(clientX) {
|
|
583
|
+
if (!Array.isArray(this.#value)) return 0;
|
|
584
|
+
const candidate = this.#valueAt(clientX);
|
|
585
|
+
const firstDistance = Math.abs(candidate - this.#physicalValues[0]);
|
|
586
|
+
const secondDistance = Math.abs(candidate - this.#physicalValues[1]);
|
|
587
|
+
return firstDistance === secondDistance ? this.#lastActiveThumb : firstDistance < secondDistance ? 0 : 1;
|
|
588
|
+
}
|
|
404
589
|
#beginDrag(event) {
|
|
405
590
|
if (this.#isDisabled || event.button !== 0) return;
|
|
406
591
|
const rect = this.#railArea.getBoundingClientRect();
|
|
407
592
|
if (rect.width <= 0) return;
|
|
408
|
-
this.#
|
|
593
|
+
const thumb = event.composedPath()[0] === this.#thumb ? 0 : event.composedPath()[0] === this.#thumbEnd ? 1 : this.#thumbAt(event.clientX);
|
|
594
|
+
const startValue = Array.isArray(this.#value) ? this.#physicalValues[thumb] : this.#value;
|
|
595
|
+
this.#drag = { pointerId: event.pointerId, startX: event.clientX, startValue, startPublicValue: this.value, thumb };
|
|
409
596
|
this.#control.setPointerCapture(event.pointerId);
|
|
410
597
|
this.#control.dataset.dragging = "";
|
|
411
598
|
this.#control.dataset.pointerFocus = "";
|
|
412
|
-
this
|
|
413
|
-
|
|
599
|
+
this.#lastActiveThumb = thumb;
|
|
600
|
+
this.#thumb.toggleAttribute("data-last-active", thumb === 0);
|
|
601
|
+
this.#thumbEnd.toggleAttribute("data-last-active", thumb === 1);
|
|
602
|
+
const focusTarget = Array.isArray(this.#value) ? [this.#thumb, this.#thumbEnd][thumb] : this;
|
|
603
|
+
focusTarget.focus({ preventScroll: true });
|
|
604
|
+
[this.#thumb, this.#thumbEnd][thumb].dataset.active = "";
|
|
605
|
+
if (this.getAttribute("track-click") === "jump") this.#setValue(this.#valueAt(event.clientX), thumb);
|
|
414
606
|
event.preventDefault();
|
|
415
607
|
}
|
|
416
608
|
#moveDrag(event) {
|
|
@@ -421,7 +613,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
421
613
|
return;
|
|
422
614
|
}
|
|
423
615
|
const next = this.getAttribute("track-click") === "jump" ? this.#valueAt(event.clientX) : drag.startValue + (event.clientX - drag.startX) / this.#railArea.getBoundingClientRect().width * (this.#max - this.#min);
|
|
424
|
-
this.#setValue(next);
|
|
616
|
+
this.#setValue(next, drag.thumb);
|
|
425
617
|
event.preventDefault();
|
|
426
618
|
}
|
|
427
619
|
#finishDrag(event) {
|
|
@@ -429,28 +621,33 @@ class ASliderElement extends HTMLElementBase {
|
|
|
429
621
|
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
430
622
|
this.#drag = void 0;
|
|
431
623
|
delete this.#control.dataset.dragging;
|
|
624
|
+
delete [this.#thumb, this.#thumbEnd][drag.thumb].dataset.active;
|
|
432
625
|
if (this.#control.hasPointerCapture(event.pointerId)) this.#control.releasePointerCapture(event.pointerId);
|
|
433
|
-
if (this.#value
|
|
626
|
+
if (!sameSliderValue(this.#value, drag.startPublicValue)) this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
434
627
|
}
|
|
435
628
|
#handleKeydown(event) {
|
|
436
|
-
|
|
629
|
+
const source = event.composedPath()[0];
|
|
630
|
+
const range = Array.isArray(this.#value);
|
|
631
|
+
const thumb = source === this.#thumb ? 0 : source === this.#thumbEnd ? 1 : void 0;
|
|
632
|
+
if ((range ? thumb === void 0 : source !== this) || this.#isDisabled || isModifiedNavigationKey(event)) return;
|
|
437
633
|
delete this.#control.dataset.pointerFocus;
|
|
438
634
|
const page = Math.max(this.#step, (this.#max - this.#min) / 10);
|
|
635
|
+
const current = range ? this.#physicalValues[thumb ?? 0] : this.#value;
|
|
439
636
|
let next;
|
|
440
637
|
switch (event.key) {
|
|
441
638
|
case "ArrowRight":
|
|
442
639
|
case "ArrowUp":
|
|
443
|
-
next =
|
|
640
|
+
next = current + this.#step;
|
|
444
641
|
break;
|
|
445
642
|
case "ArrowLeft":
|
|
446
643
|
case "ArrowDown":
|
|
447
|
-
next =
|
|
644
|
+
next = current - this.#step;
|
|
448
645
|
break;
|
|
449
646
|
case "PageUp":
|
|
450
|
-
next =
|
|
647
|
+
next = current + page;
|
|
451
648
|
break;
|
|
452
649
|
case "PageDown":
|
|
453
|
-
next =
|
|
650
|
+
next = current - page;
|
|
454
651
|
break;
|
|
455
652
|
case "Home":
|
|
456
653
|
next = this.#min;
|
|
@@ -462,7 +659,7 @@ class ASliderElement extends HTMLElementBase {
|
|
|
462
659
|
return;
|
|
463
660
|
}
|
|
464
661
|
event.preventDefault();
|
|
465
|
-
if (this.#setValue(next)) this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
662
|
+
if (this.#setValue(next, range ? thumb ?? 0 : 0)) this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
466
663
|
}
|
|
467
664
|
}
|
|
468
665
|
function register_a_slider() {
|
package/dist/general_types.d.ts
CHANGED
|
@@ -705,9 +705,12 @@ export interface AInputAttributes extends BaseAttributes {
|
|
|
705
705
|
* wrapper) the glyph. Only `critical` carries validity weight (`aria-invalid`
|
|
706
706
|
* + `:state(invalid)`); the others are advisory. Omit for the neutral field. */
|
|
707
707
|
status?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical';
|
|
708
|
-
/** Custom accent color (any literal CSS color) — tints the
|
|
709
|
-
*
|
|
708
|
+
/** Custom accent color (any literal CSS color) — tints the border when shown
|
|
709
|
+
* via an oklch derivation. `status` overrides it for validation. */
|
|
710
710
|
tone?: string;
|
|
711
|
+
/** Field emphasis. Secondary removes the fill; tertiary also makes the
|
|
712
|
+
* resting border transparent. Status borders remain visible. */
|
|
713
|
+
priority?: 'primary' | 'secondary' | 'tertiary';
|
|
711
714
|
/** Disabled state. Presence-based. */
|
|
712
715
|
disabled?: boolean | '';
|
|
713
716
|
/** Read-only state. Presence-based. */
|
|
@@ -762,9 +765,9 @@ export interface AInputAttributes extends BaseAttributes {
|
|
|
762
765
|
/** Attributes for the `<a-slider>` custom element. For the typed JSX wrapper,
|
|
763
766
|
* display formatting, and marker layout use `Slider` from `@antadesign/anta`. */
|
|
764
767
|
export interface ASliderAttributes extends BaseAttributes {
|
|
765
|
-
/** Controlled
|
|
768
|
+
/** Controlled value. Range attributes use two space-separated numbers. */
|
|
766
769
|
value?: number | string;
|
|
767
|
-
/** Initial uncontrolled value and form-reset baseline. */
|
|
770
|
+
/** Initial uncontrolled value and form-reset baseline. Range attributes use two space-separated numbers. */
|
|
768
771
|
defaultvalue?: number | string;
|
|
769
772
|
/** Lowest permitted value. Defaults to 0. */
|
|
770
773
|
min?: number | string;
|
|
@@ -792,6 +795,8 @@ export interface ASliderAttributes extends BaseAttributes {
|
|
|
792
795
|
round?: boolean | number | string;
|
|
793
796
|
/** `jump` moves to a pressed rail position. Omit for relative dragging. */
|
|
794
797
|
'track-click'?: 'jump';
|
|
798
|
+
/** Fill the rail outside the selected value or range. Presence-based. */
|
|
799
|
+
inverted?: boolean | '';
|
|
795
800
|
/** `inline`, `thumb`, or `none`; omit for a value at the label row's end. */
|
|
796
801
|
'value-display'?: 'inline' | 'thumb' | 'none';
|
|
797
802
|
/** Text inserted before the live numeric value. */
|
package/dist/index.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export type { ExpanderProps } from './components/Expander';
|
|
|
70
70
|
export { Input } from './components/Input';
|
|
71
71
|
export type { InputProps, InputChangeAttrs } from './components/Input';
|
|
72
72
|
export { Slider } from './components/Slider';
|
|
73
|
-
export type { SliderProps, SliderMarker, SliderChangeAttrs } from './components/Slider';
|
|
73
|
+
export type { SliderProps, SliderMarker, SliderChangeAttrs, SliderRangeValue, SliderValue } from './components/Slider';
|
|
74
74
|
export { Calendar } from './components/Calendar';
|
|
75
75
|
export type { CalendarProps, CalendarChangeAttrs } from './components/Calendar';
|
|
76
76
|
export { InputDate } from './components/InputDate';
|