-
Notifications
You must be signed in to change notification settings - Fork 897
[WIP] [EuiInlineEdit] Allow EuiInlineEdit to be used as a controlled component
#7117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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<EuiInlineEditFormProps> = ({ | |||||||||
| children, | ||||||||||
| sizes, | ||||||||||
| defaultValue, | ||||||||||
| value, | ||||||||||
| onChange, | ||||||||||
| onCancel, | ||||||||||
| placeholder, | ||||||||||
| inputAriaLabel, | ||||||||||
| startWithEditOpen, | ||||||||||
|
|
@@ -168,8 +187,16 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({ | |||||||||
| ]); | ||||||||||
|
|
||||||||||
| 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); | ||||||||||
|
Comment on lines
+190
to
+191
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My 2c is I don't think we need to use
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is actually how I'm able to pass
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh super interesting! If readModeValue is the only one that needs this logic, let's set it just for that and add an inline comment noting why |
||||||||||
|
|
||||||||||
| const valueToUse = useMemo(() => { | ||||||||||
| if (value) { | ||||||||||
|
Comment on lines
+193
to
+194
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [naming things is hard] how do you feel about renaming the consumer-passed |
||||||||||
| return value; | ||||||||||
| } else { | ||||||||||
| return isEditing ? editModeValue : readModeValue || placeholder; | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still can't get over how elegant this ternary is haha. Super awesome! |
||||||||||
| } | ||||||||||
| }, [value, editModeValue, readModeValue, isEditing, placeholder]); | ||||||||||
|
|
||||||||||
| const readModeStyles = euiInlineEditReadModeStyles(euiTheme); | ||||||||||
| const readModeCssStyles = [ | ||||||||||
|
|
@@ -186,20 +213,21 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({ | |||||||||
|
|
||||||||||
| const cancelInlineEdit = () => { | ||||||||||
| setEditModeValue(readModeValue); | ||||||||||
| onCancel && onCancel(readModeValue); | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am using |
||||||||||
| setIsEditing(false); | ||||||||||
| requestAnimationFrame(() => readModeFocusRef.current?.focus()); | ||||||||||
| }; | ||||||||||
|
|
||||||||||
| 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); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll probably also want to test that |
||||||||||
| 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<EuiInlineEditFormProps> = ({ | |||||||||
| > | ||||||||||
| <EuiFieldText | ||||||||||
| fullWidth | ||||||||||
| value={editModeValue} | ||||||||||
| value={valueToUse} | ||||||||||
| aria-label={inputAriaLabel} | ||||||||||
| compressed={sizes.compressed} | ||||||||||
| isInvalid={isInvalid} | ||||||||||
|
|
@@ -245,6 +273,7 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({ | |||||||||
| inputRef={setEditModeRefs} | ||||||||||
| onChange={(e) => { | ||||||||||
| setEditModeValue(e.target.value); | ||||||||||
| onChange && onChange(e); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. quick nit while I'm here: |
||||||||||
| editModeProps?.inputProps?.onChange?.(e); | ||||||||||
| }} | ||||||||||
| onKeyDown={(e) => { | ||||||||||
|
|
@@ -333,7 +362,7 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({ | |||||||||
| 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<EuiInlineEditFormProps> = ({ | |||||||||
| readModeProps?.onClick?.(e); | ||||||||||
| }} | ||||||||||
| > | ||||||||||
| {children(readModeValue || placeholder)} | ||||||||||
| {children(valueToUse)} | ||||||||||
| </EuiButtonEmpty> | ||||||||||
| <span id={readModeDescribedById} hidden> | ||||||||||
| {!isReadOnly && ( | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌💋 B-E-A-utiful developer experience!