UNPKG

@zag-js/slider

Version:

Core logic for the slider widget implemented as a state machine

355 lines (353 loc) • 13.5 kB
"use strict"; 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 });