tp-react-elements 2.0.3 → 2.0.4

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 CHANGED
@@ -202,10 +202,14 @@ npm run storybook
202
202
  ```
203
203
 
204
204
  - **Docs → Paginated Grid** — API reference plus **four copy-paste examples** (embedded panel, wrapped headers, typography, invoice filters)
205
- - **Components → PaginatedGrid → Sample Grids** — mock grids (no API): header wrap, compact layout, viewport fill
205
+ - **Components → PaginatedGrid → Sample Grids** — mock grids (no API): header wrap, compact layout, viewport fill, multi-select with Apply button, month picker
206
206
  - **Components → PaginatedGrid → Example Grid** — invoice grid demo using mock data (no API)
207
207
 
208
- **Global Search:** every `GenericPaginatedGrid` includes a built-in search icon in the top-right toolbar (next to Show/Hide Columns, Density, and Fullscreen) — no extra props needed. Click it to expand a free-text search that filters across all visible columns of the current batch. See **Docs → Paginated Grid → Global search**.
208
+ **Global Search:** every `GenericPaginatedGrid` includes a built-in search icon in the top-right toolbar — **collapsed by default** (set `showGlobalSearchByDefault={true}` to start expanded). Click the icon to expand a free-text search that filters across all visible columns of the current batch. See **Docs → Paginated Grid → Global search**.
209
+
210
+ **Excel export:** the Export button downloads an `.xlsx` file with the header row styled in `headerBgColor` (bold white text) and columns auto-sized to fit content. Requires `xlsx-js-style` as a peer dependency.
211
+
212
+ **Element IDs:** every interactive element (toolbar buttons, filter chips, pagination controls) receives a stable `id` attribute. Pass `gridId="invoice"` (or omit to default to `exportFilename`) and all elements follow the pattern `{gridId}_refresh_icon`, `{gridId}_dateRange_chip`, `{gridId}_next_page_icon`, etc. See **Docs → Paginated Grid — Element IDs** in Storybook for the full reference table.
209
213
 
210
214
  **Example — compact embedded grid with smaller fonts:**
211
215
 
@@ -1,3 +1,3 @@
1
- var InputRangeField = {};
1
+ var Month = {};
2
2
 
3
- export { InputRangeField as __exports };
3
+ export { Month as __exports };
@@ -1,3 +1,3 @@
1
- var Month = {};
1
+ var DateInput = {};
2
2
 
3
- export { Month as __exports };
3
+ export { DateInput as __exports };
@@ -1,3 +1,3 @@
1
- var DateInput = {};
1
+ var InputRangeField = {};
2
2
 
3
- export { DateInput as __exports };
3
+ export { InputRangeField as __exports };
@@ -1,3 +1,3 @@
1
- var DateRangePicker = {};
1
+ var DefinedRange = {};
2
2
 
3
- export { DateRangePicker as __exports };
3
+ export { DefinedRange as __exports };
@@ -1,3 +1,3 @@
1
- var DefinedRange = {};
1
+ var Calendar = {};
2
2
 
3
- export { DefinedRange as __exports };
3
+ export { Calendar as __exports };
@@ -1,3 +1,3 @@
1
- var Calendar = {};
1
+ var DateRangePicker = {};
2
2
 
3
- export { Calendar as __exports };
3
+ export { DateRangePicker as __exports };
@@ -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;
@@ -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;
@@ -17,6 +17,8 @@ import FilterListIcon from '@mui/icons-material/FilterList';
17
17
  import CheckIcon from '@mui/icons-material/Check';
18
18
  import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
19
19
  import SearchIcon from '@mui/icons-material/Search';
20
+ import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
21
+ import ChevronRightIcon from '@mui/icons-material/ChevronRight';
20
22
 
21
23
  // Enable strict-format parsing so dayjs can handle the DD/MM/YYYY strings
22
24
  // that DatepickerWrapperV2 passes to onChangeFn
@@ -30,6 +32,7 @@ const TYPE_PILL = {
30
32
  dropdown: { label: 'Select', color: '#6a1b9a', bg: '#f3e5f5' },
31
33
  searchableDropdown: { label: 'Search', color: '#bf360c', bg: '#fbe9e7' },
32
34
  multiSelect: { label: 'Multi', color: '#0277bd', bg: '#e1f5fe' },
35
+ monthPicker: { label: 'Month', color: '#6a1b9a', bg: '#f3e5f5' },
33
36
  };
34
37
  // Column filter type pills (used in COLUMN FILTERS section of Manage Filters)
35
38
  const COLUMN_TYPE_PILL = {
@@ -78,7 +81,7 @@ const fmtDate = (iso) => {
78
81
  const yearSuffix = y !== thisYear ? ` '${y.slice(2)}` : '';
79
82
  return `${Number(d)} ${months[Number(m) - 1]}${yearSuffix}`;
80
83
  };
81
- const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove, chipStyle }) => {
84
+ const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove, chipStyle, baseId }) => {
82
85
  // Inject react-date-range CSS via JS (not CSS import) to prevent it from being
83
86
  // bundled into the library's extracted CSS file and leaking into consumer apps.
84
87
  useRdrStyles();
@@ -120,14 +123,14 @@ const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove, chipStyle }
120
123
  setAnchor(null);
121
124
  }
122
125
  };
123
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipLabel : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: openPicker, startIcon: jsx(CalendarTodayIcon, { sx: { fontSize: 13 } }), endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipLabel }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, overflow: 'hidden' } }, children: [jsx(distExports.DateRange, { editableDateInputs: false, onChange: handleRangeChange, moveRangeOnFirstSelection: false, ranges: selRange, months: 2, direction: "horizontal", showDateDisplay: false, dateDisplayFormat: "dd/MM/yyyy", rangeColors: ['#1976d2'] }), active && (jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-end', px: 2, pb: 1.5 }, children: jsx(Button, { size: "small", color: "inherit", onClick: () => { onApply('', ''); setAnchor(null); }, children: "Clear" }) }))] })] }));
126
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipLabel : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: openPicker, startIcon: jsx(CalendarTodayIcon, { sx: { fontSize: 13 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipLabel }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, overflow: 'hidden' } }, children: [jsx(distExports.DateRange, { editableDateInputs: false, onChange: handleRangeChange, moveRangeOnFirstSelection: false, ranges: selRange, months: 2, direction: "horizontal", showDateDisplay: false, dateDisplayFormat: "dd/MM/yyyy", rangeColors: ['#1976d2'] }), active && (jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-end', px: 2, pb: 1.5 }, children: jsx(Button, { size: "small", color: "inherit", onClick: () => { onApply('', ''); setAnchor(null); }, children: "Clear" }) }))] })] }));
124
127
  };
125
- const TextFilterChip = ({ label, value, onApply, onRemove, placeholder, chipStyle }) => {
128
+ const TextFilterChip = ({ label, value, onApply, onRemove, placeholder, chipStyle, baseId }) => {
126
129
  const [anchor, setAnchor] = useState(null);
127
130
  const [draft, setDraft] = useState('');
128
131
  const active = Boolean(value);
129
132
  const chipText = active ? `${label}: ${value}` : label;
130
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: (e) => { setDraft(value); setAnchor(e.currentTarget); }, endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, minWidth: 240 } }, children: jsxs(Box, { sx: { p: 2 }, children: [jsx(Typography, { variant: "caption", fontWeight: 600, color: "text.secondary", display: "block", mb: 1.5, children: label }), jsx(TextField, { value: draft, onChange: (e) => setDraft(e.target.value), placeholder: placeholder, size: "small", fullWidth: true, autoFocus: true, onKeyDown: (e) => {
133
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: (e) => { setDraft(value); setAnchor(e.currentTarget); }, endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, minWidth: 240 } }, children: jsxs(Box, { sx: { p: 2 }, children: [jsx(Typography, { variant: "caption", fontWeight: 600, color: "text.secondary", display: "block", mb: 1.5, children: label }), jsx(TextField, { value: draft, onChange: (e) => setDraft(e.target.value), placeholder: placeholder, size: "small", fullWidth: true, autoFocus: true, onKeyDown: (e) => {
131
134
  if (e.key === 'Enter') {
132
135
  onApply(draft);
133
136
  setAnchor(null);
@@ -136,7 +139,7 @@ const TextFilterChip = ({ label, value, onApply, onRemove, placeholder, chipStyl
136
139
  setAnchor(null);
137
140
  } }), jsxs(Stack, { direction: "row", spacing: 1, justifyContent: "flex-end", mt: 1.5, children: [active && (jsx(Button, { size: "small", color: "inherit", onClick: () => { onApply(''); setAnchor(null); }, children: "Clear" })), jsx(Button, { size: "small", variant: "contained", disableElevation: true, onClick: () => { onApply(draft); setAnchor(null); }, children: "Apply" })] })] }) })] }));
138
141
  };
139
- const DatePickerChip = ({ label, value, onApply, onRemove, chipStyle }) => {
142
+ const DatePickerChip = ({ label, value, onApply, onRemove, chipStyle, baseId }) => {
140
143
  const [open, setOpen] = useState(false);
141
144
  const [anchorEl, setAnchorEl] = useState(null);
142
145
  const active = Boolean(value);
@@ -160,7 +163,7 @@ const DatePickerChip = ({ label, value, onApply, onRemove, chipStyle }) => {
160
163
  // LocalizationProvider must wrap DatePicker — scoped here so it only
161
164
  // loads when the chip is actually used (DatePickerChip is tree-shaken
162
165
  // if the 'date' filter type is never included in serverFilterDefs).
163
- jsxs(LocalizationProvider, { dateAdapter: AdapterDayjs, children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: handleChipClick, startIcon: jsx(CalendarTodayIcon, { sx: { fontSize: 13 } }), endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(DatePicker, { value: dayjsValue, open: open, onClose: () => setOpen(false), onChange: handleChange, slotProps: {
166
+ jsxs(LocalizationProvider, { dateAdapter: AdapterDayjs, children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: handleChipClick, startIcon: jsx(CalendarTodayIcon, { sx: { fontSize: 13 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(DatePicker, { value: dayjsValue, open: open, onClose: () => setOpen(false), onChange: handleChange, slotProps: {
164
167
  textField: { sx: { display: 'none' }, size: 'small' },
165
168
  popper: {
166
169
  anchorEl,
@@ -168,7 +171,7 @@ const DatePickerChip = ({ label, value, onApply, onRemove, chipStyle }) => {
168
171
  },
169
172
  } })] }));
170
173
  };
171
- const DropdownFilterChip = ({ label, value, options, onApply, onRemove, chipStyle }) => {
174
+ const DropdownFilterChip = ({ label, value, options, onApply, onRemove, chipStyle, baseId }) => {
172
175
  const [anchor, setAnchor] = useState(null);
173
176
  const active = Boolean(value);
174
177
  const selectedLabel = options.find((o) => o.value === value)?.label ?? '';
@@ -199,7 +202,7 @@ const DropdownFilterChip = ({ label, value, options, onApply, onRemove, chipStyl
199
202
  ],
200
203
  };
201
204
  const chipText = active ? `${label}: ${selectedLabel}` : label;
202
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: (e) => setAnchor(e.currentTarget), startIcon: jsx(ArrowDropDownIcon, { sx: { fontSize: '15px !important', mr: -0.5 } }), endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, p: 1.5, minWidth: 240 } }, children: jsx(SingleSelectNonAutoComplete, { props: {
205
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: (e) => setAnchor(e.currentTarget), startIcon: jsx(ArrowDropDownIcon, { sx: { fontSize: '15px !important', mr: -0.5 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, p: 1.5, minWidth: 240 } }, children: jsx(SingleSelectNonAutoComplete, { props: {
203
206
  item,
204
207
  register,
205
208
  control,
@@ -210,7 +213,7 @@ const DropdownFilterChip = ({ label, value, options, onApply, onRemove, chipStyl
210
213
  watch,
211
214
  }, variant: "outlined" }) })] }));
212
215
  };
213
- const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeholder = 'Search…', chipStyle, }) => {
216
+ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeholder = 'Search…', chipStyle, baseId, }) => {
214
217
  const [anchor, setAnchor] = useState(null);
215
218
  const [search, setSearch] = useState('');
216
219
  const active = Boolean(value);
@@ -228,7 +231,7 @@ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeh
228
231
  ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()))
229
232
  : options;
230
233
  const chipText = active ? `${label}: ${selectedLabel}` : label;
231
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: open, startIcon: jsx(SearchIcon, { sx: { fontSize: '14px !important', mr: -0.25 } }), endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: {
234
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: open, startIcon: jsx(SearchIcon, { sx: { fontSize: '14px !important', mr: -0.25 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: {
232
235
  sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, width: 280, display: 'flex', flexDirection: 'column' },
233
236
  }, children: [jsx(Box, { sx: { px: 1.5, pt: 1.5, pb: 0.75 }, children: jsx(TextField, { size: "small", fullWidth: true, autoFocus: true, placeholder: placeholder, value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: (e) => { if (e.key === 'Escape')
234
237
  setAnchor(null); }, InputProps: {
@@ -246,15 +249,24 @@ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeh
246
249
  } }), isSelected && (jsx(CheckIcon, { sx: { fontSize: 15, color: 'primary.main', flexShrink: 0 } }))] }, opt.value));
247
250
  }))] })] })] }));
248
251
  };
249
- const MultiSelectFilterChip = ({ label, selectedValues, options, onApply, onRemove, chipStyle, }) => {
252
+ const MultiSelectFilterChip = ({ label, selectedValues, options, onApply, onRemove, chipStyle, baseId, }) => {
250
253
  const [anchor, setAnchor] = useState(null);
254
+ // Draft is only committed on Apply — prevents an API call per checkbox tick.
255
+ const [draft, setDraft] = useState([]);
251
256
  const active = selectedValues.length > 0;
252
- const toggle = (value) => {
253
- const next = selectedValues.includes(value)
254
- ? selectedValues.filter((v) => v !== value)
255
- : [...selectedValues, value];
256
- onApply(next);
257
+ const openPopover = (e) => {
258
+ setDraft(selectedValues); // always start from the committed state
259
+ setAnchor(e.currentTarget);
260
+ };
261
+ const toggleDraft = (value) => setDraft((prev) => prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]);
262
+ const allSelected = draft.length === options.length && options.length > 0;
263
+ const someSelected = draft.length > 0 && !allSelected;
264
+ const toggleAll = () => setDraft(allSelected ? [] : options.map((o) => o.value));
265
+ const handleApply = () => {
266
+ onApply(draft);
267
+ setAnchor(null);
257
268
  };
269
+ // Chip label reflects committed values, not the open draft
258
270
  const chipText = (() => {
259
271
  if (!active)
260
272
  return label;
@@ -268,18 +280,100 @@ const MultiSelectFilterChip = ({ label, selectedValues, options, onApply, onRemo
268
280
  }
269
281
  return `${label}: ${selectedValues.length} selected`;
270
282
  })();
271
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { variant: "outlined", size: "small", onClick: (e) => setAnchor(e.currentTarget), startIcon: jsx(FilterListIcon, { sx: { fontSize: '14px !important', mr: -0.25 } }), endIcon: jsx(CloseIcon, { sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, width: 260 } }, children: [active && (jsxs(Box, { sx: {
283
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: openPopover, startIcon: jsx(FilterListIcon, { sx: { fontSize: '14px !important', mr: -0.25 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, width: 260 } }, children: [jsxs(Box, { sx: {
272
284
  px: 2, py: 0.75,
273
285
  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
274
286
  borderBottom: '1px solid', borderColor: 'divider',
275
- }, children: [jsxs(Typography, { sx: { fontSize: 11, color: 'primary.main', fontWeight: 600 }, children: [selectedValues.length, " selected"] }), jsx(Button, { size: "small", color: "inherit", sx: { fontSize: 11, py: 0, textTransform: 'none', minWidth: 'auto' }, onClick: () => onApply([]), children: "Clear all" })] })), jsx(List, { dense: true, disablePadding: true, sx: { maxHeight: 300, overflowY: 'auto', py: 0.5 }, children: options.map((opt) => {
276
- const checked = selectedValues.includes(opt.value);
277
- return (jsxs(ListItemButton, { onClick: () => toggle(opt.value), sx: { px: 1, py: 0.25 }, children: [jsx(Checkbox, { checked: checked, size: "small", disableRipple: true, sx: { p: 0.5, mr: 0.5, '& .MuiSvgIcon-root': { fontSize: 16 } } }), jsx(ListItemText, { primary: opt.label, primaryTypographyProps: {
287
+ }, children: [jsx(Typography, { sx: { fontSize: 11, color: draft.length > 0 ? 'primary.main' : 'text.secondary', fontWeight: draft.length > 0 ? 600 : 400 }, children: draft.length > 0 ? `${draft.length} of ${options.length} selected` : 'Select options' }), draft.length > 0 && (jsx(Button, { size: "small", color: "inherit", sx: { fontSize: 11, py: 0, textTransform: 'none', minWidth: 'auto' }, onClick: () => setDraft([]), children: "Clear all" }))] }), jsxs(ListItemButton, { onClick: toggleAll, sx: { px: 1, py: 0.25 }, children: [jsx(Checkbox, { checked: allSelected, indeterminate: someSelected, size: "small", disableRipple: true, sx: { p: 0.5, mr: 0.5, '& .MuiSvgIcon-root': { fontSize: 16 } } }), jsx(ListItemText, { primary: "All", primaryTypographyProps: {
288
+ fontSize: 13,
289
+ fontStyle: 'italic',
290
+ color: allSelected || someSelected ? 'primary.main' : 'text.secondary',
291
+ fontWeight: allSelected ? 600 : 400,
292
+ } })] }), jsx(Divider, {}), jsx(List, { dense: true, disablePadding: true, sx: { maxHeight: 240, overflowY: 'auto', py: 0.5 }, children: options.map((opt) => {
293
+ const checked = draft.includes(opt.value);
294
+ return (jsxs(ListItemButton, { onClick: () => toggleDraft(opt.value), sx: { px: 1, py: 0.25 }, children: [jsx(Checkbox, { checked: checked, size: "small", disableRipple: true, sx: { p: 0.5, mr: 0.5, '& .MuiSvgIcon-root': { fontSize: 16 } } }), jsx(ListItemText, { primary: opt.label, primaryTypographyProps: {
278
295
  fontSize: 13,
279
296
  color: checked ? 'primary.main' : 'text.primary',
280
297
  fontWeight: checked ? 600 : 400,
281
298
  } })] }, opt.value));
282
- }) })] })] }));
299
+ }) }), jsx(Box, { sx: {
300
+ px: 1.5, py: 1,
301
+ display: 'flex', justifyContent: 'flex-end',
302
+ borderTop: '1px solid', borderColor: 'divider',
303
+ }, children: jsx(Button, { size: "small", variant: "contained", disableElevation: true, onClick: handleApply, children: "Apply" }) })] })] }));
304
+ };
305
+ // ─── MonthPickerChip ─────────────────────────────────────────────────────────
306
+ //
307
+ // Multi-month selection chip. Users navigate by year and tick individual months.
308
+ // Draft changes are buffered locally; `onApply` is called once when Apply is
309
+ // clicked (single API call per filter action).
310
+ //
311
+ // Value format: comma-separated "YYYY-MM" strings, e.g. "2025-01,2025-03".
312
+ // ─────────────────────────────────────────────────────────────────────────────
313
+ const MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
314
+ const MonthPickerChip = ({ label, value, onApply, onRemove, chipStyle, baseId }) => {
315
+ const parseYMs = (v) => v ? v.split(',').filter(Boolean) : [];
316
+ const [anchor, setAnchor] = useState(null);
317
+ const [viewYear, setViewYear] = useState(() => new Date().getFullYear());
318
+ const [draft, setDraft] = useState(() => parseYMs(value));
319
+ const committed = parseYMs(value);
320
+ const active = committed.length > 0;
321
+ // Sync view year to earliest selected year when opening
322
+ const openPopover = (e) => {
323
+ const yms = parseYMs(value);
324
+ setDraft(yms);
325
+ if (yms.length > 0) {
326
+ const years = yms.map((ym) => Number(ym.split('-')[0]));
327
+ setViewYear(Math.min(...years));
328
+ }
329
+ setAnchor(e.currentTarget);
330
+ };
331
+ const toggleMonth = (ym) => setDraft((prev) => prev.includes(ym) ? prev.filter((v) => v !== ym) : [...prev, ym]);
332
+ const handleApply = () => {
333
+ // Sort selected months chronologically before storing
334
+ onApply([...draft].sort().join(','));
335
+ setAnchor(null);
336
+ };
337
+ const chipText = (() => {
338
+ if (!active)
339
+ return label;
340
+ if (committed.length === 1) {
341
+ const [y, m] = committed[0].split('-');
342
+ return `${MONTH_LABELS[Number(m) - 1]} ${y}`;
343
+ }
344
+ if (committed.length <= 3) {
345
+ const parts = committed.map((ym) => {
346
+ const [y, m] = ym.split('-');
347
+ return `${MONTH_LABELS[Number(m) - 1]} '${y.slice(2)}`;
348
+ });
349
+ return `${label}: ${parts.join(', ')}`;
350
+ }
351
+ return `${label}: ${committed.length} months`;
352
+ })();
353
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: active ? chipText : '', placement: "top", arrow: true, children: jsx(Button, { id: baseId ? `${baseId}_chip` : undefined, variant: "outlined", size: "small", onClick: openPopover, startIcon: jsx(CalendarTodayIcon, { sx: { fontSize: 13 } }), endIcon: jsx(CloseIcon, { id: baseId ? `${baseId}_remove_icon` : undefined, sx: { fontSize: '12px !important' }, onClick: (e) => { e.stopPropagation(); onRemove(); } }), sx: chipSx(active, chipStyle), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: { sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, width: 280 } }, children: [jsxs(Box, { sx: {
354
+ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
355
+ px: 1.5, py: 0.75,
356
+ borderBottom: '1px solid', borderColor: 'divider',
357
+ }, children: [jsx(IconButton, { id: baseId ? `${baseId}_prev_year_icon` : undefined, size: "small", onClick: () => setViewYear((y) => y - 1), children: jsx(ChevronLeftIcon, { sx: { fontSize: 18 } }) }), jsx(Typography, { fontWeight: 600, sx: { fontSize: 14, userSelect: 'none' }, children: viewYear }), jsx(IconButton, { id: baseId ? `${baseId}_next_year_icon` : undefined, size: "small", onClick: () => setViewYear((y) => y + 1), children: jsx(ChevronRightIcon, { sx: { fontSize: 18 } }) })] }), jsx(Box, { sx: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 0.75, p: 1.5 }, children: MONTH_LABELS.map((mon, idx) => {
358
+ const ym = `${viewYear}-${String(idx + 1).padStart(2, '0')}`;
359
+ const isSelected = draft.includes(ym);
360
+ return (jsx(Button, { id: baseId ? `${baseId}_month_${ym}` : undefined, variant: isSelected ? 'contained' : 'outlined', size: "small", disableElevation: true, onClick: () => toggleMonth(ym), sx: {
361
+ fontSize: 12,
362
+ textTransform: 'none',
363
+ borderRadius: 2,
364
+ py: 0.75,
365
+ borderColor: isSelected ? 'primary.main' : 'divider',
366
+ fontWeight: isSelected ? 700 : 400,
367
+ }, children: mon }, ym));
368
+ }) }), draft.length > 0 && (jsxs(Box, { sx: {
369
+ px: 2, py: 0.75,
370
+ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
371
+ borderTop: '1px solid', borderColor: 'divider',
372
+ }, children: [jsxs(Typography, { sx: { fontSize: 11, color: 'primary.main', fontWeight: 600 }, children: [draft.length, " month", draft.length > 1 ? 's' : '', " selected"] }), jsx(Button, { size: "small", color: "inherit", sx: { fontSize: 11, py: 0, textTransform: 'none', minWidth: 'auto' }, onClick: () => setDraft([]), children: "Clear" })] })), jsx(Box, { sx: {
373
+ px: 1.5, py: 1,
374
+ display: 'flex', justifyContent: 'flex-end',
375
+ borderTop: '1px solid', borderColor: 'divider',
376
+ }, children: jsx(Button, { size: "small", variant: "contained", disableElevation: true, onClick: handleApply, children: "Apply" }) })] })] }));
283
377
  };
284
378
  const GlobalSearchInput = memo(({ value, onChange, chipStyle, placeholder = 'Search…' }) => {
285
379
  const [draft, setDraft] = useState(value);
@@ -316,7 +410,7 @@ const GlobalSearchInput = memo(({ value, onChange, chipStyle, placeholder = 'Sea
316
410
  } }));
317
411
  });
318
412
  GlobalSearchInput.displayName = 'GlobalSearchInput';
319
- const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, onToggle, maxVisible = 4, chipStyle, }) => {
413
+ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, onToggle, maxVisible = 4, chipStyle, gridId, }) => {
320
414
  const [anchor, setAnchor] = useState(null);
321
415
  const atLimit = visibleIds.length >= maxVisible;
322
416
  // Shared pill box renderer
@@ -331,7 +425,7 @@ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, o
331
425
  letterSpacing: 0.4,
332
426
  lineHeight: 1.6,
333
427
  }, children: label }));
334
- return (jsxs(Fragment, { children: [jsx(Tooltip, { title: "Add or remove filter chips", children: jsx(Button, { size: "small", variant: "outlined", startIcon: jsx(TuneIcon, { sx: { fontSize: 14 } }), onClick: (e) => setAnchor(e.currentTarget), sx: {
428
+ return (jsxs(Fragment, { children: [jsx(Tooltip, { title: "Add or remove filter chips", children: jsx(Button, { id: gridId ? `${gridId}_manage_filters_icon` : undefined, size: "small", variant: "outlined", startIcon: jsx(TuneIcon, { sx: { fontSize: 14 } }), onClick: (e) => setAnchor(e.currentTarget), sx: {
335
429
  borderRadius: 5, textTransform: 'none', fontSize: chipStyle.fontSize,
336
430
  borderColor: 'divider', color: 'text.secondary',
337
431
  px: chipStyle.px ?? 1.5, minHeight: chipStyle.minHeight,
@@ -362,7 +456,7 @@ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, o
362
456
  } }), selected && jsx(CheckIcon, { sx: { fontSize: 16, color: 'primary.main', flexShrink: 0 } })] }) }) }, col.id));
363
457
  }) })] }))] })] })] }));
364
458
  };
365
- const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, uiDensity = 'default', filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, }) => {
459
+ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, uiDensity = 'default', filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, gridId, }) => {
366
460
  const chipStyle = {
367
461
  fontSize: filterChipFontSize ?? (uiDensity === 'compact' ? 11 : 12),
368
462
  minHeight: filterChipMinHeight ?? (uiDensity === 'compact' ? 26 : 30),
@@ -391,7 +485,8 @@ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter,
391
485
  else if (def?.type === 'text' ||
392
486
  def?.type === 'dropdown' ||
393
487
  def?.type === 'searchableDropdown' ||
394
- def?.type === 'multiSelect') {
488
+ def?.type === 'multiSelect' ||
489
+ def?.type === 'monthPicker') {
395
490
  onFilterValuesChange({ ...filterValues, [def.filterKey]: '' });
396
491
  }
397
492
  else if (def?.type === 'date') {
@@ -412,46 +507,48 @@ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter,
412
507
  return (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 0.75 }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.4, mr: 0.25 }, children: [jsx(FilterListIcon, { sx: { fontSize: labelFontSize + 3, color: 'text.disabled' } }), jsx(Typography, { sx: { fontSize: labelFontSize }, color: "text.secondary", fontWeight: 500, noWrap: true, children: "Filter by:" })] }), visibleFilterIds.map((id) => {
413
508
  const def = serverFilterDefs.find((d) => d.id === id);
414
509
  if (def?.type === 'dateRange') {
415
- return (jsx(DateRangeChip, { label: def.label, fromDate: filterValues[def.fromKey] ?? '', toDate: filterValues[def.toKey] ?? '', onApply: (from, to) => onFilterValuesChange({ ...filterValues, [def.fromKey]: from, [def.toKey]: to }), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
510
+ return (jsx(DateRangeChip, { label: def.label, fromDate: filterValues[def.fromKey] ?? '', toDate: filterValues[def.toKey] ?? '', onApply: (from, to) => onFilterValuesChange({ ...filterValues, [def.fromKey]: from, [def.toKey]: to }), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
416
511
  }
417
512
  if (def?.type === 'text') {
418
- return (jsx(TextFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), placeholder: def.placeholder, chipStyle: chipStyle }, id));
513
+ return (jsx(TextFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), placeholder: def.placeholder, chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
419
514
  }
420
515
  if (def?.type === 'dropdown') {
421
- return (jsx(DropdownFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', options: def.options, onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
516
+ return (jsx(DropdownFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', options: def.options, onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
422
517
  }
423
518
  if (def?.type === 'searchableDropdown') {
424
- return (jsx(SearchableSelectChip, { label: def.label, value: filterValues[def.filterKey] ?? '', options: def.options, onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), placeholder: def.placeholder ?? 'Search…', chipStyle: chipStyle }, id));
519
+ return (jsx(SearchableSelectChip, { label: def.label, value: filterValues[def.filterKey] ?? '', options: def.options, onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), placeholder: def.placeholder ?? 'Search…', chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
425
520
  }
426
521
  if (def?.type === 'multiSelect') {
427
- // filterValues[key] stores comma-separated values: "Pending,Shipped"
428
522
  const selected = (filterValues[def.filterKey] ?? '')
429
523
  .split(',')
430
524
  .filter(Boolean);
431
525
  return (jsx(MultiSelectFilterChip, { label: def.label, selectedValues: selected, options: def.options, onApply: (vals) => onFilterValuesChange({
432
526
  ...filterValues,
433
527
  [def.filterKey]: vals.join(','),
434
- }), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
528
+ }), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
529
+ }
530
+ if (def?.type === 'monthPicker') {
531
+ return (jsx(MonthPickerChip, { label: def.label, value: filterValues[def.filterKey] ?? '', onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
435
532
  }
436
533
  if (def?.type === 'date') {
437
- return (jsx(DatePickerChip, { label: def.label, value: getColValue(def.columnKey), onApply: (v) => applyColFilter(def.columnKey, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
534
+ return (jsx(DatePickerChip, { label: def.label, value: getColValue(def.columnKey), onApply: (v) => applyColFilter(def.columnKey, v), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
438
535
  }
439
536
  // Column filter chip — render the variant that matches the column's filterType
440
537
  const col = availableColumns.find((c) => c.id === id);
441
538
  if (!col)
442
539
  return null;
443
540
  if (col.filterType === 'date') {
444
- return (jsx(DatePickerChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
541
+ return (jsx(DatePickerChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
445
542
  }
446
543
  if (col.filterType === 'select' || col.filterType === 'searchable-select') {
447
- return (jsx(SearchableSelectChip, { label: col.label, value: getColValue(id), options: col.filterOptions ?? [], onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
544
+ return (jsx(SearchableSelectChip, { label: col.label, value: getColValue(id), options: col.filterOptions ?? [], onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
448
545
  }
449
546
  if (col.filterType === 'multi-select') {
450
- return (jsx(MultiSelectFilterChip, { label: col.label, selectedValues: getColValues(id), options: col.filterOptions ?? [], onApply: (vals) => applyColMultiFilter(id, vals), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
547
+ return (jsx(MultiSelectFilterChip, { label: col.label, selectedValues: getColValues(id), options: col.filterOptions ?? [], onApply: (vals) => applyColMultiFilter(id, vals), onRemove: () => removeFilter(id), chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
451
548
  }
452
549
  // Default: free-text input
453
- return (jsx(TextFilterChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), placeholder: `Filter by ${col.label}`, chipStyle: chipStyle }, id));
454
- }), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters, chipStyle: chipStyle }), onGlobalFilterChange && (jsx(GlobalSearchInput, { value: globalFilter ?? '', onChange: onGlobalFilterChange, chipStyle: chipStyle, placeholder: globalSearchPlaceholder }))] }));
550
+ return (jsx(TextFilterChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), placeholder: `Filter by ${col.label}`, chipStyle: chipStyle, baseId: gridId ? `${gridId}_${id}` : undefined }, id));
551
+ }), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters, chipStyle: chipStyle, gridId: gridId }), onGlobalFilterChange && (jsx(GlobalSearchInput, { value: globalFilter ?? '', onChange: onGlobalFilterChange, chipStyle: chipStyle, placeholder: globalSearchPlaceholder }))] }));
455
552
  };
456
553
  var DynamicFilterBar$1 = memo(DynamicFilterBar);
457
554
 
@@ -55,8 +55,14 @@ export interface GenericPaginatedGridProps<TData extends object> {
55
55
  defaultVisibleFilterIds?: string[];
56
56
  /** Number of rows fetched per API call. Default: 10 000. */
57
57
  batchSize?: number;
58
- /** CSV file name prefix. Default: "export". */
58
+ /** Excel (.xlsx) file name prefix (e.g. "invoice" → "invoice-page1.xlsx"). Default: "export". */
59
59
  exportFilename?: string;
60
+ /**
61
+ * ID prefix applied to every interactive element in this grid instance.
62
+ * Useful for automated testing and deep-linking. Defaults to `exportFilename`.
63
+ * Pattern: `{gridId}_refresh_icon`, `{gridId}_export_icon`, `{gridId}_status_chip`, etc.
64
+ */
65
+ gridId?: string;
60
66
  /**
61
67
  * Height of the entire grid component.
62
68
  * When omitted (default) the grid auto-sizes to fill the remaining viewport
@@ -95,7 +101,7 @@ export interface GenericPaginatedGridProps<TData extends object> {
95
101
  * Show the Global Search input expanded by default (instead of requiring a
96
102
  * click on the search icon to reveal it). The icon remains in the top-right
97
103
  * toolbar actions and can still be used to collapse/expand the input.
98
- * Default: `true`.
104
+ * Default: `false`.
99
105
  */
100
106
  showGlobalSearchByDefault?: boolean;
101
107
  /**
@@ -192,5 +198,5 @@ export interface GenericPaginatedGridProps<TData extends object> {
192
198
  */
193
199
  enableExpanding?: boolean;
194
200
  }
195
- declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, pageSizeOptions, showGlobalSearchByDefault, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
201
+ declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, gridId, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, pageSizeOptions, showGlobalSearchByDefault, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
196
202
  export default GenericPaginatedGrid;
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { useMemo, useState, useRef, useLayoutEffect, useCallback } from 'react';
3
+ import * as XLSX from 'xlsx-js-style';
3
4
  import { useMaterialReactTable, MRT_ToggleGlobalFilterButton, MRT_ShowHideColumnsButton, MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, MaterialReactTable } from 'material-react-table';
4
5
  import { useQuery, keepPreviousData } from '@tanstack/react-query';
5
6
  import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, CircularProgress } from '@mui/material';
@@ -52,6 +53,8 @@ const buildBodyGlobalStyles = (bodyFont) => ({
52
53
  '.tp-gpg-root .MuiTableBody-root .MuiTableCell-root': {
53
54
  fontSize: `${bodyFont} !important`,
54
55
  lineHeight: 1.35,
56
+ borderRight: '1px solid rgba(224,224,224,1)',
57
+ userSelect: 'text',
55
58
  },
56
59
  });
57
60
  const buildHeaderGlobalStyles = (headerMin, headerMax, headerFont, headerBgColor) => {
@@ -191,7 +194,7 @@ const OverlayLoader = ({ message }) => (jsxs(Box, { sx: {
191
194
  bgcolor: 'rgba(255,255,255,0.80)', backdropFilter: 'blur(2px)',
192
195
  zIndex: 10, gap: 1.5,
193
196
  }, children: [jsx(CircularProgress, { size: 50, thickness: 4 }), jsx(Typography, { variant: "body2", color: "text.secondary", fontWeight: 500, children: message })] }));
194
- const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, }) => {
197
+ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, gridId, }) => {
195
198
  const fs = density.footerFontSize;
196
199
  const selectH = density.footerMinHeight - 8;
197
200
  const startRow = totalRecords === 0 ? 0 : pageIndex * pageSize + 1;
@@ -203,7 +206,7 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
203
206
  bgcolor: 'background.paper', flexWrap: 'wrap',
204
207
  minHeight: density.footerMinHeight,
205
208
  flexShrink: 0,
206
- }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.75 }, children: [jsx(Typography, { sx: { fontSize: fs }, color: "text.secondary", noWrap: true, children: "Rows per page:" }), jsx(Select, { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), size: "small", variant: "outlined", sx: {
209
+ }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.75 }, children: [jsx(Typography, { sx: { fontSize: fs }, color: "text.secondary", noWrap: true, children: "Rows per page:" }), jsx(Select, { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), inputProps: { id: `${gridId}_page_size_select` }, size: "small", variant: "outlined", sx: {
207
210
  height: selectH, fontSize: fs - 1, minWidth: 72,
208
211
  '.MuiSelect-select': { py: '2px !important' },
209
212
  '.MuiOutlinedInput-notchedOutline': { borderColor: 'divider' },
@@ -211,18 +214,19 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
211
214
  ? 'Loading…'
212
215
  : totalRecords === 0
213
216
  ? 'No records'
214
- : `${startRow.toLocaleString()}–${endRow.toLocaleString()} of ${totalRecords.toLocaleString()}` }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.25 }, children: [jsx(Tooltip, { title: "First page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onFirst, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(FirstPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Previous page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onPrev, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(ChevronLeftIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Typography, { fontWeight: 600, sx: {
217
+ : `${startRow.toLocaleString()}–${endRow.toLocaleString()} of ${totalRecords.toLocaleString()}` }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.25 }, children: [jsx(Tooltip, { title: "First page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_first_page_icon`, size: "small", onClick: onFirst, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(FirstPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Previous page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_prev_page_icon`, size: "small", onClick: onPrev, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(ChevronLeftIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Typography, { fontWeight: 600, sx: {
215
218
  mx: 0.5,
216
219
  minWidth: density.footerMinHeight - 12,
217
220
  height: density.footerMinHeight - 12,
218
221
  display: 'flex', alignItems: 'center', justifyContent: 'center',
219
222
  borderRadius: 1, border: '1px solid', borderColor: 'primary.main',
220
223
  color: 'primary.main', bgcolor: 'rgba(25,118,210,0.07)', fontSize: fs - 1,
221
- }, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
224
+ }, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_next_page_icon`, size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_last_page_icon`, size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
222
225
  };
223
226
  // ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
224
- function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = true, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
227
+ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = false, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
225
228
  const densityTokens = useMemo(() => ({ ...UI_DENSITY_PRESETS[uiDensity], ...uiDensityOptions }), [uiDensity, uiDensityOptions]);
229
+ const resolvedGridId = gridId ?? exportFilename;
226
230
  const resolvedHeaderMinHeight = toCssSize(headerMinHeight, uiDensity === 'compact' ? '34px' : '40px');
227
231
  const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight, uiDensity === 'compact' ? '56px' : '72px');
228
232
  const resolvedHeaderFontSize = toCssSize(headerFontSize ?? densityTokens.headerFontSize, uiDensity === 'compact' ? '11px' : '12px');
@@ -408,22 +412,42 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
408
412
  setPagination((p) => ({ ...p, pageIndex: 0 }));
409
413
  }, [defaultFilters, defaultVisible]);
410
414
  const handleExport = useCallback(() => {
411
- const headers = columns.map((c) => c.header).join(',');
412
- const csvRows = rows.map((row) => columns
413
- .map((c) => {
414
- const key = c.accessorKey ?? '';
415
- const val = row[key] ?? '';
416
- return `"${String(val).replace(/"/g, '""')}"`;
417
- })
418
- .join(','));
419
- const blob = new Blob([[headers, ...csvRows].join('\n')], { type: 'text/csv' });
420
- const url = URL.createObjectURL(blob);
421
- const a = document.createElement('a');
422
- a.href = url;
423
- a.download = `${exportFilename}-page${pagination.pageIndex + 1}.csv`;
424
- a.click();
425
- URL.revokeObjectURL(url);
426
- }, [columns, rows, exportFilename, pagination.pageIndex]);
415
+ const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey);
416
+ // xlsx-js-style requires 8-char ARGB (AA + RRGGBB). Prepend full-opacity "FF".
417
+ const headerArgb = headerBgColor?.startsWith('#')
418
+ ? 'FF' + headerBgColor.slice(1).toUpperCase().padEnd(6, '0')
419
+ : 'FF1565C0';
420
+ const headerRow = dataCols.map((c) => c.header ?? '');
421
+ const dataRows = rows.map((row) => dataCols.map((c) => String(row[c.accessorKey] ?? '')));
422
+ const ws = XLSX.utils.aoa_to_sheet([headerRow, ...dataRows]);
423
+ // Style header row
424
+ dataCols.forEach((_, colIdx) => {
425
+ const cellRef = XLSX.utils.encode_cell({ r: 0, c: colIdx });
426
+ if (ws[cellRef]) {
427
+ ws[cellRef].s = {
428
+ fill: { patternType: 'solid', fgColor: { rgb: headerArgb } },
429
+ font: { bold: true, color: { rgb: 'FFFFFFFF' }, sz: 10 },
430
+ alignment: { horizontal: 'center', vertical: 'center', wrapText: true },
431
+ border: {
432
+ bottom: { style: 'thin', color: { rgb: 'FFCCCCCC' } },
433
+ right: { style: 'thin', color: { rgb: 'FFCCCCCC' } },
434
+ },
435
+ };
436
+ }
437
+ });
438
+ // Auto-fit column widths based on header + data content length
439
+ ws['!cols'] = dataCols.map((c) => {
440
+ const headerLen = (c.header ?? '').length;
441
+ const maxDataLen = rows.reduce((max, row) => {
442
+ const val = String(row[c.accessorKey] ?? '');
443
+ return Math.max(max, val.length);
444
+ }, 0);
445
+ return { wch: Math.max(headerLen, maxDataLen, 8) + 2 };
446
+ });
447
+ const wb = XLSX.utils.book_new();
448
+ XLSX.utils.book_append_sheet(wb, ws, 'Data');
449
+ XLSX.writeFile(wb, `${exportFilename}-page${pagination.pageIndex + 1}.xlsx`);
450
+ }, [columns, rows, exportFilename, pagination.pageIndex, headerBgColor]);
427
451
  // ── Table instance ─────────────────────────────────────────────────────────
428
452
  const table = useMaterialReactTable({
429
453
  columns: processedColumns,
@@ -636,15 +660,15 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
636
660
  muiToolbarAlertBannerProps: isError
637
661
  ? { color: 'error', children: 'Failed to load data. Please try again.' }
638
662
  : undefined,
639
- renderTopToolbarCustomActions: () => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0, pr: 1, gap: 0.5 }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flexShrink: 0, gap: 0.25 }, children: [jsx(Tooltip, { title: "Clear filters & refresh", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: () => { handleClearAll(); refetch(); }, disabled: isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(RefreshIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) }), jsx(Tooltip, { title: "Export batch as CSV", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: handleExport, disabled: rows.length === 0 || isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) })] }), jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: jsx(DynamicFilterBar, { serverFilterDefs: serverFilterDefs, visibleFilterIds: visibleFilterIds, onToggleFilter: handleToggleFilter, filterValues: filterValues, onFilterValuesChange: handleFilterValuesChange, columnFilters: columnFilters, onColumnFilterChange: setColumnFilters, availableColumns: availableColumns, maxVisibleFilters: maxVisibleFilters, uiDensity: uiDensity, filterChipFontSize: densityTokens.filterChipFontSize, filterChipMinHeight: densityTokens.filterChipMinHeight, filterLabelFontSize: densityTokens.filterLabelFontSize }) })] })),
663
+ renderTopToolbarCustomActions: () => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0, pr: 1, gap: 0.5 }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flexShrink: 0, gap: 0.25 }, children: [jsx(Tooltip, { title: "Clear filters & refresh", children: jsx("span", { children: jsx(IconButton, { id: `${resolvedGridId}_refresh_icon`, size: "small", onClick: () => { handleClearAll(); refetch(); }, disabled: isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(RefreshIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) }), jsx(Tooltip, { title: "Export batch as Excel (.xlsx)", children: jsx("span", { children: jsx(IconButton, { id: `${resolvedGridId}_export_icon`, size: "small", onClick: handleExport, disabled: rows.length === 0 || isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) })] }), jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: jsx(DynamicFilterBar, { serverFilterDefs: serverFilterDefs, visibleFilterIds: visibleFilterIds, onToggleFilter: handleToggleFilter, filterValues: filterValues, onFilterValuesChange: handleFilterValuesChange, columnFilters: columnFilters, onColumnFilterChange: setColumnFilters, availableColumns: availableColumns, maxVisibleFilters: maxVisibleFilters, uiDensity: uiDensity, filterChipFontSize: densityTokens.filterChipFontSize, filterChipMinHeight: densityTokens.filterChipMinHeight, filterLabelFontSize: densityTokens.filterLabelFontSize, gridId: resolvedGridId }) })] })),
640
664
  // Single global search control: MRT's built-in search icon/input in the
641
665
  // top-right toolbar actions. The inline search box next to "Manage
642
666
  // Filters" is intentionally not rendered (see renderTopToolbarCustomActions)
643
667
  // to avoid showing two search controls.
644
- renderToolbarInternalActions: ({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t }), jsx(MRT_ShowHideColumnsButton, { table: t }), jsx(MRT_ToggleDensePaddingButton, { table: t }), jsx(MRT_ToggleFullScreenButton, { table: t })] })),
645
- renderBottomToolbar: ({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: pageSizeOptions, density: densityTokens })),
668
+ renderToolbarInternalActions: ({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t, id: `${resolvedGridId}_global_search_icon` }), jsx(MRT_ShowHideColumnsButton, { table: t, id: `${resolvedGridId}_columns_icon` }), jsx(MRT_ToggleDensePaddingButton, { table: t, id: `${resolvedGridId}_density_icon` }), jsx(MRT_ToggleFullScreenButton, { table: t, id: `${resolvedGridId}_fullscreen_icon` })] })),
669
+ renderBottomToolbar: ({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: pageSizeOptions, density: densityTokens, gridId: resolvedGridId })),
646
670
  });
647
- return (jsxs(Box, { ref: containerRef, className: "tp-gpg-root", sx: {
671
+ return (jsxs(Box, { ref: containerRef, id: resolvedGridId, className: "tp-gpg-root", sx: {
648
672
  position: 'relative',
649
673
  height: resolvedHeight,
650
674
  minHeight: tableMinHeight,
@@ -1,4 +1,4 @@
1
- import { __exports as Calendar } from '../../../../../_virtual/index.esm7.js';
1
+ import { __exports as Calendar } from '../../../../../_virtual/index.esm6.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireDayCell } from '../DayCell/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DateInput } from '../../../../../_virtual/index.esm14.js';
1
+ import { __exports as DateInput } from '../../../../../_virtual/index.esm13.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm5.js';
1
+ import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm7.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireDateRange } from '../DateRange/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DefinedRange } from '../../../../../_virtual/index.esm6.js';
1
+ import { __exports as DefinedRange } from '../../../../../_virtual/index.esm5.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireStyles } from '../../styles.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as InputRangeField } from '../../../../../_virtual/index.esm12.js';
1
+ import { __exports as InputRangeField } from '../../../../../_virtual/index.esm14.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
 
@@ -1,4 +1,4 @@
1
- import { __exports as Month } from '../../../../../_virtual/index.esm13.js';
1
+ import { __exports as Month } from '../../../../../_virtual/index.esm12.js';
2
2
  import React__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireDayCell } from '../DayCell/index.esm.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tp-react-elements",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",