Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 59b0080

Browse files
authored
Redesign text fields (#187)
* New TextFieldInput designs * New Select designs * New AddressInput designs
1 parent c986e41 commit 59b0080

File tree

39 files changed

+2074
-1169
lines changed

39 files changed

+2074
-1169
lines changed

.storybook/main.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module.exports = {
2-
stories: ["../src/**/*.stories.tsx"],
2+
stories: ['../src/**/*.stories.tsx'],
33
addons: [
4-
"@storybook/addon-actions",
5-
"@storybook/addon-links",
6-
"@storybook/addon-docs",
7-
"storybook-addon-react-docgen",
8-
]
4+
'@storybook/addon-actions',
5+
'@storybook/addon-links',
6+
'@storybook/addon-docs',
7+
'storybook-addon-react-docgen',
8+
'storybook-addon-controls',
9+
],
910
};

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@gnosis.pm/safe-react-components",
3-
"version": "0.9.8",
3+
"version": "1.0.0",
44
"description": "Gnosis UI components",
55
"main": "dist/index.min.js",
66
"typings": "dist/index.d.ts",
@@ -35,10 +35,12 @@
3535
"@babel/preset-typescript": "^7.16.0",
3636
"@material-ui/core": "^4.12.3",
3737
"@material-ui/icons": "^4.11.0",
38+
"@mui/x-data-grid": "4.0.2",
3839
"@storybook/addon-actions": "^6.3.12",
3940
"@storybook/addon-docs": "^6.3.12",
4041
"@storybook/addon-links": "^6.3.12",
4142
"@storybook/addon-storyshots": "^6.3.12",
43+
"@storybook/addon-controls": "^6.4.19",
4244
"@storybook/addons": "^6.3.12",
4345
"@storybook/react": "^6.3.12",
4446
"@testing-library/jest-dom": "^5.11.5",
@@ -70,7 +72,6 @@
7072
"rimraf": "^3.0.2",
7173
"storybook-addon-react-docgen": "^1.2.42",
7274
"styled-components": "^5.3.3",
73-
"@mui/x-data-grid": "4.0.2",
7475
"ts-loader": "^8.2.0",
7576
"typescript": "^4.5.0",
7677
"url-loader": "^4.1.1",

src/inputs/AddressInput/AddressInput.stories.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default {
3131

3232
hiddenLabel: {
3333
control: { type: 'boolean' },
34-
defaultValue: true,
34+
defaultValue: false,
3535
},
3636
disabled: {
3737
control: { type: 'boolean' },
@@ -99,6 +99,8 @@ export const SimpleAddressInput = ({
9999
<div>
100100
<StyledText>Network Settings:</StyledText>
101101
<Select
102+
name="network"
103+
label="Network"
102104
items={networks}
103105
activeItemId={currentNetworkPrefix}
104106
onItemClick={(networkPrefix) => {

src/inputs/AddressInput/index.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function AddressInput({
5151
...rest
5252
}: AddressInputProps): ReactElement {
5353
const [isLoadingENSResolution, setIsLoadingENSResolution] = useState(false);
54+
const [inputValue, setInputValue] = useState('');
5455
const defaulInputValue = addPrefix(address, networkPrefix, showNetworkPrefix);
5556
const inputRef = useRef({ value: defaulInputValue });
5657
const throttle = useThrottle();
@@ -126,14 +127,14 @@ function AddressInput({
126127
const inputPrefix = getNetworkPrefix(inputValue);
127128
const inputWithoutPrefix = getAddressWithoutNetworkPrefix(inputValue);
128129

130+
// if the valid network prefix is present, we remove it from the address state
129131
const isValidPrefix = networkPrefix === inputPrefix;
132+
const checksumAddress = checksumValidAddress(
133+
isValidPrefix ? inputWithoutPrefix : inputValue
134+
);
130135

131-
if (isValidPrefix) {
132-
// if the valid network prefix is present, we remove it from the address state
133-
onChangeAddress(checksumValidAddress(inputWithoutPrefix));
134-
} else {
135-
onChangeAddress(checksumValidAddress(inputValue));
136-
}
136+
onChangeAddress(checksumAddress);
137+
setInputValue(checksumAddress);
137138
},
138139
[networkPrefix, onChangeAddress]
139140
);
@@ -162,6 +163,7 @@ function AddressInput({
162163
hiddenLabel={hiddenLabel && !shrink}
163164
disabled={disabled || isLoadingENSResolution}
164165
onChange={onChange}
166+
value={inputValue}
165167
InputProps={{
166168
...InputProps,
167169
// if isLoading we show a custom loader adornment

src/inputs/Select/dai.png

-4.1 KB
Binary file not shown.

src/inputs/Select/gnosis.png

-6.37 KB
Binary file not shown.

src/inputs/Select/index.tsx

Lines changed: 119 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,16 @@
11
import React from 'react';
22
import MenuItem from '@material-ui/core/MenuItem';
3+
import SelectMUI, {
4+
SelectProps as SelectMuiProps,
5+
} from '@material-ui/core/Select';
36
import FormControl from '@material-ui/core/FormControl';
4-
import SelectMUI from '@material-ui/core/Select';
7+
import FormHelperText from '@material-ui/core/FormHelperText';
8+
import InputLabel from '@material-ui/core/InputLabel';
59
import styled from 'styled-components';
610

711
import { Text } from '../../dataDisplay';
812

9-
const IconImg = styled.img`
10-
width: 20px;
11-
margin-right: 10px;
12-
`;
13-
14-
const StyledSelect = styled(SelectMUI)`
15-
background-color: ${(props) => props.theme.colors.separator};
16-
border-radius: 5px;
17-
height: 56px;
18-
width: 140px;
19-
20-
.MuiSelect-select {
21-
display: flex;
22-
align-items: center;
23-
padding-left: 15px;
24-
}
25-
26-
.MuiSelect-selectMenu {
27-
font-family: ${(props) => props.theme.fonts.fontFamily};
28-
}
29-
30-
&.MuiInput-underline:hover:not(.Mui-disabled):before {
31-
border-bottom: 2px solid ${(props) => props.theme.colors.primary};
32-
}
33-
&.MuiInput-underline:after {
34-
border-bottom: 2px solid ${(props) => props.theme.colors.primary};
35-
}
36-
`;
13+
import { inputLabelStyles, inputStyles, errorStyles } from '../styles';
3714

3815
export type SelectItem = {
3916
id: string;
@@ -42,24 +19,37 @@ export type SelectItem = {
4219
iconUrl?: string;
4320
};
4421

45-
type Props = {
22+
type SelectProps = {
23+
id?: string;
24+
name: string;
25+
label: string;
26+
error?: string;
27+
helperText?: string | undefined;
28+
showErrorsInTheLabel?: boolean | undefined;
4629
items: Array<SelectItem>;
4730
activeItemId: string;
4831
onItemClick: (id: string) => void;
49-
id?: string;
5032
fallbackImage?: string;
51-
};
33+
} & Omit<SelectMuiProps, 'error'>;
5234

5335
function Select({
36+
id,
37+
name,
38+
label,
39+
error,
40+
helperText,
41+
showErrorsInTheLabel,
5442
items,
5543
activeItemId,
5644
onItemClick,
57-
id,
5845
fallbackImage,
46+
fullWidth,
5947
...rest
60-
}: Props): React.ReactElement {
48+
}: SelectProps): React.ReactElement {
6149
const [open, setOpen] = React.useState(false);
6250

51+
const hasError = !!error;
52+
6353
const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
6454
onItemClick(event.target.value as string);
6555
};
@@ -82,44 +72,103 @@ function Select({
8272
};
8373

8474
return (
85-
<div>
86-
<FormControl>
87-
<StyledSelect
88-
labelId={id ? id : 'generic-select'}
89-
id={id ? id : 'generic-select'}
90-
open={open}
91-
onClose={handleClose}
92-
onOpen={handleOpen}
93-
value={activeItemId}
94-
onChange={handleChange}
95-
{...rest}>
96-
{items.map((i) => {
97-
return (
98-
<MenuItem value={i.id} key={i.id}>
99-
{i.iconUrl && (
100-
<IconImg
101-
alt={i.label}
102-
onError={onFallbackImage}
103-
src={i.iconUrl}
104-
/>
105-
)}
106-
<div>
107-
<Text size="sm" color="text">
108-
{i.label}
75+
<StyledFormControl variant="outlined" fullWidth={fullWidth}>
76+
<InputLabel error={!!error}>
77+
{showErrorsInTheLabel && hasError ? error : label}
78+
</InputLabel>
79+
<StyledSelect
80+
id={id}
81+
name={name}
82+
labelId={id}
83+
error={hasError}
84+
open={open}
85+
onClose={handleClose}
86+
onOpen={handleOpen}
87+
value={activeItemId}
88+
onChange={handleChange}
89+
label={id ? id : 'generic-select'}
90+
variant="outlined"
91+
{...rest}>
92+
{items.map((i) => {
93+
return (
94+
<MenuItem value={i.id} key={i.id}>
95+
{i.iconUrl && (
96+
<IconImg
97+
alt={i.label}
98+
onError={onFallbackImage}
99+
src={i.iconUrl}
100+
/>
101+
)}
102+
<div>
103+
<Text size="sm" color="text">
104+
{i.label}
105+
</Text>
106+
{i.subLabel && (
107+
<Text size="sm" color="secondary" strong>
108+
{i.subLabel}
109109
</Text>
110-
{i.subLabel && (
111-
<Text size="sm" color="secondary" strong>
112-
{i.subLabel}
113-
</Text>
114-
)}
115-
</div>
116-
</MenuItem>
117-
);
118-
})}
119-
</StyledSelect>
120-
</FormControl>
121-
</div>
110+
)}
111+
</div>
112+
</MenuItem>
113+
);
114+
})}
115+
</StyledSelect>
116+
{(helperText || (error && showErrorsInTheLabel)) && (
117+
<StyledFormHelperText error={hasError && !showErrorsInTheLabel}>
118+
{helperText || error}
119+
</StyledFormHelperText>
120+
)}
121+
</StyledFormControl>
122122
);
123123
}
124124

125+
const IconImg = styled.img`
126+
width: 20px;
127+
margin-right: 10px;
128+
`;
129+
130+
const StyledSelect = styled(SelectMUI)`
131+
&& {
132+
.MuiSelect-root {
133+
background: #fff;
134+
}
135+
136+
.MuiSelect-select {
137+
display: flex;
138+
align-items: center;
139+
padding-left: 15px;
140+
}
141+
142+
.MuiSelect-selectMenu {
143+
font-family: ${(props) => props.theme.fonts.fontFamily};
144+
}
145+
146+
&& {
147+
fieldset {
148+
border: 1px solid
149+
${({ theme, value, error }) =>
150+
error
151+
? theme.colors.error
152+
: value
153+
? theme.colors.inputFilled
154+
: theme.colors.inputDisabled};
155+
}
156+
}
157+
}
158+
`;
159+
160+
const StyledFormControl = styled(FormControl)`
161+
&& {
162+
${inputLabelStyles}
163+
${inputStyles}
164+
${errorStyles}
165+
}
166+
`;
167+
168+
const StyledFormHelperText = styled(FormHelperText)`
169+
&& {
170+
font-family: ${(props) => props.theme.fonts.fontFamily};
171+
}
172+
`;
173+
125174
export default Select;

0 commit comments

Comments
 (0)