ish-ui 1.0.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/.eslintrc.json +39 -0
- package/.gitattributes +3 -0
- package/.github/workflows/release-package.yml +33 -0
- package/.prettierrc +5 -0
- package/README.md +80 -0
- package/assets/fonts/inter/Inter-Italic.var.woff2 +0 -0
- package/assets/fonts/inter/Inter-Roman.var.woff2 +0 -0
- package/assets/fonts/inter/LICENSE.txt +92 -0
- package/assets/fonts/inter/index.d.ts +10 -0
- package/assets/fonts/inter/inter.scss +17 -0
- package/package.json +108 -0
- package/src/actions/FieldProcessing.ts +21 -0
- package/src/actions/index.ts +10 -0
- package/src/appBar/AppBarHelpMenu.tsx +139 -0
- package/src/appBar/index.ts +9 -0
- package/src/buttons/AddButton.tsx +30 -0
- package/src/buttons/TimetableButton.tsx +19 -0
- package/src/buttons/index.ts +10 -0
- package/src/colorPicker/ColorPicker.tsx +223 -0
- package/src/colorPicker/index.ts +9 -0
- package/src/dialog/BrowserWarning.tsx +24 -0
- package/src/dialog/confirm/ConfirmBase.tsx +59 -0
- package/src/dialog/index.ts +11 -0
- package/src/dialog/message/Message.tsx +140 -0
- package/src/documents/DocumentIconsChooser.tsx +69 -0
- package/src/documents/index.ts +10 -0
- package/src/documents/utils/index.tsx +71 -0
- package/src/dynamicSizeList/DynamicSizeList.tsx +208 -0
- package/src/dynamicSizeList/index.ts +9 -0
- package/src/fieldMessage/ErrorMessage.tsx +28 -0
- package/src/fieldMessage/WarningMessage.tsx +28 -0
- package/src/fieldMessage/index.ts +11 -0
- package/src/fieldMessage/styles.ts +21 -0
- package/src/fileUploader/FileUploaderDialog.tsx +158 -0
- package/src/fileUploader/index.ts +9 -0
- package/src/formFields/CheckboxField.tsx +90 -0
- package/src/formFields/CodeEditorField.tsx +103 -0
- package/src/formFields/ColoredCheckBox.tsx +74 -0
- package/src/formFields/DateTimeField.tsx +61 -0
- package/src/formFields/EditInPlaceDateTimeField.tsx +285 -0
- package/src/formFields/EditInPlaceDurationField.tsx +79 -0
- package/src/formFields/EditInPlaceField.tsx +131 -0
- package/src/formFields/EditInPlaceFieldBase.tsx +241 -0
- package/src/formFields/EditInPlaceFileField.tsx +67 -0
- package/src/formFields/EditInPlaceMoneyField.tsx +64 -0
- package/src/formFields/EditInPlacePhoneField.tsx +97 -0
- package/src/formFields/EditInPlaceSearchSelect.tsx +562 -0
- package/src/formFields/FieldAdornments.tsx +70 -0
- package/src/formFields/FilePreview.tsx +149 -0
- package/src/formFields/FormRadioButtons.tsx +62 -0
- package/src/formFields/SelectCustomComponents.tsx +228 -0
- package/src/formFields/Switch.tsx +146 -0
- package/src/formFields/TextField.tsx +60 -0
- package/src/formFields/UneditableBase.tsx +101 -0
- package/src/formFields/index.ts +27 -0
- package/src/index.ts +26 -0
- package/src/layout/InfoPill.tsx +36 -0
- package/src/layout/index.ts +10 -0
- package/src/layout/resizable/ResizableWrapper.tsx +87 -0
- package/src/markdownEditor/HtmlEditor.tsx +44 -0
- package/src/markdownEditor/WysiwygEditor.tsx +137 -0
- package/src/markdownEditor/index.ts +12 -0
- package/src/markdownEditor/style.ts +188 -0
- package/src/markdownEditor/utils/index.ts +48 -0
- package/src/model/AppBar.ts +20 -0
- package/src/model/CommomObjects.ts +8 -0
- package/src/model/CommonFunctions.ts +20 -0
- package/src/model/Confirm.ts +27 -0
- package/src/model/Fields.ts +254 -0
- package/src/model/NestedEntity.ts +14 -0
- package/src/model/Theme.ts +42 -0
- package/src/model/index.ts +16 -0
- package/src/styles/GlobalStylesProvider.tsx +520 -0
- package/src/styles/StylesProviderCustom.tsx +8 -0
- package/src/styles/animateStyles.ts +94 -0
- package/src/styles/bootstrap.ts +503 -0
- package/src/styles/hooks.ts +44 -0
- package/src/styles/index.ts +18 -0
- package/src/styles/makeStyles.ts +21 -0
- package/src/styles/mixins/common.ts +40 -0
- package/src/styles/mixins/keyframes.ts +16 -0
- package/src/styles/mixins/prefixer.ts +21 -0
- package/src/tagsInput/AddTagMenu.tsx +74 -0
- package/src/tagsInput/AddTagMenuItem.tsx +50 -0
- package/src/tagsInput/TagInputList.tsx +428 -0
- package/src/tagsInput/index.ts +4 -0
- package/src/themes/appTheme.ts +324 -0
- package/src/themes/index.ts +10 -0
- package/src/themes/ishTheme.ts +401 -0
- package/src/timetable/datePeriodFilter/DayPeriodIcons.tsx +95 -0
- package/src/timetable/datePeriodFilter/index.ts +10 -0
- package/src/timetable/index.ts +11 -0
- package/src/timetable/miniCalendar/CalendarDay.tsx +109 -0
- package/src/timetable/miniCalendar/CalendarHeader.tsx +37 -0
- package/src/timetable/miniCalendar/CalendarWeekPanel.tsx +35 -0
- package/src/timetable/miniCalendar/WeekDay.tsx +49 -0
- package/src/timetable/miniCalendar/index.ts +13 -0
- package/src/utils/DOM/Links.ts +17 -0
- package/src/utils/DOM/getCaretCoordinates.ts +122 -0
- package/src/utils/DOM/getOS.ts +32 -0
- package/src/utils/DOM/index.ts +34 -0
- package/src/utils/dates/datesNormalizing.ts +4 -0
- package/src/utils/dates/format.ts +52 -0
- package/src/utils/dates/formatRelative.ts +22 -0
- package/src/utils/dates/formatString.ts +233 -0
- package/src/utils/dates/formatTimezone.ts +37 -0
- package/src/utils/dates/index.ts +15 -0
- package/src/utils/dates/timetable.ts +46 -0
- package/src/utils/events/index.ts +8 -0
- package/src/utils/fields/index.ts +23 -0
- package/src/utils/formatting/PhoneMasks.ts +320 -0
- package/src/utils/formatting/index.tsx +20 -0
- package/src/utils/hooks/index.ts +19 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/numbers/decimalCalculation.ts +26 -0
- package/src/utils/numbers/index.ts +11 -0
- package/src/utils/numbers/numbersNormalizing.ts +52 -0
- package/src/utils/stubs/index.tsx +12 -0
- package/src/utils/tags/index.ts +53 -0
- package/tools/webpack/webpack.aliases.js +13 -0
- package/tools/webpack/webpack.config.dev.js +29 -0
- package/tools/webpack/webpack.config.prod.js +36 -0
- package/tools/webpack/webpack.helpers.js +26 -0
- package/tools/webpack/webpack.plugins.js +15 -0
- package/tools/webpack/webpack.rules.js +51 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright ish group pty ltd. All rights reserved. https://www.ish.com.au
|
|
3
|
+
* No copying or use of this code is allowed without permission in writing from ish.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import Typography from '@mui/material/Typography';
|
|
8
|
+
import Button from '@mui/material/Button';
|
|
9
|
+
import { createStyles, withStyles } from '@mui/styles';
|
|
10
|
+
import { darken } from '@mui/material/styles';
|
|
11
|
+
import IconButton from '@mui/material/IconButton';
|
|
12
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
13
|
+
import Avatar from '@mui/material/Avatar';
|
|
14
|
+
import clsx from 'clsx';
|
|
15
|
+
import { AppTheme } from '@src/model';
|
|
16
|
+
|
|
17
|
+
const styles = (theme: AppTheme) => createStyles({
|
|
18
|
+
root: {
|
|
19
|
+
height: 'fit-content',
|
|
20
|
+
width: 'fit-content',
|
|
21
|
+
position: 'relative',
|
|
22
|
+
fontSize: 0,
|
|
23
|
+
'&:hover $backdrop$active': {
|
|
24
|
+
opacity: 1
|
|
25
|
+
},
|
|
26
|
+
color: '#fff',
|
|
27
|
+
},
|
|
28
|
+
backdrop: {
|
|
29
|
+
display: 'flex',
|
|
30
|
+
alignItems: 'center',
|
|
31
|
+
justifyContent: 'center',
|
|
32
|
+
background: theme.palette.action.active,
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
height: '100%',
|
|
35
|
+
width: '100%',
|
|
36
|
+
opacity: 0,
|
|
37
|
+
transition: theme.transitions.create('opacity', {
|
|
38
|
+
duration: theme.transitions.duration.complex,
|
|
39
|
+
easing: theme.transitions.easing.easeInOut
|
|
40
|
+
}),
|
|
41
|
+
zIndex: 1,
|
|
42
|
+
},
|
|
43
|
+
rounded: {
|
|
44
|
+
borderRadius: '100%',
|
|
45
|
+
},
|
|
46
|
+
actionButton: {
|
|
47
|
+
background: theme.palette.background.paper,
|
|
48
|
+
'&:hover': {
|
|
49
|
+
background: darken(theme.palette.background.paper, 0.2)
|
|
50
|
+
},
|
|
51
|
+
marginTop: theme.spacing(1)
|
|
52
|
+
},
|
|
53
|
+
noValue: {
|
|
54
|
+
color: theme.palette.divider,
|
|
55
|
+
marginTop: theme.spacing(-1)
|
|
56
|
+
},
|
|
57
|
+
active: {},
|
|
58
|
+
avatarRoot: {
|
|
59
|
+
maxWidth: '100%',
|
|
60
|
+
transition: theme.transitions.create('all', {
|
|
61
|
+
duration: theme.transitions.duration.complex,
|
|
62
|
+
easing: theme.transitions.easing.easeInOut
|
|
63
|
+
}),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
interface Props {
|
|
68
|
+
data: string;
|
|
69
|
+
label?: string;
|
|
70
|
+
actions?: {
|
|
71
|
+
actionLabel?: string;
|
|
72
|
+
onAction?: any;
|
|
73
|
+
disabled?: boolean,
|
|
74
|
+
icon?: any;
|
|
75
|
+
}[];
|
|
76
|
+
classes?: any;
|
|
77
|
+
iconPlacementRow?: boolean;
|
|
78
|
+
disabled?: boolean;
|
|
79
|
+
avatarSize?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const FilePreview: React.FC<Props> = ({
|
|
83
|
+
label, actions, data, classes, iconPlacementRow, disabled, avatarSize
|
|
84
|
+
}) => {
|
|
85
|
+
const size = avatarSize || 90;
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
{label && (
|
|
89
|
+
<Typography variant="caption" color="textSecondary" component="div" className="pb-1">
|
|
90
|
+
{label}
|
|
91
|
+
</Typography>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
{data ? (
|
|
95
|
+
<div className={classes.root}>
|
|
96
|
+
{!disabled && (
|
|
97
|
+
<div className={clsx(classes.backdrop, avatarSize && classes.rounded, actions && classes.active)}>
|
|
98
|
+
<div className={iconPlacementRow ? 'centeredFlex' : 'flex-column'}>
|
|
99
|
+
{actions
|
|
100
|
+
&& actions.map((a, i) => (a.icon ? (
|
|
101
|
+
<Tooltip key={i} title={a.actionLabel} placement={iconPlacementRow ? 'top' : 'right'}>
|
|
102
|
+
<IconButton color="inherit" size="medium" onClick={a.onAction} disabled={a.disabled}>
|
|
103
|
+
{a.icon}
|
|
104
|
+
</IconButton>
|
|
105
|
+
</Tooltip>
|
|
106
|
+
) : (
|
|
107
|
+
<Button
|
|
108
|
+
key={i}
|
|
109
|
+
size="small"
|
|
110
|
+
variant="outlined"
|
|
111
|
+
color="secondary"
|
|
112
|
+
classes={{
|
|
113
|
+
root: classes.actionButton
|
|
114
|
+
}}
|
|
115
|
+
onClick={a.onAction}
|
|
116
|
+
disabled={a.disabled}
|
|
117
|
+
>
|
|
118
|
+
{a.actionLabel}
|
|
119
|
+
</Button>
|
|
120
|
+
)))}
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
{avatarSize
|
|
125
|
+
? (
|
|
126
|
+
<Avatar
|
|
127
|
+
alt="FilePreview"
|
|
128
|
+
src={`data:image/png;base64, ${data}`}
|
|
129
|
+
sx={{ width: size, height: size }}
|
|
130
|
+
classes={{ root: classes.avatarRoot }}
|
|
131
|
+
/>
|
|
132
|
+
) : (
|
|
133
|
+
<img
|
|
134
|
+
alt="FilePreview"
|
|
135
|
+
src={`data:image/png;base64, ${data}`}
|
|
136
|
+
className={classes.avatarRoot}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
) : (
|
|
141
|
+
<Typography variant="body1" className={classes.noValue}>
|
|
142
|
+
No Value
|
|
143
|
+
</Typography>
|
|
144
|
+
)}
|
|
145
|
+
</>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export default withStyles(styles)(FilePreview);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright ish group pty ltd 2023.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
5
|
+
*
|
|
6
|
+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { withStyles } from '@mui/styles';
|
|
11
|
+
import {
|
|
12
|
+
FormControl, FormControlLabel, Radio, RadioGroup
|
|
13
|
+
} from '@mui/material';
|
|
14
|
+
import Typography from '@mui/material/Typography';
|
|
15
|
+
|
|
16
|
+
const styles = theme => ({
|
|
17
|
+
root: {
|
|
18
|
+
display: 'flex'
|
|
19
|
+
},
|
|
20
|
+
group: {
|
|
21
|
+
margin: theme.spacing(1, 0)
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const FormRadioButtons = props => {
|
|
26
|
+
const {
|
|
27
|
+
classes,
|
|
28
|
+
items,
|
|
29
|
+
disabled,
|
|
30
|
+
input: { value, onChange, name },
|
|
31
|
+
labelPath = 'label',
|
|
32
|
+
valuePath = 'value',
|
|
33
|
+
color = 'primary',
|
|
34
|
+
row
|
|
35
|
+
} = props;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className={classes.root}>
|
|
39
|
+
<FormControl component="fieldset">
|
|
40
|
+
<RadioGroup className={classes.group} value={value} onChange={(e: any) => onChange(e.target.value)} row={row}>
|
|
41
|
+
{items
|
|
42
|
+
&& items.map((i, n) => (
|
|
43
|
+
<FormControlLabel
|
|
44
|
+
key={n}
|
|
45
|
+
value={i[valuePath]}
|
|
46
|
+
control={<Radio color={color} id={`input-${n}-${name}`} name={name} />}
|
|
47
|
+
label={(
|
|
48
|
+
<Typography component="span" variant="body2">
|
|
49
|
+
{i[labelPath]}
|
|
50
|
+
</Typography>
|
|
51
|
+
)}
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
htmlFor={`input-${n}-${name}`}
|
|
54
|
+
/>
|
|
55
|
+
))}
|
|
56
|
+
</RadioGroup>
|
|
57
|
+
</FormControl>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default withStyles(styles)(FormRadioButtons) as React.FunctionComponent<any>;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright ish group pty ltd 2023.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
5
|
+
*
|
|
6
|
+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import useTheme from '@mui/styles/useTheme';
|
|
10
|
+
import useMediaQuery from '@mui/material/useMediaQuery';
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import ListSubheader from '@mui/material/ListSubheader';
|
|
13
|
+
import InfiniteLoader from 'react-window-infinite-loader';
|
|
14
|
+
import { areEqual, FixedSizeList as List } from 'react-window';
|
|
15
|
+
import { createStyles } from '@mui/styles';
|
|
16
|
+
import { green } from '@mui/material/colors';
|
|
17
|
+
import clsx from 'clsx';
|
|
18
|
+
import { ListItem } from '@mui/material';
|
|
19
|
+
import { AppTheme } from '@src/model';
|
|
20
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
21
|
+
|
|
22
|
+
export const selectStyles = theme => createStyles({
|
|
23
|
+
bottomMargin: {
|
|
24
|
+
marginBottom: `${theme.spacing(1) + 1}`
|
|
25
|
+
},
|
|
26
|
+
bottomPadding: {
|
|
27
|
+
paddingBottom: `${theme.spacing(1) + 1}`
|
|
28
|
+
},
|
|
29
|
+
topMargin: {
|
|
30
|
+
marginTop: `${theme.spacing(1)}`,
|
|
31
|
+
paddingLeft: '0'
|
|
32
|
+
},
|
|
33
|
+
editIcon: {
|
|
34
|
+
fontSize: '24px',
|
|
35
|
+
color: theme.palette.divider,
|
|
36
|
+
verticalAlign: 'middle',
|
|
37
|
+
margin: 0
|
|
38
|
+
},
|
|
39
|
+
editable: {
|
|
40
|
+
'&:hover': {
|
|
41
|
+
color: theme.palette.primary.main,
|
|
42
|
+
fill: theme.palette.primary.main
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
label: {
|
|
46
|
+
whiteSpace: 'nowrap',
|
|
47
|
+
'&$valid': {
|
|
48
|
+
color: green[500]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
valid: {},
|
|
52
|
+
autoWidthSelect: {
|
|
53
|
+
width: 'calc(100% + 30px)'
|
|
54
|
+
},
|
|
55
|
+
emptySelect: {
|
|
56
|
+
color: '#fff'
|
|
57
|
+
},
|
|
58
|
+
error: {
|
|
59
|
+
color: theme.palette.error.main
|
|
60
|
+
},
|
|
61
|
+
validUnderline: {
|
|
62
|
+
'&:after': {
|
|
63
|
+
borderBottomColor: green[500]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
menuItem: {
|
|
67
|
+
'&:hover .placeholderContent': {
|
|
68
|
+
color: '#fff'
|
|
69
|
+
},
|
|
70
|
+
overflow: 'hidden',
|
|
71
|
+
textOverflow: 'ellipsis'
|
|
72
|
+
},
|
|
73
|
+
menuItemActive: {
|
|
74
|
+
'& .placeholderContent': {
|
|
75
|
+
color: '#fff'
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
menuList: {
|
|
79
|
+
background: theme.palette.background.paper,
|
|
80
|
+
borderRadius: theme.shape.borderRadius,
|
|
81
|
+
},
|
|
82
|
+
readonly: {
|
|
83
|
+
fontWeight: 300,
|
|
84
|
+
pointerEvents: 'none'
|
|
85
|
+
},
|
|
86
|
+
multiple: {},
|
|
87
|
+
inline: {
|
|
88
|
+
display: 'inline-block',
|
|
89
|
+
'& .MuiInput-root .MuiInput-input': {
|
|
90
|
+
padding: 0
|
|
91
|
+
},
|
|
92
|
+
'& $inputEndAdornment': {
|
|
93
|
+
marginBottom: '-8px'
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
root: {
|
|
97
|
+
'& $multiple': {
|
|
98
|
+
flexWrap: 'wrap'
|
|
99
|
+
},
|
|
100
|
+
'& $multiple $inputEndAdornment': {
|
|
101
|
+
position: 'absolute',
|
|
102
|
+
right: 0,
|
|
103
|
+
bottom: 6,
|
|
104
|
+
height: 'auto'
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
inputEndAdornment: {
|
|
108
|
+
marginBottom: '-6px',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
display: 'flex',
|
|
111
|
+
},
|
|
112
|
+
inputWrapper: {
|
|
113
|
+
'&:hover $inputEndAdornment': {
|
|
114
|
+
visibility: 'visible'
|
|
115
|
+
},
|
|
116
|
+
'&.Mui-focused $expandIcon': {
|
|
117
|
+
opacity: 1
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
expandIcon: { opacity: 0.5 },
|
|
121
|
+
hasPopup: {
|
|
122
|
+
'&$root $inputWrapper': {
|
|
123
|
+
paddingRight: 0
|
|
124
|
+
},
|
|
125
|
+
'&$root$hasClear $inputWrapper': {
|
|
126
|
+
paddingRight: 0
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
hasClear: {
|
|
130
|
+
'&$root $inputWrapper': {
|
|
131
|
+
paddingRight: 0
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export const ListRow = React.memo<any>(({ data: { children, selectAdornment }, index, style }) => {
|
|
137
|
+
const inlineStyle = {
|
|
138
|
+
...style,
|
|
139
|
+
top: (style.top as number) + 8,
|
|
140
|
+
paddingLeft: 0,
|
|
141
|
+
paddingRight: 0,
|
|
142
|
+
whiteSpace: 'nowrap'
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return (
|
|
146
|
+
<ListItem button style={inlineStyle}>
|
|
147
|
+
{((selectAdornment?.position === 'start' && index === 0)
|
|
148
|
+
|| (selectAdornment?.position === 'end' && index === children.length))
|
|
149
|
+
? selectAdornment.content
|
|
150
|
+
: children[index]
|
|
151
|
+
}
|
|
152
|
+
</ListItem>
|
|
153
|
+
);
|
|
154
|
+
}, areEqual);
|
|
155
|
+
|
|
156
|
+
const OuterElementContext = React.createContext({});
|
|
157
|
+
|
|
158
|
+
const OuterElementType = React.forwardRef<any, any>((props, ref) => {
|
|
159
|
+
const outerProps = React.useContext(OuterElementContext);
|
|
160
|
+
return <div ref={ref} {...props} {...outerProps} />;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
export const ListboxComponent = React.forwardRef<any, any>((props, ref) => {
|
|
164
|
+
const {
|
|
165
|
+
children, rowHeight, remoteRowCount, loadMoreRows, classes, loading, selectAdornment, fieldClasses, ...other
|
|
166
|
+
} = props;
|
|
167
|
+
|
|
168
|
+
const itemData = { selectAdornment, children: React.Children.toArray(children) };
|
|
169
|
+
const theme = useTheme() as AppTheme;
|
|
170
|
+
const smUp = useMediaQuery(theme.breakpoints.up('sm'), { noSsr: true });
|
|
171
|
+
const itemSize = rowHeight || (smUp ? 36 : 48);
|
|
172
|
+
const itemCount = (remoteRowCount > children.length ? children.length + 3 : children.length) + (selectAdornment ? 1 : 0);
|
|
173
|
+
|
|
174
|
+
const getChildSize = child => {
|
|
175
|
+
if (React.isValidElement(child) && child.type === ListSubheader) {
|
|
176
|
+
return 48;
|
|
177
|
+
}
|
|
178
|
+
return itemSize;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const getHeight = () => {
|
|
182
|
+
if (itemCount > 8) {
|
|
183
|
+
return 8 * itemSize;
|
|
184
|
+
}
|
|
185
|
+
return itemData.children.map(getChildSize).reduce((a, b) => a + b, 0);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const loadMoreItems = () => (loading ? undefined : loadMoreRows(itemData.children.length));
|
|
189
|
+
|
|
190
|
+
const isItemLoaded = index => index < (children.length + (selectAdornment ? 1 : 0));
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<div ref={ref}>
|
|
194
|
+
<OuterElementContext.Provider value={other}>
|
|
195
|
+
<InfiniteLoader
|
|
196
|
+
isItemLoaded={isItemLoaded}
|
|
197
|
+
itemCount={itemCount}
|
|
198
|
+
loadMoreItems={loadMoreItems}
|
|
199
|
+
>
|
|
200
|
+
{({ onItemsRendered }) => (
|
|
201
|
+
<List
|
|
202
|
+
height={getHeight() + 2 * 8}
|
|
203
|
+
width="100%"
|
|
204
|
+
className={clsx(classes.menuList, fieldClasses.selectMenu)}
|
|
205
|
+
itemData={itemData}
|
|
206
|
+
outerElementType={OuterElementType}
|
|
207
|
+
onItemsRendered={onItemsRendered}
|
|
208
|
+
itemSize={itemSize}
|
|
209
|
+
itemCount={itemCount}
|
|
210
|
+
>
|
|
211
|
+
{ListRow}
|
|
212
|
+
</List>
|
|
213
|
+
)}
|
|
214
|
+
</InfiniteLoader>
|
|
215
|
+
</OuterElementContext.Provider>
|
|
216
|
+
</div>
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
export const NoWrapOption = (content, data, search, parentProps) => (
|
|
221
|
+
<div {...parentProps || {}}>
|
|
222
|
+
<Tooltip title={content}>
|
|
223
|
+
<div className="text-nowrap text-truncate">
|
|
224
|
+
{content}
|
|
225
|
+
</div>
|
|
226
|
+
</Tooltip>
|
|
227
|
+
</div>
|
|
228
|
+
);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright ish group pty ltd 2023.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
5
|
+
*
|
|
6
|
+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Wrapper component for Material UI button
|
|
11
|
+
* */
|
|
12
|
+
|
|
13
|
+
import React, { useCallback } from 'react';
|
|
14
|
+
import MuiSwitch from '@mui/material/Switch';
|
|
15
|
+
import Typography from '@mui/material/Typography';
|
|
16
|
+
import { createStyles, withStyles } from '@mui/styles';
|
|
17
|
+
import clsx from 'clsx';
|
|
18
|
+
import { FieldInputProps, FormSwitchProps } from '@src/model';
|
|
19
|
+
|
|
20
|
+
const getValue = value => {
|
|
21
|
+
switch (value) {
|
|
22
|
+
case 'false':
|
|
23
|
+
return false;
|
|
24
|
+
case 'true':
|
|
25
|
+
return true;
|
|
26
|
+
default:
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const styles = theme => createStyles({
|
|
32
|
+
bar: {
|
|
33
|
+
height: '22px',
|
|
34
|
+
borderRadius: '12px',
|
|
35
|
+
marginTop: '2px',
|
|
36
|
+
marginLeft: '-7px',
|
|
37
|
+
width: '38px'
|
|
38
|
+
},
|
|
39
|
+
checked: {
|
|
40
|
+
'&$disabled + $bar ': {
|
|
41
|
+
opacity: 0.12
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
icon: {
|
|
45
|
+
boxShadow: theme.shadows[1],
|
|
46
|
+
backgroundColor: theme.palette.common.white
|
|
47
|
+
},
|
|
48
|
+
root: {
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
'&$disabled': {
|
|
51
|
+
opacity: 0.12
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
inline: {
|
|
55
|
+
marginLeft: '-12px'
|
|
56
|
+
},
|
|
57
|
+
default: {
|
|
58
|
+
top: theme.spacing(0.5),
|
|
59
|
+
height: theme.spacing(4),
|
|
60
|
+
width: theme.spacing(4),
|
|
61
|
+
padding: 0,
|
|
62
|
+
'&$disabled': {
|
|
63
|
+
color: theme.palette.common.white
|
|
64
|
+
},
|
|
65
|
+
'&$checked': {
|
|
66
|
+
transform: `translateX(${theme.spacing(2)})`
|
|
67
|
+
},
|
|
68
|
+
'&$checked + $bar': {
|
|
69
|
+
opacity: 1
|
|
70
|
+
},
|
|
71
|
+
'&$checked$disabled + $bar': {
|
|
72
|
+
backgroundColor: theme.palette.primary.main,
|
|
73
|
+
opacity: 0.6
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
focusVisible: {
|
|
77
|
+
background: 'red'
|
|
78
|
+
},
|
|
79
|
+
disabled: {}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const SwitchBase = props => {
|
|
83
|
+
const {
|
|
84
|
+
classes, color = 'primary', inline, checked, ...custom
|
|
85
|
+
} = props;
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<MuiSwitch
|
|
89
|
+
color={color}
|
|
90
|
+
checked={Boolean(checked)}
|
|
91
|
+
classes={{
|
|
92
|
+
track: classes.bar,
|
|
93
|
+
root: clsx(classes.root, { [classes.inline]: inline }),
|
|
94
|
+
checked: classes.checked,
|
|
95
|
+
thumb: classes.icon,
|
|
96
|
+
switchBase: classes.default,
|
|
97
|
+
disabled: classes.disabled
|
|
98
|
+
}}
|
|
99
|
+
{...custom}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const Switch = withStyles(styles)(SwitchBase);
|
|
105
|
+
|
|
106
|
+
export function FormSwitch<InputProps extends FieldInputProps>({ input, color, disabled, stringValue, label, className, inline, onChangeHandler, onClick }:FormSwitchProps<InputProps>) {
|
|
107
|
+
const onChange = useCallback(
|
|
108
|
+
(e, value) => {
|
|
109
|
+
let checked = value;
|
|
110
|
+
|
|
111
|
+
if (stringValue) {
|
|
112
|
+
checked = checked.toString();
|
|
113
|
+
}
|
|
114
|
+
if (typeof onChangeHandler === 'function') {
|
|
115
|
+
onChangeHandler(e, checked);
|
|
116
|
+
}
|
|
117
|
+
if (!e.isDefaultPrevented()) {
|
|
118
|
+
input.onChange(checked);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
[stringValue, input, onChangeHandler]
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<>
|
|
126
|
+
{label && (
|
|
127
|
+
<Typography variant="caption" color="textSecondary">
|
|
128
|
+
<label htmlFor={`input-${input.name}`}>
|
|
129
|
+
{label}
|
|
130
|
+
</label>
|
|
131
|
+
</Typography>
|
|
132
|
+
)}
|
|
133
|
+
<Switch
|
|
134
|
+
checked={getValue(input.value)}
|
|
135
|
+
onClick={onClick}
|
|
136
|
+
onChange={onChange}
|
|
137
|
+
color={color}
|
|
138
|
+
disabled={disabled}
|
|
139
|
+
className={className}
|
|
140
|
+
inline={inline}
|
|
141
|
+
id={`input-${input.name}`}
|
|
142
|
+
name={input.name}
|
|
143
|
+
/>
|
|
144
|
+
</>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright ish group pty ltd 2023.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
5
|
+
*
|
|
6
|
+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Wrapper component for Material Text Field
|
|
11
|
+
* */
|
|
12
|
+
|
|
13
|
+
import * as React from 'react';
|
|
14
|
+
import { withStyles } from '@mui/styles';
|
|
15
|
+
import MuiTextField from '@mui/material/TextField';
|
|
16
|
+
|
|
17
|
+
const styles = theme => ({
|
|
18
|
+
textField: {
|
|
19
|
+
marginLeft: theme.spacing(1),
|
|
20
|
+
marginRight: theme.spacing(1)
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
class TextInput extends React.Component<any, any> {
|
|
25
|
+
render() {
|
|
26
|
+
const {
|
|
27
|
+
classes, onChange, id, margin = 'dense', ...props
|
|
28
|
+
} = this.props;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<MuiTextField
|
|
32
|
+
name={props.id}
|
|
33
|
+
onChange={e => onChange(e.target.value, id)}
|
|
34
|
+
margin={margin}
|
|
35
|
+
{...props}
|
|
36
|
+
variant="standard"
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const TextField = withStyles(styles)(TextInput);
|
|
43
|
+
|
|
44
|
+
// Form field text component creator
|
|
45
|
+
export const FormTextField = props => {
|
|
46
|
+
const {
|
|
47
|
+
input, meta: { error, invalid, touched }, helperText, inputRef, ...custom
|
|
48
|
+
} = props;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<TextField
|
|
52
|
+
error={touched && invalid}
|
|
53
|
+
inputRef={inputRef}
|
|
54
|
+
helperText={(touched && error) || helperText}
|
|
55
|
+
fullWidth
|
|
56
|
+
{...input}
|
|
57
|
+
{...custom}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
};
|