@zesty-io/material 0.0.3 → 0.1.1
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/.storybook/main.js +15 -2
- package/.storybook/preview-head.html +1 -0
- package/.storybook/preview.js +14 -8
- 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/CopyButton.stories.d.ts +5 -0
- package/es/CopyButton/CopyButton.stories.js +14 -0
- package/es/CopyButton/index.d.ts +10 -0
- package/es/CopyButton/index.js +26 -0
- 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 +29 -0
- package/es/FieldTypeOneToMany/index.d.ts +14 -0
- package/es/FieldTypeOneToMany/index.js +30 -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.d.ts +5 -0
- package/es/FieldTypeSort/FieldTypeSort.stories.js +22 -0
- package/es/FieldTypeSort/index.d.ts +7 -0
- package/es/FieldTypeSort/index.js +22 -0
- package/es/FieldTypeText/FieldTypeText.stories.d.ts +6 -0
- package/es/FieldTypeText/FieldTypeText.stories.js +29 -0
- package/es/FieldTypeText/index.d.ts +12 -0
- package/es/FieldTypeText/index.js +7 -0
- package/es/FieldTypeUrl/FieldTypeUrl.stories.d.ts +5 -0
- package/es/FieldTypeUrl/FieldTypeUrl.stories.js +21 -0
- package/es/FieldTypeUrl/index.d.ts +12 -0
- package/es/FieldTypeUrl/index.js +13 -0
- package/es/index.d.ts +12 -0
- package/es/index.js +12 -0
- package/es/theme/Theme.stories.d.ts +4 -0
- package/es/theme/Theme.stories.js +10 -0
- package/es/theme/index.js +36 -8
- package/es/utils/virtualization.d.ts +3 -0
- package/es/utils/virtualization.js +74 -0
- package/package.json +8 -3
- package/src/ConfirmModal/ConfirmModal.stories.tsx +35 -0
- package/src/ConfirmModal/index.tsx +50 -0
- package/src/CopyButton/CopyButton.stories.tsx +20 -0
- package/src/CopyButton/index.tsx +55 -0
- 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 +65 -0
- package/src/FieldTypeOneToOne/FieldTypeOneToOne.stories.tsx +46 -0
- package/src/FieldTypeOneToOne/index.tsx +97 -0
- package/src/FieldTypeSort/FieldTypeSort.stories.tsx +36 -0
- package/src/FieldTypeSort/index.tsx +56 -0
- package/src/FieldTypeText/FieldTypeText.stories.tsx +45 -0
- package/src/FieldTypeText/index.tsx +35 -0
- package/src/FieldTypeUrl/FieldTypeUrl.stories.tsx +33 -0
- package/src/FieldTypeUrl/index.tsx +43 -0
- package/src/index.ts +12 -0
- package/src/{stories → theme}/Theme.stories.tsx +1 -1
- package/src/theme/index.ts +41 -9
- package/src/utils/virtualization.tsx +125 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
2
|
+
import { FormControl, FormLabel, Box } from '@mui/material';
|
|
3
|
+
|
|
4
|
+
export interface FieldTypeTextProps extends Omit<OutlinedTextFieldProps, 'variant'> {
|
|
5
|
+
/**
|
|
6
|
+
* Max length of the field
|
|
7
|
+
* @default 150
|
|
8
|
+
*/
|
|
9
|
+
maxLength?: number;
|
|
10
|
+
value: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const FieldTypeText = ({label, maxLength = 150, value, helperText, required, ...props }: FieldTypeTextProps) => {
|
|
14
|
+
|
|
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>
|
|
22
|
+
<MuiTextField
|
|
23
|
+
size="small"
|
|
24
|
+
variant='outlined'
|
|
25
|
+
value={value}
|
|
26
|
+
error={value?.length > maxLength}
|
|
27
|
+
helperText={value?.length > maxLength ? 'Your input is over the specified limit' : helperText}
|
|
28
|
+
// Spread props at the end to allow prop overrides
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
</FormControl>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export default FieldTypeText;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ChangeEvent, useState } from 'react';
|
|
2
|
+
import { Story, Meta } from '@storybook/react/types-6-0';
|
|
3
|
+
import FieldTypeUrl, { FieldTypeUrlProps } from './';
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'FieldTypeUrl',
|
|
7
|
+
component: FieldTypeUrl,
|
|
8
|
+
argType: {},
|
|
9
|
+
} as Meta;
|
|
10
|
+
|
|
11
|
+
const Template: Story<FieldTypeUrlProps> = (args) => {
|
|
12
|
+
const [value, setValue] = useState('');
|
|
13
|
+
|
|
14
|
+
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
15
|
+
setValue(e.target.value);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<FieldTypeUrl
|
|
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: 'Some label',
|
|
31
|
+
fullWidth: true,
|
|
32
|
+
};
|
|
33
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import MuiTextField, { OutlinedTextFieldProps } from '@mui/material/TextField';
|
|
3
|
+
import { FormControl, FormLabel, Box } from '@mui/material';
|
|
4
|
+
|
|
5
|
+
export interface FieldTypeUrlProps extends Omit<OutlinedTextFieldProps, 'variant'> {
|
|
6
|
+
/**
|
|
7
|
+
* Max length of the field
|
|
8
|
+
* @default 2000
|
|
9
|
+
*/
|
|
10
|
+
maxLength?: number;
|
|
11
|
+
value: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const FieldTypeUrl = ({label, maxLength = 2000, value, helperText, required, inputProps, ...props }: FieldTypeUrlProps) => {
|
|
15
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<FormControl fullWidth required={required}>
|
|
19
|
+
{/* Sets flex order to make appended required asterisk properly positioned */}
|
|
20
|
+
<FormLabel sx={{display: 'flex', justifyContent: 'space-between', '& .MuiFormLabel-asterisk': {order: 2}}}>
|
|
21
|
+
<Box sx={{ order: 1}}>{label}</Box>
|
|
22
|
+
<Box sx={{ order: 3, flex: 1, textAlign: 'right'}}>{value?.length}/{maxLength}</Box>
|
|
23
|
+
</FormLabel>
|
|
24
|
+
<MuiTextField
|
|
25
|
+
size="small"
|
|
26
|
+
type='url'
|
|
27
|
+
variant='outlined'
|
|
28
|
+
value={value}
|
|
29
|
+
inputProps={{
|
|
30
|
+
ref: inputRef,
|
|
31
|
+
// Spread props at the end to allow inputProps prop overrides
|
|
32
|
+
...inputProps,
|
|
33
|
+
}}
|
|
34
|
+
error={(value && !inputRef.current?.validity.valid) || value?.length > maxLength}
|
|
35
|
+
helperText={value?.length > maxLength ? 'Your input is over the specified limit' : (value && !inputRef.current?.validity.valid) ? 'Your input is not a valid url' : helperText}
|
|
36
|
+
// Spread props at the end to allow prop overrides
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
</FormControl>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export default FieldTypeUrl;
|
package/src/index.ts
CHANGED
|
@@ -1 +1,13 @@
|
|
|
1
1
|
export { default as theme } from './theme';
|
|
2
|
+
export { default as FieldTypeText } from './FieldTypeText';
|
|
3
|
+
export { default as FieldTypeSort } from './FieldTypeSort';
|
|
4
|
+
export { default as FieldTypeUrl } from './FieldTypeUrl';
|
|
5
|
+
export { default as FieldTypeDate } from './FieldTypeDate';
|
|
6
|
+
export { default as FieldTypeDateTime } from './FieldTypeDateTime';
|
|
7
|
+
export { default as FieldTypeColor } from './FieldTypeColor';
|
|
8
|
+
export { default as FieldTypeNumber } from './FieldTypeNumber';
|
|
9
|
+
export { default as FieldTypeDropdown } from './FieldTypeDropdown';
|
|
10
|
+
export { default as FieldTypeOneToOne} from './FieldTypeOneToOne';
|
|
11
|
+
export { default as FieldTypeOneToMany} from './FieldTypeOneToMany';
|
|
12
|
+
export { default as CopyButton } from './CopyButton';
|
|
13
|
+
export { default as ConfirmModal } from './ConfirmModal';
|
package/src/theme/index.ts
CHANGED
|
@@ -9,27 +9,59 @@ let theme: Theme = createTheme({
|
|
|
9
9
|
|
|
10
10
|
theme = createTheme(theme, {
|
|
11
11
|
components: {
|
|
12
|
+
MuiButton: {
|
|
13
|
+
styleOverrides: {
|
|
14
|
+
root: {
|
|
15
|
+
minWidth: 'auto',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
12
19
|
MuiTooltip: {
|
|
13
20
|
styleOverrides: {
|
|
14
21
|
tooltip: {
|
|
15
22
|
color: theme.palette.primary.contrastText,
|
|
16
23
|
backgroundColor: theme.palette.primary.main,
|
|
17
|
-
fontSize:
|
|
18
|
-
lineHeight:
|
|
24
|
+
fontSize: '14px',
|
|
25
|
+
lineHeight: '20px',
|
|
19
26
|
},
|
|
20
27
|
arrow: {
|
|
21
28
|
color: theme.palette.primary.main,
|
|
22
|
-
}
|
|
23
|
-
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
24
31
|
},
|
|
25
32
|
MuiInputBase: {
|
|
26
33
|
styleOverrides: {
|
|
27
34
|
root: {
|
|
28
|
-
backgroundColor: theme.palette.primary.contrastText
|
|
35
|
+
backgroundColor: theme.palette.primary.contrastText,
|
|
29
36
|
},
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
MuiFormLabel: {
|
|
40
|
+
styleOverrides: {
|
|
41
|
+
root: {
|
|
42
|
+
color: theme.palette.primary.dark,
|
|
43
|
+
},
|
|
44
|
+
asterisk: {
|
|
45
|
+
color: theme.palette.error.main,
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
MuiToggleButton: {
|
|
50
|
+
styleOverrides: {
|
|
51
|
+
root: ({ ownerState, theme }: any) => ({
|
|
52
|
+
backgroundColor: `${
|
|
53
|
+
theme.palette[ownerState.color].contrastText
|
|
54
|
+
} !important`,
|
|
55
|
+
...(ownerState.selected && {
|
|
56
|
+
color: `${theme.palette[ownerState.color].contrastText} !important`,
|
|
57
|
+
backgroundColor: `${
|
|
58
|
+
theme.palette[ownerState.color].main
|
|
59
|
+
} !important`,
|
|
60
|
+
}),
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
});
|
|
34
66
|
|
|
35
67
|
export default theme;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
3
|
+
import ListSubheader from '@mui/material/ListSubheader';
|
|
4
|
+
import { useTheme } from '@mui/material/styles';
|
|
5
|
+
import { VariableSizeList, ListChildComponentProps } from 'react-window';
|
|
6
|
+
import Typography from '@mui/material/Typography';
|
|
7
|
+
|
|
8
|
+
const LISTBOX_PADDING = 8; // px
|
|
9
|
+
|
|
10
|
+
function renderRow(props: ListChildComponentProps) {
|
|
11
|
+
const { data, index, style } = props;
|
|
12
|
+
const dataSet = data[index];
|
|
13
|
+
const inlineStyle = {
|
|
14
|
+
...style,
|
|
15
|
+
top: (style.top as number) + LISTBOX_PADDING,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
if (dataSet.hasOwnProperty('group')) {
|
|
19
|
+
return (
|
|
20
|
+
<ListSubheader key={dataSet.key} component="div" style={inlineStyle}>
|
|
21
|
+
{dataSet.group}
|
|
22
|
+
</ListSubheader>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Typography component="li" {...dataSet[0]} noWrap style={inlineStyle}>
|
|
28
|
+
{dataSet[1]}
|
|
29
|
+
</Typography>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const OuterElementContext = React.createContext({});
|
|
34
|
+
|
|
35
|
+
const OuterElementType = React.forwardRef<HTMLDivElement>((props, ref) => {
|
|
36
|
+
const outerProps = React.useContext(OuterElementContext);
|
|
37
|
+
return <div ref={ref} {...props} {...outerProps} />;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function useResetCache(data: any) {
|
|
41
|
+
const ref = React.useRef<VariableSizeList>(null);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
if (ref.current != null) {
|
|
44
|
+
ref.current.resetAfterIndex(0, true);
|
|
45
|
+
}
|
|
46
|
+
}, [data]);
|
|
47
|
+
return ref;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Adapter for react-window
|
|
51
|
+
export const ListboxComponent = React.forwardRef<
|
|
52
|
+
HTMLDivElement,
|
|
53
|
+
React.HTMLAttributes<HTMLElement>
|
|
54
|
+
>(function ListboxComponent(props, ref) {
|
|
55
|
+
const { children, ...other } = props;
|
|
56
|
+
const itemData: React.ReactChild[] = [];
|
|
57
|
+
(children as React.ReactChild[]).forEach(
|
|
58
|
+
(item: React.ReactChild & { children?: React.ReactChild[] }) => {
|
|
59
|
+
itemData.push(item);
|
|
60
|
+
itemData.push(...(item.children || []));
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const theme = useTheme();
|
|
65
|
+
const smUp = useMediaQuery(theme.breakpoints.up('sm'), {
|
|
66
|
+
noSsr: true,
|
|
67
|
+
});
|
|
68
|
+
const itemCount = itemData.length;
|
|
69
|
+
const itemSize = smUp ? 36 : 48;
|
|
70
|
+
|
|
71
|
+
const getChildSize = (child: React.ReactChild) => {
|
|
72
|
+
if (child.hasOwnProperty('group')) {
|
|
73
|
+
return 48;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return itemSize;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const getHeight = () => {
|
|
80
|
+
if (itemCount > 8) {
|
|
81
|
+
return 8 * itemSize;
|
|
82
|
+
}
|
|
83
|
+
return itemData.map(getChildSize).reduce((a, b) => a + b, 0);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const gridRef = useResetCache(itemCount);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div ref={ref}>
|
|
90
|
+
<OuterElementContext.Provider value={other}>
|
|
91
|
+
<VariableSizeList
|
|
92
|
+
itemData={itemData}
|
|
93
|
+
height={getHeight() + 2 * LISTBOX_PADDING}
|
|
94
|
+
width="100%"
|
|
95
|
+
ref={gridRef}
|
|
96
|
+
outerElementType={OuterElementType}
|
|
97
|
+
innerElementType="ul"
|
|
98
|
+
itemSize={(index: any) => getChildSize(itemData[index])}
|
|
99
|
+
overscanCount={5}
|
|
100
|
+
itemCount={itemCount}
|
|
101
|
+
>
|
|
102
|
+
{renderRow}
|
|
103
|
+
</VariableSizeList>
|
|
104
|
+
</OuterElementContext.Provider>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
function random(length: number) {
|
|
110
|
+
const characters =
|
|
111
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
112
|
+
let result = '';
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < length; i += 1) {
|
|
115
|
+
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
export const randomOptions = Array.from(new Array(10000))
|
|
123
|
+
.map(() => random(10 + Math.ceil(Math.random() * 20)))
|
|
124
|
+
.sort((a: string, b: string) => a.toUpperCase().localeCompare(b.toUpperCase()));
|
|
125
|
+
|