@zesty-io/material 0.1.4 → 0.2.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/FieldTypeDate/index.d.ts +2 -2
- package/es/FieldTypeDate/index.js +2 -2
- package/es/FieldTypeDateTime/index.d.ts +2 -2
- package/es/FieldTypeDateTime/index.js +2 -2
- package/es/FieldTypeSort/index.d.ts +1 -1
- package/es/FieldTypeSort/index.js +18 -6
- package/es/FieldTypeUrl/index.js +5 -4
- package/es/VitualizedAutocomplete/VirtualizedAutocomplete.stories.d.ts +5 -0
- package/es/VitualizedAutocomplete/VirtualizedAutocomplete.stories.js +27 -0
- package/es/VitualizedAutocomplete/index.d.ts +28 -0
- package/es/VitualizedAutocomplete/index.js +21 -0
- package/es/index.d.ts +1 -1
- package/es/index.js +1 -1
- package/es/theme/index.js +7 -0
- package/package.json +1 -1
- package/src/FieldTypeDate/index.tsx +4 -3
- package/src/FieldTypeDateTime/index.tsx +5 -4
- package/src/FieldTypeSort/index.tsx +19 -5
- package/src/FieldTypeUrl/index.tsx +6 -5
- package/src/VitualizedAutocomplete/VirtualizedAutocomplete.stories.tsx +45 -0
- package/src/VitualizedAutocomplete/index.tsx +69 -0
- package/src/index.ts +2 -2
- package/src/theme/index.ts +7 -0
- package/zesty-io-material-0.1.2.tgz +0 -0
- package/src/FieldTypeDropdown/FieldTypeDropwdon.stories.tsx +0 -52
- package/src/FieldTypeDropdown/index.tsx +0 -41
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
3
|
-
export interface FieldTypeDateProps extends Omit<
|
|
2
|
+
import { DesktopDatePickerProps } from '@mui/x-date-pickers';
|
|
3
|
+
export interface FieldTypeDateProps extends Omit<DesktopDatePickerProps<Date, Date>, 'renderInput'> {
|
|
4
4
|
helperText?: string;
|
|
5
5
|
error?: boolean;
|
|
6
6
|
required?: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
3
3
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
4
|
-
import {
|
|
4
|
+
import { DesktopDatePicker } from '@mui/x-date-pickers';
|
|
5
5
|
import { FormControl, FormLabel, TextField } from '@mui/material';
|
|
6
6
|
;
|
|
7
7
|
const FieldTypeDate = ({ label, helperText, error, required, ...props }) => {
|
|
8
|
-
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(
|
|
8
|
+
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(DesktopDatePicker, { "data-testid": "zds-date-picker", renderInput: (params) => _jsx(TextField, { ...params, helperText: helperText, error: error, size: "small" }), ...props }) })] }));
|
|
9
9
|
};
|
|
10
10
|
export default FieldTypeDate;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import {
|
|
3
|
-
export interface FieldTypeDateTimeProps extends Omit<
|
|
2
|
+
import { DesktopDateTimePickerProps } from '@mui/x-date-pickers';
|
|
3
|
+
export interface FieldTypeDateTimeProps extends Omit<DesktopDateTimePickerProps<Date, Date>, 'renderInput'> {
|
|
4
4
|
helperText?: string;
|
|
5
5
|
error?: boolean;
|
|
6
6
|
required?: boolean;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
3
3
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
4
|
-
import {
|
|
4
|
+
import { DesktopDateTimePicker } from '@mui/x-date-pickers';
|
|
5
5
|
import { TextField, FormControl, FormLabel } from '@mui/material';
|
|
6
6
|
;
|
|
7
7
|
const FieldTypeDateTime = ({ label, helperText, error, required, ...props }) => {
|
|
8
|
-
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(
|
|
8
|
+
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(LocalizationProvider, { dateAdapter: AdapterDateFns, children: _jsx(DesktopDateTimePicker, { "data-testid": "zds-date-time-picker", renderInput: (params) => _jsx(TextField, { ...params, helperText: helperText, error: error, size: "small" }), ...props }) })] }));
|
|
9
9
|
};
|
|
10
10
|
export default FieldTypeDateTime;
|
|
@@ -3,5 +3,5 @@ import { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
|
3
3
|
export interface FieldTypeSortProps extends Omit<OutlinedTextFieldProps, 'variant'> {
|
|
4
4
|
value: string;
|
|
5
5
|
}
|
|
6
|
-
declare const FieldTypeSort: ({ label, value, InputProps, required, ...props }: FieldTypeSortProps) => JSX.Element;
|
|
6
|
+
declare const FieldTypeSort: ({ label, value, InputProps, required, onChange, ...props }: FieldTypeSortProps) => JSX.Element;
|
|
7
7
|
export default FieldTypeSort;
|
|
@@ -3,17 +3,29 @@ import MuiTextField from '@mui/material/TextField';
|
|
|
3
3
|
import { Button, FormControl, FormLabel, InputAdornment } from '@mui/material';
|
|
4
4
|
import AddIcon from '@mui/icons-material/Add';
|
|
5
5
|
import RemoveIcon from '@mui/icons-material/Remove';
|
|
6
|
-
const FieldTypeSort = ({ label, value, InputProps, required, ...props }) => {
|
|
7
|
-
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(MuiTextField, { size: "small", variant: 'outlined', type: 'number', value: value, InputProps: {
|
|
6
|
+
const FieldTypeSort = ({ label, value, InputProps, required, onChange, ...props }) => {
|
|
7
|
+
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsx(FormLabel, { children: label }), _jsx(MuiTextField, { size: "small", variant: 'outlined', type: 'number', value: value, onChange: onChange, InputProps: {
|
|
8
8
|
startAdornment: (_jsx(InputAdornment, { position: "start", children: _jsx(Button, { size: "small", variant: "contained", onClick: (e) => {
|
|
9
|
-
|
|
9
|
+
e.stopPropagation();
|
|
10
|
+
// References input via click event in order to obtain its value
|
|
10
11
|
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1];
|
|
11
|
-
|
|
12
|
+
const newValue = String(+input.value - 1);
|
|
13
|
+
// Updates internal input value in case component is not controlled
|
|
14
|
+
input.value = newValue;
|
|
15
|
+
// Mocks an event change
|
|
16
|
+
const event = { target: { value: newValue } };
|
|
17
|
+
onChange && onChange(event);
|
|
12
18
|
}, children: _jsx(RemoveIcon, { fontSize: 'small' }) }) })),
|
|
13
19
|
endAdornment: (_jsx(InputAdornment, { position: "end", children: _jsx(Button, { size: "small", variant: "contained", onClick: (e) => {
|
|
14
|
-
|
|
20
|
+
e.stopPropagation();
|
|
21
|
+
// References input via click event in order to obtain its value
|
|
15
22
|
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1];
|
|
16
|
-
|
|
23
|
+
const newValue = String(+input.value + 1);
|
|
24
|
+
// Updates internal input value in case component is not controlled
|
|
25
|
+
input.value = newValue;
|
|
26
|
+
// Mocks an event change
|
|
27
|
+
const event = { target: { value: newValue } };
|
|
28
|
+
onChange && onChange(event);
|
|
17
29
|
}, children: _jsx(AddIcon, { fontSize: 'small' }) }) })),
|
|
18
30
|
// Spread props at the end to allow Input prop overrides
|
|
19
31
|
...InputProps,
|
package/es/FieldTypeUrl/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
import MuiTextField from '@mui/material/TextField';
|
|
4
4
|
import { FormControl, FormLabel, Box } from '@mui/material';
|
|
5
5
|
const FieldTypeUrl = ({ label, maxLength = 2000, value, helperText, required, inputProps, ...props }) => {
|
|
6
|
-
|
|
6
|
+
// Use state to hold input reference to re-render once ref changes in case error needs to be shown on mount
|
|
7
|
+
const [inputRef, setInputRef] = useState();
|
|
7
8
|
return (_jsxs(FormControl, { fullWidth: true, required: required, children: [_jsxs(FormLabel, { sx: { display: 'flex', justifyContent: 'space-between', '& .MuiFormLabel-asterisk': { order: 2 } }, children: [_jsx(Box, { sx: { order: 1 }, children: label }), _jsxs(Box, { sx: { order: 3, flex: 1, textAlign: 'right' }, children: [value?.length, "/", maxLength] })] }), _jsx(MuiTextField, { size: "small", type: 'url', variant: 'outlined', value: value, inputProps: {
|
|
8
|
-
ref: inputRef,
|
|
9
|
+
ref: (inputRef) => setInputRef(inputRef),
|
|
9
10
|
// Spread props at the end to allow inputProps prop overrides
|
|
10
11
|
...inputProps,
|
|
11
|
-
}, error: (value && !inputRef
|
|
12
|
+
}, error: (value && !inputRef?.validity.valid) || value?.length > maxLength, helperText: value?.length > maxLength ? 'Your input is over the specified limit' : (value && !inputRef?.validity.valid) ? 'Your input is not a valid url' : helperText, ...props })] }));
|
|
12
13
|
};
|
|
13
14
|
export default FieldTypeUrl;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
2
|
+
import { VirtualizedAutocompleteProps } from './';
|
|
3
|
+
declare const _default: Meta<import("@storybook/react/types-6-0").Args>;
|
|
4
|
+
export default _default;
|
|
5
|
+
export declare const Default: Story<VirtualizedAutocompleteProps>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import VirtualizedAutocomplete from './';
|
|
4
|
+
export default {
|
|
5
|
+
title: 'VirtualizedAutocomplete',
|
|
6
|
+
component: VirtualizedAutocomplete,
|
|
7
|
+
argType: {},
|
|
8
|
+
};
|
|
9
|
+
const Template = (args) => {
|
|
10
|
+
const [value, setValue] = useState({ component: '- None -', value: '0', inputLabel: '- None -' });
|
|
11
|
+
const [options, setOptions] = useState([]);
|
|
12
|
+
const handleOnOpen = async () => {
|
|
13
|
+
const largeArr = new Array(1000).fill(null);
|
|
14
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
15
|
+
const data = largeArr.map((_, idx) => ({ component: _jsx("div", { children: `Test ${idx}` }), value: String(Math.random()), inputLabel: `Test ${idx}` }));
|
|
16
|
+
setOptions(data);
|
|
17
|
+
};
|
|
18
|
+
const handleOnChange = (e, option) => {
|
|
19
|
+
setValue(option);
|
|
20
|
+
};
|
|
21
|
+
return (_jsx(VirtualizedAutocomplete, { ...args, value: value, onChange: handleOnChange, options: options, onOpen: handleOnOpen }));
|
|
22
|
+
};
|
|
23
|
+
export const Default = Template.bind({});
|
|
24
|
+
Default.args = {
|
|
25
|
+
helperText: 'OneToOne helperText',
|
|
26
|
+
placeholder: 'OneToOne placeholder'
|
|
27
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AutocompleteProps } from '@mui/material';
|
|
3
|
+
export interface VirtualizedAutocompleteProps extends Omit<AutocompleteProps<any, false, false, false>, 'renderInput'> {
|
|
4
|
+
helperText?: string;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
error?: boolean;
|
|
7
|
+
startAdornment?: ReactNode;
|
|
8
|
+
endAdornment?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Structure for option
|
|
11
|
+
*/
|
|
12
|
+
options: {
|
|
13
|
+
/**
|
|
14
|
+
* Component to be rendered in the dropdown
|
|
15
|
+
*/
|
|
16
|
+
component: ReactNode | string;
|
|
17
|
+
/**
|
|
18
|
+
* Value of option
|
|
19
|
+
*/
|
|
20
|
+
value: string;
|
|
21
|
+
/**
|
|
22
|
+
* Label that should display in the input when selected
|
|
23
|
+
*/
|
|
24
|
+
inputLabel: string;
|
|
25
|
+
}[];
|
|
26
|
+
}
|
|
27
|
+
declare const VirtualizedAutocomplete: ({ helperText, placeholder, error, startAdornment, endAdornment, ...props }: VirtualizedAutocompleteProps) => JSX.Element;
|
|
28
|
+
export default VirtualizedAutocomplete;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Popper, styled, TextField, InputAdornment } from '@mui/material';
|
|
3
|
+
import Autocomplete, { autocompleteClasses } from '@mui/material/Autocomplete';
|
|
4
|
+
import { ListboxComponent } from '../utils/virtualization';
|
|
5
|
+
const VirtualizedAutocomplete = ({ helperText, placeholder, error, startAdornment, endAdornment, ...props }) => {
|
|
6
|
+
return (_jsx(Autocomplete, { fullWidth: true, disableListWrap: true, size: 'small', PopperComponent: StyledPopper, ListboxComponent: ListboxComponent, renderInput: (params) => (_jsx(TextField, { ...params, helperText: helperText, error: error, placeholder: placeholder, InputProps: {
|
|
7
|
+
...params.InputProps,
|
|
8
|
+
startAdornment: _jsx(InputAdornment, { position: 'end', children: startAdornment }),
|
|
9
|
+
endAdornment: _jsxs(_Fragment, { children: [params.InputProps.endAdornment, _jsx(InputAdornment, { sx: { position: 'relative', right: '40px' }, position: 'end', children: endAdornment })] })
|
|
10
|
+
} })), getOptionLabel: (option) => option.inputLabel, renderOption: (props, option) => [props, option.component], ...props }));
|
|
11
|
+
};
|
|
12
|
+
export default VirtualizedAutocomplete;
|
|
13
|
+
const StyledPopper = styled(Popper)({
|
|
14
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
15
|
+
boxSizing: 'border-box',
|
|
16
|
+
'& ul': {
|
|
17
|
+
padding: 0,
|
|
18
|
+
margin: 0,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
package/es/index.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export { default as FieldTypeDate } from './FieldTypeDate';
|
|
|
6
6
|
export { default as FieldTypeDateTime } from './FieldTypeDateTime';
|
|
7
7
|
export { default as FieldTypeColor } from './FieldTypeColor';
|
|
8
8
|
export { default as FieldTypeNumber } from './FieldTypeNumber';
|
|
9
|
-
export { default as FieldTypeDropdown } from './FieldTypeDropdown';
|
|
10
9
|
export { default as FieldTypeOneToOne } from './FieldTypeOneToOne';
|
|
11
10
|
export { default as FieldTypeOneToMany } from './FieldTypeOneToMany';
|
|
12
11
|
export { default as CopyButton } from './CopyButton';
|
|
13
12
|
export { default as ConfirmDialog } from './ConfirmDialog';
|
|
13
|
+
export { default as VirtualizedAutocomplete } from './VitualizedAutocomplete';
|
package/es/index.js
CHANGED
|
@@ -6,8 +6,8 @@ export { default as FieldTypeDate } from './FieldTypeDate';
|
|
|
6
6
|
export { default as FieldTypeDateTime } from './FieldTypeDateTime';
|
|
7
7
|
export { default as FieldTypeColor } from './FieldTypeColor';
|
|
8
8
|
export { default as FieldTypeNumber } from './FieldTypeNumber';
|
|
9
|
-
export { default as FieldTypeDropdown } from './FieldTypeDropdown';
|
|
10
9
|
export { default as FieldTypeOneToOne } from './FieldTypeOneToOne';
|
|
11
10
|
export { default as FieldTypeOneToMany } from './FieldTypeOneToMany';
|
|
12
11
|
export { default as CopyButton } from './CopyButton';
|
|
13
12
|
export { default as ConfirmDialog } from './ConfirmDialog';
|
|
13
|
+
export { default as VirtualizedAutocomplete } from './VitualizedAutocomplete';
|
package/es/theme/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
2
2
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
3
|
-
import {
|
|
3
|
+
import { DesktopDatePicker, DesktopDatePickerProps } from '@mui/x-date-pickers';
|
|
4
4
|
import { FormControl, FormLabel, TextField } from '@mui/material';
|
|
5
5
|
|
|
6
|
-
export interface FieldTypeDateProps extends Omit<
|
|
6
|
+
export interface FieldTypeDateProps extends Omit<DesktopDatePickerProps<Date, Date>, 'renderInput'> {
|
|
7
7
|
helperText?: string;
|
|
8
8
|
error?: boolean;
|
|
9
9
|
required?: boolean;
|
|
@@ -14,13 +14,14 @@ const FieldTypeDate = ({label, helperText, error, required, ...props}: FieldType
|
|
|
14
14
|
<FormControl fullWidth required={required}>
|
|
15
15
|
<FormLabel>{label}</FormLabel>
|
|
16
16
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
|
17
|
-
<
|
|
17
|
+
<DesktopDatePicker
|
|
18
18
|
data-testid="zds-date-picker"
|
|
19
19
|
renderInput={(params) =>
|
|
20
20
|
<TextField
|
|
21
21
|
{...params}
|
|
22
22
|
helperText={helperText}
|
|
23
23
|
error={error}
|
|
24
|
+
size="small"
|
|
24
25
|
/>
|
|
25
26
|
}
|
|
26
27
|
// Spread props at the end to allow prop overrides
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
|
|
2
2
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
3
|
-
import {
|
|
3
|
+
import { DesktopDateTimePicker, DesktopDateTimePickerProps } from '@mui/x-date-pickers';
|
|
4
4
|
import { TextField, FormControl, FormLabel } from '@mui/material';
|
|
5
5
|
|
|
6
|
-
export interface FieldTypeDateTimeProps extends Omit<
|
|
6
|
+
export interface FieldTypeDateTimeProps extends Omit<DesktopDateTimePickerProps<Date, Date>, 'renderInput'> {
|
|
7
7
|
helperText?: string;
|
|
8
8
|
error?: boolean;
|
|
9
9
|
required?: boolean;
|
|
@@ -14,14 +14,15 @@ const FieldTypeDateTime = ({label, helperText, error, required, ...props}: Field
|
|
|
14
14
|
<FormControl fullWidth required={required}>
|
|
15
15
|
<FormLabel>{label}</FormLabel>
|
|
16
16
|
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
|
17
|
-
<
|
|
18
|
-
data-testid="zds-date-picker"
|
|
17
|
+
<DesktopDateTimePicker
|
|
18
|
+
data-testid="zds-date-time-picker"
|
|
19
19
|
renderInput={(params) =>
|
|
20
20
|
<TextField
|
|
21
21
|
|
|
22
22
|
{...params}
|
|
23
23
|
helperText={helperText}
|
|
24
24
|
error={error}
|
|
25
|
+
size="small"
|
|
25
26
|
/>
|
|
26
27
|
}
|
|
27
28
|
// Spread props at the end to allow prop overrides
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ChangeEvent } from 'react';
|
|
1
2
|
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
2
3
|
import { Button, FormControl, FormLabel, InputAdornment } from '@mui/material';
|
|
3
4
|
import AddIcon from '@mui/icons-material/Add';
|
|
@@ -7,7 +8,7 @@ export interface FieldTypeSortProps extends Omit<OutlinedTextFieldProps, 'varian
|
|
|
7
8
|
value: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
const FieldTypeSort = ({label, value, InputProps, required, ...props }: FieldTypeSortProps) => {
|
|
11
|
+
const FieldTypeSort = ({label, value, InputProps, required, onChange, ...props }: FieldTypeSortProps) => {
|
|
11
12
|
return (
|
|
12
13
|
<FormControl fullWidth required={required}>
|
|
13
14
|
<FormLabel>{label}</FormLabel>
|
|
@@ -16,6 +17,7 @@ const FieldTypeSort = ({label, value, InputProps, required, ...props }: FieldTyp
|
|
|
16
17
|
variant='outlined'
|
|
17
18
|
type='number'
|
|
18
19
|
value={value}
|
|
20
|
+
onChange={onChange}
|
|
19
21
|
InputProps={{
|
|
20
22
|
startAdornment: (
|
|
21
23
|
<InputAdornment position="start">
|
|
@@ -23,9 +25,15 @@ const FieldTypeSort = ({label, value, InputProps, required, ...props }: FieldTyp
|
|
|
23
25
|
size="small"
|
|
24
26
|
variant="contained"
|
|
25
27
|
onClick={(e) => {
|
|
26
|
-
|
|
28
|
+
e.stopPropagation();
|
|
29
|
+
// References input via click event in order to obtain its value
|
|
27
30
|
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1] as HTMLInputElement;
|
|
28
|
-
|
|
31
|
+
const newValue = String(+input.value - 1)
|
|
32
|
+
// Updates internal input value in case component is not controlled
|
|
33
|
+
input.value = newValue
|
|
34
|
+
// Mocks an event change
|
|
35
|
+
const event = {target: {value: newValue}}
|
|
36
|
+
onChange && onChange(event as ChangeEvent<HTMLTextAreaElement | HTMLInputElement>);
|
|
29
37
|
}}><RemoveIcon fontSize='small' />
|
|
30
38
|
</Button>
|
|
31
39
|
</InputAdornment>
|
|
@@ -36,9 +44,15 @@ const FieldTypeSort = ({label, value, InputProps, required, ...props }: FieldTyp
|
|
|
36
44
|
size="small"
|
|
37
45
|
variant="contained"
|
|
38
46
|
onClick={(e) => {
|
|
39
|
-
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
// References input via click event in order to obtain its value
|
|
40
49
|
const input = e.currentTarget?.parentElement?.parentElement?.childNodes?.[1] as HTMLInputElement;
|
|
41
|
-
|
|
50
|
+
const newValue = String(+input.value + 1)
|
|
51
|
+
// Updates internal input value in case component is not controlled
|
|
52
|
+
input.value = newValue
|
|
53
|
+
// Mocks an event change
|
|
54
|
+
const event = {target: {value: newValue}}
|
|
55
|
+
onChange && onChange(event as ChangeEvent<HTMLTextAreaElement | HTMLInputElement>);
|
|
42
56
|
}}><AddIcon fontSize='small' />
|
|
43
57
|
</Button>
|
|
44
58
|
</InputAdornment>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useState } from 'react';
|
|
2
2
|
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
3
|
import { FormControl, FormLabel, Box } from '@mui/material';
|
|
4
4
|
|
|
@@ -12,7 +12,8 @@ export interface FieldTypeUrlProps extends Omit<OutlinedTextFieldProps, 'variant
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const FieldTypeUrl = ({label, maxLength = 2000, value, helperText, required, inputProps, ...props }: FieldTypeUrlProps) => {
|
|
15
|
-
|
|
15
|
+
// Use state to hold input reference to re-render once ref changes in case error needs to be shown on mount
|
|
16
|
+
const [inputRef, setInputRef] = useState<HTMLInputElement>();
|
|
16
17
|
|
|
17
18
|
return (
|
|
18
19
|
<FormControl fullWidth required={required}>
|
|
@@ -27,12 +28,12 @@ const FieldTypeUrl = ({label, maxLength = 2000, value, helperText, required, inp
|
|
|
27
28
|
variant='outlined'
|
|
28
29
|
value={value}
|
|
29
30
|
inputProps={{
|
|
30
|
-
ref: inputRef,
|
|
31
|
+
ref: (inputRef: HTMLInputElement) => setInputRef(inputRef),
|
|
31
32
|
// Spread props at the end to allow inputProps prop overrides
|
|
32
33
|
...inputProps,
|
|
33
34
|
}}
|
|
34
|
-
error={(value && !inputRef
|
|
35
|
-
helperText={value?.length > maxLength ? 'Your input is over the specified limit' : (value && !inputRef
|
|
35
|
+
error={(value && !inputRef?.validity.valid) || value?.length > maxLength}
|
|
36
|
+
helperText={value?.length > maxLength ? 'Your input is over the specified limit' : (value && !inputRef?.validity.valid) ? 'Your input is not a valid url' : helperText}
|
|
36
37
|
// Spread props at the end to allow prop overrides
|
|
37
38
|
{...props}
|
|
38
39
|
/>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ReactNode, SyntheticEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import VirtualizedAutocomplete, { VirtualizedAutocompleteProps } from './';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'VirtualizedAutocomplete',
|
|
7
|
+
component: VirtualizedAutocomplete,
|
|
8
|
+
argType: {},
|
|
9
|
+
} as Meta;
|
|
10
|
+
|
|
11
|
+
const Template: Story<VirtualizedAutocompleteProps> = (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
|
+
<VirtualizedAutocomplete
|
|
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
|
+
helperText: 'OneToOne helperText',
|
|
41
|
+
placeholder: 'OneToOne placeholder'
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
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 VirtualizedAutocompleteProps extends Omit<AutocompleteProps<any, false, false, false>, 'renderInput'> {
|
|
7
|
+
helperText?: string;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
error?: boolean;
|
|
10
|
+
startAdornment?: ReactNode;
|
|
11
|
+
endAdornment?: ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Structure for option
|
|
14
|
+
*/
|
|
15
|
+
options: {
|
|
16
|
+
/**
|
|
17
|
+
* Component to be rendered in the dropdown
|
|
18
|
+
*/
|
|
19
|
+
component: ReactNode | string;
|
|
20
|
+
/**
|
|
21
|
+
* Value of option
|
|
22
|
+
*/
|
|
23
|
+
value: string;
|
|
24
|
+
/**
|
|
25
|
+
* Label that should display in the input when selected
|
|
26
|
+
*/
|
|
27
|
+
inputLabel: string;
|
|
28
|
+
}[]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const VirtualizedAutocomplete = ({helperText, placeholder, error, startAdornment, endAdornment, ...props }: VirtualizedAutocompleteProps) => {
|
|
32
|
+
return (
|
|
33
|
+
<Autocomplete
|
|
34
|
+
fullWidth
|
|
35
|
+
disableListWrap
|
|
36
|
+
size='small'
|
|
37
|
+
PopperComponent={StyledPopper}
|
|
38
|
+
ListboxComponent={ListboxComponent}
|
|
39
|
+
renderInput={(params) => (
|
|
40
|
+
<TextField
|
|
41
|
+
{...params}
|
|
42
|
+
helperText={helperText}
|
|
43
|
+
error={error}
|
|
44
|
+
placeholder={placeholder}
|
|
45
|
+
InputProps={{
|
|
46
|
+
...params.InputProps,
|
|
47
|
+
startAdornment: <InputAdornment position='end'>{startAdornment}</InputAdornment>,
|
|
48
|
+
endAdornment: <>{params.InputProps.endAdornment}<InputAdornment sx={{ position: 'relative', right: '40px'}} position='end'>{endAdornment}</InputAdornment></>
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
getOptionLabel={(option) => option.inputLabel}
|
|
53
|
+
renderOption={(props, option) => [props, option.component]}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default VirtualizedAutocomplete;
|
|
60
|
+
|
|
61
|
+
const StyledPopper = styled(Popper)({
|
|
62
|
+
[`& .${autocompleteClasses.listbox}`]: {
|
|
63
|
+
boxSizing: 'border-box',
|
|
64
|
+
'& ul': {
|
|
65
|
+
padding: 0,
|
|
66
|
+
margin: 0,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -6,8 +6,8 @@ export { default as FieldTypeDate } from './FieldTypeDate';
|
|
|
6
6
|
export { default as FieldTypeDateTime } from './FieldTypeDateTime';
|
|
7
7
|
export { default as FieldTypeColor } from './FieldTypeColor';
|
|
8
8
|
export { default as FieldTypeNumber } from './FieldTypeNumber';
|
|
9
|
-
export { default as FieldTypeDropdown } from './FieldTypeDropdown';
|
|
10
9
|
export { default as FieldTypeOneToOne} from './FieldTypeOneToOne';
|
|
11
10
|
export { default as FieldTypeOneToMany} from './FieldTypeOneToMany';
|
|
12
11
|
export { default as CopyButton } from './CopyButton';
|
|
13
|
-
export { default as ConfirmDialog } from './ConfirmDialog';
|
|
12
|
+
export { default as ConfirmDialog } from './ConfirmDialog';
|
|
13
|
+
export { default as VirtualizedAutocomplete } from './VitualizedAutocomplete';
|
package/src/theme/index.ts
CHANGED
|
Binary file
|
|
@@ -1,52 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,41 +0,0 @@
|
|
|
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;
|