import React, { useState, CSSProperties, ReactNode, useCallback, HTMLAttributes } from 'react' import RcSlider, { SliderProps as RcSliderProps } from 'rc-slider' import { usePrefix } from '../ConfigProvider' import SliderTooltip from './SliderTooltip' import { WithRef } from '../utils/type' export interface SliderProps { /** * 当前值 */ value?: number /** * 初始值 * @default 0 */ defaultValue?: number /** * 最小值 * @default 0 */ min?: number /** * 最大值 * @default 100 */ max?: number /** * 步长,取值必须大于 0,并且可被 (max - min) 整除 * @default 1 */ step?: number /** * 垂直方向 * @default false */ vertical?: boolean /** * 禁用 * @default false */ disabled?: boolean /** * 反向坐标轴 * @default false */ reverse?: boolean /** * Slider 把当前值传给 tipFormatter,并在 Tooltip 中显示 tipFormatter 的返回值。 * 若为 null,则隐藏 Tooltip */ tipFormatter?: null | ((value: number) => ReactNode) /** * 当 Slider 的值发生改变时触发,把改变后的值作为参数传入 */ onChange?: (value: number) => void /** * 与 onmouseup 触发时机一致,把当前值作为参数传入 */ onAfterChange?: (value: number) => void /** * 自定义样式名 */ className?: string /** * 自定义样式 */ style?: CSSProperties /** * 可拖动按钮的 html 属性 */ handleHtmlProps?: WithRef, HTMLDivElement> } export default function Slider(props: SliderProps) { const { tipFormatter, vertical, handleHtmlProps, onChange, onAfterChange, ...restProps } = props const prefix = usePrefix('slider') const [hovering, setHovering] = useState(false) const handleRender: RcSliderProps['handleRender'] = useCallback((origin, { value, dragging }) => { if (tipFormatter === null) { return React.cloneElement(origin, { ...origin.props, ...handleHtmlProps, style: { ...origin.props.style, ...handleHtmlProps?.style } }) } const tooltipVisible = hovering || dragging return ( { React.cloneElement(origin, { ...origin.props, ...handleHtmlProps, style: { ...origin.props.style, ...handleHtmlProps?.style }, onMouseEnter: (e: React.MouseEvent) => { setHovering(true) handleHtmlProps?.onMouseEnter?.(e) }, onMouseLeave: (e: React.MouseEvent) => { setHovering(false) handleHtmlProps?.onMouseLeave?.(e) } }) } ) }, [tipFormatter, hovering, vertical, handleHtmlProps]) // rc-slider 支持 Range 但我们不支持,这里只是为了通过类型检查 const handleChange = useCallback((v: number | number[]) => typeof v === 'number' && onChange?.(v), [onChange]) const handleAfterChange = useCallback((v: number | number[]) => typeof v === 'number' && onAfterChange?.(v), [onAfterChange]) return ( ) }