diff --git a/src-docs/src/views/inline_edit/inline_edit_title.tsx b/src-docs/src/views/inline_edit/inline_edit_title.tsx index addf74b1fd65..f970278d60e3 100644 --- a/src-docs/src/views/inline_edit/inline_edit_title.tsx +++ b/src-docs/src/views/inline_edit/inline_edit_title.tsx @@ -42,6 +42,8 @@ export default () => { setToggleTitleButtonSize(optionId); }; + const [inlineEditValue, setInlineEditValue] = useState('hello world'); + return ( <> { inputAriaLabel="Edit title inline" defaultValue="Hello World (but as a title)!" /> + + + + { + setInlineEditValue(e.target.value); + }} + onCancel={(previousValue) => { + setInlineEditValue(previousValue); + }} + /> ); }; diff --git a/src/components/inline_edit/inline_edit_form.tsx b/src/components/inline_edit/inline_edit_form.tsx index 347633f79344..ba387ca4d05a 100644 --- a/src/components/inline_edit/inline_edit_form.tsx +++ b/src/components/inline_edit/inline_edit_form.tsx @@ -12,13 +12,14 @@ import React, { useState, useRef, useEffect, + useMemo, HTMLAttributes, MouseEvent, KeyboardEvent, } from 'react'; import classNames from 'classnames'; -import { CommonProps } from '../common'; +import { CommonProps, ExclusiveUnion } from '../common'; import { EuiFormRow, EuiFormRowProps, @@ -42,7 +43,6 @@ export type EuiInlineEditCommonProps = Omit< 'children' > & CommonProps & { - defaultValue: string; placeholder?: string; /** * Callback that fires when a user clicks the save button. @@ -90,7 +90,23 @@ export type EuiInlineEditCommonProps = Omit< * Locks inline edit in read mode and displays the text value */ isReadOnly?: boolean; - }; + } & ExclusiveUnion< + { + /** + * Initial inline edit text value + */ + defaultValue: string; + }, + { + /** + * To use inline edit as a controlled component, continuously pass the value via this prop + */ + value: string; + // TODO: Update to an HTML Change Event + onChange: (event: any) => void; + onCancel: (perviousValue: string) => void; + } + >; // Internal-only props, passed by the consumer-facing components export type EuiInlineEditFormProps = EuiInlineEditCommonProps & { @@ -125,6 +141,9 @@ export const EuiInlineEditForm: FunctionComponent = ({ children, sizes, defaultValue, + value, + onChange, + onCancel, placeholder, inputAriaLabel, startWithEditOpen, @@ -168,8 +187,16 @@ export const EuiInlineEditForm: FunctionComponent = ({ ]); const [isEditing, setIsEditing] = useState(false || startWithEditOpen); - const [editModeValue, setEditModeValue] = useState(defaultValue); - const [readModeValue, setReadModeValue] = useState(defaultValue); + const [editModeValue, setEditModeValue] = useState(value || defaultValue); + const [readModeValue, setReadModeValue] = useState(value || defaultValue); + + const valueToUse = useMemo(() => { + if (value) { + return value; + } else { + return isEditing ? editModeValue : readModeValue || placeholder; + } + }, [value, editModeValue, readModeValue, isEditing, placeholder]); const readModeStyles = euiInlineEditReadModeStyles(euiTheme); const readModeCssStyles = [ @@ -186,6 +213,7 @@ export const EuiInlineEditForm: FunctionComponent = ({ const cancelInlineEdit = () => { setEditModeValue(readModeValue); + onCancel && onCancel(readModeValue); setIsEditing(false); requestAnimationFrame(() => readModeFocusRef.current?.focus()); }; @@ -193,13 +221,13 @@ export const EuiInlineEditForm: FunctionComponent = ({ const saveInlineEditValue = async () => { // If an onSave callback is present, and returns false, stay in edit mode if (onSave) { - const onSaveReturn = onSave(editModeValue); + const onSaveReturn = onSave(valueToUse); const awaitedReturn = onSaveReturn instanceof Promise ? await onSaveReturn : onSaveReturn; if (awaitedReturn === false) return; } - setReadModeValue(editModeValue); + setReadModeValue(valueToUse); setIsEditing(false); requestAnimationFrame(() => readModeFocusRef.current?.focus()); }; @@ -234,7 +262,7 @@ export const EuiInlineEditForm: FunctionComponent = ({ > = ({ inputRef={setEditModeRefs} onChange={(e) => { setEditModeValue(e.target.value); + onChange && onChange(e); editModeProps?.inputProps?.onChange?.(e); }} onKeyDown={(e) => { @@ -333,7 +362,7 @@ export const EuiInlineEditForm: FunctionComponent = ({ data-test-subj="euiInlineReadModeButton" disabled={isReadOnly} css={readModeCssStyles} - title={readModeValue || placeholder} + title={valueToUse} {...readModeProps} buttonRef={setReadModeRefs} aria-describedby={classNames( @@ -345,7 +374,7 @@ export const EuiInlineEditForm: FunctionComponent = ({ readModeProps?.onClick?.(e); }} > - {children(readModeValue || placeholder)} + {children(valueToUse)}