tp-react-elements 3.0.1 → 3.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.
@@ -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 Month = {};
1
+ var DateInput = {};
2
2
 
3
- export { Month as __exports };
3
+ export { DateInput as __exports };
@@ -1,5 +1,6 @@
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';
4
5
  import SingleSelect from '../FormComponents/Select/SingleSelect.esm.js';
5
6
  import MultiSelectAutocomplete from '../FormComponents/Select/MultiSelectAutocomplete.esm.js';
@@ -12,7 +13,6 @@ import RichTextEditorWrapper from '../FormComponents/RichTextEditor/RichTextEdit
12
13
  import SingleSelectSearchApi from '../FormComponents/Select/SingleSelectSearchApi.esm.js';
13
14
  import DatetimepickerWrapper from '../FormComponents/DatePicker/DatetimepickerWrapper.esm.js';
14
15
  import FormTextAreaField from '../FormComponents/FormTextAreaField/FormTextAreaField.esm.js';
15
- import FormCheckBox from '../FormComponents/FormCheckBox/FormCheckBox.esm.js';
16
16
  import FormRadioGroup from '../FormComponents/FormRadioGroup/FormRadioGroup.esm.js';
17
17
  import FormNumberFieldDecimal from '../FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js';
18
18
  import FormNumberField from '../FormComponents/FormNumberField/FormNumberField.esm.js';
@@ -1,3 +1,4 @@
1
+ export { default as FormCheckBox } from './FormCheckBox/FormCheckBox.esm.js';
1
2
  export { default as SingleSelect } from './Select/SingleSelect.esm.js';
2
3
  export { default as SingleSelectNonAutoComplete } from './Select/SingleSelectNonAutoComplete.esm.js';
3
4
  export { default as SingleSelectSearchApi } from './Select/SingleSelectSearchApi.esm.js';
@@ -6,20 +7,8 @@ export { default as MultiSelectTable } from './Select/MultiSelectTable.esm.js';
6
7
  export { default as SearchableSelect } from './Select/SearchableSelect.esm.js';
7
8
  export { default as FormCheckBoxGroup } from './FormCheckBoxGroup/FormCheckBoxGroup.esm.js';
8
9
  export { default as DatepickerWrapperV2 } from './DatePicker/DatepickerWrapperV2.esm.js';
9
- export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
10
- import 'react/jsx-runtime';
11
- import 'react';
12
- import '@mui/material';
13
- import '@mui/icons-material/CalendarToday';
14
- import '@mui/icons-material/ChevronLeft';
15
- import '@mui/icons-material/ChevronRight';
16
- import 'react-hook-form';
17
10
  export { default as FormBottomField } from './FormBottomField/FormBottomField.esm.js';
18
- import 'dayjs';
19
- export { default as YearPickerField } from './YearPickerField/YearPickerField.esm.js';
20
11
  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
12
  export { default as FormNumberField } from './FormNumberField/FormNumberField.esm.js';
24
13
  export { default as FormNumberFieldDecimal } from './FormNumberField/FormNumberFieldDecimal.esm.js';
25
14
  export { default as FormRadioGroup } from './FormRadioGroup/FormRadioGroup.esm.js';
@@ -27,7 +16,10 @@ export { default as FormRenderFileUpload } from './FileUpload/FormRenderFileUplo
27
16
  export { default as FormRenderMultiFileUpload } from './FileUpload/FormRenderMultiFileUpload.esm.js';
28
17
  export { default as FormTextAreaField } from './FormTextAreaField/FormTextAreaField.esm.js';
29
18
  export { default as FormTextField } from './FormTextField/FormTextField.esm.js';
19
+ export { default as HelperText } from './HelperText/HelperText.esm.js';
20
+ export { default as Monthpickerrender } from './DatePicker/Monthpickerrender.esm.js';
30
21
  export { default as PasswordField } from './PasswordField/PasswordField.esm.js';
31
22
  export { default as RichTextEditor } from './RichTextEditor/RichTextEditor.esm.js';
32
23
  export { default as RichTextEditorWrapper } from './RichTextEditor/RichTextEditorWrapper.esm.js';
33
24
  export { default as TimePicker } from './TimePicker/TimePicker.esm.js';
25
+ export { default as YearPickerField } from './YearPickerField/YearPickerField.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,
@@ -693,7 +726,16 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
693
726
  onPaginationChange: setPagination,
694
727
  onSortingChange: setSorting,
695
728
  onColumnFiltersChange: setColumnFilters,
696
- onGlobalFilterChange: setGlobalFilter,
729
+ // MRT's own "clear search" (X) button inside the search field calls this
730
+ // with `undefined` (not ''), e.g. via its internal handleClear. Normalize
731
+ // here so `globalFilter` is never anything but a string — code elsewhere
732
+ // in this component (e.g. `isFiltered`) assumes that invariant.
733
+ onGlobalFilterChange: (updater) => {
734
+ setGlobalFilter((prev) => {
735
+ const next = typeof updater === 'function' ? updater(prev) : updater;
736
+ return next ?? '';
737
+ });
738
+ },
697
739
  onColumnPinningChange: (updater) => {
698
740
  setColumnPinning((prev) => {
699
741
  const next = typeof updater === 'function' ? updater(prev) : updater;
@@ -826,6 +868,9 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
826
868
  renderToolbarInternalActions,
827
869
  renderBottomToolbar,
828
870
  });
871
+ // Keep the latest table instance available to handleExport (see tableRef
872
+ // declaration above) without adding `table` to its dependency array.
873
+ tableRef.current = table;
829
874
  return (jsxs(Box, { ref: containerRef, id: resolvedGridId, className: "tp-gpg-root", sx: {
830
875
  position: 'relative',
831
876
  height: resolvedHeight,
@@ -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 require$$0__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.esm14.js';
1
+ import { __exports as Month } from '../../../../../_virtual/index.esm13.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 requireDayCell } from '../DayCell/index.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.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "React form components library built with React Hook Form and Yup",