@zag-js/slider 1.34.1 → 1.35.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/dist/index.mjs CHANGED
@@ -1,1050 +1,10 @@
1
- import { createAnatomy } from '@zag-js/anatomy';
2
- import { raf, setElementValue, resizeObserverBorderBox, trackPointerMove, trackFormControl, dispatchInputValueEvent, queryAll, dataAttr, isLeftClick, isModifierKey, getEventPoint, getEventStep, getEventKey, ariaAttr } from '@zag-js/dom-query';
3
- import { setValueAtIndex, callAll, getValuePercent, isEqual, createSplitProps, snapValueToStep, clampValue, getValueRanges, getNextStepValue, getPreviousStepValue, getPercentValue, pick, isValueWithinRange, clampPercent, first, last, toPx, getValueTransformer } from '@zag-js/utils';
4
- import { createMachine, memo } from '@zag-js/core';
5
- import { createProps } from '@zag-js/types';
6
-
7
- // src/slider.anatomy.ts
8
- var anatomy = createAnatomy("slider").parts(
9
- "root",
10
- "label",
11
- "thumb",
12
- "valueText",
13
- "track",
14
- "range",
15
- "control",
16
- "markerGroup",
17
- "marker",
18
- "draggingIndicator"
19
- );
20
- var parts = anatomy.build();
21
- var getRootId = (ctx) => ctx.ids?.root ?? `slider:${ctx.id}`;
22
- var getThumbId = (ctx, index) => ctx.ids?.thumb?.(index) ?? `slider:${ctx.id}:thumb:${index}`;
23
- var getHiddenInputId = (ctx, index) => ctx.ids?.hiddenInput?.(index) ?? `slider:${ctx.id}:input:${index}`;
24
- var getControlId = (ctx) => ctx.ids?.control ?? `slider:${ctx.id}:control`;
25
- var getTrackId = (ctx) => ctx.ids?.track ?? `slider:${ctx.id}:track`;
26
- var getRangeId = (ctx) => ctx.ids?.range ?? `slider:${ctx.id}:range`;
27
- var getLabelId = (ctx) => ctx.ids?.label ?? `slider:${ctx.id}:label`;
28
- var getValueTextId = (ctx) => ctx.ids?.valueText ?? `slider:${ctx.id}:value-text`;
29
- var getMarkerId = (ctx, value) => ctx.ids?.marker?.(value) ?? `slider:${ctx.id}:marker:${value}`;
30
- var getRootEl = (ctx) => ctx.getById(getRootId(ctx));
31
- var getThumbEl = (ctx, index) => ctx.getById(getThumbId(ctx, index));
32
- var getThumbEls = (ctx) => queryAll(getControlEl(ctx), "[role=slider]");
33
- var getFirstThumbEl = (ctx) => getThumbEls(ctx)[0];
34
- var getHiddenInputEl = (ctx, index) => ctx.getById(getHiddenInputId(ctx, index));
35
- var getControlEl = (ctx) => ctx.getById(getControlId(ctx));
36
- var getThumbInset = (thumbSize, thumbAlignment, orientation) => {
37
- const isContain = thumbAlignment === "contain";
38
- const isVertical = orientation === "vertical";
39
- return isContain ? (isVertical ? thumbSize?.height ?? 0 : thumbSize?.width ?? 0) / 2 : 0;
1
+ // src/index.ts
2
+ import { anatomy } from "./slider.anatomy.mjs";
3
+ import { connect } from "./slider.connect.mjs";
4
+ import { machine } from "./slider.machine.mjs";
5
+ export * from "./slider.props.mjs";
6
+ export {
7
+ anatomy,
8
+ connect,
9
+ machine
40
10
  };
41
- var getPointValue = (params, point) => {
42
- const { context, prop, scope, refs } = params;
43
- const controlEl = getControlEl(scope);
44
- if (!controlEl) return;
45
- const offset = refs.get("thumbDragOffset");
46
- const adjustedPoint = {
47
- x: point.x - (offset?.x ?? 0),
48
- y: point.y - (offset?.y ?? 0)
49
- };
50
- const thumbInset = getThumbInset(context.get("thumbSize"), prop("thumbAlignment"), prop("orientation"));
51
- const relativePoint = getRelativePointWithInset(adjustedPoint, controlEl, thumbInset);
52
- const percent = relativePoint.getPercentValue({
53
- orientation: prop("orientation"),
54
- dir: prop("dir"),
55
- inverted: { y: true }
56
- });
57
- return getPercentValue(percent, prop("min"), prop("max"), prop("step"));
58
- };
59
- function getRelativePointWithInset(point, element, inset) {
60
- const { left, top, width, height } = element.getBoundingClientRect();
61
- const effectiveWidth = width - inset * 2;
62
- const effectiveHeight = height - inset * 2;
63
- const effectiveLeft = left + inset;
64
- const effectiveTop = top + inset;
65
- const offset = {
66
- x: point.x - effectiveLeft,
67
- y: point.y - effectiveTop
68
- };
69
- const percent = {
70
- x: effectiveWidth > 0 ? clampPercent(offset.x / effectiveWidth) : 0,
71
- y: effectiveHeight > 0 ? clampPercent(offset.y / effectiveHeight) : 0
72
- };
73
- function getPercentValue3(options = {}) {
74
- const { dir = "ltr", orientation = "horizontal", inverted } = options;
75
- const invertX = typeof inverted === "object" ? inverted.x : inverted;
76
- const invertY = typeof inverted === "object" ? inverted.y : inverted;
77
- if (orientation === "horizontal") {
78
- return dir === "rtl" || invertX ? 1 - percent.x : percent.x;
79
- }
80
- return invertY ? 1 - percent.y : percent.y;
81
- }
82
- return { offset, percent, getPercentValue: getPercentValue3 };
83
- }
84
- var dispatchChangeEvent = (ctx, value) => {
85
- value.forEach((value2, index) => {
86
- const inputEl = getHiddenInputEl(ctx, index);
87
- if (!inputEl) return;
88
- dispatchInputValueEvent(inputEl, { value: value2 });
89
- });
90
- };
91
- var getOffsetRect = (el) => ({
92
- left: el?.offsetLeft ?? 0,
93
- top: el?.offsetTop ?? 0,
94
- width: el?.offsetWidth ?? 0,
95
- height: el?.offsetHeight ?? 0
96
- });
97
- function getBounds(value) {
98
- const firstValue = value[0];
99
- const lastThumb = value[value.length - 1];
100
- return [firstValue, lastThumb];
101
- }
102
- function getRangeOffsets(params) {
103
- const { prop, computed } = params;
104
- const valuePercent = computed("valuePercent");
105
- const [firstPercent, lastPercent] = getBounds(valuePercent);
106
- if (valuePercent.length === 1) {
107
- if (prop("origin") === "center") {
108
- const isNegative = valuePercent[0] < 50;
109
- const start = isNegative ? `${valuePercent[0]}%` : "50%";
110
- const end = isNegative ? "50%" : `${100 - valuePercent[0]}%`;
111
- return { start, end };
112
- }
113
- if (prop("origin") === "end") {
114
- return { start: `${lastPercent}%`, end: "0%" };
115
- }
116
- return { start: "0%", end: `${100 - lastPercent}%` };
117
- }
118
- return { start: `${firstPercent}%`, end: `${100 - lastPercent}%` };
119
- }
120
- function getRangeStyle(params) {
121
- const { computed } = params;
122
- const isVertical = computed("isVertical");
123
- const isRtl = computed("isRtl");
124
- if (isVertical) {
125
- return {
126
- position: "absolute",
127
- bottom: "var(--slider-range-start)",
128
- top: "var(--slider-range-end)"
129
- };
130
- }
131
- return {
132
- position: "absolute",
133
- [isRtl ? "right" : "left"]: "var(--slider-range-start)",
134
- [isRtl ? "left" : "right"]: "var(--slider-range-end)"
135
- };
136
- }
137
- function getVerticalThumbOffset(params, value) {
138
- const { context, prop } = params;
139
- const { height = 0 } = context.get("thumbSize") ?? {};
140
- const getValue = getValueTransformer([prop("min"), prop("max")], [-height / 2, height / 2]);
141
- return parseFloat(getValue(value).toFixed(2));
142
- }
143
- function getHorizontalThumbOffset(params, value) {
144
- const { computed, context, prop } = params;
145
- const { width = 0 } = context.get("thumbSize") ?? {};
146
- const isRtl = computed("isRtl");
147
- if (isRtl) {
148
- const getValue2 = getValueTransformer([prop("max"), prop("min")], [-width / 2, width / 2]);
149
- return -1 * parseFloat(getValue2(value).toFixed(2));
150
- }
151
- const getValue = getValueTransformer([prop("min"), prop("max")], [-width / 2, width / 2]);
152
- return parseFloat(getValue(value).toFixed(2));
153
- }
154
- function getOffset(params, percent, value) {
155
- const { computed, prop } = params;
156
- if (prop("thumbAlignment") === "center") return `${percent}%`;
157
- const offset = computed("isVertical") ? getVerticalThumbOffset(params, value) : getHorizontalThumbOffset(params, value);
158
- return `calc(${percent}% - ${offset}px)`;
159
- }
160
- function getThumbOffset(params, value) {
161
- const { prop } = params;
162
- const percent = getValuePercent(value, prop("min"), prop("max")) * 100;
163
- return getOffset(params, percent, value);
164
- }
165
- function getVisibility(params) {
166
- const { computed, prop } = params;
167
- let visibility = "visible";
168
- if (prop("thumbAlignment") === "contain" && !computed("hasMeasuredThumbSize")) {
169
- visibility = "hidden";
170
- }
171
- return visibility;
172
- }
173
- function getThumbStyle(params, index) {
174
- const { computed, context } = params;
175
- const placementProp = computed("isVertical") ? "bottom" : "insetInlineStart";
176
- const focusedIndex = context.get("focusedIndex");
177
- return {
178
- visibility: getVisibility(params),
179
- position: "absolute",
180
- transform: "var(--slider-thumb-transform)",
181
- [placementProp]: `var(--slider-thumb-offset-${index})`,
182
- zIndex: focusedIndex === index ? 1 : void 0
183
- };
184
- }
185
- function getControlStyle() {
186
- return {
187
- touchAction: "none",
188
- userSelect: "none",
189
- WebkitUserSelect: "none",
190
- position: "relative"
191
- };
192
- }
193
- function getRootStyle(params) {
194
- const { context, computed } = params;
195
- const isVertical = computed("isVertical");
196
- const isRtl = computed("isRtl");
197
- const range = getRangeOffsets(params);
198
- const thumbSize = context.get("thumbSize");
199
- const offsetStyles = context.get("value").reduce((styles, value, index) => {
200
- const offset = getThumbOffset(params, value);
201
- return { ...styles, [`--slider-thumb-offset-${index}`]: offset };
202
- }, {});
203
- return {
204
- ...offsetStyles,
205
- "--slider-thumb-width": toPx(thumbSize?.width),
206
- "--slider-thumb-height": toPx(thumbSize?.height),
207
- "--slider-thumb-transform": isVertical ? "translateY(50%)" : isRtl ? "translateX(50%)" : "translateX(-50%)",
208
- "--slider-range-start": range.start,
209
- "--slider-range-end": range.end
210
- };
211
- }
212
- function getMarkerStyle(params, value) {
213
- const { computed } = params;
214
- const isHorizontal = computed("isHorizontal");
215
- const isRtl = computed("isRtl");
216
- return {
217
- visibility: getVisibility(params),
218
- position: "absolute",
219
- pointerEvents: "none",
220
- [isHorizontal ? "insetInlineStart" : "bottom"]: getThumbOffset(params, value),
221
- translate: "var(--translate-x) var(--translate-y)",
222
- "--translate-x": isHorizontal ? isRtl ? "50%" : "-50%" : "0%",
223
- "--translate-y": !isHorizontal ? "50%" : "0%"
224
- };
225
- }
226
- function getMarkerGroupStyle() {
227
- return {
228
- userSelect: "none",
229
- WebkitUserSelect: "none",
230
- pointerEvents: "none",
231
- position: "relative"
232
- };
233
- }
234
- function getThumbBounds(ctx) {
235
- const { index, values, min, max, gap } = ctx;
236
- const prevThumb = values[index - 1];
237
- const nextThumb = values[index + 1];
238
- return {
239
- min: prevThumb != null ? prevThumb + gap : min,
240
- max: nextThumb != null ? nextThumb - gap : max
241
- };
242
- }
243
- function round(value) {
244
- return Math.round(value * 1e10) / 1e10;
245
- }
246
- function handleNone(ctx) {
247
- const { index, value, values } = ctx;
248
- const bounds = getThumbBounds(ctx);
249
- const nextValues = values.slice();
250
- nextValues[index] = round(clampValue(value, bounds.min, bounds.max));
251
- return { values: nextValues, index, swapped: false };
252
- }
253
- function handlePush(ctx) {
254
- const { index, value, values, min, max, gap } = ctx;
255
- const nextValues = values.slice();
256
- const absoluteMin = min + index * gap;
257
- const absoluteMax = max - (values.length - 1 - index) * gap;
258
- nextValues[index] = round(clampValue(value, absoluteMin, absoluteMax));
259
- for (let i = index + 1; i < values.length; i++) {
260
- const minAllowed = nextValues[i - 1] + gap;
261
- if (nextValues[i] < minAllowed) {
262
- nextValues[i] = round(minAllowed);
263
- }
264
- }
265
- for (let i = index - 1; i >= 0; i--) {
266
- const maxAllowed = nextValues[i + 1] - gap;
267
- if (nextValues[i] > maxAllowed) {
268
- nextValues[i] = round(maxAllowed);
269
- }
270
- }
271
- return { values: nextValues, index, swapped: false };
272
- }
273
- function handleSwap(ctx, startValue) {
274
- const { index, value, values, gap } = ctx;
275
- const prevThumb = values[index - 1];
276
- const nextThumb = values[index + 1];
277
- const crossingNext = nextThumb != null && value >= nextThumb && value > startValue;
278
- const crossingPrev = prevThumb != null && value <= prevThumb && value < startValue;
279
- if (!crossingNext && !crossingPrev) {
280
- return handleNone(ctx);
281
- }
282
- const swapIndex = crossingNext ? index + 1 : index - 1;
283
- const nextValues = values.slice();
284
- const newCtx = { ...ctx, index: swapIndex };
285
- const bounds = getThumbBounds(newCtx);
286
- nextValues[swapIndex] = round(clampValue(value, bounds.min, bounds.max));
287
- nextValues[index] = values[swapIndex];
288
- if (crossingNext && nextValues[index] > nextValues[swapIndex] - gap) {
289
- nextValues[index] = round(nextValues[swapIndex] - gap);
290
- } else if (crossingPrev && nextValues[index] < nextValues[swapIndex] + gap) {
291
- nextValues[index] = round(nextValues[swapIndex] + gap);
292
- }
293
- return { values: nextValues, index: swapIndex, swapped: true };
294
- }
295
- function resolveThumbCollision(behavior, index, value, values, min, max, step, minStepsBetweenThumbs, startValue) {
296
- if (values.length === 1) {
297
- return { values: [round(clampValue(value, min, max))], index: 0, swapped: false };
298
- }
299
- const gap = step * minStepsBetweenThumbs;
300
- const ctx = { behavior, index, value, values, min, max, gap };
301
- switch (behavior) {
302
- case "push":
303
- return handlePush(ctx);
304
- case "swap":
305
- return handleSwap(ctx, startValue ?? values[index]);
306
- case "none":
307
- default:
308
- return handleNone(ctx);
309
- }
310
- }
311
- function normalizeValues(params, nextValues) {
312
- return nextValues.map((value, index) => {
313
- return constrainValue(params, value, index);
314
- });
315
- }
316
- function getRangeAtIndex(params, index) {
317
- const { context, prop } = params;
318
- const step = prop("step") * prop("minStepsBetweenThumbs");
319
- return getValueRanges(context.get("value"), prop("min"), prop("max"), step)[index];
320
- }
321
- function constrainValue(params, value, index) {
322
- const { prop } = params;
323
- const range = getRangeAtIndex(params, index);
324
- const snapValue = snapValueToStep(value, prop("min"), prop("max"), prop("step"));
325
- return clampValue(snapValue, range.min, range.max);
326
- }
327
- function decrement(params, index, step) {
328
- const { context, prop } = params;
329
- const idx = index ?? context.get("focusedIndex");
330
- const range = getRangeAtIndex(params, idx);
331
- const nextValues = getPreviousStepValue(idx, {
332
- ...range,
333
- step: step ?? prop("step"),
334
- values: context.get("value")
335
- });
336
- nextValues[idx] = clampValue(nextValues[idx], range.min, range.max);
337
- return nextValues;
338
- }
339
- function increment(params, index, step) {
340
- const { context, prop } = params;
341
- const idx = index ?? context.get("focusedIndex");
342
- const range = getRangeAtIndex(params, idx);
343
- const nextValues = getNextStepValue(idx, {
344
- ...range,
345
- step: step ?? prop("step"),
346
- values: context.get("value")
347
- });
348
- nextValues[idx] = clampValue(nextValues[idx], range.min, range.max);
349
- return nextValues;
350
- }
351
- function getClosestIndex(params, pointValue) {
352
- const { context } = params;
353
- const values = context.get("value");
354
- let closestIndex = 0;
355
- let minDistance = Math.abs(values[0] - pointValue);
356
- for (let i = 1; i < values.length; i++) {
357
- const distance = Math.abs(values[i] - pointValue);
358
- if (distance <= minDistance) {
359
- closestIndex = i;
360
- minDistance = distance;
361
- }
362
- }
363
- return selectMovableThumb(params, closestIndex);
364
- }
365
- function selectMovableThumb(params, index) {
366
- const { context, prop } = params;
367
- const values = context.get("value");
368
- const max = prop("max");
369
- const thumbValue = values[index];
370
- if (thumbValue === max) {
371
- let movableIndex = index;
372
- while (movableIndex > 0 && values[movableIndex - 1] === max) {
373
- movableIndex -= 1;
374
- }
375
- return movableIndex;
376
- }
377
- return index;
378
- }
379
-
380
- // src/slider.connect.ts
381
- function connect(service, normalize2) {
382
- const { state, send, context, prop, computed, scope } = service;
383
- const ariaLabel = prop("aria-label");
384
- const ariaLabelledBy = prop("aria-labelledby");
385
- const sliderValue = context.get("value");
386
- const focusedIndex = context.get("focusedIndex");
387
- const focused = state.matches("focus");
388
- const dragging = state.matches("dragging");
389
- const disabled = computed("isDisabled");
390
- const invalid = prop("invalid");
391
- const interactive = computed("isInteractive");
392
- const isHorizontal = prop("orientation") === "horizontal";
393
- const isVertical = prop("orientation") === "vertical";
394
- function getValuePercentFn(value) {
395
- return getValuePercent(value, prop("min"), prop("max"));
396
- }
397
- function getPercentValueFn(percent) {
398
- return getPercentValue(percent, prop("min"), prop("max"), prop("step"));
399
- }
400
- return {
401
- value: sliderValue,
402
- dragging,
403
- focused,
404
- setValue(value) {
405
- send({ type: "SET_VALUE", value });
406
- },
407
- getThumbValue(index) {
408
- return sliderValue[index];
409
- },
410
- setThumbValue(index, value) {
411
- send({ type: "SET_VALUE", index, value });
412
- },
413
- getValuePercent: getValuePercentFn,
414
- getPercentValue: getPercentValueFn,
415
- getThumbPercent(index) {
416
- return getValuePercentFn(sliderValue[index]);
417
- },
418
- setThumbPercent(index, percent) {
419
- const value = getPercentValueFn(percent);
420
- send({ type: "SET_VALUE", index, value });
421
- },
422
- getThumbMin(index) {
423
- return getRangeAtIndex(service, index).min;
424
- },
425
- getThumbMax(index) {
426
- return getRangeAtIndex(service, index).max;
427
- },
428
- increment(index) {
429
- send({ type: "INCREMENT", index });
430
- },
431
- decrement(index) {
432
- send({ type: "DECREMENT", index });
433
- },
434
- focus() {
435
- if (!interactive) return;
436
- send({ type: "FOCUS", index: 0 });
437
- },
438
- getLabelProps() {
439
- return normalize2.label({
440
- ...parts.label.attrs,
441
- dir: prop("dir"),
442
- "data-disabled": dataAttr(disabled),
443
- "data-orientation": prop("orientation"),
444
- "data-invalid": dataAttr(invalid),
445
- "data-dragging": dataAttr(dragging),
446
- "data-focus": dataAttr(focused),
447
- id: getLabelId(scope),
448
- htmlFor: getHiddenInputId(scope, 0),
449
- onClick(event) {
450
- if (!interactive) return;
451
- event.preventDefault();
452
- getFirstThumbEl(scope)?.focus();
453
- },
454
- style: {
455
- userSelect: "none",
456
- WebkitUserSelect: "none"
457
- }
458
- });
459
- },
460
- getRootProps() {
461
- return normalize2.element({
462
- ...parts.root.attrs,
463
- "data-disabled": dataAttr(disabled),
464
- "data-orientation": prop("orientation"),
465
- "data-dragging": dataAttr(dragging),
466
- "data-invalid": dataAttr(invalid),
467
- "data-focus": dataAttr(focused),
468
- id: getRootId(scope),
469
- dir: prop("dir"),
470
- style: getRootStyle(service)
471
- });
472
- },
473
- getValueTextProps() {
474
- return normalize2.element({
475
- ...parts.valueText.attrs,
476
- dir: prop("dir"),
477
- "data-disabled": dataAttr(disabled),
478
- "data-orientation": prop("orientation"),
479
- "data-invalid": dataAttr(invalid),
480
- "data-focus": dataAttr(focused),
481
- id: getValueTextId(scope)
482
- });
483
- },
484
- getTrackProps() {
485
- return normalize2.element({
486
- ...parts.track.attrs,
487
- dir: prop("dir"),
488
- id: getTrackId(scope),
489
- "data-disabled": dataAttr(disabled),
490
- "data-invalid": dataAttr(invalid),
491
- "data-dragging": dataAttr(dragging),
492
- "data-orientation": prop("orientation"),
493
- "data-focus": dataAttr(focused),
494
- style: { position: "relative" }
495
- });
496
- },
497
- getThumbProps(props2) {
498
- const { index = 0, name } = props2;
499
- const value = sliderValue[index];
500
- const range = getRangeAtIndex(service, index);
501
- const valueText = prop("getAriaValueText")?.({ value, index });
502
- const _ariaLabel = Array.isArray(ariaLabel) ? ariaLabel[index] : ariaLabel;
503
- const _ariaLabelledBy = Array.isArray(ariaLabelledBy) ? ariaLabelledBy[index] : ariaLabelledBy;
504
- return normalize2.element({
505
- ...parts.thumb.attrs,
506
- dir: prop("dir"),
507
- "data-index": index,
508
- "data-name": name,
509
- id: getThumbId(scope, index),
510
- "data-disabled": dataAttr(disabled),
511
- "data-orientation": prop("orientation"),
512
- "data-focus": dataAttr(focused && focusedIndex === index),
513
- "data-dragging": dataAttr(dragging && focusedIndex === index),
514
- draggable: false,
515
- "aria-disabled": ariaAttr(disabled),
516
- "aria-label": _ariaLabel,
517
- "aria-labelledby": _ariaLabelledBy ?? getLabelId(scope),
518
- "aria-orientation": prop("orientation"),
519
- "aria-valuemax": range.max,
520
- "aria-valuemin": range.min,
521
- "aria-valuenow": sliderValue[index],
522
- "aria-valuetext": valueText,
523
- role: "slider",
524
- tabIndex: disabled ? void 0 : 0,
525
- style: getThumbStyle(service, index),
526
- onPointerDown(event) {
527
- if (!interactive) return;
528
- if (!isLeftClick(event)) return;
529
- const thumbEl = event.currentTarget;
530
- const rect = thumbEl.getBoundingClientRect();
531
- const midpoint = {
532
- x: rect.left + rect.width / 2,
533
- y: rect.top + rect.height / 2
534
- };
535
- const offset = {
536
- x: event.clientX - midpoint.x,
537
- y: event.clientY - midpoint.y
538
- };
539
- send({ type: "THUMB_POINTER_DOWN", index, offset });
540
- event.stopPropagation();
541
- },
542
- onBlur() {
543
- if (!interactive) return;
544
- send({ type: "BLUR" });
545
- },
546
- onFocus() {
547
- if (!interactive) return;
548
- send({ type: "FOCUS", index });
549
- },
550
- onKeyDown(event) {
551
- if (event.defaultPrevented) return;
552
- if (!interactive) return;
553
- const step = getEventStep(event) * prop("step");
554
- const keyMap = {
555
- ArrowUp() {
556
- if (isHorizontal) return;
557
- send({ type: "ARROW_INC", step, src: "ArrowUp" });
558
- },
559
- ArrowDown() {
560
- if (isHorizontal) return;
561
- send({ type: "ARROW_DEC", step, src: "ArrowDown" });
562
- },
563
- ArrowLeft() {
564
- if (isVertical) return;
565
- send({ type: "ARROW_DEC", step, src: "ArrowLeft" });
566
- },
567
- ArrowRight() {
568
- if (isVertical) return;
569
- send({ type: "ARROW_INC", step, src: "ArrowRight" });
570
- },
571
- PageUp() {
572
- send({ type: "ARROW_INC", step, src: "PageUp" });
573
- },
574
- PageDown() {
575
- send({ type: "ARROW_DEC", step, src: "PageDown" });
576
- },
577
- Home() {
578
- send({ type: "HOME" });
579
- },
580
- End() {
581
- send({ type: "END" });
582
- }
583
- };
584
- const key = getEventKey(event, {
585
- dir: prop("dir"),
586
- orientation: prop("orientation")
587
- });
588
- const exec = keyMap[key];
589
- if (exec) {
590
- exec(event);
591
- event.preventDefault();
592
- event.stopPropagation();
593
- }
594
- }
595
- });
596
- },
597
- getHiddenInputProps(props2) {
598
- const { index = 0, name } = props2;
599
- return normalize2.input({
600
- name: name ?? (prop("name") ? prop("name") + (sliderValue.length > 1 ? "[]" : "") : void 0),
601
- form: prop("form"),
602
- type: "text",
603
- hidden: true,
604
- defaultValue: sliderValue[index],
605
- id: getHiddenInputId(scope, index)
606
- });
607
- },
608
- getRangeProps() {
609
- return normalize2.element({
610
- id: getRangeId(scope),
611
- ...parts.range.attrs,
612
- dir: prop("dir"),
613
- "data-dragging": dataAttr(dragging),
614
- "data-focus": dataAttr(focused),
615
- "data-invalid": dataAttr(invalid),
616
- "data-disabled": dataAttr(disabled),
617
- "data-orientation": prop("orientation"),
618
- style: getRangeStyle(service)
619
- });
620
- },
621
- getControlProps() {
622
- return normalize2.element({
623
- ...parts.control.attrs,
624
- dir: prop("dir"),
625
- id: getControlId(scope),
626
- "data-dragging": dataAttr(dragging),
627
- "data-disabled": dataAttr(disabled),
628
- "data-orientation": prop("orientation"),
629
- "data-invalid": dataAttr(invalid),
630
- "data-focus": dataAttr(focused),
631
- style: getControlStyle(),
632
- onPointerDown(event) {
633
- if (!interactive) return;
634
- if (!isLeftClick(event)) return;
635
- if (isModifierKey(event)) return;
636
- const point = getEventPoint(event);
637
- send({ type: "POINTER_DOWN", point });
638
- event.preventDefault();
639
- event.stopPropagation();
640
- }
641
- });
642
- },
643
- getMarkerGroupProps() {
644
- return normalize2.element({
645
- ...parts.markerGroup.attrs,
646
- role: "presentation",
647
- dir: prop("dir"),
648
- "aria-hidden": true,
649
- "data-orientation": prop("orientation"),
650
- style: getMarkerGroupStyle()
651
- });
652
- },
653
- getMarkerProps(props2) {
654
- const style = getMarkerStyle(service, props2.value);
655
- let markerState;
656
- if (props2.value < first(sliderValue)) {
657
- markerState = "under-value";
658
- } else if (props2.value > last(sliderValue)) {
659
- markerState = "over-value";
660
- } else {
661
- markerState = "at-value";
662
- }
663
- return normalize2.element({
664
- ...parts.marker.attrs,
665
- id: getMarkerId(scope, props2.value),
666
- role: "presentation",
667
- dir: prop("dir"),
668
- "data-orientation": prop("orientation"),
669
- "data-value": props2.value,
670
- "data-disabled": dataAttr(disabled),
671
- "data-state": markerState,
672
- style
673
- });
674
- },
675
- getDraggingIndicatorProps(props2) {
676
- const { index = 0 } = props2;
677
- const isDragging = index === focusedIndex && dragging;
678
- return normalize2.element({
679
- ...parts.draggingIndicator.attrs,
680
- role: "presentation",
681
- dir: prop("dir"),
682
- hidden: !isDragging,
683
- "data-orientation": prop("orientation"),
684
- "data-state": isDragging ? "open" : "closed",
685
- style: getThumbStyle(service, index)
686
- });
687
- }
688
- };
689
- }
690
- var isEqualSize = (a, b) => {
691
- return a?.width === b?.width && a?.height === b?.height;
692
- };
693
- var normalize = (value, min, max, step, minStepsBetweenThumbs) => {
694
- const ranges = getValueRanges(value, min, max, minStepsBetweenThumbs * step);
695
- return ranges.map((range) => {
696
- const snapValue = snapValueToStep(range.value, range.min, range.max, step);
697
- const rangeValue = clampValue(snapValue, range.min, range.max);
698
- if (!isValueWithinRange(rangeValue, min, max)) {
699
- throw new Error(
700
- "[zag-js/slider] The configured `min`, `max`, `step` or `minStepsBetweenThumbs` values are invalid"
701
- );
702
- }
703
- return rangeValue;
704
- });
705
- };
706
- var machine = createMachine({
707
- props({ props: props2 }) {
708
- const min = props2.min ?? 0;
709
- const max = props2.max ?? 100;
710
- const step = props2.step ?? 1;
711
- const defaultValue = props2.defaultValue ?? [min];
712
- const minStepsBetweenThumbs = props2.minStepsBetweenThumbs ?? 0;
713
- return {
714
- dir: "ltr",
715
- thumbAlignment: "contain",
716
- origin: "start",
717
- orientation: "horizontal",
718
- thumbCollisionBehavior: "none",
719
- minStepsBetweenThumbs,
720
- ...props2,
721
- defaultValue: normalize(defaultValue, min, max, step, minStepsBetweenThumbs),
722
- value: props2.value ? normalize(props2.value, min, max, step, minStepsBetweenThumbs) : void 0,
723
- max,
724
- step,
725
- min
726
- };
727
- },
728
- initialState() {
729
- return "idle";
730
- },
731
- context({ prop, bindable, getContext }) {
732
- return {
733
- thumbSize: bindable(() => ({
734
- defaultValue: prop("thumbSize") || null
735
- })),
736
- value: bindable(() => ({
737
- defaultValue: prop("defaultValue"),
738
- value: prop("value"),
739
- isEqual,
740
- hash(a) {
741
- return a.join(",");
742
- },
743
- onChange(value) {
744
- prop("onValueChange")?.({ value });
745
- }
746
- })),
747
- focusedIndex: bindable(() => ({
748
- defaultValue: -1,
749
- onChange(value) {
750
- const ctx = getContext();
751
- prop("onFocusChange")?.({ focusedIndex: value, value: ctx.get("value") });
752
- }
753
- })),
754
- fieldsetDisabled: bindable(() => ({
755
- defaultValue: false
756
- }))
757
- };
758
- },
759
- refs() {
760
- return {
761
- thumbDragOffset: null,
762
- thumbDragStartValue: null
763
- };
764
- },
765
- computed: {
766
- isHorizontal: ({ prop }) => prop("orientation") === "horizontal",
767
- isVertical: ({ prop }) => prop("orientation") === "vertical",
768
- isRtl: ({ prop }) => prop("orientation") === "horizontal" && prop("dir") === "rtl",
769
- isDisabled: ({ context, prop }) => !!prop("disabled") || context.get("fieldsetDisabled"),
770
- isInteractive: ({ prop, computed }) => !(prop("readOnly") || computed("isDisabled")),
771
- hasMeasuredThumbSize: ({ context }) => context.get("thumbSize") != null,
772
- valuePercent: memo(
773
- ({ context, prop }) => [context.get("value"), prop("min"), prop("max")],
774
- ([value, min, max]) => value.map((value2) => 100 * getValuePercent(value2, min, max))
775
- )
776
- },
777
- watch({ track, action, context, computed, send }) {
778
- track([() => context.hash("value")], () => {
779
- action(["syncInputElements", "dispatchChangeEvent"]);
780
- });
781
- track([() => computed("isDisabled")], () => {
782
- if (computed("isDisabled")) {
783
- send({ type: "POINTER_CANCEL" });
784
- }
785
- });
786
- },
787
- effects: ["trackFormControlState", "trackThumbSize"],
788
- on: {
789
- SET_VALUE: [
790
- {
791
- guard: "hasIndex",
792
- actions: ["setValueAtIndex", "invokeOnChangeEnd"]
793
- },
794
- {
795
- actions: ["setValue", "invokeOnChangeEnd"]
796
- }
797
- ],
798
- INCREMENT: {
799
- actions: ["incrementThumbAtIndex", "invokeOnChangeEnd"]
800
- },
801
- DECREMENT: {
802
- actions: ["decrementThumbAtIndex", "invokeOnChangeEnd"]
803
- }
804
- },
805
- states: {
806
- idle: {
807
- on: {
808
- POINTER_DOWN: {
809
- target: "dragging",
810
- actions: ["setClosestThumbIndex", "setThumbDragStartValue", "setPointerValue", "focusActiveThumb"]
811
- },
812
- FOCUS: {
813
- target: "focus",
814
- actions: ["setFocusedIndex"]
815
- },
816
- THUMB_POINTER_DOWN: {
817
- target: "dragging",
818
- actions: ["setFocusedIndex", "setThumbDragOffset", "setThumbDragStartValue", "focusActiveThumb"]
819
- }
820
- }
821
- },
822
- focus: {
823
- entry: ["focusActiveThumb"],
824
- on: {
825
- POINTER_DOWN: {
826
- target: "dragging",
827
- actions: ["setClosestThumbIndex", "setThumbDragStartValue", "setPointerValue", "focusActiveThumb"]
828
- },
829
- THUMB_POINTER_DOWN: {
830
- target: "dragging",
831
- actions: ["setFocusedIndex", "setThumbDragOffset", "setThumbDragStartValue", "focusActiveThumb"]
832
- },
833
- ARROW_DEC: {
834
- actions: ["decrementThumbAtIndex", "invokeOnChangeEnd"]
835
- },
836
- ARROW_INC: {
837
- actions: ["incrementThumbAtIndex", "invokeOnChangeEnd"]
838
- },
839
- HOME: {
840
- actions: ["setFocusedThumbToMin", "invokeOnChangeEnd"]
841
- },
842
- END: {
843
- actions: ["setFocusedThumbToMax", "invokeOnChangeEnd"]
844
- },
845
- BLUR: {
846
- target: "idle",
847
- actions: ["clearFocusedIndex"]
848
- }
849
- }
850
- },
851
- dragging: {
852
- entry: ["focusActiveThumb"],
853
- effects: ["trackPointerMove"],
854
- on: {
855
- POINTER_UP: {
856
- target: "focus",
857
- actions: ["invokeOnChangeEnd", "clearThumbDragOffset", "clearThumbDragStartValue"]
858
- },
859
- POINTER_MOVE: {
860
- actions: ["setPointerValue"]
861
- },
862
- POINTER_CANCEL: {
863
- target: "idle",
864
- actions: ["clearFocusedIndex", "clearThumbDragOffset", "clearThumbDragStartValue"]
865
- }
866
- }
867
- }
868
- },
869
- implementations: {
870
- guards: {
871
- hasIndex: ({ event }) => event.index != null
872
- },
873
- effects: {
874
- trackFormControlState({ context, scope }) {
875
- return trackFormControl(getRootEl(scope), {
876
- onFieldsetDisabledChange(disabled) {
877
- context.set("fieldsetDisabled", disabled);
878
- },
879
- onFormReset() {
880
- context.set("value", context.initial("value"));
881
- }
882
- });
883
- },
884
- trackPointerMove({ scope, send }) {
885
- return trackPointerMove(scope.getDoc(), {
886
- onPointerMove(info) {
887
- send({ type: "POINTER_MOVE", point: info.point });
888
- },
889
- onPointerUp() {
890
- send({ type: "POINTER_UP" });
891
- }
892
- });
893
- },
894
- trackThumbSize({ context, scope, prop }) {
895
- if (prop("thumbAlignment") !== "contain" || prop("thumbSize")) return;
896
- const exec = (el) => {
897
- const rect = getOffsetRect(el);
898
- const size = pick(rect, ["width", "height"]);
899
- if (isEqualSize(context.get("thumbSize"), size)) return;
900
- context.set("thumbSize", size);
901
- };
902
- const thumbEls = getThumbEls(scope);
903
- thumbEls.forEach(exec);
904
- const cleanups = thumbEls.map((el) => resizeObserverBorderBox.observe(el, () => exec(el)));
905
- return callAll(...cleanups);
906
- }
907
- },
908
- actions: {
909
- dispatchChangeEvent({ context, scope }) {
910
- dispatchChangeEvent(scope, context.get("value"));
911
- },
912
- syncInputElements({ context, scope }) {
913
- context.get("value").forEach((value, index) => {
914
- const inputEl = getHiddenInputEl(scope, index);
915
- setElementValue(inputEl, value.toString());
916
- });
917
- },
918
- invokeOnChangeEnd({ prop, context }) {
919
- queueMicrotask(() => {
920
- prop("onValueChangeEnd")?.({ value: context.get("value") });
921
- });
922
- },
923
- setClosestThumbIndex(params) {
924
- const { context, event } = params;
925
- const pointValue = getPointValue(params, event.point);
926
- if (pointValue == null) return;
927
- const focusedIndex = getClosestIndex(params, pointValue);
928
- context.set("focusedIndex", focusedIndex);
929
- },
930
- setFocusedIndex(params) {
931
- const { context, event } = params;
932
- const movableIndex = selectMovableThumb(params, event.index);
933
- context.set("focusedIndex", movableIndex);
934
- },
935
- clearFocusedIndex({ context }) {
936
- context.set("focusedIndex", -1);
937
- },
938
- setThumbDragOffset(params) {
939
- const { refs, event } = params;
940
- refs.set("thumbDragOffset", event.offset ?? null);
941
- },
942
- clearThumbDragOffset({ refs }) {
943
- refs.set("thumbDragOffset", null);
944
- },
945
- setThumbDragStartValue({ refs, context }) {
946
- refs.set("thumbDragStartValue", context.get("value").slice());
947
- },
948
- clearThumbDragStartValue({ refs }) {
949
- refs.set("thumbDragStartValue", null);
950
- },
951
- setPointerValue(params) {
952
- queueMicrotask(() => {
953
- const { context, event, prop, refs } = params;
954
- const pointValue = getPointValue(params, event.point);
955
- if (pointValue == null) return;
956
- const focusedIndex = context.get("focusedIndex");
957
- const startValues = refs.get("thumbDragStartValue");
958
- const result = resolveThumbCollision(
959
- prop("thumbCollisionBehavior"),
960
- focusedIndex,
961
- pointValue,
962
- context.get("value"),
963
- prop("min"),
964
- prop("max"),
965
- prop("step"),
966
- prop("minStepsBetweenThumbs"),
967
- startValues?.[focusedIndex]
968
- );
969
- if (result.swapped) {
970
- context.set("focusedIndex", result.index);
971
- }
972
- context.set("value", result.values);
973
- });
974
- },
975
- focusActiveThumb({ scope, context }) {
976
- raf(() => {
977
- const thumbEl = getThumbEl(scope, context.get("focusedIndex"));
978
- thumbEl?.focus({ preventScroll: true });
979
- });
980
- },
981
- decrementThumbAtIndex(params) {
982
- const { context, event } = params;
983
- const value = decrement(params, event.index, event.step);
984
- context.set("value", value);
985
- },
986
- incrementThumbAtIndex(params) {
987
- const { context, event } = params;
988
- const value = increment(params, event.index, event.step);
989
- context.set("value", value);
990
- },
991
- setFocusedThumbToMin(params) {
992
- const { context } = params;
993
- const index = context.get("focusedIndex");
994
- const { min } = getRangeAtIndex(params, index);
995
- context.set("value", (prev) => setValueAtIndex(prev, index, min));
996
- },
997
- setFocusedThumbToMax(params) {
998
- const { context } = params;
999
- const index = context.get("focusedIndex");
1000
- const { max } = getRangeAtIndex(params, index);
1001
- context.set("value", (prev) => setValueAtIndex(prev, index, max));
1002
- },
1003
- setValueAtIndex(params) {
1004
- const { context, event } = params;
1005
- const value = constrainValue(params, event.value, event.index);
1006
- context.set("value", (prev) => setValueAtIndex(prev, event.index, value));
1007
- },
1008
- setValue(params) {
1009
- const { context, event } = params;
1010
- const value = normalizeValues(params, event.value);
1011
- context.set("value", value);
1012
- }
1013
- }
1014
- }
1015
- });
1016
- var props = createProps()([
1017
- "aria-label",
1018
- "aria-labelledby",
1019
- "dir",
1020
- "disabled",
1021
- "form",
1022
- "getAriaValueText",
1023
- "getRootNode",
1024
- "id",
1025
- "ids",
1026
- "invalid",
1027
- "max",
1028
- "min",
1029
- "minStepsBetweenThumbs",
1030
- "name",
1031
- "onFocusChange",
1032
- "onValueChange",
1033
- "onValueChangeEnd",
1034
- "orientation",
1035
- "origin",
1036
- "readOnly",
1037
- "step",
1038
- "thumbAlignment",
1039
- "thumbCollisionBehavior",
1040
- "thumbSize",
1041
- "value",
1042
- "defaultValue"
1043
- ]);
1044
- var splitProps = createSplitProps(props);
1045
- var thumbProps = createProps()(["index", "name"]);
1046
- var splitThumbProps = createSplitProps(thumbProps);
1047
- var markerProps = createProps()(["value"]);
1048
- var splitMarkerProps = createSplitProps(markerProps);
1049
-
1050
- export { anatomy, connect, machine, markerProps, props, splitMarkerProps, splitProps, splitThumbProps, thumbProps };