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 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** — live invoice API demo
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 Month = {};
1
+ var InputRangeField = {};
2
2
 
3
- export { Month as __exports };
3
+ export { InputRangeField as __exports };
@@ -1,3 +1,3 @@
1
- var DateInput = {};
1
+ var Month = {};
2
2
 
3
- export { DateInput as __exports };
3
+ export { Month as __exports };
@@ -1,3 +1,3 @@
1
- var InputRangeField = {};
1
+ var DateInput = {};
2
2
 
3
- export { InputRangeField as __exports };
3
+ export { DateInput as __exports };
@@ -1,3 +1,3 @@
1
- var Calendar = {};
1
+ var DateRangePicker = {};
2
2
 
3
- export { Calendar as __exports };
3
+ export { DateRangePicker as __exports };
@@ -1,3 +1,3 @@
1
- var DateRangePicker = {};
1
+ var DefinedRange = {};
2
2
 
3
- export { DateRangePicker as __exports };
3
+ export { DefinedRange as __exports };
@@ -1,3 +1,3 @@
1
- var DefinedRange = {};
1
+ var Calendar = {};
2
2
 
3
- export { DefinedRange as __exports };
3
+ export { Calendar as __exports };
@@ -1,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 DynamicFilterBar: ({ serverFilterDefs, visibleFilterIds, onToggleFilter, filterValues, onFilterValuesChange, columnFilters, onColumnFilterChange, availableColumns, maxVisibleFilters, uiDensity, filterChipFontSize, filterChipMinHeight, filterLabelFontSize, }: DynamicFilterBarProps) => import("react/jsx-runtime").JSX.Element;
132
- export default DynamicFilterBar;
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 { jsxs, jsx, Fragment } from 'react/jsx-runtime';
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, TextField, Stack, InputAdornment, List, ListItemButton, ListItemText, Checkbox, Divider } from '@mui/material';
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
- const defaultVisible = defaultVisibleFilterIds
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
- const handleFilterValuesChange = (newValues) => {
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
- enableFilters: false,
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.esm5.js';
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.esm13.js';
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.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.esm7.js';
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.esm14.js';
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.esm12.js';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tp-react-elements",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",
@@ -1,2 +0,0 @@
1
- import type { InvoiceRequest, InvoiceApiResponse } from './types';
2
- export declare const fetchInvoiceDetails: (request: InvoiceRequest) => Promise<InvoiceApiResponse>;