tp-react-elements 1.3.10 → 1.3.11

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
@@ -165,9 +165,33 @@ The library provides a comprehensive set of form components that integrate seaml
165
165
  - **RadioGroup** - Radio button selection groups
166
166
  - **Switch** - Toggle switches for boolean values
167
167
  - **Form** - Container component with built-in validation
168
+ - **GenericPaginatedGrid** - Server-paginated data grid with dynamic filter chips (see Storybook **Docs → Paginated Grid**)
168
169
 
169
170
  Refer to our Storybook documentation for detailed API documentation and examples.
170
171
 
172
+ ### Paginated grid (Storybook)
173
+
174
+ ```bash
175
+ npm run storybook
176
+ ```
177
+
178
+ - **Docs → Paginated Grid** — full API: grid height, header wrap (`headerMinHeight` / `headerMaxHeight`), `headerBgColor`, filters, troubleshooting
179
+ - **Components → PaginatedGrid → Sample Grids** — mock grids (no API): header wrap test, compact layout, viewport fill
180
+ - **Components → PaginatedGrid → Example Grid** — live invoice API demo
181
+
182
+ Example header styling:
183
+
184
+ ```tsx
185
+ <GenericPaginatedGrid
186
+ headerBgColor="#e8eaf6"
187
+ headerMinHeight="48px"
188
+ headerMaxHeight="96px"
189
+ tableHeight="calc(100vh - 200px)"
190
+ autoFillViewport={false}
191
+ {...gridProps}
192
+ />
193
+ ```
194
+
171
195
  ## 🏗️ Best Practices for Code Structure and Organization
172
196
 
173
197
  ### Component Organization
@@ -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 InputRangeField = {};
2
2
 
3
- export { Month as __exports };
3
+ export { InputRangeField 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 DateRange = {};
1
+ var DateRangePicker = {};
2
2
 
3
- export { DateRange as __exports };
3
+ export { DateRangePicker as __exports };
@@ -1,3 +1,3 @@
1
- var DateRangePicker = {};
1
+ var DateRange = {};
2
2
 
3
- export { DateRangePicker as __exports };
3
+ export { DateRange as __exports };
@@ -1,3 +1,3 @@
1
- var Calendar = {};
1
+ var DefinedRange = {};
2
2
 
3
- export { Calendar as __exports };
3
+ export { DefinedRange as __exports };
@@ -82,6 +82,10 @@ export interface DynamicFilterBarProps {
82
82
  availableColumns: AvailableColumn[];
83
83
  /** Maximum number of chips that may be visible at once. Default: 4. */
84
84
  maxVisibleFilters?: number;
85
+ uiDensity?: 'default' | 'compact';
86
+ filterChipFontSize?: number;
87
+ filterChipMinHeight?: number;
88
+ filterLabelFontSize?: number;
85
89
  }
86
- declare const DynamicFilterBar: ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element;
90
+ declare const DynamicFilterBar: ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, uiDensity, filterChipFontSize, filterChipMinHeight, filterLabelFontSize, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element;
87
91
  export default DynamicFilterBar;
@@ -38,19 +38,17 @@ const COLUMN_TYPE_PILL = {
38
38
  'searchable-select': { label: 'Search', color: '#bf360c', bg: '#fbe9e7' },
39
39
  number: { label: 'Number', color: '#e65100', bg: '#fff3e0' },
40
40
  };
41
- // ─── Chip shared style ────────────────────────────────────────────────────────
42
- const chipSx = (active) => ({
41
+ const chipSx = (active, opts) => ({
43
42
  borderRadius: 5,
44
43
  textTransform: 'none',
45
- fontSize: 12,
44
+ fontSize: opts.fontSize,
46
45
  fontWeight: active ? 600 : 400,
47
46
  borderColor: active ? 'primary.main' : 'divider',
48
47
  color: active ? 'primary.main' : 'text.secondary',
49
48
  bgcolor: active ? 'rgba(25,118,210,0.08)' : 'transparent',
50
49
  whiteSpace: 'nowrap',
51
- px: 1.5,
52
- minHeight: 30,
53
- // Cap chip width so long option labels don't break the filter bar layout
50
+ px: opts.px ?? (opts.fontSize <= 11 ? 1 : 1.5),
51
+ minHeight: opts.minHeight,
54
52
  maxWidth: 260,
55
53
  overflow: 'hidden',
56
54
  '&:hover': { borderColor: 'primary.main', bgcolor: 'rgba(25,118,210,0.08)' },
@@ -78,7 +76,7 @@ const fmtDate = (iso) => {
78
76
  const yearSuffix = y !== thisYear ? ` '${y.slice(2)}` : '';
79
77
  return `${Number(d)} ${months[Number(m) - 1]}${yearSuffix}`;
80
78
  };
81
- const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove }) => {
79
+ const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove, chipStyle }) => {
82
80
  // Inject react-date-range CSS via JS (not CSS import) to prevent it from being
83
81
  // bundled into the library's extracted CSS file and leaking into consumer apps.
84
82
  useRdrStyles();
@@ -120,14 +118,14 @@ const DateRangeChip = ({ label, fromDate, toDate, onApply, onRemove }) => {
120
118
  setAnchor(null);
121
119
  }
122
120
  };
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), 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" }) }))] })] }));
121
+ 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" }) }))] })] }));
124
122
  };
125
- const TextFilterChip = ({ label, value, onApply, onRemove, placeholder }) => {
123
+ const TextFilterChip = ({ label, value, onApply, onRemove, placeholder, chipStyle }) => {
126
124
  const [anchor, setAnchor] = useState(null);
127
125
  const [draft, setDraft] = useState('');
128
126
  const active = Boolean(value);
129
127
  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), 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) => {
128
+ 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) => {
131
129
  if (e.key === 'Enter') {
132
130
  onApply(draft);
133
131
  setAnchor(null);
@@ -136,7 +134,7 @@ const TextFilterChip = ({ label, value, onApply, onRemove, placeholder }) => {
136
134
  setAnchor(null);
137
135
  } }), 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
136
  };
139
- const DatePickerChip = ({ label, value, onApply, onRemove }) => {
137
+ const DatePickerChip = ({ label, value, onApply, onRemove, chipStyle }) => {
140
138
  const [open, setOpen] = useState(false);
141
139
  const [anchorEl, setAnchorEl] = useState(null);
142
140
  const active = Boolean(value);
@@ -160,7 +158,7 @@ const DatePickerChip = ({ label, value, onApply, onRemove }) => {
160
158
  // LocalizationProvider must wrap DatePicker — scoped here so it only
161
159
  // loads when the chip is actually used (DatePickerChip is tree-shaken
162
160
  // 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), children: jsx(ChipLabel, { text: chipText }) }) }), jsx(DatePicker, { value: dayjsValue, open: open, onClose: () => setOpen(false), onChange: handleChange, slotProps: {
161
+ 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: {
164
162
  textField: { sx: { display: 'none' }, size: 'small' },
165
163
  popper: {
166
164
  anchorEl,
@@ -168,7 +166,7 @@ const DatePickerChip = ({ label, value, onApply, onRemove }) => {
168
166
  },
169
167
  } })] }));
170
168
  };
171
- const DropdownFilterChip = ({ label, value, options, onApply, onRemove }) => {
169
+ const DropdownFilterChip = ({ label, value, options, onApply, onRemove, chipStyle }) => {
172
170
  const [anchor, setAnchor] = useState(null);
173
171
  const active = Boolean(value);
174
172
  const selectedLabel = options.find((o) => o.value === value)?.label ?? '';
@@ -199,7 +197,7 @@ const DropdownFilterChip = ({ label, value, options, onApply, onRemove }) => {
199
197
  ],
200
198
  };
201
199
  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), 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: {
200
+ 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: {
203
201
  item,
204
202
  register,
205
203
  control,
@@ -210,7 +208,7 @@ const DropdownFilterChip = ({ label, value, options, onApply, onRemove }) => {
210
208
  watch,
211
209
  }, variant: "outlined" }) })] }));
212
210
  };
213
- const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeholder = 'Search…', }) => {
211
+ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeholder = 'Search…', chipStyle, }) => {
214
212
  const [anchor, setAnchor] = useState(null);
215
213
  const [search, setSearch] = useState('');
216
214
  const active = Boolean(value);
@@ -228,7 +226,7 @@ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeh
228
226
  ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase()))
229
227
  : options;
230
228
  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), children: jsx(ChipLabel, { text: chipText }) }) }), jsxs(Popover, { open: Boolean(anchor), anchorEl: anchor, onClose: () => setAnchor(null), anchorOrigin: { vertical: 'bottom', horizontal: 'left' }, PaperProps: {
229
+ 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: {
232
230
  sx: { mt: 0.75, borderRadius: 2, boxShadow: 6, width: 280, display: 'flex', flexDirection: 'column' },
233
231
  }, 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
232
  setAnchor(null); }, InputProps: {
@@ -246,7 +244,7 @@ const SearchableSelectChip = ({ label, value, options, onApply, onRemove, placeh
246
244
  } }), isSelected && (jsx(CheckIcon, { sx: { fontSize: 15, color: 'primary.main', flexShrink: 0 } }))] }, opt.value));
247
245
  }))] })] })] }));
248
246
  };
249
- const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, onToggle, maxVisible = 4, }) => {
247
+ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, onToggle, maxVisible = 4, chipStyle, }) => {
250
248
  const [anchor, setAnchor] = useState(null);
251
249
  const atLimit = visibleIds.length >= maxVisible;
252
250
  // Shared pill box renderer
@@ -262,9 +260,9 @@ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, o
262
260
  lineHeight: 1.6,
263
261
  }, children: label }));
264
262
  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: {
265
- borderRadius: 5, textTransform: 'none', fontSize: 12,
263
+ borderRadius: 5, textTransform: 'none', fontSize: chipStyle.fontSize,
266
264
  borderColor: 'divider', color: 'text.secondary',
267
- px: 1.5, minHeight: 30,
265
+ px: chipStyle.px ?? 1.5, minHeight: chipStyle.minHeight,
268
266
  '&:hover': { borderColor: 'primary.main', color: 'primary.main' },
269
267
  }, children: "Manage Filters" }) }), 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: [atLimit && (jsx(Box, { sx: {
270
268
  px: 2, py: 0.75,
@@ -292,7 +290,12 @@ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, o
292
290
  } }), selected && jsx(CheckIcon, { sx: { fontSize: 16, color: 'primary.main', flexShrink: 0 } })] }) }) }, col.id));
293
291
  }) })] }))] })] })] }));
294
292
  };
295
- const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, }) => {
293
+ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, uiDensity = 'default', filterChipFontSize, filterChipMinHeight, filterLabelFontSize, }) => {
294
+ const chipStyle = {
295
+ fontSize: filterChipFontSize ?? (uiDensity === 'compact' ? 11 : 12),
296
+ minHeight: filterChipMinHeight ?? (uiDensity === 'compact' ? 26 : 30),
297
+ };
298
+ const labelFontSize = filterLabelFontSize ?? (uiDensity === 'compact' ? 11 : 12);
296
299
  const getColValue = (id) => columnFilters.find((f) => f.id === id)?.value ?? '';
297
300
  const applyColFilter = (id, value) => {
298
301
  const rest = columnFilters.filter((f) => f.id !== id);
@@ -316,36 +319,36 @@ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter,
316
319
  }
317
320
  onToggleFilter(id);
318
321
  };
319
- 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: 15, color: 'text.disabled' } }), jsx(Typography, { variant: "body2", fontSize: 12, color: "text.secondary", fontWeight: 500, noWrap: true, children: "Filter by:" })] }), visibleFilterIds.map((id) => {
322
+ 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) => {
320
323
  const def = serverFilterDefs.find((d) => d.id === id);
321
324
  if (def?.type === 'dateRange') {
322
- 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) }, id));
325
+ 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));
323
326
  }
324
327
  if (def?.type === 'text') {
325
- return (jsx(TextFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id), placeholder: def.placeholder }, id));
328
+ 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));
326
329
  }
327
330
  if (def?.type === 'dropdown') {
328
- return (jsx(DropdownFilterChip, { label: def.label, value: filterValues[def.filterKey] ?? '', options: def.options, onApply: (v) => onFilterValuesChange({ ...filterValues, [def.filterKey]: v }), onRemove: () => removeFilter(id) }, id));
331
+ 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));
329
332
  }
330
333
  if (def?.type === 'searchableDropdown') {
331
- 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…' }, id));
334
+ 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));
332
335
  }
333
336
  if (def?.type === 'date') {
334
- return (jsx(DatePickerChip, { label: def.label, value: getColValue(def.columnKey), onApply: (v) => applyColFilter(def.columnKey, v), onRemove: () => removeFilter(id) }, id));
337
+ return (jsx(DatePickerChip, { label: def.label, value: getColValue(def.columnKey), onApply: (v) => applyColFilter(def.columnKey, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
335
338
  }
336
339
  // Column filter chip — render the variant that matches the column's filterType
337
340
  const col = availableColumns.find((c) => c.id === id);
338
341
  if (!col)
339
342
  return null;
340
343
  if (col.filterType === 'date') {
341
- return (jsx(DatePickerChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id) }, id));
344
+ return (jsx(DatePickerChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
342
345
  }
343
346
  if (col.filterType === 'select' || col.filterType === 'searchable-select') {
344
- return (jsx(SearchableSelectChip, { label: col.label, value: getColValue(id), options: col.filterOptions ?? [], onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id) }, id));
347
+ return (jsx(SearchableSelectChip, { label: col.label, value: getColValue(id), options: col.filterOptions ?? [], onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), chipStyle: chipStyle }, id));
345
348
  }
346
349
  // Default: free-text input
347
- return (jsx(TextFilterChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), placeholder: `Filter by ${col.label}` }, id));
348
- }), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters })] }));
350
+ 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));
351
+ }), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters, chipStyle: chipStyle })] }));
349
352
  };
350
353
 
351
354
  export { DynamicFilterBar as default };
@@ -7,6 +7,21 @@ export interface PagedResult<TData> {
7
7
  data: TData[];
8
8
  totalRecords: number;
9
9
  }
10
+ /** Preset for toolbar, filter chips, and pagination footer sizing. */
11
+ export type GridUiDensity = 'default' | 'compact';
12
+ /** Fine-grained UI sizing overrides (merged on top of `uiDensity` preset). */
13
+ export interface GridUiDensityOptions {
14
+ footerMinHeight?: number;
15
+ footerFontSize?: number;
16
+ footerIconSize?: number;
17
+ footerPaddingY?: number;
18
+ filterChipFontSize?: number;
19
+ filterChipMinHeight?: number;
20
+ filterLabelFontSize?: number;
21
+ toolbarIconFontSize?: number | string;
22
+ /** MRT built-in toolbar control density (show/hide columns, density toggle, etc.). */
23
+ mrtDensity?: 'comfortable' | 'compact' | 'spacious';
24
+ }
10
25
  export interface GenericPaginatedGridProps<TData extends object> {
11
26
  /**
12
27
  * Column definitions. Use `TPColumnDef<TData>` (a superset of `MRT_ColumnDef`)
@@ -36,11 +51,35 @@ export interface GenericPaginatedGridProps<TData extends object> {
36
51
  /**
37
52
  * Height of the entire grid component.
38
53
  * When omitted (default) the grid auto-sizes to fill the remaining viewport
39
- * height from its top position — the page never needs to scroll.
40
- * Pass an explicit CSS value only when you need to override
41
- * (e.g. "600px", "calc(100vh - 300px)").
54
+ * height from its top position on mount and window resize only (not on scroll).
55
+ * Pass an explicit CSS value to pin height (e.g. "600px", "calc(100vh - 300px)").
42
56
  */
43
57
  tableHeight?: string;
58
+ /**
59
+ * Minimum height of the grid wrapper (CSS length).
60
+ * Used in auto-height `clamp()` and as `minHeight` when `tableHeight` is set.
61
+ * Default: `300px`.
62
+ */
63
+ tableMinHeight?: string;
64
+ /**
65
+ * Maximum height of the grid wrapper (CSS length).
66
+ * Caps auto-calculated viewport height. Default: none (only viewport clamp).
67
+ */
68
+ tableMaxHeight?: string;
69
+ /**
70
+ * When false, disables viewport auto-height; use `tableHeight` or `tableMinHeight` only.
71
+ * Default: true (unless `tableHeight` is provided).
72
+ */
73
+ autoFillViewport?: boolean;
74
+ /**
75
+ * MRT column layout. Default `grid` — columns grow to fill width (no trailing spacer column).
76
+ * Use `grid-no-grow` only when you need fixed column widths with horizontal scroll.
77
+ */
78
+ layoutMode?: 'grid' | 'semantic' | 'grid-no-grow';
79
+ /** Compact toolbar, filter chips, and footer. Default: `default`. */
80
+ uiDensity?: GridUiDensity;
81
+ /** Override individual sizes from the `uiDensity` preset. */
82
+ uiDensityOptions?: GridUiDensityOptions;
44
83
  /** Choices shown in the "Rows per page" footer dropdown. Default: [1 000, 5 000, 10 000]. */
45
84
  pageSizeOptions?: number[];
46
85
  /**
@@ -48,6 +87,21 @@ export interface GenericPaginatedGridProps<TData extends object> {
48
87
  * Accepts any valid CSS colour string.
49
88
  */
50
89
  headerBgColor?: string;
90
+ /**
91
+ * Minimum height of every header cell (CSS length or px number).
92
+ * Default: `40px` (`34px` when `uiDensity="compact"`).
93
+ */
94
+ headerMinHeight?: string | number;
95
+ /**
96
+ * Maximum height of the header row — **all columns use the same height**.
97
+ * Long titles wrap inside this box. Default: `72px` (`56px` compact).
98
+ */
99
+ headerMaxHeight?: string | number;
100
+ /**
101
+ * Optional max lines for header text (`-webkit-line-clamp`).
102
+ * Omit to allow text to use the full `headerMaxHeight` (recommended for tall headers).
103
+ */
104
+ headerMaxLines?: number;
51
105
  /**
52
106
  * Maximum number of filter chips that can be visible at once.
53
107
  * Prevents the filter bar from wrapping to a second row on typical screens.
@@ -55,5 +109,5 @@ export interface GenericPaginatedGridProps<TData extends object> {
55
109
  */
56
110
  maxVisibleFilters?: number;
57
111
  }
58
- declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, tableHeight, pageSizeOptions, headerBgColor, maxVisibleFilters, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
112
+ declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, pageSizeOptions, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, maxVisibleFilters, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
59
113
  export default GenericPaginatedGrid;
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { useState, useRef, useLayoutEffect, useMemo } from 'react';
2
+ import { useMemo, useState, useRef, useLayoutEffect } from 'react';
3
3
  import { useMaterialReactTable, MaterialReactTable } from 'material-react-table';
4
4
  import { useQuery, keepPreviousData } from '@tanstack/react-query';
5
5
  import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, CircularProgress } from '@mui/material';
@@ -11,6 +11,160 @@ import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
11
11
  import ChevronRightIcon from '@mui/icons-material/ChevronRight';
12
12
  import DynamicFilterBar from './DynamicFilterBar.esm.js';
13
13
 
14
+ const UI_DENSITY_PRESETS = {
15
+ default: {
16
+ footerMinHeight: 48,
17
+ footerFontSize: 14,
18
+ footerIconSize: 20,
19
+ footerPaddingY: 0.75,
20
+ filterChipFontSize: 12,
21
+ filterChipMinHeight: 30,
22
+ filterLabelFontSize: 12,
23
+ toolbarIconFontSize: 'small',
24
+ mrtDensity: 'comfortable',
25
+ },
26
+ compact: {
27
+ footerMinHeight: 32,
28
+ footerFontSize: 12,
29
+ footerIconSize: 18,
30
+ footerPaddingY: 0.25,
31
+ filterChipFontSize: 11,
32
+ filterChipMinHeight: 26,
33
+ filterLabelFontSize: 11,
34
+ toolbarIconFontSize: 'inherit',
35
+ mrtDensity: 'compact',
36
+ },
37
+ };
38
+ const toCssSize = (value, fallback) => {
39
+ if (value === undefined)
40
+ return fallback;
41
+ return typeof value === 'number' ? `${value}px` : value;
42
+ };
43
+ /**
44
+ * Header overrides applied via GlobalStyles (literal prop values).
45
+ * MRT sets `backgroundColor: 'inherit'` and fixed density padding — must use !important.
46
+ */
47
+ const buildHeaderGlobalStyles = (headerMin, headerMax, headerBgColor) => {
48
+ const headCell = {
49
+ height: `${headerMax} !important`,
50
+ minHeight: `${headerMin} !important`,
51
+ maxHeight: `${headerMax} !important`,
52
+ boxSizing: 'border-box !important',
53
+ alignSelf: 'stretch !important',
54
+ whiteSpace: 'normal !important',
55
+ verticalAlign: 'middle !important',
56
+ pt: '8px !important',
57
+ pb: '8px !important',
58
+ px: '14px !important',
59
+ };
60
+ if (headerBgColor) {
61
+ headCell.backgroundColor = `${headerBgColor} !important`;
62
+ headCell.backgroundImage = 'none !important';
63
+ }
64
+ return {
65
+ '.tp-gpg-root .MuiTableHead-root .MuiTableRow-root': {
66
+ height: `${headerMax} !important`,
67
+ minHeight: `${headerMin} !important`,
68
+ maxHeight: `${headerMax} !important`,
69
+ alignItems: 'stretch !important',
70
+ ...(headerBgColor ? { backgroundColor: headerBgColor } : {}),
71
+ },
72
+ '.tp-gpg-root .MuiTableHead-root .MuiTableCell-head': headCell,
73
+ '.tp-gpg-root .MuiTableHead-root .Mui-TableHeadCell-Content': {
74
+ height: '100% !important',
75
+ width: '100% !important',
76
+ minHeight: '0 !important',
77
+ alignItems: 'center !important',
78
+ },
79
+ '.tp-gpg-root .MuiTableHead-root .Mui-TableHeadCell-Content-Labels': {
80
+ overflow: 'visible !important',
81
+ flexWrap: 'wrap !important',
82
+ whiteSpace: 'normal !important',
83
+ textOverflow: 'clip !important',
84
+ width: '100% !important',
85
+ maxWidth: '100% !important',
86
+ },
87
+ '.tp-gpg-root .MuiTableHead-root .Mui-TableHeadCell-Content-Wrapper': {
88
+ overflow: 'visible !important',
89
+ whiteSpace: 'normal !important',
90
+ textOverflow: 'clip !important',
91
+ wordBreak: 'break-word !important',
92
+ overflowWrap: 'anywhere !important',
93
+ width: '100% !important',
94
+ maxWidth: '100% !important',
95
+ display: 'block !important',
96
+ WebkitLineClamp: 'unset !important',
97
+ WebkitBoxOrient: 'unset !important',
98
+ },
99
+ '.tp-gpg-root .MuiTableHead-root .MuiTableSortLabel-root': {
100
+ whiteSpace: 'normal !important',
101
+ wordBreak: 'break-word !important',
102
+ overflowWrap: 'anywhere !important',
103
+ width: '100% !important',
104
+ },
105
+ };
106
+ };
107
+ /** Per-cell sx merged into MRT (via muiTableHeadCellProps). */
108
+ const buildHeaderCellSx = (align, headerMin, headerMax, headerBgColor, headerMaxLines) => {
109
+ const textAlign = align;
110
+ const flexJustify = align === 'right' ? 'flex-end' : align === 'center' ? 'center' : 'flex-start';
111
+ const wrapperClamp = headerMaxLines != null && headerMaxLines > 0
112
+ ? {
113
+ display: '-webkit-box',
114
+ WebkitLineClamp: headerMaxLines,
115
+ WebkitBoxOrient: 'vertical',
116
+ overflow: 'hidden',
117
+ }
118
+ : {
119
+ display: 'block',
120
+ WebkitLineClamp: 'unset',
121
+ overflow: 'visible',
122
+ };
123
+ return {
124
+ ...(headerBgColor
125
+ ? { backgroundColor: `${headerBgColor} !important`, backgroundImage: 'none' }
126
+ : {}),
127
+ height: `${headerMax} !important`,
128
+ minHeight: `${headerMin} !important`,
129
+ maxHeight: `${headerMax} !important`,
130
+ boxSizing: 'border-box',
131
+ borderRight: '1px solid rgba(224,224,224,1)',
132
+ borderBottom: '2px solid rgba(0,0,0,0.15)',
133
+ '& button[aria-label="Move"]': { display: 'none !important' },
134
+ '& .MuiTableSortLabel-icon': { display: 'none !important' },
135
+ '& .Mui-TableHeadCell-ResizeHandle-Wrapper': { height: '100%', top: 0 },
136
+ '& .Mui-TableHeadCell-ResizeHandle-Divider': { borderRight: 'none' },
137
+ '& .Mui-TableHeadCell-Content': {
138
+ alignItems: 'center',
139
+ justifyContent: flexJustify,
140
+ height: '100%',
141
+ width: '100%',
142
+ },
143
+ '& .Mui-TableHeadCell-Content-Labels': {
144
+ flexWrap: 'wrap',
145
+ whiteSpace: 'normal',
146
+ textAlign,
147
+ width: '100%',
148
+ justifyContent: flexJustify,
149
+ overflow: 'visible',
150
+ },
151
+ '& .Mui-TableHeadCell-Content-Wrapper': {
152
+ whiteSpace: 'normal',
153
+ wordBreak: 'break-word',
154
+ overflowWrap: 'anywhere',
155
+ lineHeight: 1.25,
156
+ width: '100%',
157
+ textAlign,
158
+ ...wrapperClamp,
159
+ },
160
+ '& .MuiTableSortLabel-root': {
161
+ whiteSpace: 'normal',
162
+ wordBreak: 'break-word',
163
+ width: '100%',
164
+ margin: 0,
165
+ },
166
+ };
167
+ };
14
168
  // ─── Internal: overlay loader ─────────────────────────────────────────────────
15
169
  const OverlayLoader = ({ message }) => (jsxs(Box, { sx: {
16
170
  position: 'absolute', inset: 0,
@@ -19,31 +173,41 @@ const OverlayLoader = ({ message }) => (jsxs(Box, { sx: {
19
173
  bgcolor: 'rgba(255,255,255,0.80)', backdropFilter: 'blur(2px)',
20
174
  zIndex: 10, gap: 1.5,
21
175
  }, children: [jsx(CircularProgress, { size: 50, thickness: 4 }), jsx(Typography, { variant: "body2", color: "text.secondary", fontWeight: 500, children: message })] }));
22
- const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, }) => {
176
+ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, }) => {
177
+ const fs = density.footerFontSize;
178
+ const selectH = density.footerMinHeight - 8;
23
179
  const startRow = totalRecords === 0 ? 0 : pageIndex * pageSize + 1;
24
180
  const endRow = Math.min((pageIndex + 1) * pageSize, totalRecords);
25
181
  return (jsxs(Box, { sx: {
26
182
  display: 'flex', alignItems: 'center', justifyContent: 'flex-end',
27
- gap: { xs: 1.5, md: 3 }, px: 2, py: 0.75,
183
+ gap: { xs: 1, md: 2 }, px: 1.5, py: density.footerPaddingY,
28
184
  borderTop: '1px solid', borderColor: 'divider',
29
- bgcolor: 'background.paper', flexWrap: 'wrap', minHeight: 48,
30
- }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsx(Typography, { variant: "body2", 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: {
31
- height: 28, fontSize: 13, minWidth: 80,
32
- '.MuiSelect-select': { py: '3px !important' },
185
+ bgcolor: 'background.paper', flexWrap: 'wrap',
186
+ minHeight: density.footerMinHeight,
187
+ flexShrink: 0,
188
+ }, 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: {
189
+ height: selectH, fontSize: fs - 1, minWidth: 72,
190
+ '.MuiSelect-select': { py: '2px !important' },
33
191
  '.MuiOutlinedInput-notchedOutline': { borderColor: 'divider' },
34
- }, children: pageSizeOptions.map((opt) => (jsx(MenuItem, { value: opt, sx: { fontSize: 13 }, children: opt.toLocaleString() }, opt))) })] }), jsx(Typography, { variant: "body2", color: "text.secondary", noWrap: true, children: isLoading || (isFetching && totalRecords === 0)
192
+ }, children: pageSizeOptions.map((opt) => (jsx(MenuItem, { value: opt, sx: { fontSize: fs - 1 }, children: opt.toLocaleString() }, opt))) })] }), jsx(Typography, { sx: { fontSize: fs }, color: "text.secondary", noWrap: true, children: isLoading || (isFetching && totalRecords === 0)
35
193
  ? 'Loading…'
36
194
  : totalRecords === 0
37
195
  ? 'No records'
38
- : `${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, children: jsx(FirstPageIcon, { sx: { fontSize: 20 } }) }) }) }), jsx(Tooltip, { title: "Previous page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onPrev, disabled: !canPrev, children: jsx(ChevronLeftIcon, { sx: { fontSize: 20 } }) }) }) }), jsx(Typography, { variant: "body2", fontWeight: 600, sx: {
39
- mx: 0.5, minWidth: 28, height: 28,
196
+ : `${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: {
197
+ mx: 0.5,
198
+ minWidth: density.footerMinHeight - 12,
199
+ height: density.footerMinHeight - 12,
40
200
  display: 'flex', alignItems: 'center', justifyContent: 'center',
41
201
  borderRadius: 1, border: '1px solid', borderColor: 'primary.main',
42
- color: 'primary.main', bgcolor: 'rgba(25,118,210,0.07)', fontSize: 13,
43
- }, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onNext, disabled: !canNext, children: jsx(ChevronRightIcon, { sx: { fontSize: 20 } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onLast, disabled: !canNext, children: jsx(LastPageIcon, { sx: { fontSize: 20 } }) }) }) })] })] }));
202
+ color: 'primary.main', bgcolor: 'rgba(25,118,210,0.07)', fontSize: fs - 1,
203
+ }, 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 } }) }) }) })] })] }));
44
204
  };
45
205
  // ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
46
- function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', tableHeight, pageSizeOptions = [1000, 5000, 10000], headerBgColor, maxVisibleFilters = 4, }) {
206
+ 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], headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, maxVisibleFilters = 4, }) {
207
+ const densityTokens = useMemo(() => ({ ...UI_DENSITY_PRESETS[uiDensity], ...uiDensityOptions }), [uiDensity, uiDensityOptions]);
208
+ const resolvedHeaderMinHeight = toCssSize(headerMinHeight, uiDensity === 'compact' ? '34px' : '40px');
209
+ const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight, uiDensity === 'compact' ? '56px' : '72px');
210
+ const headerGlobalStyleOverrides = useMemo(() => buildHeaderGlobalStyles(resolvedHeaderMinHeight, resolvedHeaderMaxHeight, headerBgColor), [resolvedHeaderMinHeight, resolvedHeaderMaxHeight, headerBgColor]);
47
211
  const defaultVisible = defaultVisibleFilterIds
48
212
  ?? (serverFilterDefs.length > 0 ? [serverFilterDefs[0].id] : []);
49
213
  // ── State ──────────────────────────────────────────────────────────────────
@@ -57,58 +221,35 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
57
221
  const [columnFilters, setColumnFilters] = useState([]);
58
222
  const [globalFilter, setGlobalFilter] = useState('');
59
223
  const [columnPinning, setColumnPinning] = useState({});
60
- // ── Viewport-fill: measure this component's top offset and derive height ──────
224
+ // ── Viewport-fill height (mount + resize only — never on scroll) ─────────────
61
225
  //
62
- // When tableHeight is not provided, we measure how far the wrapper sits from
63
- // the top of the viewport and set height = 100vh − topOffset − 8px (tiny
64
- // bottom margin). A ResizeObserver on <html> keeps the value in sync if the
65
- // layout shifts (sidebar collapses, font loads, etc.).
66
- //
67
- // The MRT Paper + TableContainer flex chain distributes that height between
68
- // the toolbar, sticky column headers, scrollable rows, and pagination footer —
69
- // so the grid fills the window exactly and the page never needs to scroll.
226
+ // Previously a scroll listener recalculated height as the grid moved within the
227
+ // viewport, which grew the grid while scrolling and caused double scrollbars.
70
228
  const containerRef = useRef(null);
71
229
  const [autoHeight, setAutoHeight] = useState('');
230
+ const shouldAutoFill = autoFillViewport && !tableHeight;
72
231
  useLayoutEffect(() => {
73
- if (tableHeight)
74
- return; // explicit prop — skip auto calculation
232
+ if (!shouldAutoFill)
233
+ return;
75
234
  const el = containerRef.current;
76
235
  if (!el)
77
236
  return;
78
237
  const update = () => {
79
238
  const top = el.getBoundingClientRect().top;
80
- // CSS max() guarantees a minimum visible height (300px) when the grid
81
- // starts below the fold or when little viewport space remains — both
82
- // cases produce a negative/tiny calc() that would otherwise collapse
83
- // the grid to zero height.
84
- setAutoHeight(`max(300px, calc(100vh - ${Math.ceil(top) + 8}px))`);
239
+ const preferred = `calc(100vh - ${Math.ceil(top) + 8}px)`;
240
+ const maxPart = tableMaxHeight ?? preferred;
241
+ setAutoHeight(`clamp(${tableMinHeight}, ${preferred}, ${maxPart})`);
85
242
  };
86
243
  update();
87
- // Re-measure on any document resize (window resize, sidebar toggle, etc.)
88
244
  const ro = new ResizeObserver(update);
89
- ro.observe(document.documentElement);
90
- // Re-measure when the scroll container scrolls — the grid's
91
- // viewport-relative top offset shifts with scroll position, so the
92
- // height must be recalculated to fill the remaining visible space.
93
- const findScrollParent = (node) => {
94
- let p = node.parentElement;
95
- while (p && p !== document.documentElement) {
96
- const { overflow, overflowY } = window.getComputedStyle(p);
97
- if (/auto|scroll/.test(overflow) || /auto|scroll/.test(overflowY))
98
- return p;
99
- p = p.parentElement;
100
- }
101
- return window;
102
- };
103
- const scrollParent = findScrollParent(el);
104
- scrollParent.addEventListener('scroll', update, { passive: true });
245
+ ro.observe(el);
246
+ window.addEventListener('resize', update, { passive: true });
105
247
  return () => {
106
248
  ro.disconnect();
107
- scrollParent.removeEventListener('scroll', update);
249
+ window.removeEventListener('resize', update);
108
250
  };
109
- }, [tableHeight]);
110
- // Resolved height: explicit prop › auto-calculated › safe fallback
111
- const resolvedHeight = tableHeight || autoHeight || '60vh';
251
+ }, [shouldAutoFill, tableMinHeight, tableMaxHeight]);
252
+ const resolvedHeight = tableHeight || (shouldAutoFill ? autoHeight : undefined) || tableMinHeight;
112
253
  // ── Data fetching ──────────────────────────────────────────────────────────
113
254
  const { data, isLoading, isError, isFetching, refetch } = useQuery({
114
255
  queryKey: [...queryKey, filterValues, pagination.pageIndex],
@@ -124,9 +265,13 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
124
265
  // MRT doesn't know these props, so we strip them here. We also inject the
125
266
  // appropriate `filterFn` automatically so callers never have to write one.
126
267
  const processedColumns = useMemo(() => {
268
+ const allowGrow = layoutMode === 'grid' || layoutMode === 'semantic';
127
269
  return columns.map((col) => {
128
270
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
129
271
  const { filterType, options, ...mrtCol } = col;
272
+ if (allowGrow && mrtCol.grow === undefined) {
273
+ mrtCol.grow = true;
274
+ }
130
275
  // Auto-inject filterFn only when the user hasn't already supplied one.
131
276
  if (!mrtCol.filterFn && filterType) {
132
277
  if (filterType === 'date') {
@@ -145,7 +290,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
145
290
  }
146
291
  return mrtCol;
147
292
  });
148
- }, [columns]);
293
+ }, [columns, layoutMode]);
149
294
  // ── Derive column list for filter chip picker ──────────────────────────────
150
295
  //
151
296
  // A column is excluded from the "Column Filters" section of Manage Filters
@@ -211,6 +356,22 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
211
356
  const table = useMaterialReactTable({
212
357
  columns: processedColumns,
213
358
  data: rows,
359
+ layoutMode,
360
+ displayColumnDefOptions: {
361
+ 'mrt-row-spacer': {
362
+ size: 0,
363
+ minSize: 0,
364
+ maxSize: 0,
365
+ grow: false,
366
+ enableResizing: false,
367
+ muiTableHeadCellProps: {
368
+ sx: { display: 'none !important', width: 0, maxWidth: 0, p: 0, border: 'none' },
369
+ },
370
+ muiTableBodyCellProps: {
371
+ sx: { display: 'none !important', width: 0, maxWidth: 0, p: 0, border: 'none' },
372
+ },
373
+ },
374
+ },
214
375
  manualPagination: true,
215
376
  rowCount: totalRecords,
216
377
  manualSorting: false,
@@ -246,71 +407,76 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
246
407
  enableHiding: true,
247
408
  enableStickyHeader: true,
248
409
  enableRowVirtualization: true,
249
- // The container fills whatever height is left after the top toolbar and
250
- // pagination footer. minHeight ensures a visible body even when there are
251
- // no records; flex: '1 1 0' lets it grow to fill the remaining space.
410
+ initialState: {
411
+ density: densityTokens.mrtDensity,
412
+ },
413
+ muiTableProps: {
414
+ sx: { width: '100%' },
415
+ },
252
416
  muiTableContainerProps: {
253
417
  sx: {
254
418
  flex: '1 1 0',
255
- minHeight: '150px',
419
+ minHeight: 0,
420
+ maxHeight: '100%',
421
+ overflow: 'auto',
256
422
  },
257
423
  },
258
- // Paper fills the wrapper Box height and acts as the flex column host for
259
- // toolbar → table-container → pagination.
260
424
  muiTablePaperProps: {
261
425
  sx: {
262
426
  height: '100%',
427
+ minHeight: 0,
263
428
  display: 'flex',
264
429
  flexDirection: 'column',
430
+ overflow: 'hidden',
431
+ boxShadow: 'none',
265
432
  },
266
433
  },
267
434
  muiTopToolbarProps: {
268
435
  sx: {
269
436
  alignItems: 'center',
270
437
  flexWrap: 'nowrap',
438
+ minHeight: densityTokens.filterChipMinHeight + 12,
439
+ py: uiDensity === 'compact' ? 0.25 : 0.5,
440
+ '& .MuiIconButton-root': { p: uiDensity === 'compact' ? 0.35 : 0.5 },
441
+ '& .MuiIconButton-root svg': { fontSize: densityTokens.toolbarIconFontSize === 'small' ? 18 : 20 },
442
+ },
443
+ },
444
+ muiTableHeadProps: {
445
+ sx: {
446
+ position: 'sticky',
447
+ top: 0,
448
+ zIndex: 2,
449
+ ...(headerBgColor ? { backgroundColor: headerBgColor } : {}),
450
+ },
451
+ },
452
+ muiTableHeadRowProps: {
453
+ sx: {
454
+ height: resolvedHeaderMaxHeight,
455
+ minHeight: resolvedHeaderMinHeight,
456
+ maxHeight: resolvedHeaderMaxHeight,
457
+ alignItems: 'stretch',
458
+ ...(headerBgColor ? { backgroundColor: headerBgColor } : {}),
271
459
  },
272
460
  },
273
461
  muiTableHeadCellProps: ({ column }) => {
274
462
  const colProps = column.columnDef.muiTableHeadCellProps;
275
- const align = colProps && typeof colProps !== 'function'
276
- ? colProps.align
277
- : undefined;
278
- const justifyContent = align === 'right' ? 'flex-start'
279
- : align === 'center' ? 'center'
280
- : 'flex-end';
463
+ let align = 'left';
464
+ let colSx;
465
+ if (typeof colProps === 'function') {
466
+ const resolved = colProps({ column });
467
+ align = resolved?.align ?? 'left';
468
+ colSx = resolved?.sx;
469
+ }
470
+ else if (colProps) {
471
+ align = colProps.align ?? 'left';
472
+ colSx = colProps.sx;
473
+ }
281
474
  return {
282
- align: (align ?? 'left'),
283
- sx: {
284
- ...(headerBgColor ? { backgroundColor: headerBgColor } : {}),
285
- verticalAlign: 'bottom',
286
- whiteSpace: 'normal',
287
- borderRight: '1px solid rgba(224,224,224,1)',
288
- borderBottom: '2px solid rgba(0,0,0,0.15)',
289
- '& button[aria-label="Move"]': { display: 'none !important' },
290
- '& .MuiTableSortLabel-icon': { display: 'none !important' },
291
- '& .Mui-TableHeadCell-ResizeHandle-Wrapper': {
292
- height: '100%',
293
- top: 0,
294
- },
295
- '& .Mui-TableHeadCell-ResizeHandle-Divider': {
296
- borderRight: 'none',
297
- },
298
- '& .Mui-TableHeadCell-Content': {
299
- alignItems: 'flex-end',
300
- justifyContent,
301
- },
302
- '& .Mui-TableHeadCell-Content-Labels': {
303
- flexWrap: 'wrap',
304
- whiteSpace: 'normal',
305
- overflowWrap: 'normal',
306
- lineHeight: 1.3,
307
- justifyContent,
308
- },
309
- '& .Mui-TableHeadCell-Content-Wrapper': {
310
- whiteSpace: 'normal',
311
- overflow: 'visible',
312
- },
313
- },
475
+ align,
476
+ sx: [
477
+ buildHeaderCellSx(align, resolvedHeaderMinHeight, resolvedHeaderMaxHeight, headerBgColor, headerMaxLines),
478
+ ...(colSx ? [colSx] : []),
479
+ ],
314
480
  };
315
481
  },
316
482
  muiTableBodyCellProps: {
@@ -322,19 +488,25 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
322
488
  muiToolbarAlertBannerProps: isError
323
489
  ? { color: 'error', children: 'Failed to load data. Please try again.' }
324
490
  : undefined,
325
- 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, children: jsx(RefreshIcon, { fontSize: "small" }) }) }) }), jsx(Tooltip, { title: "Export batch as CSV", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: handleExport, disabled: rows.length === 0 || isFetching, children: jsx(FileDownloadIcon, { fontSize: "small" }) }) }) })] }), 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 }) })] })),
326
- 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 })),
491
+ 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 }) })] })),
492
+ 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 })),
327
493
  });
328
494
  return (jsxs(Box, { ref: containerRef, className: "tp-gpg-root", sx: {
329
495
  position: 'relative',
330
496
  height: resolvedHeight,
497
+ minHeight: tableMinHeight,
498
+ maxHeight: tableMaxHeight,
331
499
  display: 'flex',
332
500
  flexDirection: 'column',
501
+ overflow: 'hidden',
333
502
  }, children: [jsx(GlobalStyles, { styles: {
334
503
  'button[aria-label="Pin to right"]': { display: 'none' },
335
504
  '.tp-gpg-root .MuiTableSortLabel-icon': { display: 'none !important' },
336
505
  '.tp-gpg-root button[aria-label="Move"]': { display: 'none !important' },
337
- } }), isLoading && jsx(OverlayLoader, { message: "Loading data\u2026" }), !isLoading && isFetching && jsx(OverlayLoader, { message: "Updating data\u2026" }), jsx(MaterialReactTable, { table: table })] }));
506
+ '.tp-gpg-root [data-column-id="mrt-row-spacer"]': { display: 'none !important' },
507
+ '.tp-gpg-root .Mui-TableHeadCell-ColumnSpacer': { display: 'none !important' },
508
+ ...headerGlobalStyleOverrides,
509
+ } }), isLoading && jsx(OverlayLoader, { message: "Loading data\u2026" }), !isLoading && isFetching && jsx(OverlayLoader, { message: "Updating data\u2026" }), jsx(Box, { sx: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: jsx(MaterialReactTable, { table: table }) })] }));
338
510
  }
339
511
 
340
512
  export { GenericPaginatedGrid as default };
@@ -1,4 +1,5 @@
1
1
  export { default as GenericPaginatedGrid } from './GenericPaginatedGrid';
2
- export type { GenericPaginatedGridProps, PagedResult } from './GenericPaginatedGrid';
2
+ export type { GenericPaginatedGridProps, PagedResult, GridUiDensity, GridUiDensityOptions, } from './GenericPaginatedGrid';
3
3
  export { default as DynamicFilterBar } from './DynamicFilterBar';
4
4
  export type { ServerFilterDef } from './DynamicFilterBar';
5
+ export type { TPColumnDef, ColumnFilterType } from './types';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Mock data + fetch adapters for Storybook sample grids (no API required).
3
+ */
4
+ import type { TPColumnDef } from './types';
5
+ import type { PagedResult } from './GenericPaginatedGrid';
6
+ import type { ServerFilterDef } from './DynamicFilterBar';
7
+ export interface EmployeeRow {
8
+ id: number;
9
+ name: string;
10
+ department: string;
11
+ costCenter: string;
12
+ workLocation: string;
13
+ reportingManager: string;
14
+ employmentType: string;
15
+ status: string;
16
+ joinedOn: string;
17
+ }
18
+ /** Columns with long headers + narrow widths to exercise header wrapping in Storybook. */
19
+ export declare const employeeColumns: TPColumnDef<EmployeeRow>[];
20
+ export declare const employeeFilterDefs: ServerFilterDef[];
21
+ export declare const employeeDefaultFilters: Record<string, string>;
22
+ export declare function fetchEmployeePage(filters: Record<string, string>, pageIndex: number, pageSize?: number): Promise<PagedResult<EmployeeRow>>;
23
+ export interface ProductRow {
24
+ sku: string;
25
+ title: string;
26
+ category: string;
27
+ price: number;
28
+ inStock: boolean;
29
+ }
30
+ export declare const productColumns: TPColumnDef<ProductRow>[];
31
+ export declare const productFilterDefs: ServerFilterDef[];
32
+ export declare const productDefaultFilters: Record<string, string>;
33
+ export declare function fetchProductPage(filters: Record<string, string>, pageIndex: number, pageSize?: number): Promise<PagedResult<ProductRow>>;
package/dist/index.d.ts CHANGED
@@ -15,3 +15,4 @@ export * as Theme from './theme';
15
15
  export type { FormRenderProps } from './utils';
16
16
  export type { FormRenderWrapperProps } from './components/Form/FormRenderWrapper';
17
17
  export type { FormSectionPropsItem, VariantProps } from './utils';
18
+ export type { GenericPaginatedGridProps, GridUiDensity, GridUiDensityOptions, PagedResult, ServerFilterDef, TPColumnDef, } from './components/PaginatedGrid';
@@ -1,4 +1,4 @@
1
- import { __exports as Calendar } from '../../../../../_virtual/index.esm7.js';
1
+ import { __exports as Calendar } from '../../../../../_virtual/index.esm4.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 DateRange } from '../../../../../_virtual/index.esm5.js';
1
+ import { __exports as DateRange } 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 requireCalendar } from '../Calendar/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm6.js';
1
+ import { __exports as DateRangePicker } 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 requireDateRange } from '../DateRange/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DefinedRange } from '../../../../../_virtual/index.esm4.js';
1
+ import { __exports as DefinedRange } 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 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.esm14.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": "1.3.10",
3
+ "version": "1.3.11",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",