diff --git a/components/typography/Editable.tsx b/components/typography/Editable.tsx index 9b5c16f845..3923ab698f 100644 --- a/components/typography/Editable.tsx +++ b/components/typography/Editable.tsx @@ -8,7 +8,7 @@ import { DirectionType } from '../config-provider'; interface EditableProps { prefixCls?: string; - value?: string; + value: string; ['aria-label']?: string; onSave: (value: string) => void; onCancel: () => void; @@ -19,142 +19,116 @@ interface EditableProps { autoSize?: boolean | AutoSizeType; } -interface EditableState { - current: string; - prevValue?: string; -} +const Editable: React.FC = ({ + prefixCls, + 'aria-label': ariaLabel, + className, + style, + direction, + maxLength, + autoSize, + value, + onSave, + onCancel, +}) => { + const ref = React.useRef(); -class Editable extends React.Component { - static getDerivedStateFromProps(nextProps: EditableProps, prevState: EditableState) { - const { prevValue } = prevState; - const { value } = nextProps; - const newState: Partial = { - prevValue: value, - }; + const inComposition = React.useRef(false); + const lastKeyCode = React.useRef(); - if (prevValue !== value) { - newState.current = value; - } + const [current, setCurrent] = React.useState(value); - return newState; - } + React.useEffect(() => { + setCurrent(value); + }, [value]); - textarea?: TextArea; - - lastKeyCode?: number; - - inComposition?: boolean = false; - - state = { - current: '', - }; - - componentDidMount() { - if (this.textarea && this.textarea.resizableTextArea) { - const { textArea } = this.textarea.resizableTextArea; + React.useEffect(() => { + if (ref.current && ref.current.resizableTextArea) { + const { textArea } = ref.current.resizableTextArea; textArea.focus(); const { length } = textArea.value; textArea.setSelectionRange(length, length); } - } + }, [ref.current]); - onChange: React.ChangeEventHandler = ({ target: { value } }) => { - this.setState({ current: value.replace(/[\n\r]/g, '') }); + const onChange: React.ChangeEventHandler = ({ target }) => { + setCurrent(target.value.replace(/[\n\r]/g, '')); }; - onCompositionStart = () => { - this.inComposition = true; + const onCompositionStart = () => { + inComposition.current = true; }; - onCompositionEnd = () => { - this.inComposition = false; + const onCompositionEnd = () => { + inComposition.current = false; }; - onKeyDown: React.KeyboardEventHandler = ({ keyCode }) => { + const onKeyDown: React.KeyboardEventHandler = ({ keyCode }) => { // We don't record keyCode when IME is using - if (this.inComposition) return; + if (inComposition.current) return; - this.lastKeyCode = keyCode; + lastKeyCode.current = keyCode; }; - onKeyUp: React.KeyboardEventHandler = ({ + const confirmChange = () => { + onSave(current.trim()); + }; + + const onKeyUp: React.KeyboardEventHandler = ({ keyCode, ctrlKey, altKey, metaKey, shiftKey, }) => { - const { onCancel } = this.props; // Check if it's a real key if ( - this.lastKeyCode === keyCode && - !this.inComposition && + lastKeyCode.current === keyCode && + !inComposition.current && !ctrlKey && !altKey && !metaKey && !shiftKey ) { if (keyCode === KeyCode.ENTER) { - this.confirmChange(); + confirmChange(); } else if (keyCode === KeyCode.ESC) { onCancel(); } } }; - onBlur: React.FocusEventHandler = () => { - this.confirmChange(); + const onBlur: React.FocusEventHandler = () => { + confirmChange(); }; - confirmChange = () => { - const { current } = this.state; - const { onSave } = this.props; + const textAreaClassName = classNames( + prefixCls, + `${prefixCls}-edit-content`, + { + [`${prefixCls}-rtl`]: direction === 'rtl', + }, + className, + ); - onSave(current.trim()); - }; - - setTextarea = (textarea: TextArea) => { - this.textarea = textarea; - }; - - render() { - const { current } = this.state; - const { - prefixCls, - 'aria-label': ariaLabel, - className, - style, - direction, - maxLength, - autoSize, - } = this.props; - const textAreaClassName = classNames( - prefixCls, - `${prefixCls}-edit-content`, - { - [`${prefixCls}-rtl`]: direction === 'rtl', - }, - className, - ); - return ( -
-