UNPKG

zent

Version:

一套前端设计语言和基于React的实现

110 lines (98 loc) 3.83 kB
import { useContext, useState, useRef, useCallback, useEffect } from 'react'; import { IMECompositionContext } from './context'; export interface ICreateUseIMECompositionOption { getEventValue?: (...args: any[]) => string; } export interface IUseIMECompositionResult<OnChange> { value: string; onChange: OnChange; onCompositionStart: React.CompositionEventHandler; onCompositionEnd: React.CompositionEventHandler; } const defaultOption: Required<ICreateUseIMECompositionOption> = { getEventValue: e => e.target.value, }; type ElementType = HTMLInputElement | HTMLTextAreaElement; export function createUseIMEComposition( option?: ICreateUseIMECompositionOption ) { const { getEventValue } = { ...defaultOption, ...option }; return function useIMEComposition<OnChange extends (...args: any[]) => any>( propValue: string, onChangeProp?: OnChange, onCompositionStartProp?: React.CompositionEventHandler<ElementType>, onCompositionEndProp?: React.CompositionEventHandler<ElementType> ): IUseIMECompositionResult<OnChange> { const ctx = useContext(IMECompositionContext); const isCompositionRef = useRef(false); const [compositionValue, setCompositionValue] = useState(propValue); const onChangeRef = useRef(onChangeProp); const onCompositionStartRef = useRef(onCompositionStartProp); const onCompositionEndRef = useRef(onCompositionEndProp); useEffect(() => { onChangeRef.current = onChangeProp; onCompositionStartRef.current = onCompositionStartProp; onCompositionEndRef.current = onCompositionEndProp; }, [onChangeProp, onCompositionStartProp, onCompositionEndProp]); useEffect(() => { setCompositionValue(propValue); }, [propValue]); // eslint-disable-next-line react-hooks/exhaustive-deps const onCompositionValueChange = useCallback( ((...args) => { const targetValue = getEventValue(...args); // 若输入值没更新,则不触发上层组件的事件 if (targetValue === compositionValue) { return; } // 若输入法正在输入,则不触发上层组件的事件 if (isCompositionRef.current) { setCompositionValue(targetValue); return; } return onChangeRef.current?.(...args); }) as OnChange, [compositionValue, onChangeRef] ); const onCompositionStart: React.CompositionEventHandler<ElementType> = useCallback( e => { isCompositionRef.current = true; onCompositionStartRef.current?.(e); }, [onCompositionStartRef] ); const onCompositionEnd: React.CompositionEventHandler<ElementType> = useCallback( e => { isCompositionRef.current = false; onCompositionEndRef.current?.(e); const currentValue = e.currentTarget.value; setCompositionValue(currentValue); // 输入值更新时,手动触发 onChange 事件 if (currentValue !== propValue) { e.type = 'change'; onChangeRef.current?.(e); } }, [propValue, onCompositionEndRef, onChangeRef] ); // 只处理受控的组件 const isControlled = propValue !== undefined; const passCompositionHandler = isControlled && ctx.enable; const passCompositionValue = isControlled && ctx.enable && isCompositionRef.current; return { value: passCompositionValue ? compositionValue : propValue, onChange: passCompositionHandler ? onCompositionValueChange : onChangeProp, onCompositionStart: passCompositionHandler ? onCompositionStart : onCompositionStartProp, onCompositionEnd: passCompositionHandler ? onCompositionEnd : onCompositionEndProp, }; }; }