tp-react-elements 2.0.7 → 3.0.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.
Files changed (43) hide show
  1. package/dist/_virtual/index.esm11.js +2 -2
  2. package/dist/_virtual/index.esm12.js +2 -2
  3. package/dist/_virtual/index.esm13.js +2 -2
  4. package/dist/_virtual/index.esm14.js +2 -2
  5. package/dist/_virtual/index.esm4.js +2 -2
  6. package/dist/_virtual/index.esm5.js +2 -2
  7. package/dist/_virtual/index.esm6.js +2 -2
  8. package/dist/components/Button/Button.esm.js +9 -5
  9. package/dist/components/DatePicker/index.d.ts +1 -0
  10. package/dist/components/DatePicker/index.esm.js +2 -1
  11. package/dist/components/DeleteComponent/DeleteField.esm.js +20 -14
  12. package/dist/components/Form/FormActiveSwitch.esm.js +5 -1
  13. package/dist/components/Form/FormConstants.esm.js +1 -0
  14. package/dist/components/Form/FormRender.esm.js +14 -10
  15. package/dist/components/Form/FormRenderWrapper.esm.js +2 -2
  16. package/dist/components/FormComponents/DatePicker/MonthPickerMultiRender.d.ts +6 -0
  17. package/dist/components/FormComponents/DatePicker/MonthPickerMultiRender.esm.js +117 -0
  18. package/dist/components/FormComponents/DatePicker/Monthpickerrender.esm.js +6 -4
  19. package/dist/components/FormComponents/FileUpload/MultiFileWithPreview.esm.js +38 -6
  20. package/dist/components/FormComponents/FormCheckBoxGroup/FormCheckBoxGroup.esm.js +11 -8
  21. package/dist/components/FormComponents/FormRadioGroup/FormRadioGroup.esm.js +14 -12
  22. package/dist/components/FormComponents/Select/MultiSelectTable.esm.js +176 -160
  23. package/dist/components/FormComponents/Select/MultiSelectv1.esm.js +2 -2
  24. package/dist/components/FormComponents/index.esm.js +16 -22
  25. package/dist/components/ModalField/ConfirmationDialog.esm.js +37 -37
  26. package/dist/components/ModalField/ModalField.esm.js +19 -16
  27. package/dist/components/PaginatedGrid/DynamicFilterBar.d.ts +12 -4
  28. package/dist/components/PaginatedGrid/DynamicFilterBar.esm.js +48 -16
  29. package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +8 -1
  30. package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +80 -20
  31. package/dist/components/PaginatedGrid/types.d.ts +25 -0
  32. package/dist/components/SelectField/MultiSelectFieldComponent.esm.js +19 -21
  33. package/dist/node_modules/react-date-range/dist/components/Calendar/index.esm.js +2 -2
  34. package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +3 -3
  35. package/dist/node_modules/react-date-range/dist/components/DateRange/index.esm.js +3 -3
  36. package/dist/node_modules/react-date-range/dist/components/DateRangePicker/index.esm.js +3 -3
  37. package/dist/node_modules/react-date-range/dist/components/DayCell/index.esm.js +3 -3
  38. package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +3 -3
  39. package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +3 -3
  40. package/dist/node_modules/react-date-range/dist/components/Month/index.esm.js +3 -3
  41. package/dist/node_modules/react-list/react-list.esm.js +2 -2
  42. package/dist/utils/Interface/FormInterface.d.ts +1 -1
  43. package/package.json +2 -2
@@ -15,27 +15,122 @@ const extractValuesToArray = (inputString) => {
15
15
  return [];
16
16
  return inputString.split(',').map((value) => value.trim()).filter(Boolean);
17
17
  };
18
- const MultiSelectTable = ({ props, variant, }) => {
19
- const MenuProps = {
20
- PaperProps: {
21
- style: {
22
- maxHeight: ITEM_HEIGHT * 8 + ITEM_PADDING_TOP,
23
- width: '100%',
24
- minWidth: '320px',
25
- maxWidth: '500px',
26
- },
18
+ // ─── Module-level static option objects ────────────────────────────────────────
19
+ // None of these depend on props/state, so they are hoisted out of the component
20
+ // to keep stable references across renders (perf only — values are unchanged).
21
+ const SELECT_MENU_PROPS = {
22
+ PaperProps: {
23
+ style: {
24
+ maxHeight: ITEM_HEIGHT * 8 + ITEM_PADDING_TOP,
25
+ width: '100%',
26
+ minWidth: '320px',
27
+ maxWidth: '500px',
28
+ },
29
+ },
30
+ anchorOrigin: {
31
+ vertical: 'bottom',
32
+ horizontal: 'left',
33
+ },
34
+ transformOrigin: {
35
+ vertical: 'top',
36
+ horizontal: 'left',
37
+ },
38
+ autoFocus: false,
39
+ disableAutoFocusItem: true,
40
+ };
41
+ const MUI_SEARCH_TEXT_FIELD_PROPS = {
42
+ placeholder: 'Search...',
43
+ size: 'small',
44
+ sx: {
45
+ width: 'calc(100% - 16px)',
46
+ margin: '0 8px',
47
+ '& .MuiInputBase-root': {
48
+ fontSize: '11px',
49
+ height: '28px',
50
+ width: '100%',
51
+ },
52
+ '& .MuiInputBase-input': {
53
+ padding: '4px 8px',
27
54
  },
28
- anchorOrigin: {
29
- vertical: 'bottom',
30
- horizontal: 'left',
55
+ },
56
+ };
57
+ const MUI_TOP_TOOLBAR_PROPS = {
58
+ sx: {
59
+ padding: '8px 12px',
60
+ minHeight: '44px',
61
+ width: '100%',
62
+ boxSizing: 'border-box',
63
+ '& .Mui-Toolbar': {
64
+ width: '100%',
65
+ },
66
+ '& .MuiBox-root': {
67
+ width: '100%',
68
+ maxWidth: '100%',
31
69
  },
32
- transformOrigin: {
33
- vertical: 'top',
34
- horizontal: 'left',
70
+ '& > div': {
71
+ width: '100%',
35
72
  },
36
- autoFocus: false,
37
- disableAutoFocusItem: true,
38
- };
73
+ },
74
+ };
75
+ const MRT_THEME = {
76
+ baseBackgroundColor: '#fff',
77
+ };
78
+ const DEFAULT_COLUMN = {
79
+ size: 120,
80
+ minSize: 80,
81
+ maxSize: 200,
82
+ };
83
+ const MUI_PAGINATION_PROPS = {
84
+ rowsPerPageOptions: [],
85
+ showFirstButton: false,
86
+ showLastButton: false,
87
+ size: 'small',
88
+ sx: {
89
+ '& .MuiTablePagination-root': {
90
+ fontSize: '10px',
91
+ minHeight: '28px',
92
+ },
93
+ '& .MuiTablePagination-select': {
94
+ display: 'none',
95
+ },
96
+ '& .MuiTablePagination-selectLabel': {
97
+ display: 'none',
98
+ },
99
+ '& .MuiTablePagination-displayedRows': {
100
+ fontSize: '10px',
101
+ },
102
+ '& .MuiTablePagination-toolbar': {
103
+ minHeight: '28px',
104
+ padding: '0 4px',
105
+ },
106
+ },
107
+ };
108
+ const MUI_TABLE_CONTAINER_PROPS = {
109
+ sx: {
110
+ maxHeight: 400,
111
+ width: '100%',
112
+ overflowX: 'hidden',
113
+ },
114
+ };
115
+ const MUI_TABLE_BODY_CELL_PROPS = {
116
+ sx: {
117
+ fontSize: '10px',
118
+ padding: '4px 6px',
119
+ borderBottom: '1px solid #e0e0e0',
120
+ whiteSpace: 'normal',
121
+ wordWrap: 'break-word',
122
+ overflow: 'visible',
123
+ },
124
+ };
125
+ const INITIAL_STATE = {
126
+ density: 'compact',
127
+ pagination: {
128
+ pageSize: 7,
129
+ pageIndex: 0,
130
+ },
131
+ showGlobalFilter: true,
132
+ };
133
+ const MultiSelectTable = ({ props, variant, }) => {
39
134
  const [globalFilter, setGlobalFilter] = useState('');
40
135
  const tableRef = useRef(null);
41
136
  const fieldValue = useWatch({ control: props.control, name: props.item.name }) ?? [];
@@ -179,6 +274,57 @@ const MultiSelectTable = ({ props, variant, }) => {
179
274
  }));
180
275
  return [selectColumn, ...dataColumns];
181
276
  }, [columns, selectedValues, valueField, handleRowSelect, handleSelectAll, getIsAllSelected, getIsIndeterminate]);
277
+ // Depends on the `headerColor` prop, so it can't be hoisted to module scope
278
+ // like the other static MRT option objects above.
279
+ const muiTableHeadCellProps = useMemo(() => ({
280
+ sx: {
281
+ backgroundColor: headerColor,
282
+ color: '#fff',
283
+ fontWeight: 'bold',
284
+ fontSize: '11px',
285
+ padding: '4px 6px',
286
+ borderBottom: '1px solid #e0e0e0',
287
+ whiteSpace: 'normal',
288
+ wordWrap: 'break-word',
289
+ '& .Mui-TableHeadCell-Content': {
290
+ color: '#fff',
291
+ fontSize: '11px',
292
+ },
293
+ '& .MuiSvgIcon-root': {
294
+ color: '#fff',
295
+ fontSize: '16px',
296
+ },
297
+ },
298
+ }), [headerColor]);
299
+ const muiTableBodyRowProps = useCallback(({ row }) => {
300
+ const rowId = String(row.original[valueField]);
301
+ const isSelected = selectedValues.includes(rowId);
302
+ return {
303
+ onClick: () => handleRowSelect(rowId), // 👈 row click selection
304
+ sx: {
305
+ borderBottom: '1px solid #e0e0e0',
306
+ height: 'auto',
307
+ minHeight: '32px',
308
+ cursor: 'pointer',
309
+ backgroundColor: isSelected ? '#b2dfdb' : 'inherit', // optional highlight
310
+ '&:hover': {
311
+ backgroundColor: '#e0f2f1',
312
+ },
313
+ },
314
+ };
315
+ }, [valueField, selectedValues, handleRowSelect]);
316
+ const renderBottomToolbar = useCallback(({ table }) => {
317
+ const totalRows = table.getFilteredRowModel().rows.length;
318
+ const selectedCount = selectedValues.length;
319
+ return (jsxs(Box, { sx: {
320
+ display: 'flex',
321
+ justifyContent: 'space-between',
322
+ alignItems: 'center',
323
+ padding: '6px 10px',
324
+ borderTop: '1px solid #e0e0e0',
325
+ fontSize: '11px',
326
+ }, children: [jsxs(Box, { children: ["Total: ", totalRows] }), jsxs(Box, { children: ["Selected: ", selectedCount] }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsx(IconButton, { size: "small", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: jsx(ChevronLeft, { fontSize: "small" }) }), jsxs("span", { children: ["Page ", table.getState().pagination.pageIndex + 1] }), jsx(IconButton, { size: "small", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), children: jsx(ChevronRight, { fontSize: "small" }) })] })] }));
327
+ }, [selectedValues]);
182
328
  // MRT table instance
183
329
  const table = useMaterialReactTable({
184
330
  columns: mrtColumns,
@@ -198,154 +344,24 @@ const MultiSelectTable = ({ props, variant, }) => {
198
344
  enableFullScreenToggle: false,
199
345
  enableHiding: false,
200
346
  positionGlobalFilter: 'left',
201
- muiSearchTextFieldProps: {
202
- placeholder: 'Search...',
203
- size: 'small',
204
- sx: {
205
- width: 'calc(100% - 16px)',
206
- margin: '0 8px',
207
- '& .MuiInputBase-root': {
208
- fontSize: '11px',
209
- height: '28px',
210
- width: '100%',
211
- },
212
- '& .MuiInputBase-input': {
213
- padding: '4px 8px',
214
- },
215
- },
216
- },
347
+ muiSearchTextFieldProps: MUI_SEARCH_TEXT_FIELD_PROPS,
217
348
  globalFilterFn: 'contains',
218
- muiTopToolbarProps: {
219
- sx: {
220
- padding: '8px 12px',
221
- minHeight: '44px',
222
- width: '100%',
223
- boxSizing: 'border-box',
224
- '& .Mui-Toolbar': {
225
- width: '100%',
226
- },
227
- '& .MuiBox-root': {
228
- width: '100%',
229
- maxWidth: '100%',
230
- },
231
- '& > div': {
232
- width: '100%',
233
- },
234
- },
235
- },
236
- mrtTheme: {
237
- baseBackgroundColor: '#fff',
238
- },
239
- defaultColumn: {
240
- size: 120,
241
- minSize: 80,
242
- maxSize: 200,
243
- },
349
+ muiTopToolbarProps: MUI_TOP_TOOLBAR_PROPS,
350
+ mrtTheme: MRT_THEME,
351
+ defaultColumn: DEFAULT_COLUMN,
244
352
  paginationDisplayMode: 'pages',
245
- muiPaginationProps: {
246
- rowsPerPageOptions: [],
247
- showFirstButton: false,
248
- showLastButton: false,
249
- size: 'small',
250
- sx: {
251
- '& .MuiTablePagination-root': {
252
- fontSize: '10px',
253
- minHeight: '28px',
254
- },
255
- '& .MuiTablePagination-select': {
256
- display: 'none',
257
- },
258
- '& .MuiTablePagination-selectLabel': {
259
- display: 'none',
260
- },
261
- '& .MuiTablePagination-displayedRows': {
262
- fontSize: '10px',
263
- },
264
- '& .MuiTablePagination-toolbar': {
265
- minHeight: '28px',
266
- padding: '0 4px',
267
- },
268
- },
269
- },
270
- muiTableContainerProps: {
271
- sx: {
272
- maxHeight: 400,
273
- width: '100%',
274
- overflowX: 'hidden',
275
- },
276
- },
353
+ muiPaginationProps: MUI_PAGINATION_PROPS,
354
+ muiTableContainerProps: MUI_TABLE_CONTAINER_PROPS,
277
355
  layoutMode: 'semantic',
278
- muiTableHeadCellProps: {
279
- sx: {
280
- backgroundColor: headerColor,
281
- color: '#fff',
282
- fontWeight: 'bold',
283
- fontSize: '11px',
284
- padding: '4px 6px',
285
- borderBottom: '1px solid #e0e0e0',
286
- whiteSpace: 'normal',
287
- wordWrap: 'break-word',
288
- '& .Mui-TableHeadCell-Content': {
289
- color: '#fff',
290
- fontSize: '11px',
291
- },
292
- '& .MuiSvgIcon-root': {
293
- color: '#fff',
294
- fontSize: '16px',
295
- },
296
- },
297
- },
298
- muiTableBodyCellProps: {
299
- sx: {
300
- fontSize: '10px',
301
- padding: '4px 6px',
302
- borderBottom: '1px solid #e0e0e0',
303
- whiteSpace: 'normal',
304
- wordWrap: 'break-word',
305
- overflow: 'visible',
306
- },
307
- },
308
- muiTableBodyRowProps: ({ row }) => {
309
- const rowId = String(row.original[valueField]);
310
- const isSelected = selectedValues.includes(rowId);
311
- return {
312
- onClick: () => handleRowSelect(rowId), // 👈 row click selection
313
- sx: {
314
- borderBottom: '1px solid #e0e0e0',
315
- height: 'auto',
316
- minHeight: '32px',
317
- cursor: 'pointer',
318
- backgroundColor: isSelected ? '#b2dfdb' : 'inherit', // optional highlight
319
- '&:hover': {
320
- backgroundColor: '#e0f2f1',
321
- },
322
- },
323
- };
324
- },
325
- initialState: {
326
- density: 'compact',
327
- pagination: {
328
- pageSize: 7,
329
- pageIndex: 0,
330
- },
331
- showGlobalFilter: true,
332
- },
356
+ muiTableHeadCellProps,
357
+ muiTableBodyCellProps: MUI_TABLE_BODY_CELL_PROPS,
358
+ muiTableBodyRowProps,
359
+ initialState: INITIAL_STATE,
333
360
  state: {
334
361
  globalFilter,
335
362
  },
336
363
  onGlobalFilterChange: setGlobalFilter,
337
- renderBottomToolbar: ({ table }) => {
338
- const totalRows = table.getFilteredRowModel().rows.length;
339
- const selectedCount = selectedValues.length;
340
- return (jsxs(Box, { sx: {
341
- display: 'flex',
342
- justifyContent: 'space-between',
343
- alignItems: 'center',
344
- padding: '6px 10px',
345
- borderTop: '1px solid #e0e0e0',
346
- fontSize: '11px',
347
- }, children: [jsxs(Box, { children: ["Total: ", totalRows] }), jsxs(Box, { children: ["Selected: ", selectedCount] }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsx(IconButton, { size: "small", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: jsx(ChevronLeft, { fontSize: "small" }) }), jsxs("span", { children: ["Page ", table.getState().pagination.pageIndex + 1] }), jsx(IconButton, { size: "small", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), children: jsx(ChevronRight, { fontSize: "small" }) })] })] }));
348
- },
364
+ renderBottomToolbar,
349
365
  });
350
366
  return (jsx(Box, { children: jsxs(FormControl, { fullWidth: true, sx: {
351
367
  '& .MuiFormLabel-root': {
@@ -369,7 +385,7 @@ const MultiSelectTable = ({ props, variant, }) => {
369
385
  props?.item?.onCloseMenu && props?.item?.onCloseMenu();
370
386
  }, input: jsx(OutlinedInput, { label: variant !== 'standard' ? props.item.label : '' }), renderValue: () => (jsx(Tooltip, { title: selectedDisplayText, children: jsx("span", { children: selectedRows.length > (props.item.multiSelectLabelLength || 2)
371
387
  ? `${selectedRows.length} Selected`
372
- : selectedDisplayText || placeholder }) })), MenuProps: MenuProps, autoFocus: false, children: jsx(Box, { sx: {
388
+ : selectedDisplayText || placeholder }) })), MenuProps: SELECT_MENU_PROPS, autoFocus: false, children: jsx(Box, { sx: {
373
389
  maxHeight: 450, width: '100%', overflow: 'hidden', overflowY: 'auto', '.MuiTextField-root': {
374
390
  width: '280% !important'
375
391
  }
@@ -6,7 +6,7 @@ import ListItemText from '@mui/material/ListItemText';
6
6
  import MenuItem from '@mui/material/MenuItem';
7
7
  import OutlinedInput from '@mui/material/OutlinedInput';
8
8
  import Select from '@mui/material/Select';
9
- import React__default, { useState, useRef, useMemo } from 'react';
9
+ import require$$0__default, { useState, useRef, useMemo } from 'react';
10
10
  import { useWatch } from 'react-hook-form';
11
11
  import FormBottomField from '../FormBottomField/FormBottomField.esm.js';
12
12
  import 'dayjs';
@@ -40,7 +40,7 @@ function MultiSelectV1({ props, variant, }) {
40
40
  const selectedValues = fieldValue.split(',').filter(Boolean);
41
41
  return filterOptions.every((option) => selectedValues.includes(String(option.value)));
42
42
  }, [fieldValue, filterOptions]);
43
- React__default.useEffect(() => {
43
+ require$$0__default.useEffect(() => {
44
44
  if (searchText !== '') {
45
45
  setFilterOptions(sortedOptions.filter((item) => item.label.toLowerCase().includes(searchText.toLowerCase())));
46
46
  }
@@ -1,9 +1,3 @@
1
- export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
2
- export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
3
- export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
4
- export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
5
- export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
6
- export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
7
1
  export { default as SingleSelect } from './Select/SingleSelect.esm.js';
8
2
  export { default as SingleSelectNonAutoComplete } from './Select/SingleSelectNonAutoComplete.esm.js';
9
3
  export { default as SingleSelectSearchApi } from './Select/SingleSelectSearchApi.esm.js';
@@ -11,29 +5,29 @@ export { default as MultiSelectV1 } from './Select/MultiSelectv1.esm.js';
11
5
  export { default as MultiSelectTable } from './Select/MultiSelectTable.esm.js';
12
6
  export { default as SearchableSelect } from './Select/SearchableSelect.esm.js';
13
7
  export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
14
- export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
15
8
  export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
16
9
  export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
17
- export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
18
- export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
19
- export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
20
- export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
21
10
  import 'react/jsx-runtime';
22
- import '@mui/material';
23
11
  import 'react';
12
+ import '@mui/material';
13
+ import '@mui/icons-material/CalendarToday';
14
+ import '@mui/icons-material/ChevronLeft';
15
+ import '@mui/icons-material/ChevronRight';
24
16
  import 'react-hook-form';
25
- import 'dayjs';
26
17
  export { default as FormBottomField } from './FormBottomField/FormBottomField.esm.js';
27
- import '@mui/icons-material/Visibility';
28
- import '@mui/icons-material/Close';
29
- import '@mui/icons-material/NavigateBefore';
30
- import '@mui/icons-material/NavigateNext';
31
- import '@mui/icons-material/Delete';
32
- import '@mui/icons-material/UploadFile';
33
- import '@mui/icons-material/PictureAsPdf';
34
- import '@mui/icons-material/TableChart';
35
- import '@mui/icons-material/Description';
18
+ import 'dayjs';
19
+ export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
36
20
  export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
37
21
  export { default as HelperText } from './HelperText/HelperText.esm.js';
22
+ export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
23
+ export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
24
+ export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
25
+ export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
26
+ export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
27
+ export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
28
+ export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
29
+ export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
30
+ export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
38
31
  export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
39
32
  export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
33
+ export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
@@ -1,46 +1,46 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { Dialog, Slide, DialogTitle, DialogContent, Typography, Grid, DialogActions, Button } from '@mui/material';
3
+ import { useMemo } from 'react';
3
4
  import CloseIcon from '@mui/icons-material/Close';
4
5
  import { SubmitButton } from '../Global.styles.esm.js';
5
6
 
7
+ // ─── Module-level static style objects ─────────────────────────────────────
8
+ // None depend on props, so they're hoisted to keep stable references across
9
+ // renders instead of being rebuilt every time (perf only — values unchanged).
10
+ const CLOSE_ICON_SX = { cursor: 'pointer' };
11
+ const DIALOG_TITLE_SX = {
12
+ padding: '8px 16px',
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ justifyContent: 'space-between',
16
+ fontSize: '14px',
17
+ cursor: 'move',
18
+ borderBottom: '1px solid rgb(229 231 235 / 1)',
19
+ };
20
+ const DIALOG_CONTENT_STYLE = { paddingTop: '20px', paddingBottom: 0 };
21
+ const DIALOG_CONTENT_SX = { '& .pt-0': { paddingTop: 0 } };
22
+ const DIALOG_ACTIONS_SX = { borderTop: '1px solid #e0e0e0', marginTop: 3 };
23
+ const ACTIONS_ROW_STYLE = { display: 'flex', justifyContent: 'flex-end', gap: '8px' };
24
+ const CANCEL_BUTTON_SX = {
25
+ textTransform: 'none',
26
+ color: '#000',
27
+ background: '#ececee',
28
+ ':hover': { background: '#0009', color: '#fff' },
29
+ };
6
30
  const ConfirmationDialog = ({ openConfirmDialog, handleCancel, onClickSubmit, text, Submit = 'Submit', Cancel = 'Cancel', title = 'Confirmation Dailog', sx = {}, }) => {
7
- return (jsxs(Dialog, { open: openConfirmDialog, TransitionComponent: Slide, fullWidth: true, sx: {
8
- position: 'fixed',
9
- top: '10%',
10
- left: 0,
11
- right: 0,
12
- bottom: 'auto',
13
- '& .css-tlc64q-MuiPaper-root-MuiDialog-paper,.css-mbdu2s': {
14
- maxWidth: '500px',
15
- },
16
- zIndex: 40,
17
- ...sx,
18
- }, "aria-labelledby": "draggable-dialog-title", children: [jsxs(DialogTitle, { sx: {
19
- // background: theme.palette.primary.main,
20
- // color: "#fff",
21
- padding: '8px 16px',
22
- display: 'flex',
23
- alignItems: 'center',
24
- justifyContent: 'space-between',
25
- fontSize: '14px',
26
- cursor: 'move',
27
- borderBottom: '1px solid rgb(229 231 235 / 1)',
28
- }, children: [jsx("span", { children: title }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick: handleCancel })] }), jsxs(DialogContent, { style: { paddingTop: '20px', paddingBottom: 0 }, sx: {
29
- '& .pt-0': {
30
- paddingTop: 0,
31
- },
32
- }, children: [jsx(Typography, { children: text }), jsx(Grid, { container: true, gap: 3 })] }), jsx(DialogActions, { sx: { borderTop: '1px solid #e0e0e0', marginTop: 3 }, children: jsxs("div", { style: {
33
- display: 'flex',
34
- justifyContent: 'flex-end',
35
- gap: '8px',
36
- }, children: [jsx(SubmitButton, { variant: "contained", size: "small", type: "submit", onClick: onClickSubmit, children: Submit }), jsx(Button, { variant: "text",
37
- // color="error"
38
- size: "small", sx: {
39
- textTransform: 'none',
40
- color: '#000',
41
- background: '#ececee',
42
- ':hover': { background: '#0009', color: '#fff' },
43
- }, onClick: handleCancel, children: Cancel })] }) })] }));
31
+ const dialogSx = useMemo(() => ({
32
+ position: 'fixed',
33
+ top: '10%',
34
+ left: 0,
35
+ right: 0,
36
+ bottom: 'auto',
37
+ '& .css-tlc64q-MuiPaper-root-MuiDialog-paper,.css-mbdu2s': {
38
+ maxWidth: '500px',
39
+ },
40
+ zIndex: 40,
41
+ ...sx,
42
+ }), [sx]);
43
+ return (jsxs(Dialog, { open: openConfirmDialog, TransitionComponent: Slide, fullWidth: true, sx: dialogSx, "aria-labelledby": "draggable-dialog-title", children: [jsxs(DialogTitle, { sx: DIALOG_TITLE_SX, children: [jsx("span", { children: title }), jsx(CloseIcon, { sx: CLOSE_ICON_SX, onClick: handleCancel })] }), jsxs(DialogContent, { style: DIALOG_CONTENT_STYLE, sx: DIALOG_CONTENT_SX, children: [jsx(Typography, { children: text }), jsx(Grid, { container: true, gap: 3 })] }), jsx(DialogActions, { sx: DIALOG_ACTIONS_SX, children: jsxs("div", { style: ACTIONS_ROW_STYLE, children: [jsx(SubmitButton, { variant: "contained", size: "small", type: "submit", onClick: onClickSubmit, children: Submit }), jsx(Button, { variant: "text", size: "small", sx: CANCEL_BUTTON_SX, onClick: handleCancel, children: Cancel })] }) })] }));
44
44
  };
45
45
 
46
46
  export { ConfirmationDialog as default };
@@ -1,25 +1,28 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import CloseIcon from '@mui/icons-material/Close';
3
3
  import { Slide, DialogContent, DialogActions } from '@mui/material';
4
+ import { useMemo } from 'react';
4
5
  import { DialogContainer, DialogTitleWrapper, SaveAsDraftButton, SubmitButton, CancelButton } from '../Global.styles.esm.js';
5
6
 
6
- const ModalField = ({ name, openModal, handleCancel, content, width = '900px', Transition = '', handleSubmit, styles = {}, saveButton: isSaveButton = false, submitButton = true, handleSaveButton = () => null, SubmitButtonName = 'Submit', }) => {
7
+ // ─── Module-level static style objects ─────────────────────────────────────
8
+ // None depend on props, so they're hoisted to keep stable references across
9
+ // renders instead of being rebuilt every time (perf only — values unchanged).
10
+ const noop = () => null;
11
+ const CLOSE_ICON_SX = { cursor: 'pointer' };
12
+ const DIALOG_CONTENT_STYLE = { paddingTop: '20px', paddingBottom: 0 };
13
+ const DIALOG_CONTENT_SX = { '& .pt-0': { paddingTop: 0 } };
14
+ const DIALOG_ACTIONS_SX = { borderTop: '1px solid #e0e0e0', marginTop: 3 };
15
+ const ACTIONS_ROW_STYLE = { display: 'flex', justifyContent: 'flex-end', gap: '8px' };
16
+ const ModalField = ({ name, openModal, handleCancel, content, width = '900px', Transition = '', handleSubmit, styles = {}, saveButton: isSaveButton = false, submitButton = true, handleSaveButton = noop, SubmitButtonName = 'Submit', }) => {
7
17
  const transitionComponent = Transition === 'Slide' ? Slide : undefined;
8
- return (jsxs(DialogContainer, { open: openModal, TransitionComponent: transitionComponent, fullWidth: true, "aria-labelledby": "draggable-dialog-title", sx: {
9
- zIndex: 20,
10
- '& .css-tlc64q-MuiPaper-root-MuiDialog-paper,.css-mbdu2s': {
11
- maxWidth: width,
12
- },
13
- ...styles,
14
- }, children: [jsxs(DialogTitleWrapper, { children: [jsx("span", { children: name }), jsx(CloseIcon, { sx: { cursor: 'pointer' }, onClick: handleCancel })] }), jsx(DialogContent, { style: { paddingTop: '20px', paddingBottom: 0 }, sx: {
15
- '& .pt-0': {
16
- paddingTop: 0,
17
- },
18
- }, children: content }), jsx(DialogActions, { sx: { borderTop: '1px solid #e0e0e0', marginTop: 3 }, children: jsxs("div", { style: {
19
- display: 'flex',
20
- justifyContent: 'flex-end',
21
- gap: '8px',
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" })] }) })] }));
18
+ const dialogSx = useMemo(() => ({
19
+ zIndex: 20,
20
+ '& .css-tlc64q-MuiPaper-root-MuiDialog-paper,.css-mbdu2s': {
21
+ maxWidth: width,
22
+ },
23
+ ...styles,
24
+ }), [width, styles]);
25
+ return (jsxs(DialogContainer, { open: openModal, TransitionComponent: transitionComponent, fullWidth: true, "aria-labelledby": "draggable-dialog-title", sx: dialogSx, children: [jsxs(DialogTitleWrapper, { children: [jsx("span", { children: name }), jsx(CloseIcon, { sx: CLOSE_ICON_SX, onClick: handleCancel })] }), jsx(DialogContent, { style: DIALOG_CONTENT_STYLE, sx: DIALOG_CONTENT_SX, children: content }), jsx(DialogActions, { sx: DIALOG_ACTIONS_SX, children: jsxs("div", { style: ACTIONS_ROW_STYLE, 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" })] }) })] }));
23
26
  };
24
27
 
25
28
  export { ModalField as default };
@@ -98,10 +98,11 @@ export type ServerFilterDef = {
98
98
  defaultVisible?: boolean;
99
99
  } | {
100
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.
101
+ * Month-picker chip — by default lets users select **one or more months**
102
+ * across years. Selected months are stored as a comma-separated string of
103
+ * `"YYYY-MM"` values in `filterValues[filterKey]` (e.g. `"2025-01,2025-03"`,
104
+ * or just `"2025-01"` when `single: true`). Split on `","` in your
105
+ * `fetchPage` handler to build the server query.
105
106
  */
106
107
  type: 'monthPicker';
107
108
  id: string;
@@ -109,6 +110,13 @@ export type ServerFilterDef = {
109
110
  filterKey: string;
110
111
  /** Show this chip in the filter bar on first render. Default: `false`. */
111
112
  defaultVisible?: boolean;
113
+ /**
114
+ * Restrict selection to a single month instead of the default
115
+ * multi-select behaviour. Clicking a month immediately applies and
116
+ * closes the popover (no Apply button), matching other single-value
117
+ * chips like the date picker. Default: `false` (multi-select).
118
+ */
119
+ single?: boolean;
112
120
  };
113
121
  interface AvailableColumn {
114
122
  id: string;