Files
MemoryBear/web/src/components/RbSlider/index.tsx
2026-04-17 11:11:54 +08:00

112 lines
3.0 KiB
TypeScript

/*
* @Author: ZhaoYing
* @Date: 2026-02-02 15:23:39
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-03-12 16:16:49
*/
/**
* RbSlider Component
*
* A custom slider component that extends Ant Design's Slider with:
* - Value display next to the slider
* - Value change callback for side effects
* - Fixed width and custom styling
*
* @component
*/
import { type FC, type ReactNode, useEffect, useState } from 'react';
import { Slider, type SliderSingleProps, Flex, InputNumber, type InputNumberProps } from 'antd';
/** Props interface for RbSlider component */
interface RbSliderProps extends SliderSingleProps {
/** Callback fired when value changes (for side effects) */
onValueChange?: (value: number | null | undefined) => void;
/** Callback fired when value changes (for side effects) */
onChange?: (value: SliderSingleProps['value']) => void;
isInput?: boolean;
size?: 'small' | 'default';
className?: string;
prefix?: string | ReactNode;
inputClassName?: string;
}
/** Custom slider component with value display */
const RbSlider: FC<RbSliderProps> = ({
value,
min = 0,
max,
onValueChange,
onChange,
step = 0.01,
size = 'default' ,
isInput = false,
className = '',
prefix,
inputClassName,
disabled,
...rest
}) => {
const [curValue, setCurValue] = useState<SliderSingleProps['value']>(0)
useEffect(() => {
setCurValue(value)
}, [value])
/** Listen to value changes and trigger side effects via onValueChange callback */
useEffect(() => {
if (onValueChange) {
onValueChange(curValue);
}
}, [curValue, onValueChange]);
const handleInputChange: InputNumberProps['onChange'] = (newValue) => {
onChange?.(newValue as number | undefined);
setCurValue(newValue as number | undefined)
};
const handleSliderChange: SliderSingleProps['onChange'] = (newValue) => {
onChange?.(newValue);
setCurValue(newValue)
};
return (
<Flex
align="center"
justify="space-between"
gap={12}
className={`rb:rounded-[5px] ${className}`}
>
{/* Slider with fixed width */}
<Slider
style={{
overflow: 'inherit',
width: '384px'
}}
{...rest}
min={min}
max={max}
step={step}
value={curValue}
disabled={disabled}
onChange={handleSliderChange}
classNames={size === 'small' ? {
rail: 'rb:w-[calc(100%-6px)]!'
} : undefined}
className={size === 'small' ? `${size} rb:flex-1` : undefined}
/>
{/* Display current value or minimum value */}
{isInput
? <InputNumber
min={min}
max={max}
step={step as number}
value={curValue}
disabled={disabled}
onChange={handleInputChange}
prefix={prefix}
className={`${inputClassName || '' } rb:w-20!`}
/>
: <div className="rb:text-[14px] rb:text-[#155EEF] rb:leading-5">{curValue || min}</div>
}
</Flex>
);
};
export default RbSlider;