import React, { useRef, useState, useImperativeHandle, forwardRef } from 'react' import type { AriaAttributes } from 'react' import { Price, Slider, InputField } from '../../' import type { PriceProps, SliderProps } from '../../' export interface PriceRangeProps extends Omit { /** * The current use case variant for prices. */ variant?: PriceProps['variant'] /** * Formatter function that transforms the raw price value and render the result. */ formatter: PriceProps['formatter'] /** * Defines a string value that labels the current element. */ 'aria-label'?: AriaAttributes['aria-label'] /** * Label for the minimum value input field. */ minLabel?: string /** * Label for the maximum value input field. */ maxLabel?: string /** * Error message for the minimum price input field. */ minPriceErrorMessage?: string /** * Error message for the maximum price input field. */ maxPriceErrorMessage?: string } type PriceRangeRefType = { setPriceRangeValues: (values: { min: number; max: number }) => void } const PriceRange = forwardRef( function PriceRange( { formatter, max, min, step = 1, onChange, onEnd, testId = 'fs-price-range', variant, 'aria-label': ariaLabel, minLabel = 'Min', maxLabel = 'Max', minPriceErrorMessage = "Min price can't be greater than max", maxPriceErrorMessage = "Max price can't be smaller than min", ...otherProps }, ref ) { const sliderRef = useRef<{ setSliderValues: (values: { min: number; max: number }) => void }>() useImperativeHandle(ref, () => ({ setPriceRangeValues: (values: { min: number; max: number }) => { onChange?.(values) sliderRef.current?.setSliderValues(values) }, })) const inputMinRef = useRef(null) const inputMaxRef = useRef(null) const [inputMinError, setInputMinError] = useState() const [inputMaxError, setInputMaxError] = useState() const [priceRange, setPriceRange] = useState<{ min: number; max: number }>({ min: Math.floor(min.selected), max: Math.round(max.selected), }) function onChangePriceRange(value: { min: number; max: number }) { setInputMinError(undefined) setInputMaxError(undefined) setPriceRange({ min: value.min, max: value.max }) if (inputMinRef.current?.value) { inputMinRef.current.value = String(value.min) } if (inputMaxRef.current?.value) { inputMaxRef.current.value = String(value.max) } } function onChangeInputMin(value: string) { setInputMinError(undefined) if (Number(value) < Math.floor(min.absolute)) { return } if (Number(value) > Math.floor(priceRange.max)) { setInputMinError(minPriceErrorMessage) } setPriceRange({ ...priceRange, min: Number(value) }) sliderRef.current?.setSliderValues({ ...priceRange, min: Number(value), }) } function onChangeInputMax(value: string) { setInputMaxError(undefined) if (Number(value) > Math.round(max.absolute)) { return } if (Number(value) < Math.round(priceRange.min)) { setInputMaxError(maxPriceErrorMessage) } setPriceRange({ ...priceRange, max: Number(value) }) sliderRef.current?.setSliderValues({ ...priceRange, max: Number(value), }) } return (
{ onEnd?.(value) onChangePriceRange(value) }} aria-label={ariaLabel} onChange={(value) => onChange?.(value)} absoluteValuesLabel={{ min: ( ), max: ( ), }} minValueLabelComponent={(minValue) => { return ( ) }} maxValueLabelComponent={(maxValue) => { return ( ) }} />
onChangeInputMin(e.target.value)} onBlur={() => !inputMinError && onEnd?.(priceRange)} /> onChangeInputMax(e.target.value)} onBlur={() => !inputMaxError && onEnd?.(priceRange)} />
) } ) export default PriceRange