Switch from combobox to plaintextArea on click outside (#13333)

* switch back to plaintextArea on click outside

* add a test for click outside

* restore plainTextArea on blur, add cypress test
This commit is contained in:
Suzanne Aitchison 2021-04-14 09:15:26 +01:00 committed by GitHub
parent 25bf0e3950
commit 94bca23f07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 1 deletions

View file

@ -124,7 +124,12 @@ export const MentionAutocompleteTextArea = forwardRef(
const { setTextArea, setAdditionalElements } = useTextAreaAutoResize();
const { onChange, id: inputId, ...autocompleteInputProps } = inputProps;
const {
onChange,
onBlur,
id: inputId,
...autocompleteInputProps
} = inputProps;
useLayoutEffect(() => {
if (autoResize && comboboxRef.current && plainTextAreaRef.current) {
@ -180,6 +185,13 @@ export const MentionAutocompleteTextArea = forwardRef(
setSearchTerm('');
setAriaHelperText('');
setUsers([]);
const { selectionStart } = comboboxRef.current;
// Switch back to the plain text area
comboboxRef.current.classList.add('hidden');
plainTextAreaRef.current.classList.remove('hidden');
setCursorPosition(selectionStart + 1);
}
};
@ -270,6 +282,12 @@ export const MentionAutocompleteTextArea = forwardRef(
}
};
const handleComboboxBlur = () => {
// User has left the textarea, exit combobox functionality without refocusing plainTextArea
comboboxRef.current.classList.add('hidden');
plainTextAreaRef.current.classList.remove('hidden');
};
const handleSelect = (username) => {
// Construct the new textArea content with selected username inserted
const textWithSelection = `${textContent.substring(
@ -340,6 +358,10 @@ export const MentionAutocompleteTextArea = forwardRef(
onChange?.(e);
handleTextInputChange(e);
}}
onBlur={(e) => {
onBlur?.(e);
handleComboboxBlur();
}}
/>
<textarea

View file

@ -202,6 +202,63 @@ describe('Comment on articles', () => {
cy.findByText('@search_user_1').should('not.be.visible');
});
it('should close the autocomplete suggestions and exit combobox on click outside', () => {
cy.intercept(
{ method: 'GET', url: '/search/usernames' },
{ fixture: 'search/usernames.json' },
);
cy.findByLabelText(/^Add a comment to the discussion$/i).click();
// Get a handle to the newly substituted textbox
cy.findByRole('textbox', {
name: /^Add a comment to the discussion$/i,
}).as('plainTextArea');
cy.get('@plainTextArea').type('Some text @s');
// Verify the combobox has appeared
cy.findByRole('combobox', { name: /Add a comment to the discussion/ }).as(
'autocompleteCommentBox',
);
cy.get('@autocompleteCommentBox').type('earch');
cy.findByText('@search_user_1').should('be.visible');
// Click away from the dropdown
cy.get('@autocompleteCommentBox').click({ position: 'right' });
cy.findByText('@search_user_1').should('not.exist');
// Check the combobox has exited and we are returned to the plainTextArea
cy.get('@plainTextArea').should('have.focus');
});
it('should exit combobox when blurred and refocused', () => {
cy.intercept(
{ method: 'GET', url: '/search/usernames' },
{ fixture: 'search/usernames.json' },
);
cy.findByLabelText(/^Add a comment to the discussion$/i).click();
// Get a handle to the newly substituted textbox
cy.findByRole('textbox', {
name: /^Add a comment to the discussion$/i,
}).as('plainTextArea');
cy.get('@plainTextArea').type('Some text @s');
// Verify the combobox has appeared
cy.findByRole('combobox', {
name: /Add a comment to the discussion/,
}).as('combobox');
// Blur the currently active textarea, and check that the blur results in the plainTextArea being restored
cy.get('@combobox').blur();
cy.get('@combobox').should('not.be.visible');
cy.get('@plainTextArea').should('be.visible');
});
// TODO: Flaky spec
xit('should reply to a comment with user mention autocomplete', () => {
cy.intercept(