1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Update TextFieldBase to include InputComponent prop (#16422)

* Update TextFieldBase to include InputComponent

* Updating docs

* Adding test

* Update to docs

* Lint fixes

* Small doc fixe to remove some unneded spaces
This commit is contained in:
George Marshall 2022-11-09 16:33:20 -08:00 committed by GitHub
parent ce9af8aac3
commit 67e0b60dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 166 additions and 5 deletions

View File

@ -188,6 +188,61 @@ const handleOnChange = (e) => {
</Box>
```
### Input Component
Use the `InputComponent` prop change the component used for the input element. This is useful for replacing the base input with a custom input while retaining the functionality of the `TextFieldBase`.
Defaults to the [Text](/docs/ui-components-component-library-text-text-stories-js--default-story) component
To function fully the custom component should accept the following props:
- `aria-invalid`
- `as`
- `autoComplete`
- `autoFocus`
- `backgroundColor`
- `defaultValue`
- `disabled`
- `focused`
- `id`
- `margin`
- `maxLength`
- `name`
- `onBlur`
- `onChange`
- `onFocus`
- `padding`
- `paddingLeft`
- `paddingRight`
- `placeholder`
- `readOnly`
- `ref`
- `required`
- `value`
- `variant`
- `type`
<Canvas>
<Story id="ui-components-component-library-text-field-base-text-field-base-stories-js--input-component" />
</Canvas>
```jsx
import { TextFieldBase, Icon, ICON_NAMES } from '../../ui/component-library';
// should map the props to the custom input component
const CustomInputComponent = () => <div>{/* Custom input component */}</div>;
const TextFieldCustomInput = (args) => (
<TextFieldBase
size={SIZES.LG}
InputComponent={CustomInputComponent}
leftAccessory={
<Icon color={COLORS.ICON_ALTERNATIVE} name={ICON_NAMES.WALLET_FILLED} />
}
/>
);
```
### Auto Complete
Use the `autoComplete` prop to set the autocomplete html attribute. It allows the browser to predict the value based on earlier typed values.

View File

@ -44,6 +44,7 @@ export const TextFieldBase = ({
type = 'text',
truncate = true,
value,
InputComponent = Text,
...props
}) => {
const internalInputRef = useRef(null);
@ -107,13 +108,13 @@ export const TextFieldBase = ({
alignItems={ALIGN_ITEMS.CENTER}
borderWidth={1}
borderRadius={SIZES.SM}
paddingLeft={4}
paddingRight={4}
paddingLeft={leftAccessory ? 4 : 0}
paddingRight={rightAccessory ? 4 : 0}
onClick={handleClick}
{...props}
>
{leftAccessory}
<Text
<InputComponent
aria-invalid={error}
as="input"
autoComplete={autoComplete ? 'on' : 'off'}
@ -130,8 +131,8 @@ export const TextFieldBase = ({
onChange={onChange}
onFocus={handleFocus}
padding={0}
paddingLeft={leftAccessory ? 2 : null}
paddingRight={leftAccessory ? 2 : null}
paddingLeft={leftAccessory ? 2 : 4}
paddingRight={rightAccessory ? 2 : 4}
placeholder={placeholder}
readOnly={readOnly}
ref={handleInputRef}
@ -179,6 +180,11 @@ TextFieldBase.propTypes = {
* The id of the `input` element.
*/
id: PropTypes.string,
/**
* The the component that is rendered as the input
* Defaults to the Text component
*/
InputComponent: PropTypes.elementType,
/**
* Attributes applied to the `input` element.
*/

View File

@ -351,6 +351,90 @@ export const InputRef = (args) => {
);
};
const CustomInputComponent = ({
as,
autoComplete,
autoFocus,
defaultValue,
disabled,
focused,
id,
maxLength,
name,
onBlur,
onChange,
onFocus,
padding,
paddingLeft,
paddingRight,
placeholder,
readOnly,
ref,
required,
value,
variant,
type,
className,
'aria-invalid': ariaInvalid,
...props
}) => {
return (
<Box
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.COLUMN}
{...{ padding, paddingLeft, paddingRight, ...props }}
>
<Box display={DISPLAY.INLINE_FLEX}>
<Text
style={{ padding: 0 }}
aria-invalid={ariaInvalid}
{...{
as,
className,
autoComplete,
autoFocus,
defaultValue,
disabled,
focused,
id,
maxLength,
name,
onBlur,
onChange,
onFocus,
placeholder,
readOnly,
ref,
required,
value,
variant,
type,
}}
/>
<Text variant={TEXT.BODY_XS} color={COLORS.TEXT_ALTERNATIVE}>
GoerliETH
</Text>
</Box>
<Text variant={TEXT.BODY_XS}>No conversion rate available</Text>
</Box>
);
};
CustomInputComponent.propTypes = { ...TextFieldBase.propTypes };
export const InputComponent = (args) => (
<TextFieldBase
{...args}
placeholder="0"
type="number"
size={SIZES.LG}
InputComponent={CustomInputComponent}
leftAccessory={
<Icon color={COLORS.ICON_ALTERNATIVE} name={ICON_NAMES.WALLET_FILLED} />
}
/>
);
export const AutoComplete = Template.bind({});
AutoComplete.args = {
autoComplete: true,

View File

@ -235,4 +235,20 @@ describe('TextFieldBase', () => {
'',
);
});
it('should render with a custom input and still work', () => {
const CustomInputComponent = (props) => <input {...props} />;
const { getByTestId } = render(
<TextFieldBase
InputComponent={CustomInputComponent}
inputProps={{ 'data-testid': 'text-field-base', className: 'test' }}
/>,
);
const textFieldBase = getByTestId('text-field-base');
expect(textFieldBase.value).toBe(''); // initial value is empty string
fireEvent.change(textFieldBase, { target: { value: 'text value' } });
expect(textFieldBase.value).toBe('text value');
fireEvent.change(textFieldBase, { target: { value: '' } }); // reset value
expect(textFieldBase.value).toBe(''); // value is empty string after reset
});
});