Adding `TextField` component (#16105)
* Adding TextField component * Fixing lint issues * More linting fixes * Adding more tests * Adding reference to TextFieldBase props * Adding reminder todo comment to styles * Using short hand syntax for conditionally firing event props and removing some css and unused classsNames in favor of box props * Fixing up my sloppy code * Removing text base docs update * More clean up * Adding more stories and docs * Adding new stories to mdx docsfeature/default_network_editable
parent
c88efadf1e
commit
da4e6d3e37
@ -1,9 +1,10 @@ |
|||||||
process.env.METAMASK_ENV = 'test'; |
process.env.METAMASK_ENV = 'test'; |
||||||
|
|
||||||
/** |
/** |
||||||
* Used for testing components that use the Icon component
|
* Used for testing components that use the Icon component |
||||||
* 'ui/components/component-library/icon/icon.js' |
* 'ui/components/component-library/icon/icon.js' |
||||||
*/ |
*/ |
||||||
process.env.ICON_NAMES = { |
process.env.ICON_NAMES = { |
||||||
LOADING_FILLED: 'loading-filled', |
LOADING_FILLED: 'loading-filled', |
||||||
|
CLOSE_OUTLINE: 'close-outline', |
||||||
}; |
}; |
||||||
|
@ -0,0 +1,73 @@ |
|||||||
|
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; |
||||||
|
|
||||||
|
import { TextField } from './text-field'; |
||||||
|
|
||||||
|
# TextField |
||||||
|
|
||||||
|
The `TextField` component lets users enter and edit text as well as adding a show clear button option. It wraps `TextFieldBase` and functions only as a controlled input. |
||||||
|
|
||||||
|
<Canvas> |
||||||
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--default-story" /> |
||||||
|
</Canvas> |
||||||
|
|
||||||
|
## Props |
||||||
|
|
||||||
|
The `TextField` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) and [TextFieldBase](/docs/ui-components-component-library-text-field-base-text-field-base-stories-js--default-story#props) component props |
||||||
|
|
||||||
|
<ArgsTable of={TextField} /> |
||||||
|
|
||||||
|
### Show Clear |
||||||
|
|
||||||
|
Use the `showClear` prop to display a clear button when `TextField` has a value. Clicking the button will clear the value. |
||||||
|
You can also attach an `onClear` handler to the `TextField` to perform additional actions when the clear button is clicked. |
||||||
|
|
||||||
|
<Canvas> |
||||||
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--show-clear" /> |
||||||
|
</Canvas> |
||||||
|
|
||||||
|
```jsx |
||||||
|
import { TextField } from '../../ui/component-library/text-field'; |
||||||
|
|
||||||
|
<TextField showClear />; |
||||||
|
``` |
||||||
|
|
||||||
|
### On Clear |
||||||
|
|
||||||
|
Use the `onClear` prop to perform additional actions when the clear button is clicked. |
||||||
|
|
||||||
|
<Canvas> |
||||||
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--on-clear" /> |
||||||
|
</Canvas> |
||||||
|
|
||||||
|
```jsx |
||||||
|
import { TextField } from '../../ui/component-library/text-field'; |
||||||
|
|
||||||
|
<TextField showClear onClear={() => console.log('cleared input')} />; |
||||||
|
``` |
||||||
|
|
||||||
|
### Clear Button Props and Clear Button Icon Props |
||||||
|
|
||||||
|
Use the `clearButtonProps` and `clearButtonIconProps` props to pass props to the clear button and clear button icon respectively. |
||||||
|
|
||||||
|
<Canvas> |
||||||
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--clear-button-props-clear-button-icon-props" /> |
||||||
|
</Canvas> |
||||||
|
|
||||||
|
```jsx |
||||||
|
import { |
||||||
|
SIZES, |
||||||
|
COLORS, |
||||||
|
BORDER_RADIUS, |
||||||
|
} from '../../../helpers/constants/design-system'; |
||||||
|
import { TextField } from '../../ui/component-library/text-field'; |
||||||
|
|
||||||
|
<TextField |
||||||
|
showClear |
||||||
|
clearButtonProps={{ |
||||||
|
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE, |
||||||
|
borderRadius: BORDER_RADIUS.XS, |
||||||
|
'data-testid': 'clear-button', |
||||||
|
}} |
||||||
|
clearButtonIconProps={{ size: SIZES.MD }} |
||||||
|
/>; |
||||||
|
``` |
@ -0,0 +1,2 @@ |
|||||||
|
export { TextField } from './text-field'; |
||||||
|
export { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants'; |
@ -0,0 +1,7 @@ |
|||||||
|
import { |
||||||
|
TEXT_FIELD_BASE_SIZES, |
||||||
|
TEXT_FIELD_BASE_TYPES, |
||||||
|
} from '../text-field-base/text-field-base.constants'; |
||||||
|
|
||||||
|
export const TEXT_FIELD_SIZES = TEXT_FIELD_BASE_SIZES; |
||||||
|
export const TEXT_FIELD_TYPES = TEXT_FIELD_BASE_TYPES; |
@ -0,0 +1,108 @@ |
|||||||
|
import React, { useState } from 'react'; |
||||||
|
import PropTypes from 'prop-types'; |
||||||
|
import classnames from 'classnames'; |
||||||
|
|
||||||
|
import { |
||||||
|
SIZES, |
||||||
|
DISPLAY, |
||||||
|
JUSTIFY_CONTENT, |
||||||
|
ALIGN_ITEMS, |
||||||
|
COLORS, |
||||||
|
} from '../../../helpers/constants/design-system'; |
||||||
|
|
||||||
|
import Box from '../../ui/box'; |
||||||
|
|
||||||
|
import { Icon, ICON_NAMES } from '../icon'; |
||||||
|
|
||||||
|
import { TextFieldBase } from '../text-field-base'; |
||||||
|
|
||||||
|
export const TextField = ({ |
||||||
|
className, |
||||||
|
showClear, |
||||||
|
clearButtonIconProps, |
||||||
|
clearButtonProps, |
||||||
|
rightAccessory, |
||||||
|
value: valueProp, |
||||||
|
onChange, |
||||||
|
onClear, |
||||||
|
inputProps, |
||||||
|
...props |
||||||
|
}) => { |
||||||
|
const [value, setValue] = useState(valueProp || ''); |
||||||
|
const handleOnChange = (e) => { |
||||||
|
setValue(e.target.value); |
||||||
|
onChange?.(e); |
||||||
|
}; |
||||||
|
const handleClear = (e) => { |
||||||
|
setValue(''); |
||||||
|
clearButtonProps?.onClick?.(e); |
||||||
|
onClear?.(e); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<TextFieldBase |
||||||
|
className={classnames('mm-text-field', className)} |
||||||
|
value={value} |
||||||
|
onChange={handleOnChange} |
||||||
|
rightAccessory={ |
||||||
|
value && showClear ? ( |
||||||
|
<> |
||||||
|
{/* replace with ButtonIcon */} |
||||||
|
<Box |
||||||
|
className="mm-text-field__button-clear" |
||||||
|
as="button" |
||||||
|
display={DISPLAY.FLEX} |
||||||
|
alignItems={ALIGN_ITEMS.CENTER} |
||||||
|
justifyContent={JUSTIFY_CONTENT.CENTER} |
||||||
|
backgroundColor={COLORS.TRANSPARENT} |
||||||
|
padding={0} |
||||||
|
{...clearButtonProps} // don't override onClick
|
||||||
|
onClick={handleClear} |
||||||
|
> |
||||||
|
<Icon |
||||||
|
name={ICON_NAMES.CLOSE_OUTLINE} |
||||||
|
size={SIZES.SM} |
||||||
|
aria-label="Clear" // TODO: i18n
|
||||||
|
{...clearButtonIconProps} |
||||||
|
/> |
||||||
|
</Box> |
||||||
|
{rightAccessory} |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
rightAccessory |
||||||
|
) |
||||||
|
} |
||||||
|
inputProps={{ |
||||||
|
marginRight: showClear ? 6 : 0, |
||||||
|
...inputProps, |
||||||
|
}} |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
TextField.propTypes = { |
||||||
|
/** |
||||||
|
* An additional className to apply to the text-field |
||||||
|
*/ |
||||||
|
className: PropTypes.string, |
||||||
|
/** |
||||||
|
* Show a clear button to clear the input |
||||||
|
*/ |
||||||
|
showClear: PropTypes.bool, |
||||||
|
/** |
||||||
|
* The event handler for when the clear button is clicked |
||||||
|
*/ |
||||||
|
onClear: PropTypes.func, |
||||||
|
/** |
||||||
|
* The props to pass to the clear button |
||||||
|
*/ |
||||||
|
clearButtonProps: PropTypes.shape(Box.PropTypes), |
||||||
|
/** |
||||||
|
* The props to pass to the icon inside of the close button |
||||||
|
*/ |
||||||
|
clearButtonIconProps: PropTypes.shape(Icon.PropTypes), |
||||||
|
/** |
||||||
|
* TextField accepts all the props from TextFieldBase and Box |
||||||
|
*/ |
||||||
|
...TextFieldBase.propTypes, |
||||||
|
}; |
@ -0,0 +1,10 @@ |
|||||||
|
.mm-text-field { |
||||||
|
// TOD: remove most of these styles when replaced by ButtonIcon |
||||||
|
&__button-clear { |
||||||
|
height: 24px; |
||||||
|
width: 24px; |
||||||
|
max-width: 24px; |
||||||
|
flex: 0 0 24px; |
||||||
|
margin-left: -24px; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,247 @@ |
|||||||
|
import React, { useState } from 'react'; |
||||||
|
|
||||||
|
import { |
||||||
|
SIZES, |
||||||
|
COLORS, |
||||||
|
BORDER_RADIUS, |
||||||
|
} from '../../../helpers/constants/design-system'; |
||||||
|
|
||||||
|
import { Text } from '../text'; |
||||||
|
|
||||||
|
import { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants'; |
||||||
|
import { TextField } from './text-field'; |
||||||
|
|
||||||
|
import README from './README.mdx'; |
||||||
|
|
||||||
|
const marginSizeControlOptions = [ |
||||||
|
undefined, |
||||||
|
0, |
||||||
|
1, |
||||||
|
2, |
||||||
|
3, |
||||||
|
4, |
||||||
|
5, |
||||||
|
6, |
||||||
|
7, |
||||||
|
8, |
||||||
|
9, |
||||||
|
10, |
||||||
|
11, |
||||||
|
12, |
||||||
|
'auto', |
||||||
|
]; |
||||||
|
|
||||||
|
export default { |
||||||
|
title: 'Components/ComponentLibrary/TextField', |
||||||
|
id: __filename, |
||||||
|
component: TextField, |
||||||
|
parameters: { |
||||||
|
docs: { |
||||||
|
page: README, |
||||||
|
}, |
||||||
|
}, |
||||||
|
argTypes: { |
||||||
|
showClear: { |
||||||
|
control: 'boolean', |
||||||
|
}, |
||||||
|
value: { |
||||||
|
control: 'text', |
||||||
|
}, |
||||||
|
onChange: { |
||||||
|
action: 'onChange', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onClear: { |
||||||
|
action: 'onClear', |
||||||
|
}, |
||||||
|
clearButtonIconProps: { |
||||||
|
control: 'object', |
||||||
|
}, |
||||||
|
clearButtonProps: { |
||||||
|
control: 'object', |
||||||
|
}, |
||||||
|
autoComplete: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
autoFocus: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
className: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
disabled: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
error: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
id: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
inputProps: { |
||||||
|
control: 'object', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
leftAccessory: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
maxLength: { |
||||||
|
control: 'number', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
name: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onBlur: { |
||||||
|
action: 'onBlur', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onClick: { |
||||||
|
action: 'onClick', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onFocus: { |
||||||
|
action: 'onFocus', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onKeyDown: { |
||||||
|
action: 'onKeyDown', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
onKeyUp: { |
||||||
|
action: 'onKeyUp', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
placeholder: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
readOnly: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
required: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
rightAccessory: { |
||||||
|
control: 'text', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
size: { |
||||||
|
control: 'select', |
||||||
|
options: Object.values(TEXT_FIELD_SIZES), |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
type: { |
||||||
|
control: 'select', |
||||||
|
options: Object.values(TEXT_FIELD_TYPES), |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
truncate: { |
||||||
|
control: 'boolean', |
||||||
|
table: { category: 'text field base props' }, |
||||||
|
}, |
||||||
|
marginTop: { |
||||||
|
options: marginSizeControlOptions, |
||||||
|
control: 'select', |
||||||
|
table: { category: 'box props' }, |
||||||
|
}, |
||||||
|
marginRight: { |
||||||
|
options: marginSizeControlOptions, |
||||||
|
control: 'select', |
||||||
|
table: { category: 'box props' }, |
||||||
|
}, |
||||||
|
marginBottom: { |
||||||
|
options: marginSizeControlOptions, |
||||||
|
control: 'select', |
||||||
|
table: { category: 'box props' }, |
||||||
|
}, |
||||||
|
marginLeft: { |
||||||
|
options: marginSizeControlOptions, |
||||||
|
control: 'select', |
||||||
|
table: { category: 'box props' }, |
||||||
|
}, |
||||||
|
}, |
||||||
|
args: { |
||||||
|
showClear: false, |
||||||
|
placeholder: 'Placeholder...', |
||||||
|
autoFocus: false, |
||||||
|
disabled: false, |
||||||
|
error: false, |
||||||
|
id: '', |
||||||
|
readOnly: false, |
||||||
|
required: false, |
||||||
|
size: SIZES.MD, |
||||||
|
type: 'text', |
||||||
|
truncate: false, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
const Template = (args) => <TextField {...args} />; |
||||||
|
|
||||||
|
export const DefaultStory = Template.bind({}); |
||||||
|
DefaultStory.storyName = 'Default'; |
||||||
|
|
||||||
|
export const ShowClear = (args) => { |
||||||
|
const [value, setValue] = useState('show clear'); |
||||||
|
const handleOnChange = (e) => { |
||||||
|
setValue(e.target.value); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<TextField |
||||||
|
{...args} |
||||||
|
placeholder="Enter text to show clear" |
||||||
|
value={value} |
||||||
|
onChange={handleOnChange} |
||||||
|
showClear |
||||||
|
/> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export const OnClear = (args) => { |
||||||
|
const [value, setValue] = useState('onClear example'); |
||||||
|
const [showOnClearMessage, setShowOnClearMessage] = useState(false); |
||||||
|
const handleOnChange = (e) => { |
||||||
|
setValue(e.target.value); |
||||||
|
showOnClearMessage && setShowOnClearMessage(false); |
||||||
|
}; |
||||||
|
const handleOnClear = () => { |
||||||
|
setShowOnClearMessage(true); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<TextField |
||||||
|
{...args} |
||||||
|
placeholder="Clear text to show onClear message" |
||||||
|
value={value} |
||||||
|
onChange={handleOnChange} |
||||||
|
onClear={handleOnClear} |
||||||
|
showClear |
||||||
|
/> |
||||||
|
{showOnClearMessage && <Text marginTop={4}>onClear called</Text>} |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export const ClearButtonPropsClearButtonIconProps = Template.bind({}); |
||||||
|
ClearButtonPropsClearButtonIconProps.args = { |
||||||
|
value: 'clear button props', |
||||||
|
size: SIZES.LG, |
||||||
|
showClear: true, |
||||||
|
clearButtonProps: { |
||||||
|
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE, |
||||||
|
borderRadius: BORDER_RADIUS.XS, |
||||||
|
}, |
||||||
|
clearButtonIconProps: { |
||||||
|
size: SIZES.MD, |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,161 @@ |
|||||||
|
/* eslint-disable jest/require-top-level-describe */ |
||||||
|
import React from 'react'; |
||||||
|
import { fireEvent, render } from '@testing-library/react'; |
||||||
|
|
||||||
|
import { TextField } from './text-field'; |
||||||
|
|
||||||
|
describe('TextField', () => { |
||||||
|
it('should render correctly', () => { |
||||||
|
const { getByRole } = render(<TextField />); |
||||||
|
expect(getByRole('textbox')).toBeDefined(); |
||||||
|
}); |
||||||
|
it('should render and be able to input text', () => { |
||||||
|
const { getByTestId } = render( |
||||||
|
<TextField inputProps={{ 'data-testid': 'text-field' }} />, |
||||||
|
); |
||||||
|
const textField = getByTestId('text-field'); |
||||||
|
|
||||||
|
expect(textField.value).toBe(''); // initial value is empty string
|
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
fireEvent.change(textField, { target: { value: '' } }); // reset value
|
||||||
|
expect(textField.value).toBe(''); // value is empty string after reset
|
||||||
|
}); |
||||||
|
it('should render and fire onFocus and onBlur events', () => { |
||||||
|
const onFocus = jest.fn(); |
||||||
|
const onBlur = jest.fn(); |
||||||
|
const { getByTestId } = render( |
||||||
|
<TextField |
||||||
|
inputProps={{ 'data-testid': 'text-field' }} |
||||||
|
onFocus={onFocus} |
||||||
|
onBlur={onBlur} |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByTestId('text-field'); |
||||||
|
|
||||||
|
fireEvent.focus(textField); |
||||||
|
expect(onFocus).toHaveBeenCalledTimes(1); |
||||||
|
fireEvent.blur(textField); |
||||||
|
expect(onBlur).toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
it('should render and fire onChange event', () => { |
||||||
|
const onChange = jest.fn(); |
||||||
|
const { getByTestId } = render( |
||||||
|
<TextField |
||||||
|
inputProps={{ 'data-testid': 'text-field' }} |
||||||
|
onChange={onChange} |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByTestId('text-field'); |
||||||
|
|
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(onChange).toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
it('should render and fire onClick event', () => { |
||||||
|
const onClick = jest.fn(); |
||||||
|
const { getByTestId } = render( |
||||||
|
<TextField |
||||||
|
inputProps={{ 'data-testid': 'text-field' }} |
||||||
|
onClick={onClick} |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByTestId('text-field'); |
||||||
|
|
||||||
|
fireEvent.click(textField); |
||||||
|
expect(onClick).toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
it('should render showClear button when showClear is true and value exists', () => { |
||||||
|
const { getByRole, getByTestId } = render( |
||||||
|
<TextField |
||||||
|
clearButtonProps={{ 'data-testid': 'clear-button' }} |
||||||
|
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }} |
||||||
|
showClear |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
expect(textField.value).toBe(''); // initial value is empty string
|
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
expect(getByTestId('clear-button')).toBeDefined(); |
||||||
|
expect(getByTestId('clear-button-icon')).toBeDefined(); |
||||||
|
}); |
||||||
|
it('should render with the rightAccessory', () => { |
||||||
|
const { getByText } = render( |
||||||
|
<TextField rightAccessory={<div>right-accessory</div>} />, |
||||||
|
); |
||||||
|
expect(getByText('right-accessory')).toBeDefined(); |
||||||
|
}); |
||||||
|
it('should still render with the rightAccessory when showClear is true', () => { |
||||||
|
const { getByRole, getByTestId, getByText } = render( |
||||||
|
<TextField |
||||||
|
clearButtonProps={{ 'data-testid': 'clear-button' }} |
||||||
|
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }} |
||||||
|
rightAccessory={<div>right-accessory</div>} |
||||||
|
showClear |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
expect(textField.value).toBe(''); // initial value is empty string
|
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
expect(getByTestId('clear-button')).toBeDefined(); |
||||||
|
expect(getByTestId('clear-button-icon')).toBeDefined(); |
||||||
|
expect(getByText('right-accessory')).toBeDefined(); |
||||||
|
}); |
||||||
|
it('should clear text when clear button is clicked', () => { |
||||||
|
const { getByRole, getByTestId } = render( |
||||||
|
<TextField |
||||||
|
clearButtonProps={{ 'data-testid': 'clear-button' }} |
||||||
|
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }} |
||||||
|
rightAccessory={<div>right-accessory</div>} |
||||||
|
showClear |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
fireEvent.click(getByTestId('clear-button')); |
||||||
|
expect(textField.value).toBe(''); |
||||||
|
}); |
||||||
|
it('should fire onClear event when passed to onClear prop', () => { |
||||||
|
const onClear = jest.fn(); |
||||||
|
const { getByRole, getByTestId } = render( |
||||||
|
<TextField |
||||||
|
onClear={onClear} |
||||||
|
clearButtonProps={{ 'data-testid': 'clear-button' }} |
||||||
|
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }} |
||||||
|
showClear |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
fireEvent.click(getByTestId('clear-button')); |
||||||
|
expect(onClear).toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
it('should fire clearButtonProps.onClick event when passed to clearButtonProps.onClick prop', () => { |
||||||
|
const onClear = jest.fn(); |
||||||
|
const onClick = jest.fn(); |
||||||
|
const { getByRole, getByTestId } = render( |
||||||
|
<TextField |
||||||
|
onClear={onClear} |
||||||
|
clearButtonProps={{ 'data-testid': 'clear-button', onClick }} |
||||||
|
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }} |
||||||
|
showClear |
||||||
|
/>, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
fireEvent.change(textField, { target: { value: 'text value' } }); |
||||||
|
expect(textField.value).toBe('text value'); |
||||||
|
fireEvent.click(getByTestId('clear-button')); |
||||||
|
expect(onClear).toHaveBeenCalledTimes(1); |
||||||
|
expect(onClick).toHaveBeenCalledTimes(1); |
||||||
|
}); |
||||||
|
it('should be able to accept inputProps', () => { |
||||||
|
const { getByRole } = render( |
||||||
|
<TextField inputProps={{ 'data-testid': 'text-field' }} />, |
||||||
|
); |
||||||
|
const textField = getByRole('textbox'); |
||||||
|
expect(textField).toBeDefined(); |
||||||
|
}); |
||||||
|
}); |
Loading…
Reference in new issue