UNPKG

@yamada-ui/slider

Version:

Yamada UI slider components

624 lines (623 loc) • 20.9 kB
"use client" "use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; 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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/slider.tsx var slider_exports = {}; __export(slider_exports, { Slider: () => Slider, SliderFilledTrack: () => SliderFilledTrack, SliderMark: () => SliderMark, SliderThumb: () => SliderThumb, SliderTrack: () => SliderTrack, getThumbSize: () => getThumbSize, useSlider: () => useSlider }); module.exports = __toCommonJS(slider_exports); var import_core = require("@yamada-ui/core"); var import_form_control = require("@yamada-ui/form-control"); var import_use_controllable_state = require("@yamada-ui/use-controllable-state"); var import_use_latest_ref = require("@yamada-ui/use-latest-ref"); var import_use_pan_event = require("@yamada-ui/use-pan-event"); var import_use_size = require("@yamada-ui/use-size"); var import_utils = require("@yamada-ui/utils"); var import_react = require("react"); var import_jsx_runtime = require("react/jsx-runtime"); var getThumbSize = (thumbSize, styles) => { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t; return (_t = (_s = (_q = (_o = (_m = (_k = (_i = (_g = (_e = (_c = thumbSize != null ? thumbSize : (_a = styles.thumb) == null ? void 0 : _a.boxSize) != null ? _c : (_b = styles.thumb) == null ? void 0 : _b.minBoxSize) != null ? _e : (_d = styles.thumb) == null ? void 0 : _d.width) != null ? _g : (_f = styles.thumb) == null ? void 0 : _f.w) != null ? _i : (_h = styles.thumb) == null ? void 0 : _h.minWidth) != null ? _k : (_j = styles.thumb) == null ? void 0 : _j.minW) != null ? _m : (_l = styles.thumb) == null ? void 0 : _l.height) != null ? _o : (_n = styles.thumb) == null ? void 0 : _n.h) != null ? _q : (_p = styles.thumb) == null ? void 0 : _p.minHeight) != null ? _s : (_r = styles.thumb) == null ? void 0 : _r.minH) != null ? _t : "3.5"; }; var useSlider = ({ focusThumbOnChange = true, ...props }) => { if (!focusThumbOnChange) props.isReadOnly = true; const { id, name, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-valuetext": ariaValueText, defaultValue, getAriaValueText: getAriaValueTextProp, isReversed, max = 100, min = 0, orientation = "horizontal", reversed = isReversed, step = 1, thumbSize: thumbSizeProp, value: valueProp, onChange, onChangeEnd: onChangeEndProp, onChangeStart: onChangeStartProp, ...rest } = (0, import_form_control.useFormControlProps)(props); if (max < min) throw new Error("Do not assign a number less than 'min' to 'max'"); const { "aria-readonly": ariaReadonly, disabled, readOnly, required, onBlur, onFocus, ...formControlProps } = (0, import_utils.pickObject)(rest, import_form_control.formControlProperties); const [computedValue, setValue] = (0, import_use_controllable_state.useControllableState)({ defaultValue: defaultValue != null ? defaultValue : min + (max - min) / 2, value: valueProp, onChange }); const [dragging, setDragging] = (0, import_react.useState)(false); const [focused, setFocused] = (0, import_react.useState)(false); const interactive = !(disabled || readOnly); const tenStep = (max - min) / 10; const oneStep = step || (max - min) / 100; const value = (0, import_utils.clampNumber)(computedValue, min, max); const reversedValue = max - value + min; const thumbValue = reversed ? reversedValue : value; const thumbPercent = (0, import_utils.valueToPercent)(thumbValue, min, max); const vertical = orientation === "vertical"; const latestRef = (0, import_use_latest_ref.useLatestRef)({ focusThumbOnChange, interactive, max, min, step, value }); const eventSourceRef = (0, import_react.useRef)(null); const containerRef = (0, import_react.useRef)(null); const trackRef = (0, import_react.useRef)(null); const thumbRef = (0, import_react.useRef)(null); const thumbSize = (0, import_use_size.useSize)(thumbRef); const onChangeStart = (0, import_utils.useCallbackRef)(onChangeStartProp); const onChangeEnd = (0, import_utils.useCallbackRef)(onChangeEndProp); const getAriaValueText = (0, import_utils.useCallbackRef)(getAriaValueTextProp); (0, import_use_pan_event.usePanEvent)(containerRef, { onMove: (ev) => { const { interactive: interactive2 } = latestRef.current; if (!interactive2) return; setValueFromPointer(ev); }, onSessionEnd: () => { const { interactive: interactive2, value: value2 } = latestRef.current; if (!interactive2) return; setDragging(false); onChangeEnd(value2); }, onSessionStart: (ev) => { const { interactive: interactive2, value: value2 } = latestRef.current; if (!interactive2) return; setDragging(true); focusThumb(); setValueFromPointer(ev); onChangeStart(value2); } }); const getValueFromPointer = (0, import_react.useCallback)( (ev) => { var _a, _b; if (!trackRef.current) return; const { max: max2, min: min2, step: step2 } = latestRef.current; eventSourceRef.current = "pointer"; const { bottom, height, left, width } = trackRef.current.getBoundingClientRect(); const { clientX, clientY } = (_b = (_a = ev.touches) == null ? void 0 : _a[0]) != null ? _b : ev; const diff = vertical ? bottom - clientY : clientX - left; const length = vertical ? height : width; let percent = diff / length; if (reversed) percent = 1 - percent; let nextValue = (0, import_utils.percentToValue)(percent, min2, max2); if (step2) nextValue = parseFloat((0, import_utils.roundNumberToStep)(nextValue, min2, step2)); nextValue = (0, import_utils.clampNumber)(nextValue, min2, max2); return nextValue; }, [vertical, reversed, latestRef] ); const setValueFromPointer = (ev) => { const { value: value2 } = latestRef.current; const nextValue = getValueFromPointer(ev); if (nextValue != null && nextValue !== value2) setValue(nextValue); }; const focusThumb = (0, import_react.useCallback)(() => { const { focusThumbOnChange: focusThumbOnChange2 } = latestRef.current; if (focusThumbOnChange2) setTimeout(() => { var _a; return (_a = thumbRef.current) == null ? void 0 : _a.focus(); }); }, [latestRef]); const constrain = (0, import_react.useCallback)( (value2) => { const { interactive: interactive2, max: max2, min: min2 } = latestRef.current; if (!interactive2) return; value2 = parseFloat((0, import_utils.roundNumberToStep)(value2, min2, oneStep)); value2 = (0, import_utils.clampNumber)(value2, min2, max2); setValue(value2); }, [oneStep, setValue, latestRef] ); const stepUp = (0, import_react.useCallback)( (step2 = oneStep) => constrain(reversed ? value - step2 : value + step2), [constrain, reversed, oneStep, value] ); const stepDown = (0, import_react.useCallback)( (step2 = oneStep) => constrain(reversed ? value + step2 : value - step2), [constrain, reversed, oneStep, value] ); const reset = (0, import_react.useCallback)( () => constrain(defaultValue || 0), [constrain, defaultValue] ); const stepTo = (0, import_react.useCallback)((value2) => constrain(value2), [constrain]); const onKeyDown = (0, import_react.useCallback)( (ev) => { const { max: max2, min: min2 } = latestRef.current; const actions = { ArrowDown: () => stepDown(), ArrowLeft: () => stepDown(), ArrowRight: () => stepUp(), ArrowUp: () => stepUp(), End: () => constrain(max2), Home: () => constrain(min2), PageDown: () => stepDown(tenStep), PageUp: () => stepUp(tenStep) }; const action = actions[ev.key]; if (!action) return; ev.preventDefault(); ev.stopPropagation(); action(ev); eventSourceRef.current = "keyboard"; }, [constrain, latestRef, stepDown, stepUp, tenStep] ); (0, import_utils.useUpdateEffect)(() => { const { value: value2 } = latestRef.current; focusThumb(); if (eventSourceRef.current === "keyboard") onChangeEnd(value2); }, [value, onChangeEnd]); const getContainerProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => { let { height: h, width: w } = thumbSize != null ? thumbSize : { height: "var(--ui-thumb-size)", width: "var(--ui-thumb-size)" }; if ((0, import_utils.isNumber)(w)) w = `${w}px`; if ((0, import_utils.isNumber)(h)) h = `${h}px`; const paddingStyle = vertical ? { paddingLeft: `calc(${w} / 2)`, paddingRight: `calc(${w} / 2)` } : { paddingBottom: `calc(${h} / 2)`, paddingTop: `calc(${h} / 2)` }; const style = { ...props2.style, outline: 0, position: "relative", touchAction: "none", userSelect: "none", WebkitTapHighlightColor: "rgba(0, 0, 0, 0)", ...paddingStyle }; return { ...rest, ...props2, ref: (0, import_utils.mergeRefs)(ref, containerRef), style, tabIndex: -1, vars: (0, import_core.mergeVars)(rest.vars, [ { name: "thumb-size", token: "sizes", value: thumbSizeProp, __prefix: "ui" } ]) }; }, [vertical, rest, thumbSize, thumbSizeProp] ); const getInputProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => ({ "aria-readonly": ariaReadonly, ...formControlProps, ...props2, id, ref, type: "hidden", name, disabled, readOnly, required, value }), [ ariaReadonly, disabled, formControlProps, id, name, readOnly, required, value ] ); const getTrackProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => { const style = { ...props2.style, position: "absolute", ...vertical ? { height: "100%", left: "50%", transform: "translateX(-50%)" } : { top: "50%", transform: "translateY(-50%)", width: "100%" } }; return { ...formControlProps, ...props2, ref: (0, import_utils.mergeRefs)(ref, trackRef), style }; }, [vertical, formControlProps] ); const getFilledTrackProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => { const n = Math.abs(reversed ? 100 - thumbPercent : thumbPercent); const style = { ...props2.style, position: "absolute", ...vertical ? { height: `${n}%`, left: "50%", transform: "translateX(-50%)", ...reversed ? { top: "0%" } : { bottom: "0%" } } : { top: "50%", transform: "translateY(-50%)", width: `${n}%`, ...reversed ? { right: "0%" } : { left: "0%" } } }; return { ...formControlProps, ...props2, ref, style }; }, [reversed, vertical, formControlProps, thumbPercent] ); const getMarkProps = (0, import_react.useCallback)( (props2, ref = null) => { let n = (0, import_utils.valueToPercent)(props2.value, min, max); n = reversed ? 100 - n : n; const style = { ...props2.style, pointerEvents: "none", position: "absolute", ...vertical ? { bottom: `${n}%` } : { left: `${n}%` } }; return { ...formControlProps, ...props2, ref, style, "aria-hidden": true, "data-highlighted": (0, import_utils.dataAttr)(props2.value <= value), "data-invalid": (0, import_utils.dataAttr)(props2.value < min || max < props2.value) }; }, [reversed, vertical, max, min, formControlProps, value] ); const getThumbProps = (0, import_react.useCallback)( (props2 = {}, ref = null) => { var _a; const n = thumbPercent; let w = "var(--ui-thumb-size)"; let h = "var(--ui-thumb-size)"; if (thumbSize) { w = `${thumbSize.width}px`; h = `${thumbSize.height}px`; } const bottom = `calc(${n}% - (${h} / 2))`; const left = `calc(${n}% - (${w} / 2))`; const style = { ...props2.style, position: "absolute", touchAction: "none", userSelect: "none", ...vertical ? { bottom } : { left } }; return { "aria-label": ariaLabel != null ? ariaLabel : "Slider thumb", "aria-labelledby": ariaLabelledBy, "aria-readonly": ariaReadonly, ...formControlProps, ...props2, ref: (0, import_utils.mergeRefs)(ref, thumbRef), style, "aria-orientation": orientation, "aria-valuemax": max, "aria-valuemin": min, "aria-valuenow": value, "aria-valuetext": (_a = ariaValueText != null ? ariaValueText : getAriaValueText(value)) != null ? _a : value.toString(), "data-active": (0, import_utils.dataAttr)(dragging && focusThumbOnChange), role: "slider", tabIndex: interactive && focusThumbOnChange ? 0 : void 0, onBlur: (0, import_utils.handlerAll)(props2.onBlur, onBlur, () => setFocused(false)), onFocus: (0, import_utils.handlerAll)(props2.onFocus, onFocus, () => setFocused(true)), onKeyDown: (0, import_utils.handlerAll)(props2.onKeyDown, onKeyDown) }; }, [ thumbPercent, thumbSize, vertical, ariaLabel, ariaLabelledBy, ariaReadonly, formControlProps, orientation, max, min, value, ariaValueText, getAriaValueText, dragging, focusThumbOnChange, interactive, onBlur, onFocus, onKeyDown ] ); return { dragging, focused, /** * @deprecated Use `dragging` instead. */ isDragging: dragging, /** * @deprecated Use `focused` instead. */ isFocused: focused, /** * @deprecated Use `vertical` instead. */ isVertical: vertical, reset, stepDown, stepTo, stepUp, value, vertical, getContainerProps, getFilledTrackProps, getInputProps, getMarkProps, getThumbProps, getTrackProps }; }; var [SliderProvider, useSliderContext] = (0, import_utils.createContext)({ name: "SliderContext", errorMessage: `useSliderContext returned is 'undefined'. Seems you forgot to wrap the components in "<Slider />" ` }); var Slider = (0, import_core.forwardRef)((props, ref) => { const [styles, mergedProps] = (0, import_core.useComponentMultiStyle)("Slider", props); const { className, children, filledTrackColor, thumbColor, thumbSize, trackColor, trackSize, filledTrackProps, inputProps, thumbProps, trackProps, ...rest } = (0, import_core.omitThemeProps)(mergedProps); const { isVertical, getContainerProps, getFilledTrackProps, getInputProps, getMarkProps, getThumbProps, getTrackProps } = useSlider({ ...rest, thumbSize: getThumbSize(thumbSize, styles) }); const css = { ...styles.container }; const validChildren = (0, import_utils.getValidChildren)(children); const customSliderTrack = (0, import_utils.findChild)(validChildren, SliderTrack); const customSliderThumb = (0, import_utils.findChild)(validChildren, SliderThumb); const hasSliderThumb = (0, import_utils.includesChildren)(validChildren, SliderThumb); const cloneChildren = !(0, import_utils.isEmpty)(validChildren) ? (0, import_utils.omitChildren)(validChildren, SliderTrack, SliderThumb) : children; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( SliderProvider, { value: { filledTrackColor, isVertical, styles, thumbColor, thumbSize, trackColor, trackSize, filledTrackProps, getFilledTrackProps, getMarkProps, getThumbProps, getTrackProps, thumbProps, trackProps }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( import_core.ui.div, { className: (0, import_utils.cx)("ui-slider", className), __css: css, ...getContainerProps(), children: [ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_core.ui.input, { ...getInputProps(inputProps, ref) }), customSliderTrack != null ? customSliderTrack : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SliderTrack, {}), cloneChildren, customSliderThumb != null ? customSliderThumb : !hasSliderThumb ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SliderThumb, {}) : null ] } ) } ); }); Slider.displayName = "Slider"; Slider.__ui__ = "Slider"; var SliderTrack = (0, import_core.forwardRef)( ({ className, children, filledTrackProps, ...rest }, ref) => { const { isVertical, styles, trackColor, trackSize, getTrackProps, trackProps } = useSliderContext(); const css = { ...styles.track }; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_core.ui.div, { className: (0, import_utils.cx)("ui-slider__track", className), __css: css, ...getTrackProps( { ...trackColor ? { bg: trackColor } : {}, ...trackSize ? isVertical ? { w: trackSize } : { h: trackSize } : {}, ...trackProps, ...rest }, ref ), children: children != null ? children : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SliderFilledTrack, { ...filledTrackProps }) } ); } ); SliderTrack.displayName = "SliderTrack"; SliderTrack.__ui__ = "SliderTrack"; var SliderFilledTrack = (0, import_core.forwardRef)( ({ className, ...rest }, ref) => { const { filledTrackColor, styles, filledTrackProps, getFilledTrackProps } = useSliderContext(); const css = { ...styles.filledTrack }; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_core.ui.div, { className: (0, import_utils.cx)("ui-slider__track-filled", className), __css: css, ...getFilledTrackProps( { ...filledTrackColor ? { bg: filledTrackColor } : {}, ...filledTrackProps, ...rest }, ref ) } ); } ); SliderFilledTrack.displayName = "SliderFilledTrack"; SliderFilledTrack.__ui__ = "SliderFilledTrack"; var SliderMark = (0, import_core.forwardRef)( ({ className, ...rest }, ref) => { const { styles, getMarkProps } = useSliderContext(); const css = { alignItems: "center", display: "inline-flex", justifyContent: "center", ...styles.mark }; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_core.ui.div, { className: (0, import_utils.cx)("ui-slider__mark", className), __css: css, ...getMarkProps(rest, ref) } ); } ); SliderMark.displayName = "SliderMark"; SliderMark.__ui__ = "SliderMark"; var SliderThumb = (0, import_core.forwardRef)( ({ className, ...rest }, ref) => { const { styles, thumbColor, thumbSize, getThumbProps, thumbProps } = useSliderContext(); const css = { ...styles.thumb }; return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( import_core.ui.div, { className: (0, import_utils.cx)("ui-slider__thumb", className), __css: css, ...getThumbProps( { ...thumbColor ? { bg: thumbColor } : {}, ...thumbSize ? { boxSize: thumbSize } : {}, ...thumbProps, ...rest }, ref ) } ); } ); SliderThumb.displayName = "SliderThumb"; SliderThumb.__ui__ = "SliderThumb"; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Slider, SliderFilledTrack, SliderMark, SliderThumb, SliderTrack, getThumbSize, useSlider }); //# sourceMappingURL=slider.js.map