Skip to content

Commit

Permalink
Adding TextFieldSearch component (#16296)
Browse files Browse the repository at this point in the history
* Adding TextFieldSearch component

* Updating docs and stories

* Moving controlled test into testing utils

* Fixing spelling in prop types af => of
  • Loading branch information
georgewrmarshall authored Nov 15, 2022
1 parent 0a5c46b commit 6907c4a
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 31 deletions.
17 changes: 16 additions & 1 deletion test/lib/render-helpers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useMemo } from 'react';
import React, { useMemo, useState } from 'react';
import { Provider } from 'react-redux';
import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { mount, shallow } from 'enzyme';
import { Router, MemoryRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
Expand Down Expand Up @@ -122,3 +123,17 @@ export function renderWithLocalization(component) {

return render(component, { wrapper: Wrapper });
}

export function renderControlledInput(InputComponent, props) {
const ControlledWrapper = () => {
const [value, setValue] = useState('');
return (
<InputComponent
value={value}
onChange={(e) => setValue(e.target.value)}
{...props}
/>
);
};
return { user: userEvent.setup(), ...render(<ControlledWrapper />) };
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
@import 'text/text';
@import 'text-field/text-field';
@import 'text-field-base/text-field-base';
@import 'text-field-search/text-field-search';
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export const TEXT_FIELD_BASE_TYPES = {
TEXT: 'text',
NUMBER: 'number',
PASSWORD: 'password',
SEARCH: 'search',
};
92 changes: 92 additions & 0 deletions ui/components/component-library/text-field-search/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';

import { TextFieldSearch } from './text-field-search';

# TextFieldSearch

The `TextFieldSearch` allows users to enter text to search. It wraps the `TextField` component that adds a search icon to the left of the input.

<Canvas>
<Story id="ui-components-component-library-text-field-search-text-field-search-stories-js--default-story" />
</Canvas>

## Props

The `TextFieldSearch` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props), [TextField](/docs/ui-components-component-library-text-field-text-field-stories-js--default-story#props) component props

<ArgsTable of={TextFieldSearch} />

### Show Clear Button

Use the `showClearButton` prop to display a clear button when `TextFieldSearch` has a value. Use the `clearButtonOnClick` prop to pass an `onClick` event handler to clear the value of the input.

Defaults to `true`

The clear button uses [ButtonIcon](/docs/ui-components-component-library-button-icon-button-icon-stories-js--default-story) and accepts all props from that component.

**NOTE: The `showClearButton` only works with a controlled input.**

<Canvas>
<Story id="ui-components-component-library-text-field-search-text-field-search-stories-js--show-clear-button" />
</Canvas>

```jsx
import { TextFieldSearch } from '../../ui/component-library/text-field';

const [value, setValue] = useState('show clear');

const handleOnChange = (e) => {
setValue(e.target.value);
};

const handleOnClear = () => {
setValue('');
};

<TextFieldSearch
placeholder="Enter text to show clear"
value={value}
onChange={handleOnChange}
clearButtonOnClick={handleOnClear}
/>;
```

### Clear Button Props

Use the `clearButtonProps` to access other props of the clear button.

<Canvas>
<Story id="ui-components-component-library-text-field-search-text-field-search-stories-js--clear-button-props" />
</Canvas>

```jsx
import React, { useState } from 'react';
import {
SIZES,
COLORS,
BORDER_RADIUS,
} from '../../../helpers/constants/design-system';

import { TextFieldSearch } from '../../ui/component-library/text-field';

const [value, setValue] = useState('show clear');

const handleOnChange = (e) => {
setValue(e.target.value);
};

const handleOnClear = () => {
setValue('');
};

<TextFieldSearch
value={value}
onChange={handleOnChange}
clearButtonOnClick={handleOnClear}
clearButtonProps={{
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
borderRadius: BORDER_RADIUS.XS,
'data-testid': 'clear-button',
}}
/>;
```
1 change: 1 addition & 0 deletions ui/components/component-library/text-field-search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TextFieldSearch } from './text-field-search';
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';

import { SIZES } from '../../../helpers/constants/design-system';

import { ButtonIcon } from '../button-icon';
import { Icon, ICON_NAMES } from '../icon';
import { TextFieldBase, TEXT_FIELD_BASE_TYPES } from '../text-field-base';
import { TextField } from '../text-field';

export const TextFieldSearch = ({
value,
onChange,
showClearButton = true,
clearButtonOnClick,
clearButtonProps,
className,
...props
}) => (
<TextField
className={classnames('mm-text-field-search', className)}
value={value}
onChange={onChange}
type={TEXT_FIELD_BASE_TYPES.SEARCH}
leftAccessory={<Icon name={ICON_NAMES.SEARCH_FILLED} size={SIZES.SM} />}
showClearButton={showClearButton}
clearButtonOnClick={clearButtonOnClick}
clearButtonProps={clearButtonProps}
{...props}
/>
);

TextFieldSearch.propTypes = {
/**
* The value of the TextFieldSearch
*/
value: TextFieldBase.propTypes.value,
/**
* The onChange handler of the TextFieldSearch
*/
onChange: TextFieldBase.propTypes.onChange,
/**
* Show a clear button to clear the input
* Defaults to true
*/
showClearButton: PropTypes.bool,
/**
* The onClick handler for the clear button
*/
clearButtonOnClick: PropTypes.func,
/**
* The props to pass to the clear button
*/
clearButtonProps: PropTypes.shape(ButtonIcon.PropTypes),
/**
* An additional className to apply to the TextFieldSearch
*/
className: PropTypes.string,
};

TextFieldSearch.displayName = 'TextFieldSearch';
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.mm-text-field-search {
::-webkit-search-cancel-button {
display: none; // hides the default search cancel button
}
}
Loading

0 comments on commit 6907c4a

Please sign in to comment.