@zag-js/slider
Version:
Core logic for the slider widget implemented as a state machine
355 lines (353 loc) • 13.5 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/slider.connect.ts
var slider_connect_exports = {};
__export(slider_connect_exports, {
connect: () => connect
});
module.exports = __toCommonJS(slider_connect_exports);
var import_dom_query = require("@zag-js/dom-query");
var import_utils = require("@zag-js/utils");
var import_slider = require("./slider.anatomy.js");
var dom = __toESM(require("./slider.dom.js"));
var import_slider2 = require("./slider.style.js");
var import_slider3 = require("./slider.utils.js");
function connect(service, normalize) {
const { state, send, context, prop, computed, scope } = service;
const ariaLabel = prop("aria-label");
const ariaLabelledBy = prop("aria-labelledby");
const sliderValue = context.get("value");
const focusedIndex = context.get("focusedIndex");
const focused = state.matches("focus");
const dragging = state.matches("dragging");
const disabled = computed("isDisabled");
const invalid = prop("invalid");
const interactive = computed("isInteractive");
const isHorizontal = prop("orientation") === "horizontal";
const isVertical = prop("orientation") === "vertical";
function getValuePercentFn(value) {
return (0, import_utils.getValuePercent)(value, prop("min"), prop("max"));
}
function getPercentValueFn(percent) {
return (0, import_utils.getPercentValue)(percent, prop("min"), prop("max"), prop("step"));
}
return {
value: sliderValue,
dragging,
focused,
setValue(value) {
send({ type: "SET_VALUE", value });
},
getThumbValue(index) {
return sliderValue[index];
},
setThumbValue(index, value) {
send({ type: "SET_VALUE", index, value });
},
getValuePercent: getValuePercentFn,
getPercentValue: getPercentValueFn,
getThumbPercent(index) {
return getValuePercentFn(sliderValue[index]);
},
setThumbPercent(index, percent) {
const value = getPercentValueFn(percent);
send({ type: "SET_VALUE", index, value });
},
getThumbMin(index) {
return (0, import_slider3.getRangeAtIndex)(service, index).min;
},
getThumbMax(index) {
return (0, import_slider3.getRangeAtIndex)(service, index).max;
},
increment(index) {
send({ type: "INCREMENT", index });
},
decrement(index) {
send({ type: "DECREMENT", index });
},
focus() {
if (!interactive) return;
send({ type: "FOCUS", index: 0 });
},
getLabelProps() {
return normalize.label({
...import_slider.parts.label.attrs,
dir: prop("dir"),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-dragging": (0, import_dom_query.dataAttr)(dragging),
"data-focus": (0, import_dom_query.dataAttr)(focused),
id: dom.getLabelId(scope),
htmlFor: dom.getHiddenInputId(scope, 0),
onClick(event) {
if (!interactive) return;
event.preventDefault();
dom.getFirstThumbEl(scope)?.focus();
},
style: {
userSelect: "none",
WebkitUserSelect: "none"
}
});
},
getRootProps() {
return normalize.element({
...import_slider.parts.root.attrs,
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
"data-dragging": (0, import_dom_query.dataAttr)(dragging),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-focus": (0, import_dom_query.dataAttr)(focused),
id: dom.getRootId(scope),
dir: prop("dir"),
style: (0, import_slider2.getRootStyle)(service)
});
},
getValueTextProps() {
return normalize.element({
...import_slider.parts.valueText.attrs,
dir: prop("dir"),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-focus": (0, import_dom_query.dataAttr)(focused),
id: dom.getValueTextId(scope)
});
},
getTrackProps() {
return normalize.element({
...import_slider.parts.track.attrs,
dir: prop("dir"),
id: dom.getTrackId(scope),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-dragging": (0, import_dom_query.dataAttr)(dragging),
"data-orientation": prop("orientation"),
"data-focus": (0, import_dom_query.dataAttr)(focused),
style: { position: "relative" }
});
},
getThumbProps(props) {
const { index = 0, name } = props;
const value = sliderValue[index];
const range = (0, import_slider3.getRangeAtIndex)(service, index);
const valueText = prop("getAriaValueText")?.({ value, index });
const _ariaLabel = Array.isArray(ariaLabel) ? ariaLabel[index] : ariaLabel;
const _ariaLabelledBy = Array.isArray(ariaLabelledBy) ? ariaLabelledBy[index] : ariaLabelledBy;
return normalize.element({
...import_slider.parts.thumb.attrs,
dir: prop("dir"),
"data-index": index,
"data-name": name,
id: dom.getThumbId(scope, index),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
"data-focus": (0, import_dom_query.dataAttr)(focused && focusedIndex === index),
"data-dragging": (0, import_dom_query.dataAttr)(dragging && focusedIndex === index),
draggable: false,
"aria-disabled": (0, import_dom_query.ariaAttr)(disabled),
"aria-label": _ariaLabel,
"aria-labelledby": _ariaLabelledBy ?? dom.getLabelId(scope),
"aria-orientation": prop("orientation"),
"aria-valuemax": range.max,
"aria-valuemin": range.min,
"aria-valuenow": sliderValue[index],
"aria-valuetext": valueText,
role: "slider",
tabIndex: disabled ? void 0 : 0,
style: (0, import_slider2.getThumbStyle)(service, index),
onPointerDown(event) {
if (!interactive) return;
if (!(0, import_dom_query.isLeftClick)(event)) return;
const thumbEl = event.currentTarget;
const rect = thumbEl.getBoundingClientRect();
const midpoint = {
x: rect.left + rect.width / 2,
y: rect.top + rect.height / 2
};
const offset = {
x: event.clientX - midpoint.x,
y: event.clientY - midpoint.y
};
send({ type: "THUMB_POINTER_DOWN", index, offset });
event.stopPropagation();
},
onBlur() {
if (!interactive) return;
send({ type: "BLUR" });
},
onFocus() {
if (!interactive) return;
send({ type: "FOCUS", index });
},
onKeyDown(event) {
if (event.defaultPrevented) return;
if (!interactive) return;
const step = (0, import_dom_query.getEventStepValue)(event, { step: prop("step"), largeStep: prop("largeStep") });
const keyMap = {
ArrowUp() {
if (isHorizontal) return;
send({ type: "ARROW_INC", step, src: "ArrowUp" });
},
ArrowDown() {
if (isHorizontal) return;
send({ type: "ARROW_DEC", step, src: "ArrowDown" });
},
ArrowLeft() {
if (isVertical) return;
send({ type: "ARROW_DEC", step, src: "ArrowLeft" });
},
ArrowRight() {
if (isVertical) return;
send({ type: "ARROW_INC", step, src: "ArrowRight" });
},
PageUp() {
send({ type: "ARROW_INC", step, src: "PageUp" });
},
PageDown() {
send({ type: "ARROW_DEC", step, src: "PageDown" });
},
Home() {
send({ type: "HOME" });
},
End() {
send({ type: "END" });
}
};
const key = (0, import_dom_query.getEventKey)(event, {
dir: prop("dir"),
orientation: prop("orientation")
});
const exec = keyMap[key];
if (exec) {
exec(event);
event.preventDefault();
event.stopPropagation();
}
}
});
},
getHiddenInputProps(props) {
const { index = 0, name } = props;
return normalize.input({
name: name ?? (prop("name") ? prop("name") + (sliderValue.length > 1 ? "[]" : "") : void 0),
form: prop("form"),
type: "text",
hidden: true,
defaultValue: sliderValue[index],
id: dom.getHiddenInputId(scope, index)
});
},
getRangeProps() {
return normalize.element({
id: dom.getRangeId(scope),
...import_slider.parts.range.attrs,
dir: prop("dir"),
"data-dragging": (0, import_dom_query.dataAttr)(dragging),
"data-focus": (0, import_dom_query.dataAttr)(focused),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
style: (0, import_slider2.getRangeStyle)(service)
});
},
getControlProps() {
return normalize.element({
...import_slider.parts.control.attrs,
dir: prop("dir"),
id: dom.getControlId(scope),
"data-dragging": (0, import_dom_query.dataAttr)(dragging),
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-orientation": prop("orientation"),
"data-invalid": (0, import_dom_query.dataAttr)(invalid),
"data-focus": (0, import_dom_query.dataAttr)(focused),
style: (0, import_slider2.getControlStyle)(),
onPointerDown(event) {
if (!interactive) return;
if (!(0, import_dom_query.isLeftClick)(event)) return;
if ((0, import_dom_query.isModifierKey)(event)) return;
const point = (0, import_dom_query.getEventPoint)(event);
send({ type: "POINTER_DOWN", point });
event.preventDefault();
event.stopPropagation();
}
});
},
getMarkerGroupProps() {
return normalize.element({
...import_slider.parts.markerGroup.attrs,
role: "presentation",
dir: prop("dir"),
"aria-hidden": true,
"data-orientation": prop("orientation"),
style: (0, import_slider2.getMarkerGroupStyle)()
});
},
getMarkerProps(props) {
const style = (0, import_slider2.getMarkerStyle)(service, props.value);
let markerState;
if (props.value < (0, import_utils.first)(sliderValue)) {
markerState = "under-value";
} else if (props.value > (0, import_utils.last)(sliderValue)) {
markerState = "over-value";
} else {
markerState = "at-value";
}
return normalize.element({
...import_slider.parts.marker.attrs,
id: dom.getMarkerId(scope, props.value),
role: "presentation",
dir: prop("dir"),
"data-orientation": prop("orientation"),
"data-value": props.value,
"data-disabled": (0, import_dom_query.dataAttr)(disabled),
"data-state": markerState,
style
});
},
getDraggingIndicatorProps(props) {
const { index = 0 } = props;
const isDragging = index === focusedIndex && dragging;
return normalize.element({
...import_slider.parts.draggingIndicator.attrs,
role: "presentation",
dir: prop("dir"),
hidden: !isDragging,
"data-orientation": prop("orientation"),
"data-state": isDragging ? "open" : "closed",
style: (0, import_slider2.getThumbStyle)(service, index)
});
}
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
connect
});