tp-react-elements 3.0.1 → 3.0.2

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.
@@ -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 DateRangePicker = {};
2
2
 
3
- export { DefinedRange as __exports };
3
+ export { DateRangePicker as __exports };
@@ -1,6 +1,13 @@
1
1
  import { jsx, Fragment } from 'react/jsx-runtime';
2
2
  import require$$0__default, { lazy, Suspense } from 'react';
3
+ import FormCheckBox from '../FormComponents/FormCheckBox/FormCheckBox.esm.js';
3
4
  import FormCheckBoxGroup from '../FormComponents/FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
5
+ import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
6
+ import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
7
+ import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
8
+ import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
9
+ import FormTextField from '../FormComponents/FormTextField/FormTextField.esm.js';
10
+ import PasswordField from '../FormComponents/PasswordField/PasswordField.esm.js';
4
11
  import SingleSelect from '../FormComponents/Select/SingleSelect.esm.js';
5
12
  import MultiSelectAutocomplete from '../FormComponents/Select/MultiSelectAutocomplete.esm.js';
6
13
  import SingleSelectNonAutoComplete from '../FormComponents/Select/SingleSelectNonAutoComplete.esm.js';
@@ -11,13 +18,6 @@ import DateRangePickerComponent from '../DateRangePicker/DateRangePicker.esm.js'
11
18
  import RichTextEditorWrapper from '../FormComponents/RichTextEditor/RichTextEditorWrapper.esm.js';
12
19
  import SingleSelectSearchApi from '../FormComponents/Select/SingleSelectSearchApi.esm.js';
13
20
  import DatetimepickerWrapper from '../FormComponents/DatePicker/DatetimepickerWrapper.esm.js';
14
- import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
15
- import FormCheckBox from '../FormComponents/FormCheckBox/FormCheckBox.esm.js';
16
- import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
17
- import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
18
- import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
19
- import PasswordField from '../FormComponents/PasswordField/PasswordField.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,3 +1,9 @@
1
+ export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
2
+ export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
3
+ export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
4
+ export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
5
+ export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
6
+ export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
1
7
  export { default as SingleSelect } from './Select/SingleSelect.esm.js';
2
8
  export { default as SingleSelectNonAutoComplete } from './Select/SingleSelectNonAutoComplete.esm.js';
3
9
  export { default as SingleSelectSearchApi } from './Select/SingleSelectSearchApi.esm.js';
@@ -5,6 +11,7 @@ export { default as MultiSelectV1 } from './Select/MultiSelectv1.esm.js';
5
11
  export { default as MultiSelectTable } from './Select/MultiSelectTable.esm.js';
6
12
  export { default as SearchableSelect } from './Select/SearchableSelect.esm.js';
7
13
  export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
14
+ export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
8
15
  export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
9
16
  export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
10
17
  import 'react/jsx-runtime';
@@ -17,17 +24,19 @@ import 'react-hook-form';
17
24
  export { default as FormBottomField } from './FormBottomField/FormBottomField.esm.js';
18
25
  import 'dayjs';
19
26
  export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
20
- export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
21
- export { default as HelperText } from './HelperText/HelperText.esm.js';
22
- export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
23
- export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
24
- export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
25
- export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
27
+ export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
26
28
  export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUpload.esm.js';
27
29
  export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
28
- export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
29
- export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
30
- export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
30
+ import '@mui/icons-material/Visibility';
31
+ import '@mui/icons-material/Close';
32
+ import '@mui/icons-material/NavigateBefore';
33
+ import '@mui/icons-material/NavigateNext';
34
+ import '@mui/icons-material/Delete';
35
+ import '@mui/icons-material/UploadFile';
36
+ import '@mui/icons-material/PictureAsPdf';
37
+ import '@mui/icons-material/TableChart';
38
+ import '@mui/icons-material/Description';
39
+ export { default as FormErrorField } from './FormErrorField/FormErrorField.esm.js';
40
+ export { default as HelperText } from './HelperText/HelperText.esm.js';
31
41
  export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
32
42
  export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
33
- export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
@@ -2,7 +2,7 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useMemo, useState, useRef, useLayoutEffect, useCallback, useEffect } from 'react';
3
3
  import { MRT_ToggleGlobalFilterButton, MRT_ShowHideColumnsButton, MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, useMaterialReactTable, MaterialReactTable } from 'material-react-table';
4
4
  import { useQuery, keepPreviousData } from '@tanstack/react-query';
5
- import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, Skeleton } from '@mui/material';
5
+ import { Box, Tooltip, IconButton, Menu, MenuItem, GlobalStyles, Typography, Select, Skeleton } from '@mui/material';
6
6
  import RefreshIcon from '@mui/icons-material/Refresh';
7
7
  import FileDownloadIcon from '@mui/icons-material/FileDownload';
8
8
  import FirstPageIcon from '@mui/icons-material/FirstPage';
@@ -125,6 +125,19 @@ const buildHeaderGlobalStyles = (headerMin, headerMax, headerFont, headerBgColor
125
125
  width: '100% !important',
126
126
  fontSize: `${headerFont} !important`,
127
127
  },
128
+ // Column resize handle: MRT's own default sx wins over the equivalent
129
+ // rule in buildHeaderCellSx (same CSS specificity, applied later in the
130
+ // emotion cache), leaving the drag hotspot a short ~24px strip centered
131
+ // in a much taller header cell — most of the column border is then
132
+ // unresponsive to drag. GlobalStyles + !important guarantees this wins.
133
+ '.tp-gpg-root .MuiTableHead-root .Mui-TableHeadCell-ResizeHandle-Wrapper': {
134
+ height: '100% !important',
135
+ top: '0 !important',
136
+ },
137
+ '.tp-gpg-root .MuiTableHead-root .Mui-TableHeadCell-ResizeHandle-Divider': {
138
+ height: '100% !important',
139
+ borderRight: 'none !important',
140
+ },
128
141
  };
129
142
  };
130
143
  /** Per-cell sx merged into MRT (via muiTableHeadCellProps). */
@@ -156,8 +169,6 @@ const buildHeaderCellSx = (align, headerMin, headerMax, headerFont, headerBgColo
156
169
  borderBottom: '2px solid rgba(0,0,0,0.15)',
157
170
  '& button[aria-label="Move"]': { display: 'none !important' },
158
171
  '& .MuiTableSortLabel-icon': { display: 'none !important' },
159
- '& .Mui-TableHeadCell-ResizeHandle-Wrapper': { height: '100%', top: 0 },
160
- '& .Mui-TableHeadCell-ResizeHandle-Divider': { borderRight: 'none' },
161
172
  '& .Mui-TableHeadCell-Content': {
162
173
  alignItems: 'center',
163
174
  justifyContent: flexJustify,
@@ -358,6 +369,18 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
358
369
  const [columnFilters, setColumnFilters] = useState([]);
359
370
  const [globalFilter, setGlobalFilter] = useState('');
360
371
  const [columnPinning, setColumnPinning] = useState({});
372
+ const [exportMenuAnchor, setExportMenuAnchor] = useState(null);
373
+ // Whether any column filter or Global Search is currently narrowing what's
374
+ // displayed. When true, Export offers a choice (filtered vs. complete);
375
+ // when false there's nothing to choose between, so it downloads directly.
376
+ const isFiltered = columnFilters.length > 0 || globalFilter.trim() !== '';
377
+ // Always points at the latest MRT table instance (assigned right after
378
+ // useMaterialReactTable below) so handleExport — defined earlier in this
379
+ // component body — can read the CURRENT filtered row model at click time
380
+ // without needing `table` in its own dependency array (which would create
381
+ // a circular reference, since `table`'s own options include the toolbar
382
+ // renderer that uses handleExport).
383
+ const tableRef = useRef(null);
361
384
  // ── Viewport-fill height (mount + resize only — never on scroll) ─────────────
362
385
  //
363
386
  // Previously a scroll listener recalculated height as the grid moved within the
@@ -524,17 +547,24 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
524
547
  setGlobalFilter('');
525
548
  setPagination((p) => ({ ...p, pageIndex: 0 }));
526
549
  }, [defaultFilters, defaultVisible]);
527
- const handleExport = useCallback(async () => {
550
+ const handleExport = useCallback(async (scope = 'all') => {
528
551
  // Loaded on demand (and cached) so the xlsx-js-style library is excluded
529
552
  // from the initial bundle for consumers who never click Export.
530
553
  const XLSX = await getXLSX();
554
+ // "filtered" = exactly what's currently displayed (column filters + global
555
+ // search applied) — sourced from MRT's own row model so it can never drift
556
+ // from what the user sees. "all" = every row in the current fetched batch,
557
+ // ignoring column filters/global search (unchanged pre-existing behavior).
558
+ const exportRows = scope === 'filtered' && tableRef.current
559
+ ? tableRef.current.getFilteredRowModel().rows.map((r) => r.original)
560
+ : rows;
531
561
  const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey);
532
562
  // xlsx-js-style requires 8-char ARGB (AA + RRGGBB). Prepend full-opacity "FF".
533
563
  const toArgb = (hex, fallback = 'FF1565C0') => hex?.startsWith('#') ? 'FF' + hex.slice(1).toUpperCase().padEnd(6, '0') : fallback;
534
564
  const headerArgb = toArgb(exportHeaderBgColor ?? headerBgColor);
535
565
  const textArgb = toArgb(exportHeaderTextColor, 'FFFFFFFF');
536
566
  const headerRow = dataCols.map((c) => c.header ?? '');
537
- const dataRows = rows.map((row) => dataCols.map((c) => String(row[c.accessorKey] ?? '')));
567
+ const dataRows = exportRows.map((row) => dataCols.map((c) => String(row[c.accessorKey] ?? '')));
538
568
  const ws = XLSX.utils.aoa_to_sheet([headerRow, ...dataRows]);
539
569
  // Style header row
540
570
  dataCols.forEach((_, colIdx) => {
@@ -554,7 +584,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
554
584
  // Auto-fit column widths — single O(n) pass accumulates max length per column
555
585
  // instead of one reduce() per column (was O(n × cols)).
556
586
  const colWidths = dataCols.map((c) => (c.header ?? '').length);
557
- for (const row of rows) {
587
+ for (const row of exportRows) {
558
588
  const r = row;
559
589
  for (let ci = 0; ci < dataCols.length; ci++) {
560
590
  const len = String(r[dataCols[ci].accessorKey] ?? '').length;
@@ -565,7 +595,8 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
565
595
  ws['!cols'] = colWidths.map((w) => ({ wch: Math.max(w, 8) + 2 }));
566
596
  const wb = XLSX.utils.book_new();
567
597
  XLSX.utils.book_append_sheet(wb, ws, 'Data');
568
- XLSX.writeFile(wb, `${exportFilename}-page${pagination.pageIndex + 1}.xlsx`);
598
+ const suffix = scope === 'filtered' ? '-filtered' : '';
599
+ XLSX.writeFile(wb, `${exportFilename}${suffix}-page${pagination.pageIndex + 1}.xlsx`);
569
600
  }, [columns, rows, exportFilename, pagination.pageIndex, headerBgColor, exportHeaderBgColor, exportHeaderTextColor]);
570
601
  // ── Memoized cell-prop builders ───────────────────────────────────────────
571
602
  // These are functions passed to MRT per-cell. Without useCallback they get
@@ -630,9 +661,11 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
630
661
  alignItems: 'center',
631
662
  flexWrap: isNarrow ? 'wrap' : 'nowrap',
632
663
  flex: 1, minWidth: 0, pr: 1, gap: 0.5,
633
- }, 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 }) })] })), [
664
+ }, 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: isFiltered
665
+ ? 'Export as Excel (.xlsx) — choose filtered or complete data'
666
+ : 'Export as Excel (.xlsx)', children: jsx("span", { children: jsx(IconButton, { id: `${resolvedGridId}_export_icon`, size: "small", onClick: (e) => isFiltered ? setExportMenuAnchor(e.currentTarget) : handleExport('all'), disabled: rows.length === 0 || isFetching, sx: { p: resolvedUiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: resolvedUiDensity === 'compact' ? 18 : 20 } }) }) }) }), jsxs(Menu, { id: `${resolvedGridId}_export_menu`, anchorEl: exportMenuAnchor, open: Boolean(exportMenuAnchor), onClose: () => setExportMenuAnchor(null), children: [jsxs(MenuItem, { id: `${resolvedGridId}_export_filtered_option`, onClick: () => { setExportMenuAnchor(null); handleExport('filtered'); }, children: ["Filtered data (", (tableRef.current?.getFilteredRowModel().rows.length ?? rows.length).toLocaleString(), " rows)"] }), jsxs(MenuItem, { id: `${resolvedGridId}_export_all_option`, onClick: () => { setExportMenuAnchor(null); handleExport('all'); }, children: ["Complete data (", rows.length.toLocaleString(), " rows)"] })] })] }), 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 }) })] })), [
634
667
  resolvedGridId, isFetching, rows.length, resolvedUiDensity, isNarrow,
635
- handleClearAll, refetch, handleExport,
668
+ handleClearAll, refetch, handleExport, isFiltered, exportMenuAnchor,
636
669
  serverFilterDefs, visibleFilterIds, handleToggleFilter,
637
670
  filterValues, handleFilterValuesChange, columnFilters, setColumnFilters,
638
671
  availableColumns, effectiveMaxVisibleFilters, densityTokens, handleToggleFilter,
@@ -826,6 +859,9 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
826
859
  renderToolbarInternalActions,
827
860
  renderBottomToolbar,
828
861
  });
862
+ // Keep the latest table instance available to handleExport (see tableRef
863
+ // declaration above) without adding `table` to its dependency array.
864
+ tableRef.current = table;
829
865
  return (jsxs(Box, { ref: containerRef, id: resolvedGridId, className: "tp-gpg-root", sx: {
830
866
  position: 'relative',
831
867
  height: resolvedHeight,
@@ -1,4 +1,4 @@
1
- import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm5.js';
1
+ import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm6.js';
2
2
  import require$$0__default from 'react';
3
3
  import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
4
4
  import { __require as requireDateRange } from '../DateRange/index.esm.js';
@@ -1,4 +1,4 @@
1
- import { __exports as DefinedRange } from '../../../../../_virtual/index.esm6.js';
1
+ import { __exports as DefinedRange } from '../../../../../_virtual/index.esm5.js';
2
2
  import require$$0__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';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tp-react-elements",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",