import type { HTMLAttributes, KeyboardEvent } from "react"; import { forwardRef, useCallback } from "react"; import type { PropsWithRef } from "@react-md/utils"; import { DEFAULT_SLIDER_ANIMATION_TIME, DEFAULT_SLIDER_GET_VALUE_TEXT, } from "./constants"; import { SliderContainer } from "./SliderContainer"; import { SliderThumb } from "./SliderThumb"; import { SliderTrack } from "./SliderTrack"; import type { BaseSliderProps } from "./types"; import type { RangeSliderRequiredProps } from "./useRangeSlider"; import { useSliderControls } from "./useSliderControls"; /** * @remarks \@since 2.5.0 */ export interface RangeSliderProps extends RangeSliderRequiredProps, BaseSliderProps { /** * Any additional props you'd like to pass to the track element as well as an * optional `ref` if you need access to the track element for some reason. */ trackProps?: PropsWithRef, HTMLSpanElement>; /** * Any additional props you'd like to pass to the first thumb element as well * as an optional `ref` if you need access to the track element for some * reason. */ thumb1Props?: PropsWithRef, HTMLSpanElement>; /** * A convenience prop for adding an `aria-label` to the first thumb element. An * accessible label **must** be provided by this prop, the `thumb1LabelledBy` * prop, or adding an `aria-label`/`aria-labelledby` to the `thumb1Props` for * a11y. */ thumb1Label?: string; /** * A convenience prop for adding an `aria-labelledby` to the first thumb * element. An accessible label **must** be provided by this prop, the * `thumb1Label` prop, or adding an `aria-label`/`aria-labelledby` to the * `thumb1Props` for a11y. */ thumb1LabelledBy?: string; /** * Any additional props you'd like to pass to the second thumb element as well * as an optional `ref` if you need access to the track element for some * reason. */ thumb2Props?: PropsWithRef, HTMLSpanElement>; /** * A convenience prop for adding an `aria-label` to the second thumb element. * An accessible label **must** be provided by this prop, the * `thumb2LabelledBy` prop, or adding an `aria-label`/`aria-labelledby` to the * `thumb2Props` for a11y. */ thumb2Label?: string; /** * A convenience prop for adding an `aria-labelledby` to the second thumb * element. An accessible label **must** be provided by this prop, the * `thumb2Label` prop, or adding an `aria-label`/`aria-labelledby` to the * `thumb2Props` for a11y. */ thumb2LabelledBy?: string; } /** * The `RangeSlider` component allows the user to select a min and max value from * a predefined range of numbers. The functionality for controlling the value of * this component is provided by the `useRangeSlider` hook. * * @remarks \@since 2.5.0 */ export const RangeSlider = forwardRef( function RangeSlider( { baseId, min, max, step, discrete = false, disabled = false, vertical = false, label, labelProps, trackProps: propTrackProps, onBlur, onMouseDown, onTouchStart, getValueText = DEFAULT_SLIDER_GET_VALUE_TEXT, animationDuration = DEFAULT_SLIDER_ANIMATION_TIME, value, minimum, maximum, increment, incrementJump, decrement, decrementJump, persist, setValue, thumb1Props, thumb1Label = "Min", thumb1LabelledBy, thumb2Props, thumb2Label = "Max", thumb2LabelledBy, ...props }, ref ) { const { thumb1Ref, thumb1Value, thumb2Ref, thumb2Value, dragging, draggingIndex, onKeyDown, ...trackProps } = useSliderControls({ ref: propTrackProps?.ref, thumb1Ref: thumb1Props?.ref, thumb2Ref: thumb2Props?.ref, min, max, step, value, disabled, vertical, onBlur, onMouseDown, onTouchStart, animationDuration, minimum, maximum, increment, incrementJump, decrement, decrementJump, persist, setValue, }); const thumb1KeyDown = useCallback( (event: KeyboardEvent) => { if (thumb1Props?.onKeyDown) { thumb1Props.onKeyDown(event); } onKeyDown(event); }, [thumb1Props, onKeyDown] ); const thumb2KeyDown = useCallback( (event: KeyboardEvent) => { if (thumb2Props?.onKeyDown) { thumb2Props.onKeyDown(event); } onKeyDown(event); }, [thumb2Props, onKeyDown] ); const thumbProps = { baseId, min, max, discrete, disabled, vertical, animate: !dragging, animationDuration, getValueText, }; let labelId = ""; if (label) { labelId = labelProps?.id || `${baseId}-label`; } return ( ); } );