@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
1 lines • 17.8 kB
Source Map (JSON)
{"version":3,"file":"use-slider.cjs","names":["useFieldProps","useControllableState","useI18n","usePanEvent","value","min","max","step","getRootProps: PropGetter","computedProps: HTMLProps","props","getInputProps: PropGetter<\"input\", { index?: number }>","visuallyHiddenAttributes","mergeRefs","getTrackProps: PropGetter","getRangeProps: PropGetter","valueProp","percent","rest","props: HTMLProps"],"sources":["../../../../src/components/slider/use-slider.ts"],"sourcesContent":["\"use client\"\n\nimport type { KeyboardEvent } from \"react\"\nimport type {\n HTMLProps,\n HTMLRefAttributes,\n Orientation,\n PropGetter,\n RequiredPropGetter,\n} from \"../../core\"\nimport type { Point } from \"../../utils\"\nimport type { FieldProps } from \"../field\"\nimport { useCallback, useRef } from \"react\"\nimport { useControllableState } from \"../../hooks/use-controllable-state\"\nimport { usePanEvent } from \"../../hooks/use-pan-event\"\nimport { useI18n } from \"../../providers/i18n-provider\"\nimport {\n clampNumber,\n cx,\n dataAttr,\n handlerAll,\n isArray,\n isNumber,\n mergeRefs,\n percentToValue,\n roundNumberToStep,\n runKeyAction,\n valueToPercent,\n visuallyHiddenAttributes,\n} from \"../../utils\"\nimport { useFieldProps } from \"../field\"\n\nexport interface UseSliderProps<Y extends [number, number] | number = number>\n extends Omit<HTMLProps, \"defaultValue\" | \"onChange\" | \"ref\">,\n HTMLRefAttributes<\"input\">,\n FieldProps {\n /**\n * The base `id` to use for the slider.\n */\n id?: string\n /**\n * The name attribute of the hidden `input` field.\n * This is particularly useful in forms.\n */\n name?: string\n /**\n * The minimum distance between slider thumbs.\n * Useful for preventing the thumbs from being too close together.\n *\n * @default 0\n */\n betweenThumbs?: number\n /**\n * The initial value of the slider.\n */\n defaultValue?: Y\n /**\n * This is used to format the value so that screen readers\n * can speak out a more human-friendly value.\n *\n * It is used to set the `aria-valuetext` property of the input.\n */\n getAriaValueText?: (value: number, index: number) => string | undefined\n /**\n * The maximum allowed value of the slider. Cannot be less than min.\n *\n * @default 100\n */\n max?: number\n /**\n * The minimum allowed value of the slider. Cannot be greater than max.\n *\n * @default 0\n */\n min?: number\n /**\n * The orientation of the slider.\n *\n * @default 'horizontal'\n */\n orientation?: Orientation\n /**\n * The step in which increments or decrements have to be made.\n *\n * @default 1\n */\n step?: number\n /**\n * The value of the slider.\n */\n value?: Y\n /**\n * Function called whenever the slider value changes.\n */\n onChange?: (value: Y) => void\n /**\n * Function called when the user is done selecting a new value.\n */\n onChangeEnd?: (value: Y) => void\n /**\n * Function called when the user starts selecting a new value.\n */\n onChangeStart?: (value: Y) => void\n}\n\nexport const useSlider = <Y extends [number, number] | number = number>(\n props: UseSliderProps<Y> = {},\n) => {\n const {\n props: {\n id,\n ref,\n name,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-valuetext\": ariaValueText,\n betweenThumbs = 0,\n defaultValue = 0 as Y,\n disabled,\n getAriaValueText,\n max = 100,\n min = 0,\n orientation = \"horizontal\",\n readOnly,\n required,\n step = 1,\n value: valueProp,\n onChange: onChangeProp,\n onChangeEnd,\n onChangeStart,\n ...rest\n },\n ariaProps,\n dataProps,\n eventProps,\n } = useFieldProps(props)\n const [value, setValue] = useControllableState({\n defaultValue,\n value: valueProp,\n onChange: onChangeProp,\n })\n const { t } = useI18n(\"slider\")\n const currentIndex = useRef(0)\n const interactive = !(disabled || readOnly)\n const [_, getPanEventProps] = usePanEvent<HTMLDivElement>({\n onEnd: (_, point, rect) => {\n if (!interactive) return\n\n const panValue = getPanValue(point, rect)\n\n if (range) {\n const start = currentIndex.current === 0\n const oppositeIndex = currentIndex.current === 0 ? 1 : 0\n const oppositeValue = value[oppositeIndex]!\n\n onChangeEnd?.(\n (start ? [panValue, oppositeValue] : [oppositeValue, panValue]) as Y,\n )\n } else {\n onChangeEnd?.(panValue as Y)\n }\n },\n onMove: (_, point, rect) => {\n if (!interactive) return\n\n const panValue = getPanValue(point, rect)\n\n onChange(currentIndex.current, panValue)\n },\n onStart: (_, point, rect) => {\n if (!interactive) return\n\n const panValue = getPanValue(point, rect)\n\n if (range) {\n const distances = value.map((value) => Math.abs(value - panValue))\n const closest = Math.min(...distances)\n const index = distances.indexOf(closest)\n\n currentIndex.current = index\n\n const start = index === 0\n const oppositeIndex = index === 0 ? 1 : 0\n const oppositeValue = value[oppositeIndex]!\n\n onChangeStart?.(\n (start ? [panValue, oppositeValue] : [oppositeValue, panValue]) as Y,\n )\n } else {\n currentIndex.current = 0\n\n onChangeStart?.(value as Y)\n }\n\n onChange(currentIndex.current, panValue)\n },\n })\n const range = !isNumber(value)\n const percent = (\n range\n ? value.map((value) => valueToPercent(value, min, max))\n : valueToPercent(value, min, max)\n ) as Y extends number ? number : number[]\n const tenStep = (max - min) / 10\n const oneStep = step || (max - min) / 100\n\n if (max < min) console.warn(\"Do not assign a number less than 'min' to 'max'\")\n\n const getMinMax = useCallback(\n (index: number) => {\n const start = index === 0\n const oppositeIndex = index === 0 ? 1 : 0\n const oppositeValue = range ? value[oppositeIndex]! : value\n\n return {\n max: range ? (start ? oppositeValue - betweenThumbs : max) : max,\n min: range ? (start ? min : oppositeValue + betweenThumbs) : min,\n }\n },\n [betweenThumbs, max, min, range, value],\n )\n\n const getPanValue = useCallback(\n ({ x, y }: Point, { bottom, height, left, width }: DOMRect) => {\n const diff = orientation === \"horizontal\" ? x - left : bottom - y\n const length = orientation === \"horizontal\" ? width : height\n const percent = diff / length\n\n let nextValue = percentToValue(percent, min, max)\n\n nextValue = parseFloat(roundNumberToStep(nextValue, min, step))\n nextValue = clampNumber(nextValue, min, max)\n\n return nextValue\n },\n [orientation, min, max, step],\n )\n\n const onChange = useCallback(\n (index: number, value: number) => {\n if (!interactive) return\n\n const { max, min } = getMinMax(index)\n\n value = parseFloat(roundNumberToStep(value, min, oneStep))\n value = clampNumber(value, min, max)\n\n setValue((prev) => {\n if (isArray(prev)) {\n const next = [...prev]\n\n next[index] = value\n\n return next as Y\n } else {\n return value as Y\n }\n })\n },\n [getMinMax, interactive, oneStep, setValue],\n )\n\n const stepUp = useCallback(\n (index: number, step = oneStep) =>\n range\n ? onChange(index, value[index]! + step)\n : onChange(index, value + step),\n [oneStep, range, onChange, value],\n )\n\n const stepDown = useCallback(\n (index: number, step = oneStep) =>\n range\n ? onChange(index, value[index]! - step)\n : onChange(index, value - step),\n [oneStep, range, onChange, value],\n )\n\n const onKeyDown = useCallback(\n (index: number) => (ev: KeyboardEvent<HTMLDivElement>) => {\n const { max, min } = getMinMax(index)\n\n runKeyAction(ev, {\n ArrowDown: () => stepDown(index),\n ArrowLeft: () => stepDown(index),\n ArrowRight: () => stepUp(index),\n ArrowUp: () => stepUp(index),\n End: () => onChange(index, max),\n Home: () => onChange(index, min),\n PageDown: () => stepDown(index, tenStep),\n PageUp: () => stepUp(index, tenStep),\n })\n },\n [getMinMax, onChange, stepDown, stepUp, tenStep],\n )\n\n const getRootProps: PropGetter = useCallback(\n (props = {}) => {\n const computedProps: HTMLProps = {\n ...dataProps,\n \"data-orientation\": orientation,\n ...rest,\n ...props,\n onBlur: handlerAll(props.onBlur, eventProps.onBlur),\n onFocus: handlerAll(props.onFocus, eventProps.onFocus),\n }\n\n computedProps.style ??= {}\n\n if (isArray(percent)) {\n computedProps.style[\"--range-start\"] = `${Math.abs(percent[0]!)}%`\n computedProps.style[\"--range-end\"] = `${Math.abs(percent[1]!)}%`\n } else {\n computedProps.style[\"--range-start\"] = \"0%\"\n computedProps.style[\"--range-end\"] = `${Math.abs(percent)}%`\n }\n\n return computedProps\n },\n [dataProps, eventProps, orientation, percent, rest],\n )\n\n const getInputProps: PropGetter<\"input\", { index?: number }> = useCallback(\n ({ index = 0, ...props } = {}) => ({\n ...visuallyHiddenAttributes,\n ...dataProps,\n ...ariaProps,\n id,\n type: \"hidden\",\n name,\n disabled,\n readOnly,\n required,\n value: range ? value[index]! : value,\n ...props,\n ref: index === 0 ? mergeRefs(props.ref, ref) : props.ref,\n }),\n [\n dataProps,\n ariaProps,\n id,\n name,\n disabled,\n readOnly,\n required,\n range,\n value,\n ref,\n ],\n )\n\n const getTrackProps: PropGetter = useCallback(\n (props) =>\n getPanEventProps({\n ...dataProps,\n \"data-orientation\": orientation,\n ...props,\n }),\n [dataProps, getPanEventProps, orientation],\n )\n\n const getRangeProps: PropGetter = useCallback(\n (props) => ({\n ...dataProps,\n \"data-orientation\": orientation,\n \"data-range\": dataAttr(range),\n ...props,\n }),\n [dataProps, orientation, range],\n )\n\n const getMarkProps: RequiredPropGetter<\"div\", { value: number }> =\n useCallback(\n ({ style, value: valueProp, ...props }) => {\n const between = range\n ? value[0]! < valueProp && valueProp < value[1]!\n : valueProp < value\n const percent = valueToPercent(valueProp, min, max)\n\n return {\n ...dataProps,\n \"aria-hidden\": true,\n \"data-between\": dataAttr(between),\n \"data-orientation\": orientation,\n role: \"presentation\",\n ...props,\n style: { ...style, \"--mark-position\": `${percent}%` },\n }\n },\n [dataProps, max, min, orientation, range, value],\n )\n\n const getThumbProps: PropGetter<\"div\", { index?: number }> = useCallback(\n ({ index = 0, ...rest } = {}) => {\n const { max, min } = getMinMax(index)\n\n const props: HTMLProps = {\n ...dataProps,\n ...ariaProps,\n \"aria-label\": t(\"Slider thumb\"),\n \"aria-orientation\": orientation,\n \"aria-valuemax\": max,\n \"aria-valuemin\": min,\n role: \"slider\",\n tabIndex: interactive ? 0 : -1,\n ...rest,\n \"aria-labelledby\": cx(rest[\"aria-labelledby\"], ariaLabelledBy),\n onKeyDown: handlerAll(rest.onKeyDown, onKeyDown(index)),\n }\n\n if (range) {\n const currentValue = value[index]!\n\n props[\"data-start\"] = dataAttr(index === 0)\n props[\"data-end\"] = dataAttr(index === 1)\n props[\"aria-valuenow\"] = currentValue\n props[\"aria-valuetext\"] =\n ariaValueText ??\n getAriaValueText?.(currentValue, index) ??\n currentValue.toString()\n } else {\n props[\"data-end\"] = dataAttr(index === 0)\n props[\"aria-valuenow\"] = value\n props[\"aria-valuetext\"] =\n ariaValueText ?? getAriaValueText?.(value, index) ?? value.toString()\n }\n\n return props\n },\n [\n t,\n ariaLabelledBy,\n ariaProps,\n ariaValueText,\n dataProps,\n getAriaValueText,\n getMinMax,\n interactive,\n onKeyDown,\n orientation,\n range,\n value,\n ],\n )\n\n return {\n percent,\n range,\n setValue,\n stepDown,\n stepUp,\n value,\n getInputProps,\n getMarkProps,\n getRangeProps,\n getRootProps,\n getThumbProps,\n getTrackProps,\n onChange,\n }\n}\n\nexport type UseSliderReturn = ReturnType<typeof useSlider>\n"],"mappings":"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"}