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,241 @@
|
|
|
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, { useEffect, useMemo, useRef, useState } from 'react';
|
|
10
|
+
import clsx from 'clsx';
|
|
11
|
+
import {
|
|
12
|
+
FilledInput,
|
|
13
|
+
FormControl,
|
|
14
|
+
FormHelperText,
|
|
15
|
+
Input,
|
|
16
|
+
InputAdornment,
|
|
17
|
+
InputLabel,
|
|
18
|
+
OutlinedInput
|
|
19
|
+
} from '@mui/material';
|
|
20
|
+
import { InputProps } from '@mui/material/Input/Input';
|
|
21
|
+
import { makeAppStyles } from '@src/styles';
|
|
22
|
+
import WarningMessage from '../fieldMessage/WarningMessage';
|
|
23
|
+
import { FieldClasses } from '@src/model';
|
|
24
|
+
import { FormControlTypeMap } from '@mui/material/FormControl/FormControl';
|
|
25
|
+
import { countWidth } from '@src/utils';
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
name: string;
|
|
29
|
+
value: string;
|
|
30
|
+
className?: string;
|
|
31
|
+
endAdornmentClass?: string;
|
|
32
|
+
label?: React.ReactNode;
|
|
33
|
+
labelAdornment?: React.ReactNode;
|
|
34
|
+
editIcon?: React.ReactNode;
|
|
35
|
+
CustomInput?: React.ReactNode;
|
|
36
|
+
InputProps?: Partial<InputProps>,
|
|
37
|
+
fieldClasses?: FieldClasses,
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
warning?: string;
|
|
40
|
+
error?: string;
|
|
41
|
+
rightAligned?: boolean;
|
|
42
|
+
inline?: boolean;
|
|
43
|
+
invalid?: boolean;
|
|
44
|
+
shrink?: boolean;
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
hideArrows?: boolean;
|
|
47
|
+
variant?: FormControlTypeMap['props']['variant'];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const useStyles = makeAppStyles(theme => ({
|
|
51
|
+
label: {
|
|
52
|
+
whiteSpace: 'nowrap',
|
|
53
|
+
overflow: 'hidden',
|
|
54
|
+
textOverflow: 'ellipsis',
|
|
55
|
+
maxWidth: '100%',
|
|
56
|
+
marginRight: theme.spacing(0.5)
|
|
57
|
+
},
|
|
58
|
+
rightLabel: {
|
|
59
|
+
left: 'unset',
|
|
60
|
+
right: theme.spacing(-2),
|
|
61
|
+
'& $label': {
|
|
62
|
+
marginRight: 0
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
inputWrapper: {
|
|
66
|
+
paddingBottom: 0,
|
|
67
|
+
'&:hover .d-none': {
|
|
68
|
+
display: 'flex',
|
|
69
|
+
},
|
|
70
|
+
'&:hover .invisible': {
|
|
71
|
+
visibility: 'visible',
|
|
72
|
+
},
|
|
73
|
+
'& .Mui-focused $inputEndAdornment': {
|
|
74
|
+
opacity: 1,
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
hideArrows: {
|
|
78
|
+
'&::-webkit-outer-spin-button': {
|
|
79
|
+
'-webkit-appearance': 'none',
|
|
80
|
+
margin: 0
|
|
81
|
+
},
|
|
82
|
+
'&::-webkit-inner-spin-button': {
|
|
83
|
+
'-webkit-appearance': 'none',
|
|
84
|
+
margin: 0
|
|
85
|
+
},
|
|
86
|
+
'-moz-appearance': 'textfield'
|
|
87
|
+
},
|
|
88
|
+
inlineInput: {
|
|
89
|
+
padding: 0,
|
|
90
|
+
fontSize: 'inherit',
|
|
91
|
+
},
|
|
92
|
+
readonly: {
|
|
93
|
+
fontWeight: 300,
|
|
94
|
+
pointerEvents: 'none'
|
|
95
|
+
},
|
|
96
|
+
inputEndAdornment: {
|
|
97
|
+
display: 'flex',
|
|
98
|
+
fontSize: '24px',
|
|
99
|
+
color: theme.palette.primary.main,
|
|
100
|
+
alignItems: 'flex-end',
|
|
101
|
+
alignSelf: 'flex-end',
|
|
102
|
+
marginBottom: '5px'
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
const EditInPlaceFieldBase = (
|
|
107
|
+
{
|
|
108
|
+
value,
|
|
109
|
+
invalid,
|
|
110
|
+
className,
|
|
111
|
+
inline,
|
|
112
|
+
label,
|
|
113
|
+
fieldClasses = {},
|
|
114
|
+
rightAligned,
|
|
115
|
+
shrink,
|
|
116
|
+
name,
|
|
117
|
+
disabled,
|
|
118
|
+
labelAdornment,
|
|
119
|
+
editIcon,
|
|
120
|
+
error,
|
|
121
|
+
placeholder,
|
|
122
|
+
hideArrows,
|
|
123
|
+
warning,
|
|
124
|
+
endAdornmentClass,
|
|
125
|
+
CustomInput,
|
|
126
|
+
InputProps,
|
|
127
|
+
variant = 'standard'
|
|
128
|
+
}: Props) => {
|
|
129
|
+
|
|
130
|
+
const [inputWidth, setInputWidth] = useState<number>();
|
|
131
|
+
|
|
132
|
+
const classes = useStyles();
|
|
133
|
+
|
|
134
|
+
const inputNode = useRef<any>();
|
|
135
|
+
|
|
136
|
+
const onAdornmentClick = () => {
|
|
137
|
+
inputNode.current.focus();
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
if (inline && inputNode.current) {
|
|
142
|
+
setInputWidth(countWidth(value || placeholder, inputNode.current) + 1);
|
|
143
|
+
}
|
|
144
|
+
}, [value]);
|
|
145
|
+
|
|
146
|
+
const InputComp = useMemo(() => {
|
|
147
|
+
switch (variant) {
|
|
148
|
+
default:
|
|
149
|
+
case 'standard':
|
|
150
|
+
return Input;
|
|
151
|
+
case 'filled':
|
|
152
|
+
return FilledInput;
|
|
153
|
+
case 'outlined':
|
|
154
|
+
return OutlinedInput;
|
|
155
|
+
}
|
|
156
|
+
}, [variant]);
|
|
157
|
+
|
|
158
|
+
return (
|
|
159
|
+
<FormControl
|
|
160
|
+
fullWidth
|
|
161
|
+
error={invalid}
|
|
162
|
+
variant={variant}
|
|
163
|
+
margin="none"
|
|
164
|
+
className={clsx(className, classes.inputWrapper)}
|
|
165
|
+
>
|
|
166
|
+
{
|
|
167
|
+
label && (
|
|
168
|
+
<InputLabel
|
|
169
|
+
classes={{
|
|
170
|
+
root: clsx(
|
|
171
|
+
fieldClasses.label,
|
|
172
|
+
'd-flex',
|
|
173
|
+
'overflow-visible',
|
|
174
|
+
rightAligned && classes.rightLabel
|
|
175
|
+
),
|
|
176
|
+
}}
|
|
177
|
+
shrink={shrink}
|
|
178
|
+
htmlFor={`input-${name}`}
|
|
179
|
+
>
|
|
180
|
+
<span className={classes.label}>
|
|
181
|
+
{label}
|
|
182
|
+
</span>
|
|
183
|
+
{labelAdornment}
|
|
184
|
+
</InputLabel>
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
{CustomInput ||
|
|
188
|
+
<InputComp
|
|
189
|
+
{...InputProps || {}}
|
|
190
|
+
label={label}
|
|
191
|
+
inputRef={inputNode}
|
|
192
|
+
inputProps={{
|
|
193
|
+
placeholder,
|
|
194
|
+
disabled,
|
|
195
|
+
className: clsx(fieldClasses.text, {
|
|
196
|
+
[classes.inlineInput]: inline,
|
|
197
|
+
[classes.readonly]: disabled,
|
|
198
|
+
[classes.hideArrows]: hideArrows,
|
|
199
|
+
'text-end': rightAligned
|
|
200
|
+
}),
|
|
201
|
+
style: {
|
|
202
|
+
width: inline && !invalid ? inputWidth : undefined
|
|
203
|
+
},
|
|
204
|
+
...InputProps?.inputProps || {}
|
|
205
|
+
}}
|
|
206
|
+
classes={{
|
|
207
|
+
root: clsx(fieldClasses.text, inline && classes.inlineInput),
|
|
208
|
+
underline: fieldClasses.underline
|
|
209
|
+
}}
|
|
210
|
+
disabled={disabled}
|
|
211
|
+
endAdornment={!disabled &&
|
|
212
|
+
<InputAdornment
|
|
213
|
+
position="end"
|
|
214
|
+
onClick={onAdornmentClick}
|
|
215
|
+
className={clsx(classes.inputEndAdornment, endAdornmentClass, {
|
|
216
|
+
['fsInherit']: inline,
|
|
217
|
+
['d-none']: (rightAligned || inline),
|
|
218
|
+
['invisible']: !(rightAligned || inline)
|
|
219
|
+
})}
|
|
220
|
+
>
|
|
221
|
+
{editIcon}
|
|
222
|
+
</InputAdornment>
|
|
223
|
+
}
|
|
224
|
+
id={`input-${name}`}
|
|
225
|
+
name={name}
|
|
226
|
+
/>
|
|
227
|
+
}
|
|
228
|
+
<FormHelperText
|
|
229
|
+
classes={{
|
|
230
|
+
root: clsx(rightAligned && 'text-end'),
|
|
231
|
+
error: 'shakingError'
|
|
232
|
+
}}
|
|
233
|
+
>
|
|
234
|
+
{error}
|
|
235
|
+
{warning && <WarningMessage warning={warning} />}
|
|
236
|
+
</FormHelperText>
|
|
237
|
+
</FormControl>
|
|
238
|
+
);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export default EditInPlaceFieldBase;
|
|
@@ -0,0 +1,67 @@
|
|
|
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 Select and Text Field with edit in plaxce functional
|
|
11
|
+
* */
|
|
12
|
+
|
|
13
|
+
import React, { useRef } from 'react';
|
|
14
|
+
import AttachmentIcon from '@mui/icons-material/Attachment';
|
|
15
|
+
import InputAdornment from '@mui/material/InputAdornment';
|
|
16
|
+
import EditInPlaceField from './EditInPlaceField';
|
|
17
|
+
import { EditInPlaceFieldProps, FieldInputProps, FieldMetaProps } from '@src/model';
|
|
18
|
+
import { stubFunction } from '@src/utils';
|
|
19
|
+
|
|
20
|
+
function EditInPlaceFileField<InputProps extends FieldInputProps, MetaProps extends FieldMetaProps>(
|
|
21
|
+
{
|
|
22
|
+
input,
|
|
23
|
+
...restProps
|
|
24
|
+
}: EditInPlaceFieldProps<InputProps, MetaProps>) {
|
|
25
|
+
|
|
26
|
+
const inputRef = useRef<HTMLInputElement>();
|
|
27
|
+
const fileRef = useRef<HTMLInputElement>();
|
|
28
|
+
|
|
29
|
+
const handleFileSelect = e => {
|
|
30
|
+
if (e.target.files[0]) {
|
|
31
|
+
input.onChange(e.target.files[0]);
|
|
32
|
+
fileRef.current.value = null;
|
|
33
|
+
inputRef.current.blur();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const onFocus = () => {
|
|
38
|
+
fileRef.current.click();
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
inputRef.current.blur();
|
|
41
|
+
}, 200);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<input type="file" ref={fileRef} onChange={handleFileSelect} className="d-none" />
|
|
47
|
+
<EditInPlaceField
|
|
48
|
+
{...restProps}
|
|
49
|
+
input={{
|
|
50
|
+
onChange: stubFunction,
|
|
51
|
+
onFocus: stubFunction,
|
|
52
|
+
onBlur: stubFunction
|
|
53
|
+
}}
|
|
54
|
+
InputProps={{
|
|
55
|
+
startAdornment: <InputAdornment position="start"><AttachmentIcon /></InputAdornment>,
|
|
56
|
+
onFocus,
|
|
57
|
+
inputProps: {
|
|
58
|
+
ref: inputRef
|
|
59
|
+
},
|
|
60
|
+
value: input.value ? input.value.name : '',
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default EditInPlaceFileField;
|
|
@@ -0,0 +1,64 @@
|
|
|
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, { useCallback } from 'react';
|
|
10
|
+
import { NumericFormat } from 'react-number-format';
|
|
11
|
+
import InputAdornment from '@mui/material/InputAdornment';
|
|
12
|
+
import clsx from 'clsx';
|
|
13
|
+
import EditInPlaceField from './EditInPlaceField';
|
|
14
|
+
import { EditInPlaceFieldProps } from '@src/model';
|
|
15
|
+
import { formatCurrency, normalizeNumber } from '@src/utils';
|
|
16
|
+
import { Dispatch } from 'redux';
|
|
17
|
+
|
|
18
|
+
interface NumberFormatCustomProps {
|
|
19
|
+
onChange?: (event: { target: { value: string } }) => void;
|
|
20
|
+
decimalScale: number;
|
|
21
|
+
allowNegative: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const NumberFormatCustom = React.forwardRef<any, NumberFormatCustomProps>((props, ref) => {
|
|
25
|
+
const { onChange, allowNegative = true, ...other } = props;
|
|
26
|
+
|
|
27
|
+
const onValueChange = useCallback(values => {
|
|
28
|
+
onChange(normalizeNumber(values.value));
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<NumericFormat
|
|
33
|
+
{...other}
|
|
34
|
+
getInputRef={ref}
|
|
35
|
+
onValueChange={onValueChange}
|
|
36
|
+
allowNegative={allowNegative}
|
|
37
|
+
decimalScale={2}
|
|
38
|
+
thousandSeparator
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
interface Props<InputProps, MetaProps> extends EditInPlaceFieldProps<InputProps, MetaProps> {
|
|
44
|
+
currencySymbol: string;
|
|
45
|
+
dispatch?: Dispatch;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const preformatDisplayValue = value => value || value === 0 ? formatCurrency(value, '') : value;
|
|
49
|
+
|
|
50
|
+
function EditInPlaceMoneyField<IP, MP>({ InputProps, currencySymbol, dispatch, className, ...restProps }: Props<IP, MP>) {
|
|
51
|
+
return (
|
|
52
|
+
<EditInPlaceField
|
|
53
|
+
{...restProps}
|
|
54
|
+
preformatDisplayValue={preformatDisplayValue}
|
|
55
|
+
InputProps={{
|
|
56
|
+
...InputProps,
|
|
57
|
+
startAdornment: <InputAdornment position="start">{currencySymbol}</InputAdornment>,
|
|
58
|
+
inputComponent: NumberFormatCustom as any,
|
|
59
|
+
}}
|
|
60
|
+
className={clsx('money', className)}
|
|
61
|
+
/>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
export default EditInPlaceMoneyField;
|
|
@@ -0,0 +1,97 @@
|
|
|
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, {
|
|
10
|
+
useCallback, useEffect, useRef, useState
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { PatternFormat } from 'react-number-format';
|
|
13
|
+
import InputAdornment from '@mui/material/InputAdornment';
|
|
14
|
+
import PhoneIcon from '@mui/icons-material/Phone';
|
|
15
|
+
import debounce from 'lodash.debounce';
|
|
16
|
+
import EditInPlaceField from './EditInPlaceField';
|
|
17
|
+
import { AnyArgFunction, EditInPlaceFieldProps, FieldInputProps, FieldMetaProps } from '@src/model';
|
|
18
|
+
import { getPhoneMask } from '@src/utils';
|
|
19
|
+
|
|
20
|
+
interface NumberFormatCustomProps {
|
|
21
|
+
onChange?: (event: any) => void;
|
|
22
|
+
value?: string;
|
|
23
|
+
input?: Partial<Omit<FieldInputProps, 'onBlur'>> & { onBlur?: AnyArgFunction };
|
|
24
|
+
meta?: Partial<FieldMetaProps>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const NumberFormatCustom = React.forwardRef<any, NumberFormatCustomProps>((props, ref) => {
|
|
28
|
+
const { onChange, ...other } = props;
|
|
29
|
+
|
|
30
|
+
const inputRef = useRef<any>();
|
|
31
|
+
|
|
32
|
+
const [format, setFormat] = useState(null);
|
|
33
|
+
const [prefix, setPrefix] = useState(undefined);
|
|
34
|
+
|
|
35
|
+
const processFormat = useCallback(debounce(data => {
|
|
36
|
+
setFormat(getPhoneMask(data.value));
|
|
37
|
+
if (!data.value) {
|
|
38
|
+
setPrefix(undefined);
|
|
39
|
+
}
|
|
40
|
+
if (data.formattedValue.startsWith('+') && prefix !== '+') {
|
|
41
|
+
setPrefix('+');
|
|
42
|
+
}
|
|
43
|
+
}, 500), []);
|
|
44
|
+
|
|
45
|
+
const onValueChange = useCallback(data => {
|
|
46
|
+
onChange(data.formattedValue?.replace(/[^0-9+]/g, '') || null);
|
|
47
|
+
processFormat(data);
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (other.value) {
|
|
52
|
+
setFormat(getPhoneMask(other.value));
|
|
53
|
+
}
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const onKeyPress = e => {
|
|
57
|
+
if (e.key === '+') {
|
|
58
|
+
inputRef.current._valueTracker.setValue('+');
|
|
59
|
+
if (prefix !== '+') {
|
|
60
|
+
setPrefix('+');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const getInputRef = input => {
|
|
66
|
+
ref = input;
|
|
67
|
+
inputRef.current = input;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<PatternFormat
|
|
72
|
+
{...other}
|
|
73
|
+
getInputRef={getInputRef}
|
|
74
|
+
onKeyPress={onKeyPress}
|
|
75
|
+
prefix={prefix}
|
|
76
|
+
onValueChange={onValueChange}
|
|
77
|
+
format={format}
|
|
78
|
+
type="text"
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
function EditInPlacePhoneField<FP extends FieldInputProps, MP extends FieldMetaProps>({ InputProps, className, ...restProps }: EditInPlaceFieldProps<FP, MP>) {
|
|
84
|
+
return (
|
|
85
|
+
<EditInPlaceField
|
|
86
|
+
{...restProps}
|
|
87
|
+
InputProps={{
|
|
88
|
+
...InputProps,
|
|
89
|
+
startAdornment: <InputAdornment position="start"><PhoneIcon /></InputAdornment>,
|
|
90
|
+
inputComponent: NumberFormatCustom
|
|
91
|
+
}}
|
|
92
|
+
className={className}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default EditInPlacePhoneField;
|