tp-react-elements 2.0.2 → 2.0.3
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 +3 -1
- package/dist/_virtual/index.esm12.js +2 -2
- package/dist/_virtual/index.esm13.js +2 -2
- package/dist/_virtual/index.esm14.js +2 -2
- package/dist/_virtual/index.esm5.js +2 -2
- package/dist/_virtual/index.esm6.js +2 -2
- package/dist/_virtual/index.esm7.js +2 -2
- package/dist/components/FormComponents/Select/MultiSelect.d.ts +10 -0
- package/dist/components/PaginatedGrid/DynamicFilterBar.d.ts +12 -2
- package/dist/components/PaginatedGrid/DynamicFilterBar.esm.js +42 -6
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +8 -1
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +57 -14
- package/dist/components/PaginatedGrid/mockData.d.ts +9 -1
- package/dist/components/PaginatedGrid/types.d.ts +0 -17
- package/dist/node_modules/react-date-range/dist/components/Calendar/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRangePicker/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/Month/index.esm.js +1 -1
- package/package.json +1 -1
- package/dist/components/PaginatedGrid/invoiceApi.d.ts +0 -2
package/README.md
CHANGED
|
@@ -203,7 +203,9 @@ npm run storybook
|
|
|
203
203
|
|
|
204
204
|
- **Docs → Paginated Grid** — API reference plus **four copy-paste examples** (embedded panel, wrapped headers, typography, invoice filters)
|
|
205
205
|
- **Components → PaginatedGrid → Sample Grids** — mock grids (no API): header wrap, compact layout, viewport fill
|
|
206
|
-
- **Components → PaginatedGrid → Example Grid** —
|
|
206
|
+
- **Components → PaginatedGrid → Example Grid** — invoice grid demo using mock data (no API)
|
|
207
|
+
|
|
208
|
+
**Global Search:** every `GenericPaginatedGrid` includes a built-in search icon in the top-right toolbar (next to Show/Hide Columns, Density, and Fullscreen) — no extra props needed. Click it to expand a free-text search that filters across all visible columns of the current batch. See **Docs → Paginated Grid → Global search**.
|
|
207
209
|
|
|
208
210
|
**Example — compact embedded grid with smaller fonts:**
|
|
209
211
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var InputRangeField = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { InputRangeField as __exports };
|
|
@@ -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 };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DateRangePicker = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DateRangePicker as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var DefinedRange = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { DefinedRange as __exports };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var Calendar = {};
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { Calendar as __exports };
|
|
@@ -1,2 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MultiSelect` is currently a stub placeholder pending activation.
|
|
3
|
+
*
|
|
4
|
+
* Use one of these fully-implemented alternatives instead:
|
|
5
|
+
* - `MultiSelectAutocomplete` (react-hook-form aware) — Docs → Multi Select Autocomplete
|
|
6
|
+
* - `MultiSelectField` (standalone) — Docs → Multi Select Field
|
|
7
|
+
* - `MultiSelectV1` (react-hook-form aware, used via FormRender `inputType: 'multiselect'`)
|
|
8
|
+
*
|
|
9
|
+
* See Docs → Multi Select (docs/multi-select.mdx) for status details.
|
|
10
|
+
*/
|
|
1
11
|
declare const MultiSelect: () => import("react/jsx-runtime").JSX.Element;
|
|
2
12
|
export default MultiSelect;
|
|
@@ -127,6 +127,16 @@ export interface DynamicFilterBarProps {
|
|
|
127
127
|
filterChipFontSize?: number;
|
|
128
128
|
filterChipMinHeight?: number;
|
|
129
129
|
filterLabelFontSize?: number;
|
|
130
|
+
/**
|
|
131
|
+
* Current value of MRT's global filter (free-text search across every
|
|
132
|
+
* visible column). When provided together with `onGlobalFilterChange`, a
|
|
133
|
+
* search box is rendered next to "Manage Filters".
|
|
134
|
+
*/
|
|
135
|
+
globalFilter?: string;
|
|
136
|
+
/** Called (debounced) as the user types in the global search box. */
|
|
137
|
+
onGlobalFilterChange?: (value: string) => void;
|
|
138
|
+
/** Placeholder text for the global search box. Default: "Search…". */
|
|
139
|
+
globalSearchPlaceholder?: string;
|
|
130
140
|
}
|
|
131
|
-
declare const
|
|
132
|
-
export default
|
|
141
|
+
declare const _default: import("react").MemoExoticComponent<({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, uiDensity, filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element>;
|
|
142
|
+
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { memo, useState, useEffect } from 'react';
|
|
3
3
|
import { useForm } from 'react-hook-form';
|
|
4
4
|
import dayjs from 'dayjs';
|
|
5
5
|
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
@@ -9,7 +9,7 @@ import { DatePicker } from '@mui/x-date-pickers/DatePicker';
|
|
|
9
9
|
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
|
|
10
10
|
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
|
11
11
|
import SingleSelectNonAutoComplete from '../FormComponents/Select/SingleSelectNonAutoComplete.esm.js';
|
|
12
|
-
import { Box, Typography, Tooltip, Button, Popover,
|
|
12
|
+
import { TextField, InputAdornment, IconButton, Box, Typography, Tooltip, Button, Popover, Stack, List, ListItemButton, ListItemText, Checkbox, Divider } from '@mui/material';
|
|
13
13
|
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
|
|
14
14
|
import TuneIcon from '@mui/icons-material/Tune';
|
|
15
15
|
import CloseIcon from '@mui/icons-material/Close';
|
|
@@ -281,6 +281,41 @@ const MultiSelectFilterChip = ({ label, selectedValues, options, onApply, onRemo
|
|
|
281
281
|
} })] }, opt.value));
|
|
282
282
|
}) })] })] }));
|
|
283
283
|
};
|
|
284
|
+
const GlobalSearchInput = memo(({ value, onChange, chipStyle, placeholder = 'Search…' }) => {
|
|
285
|
+
const [draft, setDraft] = useState(value);
|
|
286
|
+
// Keep local draft in sync when the external value changes elsewhere
|
|
287
|
+
// (e.g. "Clear filters & refresh" resets globalFilter to '').
|
|
288
|
+
useEffect(() => {
|
|
289
|
+
setDraft(value);
|
|
290
|
+
}, [value]);
|
|
291
|
+
// Debounce: push to parent (and trigger MRT's global filter) 250ms after typing stops.
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
if (draft === value)
|
|
294
|
+
return;
|
|
295
|
+
const handle = setTimeout(() => onChange(draft), 250);
|
|
296
|
+
return () => clearTimeout(handle);
|
|
297
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
298
|
+
}, [draft]);
|
|
299
|
+
const handleClear = () => {
|
|
300
|
+
setDraft('');
|
|
301
|
+
onChange('');
|
|
302
|
+
};
|
|
303
|
+
return (jsx(TextField, { value: draft, onChange: (e) => setDraft(e.target.value), placeholder: placeholder, size: "small", variant: "outlined", "aria-label": "Search all columns", InputProps: {
|
|
304
|
+
startAdornment: (jsx(InputAdornment, { position: "start", children: jsx(SearchIcon, { sx: { fontSize: 16, color: 'text.disabled' } }) })),
|
|
305
|
+
endAdornment: draft ? (jsx(InputAdornment, { position: "end", children: jsx(IconButton, { size: "small", onClick: handleClear, "aria-label": "Clear search", sx: { p: 0.25 }, children: jsx(CloseIcon, { sx: { fontSize: '14px !important' } }) }) })) : undefined,
|
|
306
|
+
}, sx: {
|
|
307
|
+
minWidth: 160,
|
|
308
|
+
maxWidth: 220,
|
|
309
|
+
flexShrink: 0,
|
|
310
|
+
'& .MuiOutlinedInput-root': {
|
|
311
|
+
borderRadius: 5,
|
|
312
|
+
fontSize: chipStyle.fontSize,
|
|
313
|
+
height: chipStyle.minHeight,
|
|
314
|
+
},
|
|
315
|
+
'& .MuiOutlinedInput-input': { py: 0 },
|
|
316
|
+
} }));
|
|
317
|
+
});
|
|
318
|
+
GlobalSearchInput.displayName = 'GlobalSearchInput';
|
|
284
319
|
const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, onToggle, maxVisible = 4, chipStyle, }) => {
|
|
285
320
|
const [anchor, setAnchor] = useState(null);
|
|
286
321
|
const atLimit = visibleIds.length >= maxVisible;
|
|
@@ -327,7 +362,7 @@ const ManageFiltersButton = ({ serverFilterDefs, visibleIds, availableColumns, o
|
|
|
327
362
|
} }), selected && jsx(CheckIcon, { sx: { fontSize: 16, color: 'primary.main', flexShrink: 0 } })] }) }) }, col.id));
|
|
328
363
|
}) })] }))] })] })] }));
|
|
329
364
|
};
|
|
330
|
-
const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, uiDensity = 'default', filterChipFontSize, filterChipMinHeight, filterLabelFontSize, }) => {
|
|
365
|
+
const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters = 4, uiDensity = 'default', filterChipFontSize, filterChipMinHeight, filterLabelFontSize, globalFilter, onGlobalFilterChange, globalSearchPlaceholder, }) => {
|
|
331
366
|
const chipStyle = {
|
|
332
367
|
fontSize: filterChipFontSize ?? (uiDensity === 'compact' ? 11 : 12),
|
|
333
368
|
minHeight: filterChipMinHeight ?? (uiDensity === 'compact' ? 26 : 30),
|
|
@@ -416,7 +451,8 @@ const DynamicFilterBar = ({ serverFilterDefs, visibleFilterIds, onToggleFilter,
|
|
|
416
451
|
}
|
|
417
452
|
// Default: free-text input
|
|
418
453
|
return (jsx(TextFilterChip, { label: col.label, value: getColValue(id), onApply: (v) => applyColFilter(id, v), onRemove: () => removeFilter(id), placeholder: `Filter by ${col.label}`, chipStyle: chipStyle }, id));
|
|
419
|
-
}), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters, chipStyle: chipStyle })] }));
|
|
454
|
+
}), jsx(ManageFiltersButton, { serverFilterDefs: serverFilterDefs, visibleIds: visibleFilterIds, availableColumns: availableColumns, onToggle: onToggleFilter, maxVisible: maxVisibleFilters, chipStyle: chipStyle }), onGlobalFilterChange && (jsx(GlobalSearchInput, { value: globalFilter ?? '', onChange: onGlobalFilterChange, chipStyle: chipStyle, placeholder: globalSearchPlaceholder }))] }));
|
|
420
455
|
};
|
|
456
|
+
var DynamicFilterBar$1 = memo(DynamicFilterBar);
|
|
421
457
|
|
|
422
|
-
export { DynamicFilterBar as default };
|
|
458
|
+
export { DynamicFilterBar$1 as default };
|
|
@@ -91,6 +91,13 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
91
91
|
uiDensityOptions?: GridUiDensityOptions;
|
|
92
92
|
/** Choices shown in the "Rows per page" footer dropdown. Default: [1 000, 5 000, 10 000]. */
|
|
93
93
|
pageSizeOptions?: number[];
|
|
94
|
+
/**
|
|
95
|
+
* Show the Global Search input expanded by default (instead of requiring a
|
|
96
|
+
* click on the search icon to reveal it). The icon remains in the top-right
|
|
97
|
+
* toolbar actions and can still be used to collapse/expand the input.
|
|
98
|
+
* Default: `true`.
|
|
99
|
+
*/
|
|
100
|
+
showGlobalSearchByDefault?: boolean;
|
|
94
101
|
/**
|
|
95
102
|
* Background colour applied to every header cell.
|
|
96
103
|
* Accepts any valid CSS colour string.
|
|
@@ -185,5 +192,5 @@ export interface GenericPaginatedGridProps<TData extends object> {
|
|
|
185
192
|
*/
|
|
186
193
|
enableExpanding?: boolean;
|
|
187
194
|
}
|
|
188
|
-
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, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
195
|
+
declare function GenericPaginatedGrid<TData extends object>({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize, exportFilename, tableHeight, tableMinHeight, tableMaxHeight, autoFillViewport, layoutMode, uiDensity, uiDensityOptions, pageSizeOptions, showGlobalSearchByDefault, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding, }: GenericPaginatedGridProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
189
196
|
export default GenericPaginatedGrid;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { useMemo, useState, useRef, useLayoutEffect } from 'react';
|
|
3
|
-
import { useMaterialReactTable, MaterialReactTable } from 'material-react-table';
|
|
2
|
+
import { useMemo, useState, useRef, useLayoutEffect, useCallback } from 'react';
|
|
3
|
+
import { useMaterialReactTable, MRT_ToggleGlobalFilterButton, MRT_ShowHideColumnsButton, MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, 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';
|
|
6
6
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
@@ -221,7 +221,7 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
|
|
|
221
221
|
}, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
|
|
222
222
|
};
|
|
223
223
|
// ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
|
|
224
|
-
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
224
|
+
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = true, headerBgColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
225
225
|
const densityTokens = useMemo(() => ({ ...UI_DENSITY_PRESETS[uiDensity], ...uiDensityOptions }), [uiDensity, uiDensityOptions]);
|
|
226
226
|
const resolvedHeaderMinHeight = toCssSize(headerMinHeight, uiDensity === 'compact' ? '34px' : '40px');
|
|
227
227
|
const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight, uiDensity === 'compact' ? '56px' : '72px');
|
|
@@ -241,7 +241,11 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
241
241
|
// 1. explicit defaultVisibleFilterIds prop (override)
|
|
242
242
|
// 2. server filters + column filters that have defaultVisible: true
|
|
243
243
|
// 3. first server filter only (original fallback)
|
|
244
|
-
|
|
244
|
+
//
|
|
245
|
+
// Memoized so identity stays stable across re-renders (e.g. while
|
|
246
|
+
// `isFetching` toggles) — used as a `useCallback` dependency below and as
|
|
247
|
+
// the reset target for "Clear All".
|
|
248
|
+
const defaultVisible = useMemo(() => defaultVisibleFilterIds
|
|
245
249
|
?? (() => {
|
|
246
250
|
// Server-side chips with defaultVisible: true
|
|
247
251
|
const markedServer = serverFilterDefs
|
|
@@ -266,7 +270,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
266
270
|
return marked.length > 0
|
|
267
271
|
? marked
|
|
268
272
|
: serverFilterDefs.length > 0 ? [serverFilterDefs[0].id] : [];
|
|
269
|
-
})();
|
|
273
|
+
})(), [defaultVisibleFilterIds, serverFilterDefs, columns]);
|
|
270
274
|
// ── State ──────────────────────────────────────────────────────────────────
|
|
271
275
|
const [filterValues, setFilterValues] = useState(defaultFilters);
|
|
272
276
|
const [visibleFilterIds, setVisibleFilterIds] = useState(defaultVisible);
|
|
@@ -382,24 +386,28 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
382
386
|
}));
|
|
383
387
|
}, [columns, serverFilterDefs]);
|
|
384
388
|
// ── Handlers ───────────────────────────────────────────────────────────────
|
|
385
|
-
|
|
389
|
+
// Wrapped in useCallback so stable references can be passed down to the
|
|
390
|
+
// memoized DynamicFilterBar/chip components without forcing re-renders on
|
|
391
|
+
// every parent render (e.g. while `isFetching` toggles).
|
|
392
|
+
const handleFilterValuesChange = useCallback((newValues) => {
|
|
386
393
|
setFilterValues(newValues);
|
|
387
394
|
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
388
|
-
};
|
|
389
|
-
const handleToggleFilter = (id) => setVisibleFilterIds((prev) => {
|
|
395
|
+
}, []);
|
|
396
|
+
const handleToggleFilter = useCallback((id) => setVisibleFilterIds((prev) => {
|
|
390
397
|
if (prev.includes(id))
|
|
391
398
|
return prev.filter((v) => v !== id); // always allow remove
|
|
392
399
|
if (prev.length >= maxVisibleFilters)
|
|
393
400
|
return prev; // cap reached — ignore add
|
|
394
401
|
return [...prev, id];
|
|
395
|
-
});
|
|
396
|
-
const handleClearAll = () => {
|
|
402
|
+
}), [maxVisibleFilters]);
|
|
403
|
+
const handleClearAll = useCallback(() => {
|
|
397
404
|
setFilterValues(defaultFilters);
|
|
398
405
|
setColumnFilters([]);
|
|
399
406
|
setVisibleFilterIds(defaultVisible);
|
|
407
|
+
setGlobalFilter('');
|
|
400
408
|
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
401
|
-
};
|
|
402
|
-
const handleExport = () => {
|
|
409
|
+
}, [defaultFilters, defaultVisible]);
|
|
410
|
+
const handleExport = useCallback(() => {
|
|
403
411
|
const headers = columns.map((c) => c.header).join(',');
|
|
404
412
|
const csvRows = rows.map((row) => columns
|
|
405
413
|
.map((c) => {
|
|
@@ -415,7 +423,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
415
423
|
a.download = `${exportFilename}-page${pagination.pageIndex + 1}.csv`;
|
|
416
424
|
a.click();
|
|
417
425
|
URL.revokeObjectURL(url);
|
|
418
|
-
};
|
|
426
|
+
}, [columns, rows, exportFilename, pagination.pageIndex]);
|
|
419
427
|
// ── Table instance ─────────────────────────────────────────────────────────
|
|
420
428
|
const table = useMaterialReactTable({
|
|
421
429
|
columns: processedColumns,
|
|
@@ -484,7 +492,15 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
484
492
|
columnResizeMode: 'onChange',
|
|
485
493
|
enableExpanding,
|
|
486
494
|
renderDetailPanel,
|
|
487
|
-
|
|
495
|
+
// Note: `enableFilters` is the master switch for column AND global
|
|
496
|
+
// filtering. Keep it enabled so the Global Search box (which relies on
|
|
497
|
+
// `getCanGlobalFilter()`) actually filters rows. MRT's native per-column
|
|
498
|
+
// filter inputs are hidden separately via `enableColumnFilters: false` —
|
|
499
|
+
// column-level filtering still works because DynamicFilterBar's chips
|
|
500
|
+
// operate on `columnFilters` state directly (column.getFilterFn() is
|
|
501
|
+
// used regardless of this flag).
|
|
502
|
+
enableFilters: true,
|
|
503
|
+
enableColumnFilters: false,
|
|
488
504
|
enableGlobalFilter: true,
|
|
489
505
|
enableDensityToggle: true,
|
|
490
506
|
enableFullScreenToggle: true,
|
|
@@ -493,6 +509,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
493
509
|
enableRowVirtualization: true,
|
|
494
510
|
initialState: {
|
|
495
511
|
density: densityTokens.mrtDensity,
|
|
512
|
+
showGlobalFilter: showGlobalSearchByDefault,
|
|
496
513
|
},
|
|
497
514
|
muiTableProps: {
|
|
498
515
|
sx: { width: '100%' },
|
|
@@ -525,6 +542,27 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
525
542
|
'& .MuiIconButton-root svg': { fontSize: densityTokens.toolbarIconFontSize === 'small' ? 18 : 20 },
|
|
526
543
|
},
|
|
527
544
|
},
|
|
545
|
+
// Align the Global Search field's icon/size with the other toolbar
|
|
546
|
+
// icons (Show/Hide Columns, Density, Fullscreen) so it blends in
|
|
547
|
+
// instead of appearing oversized.
|
|
548
|
+
muiSearchTextFieldProps: {
|
|
549
|
+
size: 'small',
|
|
550
|
+
variant: 'outlined',
|
|
551
|
+
sx: {
|
|
552
|
+
minWidth: uiDensity === 'compact' ? 160 : 200,
|
|
553
|
+
'& .MuiOutlinedInput-root': {
|
|
554
|
+
height: densityTokens.filterChipMinHeight,
|
|
555
|
+
fontSize: densityTokens.filterChipFontSize,
|
|
556
|
+
},
|
|
557
|
+
// The leading search icon is rendered as a plain <SearchIcon />
|
|
558
|
+
// direct child of the input (not inside an IconButton), so size it
|
|
559
|
+
// to match the other top-toolbar action icons. The trailing clear
|
|
560
|
+
// (×) icon is inside an IconButton/InputAdornment.
|
|
561
|
+
'& .MuiOutlinedInput-root > .MuiSvgIcon-root, & .MuiInputAdornment-root .MuiSvgIcon-root': {
|
|
562
|
+
fontSize: densityTokens.toolbarIconFontSize === 'small' ? 18 : 20,
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
},
|
|
528
566
|
muiTableHeadProps: {
|
|
529
567
|
sx: {
|
|
530
568
|
position: 'sticky',
|
|
@@ -599,6 +637,11 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
599
637
|
? { color: 'error', children: 'Failed to load data. Please try again.' }
|
|
600
638
|
: undefined,
|
|
601
639
|
renderTopToolbarCustomActions: () => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0, pr: 1, gap: 0.5 }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flexShrink: 0, gap: 0.25 }, children: [jsx(Tooltip, { title: "Clear filters & refresh", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: () => { handleClearAll(); refetch(); }, disabled: isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(RefreshIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) }), jsx(Tooltip, { title: "Export batch as CSV", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: handleExport, disabled: rows.length === 0 || isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) })] }), jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: jsx(DynamicFilterBar, { serverFilterDefs: serverFilterDefs, visibleFilterIds: visibleFilterIds, onToggleFilter: handleToggleFilter, filterValues: filterValues, onFilterValuesChange: handleFilterValuesChange, columnFilters: columnFilters, onColumnFilterChange: setColumnFilters, availableColumns: availableColumns, maxVisibleFilters: maxVisibleFilters, uiDensity: uiDensity, filterChipFontSize: densityTokens.filterChipFontSize, filterChipMinHeight: densityTokens.filterChipMinHeight, filterLabelFontSize: densityTokens.filterLabelFontSize }) })] })),
|
|
640
|
+
// Single global search control: MRT's built-in search icon/input in the
|
|
641
|
+
// top-right toolbar actions. The inline search box next to "Manage
|
|
642
|
+
// Filters" is intentionally not rendered (see renderTopToolbarCustomActions)
|
|
643
|
+
// to avoid showing two search controls.
|
|
644
|
+
renderToolbarInternalActions: ({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t }), jsx(MRT_ShowHideColumnsButton, { table: t }), jsx(MRT_ToggleDensePaddingButton, { table: t }), jsx(MRT_ToggleFullScreenButton, { table: t })] })),
|
|
602
645
|
renderBottomToolbar: ({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: pageSizeOptions, density: densityTokens })),
|
|
603
646
|
});
|
|
604
647
|
return (jsxs(Box, { ref: containerRef, className: "tp-gpg-root", sx: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Mock data + fetch adapters for Storybook sample grids (no API required).
|
|
3
3
|
*/
|
|
4
|
-
import type { TPColumnDef } from './types';
|
|
4
|
+
import type { TPColumnDef, InvoiceDetail } from './types';
|
|
5
5
|
import type { PagedResult } from './GenericPaginatedGrid';
|
|
6
6
|
import type { ServerFilterDef } from './DynamicFilterBar';
|
|
7
7
|
export interface EmployeeRow {
|
|
@@ -54,6 +54,14 @@ export declare const orderColumns: TPColumnDef<OrderRow>[];
|
|
|
54
54
|
export declare const orderFilterDefs: ServerFilterDef[];
|
|
55
55
|
export declare const orderDefaultFilters: Record<string, string>;
|
|
56
56
|
export declare function fetchOrderPage(filters: Record<string, string>, pageIndex: number, pageSize?: number): Promise<PagedResult<OrderRow>>;
|
|
57
|
+
/**
|
|
58
|
+
* Mock `fetchPage` adapter for `InvoiceGrid` — pure in-memory data, no API
|
|
59
|
+
* calls. Filters the `ALL_INVOICES` array using the same filter keys
|
|
60
|
+
* (`FromDate`, `ToDate`, `Division`, `Customer`, `DC`, `ProductCode`) that the
|
|
61
|
+
* server filter chips already produce, so `InvoiceGrid.tsx` and its Storybook
|
|
62
|
+
* stories work unchanged.
|
|
63
|
+
*/
|
|
64
|
+
export declare function fetchInvoicePage(filters: Record<string, string>, pageIndex: number, pageSize?: number): Promise<PagedResult<InvoiceDetail>>;
|
|
57
65
|
export interface OrderLineItem {
|
|
58
66
|
itemId: number;
|
|
59
67
|
productCode: string;
|
|
@@ -107,20 +107,3 @@ export interface InvoiceDetail {
|
|
|
107
107
|
changeddate: string;
|
|
108
108
|
SHIP_TO_PARTY: string;
|
|
109
109
|
}
|
|
110
|
-
export interface InvoiceRequest {
|
|
111
|
-
FromDate: string;
|
|
112
|
-
ToDate: string;
|
|
113
|
-
Division: string;
|
|
114
|
-
Customer: string;
|
|
115
|
-
DC: string;
|
|
116
|
-
ProductCode: string;
|
|
117
|
-
PageNumber: number;
|
|
118
|
-
}
|
|
119
|
-
export interface InvoiceApiResponse {
|
|
120
|
-
PageNumber: number;
|
|
121
|
-
PageSize: number;
|
|
122
|
-
TotalRecords: number;
|
|
123
|
-
TotalPages: number;
|
|
124
|
-
HasNextPage: boolean;
|
|
125
|
-
Data: InvoiceDetail[];
|
|
126
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as Calendar } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as Calendar } 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 requireDayCell } from '../DayCell/index.esm.js';
|
|
@@ -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 DateRangePicker } from '../../../../../_virtual/index.
|
|
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.
|
|
1
|
+
import { __exports as DefinedRange } 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 requireStyles } from '../../styles.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as InputRangeField } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as InputRangeField } 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
|
|
|
@@ -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';
|
package/package.json
CHANGED