Skip to content
Merged
20 changes: 19 additions & 1 deletion src-docs/src/views/inline_edit/inline_edit_text.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, KeyboardEvent } from 'react';

import {
EuiInlineEditText,
Expand Down Expand Up @@ -31,6 +31,19 @@ export default () => {
setToggleTextButtonSize(optionId);
};

const customKeyDown = (event: KeyboardEvent) => {
// if (event.key === 'Enter') {
// alert('Hey this is a custom keydown message!');
// } else {
// return;
// }
switch (event.key) {
case 'Enter':
alert('Hey this is a custom keydown message!');
break;
}
};

return (
<>
<EuiButtonGroup
Expand All @@ -48,6 +61,11 @@ export default () => {
inputAriaLabel="Edit text inline"
defaultValue="Hello World!"
size={toggleTextButtonSize}
editModeProps={{
inputProps: {
onKeyDown: customKeyDown,
},
}}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,22 @@ exports[`EuiInlineEditForm Edit Mode editModeProps.cancelButtonProps 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFieldText--fullWidth"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -169,15 +176,22 @@ exports[`EuiInlineEditForm Edit Mode editModeProps.formRowProps 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFieldText--fullWidth"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -307,23 +321,30 @@ exports[`EuiInlineEditForm Edit Mode editModeProps.inputProps 1`] = `
>
<label
class="euiFormLabel euiFormControlLayout__prepend"
for="generated-id"
for="__inlineEditInput_generated-id"
>
Prepend Example
</label>
<div
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFieldText--fullWidth euiFieldText--inGroup"
data-test-subj="customInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -455,15 +476,22 @@ exports[`EuiInlineEditForm Edit Mode editModeProps.saveButtonProps 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFieldText--fullWidth"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -595,11 +623,12 @@ exports[`EuiInlineEditForm Edit Mode isInvalid 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-invalid="true"
aria-label="Edit inline"
class="euiFieldText euiFormControlLayout--1icons euiFieldText--fullWidth"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
Expand All @@ -613,6 +642,12 @@ exports[`EuiInlineEditForm Edit Mode isInvalid 1`] = `
</div>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -744,10 +779,11 @@ exports[`EuiInlineEditForm Edit Mode isLoading 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFormControlLayout--1icons euiFieldText--fullWidth euiFieldText-isLoading"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
Expand All @@ -762,6 +798,12 @@ exports[`EuiInlineEditForm Edit Mode isLoading 1`] = `
</div>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down Expand Up @@ -847,15 +889,22 @@ exports[`EuiInlineEditForm Edit Mode renders 1`] = `
class="euiFormControlLayout__childrenWrapper"
>
<input
aria-describedby="inlineEdit_generated-id"
aria-label="Edit inline"
class="euiFieldText euiFieldText--fullWidth"
data-test-subj="euiInlineEditModeInput"
id="generated-id"
id="__inlineEditInput_generated-id"
type="text"
value="Hello World!"
/>
</div>
</div>
<span
hidden=""
id="inlineEdit_generated-id"
>
Press Enter to save your edited text. Press Escape to cancel your edit.
</span>
</div>
</div>
</div>
Expand Down
61 changes: 61 additions & 0 deletions src/components/inline_edit/inline_edit_form.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,66 @@ describe('EuiInlineEditForm', () => {
});
});
});

describe('keyboard events', () => {
test('pressing the Enter key saves text and returns to readMode', () => {
const { getByTestSubject, getByText } = render(
<EuiInlineEditForm
{...commonInlineEditFormProps}
startWithEditOpen={true}
/>
);

fireEvent.change(getByTestSubject('euiInlineEditModeInput'), {
target: { value: 'New message!' },
});
fireEvent.keyDown(getByTestSubject('euiInlineEditModeInput'), {
key: 'Enter',
});

expect(getByTestSubject('euiInlineReadModeButton')).toBeTruthy();
expect(getByText('New message!')).toBeTruthy();
});

test('pressing the Escape key cancels text changes and returns to readMode', () => {
const { getByTestSubject, getByText } = render(
<EuiInlineEditForm
{...commonInlineEditFormProps}
startWithEditOpen={true}
/>
);

fireEvent.change(getByTestSubject('euiInlineEditModeInput'), {
target: { value: 'New message!' },
});
fireEvent.keyDown(getByTestSubject('euiInlineEditModeInput'), {
key: 'Escape',
});

expect(getByTestSubject('euiInlineReadModeButton')).toBeTruthy();
expect(getByText('Hello World!')).toBeTruthy();
});

it('calls passed `inputModeProps.onKeyDown` callbacks', () => {
const onKeyDown = jest.fn();

const { getByTestSubject } = render(
<EuiInlineEditForm
{...commonInlineEditFormProps}
onSave={onSave}
startWithEditOpen={true}
editModeProps={{ inputProps: { onKeyDown } }}
/>
);

fireEvent.keyDown(getByTestSubject('euiInlineEditModeInput'), {
key: 'Enter',
});

// If a keyDown event is mapped to Enter/Escape, both the default and custom events should run
expect(onKeyDown).toHaveBeenCalled();
expect(onSave).toHaveBeenCalled();
});
});
});
});
62 changes: 46 additions & 16 deletions src/components/inline_edit/inline_edit_form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import React, {
useState,
HTMLAttributes,
MouseEvent,
KeyboardEvent,
} from 'react';
import classNames from 'classnames';

Expand All @@ -29,8 +30,8 @@ import { EuiButtonIconPropsForButton } from '../button/button_icon';
import { EuiButtonEmptyPropsForButton } from '../button/button_empty/button_empty';
import { EuiFlexGroup, EuiFlexItem } from '../flex';
import { EuiSkeletonRectangle } from '../skeleton';
import { useEuiTheme } from '../../services';
import { useEuiI18n } from '../i18n';
import { useEuiTheme, keys } from '../../services';
import { EuiI18n, useEuiI18n } from '../i18n';
import { useGeneratedHtmlId } from '../../services/accessibility';

// Props shared between the internal form component as well as consumer-facing components
Expand Down Expand Up @@ -139,6 +140,8 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
'Cancel edit'
);

const editModeDescribedById = useGeneratedHtmlId({ prefix: 'inlineEdit' });

const [isEditing, setIsEditing] = useState(false || startWithEditOpen);
const inlineEditInputId = useGeneratedHtmlId({ prefix: '__inlineEditInput' });

Expand All @@ -163,6 +166,17 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
setIsEditing(false);
};

const editModeInputOnKeyDown = (event: KeyboardEvent<HTMLElement>) => {
switch (event.key) {
case keys.ENTER:
saveInlineEditValue();
break;
case keys.ESCAPE:
cancelInlineEdit();
break;
}
};

const editModeForm = (
<EuiForm fullWidth>
<EuiFlexGroup gutterSize="s">
Expand All @@ -172,20 +186,36 @@ export const EuiInlineEditForm: FunctionComponent<EuiInlineEditFormProps> = ({
error={isInvalid && editModeProps?.formRowProps?.error}
{...editModeProps?.formRowProps}
>
<EuiFieldText
id={inlineEditInputId}
value={editModeValue}
onChange={(e) => {
setEditModeValue(e.target.value);
}}
aria-label={inputAriaLabel}
autoFocus
compressed={sizes.compressed}
isInvalid={isInvalid}
isLoading={isLoading}
data-test-subj="euiInlineEditModeInput"
{...editModeProps?.inputProps}
/>
<>
<EuiFieldText
id={inlineEditInputId}
value={editModeValue}
onChange={(e) => {
setEditModeValue(e.target.value);
}}
aria-label={inputAriaLabel}
autoFocus
compressed={sizes.compressed}
isInvalid={isInvalid}
isLoading={isLoading}
data-test-subj="euiInlineEditModeInput"
{...editModeProps?.inputProps}
aria-describedby={classNames(
editModeDescribedById,
editModeProps?.inputProps?.['aria-describedby']
)}
onKeyDown={(e: KeyboardEvent<HTMLInputElement>) => {
editModeInputOnKeyDown(e);
editModeProps?.inputProps?.onKeyDown?.(e);
}}
/>
<span id={editModeDescribedById} hidden>
<EuiI18n
token="euiInlineEditForm.inputKeyboardInstructions"
default="Press Enter to save your edited text. Press Escape to cancel your edit."
/>
</span>
</>
</EuiFormRow>
</EuiFlexItem>

Expand Down