tp-react-elements 2.0.3 → 2.0.5
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/README.md +6 -2
- package/dist/_virtual/index.esm11.js +2 -2
- package/dist/_virtual/index.esm12.js +2 -2
- package/dist/_virtual/index.esm13.js +2 -2
- package/dist/_virtual/index.esm14.js +2 -2
- package/dist/_virtual/index.esm4.js +2 -2
- package/dist/_virtual/index.esm5.js +2 -2
- package/dist/_virtual/index.esm6.js +2 -2
- package/dist/components/DateRangePicker/DateRangePicker.esm.js +49 -72
- package/dist/components/Form/FormRender.esm.js +1 -1
- package/dist/components/FormComponents/DatePicker/DatepickerWrapperV2.esm.js +10 -15
- package/dist/components/FormComponents/DatePicker/DatetimepickerWrapper.esm.js +53 -61
- package/dist/components/FormComponents/FileUpload/FormRenderFileUpload.esm.js +54 -68
- package/dist/components/FormComponents/FileUpload/FormRenderMultiFileUpload.esm.js +61 -76
- package/dist/components/FormComponents/FileUpload/MultiFileWithPreview.esm.js +103 -132
- package/dist/components/FormComponents/FormNumberField/FormNumberField.d.ts +0 -38
- package/dist/components/FormComponents/FormNumberField/FormNumberField.esm.js +32 -97
- package/dist/components/FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js +44 -38
- package/dist/components/FormComponents/FormTextField/FormTextField.esm.js +3 -3
- package/dist/components/FormComponents/FormTextFieldWithSelect/FormTextFieldWithSelect.esm.js +3 -2
- package/dist/components/FormComponents/PasswordField/PasswordField.esm.js +4 -4
- package/dist/components/FormComponents/RichTextEditor/RichTextEditor.esm.js +23 -22
- package/dist/components/FormComponents/Select/SearchableSelect.esm.js +9 -9
- package/dist/components/FormComponents/TimePicker/TimePicker.esm.js +19 -19
- package/dist/components/FormComponents/index.esm.js +2 -2
- package/dist/components/ModalField/ConfirmationDialog.esm.js +3 -3
- package/dist/components/ModalField/ModalField.esm.js +5 -12
- package/dist/components/PaginatedGrid/DynamicFilterBar.d.ts +17 -2
- package/dist/components/PaginatedGrid/DynamicFilterBar.esm.js +161 -61
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +21 -3
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +133 -92
- package/dist/components/SelectField/MultiSelectFieldComponent.esm.js +3 -3
- package/dist/components/SessionTimeOut/SessionTimeOut.esm.js +33 -34
- package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRangePicker/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DayCell/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/Month/index.esm.js +1 -1
- package/package.json +1 -1
|
@@ -1,108 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
2
3
|
import { TextField } from '@mui/material';
|
|
3
|
-
import {
|
|
4
|
+
import { useController } from 'react-hook-form';
|
|
4
5
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
5
6
|
import 'dayjs';
|
|
6
7
|
import { renderLabel } from '../../../utils/Constants/FormConstants.esm.js';
|
|
7
8
|
|
|
8
|
-
/**
|
|
9
|
-
* FormNumberField Component
|
|
10
|
-
*
|
|
11
|
-
* A numeric input field component that integrates with react-hook-form.
|
|
12
|
-
* This component is used for integer inputs, phone numbers, and pincodes.
|
|
13
|
-
* It restricts input to numeric characters only.
|
|
14
|
-
*
|
|
15
|
-
* @component
|
|
16
|
-
* @param {Object} props - The component props
|
|
17
|
-
* @param {FormRenderProps} props.props - Form rendering properties from parent form
|
|
18
|
-
* @param {VariantProps} props.variant - UI variant style ('standard', 'outlined', etc.)
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* // Basic usage in FormRender
|
|
22
|
-
* <FormNumberField props={formRenderProps} variant="outlined" />
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* // Usage with specific configuration
|
|
26
|
-
* const formItem = {
|
|
27
|
-
* name: "phoneNumber",
|
|
28
|
-
* label: "Phone Number",
|
|
29
|
-
* inputType: "number",
|
|
30
|
-
* required: true,
|
|
31
|
-
* maxLength: 10
|
|
32
|
-
* };
|
|
33
|
-
* <FormNumberField
|
|
34
|
-
* props={{
|
|
35
|
-
* item: formItem,
|
|
36
|
-
* control: formMethods.control,
|
|
37
|
-
* errors: formMethods.formState.errors
|
|
38
|
-
* }}
|
|
39
|
-
* variant="outlined"
|
|
40
|
-
* />
|
|
41
|
-
*/
|
|
42
9
|
const FormNumberField = ({ props, variant }) => {
|
|
43
|
-
/**
|
|
44
|
-
* Determines if the field has an error based on form validation
|
|
45
|
-
*/
|
|
46
10
|
const isError = !!props.errors?.[props.item.name];
|
|
47
|
-
const isShowBorderError = isError;
|
|
48
|
-
/**
|
|
49
|
-
* Generates the field label based on variant type
|
|
50
|
-
* For non-standard variants, appends an asterisk if the field is required
|
|
51
|
-
*/
|
|
52
11
|
const label = variant !== 'standard' ? `${props.item.label}${props.item.required ? ' *' : ''}` : '';
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* @param {any} e - The blur event object
|
|
83
|
-
*/
|
|
84
|
-
onBlur: (e) => {
|
|
85
|
-
props?.item?.onBlurFn && props?.item?.onBlurFn(e);
|
|
86
|
-
}, sx: {
|
|
87
|
-
'& .css-1holvmy,.css-lqj8pz-MuiFormLabel-root-MuiInputLabel-root,.css-kichxs-MuiFormLabel-root-MuiInputLabel-root': {
|
|
88
|
-
top: '-10px',
|
|
89
|
-
},
|
|
90
|
-
}, placeholder: props.item.placeholder || '',
|
|
91
|
-
/**
|
|
92
|
-
* Additional input properties for the TextField
|
|
93
|
-
* Controls input pattern, length restrictions, and additional input handling
|
|
94
|
-
*/
|
|
95
|
-
onInput: (e) => {
|
|
96
|
-
props.item.onInputProps && props.item.onInputProps(e);
|
|
97
|
-
}, inputProps: {
|
|
98
|
-
pattern: '[0-9]*',
|
|
99
|
-
maxLength: props.item.maxLength || 20,
|
|
100
|
-
maxValue: props.item.maxValue || 9999999999,
|
|
101
|
-
'aria-labelledby': `${props.item.name}-label`,
|
|
102
|
-
'aria-describedby': `${props.item.name}-helper ${props.item.name}-error`,
|
|
103
|
-
'aria-required': props.item.required ? true : undefined,
|
|
104
|
-
}, disabled: props.item.disable }), jsx(FormBottomField, { ...props })] }));
|
|
105
|
-
} }, props.item.name) }));
|
|
12
|
+
// useController gives a stable `field` reference outside any render prop,
|
|
13
|
+
// enabling proper useCallback usage for the event handlers below.
|
|
14
|
+
const { field } = useController({ control: props.control, name: props.item.name });
|
|
15
|
+
const handleChange = useCallback((e) => {
|
|
16
|
+
const sanitized = String(e.target.value || '').replace(/[^0-9]/g, '');
|
|
17
|
+
const nextValue = sanitized === '' ? null : sanitized;
|
|
18
|
+
field.onChange(nextValue);
|
|
19
|
+
props?.item?.onChangeFn && props?.item?.onChangeFn(nextValue);
|
|
20
|
+
props?.clearErrors && props?.clearErrors(props.item.name);
|
|
21
|
+
if (nextValue && props.item.maxValue && parseInt(nextValue) > props.item.maxValue) {
|
|
22
|
+
field.onChange(props.item.maxValue);
|
|
23
|
+
}
|
|
24
|
+
}, [field, props.item, props.clearErrors]);
|
|
25
|
+
const handleBlur = useCallback((e) => {
|
|
26
|
+
props?.item?.onBlurFn && props?.item?.onBlurFn(e);
|
|
27
|
+
}, [props.item.onBlurFn]);
|
|
28
|
+
const handleInput = useCallback((e) => {
|
|
29
|
+
props.item.onInputProps && props.item.onInputProps(e);
|
|
30
|
+
}, [props.item.onInputProps]);
|
|
31
|
+
return (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(TextField, { ...field, size: "small", label: label, error: isError, value: field.value ?? '', onChange: handleChange, onBlur: handleBlur, onInput: handleInput, sx: {
|
|
32
|
+
'& .css-1holvmy,.css-lqj8pz-MuiFormLabel-root-MuiInputLabel-root,.css-kichxs-MuiFormLabel-root-MuiInputLabel-root': { top: '-10px' },
|
|
33
|
+
}, placeholder: props.item.placeholder || '', inputProps: {
|
|
34
|
+
pattern: '[0-9]*',
|
|
35
|
+
maxLength: props.item.maxLength || 20,
|
|
36
|
+
maxValue: props.item.maxValue || 9999999999,
|
|
37
|
+
'aria-labelledby': `${props.item.name}-label`,
|
|
38
|
+
'aria-describedby': `${props.item.name}-helper ${props.item.name}-error`,
|
|
39
|
+
'aria-required': props.item.required ? true : undefined,
|
|
40
|
+
}, disabled: props.item.disable }), jsx(FormBottomField, { ...props })] }));
|
|
106
41
|
};
|
|
107
42
|
|
|
108
43
|
export { FormNumberField as default };
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
2
3
|
import { TextField } from '@mui/material';
|
|
3
|
-
import {
|
|
4
|
+
import { useController } from 'react-hook-form';
|
|
4
5
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
5
6
|
import 'dayjs';
|
|
6
7
|
import { renderLabel } from '../../../utils/Constants/FormConstants.esm.js';
|
|
7
8
|
|
|
8
9
|
const FormNumberFieldDecimal = ({ props, variant, }) => {
|
|
9
10
|
const fixedLength = props.item.decimalFixedTo || 2;
|
|
10
|
-
const
|
|
11
|
+
const label = variant !== 'standard' ? `${props.item.label}${props.item.required ? ' *' : ''}` : '';
|
|
12
|
+
const isError = !!props.errors?.[props.item.name];
|
|
13
|
+
const { field } = useController({
|
|
14
|
+
control: props.control,
|
|
15
|
+
name: props.item.name,
|
|
16
|
+
disabled: props.item?.disable,
|
|
17
|
+
});
|
|
18
|
+
const sanitizeDecimal = useCallback((raw) => {
|
|
11
19
|
let next = (raw ?? '').replace(/[^0-9.-]/g, '');
|
|
12
|
-
// Collapse multiple '-' to one at start
|
|
13
20
|
next = next.replace(/(?!^)-/g, '');
|
|
14
21
|
if (next.includes('.')) {
|
|
15
22
|
const [intPart, decPart] = next.split('.');
|
|
@@ -17,40 +24,39 @@ const FormNumberFieldDecimal = ({ props, variant, }) => {
|
|
|
17
24
|
next = `${intPart}.${clampedDec}`;
|
|
18
25
|
}
|
|
19
26
|
return next;
|
|
20
|
-
};
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} }), jsx(FormBottomField, { ...props })] })) }, props.item.name));
|
|
27
|
+
}, [fixedLength]);
|
|
28
|
+
const handleChange = useCallback((e) => {
|
|
29
|
+
const sanitized = sanitizeDecimal(e.target.value ?? '');
|
|
30
|
+
const value = sanitized === '' ? null : sanitized;
|
|
31
|
+
field.onChange(value);
|
|
32
|
+
props?.clearErrors && props?.clearErrors(props.item.name);
|
|
33
|
+
}, [sanitizeDecimal, field, props.item.name, props.clearErrors]);
|
|
34
|
+
const handleBlur = useCallback((e) => {
|
|
35
|
+
props?.item?.onBlurFn && props?.item?.onBlurFn(e);
|
|
36
|
+
}, [props.item.onBlurFn]);
|
|
37
|
+
const handleInput = useCallback((e) => {
|
|
38
|
+
props.item.onInputProps && props.item.onInputProps(e);
|
|
39
|
+
}, [props.item.onInputProps]);
|
|
40
|
+
return (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(TextField, { type: "text", size: "small", label: label, error: isError, ...field, value: field.value ?? '', onChange: handleChange, onBlur: handleBlur, sx: {
|
|
41
|
+
'& input': {
|
|
42
|
+
textAlign: 'right',
|
|
43
|
+
},
|
|
44
|
+
'& input::placeholder': {
|
|
45
|
+
textAlign: 'left',
|
|
46
|
+
},
|
|
47
|
+
'& .css-16hdwvj,.css-1idq7r3-MuiFormLabel-root-MuiInputLabel-root': {
|
|
48
|
+
top: '-5px',
|
|
49
|
+
},
|
|
50
|
+
}, placeholder: props.item.placeholder || '', InputProps: {
|
|
51
|
+
inputProps: {
|
|
52
|
+
onInput: handleInput,
|
|
53
|
+
inputMode: 'decimal',
|
|
54
|
+
maxLength: 20,
|
|
55
|
+
'aria-labelledby': `${props.item.name}-label`,
|
|
56
|
+
'aria-describedby': `${props.item.name}-helper ${props.item.name}-error`,
|
|
57
|
+
'aria-required': props.item.required ? true : undefined,
|
|
58
|
+
},
|
|
59
|
+
} }), jsx(FormBottomField, { ...props })] }));
|
|
54
60
|
};
|
|
55
61
|
|
|
56
62
|
export { FormNumberFieldDecimal as default };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
2
3
|
import { Controller } from 'react-hook-form';
|
|
3
4
|
import { Tooltip, Box } from '@mui/material';
|
|
4
5
|
import { FormTextFieldComponent } from './FormTextField.styles.esm.js';
|
|
@@ -58,7 +59,7 @@ const FormTextField = ({ props, variant }) => {
|
|
|
58
59
|
* - Prevents input that starts with a space
|
|
59
60
|
* - Calls custom onInputProps handler if provided
|
|
60
61
|
*/
|
|
61
|
-
const onInput = (e) => {
|
|
62
|
+
const onInput = useCallback((e) => {
|
|
62
63
|
if (props?.item?.donotAllowSpace) {
|
|
63
64
|
const value = e.target.value;
|
|
64
65
|
e.target.value = value.replace(' ', '');
|
|
@@ -79,12 +80,11 @@ const FormTextField = ({ props, variant }) => {
|
|
|
79
80
|
const value = e.target.value;
|
|
80
81
|
e.target.value = value.replace(/-/g, '');
|
|
81
82
|
}
|
|
82
|
-
// Allow only alphanumeric and space
|
|
83
83
|
if (e.target.value.length === 1 && e.target.value === ' ') {
|
|
84
84
|
e.target.value = '';
|
|
85
85
|
}
|
|
86
86
|
props.item.onInputProps && props.item.onInputProps(e);
|
|
87
|
-
};
|
|
87
|
+
}, [props.item]);
|
|
88
88
|
/**
|
|
89
89
|
* Renders the text field component using react-hook-form's Controller
|
|
90
90
|
* for controlled form state management
|
package/dist/components/FormComponents/FormTextFieldWithSelect/FormTextFieldWithSelect.esm.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useCallback } from 'react';
|
|
2
3
|
import { Controller } from 'react-hook-form';
|
|
3
4
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
4
5
|
import 'dayjs';
|
|
@@ -57,11 +58,11 @@ const FormTextFieldWithSelect = ({ props, variant, }) => {
|
|
|
57
58
|
* - Prevents input that starts with a space
|
|
58
59
|
* - Calls custom onInputProps handler if provided
|
|
59
60
|
*/
|
|
60
|
-
const onInput = (e) => {
|
|
61
|
+
const onInput = useCallback((e) => {
|
|
61
62
|
props.item.onInputProps && props.item.onInputProps(e);
|
|
62
63
|
const filteredValue = e.target.value.replace(/[^a-zA-Z0-9._]/g, '');
|
|
63
64
|
e.target.value = filteredValue;
|
|
64
|
-
};
|
|
65
|
+
}, [props.item.onInputProps]);
|
|
65
66
|
/**
|
|
66
67
|
* Renders the text field component using react-hook-form's Controller
|
|
67
68
|
* for controlled form state management
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { Visibility, VisibilityOff } from '@mui/icons-material';
|
|
3
3
|
import { Box, FormControl, TextField, IconButton } from '@mui/material';
|
|
4
|
-
import { useState } from 'react';
|
|
4
|
+
import { useState, useCallback } from 'react';
|
|
5
5
|
import { Controller } from 'react-hook-form';
|
|
6
6
|
import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
|
|
7
7
|
import 'dayjs';
|
|
@@ -30,9 +30,9 @@ const PasswordField = ({ props, variant }) => {
|
|
|
30
30
|
/**
|
|
31
31
|
* Toggles password visibility between plain text and hidden
|
|
32
32
|
*/
|
|
33
|
-
const handleTogglePasswordVisibility = () => {
|
|
34
|
-
setShowPassword((
|
|
35
|
-
};
|
|
33
|
+
const handleTogglePasswordVisibility = useCallback(() => {
|
|
34
|
+
setShowPassword((prev) => !prev);
|
|
35
|
+
}, []);
|
|
36
36
|
/**
|
|
37
37
|
* Generates the field label based on variant type
|
|
38
38
|
* For non-standard variants, appends an asterisk if the field is required
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useRef, useState, useEffect } from 'react';
|
|
2
|
+
import { useRef, useState, useEffect, useMemo, useCallback } from 'react';
|
|
3
3
|
import { useWatch } from 'react-hook-form';
|
|
4
4
|
import { getJoditEditor } from './jodit.index.esm.js';
|
|
5
5
|
|
|
@@ -13,10 +13,7 @@ const RichTextEditor = ({ props }) => {
|
|
|
13
13
|
const loadJoditDependencies = async () => {
|
|
14
14
|
try {
|
|
15
15
|
const joditEditorModule = await getJoditEditor();
|
|
16
|
-
|
|
17
|
-
const Editor = joditEditorModule?.default
|
|
18
|
-
? joditEditorModule.default
|
|
19
|
-
: joditEditorModule;
|
|
16
|
+
const Editor = joditEditorModule?.default ?? joditEditorModule;
|
|
20
17
|
setJoditEditor(() => Editor);
|
|
21
18
|
setIsLoading(false);
|
|
22
19
|
}
|
|
@@ -26,7 +23,9 @@ const RichTextEditor = ({ props }) => {
|
|
|
26
23
|
};
|
|
27
24
|
loadJoditDependencies();
|
|
28
25
|
}, []);
|
|
29
|
-
|
|
26
|
+
// Memoised Jodit config — only rebuilds when the item-level options change,
|
|
27
|
+
// not on every keystroke / re-render of the parent form.
|
|
28
|
+
const config = useMemo(() => ({
|
|
30
29
|
readonly: false,
|
|
31
30
|
placeholder: props.item.placeholder || 'Start typing...',
|
|
32
31
|
statusbar: false,
|
|
@@ -36,8 +35,8 @@ const RichTextEditor = ({ props }) => {
|
|
|
36
35
|
font: { list: { Arial: 'Arial', ...props.item?.FontFamily } },
|
|
37
36
|
fontsize: {
|
|
38
37
|
list: props.item.Fonts || [
|
|
39
|
-
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
40
|
-
25, 26, 27, 28, 29, 30,
|
|
38
|
+
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
|
|
39
|
+
24, 25, 26, 27, 28, 29, 30,
|
|
41
40
|
],
|
|
42
41
|
},
|
|
43
42
|
},
|
|
@@ -81,25 +80,27 @@ const RichTextEditor = ({ props }) => {
|
|
|
81
80
|
},
|
|
82
81
|
},
|
|
83
82
|
...props.item.sx,
|
|
84
|
-
}
|
|
83
|
+
}),
|
|
84
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
85
|
+
[
|
|
86
|
+
props.item.placeholder,
|
|
87
|
+
props.item.removeButtons,
|
|
88
|
+
props.item.FontFamily,
|
|
89
|
+
props.item.Fonts,
|
|
90
|
+
props.item.sx,
|
|
91
|
+
]);
|
|
85
92
|
useEffect(() => {
|
|
86
93
|
setContent(value);
|
|
87
94
|
}, [value]);
|
|
88
|
-
const handleBlur = (newContent) => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
setContent(newContent);
|
|
95
|
-
props.setValue(props.item.name, newContent);
|
|
96
|
-
}
|
|
97
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
95
|
+
const handleBlur = useCallback((newContent) => {
|
|
96
|
+
const normalized = newContent === '<p><br></p>' ? '' : newContent;
|
|
97
|
+
setContent(newContent);
|
|
98
|
+
props.setValue(props.item.name, normalized);
|
|
98
99
|
props.item.onBlurFn && props.item.onBlurFn(newContent);
|
|
99
|
-
};
|
|
100
|
-
const handleChange = (newContent) => {
|
|
100
|
+
}, [props.setValue, props.item.name, props.item.onBlurFn]);
|
|
101
|
+
const handleChange = useCallback((newContent) => {
|
|
101
102
|
props.item.onChangeFn && props.item.onChangeFn(newContent);
|
|
102
|
-
};
|
|
103
|
+
}, [props.item.onChangeFn]);
|
|
103
104
|
if (isLoading || !JoditEditor) {
|
|
104
105
|
return jsx("div", { children: "Loading editor..." });
|
|
105
106
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
3
3
|
import { FormControl, Box, TextField, InputAdornment, Popover, List, Typography, ListItemButton, ListItemText } from '@mui/material';
|
|
4
4
|
import SearchIcon from '@mui/icons-material/Search';
|
|
5
5
|
import CheckIcon from '@mui/icons-material/Check';
|
|
@@ -17,23 +17,23 @@ const SearchableSelect = ({ props, variant, }) => {
|
|
|
17
17
|
// Find the label that corresponds to the currently selected value
|
|
18
18
|
const selectedOption = options.find((o) => String(o.value) === String(value ?? ''));
|
|
19
19
|
const displayValue = selectedOption ? String(selectedOption.label) : '';
|
|
20
|
-
const handleOpen = (e) => {
|
|
20
|
+
const handleOpen = useCallback((e) => {
|
|
21
21
|
if (props.item.disable)
|
|
22
22
|
return;
|
|
23
23
|
setSearch('');
|
|
24
24
|
setAnchorEl(e.currentTarget);
|
|
25
|
-
};
|
|
26
|
-
const handleClose = () => setAnchorEl(null);
|
|
27
|
-
const handleSelect = (val) => {
|
|
25
|
+
}, [props.item.disable]);
|
|
26
|
+
const handleClose = useCallback(() => setAnchorEl(null), []);
|
|
27
|
+
const handleSelect = useCallback((val) => {
|
|
28
28
|
props.setValue(props.item.name, val);
|
|
29
29
|
props.item.onChangeFn && props.item.onChangeFn(val);
|
|
30
30
|
props.clearErrors && props.clearErrors(props.item.name);
|
|
31
|
-
|
|
32
|
-
};
|
|
31
|
+
setAnchorEl(null);
|
|
32
|
+
}, [props.setValue, props.item.name, props.item.onChangeFn, props.clearErrors]);
|
|
33
33
|
// Case-insensitive substring filter across option labels
|
|
34
|
-
const filtered = search
|
|
34
|
+
const filtered = useMemo(() => search
|
|
35
35
|
? options.filter((o) => String(o.label).toLowerCase().includes(search.toLowerCase()))
|
|
36
|
-
: options;
|
|
36
|
+
: options, [search, options]);
|
|
37
37
|
// Label shown inside the MUI TextField (suppressed in 'standard' variant)
|
|
38
38
|
const muiLabel = variant !== 'standard'
|
|
39
39
|
? `${props.item.label}${props.item.required ? ' *' : ''}`
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { ErrorMessage } from '@hookform/error-message';
|
|
3
|
-
import { useState, useEffect } from 'react';
|
|
3
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
4
4
|
import { getTimePicker } from '../../../utils/Constants/date-pickers.esm.js';
|
|
5
5
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
6
6
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
7
7
|
import { useWatch, Controller } from 'react-hook-form';
|
|
8
8
|
import { ErrorMessageComponent } from '../../Form/Form.styles.esm.js';
|
|
9
9
|
import 'dayjs';
|
|
10
|
-
import {
|
|
10
|
+
import { parseCustomTime, formatDayjsToCustomTime, renderLabel } from '../../../utils/Constants/FormConstants.esm.js';
|
|
11
11
|
|
|
12
12
|
function TimePickerFieldWrapper({ props, variant, }) {
|
|
13
13
|
const [TimePicker, setTimePicker] = useState(null);
|
|
@@ -22,26 +22,26 @@ function TimePickerFieldWrapper({ props, variant, }) {
|
|
|
22
22
|
loadComponents();
|
|
23
23
|
}, []);
|
|
24
24
|
const value = useWatch({ control: props.control, name: props.item.name });
|
|
25
|
-
const
|
|
26
|
-
const
|
|
25
|
+
const isShowBorderError = !!props.errors?.[props.item.name];
|
|
26
|
+
const handleTimeChange = useCallback((newTime) => {
|
|
27
|
+
const parsedTime = parseCustomTime(formatDayjsToCustomTime(newTime));
|
|
28
|
+
const min = props.item.minTime ? parseCustomTime(props.item.minTime) : null;
|
|
29
|
+
const max = props.item.maxTime ? parseCustomTime(props.item.maxTime) : null;
|
|
30
|
+
let finalTime = parsedTime;
|
|
31
|
+
if (min && parsedTime?.isBefore(min)) {
|
|
32
|
+
finalTime = min;
|
|
33
|
+
}
|
|
34
|
+
else if (max && parsedTime?.isAfter(max)) {
|
|
35
|
+
finalTime = max;
|
|
36
|
+
}
|
|
37
|
+
const formatted = formatDayjsToCustomTime(finalTime);
|
|
38
|
+
props.setValue(props.item.name, formatted);
|
|
39
|
+
props.item.onChangeFn && props.item.onChangeFn(formatted);
|
|
40
|
+
}, [props.item.minTime, props.item.maxTime, props.item.name, props.item.onChangeFn, props.setValue]);
|
|
27
41
|
if (isLoading) {
|
|
28
42
|
return jsx("div", { style: { minHeight: '36px' }, children: "Loading..." });
|
|
29
43
|
}
|
|
30
|
-
return (jsx(Fragment, { children: TimePicker && (jsxs(LocalizationProvider, { dateAdapter: AdapterDayjs, children: [jsx(Controller, { name: props.item.name, control: props.control, render: ({ field }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(TimePicker, { ...field, value: value ? parseCustomTime(value) : null, onChange:
|
|
31
|
-
const parsedTime = parseCustomTime(formatDayjsToCustomTime(newTime));
|
|
32
|
-
const min = props.item.minTime ? parseCustomTime(props.item.minTime) : null;
|
|
33
|
-
const max = props.item.maxTime ? parseCustomTime(props.item.maxTime) : null;
|
|
34
|
-
let finalTime = parsedTime;
|
|
35
|
-
if (min && parsedTime?.isBefore(min)) {
|
|
36
|
-
finalTime = min;
|
|
37
|
-
}
|
|
38
|
-
else if (max && parsedTime?.isAfter(max)) {
|
|
39
|
-
finalTime = max;
|
|
40
|
-
}
|
|
41
|
-
const formatted = formatDayjsToCustomTime(finalTime);
|
|
42
|
-
props.setValue(props.item.name, formatted);
|
|
43
|
-
props.item.onChangeFn && props.item.onChangeFn(formatted);
|
|
44
|
-
}, minTime: props.item.minTime
|
|
44
|
+
return (jsx(Fragment, { children: TimePicker && (jsxs(LocalizationProvider, { dateAdapter: AdapterDayjs, children: [jsx(Controller, { name: props.item.name, control: props.control, render: ({ field }) => (jsxs(Fragment, { children: [renderLabel(variant, props), jsx(TimePicker, { ...field, value: value ? parseCustomTime(value) : null, onChange: handleTimeChange, minTime: props.item.minTime
|
|
45
45
|
? parseCustomTime(props.item.minTime) || undefined
|
|
46
46
|
: undefined, maxTime: props.item.maxTime
|
|
47
47
|
? parseCustomTime(props.item.maxTime) || undefined
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
|
|
2
2
|
export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
|
|
3
3
|
export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
|
|
4
|
-
export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
|
|
5
4
|
export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
|
|
6
5
|
export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
|
|
7
6
|
export { default as SingleSelect } from './Select/SingleSelect.esm.js';
|
|
@@ -15,7 +14,6 @@ export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.j
|
|
|
15
14
|
export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
|
|
16
15
|
export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
|
|
17
16
|
export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
|
|
18
|
-
export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
|
|
19
17
|
export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
|
|
20
18
|
export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
|
|
21
19
|
import 'react/jsx-runtime';
|
|
@@ -34,6 +32,8 @@ import '@mui/icons-material/PictureAsPdf';
|
|
|
34
32
|
import '@mui/icons-material/TableChart';
|
|
35
33
|
import '@mui/icons-material/Description';
|
|
36
34
|
export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
|
|
35
|
+
export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
|
|
37
36
|
export { default as HelperText } from './HelperText/HelperText.esm.js';
|
|
38
37
|
export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
|
|
39
38
|
export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
|
|
39
|
+
export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
|
|
@@ -25,7 +25,7 @@ const ConfirmationDialog = ({ openConfirmDialog, handleCancel, onClickSubmit, te
|
|
|
25
25
|
fontSize: '14px',
|
|
26
26
|
cursor: 'move',
|
|
27
27
|
borderBottom: '1px solid rgb(229 231 235 / 1)',
|
|
28
|
-
}, children: [jsx("span", { children: title }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick:
|
|
28
|
+
}, children: [jsx("span", { children: title }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick: handleCancel })] }), jsxs(DialogContent, { style: { paddingTop: '20px', paddingBottom: 0 }, sx: {
|
|
29
29
|
'& .pt-0': {
|
|
30
30
|
paddingTop: 0,
|
|
31
31
|
},
|
|
@@ -33,14 +33,14 @@ const ConfirmationDialog = ({ openConfirmDialog, handleCancel, onClickSubmit, te
|
|
|
33
33
|
display: 'flex',
|
|
34
34
|
justifyContent: 'flex-end',
|
|
35
35
|
gap: '8px',
|
|
36
|
-
}, children: [jsx(SubmitButton, { variant: "contained", size: "small", type: "submit", onClick:
|
|
36
|
+
}, children: [jsx(SubmitButton, { variant: "contained", size: "small", type: "submit", onClick: onClickSubmit, children: Submit }), jsx(Button, { variant: "text",
|
|
37
37
|
// color="error"
|
|
38
38
|
size: "small", sx: {
|
|
39
39
|
textTransform: 'none',
|
|
40
40
|
color: '#000',
|
|
41
41
|
background: '#ececee',
|
|
42
42
|
':hover': { background: '#0009', color: '#fff' },
|
|
43
|
-
}, onClick:
|
|
43
|
+
}, onClick: handleCancel, children: Cancel })] }) })] }));
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
export { ConfirmationDialog as default };
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import CloseIcon from '@mui/icons-material/Close';
|
|
3
|
-
import { DialogContent, DialogActions
|
|
3
|
+
import { Slide, DialogContent, DialogActions } from '@mui/material';
|
|
4
4
|
import { DialogContainer, DialogTitleWrapper, SaveAsDraftButton, SubmitButton, CancelButton } from '../Global.styles.esm.js';
|
|
5
5
|
|
|
6
6
|
const ModalField = ({ name, openModal, handleCancel, content, width = '900px', Transition = '', handleSubmit, styles = {}, saveButton: isSaveButton = false, submitButton = true, handleSaveButton = () => null, SubmitButtonName = 'Submit', }) => {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
case 'Slide':
|
|
10
|
-
return Slide;
|
|
11
|
-
default:
|
|
12
|
-
return undefined;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
return (jsxs(DialogContainer, { open: openModal, TransitionComponent: TransitionComponent(), fullWidth: true, "aria-labelledby": "draggable-dialog-title", sx: {
|
|
7
|
+
const transitionComponent = Transition === 'Slide' ? Slide : undefined;
|
|
8
|
+
return (jsxs(DialogContainer, { open: openModal, TransitionComponent: transitionComponent, fullWidth: true, "aria-labelledby": "draggable-dialog-title", sx: {
|
|
16
9
|
zIndex: 20,
|
|
17
10
|
'& .css-tlc64q-MuiPaper-root-MuiDialog-paper,.css-mbdu2s': {
|
|
18
11
|
maxWidth: width,
|
|
19
12
|
},
|
|
20
13
|
...styles,
|
|
21
|
-
}, children: [jsxs(DialogTitleWrapper, { children: [jsx("span", { children: name }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick:
|
|
14
|
+
}, children: [jsxs(DialogTitleWrapper, { children: [jsx("span", { children: name }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick: handleCancel })] }), jsx(DialogContent, { style: { paddingTop: '20px', paddingBottom: 0 }, sx: {
|
|
22
15
|
'& .pt-0': {
|
|
23
16
|
paddingTop: 0,
|
|
24
17
|
},
|
|
@@ -26,7 +19,7 @@ const ModalField = ({ name, openModal, handleCancel, content, width = '900px', T
|
|
|
26
19
|
display: 'flex',
|
|
27
20
|
justifyContent: 'flex-end',
|
|
28
21
|
gap: '8px',
|
|
29
|
-
}, children: [isSaveButton && (jsx(SaveAsDraftButton, { variant: "contained", size: "small", onClick:
|
|
22
|
+
}, children: [isSaveButton && (jsx(SaveAsDraftButton, { variant: "contained", size: "small", onClick: handleSaveButton, children: "Save" })), submitButton && (jsx(SubmitButton, { variant: "contained", size: "small", onClick: handleSubmit, children: SubmitButtonName })), jsx(CancelButton, { variant: "text", size: "small", onClick: handleCancel, children: "Cancel" })] }) })] }));
|
|
30
23
|
};
|
|
31
24
|
|
|
32
25
|
export { ModalField as default };
|
|
@@ -96,6 +96,19 @@ export type ServerFilterDef = {
|
|
|
96
96
|
}[];
|
|
97
97
|
/** Show this chip in the filter bar on first render. Default: `false`. */
|
|
98
98
|
defaultVisible?: boolean;
|
|
99
|
+
} | {
|
|
100
|
+
/**
|
|
101
|
+
* Month-picker chip — lets users select **one or more months** across years.
|
|
102
|
+
* Selected months are stored as a comma-separated string of `"YYYY-MM"` values
|
|
103
|
+
* in `filterValues[filterKey]` (e.g. `"2025-01,2025-03"`).
|
|
104
|
+
* Split on `","` in your `fetchPage` handler to build the server query.
|
|
105
|
+
*/
|
|
106
|
+
type: 'monthPicker';
|
|
107
|
+
id: string;
|
|
108
|
+
label: string;
|
|
109
|
+
filterKey: string;
|
|
110
|
+
/** Show this chip in the filter bar on first render. Default: `false`. */
|
|
111
|
+
defaultVisible?: boolean;
|
|
99
112
|
};
|
|
100
113
|
interface AvailableColumn {
|
|
101
114
|
id: string;
|
|
@@ -119,7 +132,7 @@ export interface DynamicFilterBarProps {
|
|
|
119
132
|
filterValues: Record<string, string>;
|
|
120
133
|
onFilterValuesChange: (values: Record<string, string>) => void;
|
|
121
134
|
columnFilters: MRT_ColumnFiltersState;
|
|
122
|
-
onColumnFilterChange: (f: MRT_ColumnFiltersState) => void;
|
|
135
|
+
onColumnFilterChange: (f: MRT_ColumnFiltersState | ((prev: MRT_ColumnFiltersState) => MRT_ColumnFiltersState)) => void;
|
|
123
136
|
availableColumns: AvailableColumn[];
|
|
124
137
|
/** Maximum number of chips that may be visible at once. Default: 4. */
|
|
125
138
|
maxVisibleFilters?: number;
|
|
@@ -137,6 +150,8 @@ export interface DynamicFilterBarProps {
|
|
|
137
150
|
onGlobalFilterChange?: (value: string) => void;
|
|
138
151
|
/** Placeholder text for the global search box. Default: "Search…". */
|
|
139
152
|
globalSearchPlaceholder?: string;
|
|
153
|
+
/** ID prefix for all interactive elements — passed down to chips and ManageFilters. */
|
|
154
|
+
gridId?: string;
|
|
140
155
|
}
|
|
141
|
-
declare const _default: import("react").MemoExoticComponent<({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, uiDensity, filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element>;
|
|
156
|
+
declare const _default: import("react").MemoExoticComponent<({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, uiDensity, filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, gridId, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element>;
|
|
142
157
|
export default _default;
|