[WIP] [EuiInlineEdit] Allow EuiInlineEdit to be used as a controlled component#7117
[WIP] [EuiInlineEdit] Allow EuiInlineEdit to be used as a controlled component#7117breehall wants to merge 3 commits intoelastic:mainfrom
EuiInlineEdit to be used as a controlled component#7117Conversation
…as a controlled component. - Added the value and onChange props to be used when inline edit is a controlled component - Separated defaultValue and controlled props (value & onChange) into an exclusive union to ensure inline edit cannot be used in both states at once
- Add the onCancel callback prop to allow consumers to fallback to the previous inline edit value upon cancel - Create a DRY helper to switch between readModeValue, editModeValue, and value appropriately
💔 Build Failed
Failed CI StepsHistory |
|
|
||
| const cancelInlineEdit = () => { | ||
| setEditModeValue(readModeValue); | ||
| onCancel && onCancel(readModeValue); |
There was a problem hiding this comment.
I am using readModeValue instead of valueToUse here because is contains the prior text value
|
Preview documentation changes for this PR: https://eui.elastic.co/pr_7117/ |
| value={inlineEditValue} | ||
| onChange={(e) => { | ||
| setInlineEditValue(e.target.value); | ||
| }} | ||
| onCancel={(previousValue) => { | ||
| setInlineEditValue(previousValue); | ||
| }} |
There was a problem hiding this comment.
👌💋 B-E-A-utiful developer experience!
| // If an onSave callback is present, and returns false, stay in edit mode | ||
| if (onSave) { | ||
| const onSaveReturn = onSave(editModeValue); | ||
| const onSaveReturn = onSave(valueToUse); |
There was a problem hiding this comment.
We'll probably also want to test that onSave works with a controlled value as well. How you prefer to test that is up to you; whether via docs, Jest test, or Storybook
| const [editModeValue, setEditModeValue] = useState(value || defaultValue); | ||
| const [readModeValue, setReadModeValue] = useState(value || defaultValue); |
There was a problem hiding this comment.
My 2c is I don't think we need to use value || here for our internal state. Since they're only used for uncontrolled behavior, they only need to listen for defaultValue.
| const [editModeValue, setEditModeValue] = useState(value || defaultValue); | |
| const [readModeValue, setReadModeValue] = useState(value || defaultValue); | |
| const [editModeValue, setEditModeValue] = useState(defaultValue); | |
| const [readModeValue, setReadModeValue] = useState(defaultValue); |
There was a problem hiding this comment.
This logic is actually how I'm able to pass readModeValue to the onCancel function. Otherwise, the readModeValue falls out of sync and isn't a reliable backup of the previous value.
Link to code sample mentioned: #7117 (comment)
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
[naming things is hard] how do you feel about renaming the consumer-passed value prop to value: controlledValue or possibly just _value, and then just naming this value?
| if (value) { | ||
| return value; | ||
| } else { | ||
| return isEditing ? editModeValue : readModeValue || placeholder; |
There was a problem hiding this comment.
I still can't get over how elegant this ternary is haha. Super awesome!
| inputRef={setEditModeRefs} | ||
| onChange={(e) => { | ||
| setEditModeValue(e.target.value); | ||
| onChange && onChange(e); |
There was a problem hiding this comment.
quick nit while I'm here: onChange?.(e) for brevity
|
Closing this PR in favor #7157 |
🛑 WIP - DO NOT MERGE
#7084
Summary
Allows
EuiInlineEditto be used as a controlled component with the addition of three new propsMore to come (this is a WIP)
Feature Checklist
QA
Remove or strikethrough items that do not apply to your PR.
General checklist
@defaultif default values are missing) and playground toggles