tp-react-elements 2.0.5 → 2.0.7
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/dist/_virtual/index.esm13.js +2 -2
- package/dist/_virtual/index.esm14.js +2 -2
- package/dist/components/Form/FormRender.esm.js +1 -1
- package/dist/components/FormComponents/index.esm.js +2 -2
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +24 -2
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +100 -26
- package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/Month/index.esm.js +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Month = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { Month as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DateInput = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DateInput as __exports };
|
|
@@ -6,6 +6,7 @@ import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.e
|
|
|
6
6
|
import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
|
|
7
7
|
import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
|
|
8
8
|
import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
|
|
9
|
+
import FormTextField from '../FormComponents/FormTextField/FormTextField.esm.js';
|
|
9
10
|
import PasswordField from '../FormComponents/PasswordField/PasswordField.esm.js';
|
|
10
11
|
import SingleSelect from '../FormComponents/Select/SingleSelect.esm.js';
|
|
11
12
|
import MultiSelectAutocomplete from '../FormComponents/Select/MultiSelectAutocomplete.esm.js';
|
|
@@ -17,7 +18,6 @@ import DateRangePickerComponent from '../DateRangePicker/DateRangePicker.esm.js'
|
|
|
17
18
|
import RichTextEditorWrapper from '../FormComponents/RichTextEditor/RichTextEditorWrapper.esm.js';
|
|
18
19
|
import SingleSelectSearchApi from '../FormComponents/Select/SingleSelectSearchApi.esm.js';
|
|
19
20
|
import DatetimepickerWrapper from '../FormComponents/DatePicker/DatetimepickerWrapper.esm.js';
|
|
20
|
-
import FormTextField from '../FormComponents/FormTextField/FormTextField.esm.js';
|
|
21
21
|
|
|
22
22
|
// Lazy-loaded heavy components
|
|
23
23
|
// const RichTextEditorWrapper = lazy(() =>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
|
|
2
2
|
export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
|
|
3
3
|
export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
|
|
4
|
+
export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
|
|
4
5
|
export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
|
|
5
6
|
export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
|
|
6
7
|
export { default as SingleSelect } from './Select/SingleSelect.esm.js';
|
|
@@ -14,6 +15,7 @@ export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.j
|
|
|
14
15
|
export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
|
|
15
16
|
export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
|
|
16
17
|
export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
|
|
18
|
+
export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
|
|
17
19
|
export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
|
|
18
20
|
export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
|
|
19
21
|
import 'react/jsx-runtime';
|
|
@@ -32,8 +34,6 @@ import '@mui/icons-material/PictureAsPdf';
|
|
|
32
34
|
import '@mui/icons-material/TableChart';
|
|
33
35
|
import '@mui/icons-material/Description';
|
|
34
36
|
export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
|
|
35
|
-
export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
|
|
36
37
|
export { default as HelperText } from './HelperText/HelperText.esm.js';
|
|
37
38
|
export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
|
|
38
39
|
export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
|
|
39
|
-
export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
|
|
@@ -91,10 +91,32 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
91
91
|
* Use `grid-no-grow` only when you need fixed column widths with horizontal scroll.
|
|
92
92
|
*/
|
|
93
93
|
layoutMode?: 'grid' | 'semantic' | 'grid-no-grow';
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Compact toolbar, filter chips, and footer.
|
|
96
|
+
* When omitted, the grid auto-selects `compact` at the `tablet`/`mobile`
|
|
97
|
+
* responsive tiers and `default` at `desktop`. Pass explicitly to opt out
|
|
98
|
+
* of that auto-switch.
|
|
99
|
+
*/
|
|
95
100
|
uiDensity?: GridUiDensity;
|
|
96
101
|
/** Override individual sizes from the `uiDensity` preset. */
|
|
97
102
|
uiDensityOptions?: GridUiDensityOptions;
|
|
103
|
+
/**
|
|
104
|
+
* Viewport-width cutoffs (px) for the three responsive tiers:
|
|
105
|
+
* `desktop` (above `tablet`), `tablet` (between `mobile` and `tablet`),
|
|
106
|
+
* and `mobile` (at/below `mobile`). Each tier gets progressively tighter
|
|
107
|
+
* defaults — density, filter-chip cap, toolbar wrap, footer layout.
|
|
108
|
+
* Default: `{ tablet: 1024, mobile: 640 }`.
|
|
109
|
+
*/
|
|
110
|
+
responsiveBreakpoints?: {
|
|
111
|
+
tablet?: number;
|
|
112
|
+
mobile?: number;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Opt out of all automatic responsive-tier adjustments (density, filter
|
|
116
|
+
* cap, toolbar wrap, footer layout) — the grid always behaves as `desktop`.
|
|
117
|
+
* Default: `false`.
|
|
118
|
+
*/
|
|
119
|
+
disableResponsive?: boolean;
|
|
98
120
|
/** Choices shown in the "Rows per page" footer dropdown. Default: [1 000, 5 000, 10 000]. */
|
|
99
121
|
pageSizeOptions?: number[];
|
|
100
122
|
/**
|
|
@@ -210,5 +232,5 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
210
232
|
*/
|
|
211
233
|
enableExpanding?: boolean;
|
|
212
234
|
}
|
|
213
|
-
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, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
235
|
+
declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, gridId, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive, pageSizeOptions, showGlobalSearchByDefault, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
214
236
|
export default GenericPaginatedGrid;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useMemo, useState, useRef, useLayoutEffect, useCallback } from 'react';
|
|
3
|
-
import * as XLSX from 'xlsx-js-style';
|
|
2
|
+
import { useMemo, useState, useRef, useLayoutEffect, useCallback, useEffect } from 'react';
|
|
4
3
|
import { MRT_ToggleGlobalFilterButton, MRT_ShowHideColumnsButton, MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, useMaterialReactTable, MaterialReactTable } from 'material-react-table';
|
|
5
4
|
import { useQuery, keepPreviousData } from '@tanstack/react-query';
|
|
6
|
-
import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, CircularProgress } from '@mui/material';
|
|
5
|
+
import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, Skeleton, CircularProgress } from '@mui/material';
|
|
7
6
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
8
7
|
import FileDownloadIcon from '@mui/icons-material/FileDownload';
|
|
9
8
|
import FirstPageIcon from '@mui/icons-material/FirstPage';
|
|
@@ -11,6 +10,7 @@ import LastPageIcon from '@mui/icons-material/LastPage';
|
|
|
11
10
|
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
|
12
11
|
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
|
13
12
|
import DynamicFilterBar from './DynamicFilterBar.esm.js';
|
|
13
|
+
import { getXLSX } from '../../utils/Constants/xlsx-js-style.esm.js';
|
|
14
14
|
|
|
15
15
|
const UI_DENSITY_PRESETS = {
|
|
16
16
|
default: {
|
|
@@ -194,27 +194,60 @@ const OverlayLoader = ({ message }) => (jsxs(Box, { sx: {
|
|
|
194
194
|
bgcolor: 'rgba(255,255,255,0.80)', backdropFilter: 'blur(2px)',
|
|
195
195
|
zIndex: 10, gap: 1.5,
|
|
196
196
|
}, children: [jsx(CircularProgress, { size: 50, thickness: 4 }), jsx(Typography, { variant: "body2", color: "text.secondary", fontWeight: 500, children: message })] }));
|
|
197
|
-
|
|
197
|
+
// ─── Internal: skeleton loader (initial load — no data on screen yet) ────────
|
|
198
|
+
const SkeletonOverlay = ({ columnCount, rowCount = 10, }) => (jsx(Box, { sx: {
|
|
199
|
+
position: 'absolute', inset: 0,
|
|
200
|
+
display: 'flex', flexDirection: 'column',
|
|
201
|
+
bgcolor: 'background.paper',
|
|
202
|
+
zIndex: 10, p: 1.5, gap: 1,
|
|
203
|
+
overflow: 'hidden',
|
|
204
|
+
}, children: Array.from({ length: rowCount }).map((_, rowIdx) => (jsx(Box, { sx: { display: 'flex', gap: 1.5 }, children: Array.from({ length: Math.max(columnCount, 1) }).map((_, colIdx) => (jsx(Skeleton, { variant: "rounded", height: 28, sx: { flex: 1, minWidth: 0 }, animation: "wave" }, colIdx))) }, rowIdx))) }));
|
|
205
|
+
const useResponsiveTier = (tabletBreakpoint, mobileBreakpoint, enabled) => {
|
|
206
|
+
const [tier, setTier] = useState('desktop');
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
if (!enabled || typeof window === 'undefined') {
|
|
209
|
+
setTier('desktop');
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const mqlTablet = window.matchMedia(`(max-width: ${tabletBreakpoint}px)`);
|
|
213
|
+
const mqlMobile = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`);
|
|
214
|
+
const update = () => {
|
|
215
|
+
setTier(mqlMobile.matches ? 'mobile' : mqlTablet.matches ? 'tablet' : 'desktop');
|
|
216
|
+
};
|
|
217
|
+
update();
|
|
218
|
+
mqlTablet.addEventListener('change', update);
|
|
219
|
+
mqlMobile.addEventListener('change', update);
|
|
220
|
+
return () => {
|
|
221
|
+
mqlTablet.removeEventListener('change', update);
|
|
222
|
+
mqlMobile.removeEventListener('change', update);
|
|
223
|
+
};
|
|
224
|
+
}, [tabletBreakpoint, mobileBreakpoint, enabled]);
|
|
225
|
+
return enabled ? tier : 'desktop';
|
|
226
|
+
};
|
|
227
|
+
const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, gridId, isStacked, }) => {
|
|
198
228
|
const fs = density.footerFontSize;
|
|
199
229
|
const selectH = density.footerMinHeight - 8;
|
|
200
230
|
const startRow = totalRecords === 0 ? 0 : pageIndex * pageSize + 1;
|
|
201
231
|
const endRow = Math.min((pageIndex + 1) * pageSize, totalRecords);
|
|
202
232
|
return (jsxs(Box, { sx: {
|
|
203
|
-
display: 'flex',
|
|
233
|
+
display: 'flex',
|
|
234
|
+
flexDirection: isStacked ? 'column' : 'row',
|
|
235
|
+
alignItems: isStacked ? 'stretch' : 'center',
|
|
236
|
+
justifyContent: isStacked ? 'center' : 'flex-end',
|
|
204
237
|
gap: { xs: 1, md: 2 }, px: 1.5, py: density.footerPaddingY,
|
|
205
238
|
borderTop: '1px solid', borderColor: 'divider',
|
|
206
239
|
bgcolor: 'background.paper', flexWrap: 'wrap',
|
|
207
240
|
minHeight: density.footerMinHeight,
|
|
208
241
|
flexShrink: 0,
|
|
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: {
|
|
242
|
+
}, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: isStacked ? 'center' : 'flex-start', 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: {
|
|
210
243
|
height: selectH, fontSize: fs - 1, minWidth: 72,
|
|
211
244
|
'.MuiSelect-select': { py: '2px !important' },
|
|
212
245
|
'.MuiOutlinedInput-notchedOutline': { borderColor: 'divider' },
|
|
213
|
-
}, 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)
|
|
246
|
+
}, children: pageSizeOptions.map((opt) => (jsx(MenuItem, { value: opt, sx: { fontSize: fs - 1 }, children: opt.toLocaleString() }, opt))) })] }), jsx(Typography, { sx: { fontSize: fs, textAlign: isStacked ? 'center' : 'left' }, color: "text.secondary", noWrap: true, children: isLoading || (isFetching && totalRecords === 0)
|
|
214
247
|
? 'Loading…'
|
|
215
248
|
: totalRecords === 0
|
|
216
249
|
? 'No records'
|
|
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: {
|
|
250
|
+
: `${startRow.toLocaleString()}–${endRow.toLocaleString()} of ${totalRecords.toLocaleString()}` }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: isStacked ? 'center' : 'flex-start', 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: {
|
|
218
251
|
mx: 0.5,
|
|
219
252
|
minWidth: density.footerMinHeight - 12,
|
|
220
253
|
height: density.footerMinHeight - 12,
|
|
@@ -224,13 +257,29 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
|
|
|
224
257
|
}, 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 } }) }) }) })] })] }));
|
|
225
258
|
};
|
|
226
259
|
// ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
|
|
227
|
-
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity
|
|
228
|
-
|
|
260
|
+
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity, uiDensityOptions, responsiveBreakpoints, disableResponsive = false, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = false, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
261
|
+
// ── Responsive tier detection ────────────────────────────────────────────────
|
|
262
|
+
// Three tiers (desktop / tablet / mobile) drive auto density, a progressively
|
|
263
|
+
// lower filter-chip cap, toolbar wrapping, and a stacked pagination footer —
|
|
264
|
+
// unless the consumer opts out via `disableResponsive` or pins `uiDensity`
|
|
265
|
+
// explicitly (density only).
|
|
266
|
+
const tier = useResponsiveTier(responsiveBreakpoints?.tablet ?? 1024, responsiveBreakpoints?.mobile ?? 640, !disableResponsive);
|
|
267
|
+
const isNarrow = tier !== 'desktop'; // tablet or mobile — density, toolbar wrap
|
|
268
|
+
const isMobileTier = tier === 'mobile'; // mobile only — footer stacking, tightest chip cap
|
|
269
|
+
const resolvedUiDensity = uiDensity ?? (isNarrow ? 'compact' : 'default');
|
|
270
|
+
const effectiveMaxVisibleFilters = disableResponsive
|
|
271
|
+
? maxVisibleFilters
|
|
272
|
+
: tier === 'mobile'
|
|
273
|
+
? Math.min(maxVisibleFilters, 2)
|
|
274
|
+
: tier === 'tablet'
|
|
275
|
+
? Math.min(maxVisibleFilters, 3)
|
|
276
|
+
: maxVisibleFilters;
|
|
277
|
+
const densityTokens = useMemo(() => ({ ...UI_DENSITY_PRESETS[resolvedUiDensity], ...uiDensityOptions }), [resolvedUiDensity, uiDensityOptions]);
|
|
229
278
|
const resolvedGridId = gridId ?? exportFilename;
|
|
230
|
-
const resolvedHeaderMinHeight = toCssSize(headerMinHeight,
|
|
231
|
-
const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight,
|
|
232
|
-
const resolvedHeaderFontSize = toCssSize(headerFontSize ?? densityTokens.headerFontSize,
|
|
233
|
-
const resolvedBodyFontSize = toCssSize(bodyFontSize ?? densityTokens.bodyFontSize,
|
|
279
|
+
const resolvedHeaderMinHeight = toCssSize(headerMinHeight, resolvedUiDensity === 'compact' ? '34px' : '40px');
|
|
280
|
+
const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight, resolvedUiDensity === 'compact' ? '56px' : '72px');
|
|
281
|
+
const resolvedHeaderFontSize = toCssSize(headerFontSize ?? densityTokens.headerFontSize, resolvedUiDensity === 'compact' ? '11px' : '12px');
|
|
282
|
+
const resolvedBodyFontSize = toCssSize(bodyFontSize ?? densityTokens.bodyFontSize, resolvedUiDensity === 'compact' ? '11px' : '12px');
|
|
234
283
|
const tableStyleOverrides = useMemo(() => ({
|
|
235
284
|
// Static rules folded in here so the whole object comes from one useMemo
|
|
236
285
|
// and GlobalStyles receives a stable reference unless these props change.
|
|
@@ -239,6 +288,17 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
239
288
|
'.tp-gpg-root button[aria-label="Move"]': { display: 'none !important' },
|
|
240
289
|
'.tp-gpg-root [data-column-id="mrt-row-spacer"]': { display: 'none !important' },
|
|
241
290
|
'.tp-gpg-root .Mui-TableHeadCell-ColumnSpacer': { display: 'none !important' },
|
|
291
|
+
// Visible horizontal scrollbar — touch devices (iOS) hide scrollbars by
|
|
292
|
+
// default, leaving no affordance that a horizontally-overflowing table
|
|
293
|
+
// (common on narrow viewports) can be scrolled.
|
|
294
|
+
'.tp-gpg-root .MuiTableContainer-root::-webkit-scrollbar': {
|
|
295
|
+
height: 6,
|
|
296
|
+
width: 6,
|
|
297
|
+
},
|
|
298
|
+
'.tp-gpg-root .MuiTableContainer-root::-webkit-scrollbar-thumb': {
|
|
299
|
+
backgroundColor: 'rgba(0,0,0,0.25)',
|
|
300
|
+
borderRadius: 4,
|
|
301
|
+
},
|
|
242
302
|
...buildHeaderGlobalStyles(resolvedHeaderMinHeight, resolvedHeaderMaxHeight, resolvedHeaderFontSize, headerBgColor),
|
|
243
303
|
...buildBodyGlobalStyles(resolvedBodyFontSize),
|
|
244
304
|
}), [
|
|
@@ -407,10 +467,15 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
407
467
|
const handleToggleFilter = useCallback((id) => setVisibleFilterIds((prev) => {
|
|
408
468
|
if (prev.includes(id))
|
|
409
469
|
return prev.filter((v) => v !== id); // always allow remove
|
|
410
|
-
if (prev.length >=
|
|
470
|
+
if (prev.length >= effectiveMaxVisibleFilters)
|
|
411
471
|
return prev; // cap reached — ignore add
|
|
412
472
|
return [...prev, id];
|
|
413
|
-
}), [
|
|
473
|
+
}), [effectiveMaxVisibleFilters]);
|
|
474
|
+
// Trim already-visible chips down to the new cap when the viewport narrows
|
|
475
|
+
// (e.g. resizing from desktop to mobile with 4 chips already shown).
|
|
476
|
+
useEffect(() => {
|
|
477
|
+
setVisibleFilterIds((prev) => prev.length > effectiveMaxVisibleFilters ? prev.slice(0, effectiveMaxVisibleFilters) : prev);
|
|
478
|
+
}, [effectiveMaxVisibleFilters]);
|
|
414
479
|
const handleClearAll = useCallback(() => {
|
|
415
480
|
setFilterValues(defaultFilters);
|
|
416
481
|
setColumnFilters([]);
|
|
@@ -418,7 +483,10 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
418
483
|
setGlobalFilter('');
|
|
419
484
|
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
420
485
|
}, [defaultFilters, defaultVisible]);
|
|
421
|
-
const handleExport = useCallback(() => {
|
|
486
|
+
const handleExport = useCallback(async () => {
|
|
487
|
+
// Loaded on demand (and cached) so the xlsx-js-style library is excluded
|
|
488
|
+
// from the initial bundle for consumers who never click Export.
|
|
489
|
+
const XLSX = await getXLSX();
|
|
422
490
|
const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey);
|
|
423
491
|
// xlsx-js-style requires 8-char ARGB (AA + RRGGBB). Prepend full-opacity "FF".
|
|
424
492
|
const toArgb = (hex, fallback = 'FF1565C0') => hex?.startsWith('#') ? 'FF' + hex.slice(1).toUpperCase().padEnd(6, '0') : fallback;
|
|
@@ -516,15 +584,20 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
516
584
|
// ── Memoized toolbar render functions ─────────────────────────────────────
|
|
517
585
|
// Defined with useCallback so MRT receives stable references and does not
|
|
518
586
|
// re-render the toolbar on every isFetching / data update cycle.
|
|
519
|
-
const renderTopToolbarCustomActions = useCallback(() => (jsxs(Box, { sx: {
|
|
520
|
-
|
|
587
|
+
const renderTopToolbarCustomActions = useCallback(() => (jsxs(Box, { sx: {
|
|
588
|
+
display: 'flex',
|
|
589
|
+
alignItems: 'center',
|
|
590
|
+
flexWrap: isNarrow ? 'wrap' : 'nowrap',
|
|
591
|
+
flex: 1, minWidth: 0, pr: 1, gap: 0.5,
|
|
592
|
+
}, 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: resolvedUiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(RefreshIcon, { sx: { fontSize: resolvedUiDensity === '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: resolvedUiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: resolvedUiDensity === 'compact' ? 18 : 20 } }) }) }) })] }), jsx(Box, { sx: { flex: 1, minWidth: isNarrow ? '100%' : 0 }, children: jsx(DynamicFilterBar, { serverFilterDefs: serverFilterDefs, visibleFilterIds: visibleFilterIds, onToggleFilter: handleToggleFilter, filterValues: filterValues, onFilterValuesChange: handleFilterValuesChange, columnFilters: columnFilters, onColumnFilterChange: setColumnFilters, availableColumns: availableColumns, maxVisibleFilters: effectiveMaxVisibleFilters, uiDensity: resolvedUiDensity, filterChipFontSize: densityTokens.filterChipFontSize, filterChipMinHeight: densityTokens.filterChipMinHeight, filterLabelFontSize: densityTokens.filterLabelFontSize, gridId: resolvedGridId }) })] })), [
|
|
593
|
+
resolvedGridId, isFetching, rows.length, resolvedUiDensity, isNarrow,
|
|
521
594
|
handleClearAll, refetch, handleExport,
|
|
522
595
|
serverFilterDefs, visibleFilterIds, handleToggleFilter,
|
|
523
596
|
filterValues, handleFilterValuesChange, columnFilters, setColumnFilters,
|
|
524
|
-
availableColumns,
|
|
597
|
+
availableColumns, effectiveMaxVisibleFilters, densityTokens, handleToggleFilter,
|
|
525
598
|
]);
|
|
526
599
|
const renderToolbarInternalActions = useCallback(({ 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` })] })), [resolvedGridId]);
|
|
527
|
-
const renderBottomToolbar = useCallback(({ 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 })), [totalRecords, isFetching, isLoading, pageSizeOptions, densityTokens, resolvedGridId]);
|
|
600
|
+
const renderBottomToolbar = useCallback(({ 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, isStacked: isMobileTier })), [totalRecords, isFetching, isLoading, pageSizeOptions, densityTokens, resolvedGridId, isMobileTier]);
|
|
528
601
|
// ── Table instance ─────────────────────────────────────────────────────────
|
|
529
602
|
const table = useMaterialReactTable({
|
|
530
603
|
columns: processedColumns,
|
|
@@ -621,6 +694,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
621
694
|
minHeight: 0,
|
|
622
695
|
maxHeight: '100%',
|
|
623
696
|
overflow: 'auto',
|
|
697
|
+
WebkitOverflowScrolling: 'touch',
|
|
624
698
|
},
|
|
625
699
|
},
|
|
626
700
|
muiTablePaperProps: {
|
|
@@ -636,10 +710,10 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
636
710
|
muiTopToolbarProps: {
|
|
637
711
|
sx: {
|
|
638
712
|
alignItems: 'center',
|
|
639
|
-
flexWrap: 'nowrap',
|
|
713
|
+
flexWrap: isNarrow ? 'wrap' : 'nowrap',
|
|
640
714
|
minHeight: densityTokens.filterChipMinHeight + 12,
|
|
641
|
-
py:
|
|
642
|
-
'& .MuiIconButton-root': { p:
|
|
715
|
+
py: resolvedUiDensity === 'compact' ? 0.25 : 0.5,
|
|
716
|
+
'& .MuiIconButton-root': { p: resolvedUiDensity === 'compact' ? 0.35 : 0.5 },
|
|
643
717
|
'& .MuiIconButton-root svg': { fontSize: densityTokens.toolbarIconFontSize === 'small' ? 18 : 20 },
|
|
644
718
|
},
|
|
645
719
|
},
|
|
@@ -650,7 +724,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
650
724
|
size: 'small',
|
|
651
725
|
variant: 'outlined',
|
|
652
726
|
sx: {
|
|
653
|
-
minWidth:
|
|
727
|
+
minWidth: resolvedUiDensity === 'compact' ? 160 : 200,
|
|
654
728
|
'& .MuiOutlinedInput-root': {
|
|
655
729
|
height: densityTokens.filterChipMinHeight,
|
|
656
730
|
fontSize: densityTokens.filterChipFontSize,
|
|
@@ -700,7 +774,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
700
774
|
display: 'flex',
|
|
701
775
|
flexDirection: 'column',
|
|
702
776
|
overflow: 'hidden',
|
|
703
|
-
}, children: [jsx(GlobalStyles, { styles: tableStyleOverrides }), isLoading && jsx(
|
|
777
|
+
}, children: [jsx(GlobalStyles, { styles: tableStyleOverrides }), isLoading && jsx(SkeletonOverlay, { columnCount: processedColumns.length }), !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 }) })] }));
|
|
704
778
|
}
|
|
705
779
|
|
|
706
780
|
export { GenericPaginatedGrid as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateInput } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateInput } 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
|
import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as Month } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as Month } 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 requireDayCell } from '../DayCell/index.esm.js';
|