import { Component, createRef } from 'react'; import classNames from 'classnames'; import StarIcon from './star-icon'; import Star from './Star'; import { DisabledContext, IDisabledContext } from '../disabled'; export interface IRateProps { onChange?: (value: number) => void; value: number; allowClear?: boolean; allowHalf?: boolean; character?: React.ReactNode; className?: string; count: number; disabled?: boolean; style?: React.CSSProperties; readOnly?: boolean; } export interface IRateState { starRefs: Array>; cleanedValue: number | null; hoverValue: number | null; } function refArray(length: number): Array> { const refs = []; for (let i = 0; i < length; i += 1) { refs.push(createRef()); } return refs; } export class Rate extends Component { static defaultProps = { value: 0, count: 5, allowHalf: false, allowClear: true, character: , readOnly: false, }; static contextType = DisabledContext; context!: IDisabledContext; constructor(props: IRateProps) { super(props); this.state = { cleanedValue: null, hoverValue: null, starRefs: refArray(props.count), }; } onHover = (event: React.MouseEvent, index: number) => { const hoverValue = this.getStarValue(index, event.pageX); const { cleanedValue } = this.state; if (hoverValue !== cleanedValue) { this.setState({ hoverValue, cleanedValue: null, }); } }; onMouseLeave = () => { this.setState({ hoverValue: null, cleanedValue: null, }); }; onClick = (event: React.MouseEvent, index: number) => { const { onChange } = this.props; const value = this.getStarValue(index, event.pageX); let isReset = false; if (this.props.allowClear) { isReset = value === this.props.value; } this.onMouseLeave(); onChange && onChange(isReset ? 0 : value); this.setState({ cleanedValue: isReset ? value : null, }); }; getStarDOM(index: number) { const ref = this.state.starRefs[index]; if (!ref) { throw new Error( 'Missing Star Ref, this looks like a bug of zent, please file an issue' ); } const star = ref.current; if (!star) { throw new Error( 'Missing Star instance, this looks like a bug of zent, please file an issue' ); } const li = star.elRef.current; if (!li) { throw new Error( 'Missing Star element, this looks like a bug of zent, please file an issue' ); } return li; } getStarValue(index: number, x: number) { let value = index + 1; if (this.props.allowHalf) { const starEle = this.getStarDOM(index); const leftDis = starEle.getBoundingClientRect().left; const width = starEle.clientWidth; if (x - leftDis < width / 2) { value -= 0.5; } } return value; } static getDerivedStateFromProps( { count }: IRateProps, { starRefs }: IRateState ): Partial | null { if (count !== starRefs.length) { return { starRefs: refArray(count), }; } return null; } render() { const { count, allowHalf, style, disabled = this.context.value, className, character, value, readOnly, } = this.props; const { hoverValue, starRefs } = this.state; const stars = []; for (let index = 0; index < count; index++) { stars.push( ); } return (
    {stars}
); } } export default Rate;