todo/js/components/TodoTextInput.js (63 lines of code) (raw):

// @flow import * as React from 'react'; import {useEffect, useRef, useState} from 'react'; type Props = {| +className: string, +commitOnBlur?: boolean, +initialValue?: string, +onCancel?: () => void, +onDelete?: () => void, +onSave: (string) => void, +placeholder?: string, |}; const ENTER_KEY_CODE = 13; const ESC_KEY_CODE = 27; const TodoTextInput = ({ className, commitOnBlur, initialValue, onCancel, onDelete, onSave, placeholder, }: Props): React$Element<'input'> => { const [text, setText] = useState<string>(initialValue || ''); const inputRef = useRef(); useEffect(() => { if (inputRef.current) { inputRef.current.focus(); } }, [inputRef]); const commitChanges = () => { const newText = text.trim(); if (onDelete && newText === '') { onDelete(); } else if (onCancel && newText === initialValue) { onCancel(); } else if (newText !== '') { onSave(newText); setText(''); } }; const handleBlur = () => { if (commitOnBlur) { commitChanges(); } }; const handleChange = (e: SyntheticEvent<HTMLInputElement>) => setText(e.currentTarget.value); const handleKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) => { if (onCancel && e.keyCode === ESC_KEY_CODE) { onCancel(); } else if (e.keyCode === ENTER_KEY_CODE) { commitChanges(); } }; return ( <input className={className} onBlur={handleBlur} onChange={handleChange} onKeyDown={handleKeyDown} placeholder={placeholder} ref={inputRef} value={text} /> ); }; export default TodoTextInput;