Skip to content

Commit

Permalink
[EuiTextArea] Add isClearable and icon props (#7449)
Browse files Browse the repository at this point in the history
Co-authored-by: Cee Chen <[email protected]>
  • Loading branch information
shahzad31 and cee-chen authored Jan 5, 2024
1 parent e41ca57 commit 02e14a4
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
1 change: 1 addition & 0 deletions changelogs/upcoming/7449.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Updated `EuiTextArea` to accept `isClearable` and `icon` as props
2 changes: 1 addition & 1 deletion src-docs/src/views/form_controls/text_area.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default () => {

return (
/* DisplayToggles wrapper for Docs only */
<DisplayToggles>
<DisplayToggles canClear>
<EuiTextArea
placeholder="Placeholder text"
aria-label="Use aria labels when no actual label is in use"
Expand Down
48 changes: 48 additions & 0 deletions src/components/form/text_area/text_area.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

/// <reference types="cypress" />
/// <reference types="cypress-real-events" />
/// <reference types="../../../../cypress/support" />

import React, { useState } from 'react';
import { EuiTextArea } from './text_area';

describe('EuiTextArea', () => {
describe('isClearable', () => {
it('works for uncontrolled components', () => {
cy.realMount(<EuiTextArea isClearable />);

cy.get('textarea').type('hello world');
cy.get('textarea').should('have.value', 'hello world');

cy.get('[data-test-subj="clearTextAreaButton"]').click();
cy.get('textarea').should('have.value', '');
});

it('works for controlled components', () => {
const ControlledTextArea = ({}) => {
const [value, setValue] = useState('');
return (
<EuiTextArea
value={value}
onChange={(e) => setValue(e.target.value)}
isClearable
/>
);
};
cy.realMount(<ControlledTextArea />);

cy.get('textarea').type('hello world');
cy.get('textarea').should('have.value', 'hello world');

cy.get('[data-test-subj="clearTextAreaButton"]').click();
cy.get('textarea').should('have.value', '');
});
});
});
46 changes: 43 additions & 3 deletions src/components/form/text_area/text_area.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,32 @@
* Side Public License, v 1.
*/

import React, { TextareaHTMLAttributes, Ref, FunctionComponent } from 'react';
import { CommonProps } from '../../common';
import React, {
TextareaHTMLAttributes,
Ref,
FunctionComponent,
useRef,
useMemo,
} from 'react';
import classNames from 'classnames';

import { CommonProps } from '../../common';
import { useCombinedRefs } from '../../../services';

import { EuiFormControlLayout } from '../form_control_layout';
import { EuiValidatableControl } from '../validatable_control';
import { useFormContext } from '../eui_form_context';
import { EuiFormControlLayoutIconsProps } from '../form_control_layout/form_control_layout_icons';

export type EuiTextAreaProps = TextareaHTMLAttributes<HTMLTextAreaElement> &
CommonProps & {
icon?: EuiFormControlLayoutIconsProps['icon'];
isLoading?: boolean;
isInvalid?: boolean;
/**
* Shows a button that allows users to quickly clear the textarea
*/
isClearable?: boolean;
/**
* Expand to fill 100% of the parent.
* Defaults to `fullWidth` prop of `<EuiForm>`.
Expand Down Expand Up @@ -52,9 +66,11 @@ export const EuiTextArea: FunctionComponent<EuiTextAreaProps> = (props) => {
compressed,
fullWidth = defaultFullWidth,
id,
icon,
inputRef,
isLoading,
isInvalid,
isClearable,
name,
placeholder,
resize = 'vertical',
Expand Down Expand Up @@ -82,11 +98,35 @@ export const EuiTextArea: FunctionComponent<EuiTextAreaProps> = (props) => {
definedRows = 6;
}

const ref = useRef<HTMLTextAreaElement | null>(null);
const refs = useCombinedRefs([ref, inputRef]);

const clear = useMemo(() => {
if (isClearable) {
return {
onClick: () => {
if (ref.current) {
ref.current.value = '';
const event = new Event('input', {
bubbles: true,
cancelable: false,
});
ref.current.dispatchEvent(event);
ref.current.focus(); // set focus back to the textarea
}
},
'data-test-subj': 'clearTextAreaButton',
};
}
}, [isClearable]);

return (
<EuiFormControlLayout
fullWidth={fullWidth}
isLoading={isLoading}
isInvalid={isInvalid}
clear={clear}
icon={icon}
className="euiFormControlLayout--euiTextArea"
>
<EuiValidatableControl isInvalid={isInvalid}>
Expand All @@ -96,7 +136,7 @@ export const EuiTextArea: FunctionComponent<EuiTextAreaProps> = (props) => {
rows={definedRows}
name={name}
id={id}
ref={inputRef}
ref={refs}
placeholder={placeholder}
>
{children}
Expand Down

0 comments on commit 02e14a4

Please sign in to comment.