// @flow import React, { Fragment, useCallback, useRef, useState } from 'react'; import Button from '../Button'; import ButtonIcon from '../ButtonIcon'; import styles from './EditableValue.css'; type OverrideValueFn = (path: Array, value: any) => void; type EditableValueProps = {| dataType: string, overrideValueFn: OverrideValueFn, path: Array, value: any, |}; export default function EditableValue({ dataType, overrideValueFn, path, value, }: EditableValueProps) { const [hasPendingChanges, setHasPendingChanges] = useState(false); const [editableValue, setEditableValue] = useState(value); const inputRef = useRef(null); if (hasPendingChanges && editableValue === value) { setHasPendingChanges(false); } const handleChange = useCallback( ({ target }) => { if (dataType === 'boolean') { setEditableValue(target.checked); overrideValueFn(path, target.checked); } else if (dataType === 'number') { setEditableValue(parseFloat(target.value)); } else { setEditableValue(target.value); } setHasPendingChanges(true); }, [dataType, overrideValueFn, path] ); const handleReset = useCallback(() => { setEditableValue(value); setHasPendingChanges(false); if (inputRef.current !== null) { inputRef.current.focus(); } }, [value]); const handleKeyDown = useCallback( event => { // Prevent keydown events from e.g. change selected element in the tree event.stopPropagation(); const { key } = event; if (key === 'Enter') { overrideValueFn(path, editableValue); // Don't reset the pending change flag here. // The inspected fiber won't be updated until after the next "inspectElement" message. // We'll reset that flag during a subsequent render. } else if (key === 'Escape') { setEditableValue(value); setHasPendingChanges(false); } }, [path, editableValue, overrideValueFn, value] ); // Render different input types based on the dataType let type = 'text'; if (dataType === 'boolean') { type = 'checkbox'; } else if (dataType === 'number') { type = 'number'; } let inputValue = value == null ? '' : value; if (hasPendingChanges) { inputValue = editableValue == null ? '' : editableValue; } let placeholder = ''; if (value === null) { placeholder = '(null)'; } else if (value === undefined) { placeholder = '(undefined)'; } else if (dataType === 'string') { placeholder = '(string)'; } return ( {dataType === 'boolean' && ( )} {dataType !== 'boolean' && ( )} {hasPendingChanges && dataType !== 'boolean' && ( )} ); }