@zesty-io/material 0.0.4 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/ConfirmDialog/ConfirmDialog.stories.d.ts +6 -0
- package/es/ConfirmDialog/ConfirmDialog.stories.js +24 -0
- package/es/ConfirmDialog/index.d.ts +18 -0
- package/es/ConfirmDialog/index.js +11 -0
- package/es/ConfirmModal/ConfirmModal.stories.d.ts +6 -0
- package/es/ConfirmModal/ConfirmModal.stories.js +24 -0
- package/es/ConfirmModal/index.d.ts +18 -0
- package/es/ConfirmModal/index.js +11 -0
- package/es/CopyButton/index.js +3 -3
- package/es/FieldTypeColor/FieldTypeColor.stories.d.ts +5 -0
- package/es/FieldTypeColor/FieldTypeColor.stories.js +21 -0
- package/es/FieldTypeColor/index.d.ts +6 -0
- package/es/FieldTypeColor/index.js +16 -0
- package/es/FieldTypeDate/FieldTypeDate.stories.d.ts +5 -0
- package/es/FieldTypeDate/FieldTypeDate.stories.js +17 -0
- package/es/FieldTypeDate/index.d.ts +9 -0
- package/es/FieldTypeDate/index.js +10 -0
- package/es/FieldTypeDateTime/FieldTypeDateTime.stories.d.ts +5 -0
- package/es/FieldTypeDateTime/FieldTypeDateTime.stories.js +17 -0
- package/es/FieldTypeDateTime/index.d.ts +9 -0
- package/es/FieldTypeDateTime/index.js +10 -0
- package/es/FieldTypeDropdown/FieldTypeDropwdon.stories.d.ts +5 -0
- package/es/FieldTypeDropdown/FieldTypeDropwdon.stories.js +35 -0
- package/es/FieldTypeDropdown/index.d.ts +11 -0
- package/es/FieldTypeDropdown/index.js +10 -0
- package/es/FieldTypeNumber/FieldTypeNumber.stories.d.ts +5 -0
- package/es/FieldTypeNumber/FieldTypeNumber.stories.js +21 -0
- package/es/FieldTypeNumber/index.d.ts +6 -0
- package/es/FieldTypeNumber/index.js +7 -0
- package/es/FieldTypeOneToMany/FieldTypeOneToMany.stories.d.ts +5 -0
- package/es/FieldTypeOneToMany/FieldTypeOneToMany.stories.js +28 -0
- package/es/FieldTypeOneToMany/index.d.ts +32 -0
- package/es/FieldTypeOneToMany/index.js +29 -0
- package/es/FieldTypeOneToOne/FieldTypeOneToOne.stories.d.ts +5 -0
- package/es/FieldTypeOneToOne/FieldTypeOneToOne.stories.js +28 -0
- package/es/FieldTypeOneToOne/index.d.ts +34 -0
- package/es/FieldTypeOneToOne/index.js +33 -0
- package/es/FieldTypeSort/FieldTypeSort.stories.js +3 -1
- package/es/FieldTypeSort/index.d.ts +1 -1
- package/es/FieldTypeSort/index.js +17 -29
- package/es/FieldTypeText/FieldTypeText.stories.js +6 -6
- package/es/FieldTypeText/index.d.ts +1 -1
- package/es/FieldTypeText/index.js +4 -12
- package/es/FieldTypeUrl/index.d.ts +1 -1
- package/es/FieldTypeUrl/index.js +8 -16
- package/es/index.d.ts +11 -0
- package/es/index.js +11 -0
- package/es/theme/index.js +13 -2
- package/es/utils/virtualization.d.ts +2 -0
- package/es/utils/virtualization.js +63 -0
- package/package.json +7 -3
- package/src/ConfirmDialog/ConfirmDialog.stories.tsx +35 -0
- package/src/ConfirmDialog/index.tsx +50 -0
- package/src/CopyButton/index.tsx +6 -6
- package/src/FieldTypeColor/FieldTypeColor.stories.tsx +35 -0
- package/src/FieldTypeColor/index.tsx +43 -0
- package/src/FieldTypeDate/FieldTypeDate.stories.tsx +23 -0
- package/src/FieldTypeDate/index.tsx +34 -0
- package/src/FieldTypeDateTime/FieldTypeDateTime.stories.tsx +23 -0
- package/src/FieldTypeDateTime/index.tsx +35 -0
- package/src/FieldTypeDropdown/FieldTypeDropwdon.stories.tsx +52 -0
- package/src/FieldTypeDropdown/index.tsx +41 -0
- package/src/FieldTypeNumber/FieldTypeNumber.stories.tsx +35 -0
- package/src/FieldTypeNumber/index.tsx +22 -0
- package/src/FieldTypeOneToMany/FieldTypeOneToMany.stories.tsx +47 -0
- package/src/FieldTypeOneToMany/index.tsx +90 -0
- package/src/FieldTypeOneToOne/FieldTypeOneToOne.stories.tsx +46 -0
- package/src/FieldTypeOneToOne/index.tsx +96 -0
- package/src/FieldTypeSort/FieldTypeSort.stories.tsx +3 -2
- package/src/FieldTypeSort/index.tsx +15 -68
- package/src/FieldTypeText/FieldTypeText.stories.tsx +11 -9
- package/src/FieldTypeText/index.tsx +11 -19
- package/src/FieldTypeUrl/index.tsx +12 -19
- package/src/index.ts +11 -0
- package/src/theme/index.ts +15 -2
- package/src/utils/virtualization.tsx +107 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ChangeEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import FieldTypeDropdown, { FieldTypeDropdownProps } from './';
|
|
4
|
+
import { MenuItem } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'FieldTypeDropdown',
|
|
8
|
+
component: FieldTypeDropdown,
|
|
9
|
+
argType: {},
|
|
10
|
+
} as Meta;
|
|
11
|
+
|
|
12
|
+
const options = [
|
|
13
|
+
{
|
|
14
|
+
value: 'option1',
|
|
15
|
+
label: 'Option 1',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: 'option2',
|
|
19
|
+
label: 'Option 2',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: 'option3',
|
|
23
|
+
label: 'Option 3',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const Template: Story<FieldTypeDropdownProps> = (args) => {
|
|
28
|
+
const [value, setValue] = useState('');
|
|
29
|
+
|
|
30
|
+
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
31
|
+
setValue(e.target.value);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<FieldTypeDropdown
|
|
36
|
+
{...args}
|
|
37
|
+
value={value}
|
|
38
|
+
onChange={handleOnChange}
|
|
39
|
+
options={options}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const Default = Template.bind({});
|
|
45
|
+
Default.args = {
|
|
46
|
+
placeholder: 'Placeholder Text...',
|
|
47
|
+
label: 'Dropdown label',
|
|
48
|
+
helperText: 'Dropdown helper text',
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { MenuItem } from '@mui/material';
|
|
2
|
+
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
|
+
import { FormControl, FormLabel } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
interface Option {
|
|
6
|
+
label: string;
|
|
7
|
+
value: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FieldTypeDropdownProps extends Omit<OutlinedTextFieldProps, 'variant'> {
|
|
11
|
+
options: Option[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const FieldTypeDropdown = ({label, options, required, ...props }: FieldTypeDropdownProps) => {
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<FormControl fullWidth required={required}>
|
|
18
|
+
<FormLabel>{label}</FormLabel>
|
|
19
|
+
<MuiTextField
|
|
20
|
+
size="small"
|
|
21
|
+
variant='outlined'
|
|
22
|
+
select
|
|
23
|
+
SelectProps={{
|
|
24
|
+
displayEmpty: true,
|
|
25
|
+
}}
|
|
26
|
+
{...props}
|
|
27
|
+
>
|
|
28
|
+
<MenuItem key={''} value={''}>
|
|
29
|
+
- None -
|
|
30
|
+
</MenuItem>
|
|
31
|
+
{options.map((option) => (
|
|
32
|
+
<MenuItem key={option.value} value={option.value}>
|
|
33
|
+
{option.label}
|
|
34
|
+
</MenuItem>
|
|
35
|
+
))}
|
|
36
|
+
</MuiTextField>
|
|
37
|
+
</FormControl>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default FieldTypeDropdown;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ChangeEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import FieldTypeNumber, { FieldTypeNumberProps } from './';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'FieldTypeNumber',
|
|
7
|
+
component: FieldTypeNumber,
|
|
8
|
+
argType: {},
|
|
9
|
+
} as Meta;
|
|
10
|
+
|
|
11
|
+
const Template: Story<FieldTypeNumberProps> = (args) => {
|
|
12
|
+
const [value, setValue] = useState('0');
|
|
13
|
+
|
|
14
|
+
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
15
|
+
setValue(e.target.value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<FieldTypeNumber
|
|
20
|
+
{...args}
|
|
21
|
+
value={value}
|
|
22
|
+
onChange={handleOnChange}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Default = Template.bind({});
|
|
28
|
+
Default.args = {
|
|
29
|
+
placeholder: 'Placeholder Text...',
|
|
30
|
+
label: 'Number label',
|
|
31
|
+
helperText: 'Number helper text',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FormControl, FormLabel } from '@mui/material';
|
|
2
|
+
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
|
+
|
|
4
|
+
export interface FieldTypeNumberProps extends Omit<OutlinedTextFieldProps, 'variant'> {}
|
|
5
|
+
|
|
6
|
+
const FieldTypeText = ({label, required, ...props }: FieldTypeNumberProps) => {
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<FormControl fullWidth required={required}>
|
|
10
|
+
<FormLabel>{label}</FormLabel>
|
|
11
|
+
<MuiTextField
|
|
12
|
+
size="small"
|
|
13
|
+
variant='outlined'
|
|
14
|
+
type='number'
|
|
15
|
+
// Spread props at the end to allow prop overrides
|
|
16
|
+
{...props}
|
|
17
|
+
/>
|
|
18
|
+
</FormControl>
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default FieldTypeText;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ReactNode, SyntheticEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import FieldTypeOneToMany, { FieldTypeOneToManyProps } from '.';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'FieldTypeOneToMany',
|
|
7
|
+
component: FieldTypeOneToMany,
|
|
8
|
+
argType: {},
|
|
9
|
+
} as Meta;
|
|
10
|
+
|
|
11
|
+
const Template: Story<FieldTypeOneToManyProps> = (args) => {
|
|
12
|
+
const [value, setValue] = useState<{component: string | ReactNode, value: string, inputLabel: string}[]>([]);
|
|
13
|
+
|
|
14
|
+
const [options, setOptions] = useState<{component: string | ReactNode, value: string, inputLabel: string}[]>([]);
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const handleOnOpen = async () => {
|
|
18
|
+
const largeArr = new Array(1000).fill(null);
|
|
19
|
+
await new Promise((resolve) => setTimeout(resolve, 3000))
|
|
20
|
+
const data = largeArr.map((_, idx) => ({component: <div>{`Test ${idx}`}</div>, value: String(Math.random()), inputLabel: `Test ${idx}`}));
|
|
21
|
+
setOptions(data);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const handleOnChange = (e: SyntheticEvent<Element, Event>, values: {component: string | ReactNode, value: string, inputLabel: string}[]) => {
|
|
25
|
+
setValue(values);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<FieldTypeOneToMany
|
|
30
|
+
{...args}
|
|
31
|
+
value={value}
|
|
32
|
+
onChange={handleOnChange}
|
|
33
|
+
options={options}
|
|
34
|
+
onOpen={handleOnOpen}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const Default = Template.bind({});
|
|
40
|
+
Default.args = {
|
|
41
|
+
placeholder: 'Placeholder Text...',
|
|
42
|
+
label: 'OneToMany label',
|
|
43
|
+
helperText: 'OneToMany helperText',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ReactNode, useState } from 'react';
|
|
2
|
+
import { AutocompleteProps, FormControl, FormLabel, Popper, styled, TextField, TextFieldProps } from '@mui/material';
|
|
3
|
+
import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete';
|
|
4
|
+
import { ListboxComponent } from '../utils/virtualization';
|
|
5
|
+
|
|
6
|
+
export interface FieldTypeOneToManyProps extends Omit<AutocompleteProps<any, false, false, false>, 'onOpen' | 'renderInput'> {
|
|
7
|
+
label?: string;
|
|
8
|
+
helperText?: string;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
error?: boolean;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Callback to be fired upon opening the dropdown
|
|
14
|
+
*/
|
|
15
|
+
onOpen: () => Promise<any>;
|
|
16
|
+
/**
|
|
17
|
+
* Structure for option
|
|
18
|
+
*/
|
|
19
|
+
options: {
|
|
20
|
+
/**
|
|
21
|
+
* Component to be rendered in the dropdown
|
|
22
|
+
*/
|
|
23
|
+
component: ReactNode | string;
|
|
24
|
+
/**
|
|
25
|
+
* Value of option
|
|
26
|
+
*/
|
|
27
|
+
value: string;
|
|
28
|
+
/**
|
|
29
|
+
* Label that should display in the input when selected
|
|
30
|
+
*/
|
|
31
|
+
inputLabel: string;
|
|
32
|
+
}[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const FieldTypeOneToMany = ({label, helperText, placeholder, error, onOpen, options, required, ...props }: FieldTypeOneToManyProps) => {
|
|
36
|
+
const [loaded, setLoaded] = useState(false);
|
|
37
|
+
const [loading, setLoading] = useState(false);
|
|
38
|
+
|
|
39
|
+
const handleOpen = () => {
|
|
40
|
+
if (!loaded && onOpen) {
|
|
41
|
+
onOpen().then(() => {
|
|
42
|
+
setLoading(false);
|
|
43
|
+
});
|
|
44
|
+
setLoading(true);
|
|
45
|
+
setLoaded(true);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<FormControl fullWidth required={required}>
|
|
51
|
+
<FormLabel>{label}</FormLabel>
|
|
52
|
+
<Autocomplete
|
|
53
|
+
onOpen={handleOpen}
|
|
54
|
+
loading={loading}
|
|
55
|
+
fullWidth
|
|
56
|
+
multiple
|
|
57
|
+
disableListWrap
|
|
58
|
+
disableClearable
|
|
59
|
+
disablePortal
|
|
60
|
+
size='small'
|
|
61
|
+
PopperComponent={StyledPopper}
|
|
62
|
+
ListboxComponent={ListboxComponent}
|
|
63
|
+
renderInput={(params) => (
|
|
64
|
+
<TextField
|
|
65
|
+
{...params}
|
|
66
|
+
helperText={helperText}
|
|
67
|
+
error={error}
|
|
68
|
+
placeholder={placeholder}
|
|
69
|
+
/>
|
|
70
|
+
)}
|
|
71
|
+
options={loading ? [] : options}
|
|
72
|
+
getOptionLabel={(option) => option.inputLabel}
|
|
73
|
+
renderOption={(props, option) => [props, option.component]}
|
|
74
|
+
{...props}
|
|
75
|
+
/>
|
|
76
|
+
</FormControl>
|
|
77
|
+
);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default FieldTypeOneToMany;
|
|
81
|
+
|
|
82
|
+
const StyledPopper = styled(Popper)({
|
|
83
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
84
|
+
boxSizing: 'border-box',
|
|
85
|
+
'& ul': {
|
|
86
|
+
padding: 0,
|
|
87
|
+
margin: 0,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactNode, SyntheticEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import FieldTypeOneToOne, { FieldTypeOneToOneProps } from './';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'FieldTypeOneToOne',
|
|
7
|
+
component: FieldTypeOneToOne,
|
|
8
|
+
argType: {},
|
|
9
|
+
} as Meta;
|
|
10
|
+
|
|
11
|
+
const Template: Story<FieldTypeOneToOneProps> = (args) => {
|
|
12
|
+
const [value, setValue] = useState<{component: string | ReactNode, value: string, inputLabel: string}>({component: '- None -', value: '0', inputLabel: '- None -'});
|
|
13
|
+
|
|
14
|
+
const [options, setOptions] = useState<{component: string | ReactNode, value: string, inputLabel: string}[]>([]);
|
|
15
|
+
|
|
16
|
+
const handleOnOpen = async () => {
|
|
17
|
+
const largeArr = new Array(1000).fill(null);
|
|
18
|
+
await new Promise((resolve) => setTimeout(resolve, 3000))
|
|
19
|
+
const data = largeArr.map((_, idx) => ({component: <div>{`Test ${idx}`}</div>, value: String(Math.random()), inputLabel: `Test ${idx}`}));
|
|
20
|
+
setOptions(data);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const handleOnChange = (e: SyntheticEvent<Element, Event>, option: {component: string | ReactNode, value: string, inputLabel: string}) => {
|
|
24
|
+
setValue(option);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<FieldTypeOneToOne
|
|
29
|
+
{...args}
|
|
30
|
+
value={value}
|
|
31
|
+
onChange={handleOnChange}
|
|
32
|
+
options={options}
|
|
33
|
+
onOpen={handleOnOpen}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Default = Template.bind({});
|
|
39
|
+
Default.args = {
|
|
40
|
+
label: 'OneToOne label',
|
|
41
|
+
helperText: 'OneToOne helperText',
|
|
42
|
+
placeholder: 'OneToOne placeholder'
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ReactNode, useState } from 'react';
|
|
2
|
+
import { AutocompleteProps, Popper, styled, TextField, FormLabel, FormControl, InputAdornment } from '@mui/material';
|
|
3
|
+
import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete';
|
|
4
|
+
import { ListboxComponent } from '../utils/virtualization';
|
|
5
|
+
|
|
6
|
+
export interface FieldTypeOneToOneProps extends Omit<AutocompleteProps<any, false, false, false>, 'onOpen' | 'renderInput'> {
|
|
7
|
+
label?: string;
|
|
8
|
+
helperText?: string;
|
|
9
|
+
placeholder?: string;
|
|
10
|
+
error?: boolean;
|
|
11
|
+
required?: boolean;
|
|
12
|
+
startAdornment?: ReactNode;
|
|
13
|
+
endAdornment?: ReactNode;
|
|
14
|
+
/**
|
|
15
|
+
* Callback to be fired upon opening the dropdown
|
|
16
|
+
*/
|
|
17
|
+
onOpen?: () => Promise<any>;
|
|
18
|
+
/**
|
|
19
|
+
* Structure for option
|
|
20
|
+
*/
|
|
21
|
+
options: {
|
|
22
|
+
/**
|
|
23
|
+
* Component to be rendered in the dropdown
|
|
24
|
+
*/
|
|
25
|
+
component: ReactNode | string;
|
|
26
|
+
/**
|
|
27
|
+
* Value of option
|
|
28
|
+
*/
|
|
29
|
+
value: string;
|
|
30
|
+
/**
|
|
31
|
+
* Label that should display in the input when selected
|
|
32
|
+
*/
|
|
33
|
+
inputLabel: string;
|
|
34
|
+
}[]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const FieldTypeOneToOne = ({label, helperText, placeholder, error, onOpen, options, required, startAdornment, endAdornment, ...props }: FieldTypeOneToOneProps) => {
|
|
38
|
+
const [loaded, setLoaded] = useState(false);
|
|
39
|
+
const [loading, setLoading] = useState(false);
|
|
40
|
+
|
|
41
|
+
const handleOpen = () => {
|
|
42
|
+
if (!loaded && onOpen) {
|
|
43
|
+
onOpen().then(() => {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
});
|
|
46
|
+
setLoading(true);
|
|
47
|
+
setLoaded(true);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<FormControl fullWidth required={required}>
|
|
53
|
+
<FormLabel>{label}</FormLabel>
|
|
54
|
+
<Autocomplete
|
|
55
|
+
onOpen={handleOpen}
|
|
56
|
+
loading={loading}
|
|
57
|
+
fullWidth
|
|
58
|
+
disableListWrap
|
|
59
|
+
disableClearable
|
|
60
|
+
disablePortal
|
|
61
|
+
size='small'
|
|
62
|
+
PopperComponent={StyledPopper}
|
|
63
|
+
ListboxComponent={ListboxComponent}
|
|
64
|
+
renderInput={(params) => (
|
|
65
|
+
<TextField
|
|
66
|
+
{...params}
|
|
67
|
+
helperText={helperText}
|
|
68
|
+
error={error}
|
|
69
|
+
placeholder={placeholder}
|
|
70
|
+
InputProps={{
|
|
71
|
+
...params.InputProps,
|
|
72
|
+
startAdornment: <InputAdornment position='end'>{startAdornment}</InputAdornment>,
|
|
73
|
+
endAdornment: <>{params.InputProps.endAdornment}<InputAdornment sx={{ position: 'relative', right: '40px'}} position='end'>{endAdornment}</InputAdornment></>
|
|
74
|
+
}}
|
|
75
|
+
/>
|
|
76
|
+
)}
|
|
77
|
+
options={loading ? [] : options}
|
|
78
|
+
getOptionLabel={(option) => option.inputLabel}
|
|
79
|
+
renderOption={(props, option) => [props, option.component]}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
</FormControl>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default FieldTypeOneToOne;
|
|
87
|
+
|
|
88
|
+
const StyledPopper = styled(Popper)({
|
|
89
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
90
|
+
boxSizing: 'border-box',
|
|
91
|
+
'& ul': {
|
|
92
|
+
padding: 0,
|
|
93
|
+
margin: 0,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ChangeEvent, useState } from 'react';
|
|
2
2
|
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
-
import { TextFieldProps } from '@mui/material';
|
|
4
3
|
import FieldTypeSort, { FieldTypeSortProps } from './';
|
|
5
4
|
|
|
6
5
|
export default {
|
|
@@ -28,7 +27,9 @@ const Template: Story<FieldTypeSortProps> = (args) => {
|
|
|
28
27
|
export const Default = Template.bind({});
|
|
29
28
|
Default.args = {
|
|
30
29
|
placeholder: 'Placeholder Text...',
|
|
31
|
-
label: '
|
|
30
|
+
label: 'Sort label',
|
|
31
|
+
helperText: 'Sort helper text',
|
|
32
|
+
error: false,
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React, { ChangeEvent, ReactNode, useCallback, useEffect, useRef, useState } from 'react';
|
|
2
1
|
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
|
-
import { Button, InputAdornment } from '@mui/material';
|
|
2
|
+
import { Button, FormControl, FormLabel, InputAdornment } from '@mui/material';
|
|
4
3
|
import AddIcon from '@mui/icons-material/Add';
|
|
5
4
|
import RemoveIcon from '@mui/icons-material/Remove';
|
|
6
5
|
|
|
@@ -8,29 +7,26 @@ export interface FieldTypeSortProps extends Omit<OutlinedTextFieldProps, 'varian
|
|
|
8
7
|
value: string;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
const FieldTypeSort = ({value, InputProps,
|
|
12
|
-
const inputRef = useRef<HTMLInputElement>(null);
|
|
13
|
-
|
|
10
|
+
const FieldTypeSort = ({label, value, InputProps, required, ...props }: FieldTypeSortProps) => {
|
|
14
11
|
return (
|
|
12
|
+
<FormControl fullWidth required={required}>
|
|
13
|
+
<FormLabel>{label}</FormLabel>
|
|
15
14
|
<MuiTextField
|
|
16
15
|
size="small"
|
|
17
16
|
variant='outlined'
|
|
18
17
|
type='number'
|
|
19
18
|
value={value}
|
|
20
|
-
sx={{
|
|
21
|
-
width: 165,
|
|
22
|
-
// Spread props at the end to allow sx prop overrides
|
|
23
|
-
...sx
|
|
24
|
-
}}
|
|
25
19
|
InputProps={{
|
|
26
20
|
startAdornment: (
|
|
27
21
|
<InputAdornment position="start">
|
|
28
22
|
<Button
|
|
29
23
|
size="small"
|
|
30
24
|
variant="contained"
|
|
31
|
-
onClick={() => {
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
onClick={(e) => {
|
|
26
|
+
// References input via event in order to modify its value
|
|
27
|
+
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1] as HTMLInputElement;
|
|
28
|
+
input.value = String(+input.value - 1)
|
|
29
|
+
}}><RemoveIcon fontSize='small' />
|
|
34
30
|
</Button>
|
|
35
31
|
</InputAdornment>
|
|
36
32
|
),
|
|
@@ -39,71 +35,22 @@ const FieldTypeSort = ({value, InputProps, InputLabelProps, inputProps, sx, ...p
|
|
|
39
35
|
<Button
|
|
40
36
|
size="small"
|
|
41
37
|
variant="contained"
|
|
42
|
-
onClick={() => {
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
onClick={(e) => {
|
|
39
|
+
// References input via event in order to modify its value
|
|
40
|
+
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1] as HTMLInputElement;
|
|
41
|
+
input.value = String(+input.value + 1)
|
|
42
|
+
}}><AddIcon fontSize='small' />
|
|
45
43
|
</Button>
|
|
46
44
|
</InputAdornment>
|
|
47
45
|
),
|
|
48
46
|
// Spread props at the end to allow Input prop overrides
|
|
49
47
|
...InputProps,
|
|
50
48
|
}}
|
|
51
|
-
InputLabelProps={{
|
|
52
|
-
shrink: true,
|
|
53
|
-
// Spread props at the end to allow InputLabel prop overrides
|
|
54
|
-
...InputLabelProps,
|
|
55
|
-
}}
|
|
56
|
-
inputProps={{
|
|
57
|
-
ref: inputRef,
|
|
58
|
-
// Spread props at the end to allow inputProps prop overrides
|
|
59
|
-
...inputProps,
|
|
60
|
-
}}
|
|
61
49
|
// Spread props at the end to allow prop overrides
|
|
62
50
|
{...props}
|
|
63
51
|
/>
|
|
52
|
+
</FormControl>
|
|
64
53
|
);
|
|
65
54
|
};
|
|
66
55
|
|
|
67
56
|
export default FieldTypeSort;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// const FieldTypeSort = ({InputProps, InputLabelProps, ...props }: FieldTypeSortProps) => {
|
|
71
|
-
|
|
72
|
-
// return (
|
|
73
|
-
// <MuiTextField
|
|
74
|
-
// variant='outlined'
|
|
75
|
-
// type='number'
|
|
76
|
-
// InputProps={{
|
|
77
|
-
// startAdornment: (
|
|
78
|
-
// <InputAdornment position="start">
|
|
79
|
-
// <Button
|
|
80
|
-
// variant="contained"
|
|
81
|
-
// onClick={() => {
|
|
82
|
-
// callback(props.value + 1)
|
|
83
|
-
// }}>+</Button>
|
|
84
|
-
// </InputAdornment>
|
|
85
|
-
// ),
|
|
86
|
-
// endAdornment: (
|
|
87
|
-
// <InputAdornment position="end">
|
|
88
|
-
// <Button
|
|
89
|
-
// variant="contained"
|
|
90
|
-
// onClick={() => {
|
|
91
|
-
// callback(props.value - 1)
|
|
92
|
-
// }}>-</Button>
|
|
93
|
-
// </InputAdornment>
|
|
94
|
-
// ),
|
|
95
|
-
// // Spread props at the end to allow Input prop overrides
|
|
96
|
-
// ...InputProps,
|
|
97
|
-
// }}
|
|
98
|
-
// InputLabelProps={{
|
|
99
|
-
// shrink: true,
|
|
100
|
-
// // Spread props at the end to allow InputLabel prop overrides
|
|
101
|
-
// ...InputLabelProps,
|
|
102
|
-
// }}
|
|
103
|
-
// // Spread props at the end to allow prop overrides
|
|
104
|
-
// {...props}
|
|
105
|
-
// />
|
|
106
|
-
// );
|
|
107
|
-
// };
|
|
108
|
-
|
|
109
|
-
// export default FieldTypeSort;
|
|
@@ -16,19 +16,21 @@ const Template: Story<FieldTypeTextProps> = (args) => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
<>
|
|
20
|
+
<FieldTypeText
|
|
21
|
+
{...args}
|
|
22
|
+
value={value}
|
|
23
|
+
onChange={handleOnChange}
|
|
24
|
+
/>
|
|
25
|
+
</>
|
|
24
26
|
);
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
export const Default = Template.bind({});
|
|
28
30
|
Default.args = {
|
|
29
31
|
placeholder: 'Placeholder Text...',
|
|
30
|
-
label: '
|
|
31
|
-
|
|
32
|
+
label: 'Text label',
|
|
33
|
+
helperText: 'Text helper text',
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
export const TextArea = Template.bind({});
|
|
@@ -36,8 +38,8 @@ TextArea.args = {
|
|
|
36
38
|
multiline: true,
|
|
37
39
|
rows: 4,
|
|
38
40
|
placeholder: 'Placeholder Text...',
|
|
39
|
-
label: '
|
|
40
|
-
|
|
41
|
+
label: 'Text Label',
|
|
42
|
+
helperText: 'Text helper text',
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React, { ChangeEvent, ReactNode, useEffect, useRef, useState } from 'react';
|
|
2
1
|
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
|
-
import {
|
|
2
|
+
import { FormControl, FormLabel, Box } from '@mui/material';
|
|
4
3
|
|
|
5
4
|
export interface FieldTypeTextProps extends Omit<OutlinedTextFieldProps, 'variant'> {
|
|
6
5
|
/**
|
|
@@ -11,32 +10,25 @@ export interface FieldTypeTextProps extends Omit<OutlinedTextFieldProps, 'varian
|
|
|
11
10
|
value: string;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
const FieldTypeText = ({maxLength = 150, value, helperText,
|
|
13
|
+
const FieldTypeText = ({label, maxLength = 150, value, helperText, required, ...props }: FieldTypeTextProps) => {
|
|
15
14
|
|
|
16
15
|
return (
|
|
16
|
+
<FormControl fullWidth required={required}>
|
|
17
|
+
{/* Sets flex order to make appended required asterisk properly positioned */}
|
|
18
|
+
<FormLabel sx={{display: 'flex', justifyContent: 'space-between', '& .MuiFormLabel-asterisk': {order: 2}}}>
|
|
19
|
+
<Box sx={{ order: 1}}>{label}</Box>
|
|
20
|
+
<Box sx={{ order: 3, flex: 1, textAlign: 'right'}}>{value?.length}/{maxLength}</Box>
|
|
21
|
+
</FormLabel>
|
|
17
22
|
<MuiTextField
|
|
18
23
|
size="small"
|
|
19
24
|
variant='outlined'
|
|
20
25
|
value={value}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<InputAdornment position="end">
|
|
24
|
-
<>{value.length}/{maxLength}</>
|
|
25
|
-
</InputAdornment>
|
|
26
|
-
),
|
|
27
|
-
// Spread props at the end to allow Input prop overrides
|
|
28
|
-
...InputProps,
|
|
29
|
-
}}
|
|
30
|
-
InputLabelProps={{
|
|
31
|
-
shrink: true,
|
|
32
|
-
// Spread props at the end to allow InputLabel prop overrides
|
|
33
|
-
...InputLabelProps,
|
|
34
|
-
}}
|
|
35
|
-
error={value.length > maxLength}
|
|
36
|
-
helperText={value.length > maxLength ? 'Your input is over the specified limit' : helperText}
|
|
26
|
+
error={value?.length > maxLength}
|
|
27
|
+
helperText={value?.length > maxLength ? 'Your input is over the specified limit' : helperText}
|
|
37
28
|
// Spread props at the end to allow prop overrides
|
|
38
29
|
{...props}
|
|
39
30
|
/>
|
|
31
|
+
</FormControl>
|
|
40
32
|
);
|
|
41
33
|
};
|
|
42
34
|
|