mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Adding Input component and updating TextFieldBase (#17664)
* Adding Input component and updating TextField * Exporting from index, removing as prop and updating snapshot
This commit is contained in:
parent
1b382e9f2d
commit
527387bbfe
@ -20,6 +20,7 @@
|
||||
@import 'button-link/button-link';
|
||||
@import 'button-primary/button-primary';
|
||||
@import 'button-secondary/button-secondary';
|
||||
@import 'input/input';
|
||||
// Molecules
|
||||
@import 'picker-network/picker-network';
|
||||
@import 'tag-url/tag-url';
|
||||
|
@ -10,7 +10,7 @@ exports[`FormTextField should render correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="box mm-text mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent"
|
||||
class="box mm-text mm-input mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent box--border-style-none"
|
||||
focused="false"
|
||||
type="text"
|
||||
value=""
|
||||
|
@ -27,6 +27,7 @@ export { PickerNetwork } from './picker-network';
|
||||
export { Tag } from './tag';
|
||||
export { TagUrl } from './tag-url';
|
||||
export { Text, TEXT_DIRECTIONS } from './text';
|
||||
export { Input, INPUT_TYPES } from './input';
|
||||
export { TextField, TEXT_FIELD_TYPES, TEXT_FIELD_SIZES } from './text-field';
|
||||
export { TextFieldSearch } from './text-field-search';
|
||||
|
||||
|
270
ui/components/component-library/input/README.mdx
Normal file
270
ui/components/component-library/input/README.mdx
Normal file
@ -0,0 +1,270 @@
|
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||
|
||||
import { Input } from './input';
|
||||
|
||||
# Input
|
||||
|
||||
`Input` lets user enter a text data. It’s a light-weighted borderless input used inside of custom inputs. See [TextField](/docs/components-componentlibrary-textfield--default-story#textfield) for common text input.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--default-story" />
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
The `Input` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props
|
||||
|
||||
<ArgsTable of={Input} />
|
||||
|
||||
### Type
|
||||
|
||||
Use the `type` prop to change the type of input.
|
||||
|
||||
Possible types include:
|
||||
|
||||
- `INPUT_TYPES.TEXT`
|
||||
- `INPUT_TYPES.NUMBER`
|
||||
- `INPUT_TYPES.PASSWORD`
|
||||
- `INPUT_TYPES.SEARCH`
|
||||
|
||||
Defaults to `INPUT_TYPES.TEXT`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--type" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input, INPUT_TYPES } from '../../component-library';
|
||||
|
||||
<Input type={INPUT_TYPES.TEXT} />
|
||||
<Input type={INPUT_TYPES.NUMBER} />
|
||||
<Input type={INPUT_TYPES.PASSWORD} />
|
||||
<Input type={INPUT_TYPES.SEARCH} />
|
||||
```
|
||||
|
||||
### Ref
|
||||
|
||||
Use the `ref` prop to access the ref of the `<input />` html element of `Input`. This is useful for focusing the input from a button or other component.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--ref" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Button, Input } from '../../component-library';
|
||||
|
||||
const inputRef = useRef(null);
|
||||
const [value, setValue] = useState('');
|
||||
const handleOnClick = () => {
|
||||
inputRef.current.focus();
|
||||
};
|
||||
const handleOnChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
};
|
||||
|
||||
<Input
|
||||
ref={inputRef}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<Button marginLeft={1} onClick={handleOnClick}>
|
||||
Edit
|
||||
</Button>
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--auto-complete" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input type={INPUT_TYPES.PASSWORD} autoComplete />;
|
||||
```
|
||||
|
||||
### Auto Focus
|
||||
|
||||
Use the `autoFocus` prop to focus the `Input` during the first mount
|
||||
|
||||
To view story see [Canvas tab](/story/components-componentlibrary-input--auto-focus). Removing it from docs because created annoying reading experience 😁
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input autoFocus />;
|
||||
```
|
||||
|
||||
### Default Value
|
||||
|
||||
Use the `defaultValue` prop to set the default value of the `Input`. Used for uncontrolled inputs.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--default-value" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input defaultValue="default value" />;
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to set the disabled state of the `Input`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--disabled" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input disabled />;
|
||||
```
|
||||
|
||||
### Error
|
||||
|
||||
Use the `error` prop to set `aria-invalid="true"`. This helps with screen readers for accessibility. There is no visual indicator for `error` this should be handled in the parent component.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--error-story" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input error />;
|
||||
```
|
||||
|
||||
### Max Length
|
||||
|
||||
Use the `maxLength` prop to set the maximum allowed input characters for the `Input`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--max-length" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input maxLength={10} />;
|
||||
```
|
||||
|
||||
### Read Only
|
||||
|
||||
Use the `readOnly` prop to set the `Input` to read only
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--read-only" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input readOnly />;
|
||||
```
|
||||
|
||||
### Required
|
||||
|
||||
Use the `required` prop to set the html `required` attribute used by the browser api. There is no visual indicator for `required` this should be handled in the parent component.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--required" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
// No visual indicator. Used by the browser api
|
||||
<Input required />;
|
||||
```
|
||||
|
||||
### Disable Style States
|
||||
|
||||
Use the `disableStyleStates` to remove disabled and focus styles
|
||||
|
||||
#### IMPORTANT NOTE
|
||||
|
||||
This sets the CSS to `outline: none` so ensure there is a proper fallback to enable accessibility for keyboard only and vision impaired users. Check `TextField` source code to see how it is done properly.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--disable-state-styles" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input disableStyleStates />;
|
||||
```
|
||||
|
||||
### Text Variant
|
||||
|
||||
Use the `textVariant` and `TextVariant` enum to change the font size and style of the input
|
||||
|
||||
#### IMPORTANT NOTE
|
||||
|
||||
This should RARELY be used but it is available for custom inputs that require larger text
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-input--text-variant-story" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextVariant } from '../../../helpers/constants/design-system';
|
||||
import { Input } from '../../component-library';
|
||||
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.displayMd}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingLg}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingMd}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingSm}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyLgMedium}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyMdBold}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyMd}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodySm}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodySmBold}
|
||||
/>
|
||||
<Input
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyXs}
|
||||
/>
|
||||
```
|
@ -0,0 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Input should render correctly 1`] = `
|
||||
<div>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="box mm-text mm-input mm-text--body-md mm-text--color-text-default box--flex-direction-row box--background-color-transparent box--border-style-none"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
`;
|
2
ui/components/component-library/input/index.js
Normal file
2
ui/components/component-library/input/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export { Input } from './input';
|
||||
export { INPUT_TYPES } from './input.constants';
|
6
ui/components/component-library/input/input.constants.js
Normal file
6
ui/components/component-library/input/input.constants.js
Normal file
@ -0,0 +1,6 @@
|
||||
export const INPUT_TYPES = {
|
||||
TEXT: 'text',
|
||||
NUMBER: 'number',
|
||||
PASSWORD: 'password',
|
||||
SEARCH: 'search',
|
||||
};
|
170
ui/components/component-library/input/input.js
Normal file
170
ui/components/component-library/input/input.js
Normal file
@ -0,0 +1,170 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import {
|
||||
TextVariant,
|
||||
BackgroundColor,
|
||||
BorderStyle,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
import Box from '../../ui/box';
|
||||
|
||||
import { Text } from '../text';
|
||||
|
||||
import { INPUT_TYPES } from './input.constants';
|
||||
|
||||
export const Input = React.forwardRef(
|
||||
(
|
||||
{
|
||||
autoComplete,
|
||||
autoFocus,
|
||||
className,
|
||||
defaultValue,
|
||||
disabled,
|
||||
error,
|
||||
id,
|
||||
maxLength,
|
||||
name,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
placeholder,
|
||||
readOnly,
|
||||
required,
|
||||
type = 'text',
|
||||
value,
|
||||
textVariant = TextVariant.bodyMd,
|
||||
disableStateStyles,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
) => (
|
||||
<Text
|
||||
className={classnames(
|
||||
'mm-input',
|
||||
{
|
||||
'mm-input--disable-state-styles': disableStateStyles,
|
||||
'mm-input--disabled': disabled && !disableStateStyles,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
aria-invalid={error}
|
||||
as="input"
|
||||
autoComplete={autoComplete ? 'on' : 'off'}
|
||||
autoFocus={autoFocus}
|
||||
backgroundColor={BackgroundColor.transparent}
|
||||
borderStyle={BorderStyle.none}
|
||||
defaultValue={defaultValue}
|
||||
disabled={disabled}
|
||||
id={id}
|
||||
margin={0}
|
||||
maxLength={maxLength}
|
||||
name={name}
|
||||
onBlur={onBlur}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
padding={0}
|
||||
placeholder={placeholder}
|
||||
readOnly={readOnly}
|
||||
ref={ref}
|
||||
required={required}
|
||||
value={value}
|
||||
variant={textVariant}
|
||||
type={type}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
);
|
||||
|
||||
Input.propTypes = {
|
||||
/**
|
||||
* Autocomplete allows the browser to predict the value based on earlier typed values
|
||||
*/
|
||||
autoComplete: PropTypes.bool,
|
||||
/**
|
||||
* If `true`, the input will be focused during the first mount.
|
||||
*/
|
||||
autoFocus: PropTypes.bool,
|
||||
/**
|
||||
* An additional className to apply to the input
|
||||
*/
|
||||
className: PropTypes.string,
|
||||
/**
|
||||
* The default input value, useful when not controlling the component.
|
||||
*/
|
||||
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
/**
|
||||
* If `true`, the input will be disabled.
|
||||
*/
|
||||
disabled: PropTypes.bool,
|
||||
/**
|
||||
* Disables focus state by setting CSS outline: none;
|
||||
* !!IMPORTANT!!
|
||||
* If this is set to true ensure there is a proper fallback
|
||||
* to enable accessibility for keyboard only and vision impaired users
|
||||
*/
|
||||
disableStateStyles: PropTypes.bool,
|
||||
/**
|
||||
* If `true`, aria-invalid will be true
|
||||
*/
|
||||
error: PropTypes.bool,
|
||||
/**
|
||||
* The id of the `input` element.
|
||||
*/
|
||||
id: PropTypes.string,
|
||||
/**
|
||||
* Max number of characters to allow
|
||||
*/
|
||||
maxLength: PropTypes.number,
|
||||
/**
|
||||
* Name attribute of the `input` element.
|
||||
*/
|
||||
name: PropTypes.string,
|
||||
/**
|
||||
* Callback fired on blur
|
||||
*/
|
||||
onBlur: PropTypes.func,
|
||||
/**
|
||||
* Callback fired when the value is changed.
|
||||
*/
|
||||
onChange: PropTypes.func,
|
||||
/**
|
||||
* Callback fired on focus
|
||||
*/
|
||||
onFocus: PropTypes.func,
|
||||
/**
|
||||
* The short hint displayed in the input before the user enters a value.
|
||||
*/
|
||||
placeholder: PropTypes.string,
|
||||
/**
|
||||
* It prevents the user from changing the value of the field (not from interacting with the field).
|
||||
*/
|
||||
readOnly: PropTypes.bool,
|
||||
/**
|
||||
* If `true`, the input will be required. Currently no visual difference is shown.
|
||||
*/
|
||||
required: PropTypes.bool,
|
||||
/**
|
||||
* Use this to override the text variant of the Text component.
|
||||
* Should only be used for approved custom input components
|
||||
* Use the TextVariant enum
|
||||
*/
|
||||
textVariant: PropTypes.oneOf(Object.values(TextVariant)),
|
||||
/**
|
||||
* Type of the input element. Can be INPUT_TYPES.TEXT, INPUT_TYPES.PASSWORD, INPUT_TYPES.NUMBER
|
||||
* Defaults to INPUT_TYPES.TEXT ('text')
|
||||
* If you require another type add it to INPUT_TYPES
|
||||
*/
|
||||
type: PropTypes.oneOf(Object.values(INPUT_TYPES)),
|
||||
/**
|
||||
* The input value, required for a controlled component.
|
||||
*/
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
/**
|
||||
* Input accepts all the props from Box
|
||||
*/
|
||||
...Box.propTypes,
|
||||
};
|
||||
|
||||
Input.displayName = 'Input';
|
16
ui/components/component-library/input/input.scss
Normal file
16
ui/components/component-library/input/input.scss
Normal file
@ -0,0 +1,16 @@
|
||||
.mm-input {
|
||||
--input-opacity-disabled: 0.5;
|
||||
|
||||
box-sizing: content-box;
|
||||
|
||||
&--disable-state-styles {
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: var(--input-opacity-disabled);
|
||||
}
|
||||
}
|
287
ui/components/component-library/input/input.stories.js
Normal file
287
ui/components/component-library/input/input.stories.js
Normal file
@ -0,0 +1,287 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { useArgs } from '@storybook/client-api';
|
||||
|
||||
import {
|
||||
DISPLAY,
|
||||
FLEX_DIRECTION,
|
||||
TextVariant,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import Box from '../../ui/box/box';
|
||||
|
||||
import { Button } from '..';
|
||||
|
||||
import { INPUT_TYPES } from './input.constants';
|
||||
import { Input } from './input';
|
||||
|
||||
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/Input',
|
||||
component: Input,
|
||||
parameters: {
|
||||
docs: {
|
||||
page: README,
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
autoComplete: {
|
||||
control: 'boolean',
|
||||
},
|
||||
autoFocus: {
|
||||
control: 'boolean',
|
||||
},
|
||||
className: {
|
||||
control: 'text',
|
||||
},
|
||||
defaultValue: {
|
||||
control: 'text',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
},
|
||||
disableStateStyles: {
|
||||
control: 'boolean',
|
||||
},
|
||||
error: {
|
||||
control: 'boolean',
|
||||
},
|
||||
id: {
|
||||
control: 'text',
|
||||
},
|
||||
maxLength: {
|
||||
control: 'number',
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
},
|
||||
onBlur: {
|
||||
action: 'onBlur',
|
||||
},
|
||||
onChange: {
|
||||
action: 'onChange',
|
||||
},
|
||||
onFocus: {
|
||||
action: 'onFocus',
|
||||
},
|
||||
placeholder: {
|
||||
control: 'text',
|
||||
},
|
||||
readOnly: {
|
||||
control: 'boolean',
|
||||
},
|
||||
required: {
|
||||
control: 'boolean',
|
||||
},
|
||||
type: {
|
||||
control: 'select',
|
||||
options: Object.values(INPUT_TYPES),
|
||||
},
|
||||
value: {
|
||||
control: 'text',
|
||||
},
|
||||
textVariant: {
|
||||
control: 'select',
|
||||
options: Object.values(TextVariant),
|
||||
},
|
||||
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: {
|
||||
placeholder: 'Placeholder...',
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args) => {
|
||||
const [{ value }, updateArgs] = useArgs();
|
||||
const handleOnChange = (e) => {
|
||||
updateArgs({ value: e.target.value });
|
||||
};
|
||||
return <Input {...args} value={value} onChange={handleOnChange} />;
|
||||
};
|
||||
|
||||
export const DefaultStory = Template.bind({});
|
||||
DefaultStory.storyName = 'Default';
|
||||
|
||||
export const Type = (args) => (
|
||||
<Box
|
||||
display={DISPLAY.INLINE_FLEX}
|
||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||
gap={4}
|
||||
>
|
||||
<Input {...args} placeholder="Default" />
|
||||
<Input {...args} type={INPUT_TYPES.PASSWORD} placeholder="Password" />
|
||||
<Input {...args} type={INPUT_TYPES.NUMBER} placeholder="Number" />
|
||||
<Input {...args} type={INPUT_TYPES.SEARCH} placeholder="Search" />
|
||||
</Box>
|
||||
);
|
||||
|
||||
Type.args = {
|
||||
value: undefined,
|
||||
};
|
||||
|
||||
export const Ref = (args) => {
|
||||
const [{ value }, updateArgs] = useArgs();
|
||||
const inputRef = useRef(null);
|
||||
const handleOnClick = () => {
|
||||
inputRef.current.focus();
|
||||
};
|
||||
const handleOnChange = (e) => {
|
||||
updateArgs({ value: e.target.value });
|
||||
};
|
||||
return (
|
||||
<Box display={DISPLAY.FLEX}>
|
||||
<Input {...args} ref={inputRef} value={value} onChange={handleOnChange} />
|
||||
<Button marginLeft={1} onClick={handleOnClick}>
|
||||
Edit
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export const AutoComplete = Template.bind({});
|
||||
AutoComplete.args = {
|
||||
autoComplete: true,
|
||||
type: INPUT_TYPES.PASSWORD,
|
||||
placeholder: 'Enter password',
|
||||
};
|
||||
|
||||
export const AutoFocus = Template.bind({});
|
||||
AutoFocus.args = { autoFocus: true };
|
||||
|
||||
export const DefaultValue = () => (
|
||||
<Input placeholder="Default value" defaultValue="Default value" />
|
||||
);
|
||||
export const Disabled = Template.bind({});
|
||||
Disabled.args = { disabled: true };
|
||||
|
||||
export const ErrorStory = Template.bind({});
|
||||
ErrorStory.args = { error: true };
|
||||
ErrorStory.storyName = 'Error';
|
||||
|
||||
export const MaxLength = Template.bind({});
|
||||
MaxLength.args = { maxLength: 10, placeholder: 'Max length 10' };
|
||||
|
||||
export const ReadOnly = Template.bind({});
|
||||
ReadOnly.args = { readOnly: true, value: 'Read only' };
|
||||
|
||||
export const Required = Template.bind({});
|
||||
Required.args = { required: true, placeholder: 'Required' };
|
||||
|
||||
export const DisableStateStyles = Template.bind({});
|
||||
DisableStateStyles.args = {
|
||||
disableStateStyles: true,
|
||||
};
|
||||
|
||||
export const TextVariantStory = (args) => {
|
||||
const [{ value }, updateArgs] = useArgs();
|
||||
const handleOnChange = (e) => {
|
||||
updateArgs({ value: e.target.value });
|
||||
};
|
||||
return (
|
||||
<Box
|
||||
display={DISPLAY.INLINE_FLEX}
|
||||
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||
gap={4}
|
||||
>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.displayMd}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingLg}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingMd}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.headingSm}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyLgMedium}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyMdBold}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyMd}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodySm}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodySmBold}
|
||||
/>
|
||||
<Input
|
||||
{...args}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
textVariant={TextVariant.bodyXs}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
TextVariantStory.storyName = 'Text Variant';
|
145
ui/components/component-library/input/input.test.js
Normal file
145
ui/components/component-library/input/input.test.js
Normal file
@ -0,0 +1,145 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
import React from 'react';
|
||||
import { fireEvent, render, act } from '@testing-library/react';
|
||||
import { renderWithUserEvent } from '../../../../test/lib/render-helpers';
|
||||
|
||||
import { TextVariant } from '../../../helpers/constants/design-system';
|
||||
import { Input } from './input';
|
||||
import { INPUT_TYPES } from './input.constants';
|
||||
|
||||
describe('Input', () => {
|
||||
it('should render correctly', () => {
|
||||
const { getByRole, container } = render(<Input />);
|
||||
expect(getByRole('textbox')).toBeDefined();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it('should render correctly with custom className', () => {
|
||||
const { getByRole } = render(<Input className="test" />);
|
||||
expect(getByRole('textbox')).toHaveClass('test');
|
||||
});
|
||||
it('should render and be able to input text', () => {
|
||||
const { getByTestId } = render(<Input data-testid="input" />);
|
||||
const InputComponent = getByTestId('input');
|
||||
|
||||
expect(InputComponent.value).toBe(''); // initial value is empty string
|
||||
fireEvent.change(InputComponent, { target: { value: 'text value' } });
|
||||
expect(InputComponent.value).toBe('text value');
|
||||
fireEvent.change(InputComponent, { target: { value: '' } }); // reset value
|
||||
expect(InputComponent.value).toBe(''); // value is empty string after reset
|
||||
});
|
||||
it('should render without state styles when disableStateStyles is true', async () => {
|
||||
const { getByTestId, user } = renderWithUserEvent(
|
||||
<Input data-testid="input" disableStateStyles />,
|
||||
);
|
||||
const InputComponent = getByTestId('input');
|
||||
|
||||
await user.click(InputComponent);
|
||||
expect(getByTestId('input')).toHaveFocus();
|
||||
expect(getByTestId('input')).toHaveClass('mm-input--disable-state-styles');
|
||||
expect(getByTestId('input')).not.toHaveClass('mm-input--disabled');
|
||||
});
|
||||
it('should render and fire onFocus and onBlur events', async () => {
|
||||
const onFocus = jest.fn();
|
||||
const onBlur = jest.fn();
|
||||
const { getByTestId, user } = renderWithUserEvent(
|
||||
<Input data-testid="input" onFocus={onFocus} onBlur={onBlur} />,
|
||||
);
|
||||
|
||||
const InputComponent = getByTestId('input');
|
||||
await user.click(InputComponent);
|
||||
expect(onFocus).toHaveBeenCalledTimes(1);
|
||||
fireEvent.blur(InputComponent);
|
||||
expect(onBlur).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it('should pass ref to allow input to focus through another element', () => {
|
||||
const ref = React.createRef();
|
||||
const { getByRole } = renderWithUserEvent(<Input ref={ref} />);
|
||||
|
||||
act(() => ref.current.focus());
|
||||
expect(getByRole('textbox')).toHaveFocus();
|
||||
});
|
||||
it('should render and fire onChange event', async () => {
|
||||
const onChange = jest.fn();
|
||||
const { getByTestId, user } = renderWithUserEvent(
|
||||
<Input data-testid="input" onChange={onChange} />,
|
||||
);
|
||||
const InputComponent = getByTestId('input');
|
||||
await user.type(InputComponent, '123');
|
||||
expect(InputComponent).toHaveValue('123');
|
||||
expect(onChange).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
it('should render with different types', () => {
|
||||
const { getByTestId } = render(
|
||||
<>
|
||||
<Input data-testid="input-text-default" />
|
||||
<Input type={INPUT_TYPES.TEXT} data-testid="input-text" />
|
||||
<Input type={INPUT_TYPES.NUMBER} data-testid="input-number" />
|
||||
<Input type={INPUT_TYPES.PASSWORD} data-testid="input-password" />
|
||||
</>,
|
||||
);
|
||||
expect(getByTestId('input-text-default')).toHaveAttribute('type', 'text');
|
||||
expect(getByTestId('input-text')).toHaveAttribute('type', 'text');
|
||||
expect(getByTestId('input-number')).toHaveAttribute('type', 'number');
|
||||
expect(getByTestId('input-password')).toHaveAttribute('type', 'password');
|
||||
});
|
||||
it('should render with autoComplete', () => {
|
||||
const { getByTestId } = render(
|
||||
<Input autoComplete data-testid="input-auto-complete" />,
|
||||
);
|
||||
expect(getByTestId('input-auto-complete')).toHaveAttribute(
|
||||
'autocomplete',
|
||||
'on',
|
||||
);
|
||||
});
|
||||
it('should render with autoFocus', () => {
|
||||
const { getByRole } = render(<Input autoFocus />);
|
||||
expect(getByRole('textbox')).toHaveFocus();
|
||||
});
|
||||
it('should render with a defaultValue', () => {
|
||||
const { getByRole } = render(<Input defaultValue="default value" />);
|
||||
expect(getByRole('textbox').value).toBe('default value');
|
||||
});
|
||||
it('should render in disabled state and not focus or be clickable', async () => {
|
||||
const mockOnFocus = jest.fn();
|
||||
const { getByRole, getByTestId, user } = renderWithUserEvent(
|
||||
<Input disabled onFocus={mockOnFocus} data-testid="input" />,
|
||||
);
|
||||
const InputComponent = getByTestId('input');
|
||||
await user.click(InputComponent);
|
||||
expect(getByRole('textbox')).toBeDisabled();
|
||||
expect(mockOnFocus).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
it('should render with maxLength and not allow more than the set characters', async () => {
|
||||
const { getByRole, user } = renderWithUserEvent(<Input maxLength={5} />);
|
||||
const InputComponent = getByRole('textbox');
|
||||
await user.type(InputComponent, '1234567890');
|
||||
expect(getByRole('textbox')).toBeDefined();
|
||||
expect(InputComponent.maxLength).toBe(5);
|
||||
expect(InputComponent.value).toBe('12345');
|
||||
expect(InputComponent.value).toHaveLength(5);
|
||||
});
|
||||
it('should render with readOnly attr when readOnly is true', async () => {
|
||||
const { getByTestId, getByRole, user } = renderWithUserEvent(
|
||||
<Input readOnly data-testid="read-only" />,
|
||||
);
|
||||
const InputComponent = getByTestId('read-only');
|
||||
await user.type(InputComponent, '1234567890');
|
||||
expect(getByRole('textbox').value).toBe('');
|
||||
expect(getByRole('textbox')).toHaveAttribute('readonly', '');
|
||||
});
|
||||
it('should render with required attr when required is true', () => {
|
||||
const { getByTestId } = render(
|
||||
<Input required data-testid="input-required" />,
|
||||
);
|
||||
expect(getByTestId('input-required')).toHaveAttribute('required', '');
|
||||
});
|
||||
it('should render with a different Text variant', () => {
|
||||
const { getByTestId } = render(
|
||||
<Input
|
||||
data-testid="input-required"
|
||||
textVariant={TextVariant.headingSm}
|
||||
/>,
|
||||
);
|
||||
expect(getByTestId('input-required')).toHaveClass('mm-text--heading-sm');
|
||||
});
|
||||
});
|
@ -1,338 +0,0 @@
|
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||
|
||||
import { TextFieldBase } from './text-field-base';
|
||||
|
||||
### This is a base component. It should not be used in your feature code directly but as a "base" for other UI components
|
||||
|
||||
# TextFieldBase
|
||||
|
||||
The `TextFieldBase` is the base component for all text fields. It should not be used directly. It functions as both a uncontrolled and controlled input.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--default-story" />
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
The `TextFieldBase` accepts all props below as well as all [Box](/docs/components-ui-box--default-story#props) component props
|
||||
|
||||
<ArgsTable of={TextFieldBase} />
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` prop to set the height of the `TextFieldBase`.
|
||||
|
||||
Possible sizes include:
|
||||
|
||||
- `sm` 32px
|
||||
- `md` 40px
|
||||
- `lg` 48px
|
||||
|
||||
Defaults to `md`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--size-story" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Size } from '../../../helpers/constants/design-system';
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase size={Size.SM} />
|
||||
<TextFieldBase size={Size.MD} />
|
||||
<TextFieldBase size={Size.LG} />
|
||||
```
|
||||
|
||||
### Type
|
||||
|
||||
Use the `type` prop to change the type of input.
|
||||
|
||||
Possible types include:
|
||||
|
||||
- `text`
|
||||
- `number`
|
||||
- `password`
|
||||
|
||||
Defaults to `text`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--type" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase type="text" /> // (Default)
|
||||
<TextFieldBase type="number" />
|
||||
<TextFieldBase type="password" />
|
||||
```
|
||||
|
||||
### Truncate
|
||||
|
||||
Use the `truncate` prop to truncate the text of the the `TextFieldBase`. Defaults to `true`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--truncate" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase truncate />; // truncate is set to `true` by default
|
||||
<TextFieldBase truncate={false} />;
|
||||
```
|
||||
|
||||
### Left Accessory Right Accessory
|
||||
|
||||
Use the `leftAccessory` and `rightAccessory` props to add components such as icons or buttons to either side of the `TextFieldBase`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--left-accessory-right-accessory" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Color, DISPLAY } from '../../../helpers/constants/design-system';
|
||||
import { ButtonIcon, Icon, ICON_NAMES, TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase
|
||||
placeholder="Search"
|
||||
leftAccessory={
|
||||
<Icon
|
||||
color={Color.iconAlternative}
|
||||
name={ICON_NAMES.SEARCH}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<TextFieldBase
|
||||
placeholder="Public address (0x), or ENS"
|
||||
rightAccessory={
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.SCAN_BARCODE}
|
||||
ariaLabel="Scan QR code"
|
||||
iconProps={{ color: Color.primaryDefault }}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<TextFieldBase
|
||||
placeholder="Enter amount"
|
||||
type="number"
|
||||
truncate
|
||||
leftAccessory={<SelectTokenComponent />}
|
||||
rightAccessory={<TokenValueInUSDComponent />}
|
||||
/>
|
||||
|
||||
<TextFieldBase
|
||||
placeholder="Public address (0x), or ENS"
|
||||
truncate
|
||||
leftAccessory={<AvatarAccount />}
|
||||
rightAccessory={
|
||||
isAddressValid && (
|
||||
<Icon
|
||||
name={ICON_NAMES.CHECK}
|
||||
color={Color.successDefault}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
```
|
||||
|
||||
### Input Ref
|
||||
|
||||
Use the `inputRef` prop to access the ref of the `<input />` html element of `TextFieldBase`. This is useful for focusing the input from a button or other component.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--input-ref" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { Button, TextFieldBase } from '../../component-library';
|
||||
|
||||
const inputRef = useRef(null);
|
||||
const [value, setValue] = useState('');
|
||||
const handleOnClick = () => {
|
||||
inputRef.current.focus();
|
||||
};
|
||||
const handleOnChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
};
|
||||
|
||||
<TextFieldBase
|
||||
inputRef={inputRef}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
/>
|
||||
<Button marginLeft={1} onClick={handleOnClick}>
|
||||
Edit
|
||||
</Button>
|
||||
```
|
||||
|
||||
### 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/components-componentlibrary-text--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="components-componentlibrary-textfieldbase--input-component" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase, Icon, ICON_NAMES } from '../../component-library';
|
||||
import { Size } from '../../../helpers/constants/design-system';
|
||||
|
||||
// should map the props to the custom input component
|
||||
const CustomInputComponent = () => <div>{/* Custom input component */}</div>;
|
||||
|
||||
const TextFieldCustomInput = (args) => (
|
||||
<TextFieldBase
|
||||
size={Size.LG}
|
||||
InputComponent={CustomInputComponent}
|
||||
leftAccessory={
|
||||
<Icon color={Color.iconAlternative} name={ICON_NAMES.WALLET} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--auto-complete" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase type="password" autoComplete />;
|
||||
```
|
||||
|
||||
### Auto Focus
|
||||
|
||||
Use the `autoFocus` prop to focus the `TextFieldBase` during the first mount
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--auto-focus" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase autoFocus />;
|
||||
```
|
||||
|
||||
### Default Value
|
||||
|
||||
Use the `defaultValue` prop to set the default value of the `TextFieldBase`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--default-value" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase defaultValue="default value" />;
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` prop to set the disabled state of the `TextFieldBase`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--disabled" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase disabled />;
|
||||
```
|
||||
|
||||
### Error
|
||||
|
||||
Use the `error` prop to set the error state of the `TextFieldBase`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--error-story" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase error />;
|
||||
```
|
||||
|
||||
### Max Length
|
||||
|
||||
Use the `maxLength` prop to set the maximum allowed input characters for the `TextFieldBase`
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--max-length" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase maxLength={10} />;
|
||||
```
|
||||
|
||||
### Read Only
|
||||
|
||||
Use the `readOnly` prop to set the `TextFieldBase` to read only. When `readOnly` is true `TextFieldBase` will not have a focus state.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--read-only" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
<TextFieldBase readOnly />;
|
||||
```
|
||||
|
||||
### Required
|
||||
|
||||
Use the `required` prop to set the `TextFieldBase` to required. Currently there is no visual difference to the `TextFieldBase` when required.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-textfieldbase--required" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextFieldBase } from '../../component-library';
|
||||
|
||||
// Currently no visual difference
|
||||
<TextFieldBase required />;
|
||||
```
|
@ -11,7 +11,7 @@ exports[`TextFieldSearch should render correctly 1`] = `
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="box mm-text mm-text-field__input mm-text--body-md mm-text--color-text-default box--margin-right-6 box--padding-right-4 box--padding-left-2 box--flex-direction-row box--background-color-transparent"
|
||||
class="box mm-text mm-input mm-text-field__input mm-text--body-md mm-text--color-text-default box--margin-right-6 box--padding-right-4 box--padding-left-2 box--flex-direction-row box--background-color-transparent box--border-style-none"
|
||||
focused="false"
|
||||
type="search"
|
||||
value=""
|
||||
|
@ -7,7 +7,7 @@ exports[`TextField should render correctly 1`] = `
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="box mm-text mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent"
|
||||
class="box mm-text mm-input mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent box--border-style-none"
|
||||
focused="false"
|
||||
type="text"
|
||||
value=""
|
||||
|
@ -6,14 +6,13 @@ import {
|
||||
DISPLAY,
|
||||
Size,
|
||||
AlignItems,
|
||||
TextVariant,
|
||||
BorderRadius,
|
||||
BackgroundColor,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
import Box from '../../ui/box';
|
||||
|
||||
import { Text } from '../text';
|
||||
import { Input } from '../input';
|
||||
|
||||
import { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants';
|
||||
|
||||
@ -42,7 +41,7 @@ export const TextField = ({
|
||||
type = 'text',
|
||||
truncate = true,
|
||||
value,
|
||||
InputComponent = Text,
|
||||
InputComponent = Input,
|
||||
...props
|
||||
}) => {
|
||||
const internalInputRef = useRef(null);
|
||||
@ -114,8 +113,7 @@ export const TextField = ({
|
||||
{startAccessory}
|
||||
<InputComponent
|
||||
aria-invalid={error}
|
||||
as="input"
|
||||
autoComplete={autoComplete ? 'on' : 'off'}
|
||||
autoComplete={autoComplete}
|
||||
autoFocus={autoFocus}
|
||||
backgroundColor={BackgroundColor.transparent}
|
||||
defaultValue={defaultValue}
|
||||
@ -136,7 +134,6 @@ export const TextField = ({
|
||||
ref={handleInputRef}
|
||||
required={required}
|
||||
value={value}
|
||||
variant={TextVariant.bodyMd}
|
||||
type={type}
|
||||
{...inputProps} // before className so input className isn't overridden
|
||||
className={classnames('mm-text-field__input', inputProps?.className)}
|
||||
|
@ -38,17 +38,7 @@
|
||||
}
|
||||
|
||||
&__input {
|
||||
border: none;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
box-sizing: content-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ export const Text = React.forwardRef(
|
||||
},
|
||||
);
|
||||
|
||||
// // Set a default tag based on variant
|
||||
// Set a default tag based on variant
|
||||
const splitTag = Tag.split('-')[0];
|
||||
if (splitTag === 'body') {
|
||||
Tag = 'p';
|
||||
|
@ -98,7 +98,7 @@ exports[`Reveal Seed Page should match snapshot 1`] = `
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="box mm-text mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent"
|
||||
class="box mm-text mm-input mm-text-field__input mm-text--body-md mm-text--color-text-default box--padding-right-4 box--padding-left-4 box--flex-direction-row box--background-color-transparent box--border-style-none"
|
||||
data-testid="input-password"
|
||||
focused="true"
|
||||
id="password-box"
|
||||
|
Loading…
x
Reference in New Issue
Block a user