@bsol-oss/react-datatable5 1.0.63 → 1.0.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,27 +1,123 @@
1
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { IconButton, Button, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, Flex, ModalFooter, Text, Menu, MenuButton, MenuList, MenuItem, Box, FormLabel, Checkbox, Grid, Spinner, Tooltip, Icon, Tfoot, Tr as Tr$1, Th, Thead, Portal, Table as Table$1, Card, CardBody, VStack, FormControl, Input, RangeSlider, RangeSliderTrack, RangeSliderFilledTrack, RangeSliderThumb, WrapItem, Tag, TagLabel, TagCloseButton, Select, ButtonGroup, Switch, InputGroup, InputLeftElement } from '@chakra-ui/react';
3
+ import { AiOutlineColumnWidth } from 'react-icons/ai';
4
+ import { MdFilterAlt, MdOutlineMoveDown, MdOutlineSort, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdArrowUpward, MdArrowDownward, MdFirstPage, MdArrowBack, MdArrowForward, MdLastPage, MdOutlineChecklist, MdClose, MdSearch } from 'react-icons/md';
5
+ import { UpDownIcon, ChevronDownIcon, ChevronUpIcon, CloseIcon } from '@chakra-ui/icons';
6
+ import { createContext, useContext, useState, useEffect } from 'react';
7
+ import { IoMdEye, IoMdCheckbox } from 'react-icons/io';
2
8
  import { makeStateUpdater, functionalUpdate, useReactTable, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getPaginationRowModel, flexRender } from '@tanstack/react-table';
3
- import { createContext, useState, useEffect, useContext } from 'react';
4
9
  import { rankItem } from '@tanstack/match-sorter-utils';
5
10
  import axios from 'axios';
6
- import { Box, FormLabel, Checkbox, Grid, Flex, Text, Tfoot, Tr as Tr$1, Th, Menu, MenuButton, Thead, Portal, MenuList, MenuItem, IconButton, Button, useDisclosure, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, ModalFooter, InputGroup, InputLeftElement, Icon, Input, Table as Table$1, Card, CardBody, VStack, FormControl, RangeSlider, RangeSliderTrack, RangeSliderFilledTrack, RangeSliderThumb, WrapItem, Tag, TagLabel, TagCloseButton, Select, ButtonGroup, Switch, Tooltip } from '@chakra-ui/react';
7
11
  import { Tbody, Tr, Td } from '@chakra-ui/table';
8
- import { MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdFilterAlt, MdOutlineMoveDown, MdOutlineSort, MdClose, MdSearch, MdArrowUpward, MdArrowDownward, MdFirstPage, MdArrowBack, MdArrowForward, MdLastPage, MdOutlineChecklist } from 'react-icons/md';
9
- import { ChevronUpIcon, ChevronDownIcon, UpDownIcon, CloseIcon } from '@chakra-ui/icons';
12
+ import { BsExclamationCircleFill } from 'react-icons/bs';
10
13
  import { GrAscend, GrDescend } from 'react-icons/gr';
11
- import { AiOutlineColumnWidth } from 'react-icons/ai';
12
- import { IoMdEye, IoMdCheckbox } from 'react-icons/io';
13
14
  import { IoReload } from 'react-icons/io5';
14
15
  import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
15
16
  import { FaGripLinesVertical } from 'react-icons/fa';
16
17
 
18
+ const DensityToggleButton = ({ text, icon = jsx(AiOutlineColumnWidth, {}), }) => {
19
+ const { table } = useDataTable();
20
+ return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { variant: "ghost", "aria-label": "Toggle Density", icon: icon, onClick: () => {
21
+ table.toggleDensity();
22
+ } })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", "aria-label": "Toggle Density", onClick: () => {
23
+ table.toggleDensity();
24
+ }, children: text }))] }));
25
+ };
26
+
27
+ const EditFilterButton = ({ text, title = "Edit Filter", closeText = "Close", resetText = "Reset", icon = jsx(MdFilterAlt, {}), ...props }) => {
28
+ const filterModal = useDisclosure();
29
+ return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: filterModal.onOpen, "aria-label": "filter", ...props })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: filterModal.onOpen, ...props, children: text })), jsxs(Modal, { isOpen: filterModal.isOpen, onClose: filterModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsxs(Flex, { flexFlow: "column", gap: "1rem", children: [jsx(TableFilter, {}), jsx(ResetFilteringButton, { text: resetText })] }) }), jsx(ModalFooter, { children: jsx(Button, { onClick: filterModal.onClose, children: closeText }) })] })] })] }));
30
+ };
31
+
32
+ const EditOrderButton = ({ text, icon = jsx(MdOutlineMoveDown, {}), title = "Change Order", }) => {
33
+ const orderModal = useDisclosure();
34
+ return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: orderModal.onOpen, "aria-label": "change order" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: orderModal.onOpen, children: text })), jsxs(Modal, { isOpen: orderModal.isOpen, onClose: orderModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsx(Flex, { flexFlow: "column", gap: "0.25rem", children: jsx(TableOrderer, {}) }) })] })] })] }));
35
+ };
36
+
17
37
  const TableContext = createContext({
18
38
  table: {},
19
39
  refreshData: () => { },
20
40
  globalFilter: "",
21
41
  setGlobalFilter: () => { },
22
42
  loading: false,
43
+ hasError: false,
23
44
  });
24
45
 
46
+ const useDataTable = () => {
47
+ const { table, refreshData, globalFilter, setGlobalFilter, loading, hasError, } = useContext(TableContext);
48
+ return {
49
+ table,
50
+ refreshData,
51
+ globalFilter,
52
+ setGlobalFilter,
53
+ loading,
54
+ hasError,
55
+ };
56
+ };
57
+
58
+ const TableSorter = () => {
59
+ const { table } = useDataTable();
60
+ return (jsx(Fragment, { children: table.getHeaderGroups().map((headerGroup) => (jsx(Fragment, { children: headerGroup.headers.map((header) => {
61
+ const displayName = header.column.columnDef.meta === undefined
62
+ ? header.column.id
63
+ : header.column.columnDef.meta.displayName;
64
+ return (jsx(Fragment, { children: header.column.getCanSort() && (jsxs(Flex, { alignItems: "center", gap: "0.5rem", padding: "0.5rem", children: [jsx(Text, { children: displayName }), jsxs(Button, { variant: "ghost", onClick: (e) => {
65
+ header.column.toggleSorting();
66
+ }, children: [header.column.getIsSorted() === false && (
67
+ // <Text>To No sort</Text>
68
+ jsx(UpDownIcon, {})), header.column.getIsSorted() === "asc" && (
69
+ // <Text>To asc</Text>
70
+ jsx(ChevronDownIcon, {})), header.column.getIsSorted() === "desc" && (
71
+ // <Text>To desc</Text>
72
+ jsx(ChevronUpIcon, {}))] }), header.column.getIsSorted() && (jsx(Button, { onClick: (e) => {
73
+ header.column.clearSorting();
74
+ }, children: jsx(CloseIcon, {}) }))] })) }));
75
+ }) }))) }));
76
+ };
77
+
78
+ const EditSortingButton = ({ text, icon = jsx(MdOutlineSort, {}), title = "Edit Sorting", }) => {
79
+ const sortingModal = useDisclosure();
80
+ return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: sortingModal.onOpen, "aria-label": "change sorting" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: sortingModal.onOpen, children: text })), jsxs(Modal, { isOpen: sortingModal.isOpen, onClose: sortingModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(TableSorter, {}), jsx(ResetSortingButton, {})] }) })] })] })] }));
81
+ };
82
+
83
+ const EditViewButton = ({ text, icon = jsx(IoMdEye, {}), title = "Edit View", }) => {
84
+ const viewModel = useDisclosure();
85
+ return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: viewModel.onOpen, "aria-label": "change sorting" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: viewModel.onOpen, children: text })), jsxs(Modal, { isOpen: viewModel.isOpen, onClose: viewModel.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsx(TableViewer, {}) })] })] })] }));
86
+ };
87
+
88
+ const PageSizeControl = ({ pageSizes = [10, 20, 30, 40, 50], }) => {
89
+ const { table } = useDataTable();
90
+ return (jsx(Fragment, { children: jsxs(Menu, { children: [jsx(MenuButton, { as: Button, variant: "ghost", rightIcon: jsx(ChevronDownIcon, {}), gap: "0.5rem", children: table.getState().pagination.pageSize }), jsx(MenuList, { children: pageSizes.map((pageSize) => (jsx(MenuItem, { onClick: () => {
91
+ table.setPageSize(Number(pageSize));
92
+ }, children: pageSize }, crypto.randomUUID()))) })] }) }));
93
+ };
94
+
95
+ const ResetFilteringButton = ({ text = "Reset Filtering", }) => {
96
+ const { table } = useDataTable();
97
+ return (jsx(Button, { onClick: () => {
98
+ table.resetColumnFilters();
99
+ }, children: text }));
100
+ };
101
+
102
+ const ResetSelectionButton = ({ text = "Reset Selection", }) => {
103
+ const { table } = useDataTable();
104
+ return (jsx(Button, { onClick: () => {
105
+ table.resetRowSelection();
106
+ }, children: text }));
107
+ };
108
+
109
+ const ResetSortingButton = ({ text = "Reset Sorting", }) => {
110
+ const { table } = useDataTable();
111
+ return (jsx(Button, { onClick: () => {
112
+ table.resetSorting();
113
+ }, children: text }));
114
+ };
115
+
116
+ const RowCountText = () => {
117
+ const { table } = useDataTable();
118
+ return jsx(Text, { children: table.getRowCount() });
119
+ };
120
+
25
121
  // Reference: https://tanstack.com/table/latest/docs/framework/react/examples/custom-features
26
122
  // TypeScript setup for our new feature with all of the same type-safety as stock TanStack Table features
27
123
  // end of TS setup!
@@ -172,6 +268,7 @@ const DataTable = ({ columns, data, enableRowSelection = true, enableMultiRowSel
172
268
  globalFilter: globalFilter,
173
269
  setGlobalFilter: setGlobalFilter,
174
270
  loading: false,
271
+ hasError: false,
175
272
  }, children: children }));
176
273
  };
177
274
 
@@ -184,6 +281,7 @@ const useDataFromUrl = ({ url, params = {}, disableFirstFetch = false, onFetchSu
184
281
  };
185
282
  const getData = async () => {
186
283
  try {
284
+ setHasError(false);
187
285
  setLoading(true);
188
286
  const { data } = await axios.get(url, { params: params });
189
287
  console.debug("get DataFromUrl success", data);
@@ -294,7 +392,7 @@ const DataTableServer = ({ columns, url, enableRowSelection = true, enableMultiR
294
392
  });
295
393
  useEffect(() => {
296
394
  refreshData();
297
- }, [pagination, sorting, columnFilters, globalFilter]);
395
+ }, [pagination, sorting, columnFilters, globalFilter, url]);
298
396
  useEffect(() => {
299
397
  setColumnOrder(table.getAllLeafColumns().map((column) => column.id));
300
398
  }, []);
@@ -307,6 +405,7 @@ const DataTableServer = ({ columns, url, enableRowSelection = true, enableMultiR
307
405
  globalFilter,
308
406
  setGlobalFilter,
309
407
  loading: loading,
408
+ hasError: hasError,
310
409
  }, children: children }));
311
410
  };
312
411
 
@@ -360,16 +459,12 @@ const TableRowSelector = ({ index, row, hoveredRow, pinnedBgColor = { light: "gr
360
459
  };
361
460
 
362
461
  const TableControls = ({ totalText = "Total:", showFilter = false, fitTableWidth = false, fitTableHeight = false, isMobile = false, children = jsx(Fragment, {}), showFilterName = false, showFilterTags = false, filterOptions = [], }) => {
363
- return (jsxs(Grid, { templateRows: "auto auto auto 1fr auto", templateColumns: "1fr 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", justifySelf: "center", alignSelf: "center", gap: "0.5rem", children: [jsxs(Flex, { justifyContent: "space-between", gridColumn: "1 / span 2", children: [jsx(Box, { children: jsx(EditViewButton, { text: isMobile ? undefined : "View", icon: jsx(MdOutlineViewColumn, {}) }) }), jsx(Flex, { gap: "1rem", justifySelf: "end", children: showFilter && (jsxs(Fragment, { children: [jsx(GlobalFilter, {}), jsx(EditFilterButton, { text: isMobile ? undefined : "Advanced Filter" })] })) })] }), jsx(Flex, { gridColumn: "1 / span 2", flexFlow: "column", gap: "0.5rem", children: filterOptions.map((column) => {
462
+ const { loading, hasError } = useDataTable();
463
+ return (jsxs(Grid, { templateRows: "auto auto auto 1fr auto", templateColumns: "1fr 1fr", width: fitTableWidth ? "fit-content" : "100%", height: fitTableHeight ? "fit-content" : "100%", justifySelf: "center", alignSelf: "center", gap: "0.5rem", children: [jsxs(Flex, { justifyContent: "space-between", gridColumn: "1 / span 2", children: [jsx(Box, { children: jsx(EditViewButton, { text: isMobile ? undefined : "View", icon: jsx(MdOutlineViewColumn, {}) }) }), jsxs(Flex, { gap: "1rem", alignItems: "center", justifySelf: "end", children: [loading && jsx(Spinner, { size: "sm" }), hasError && (jsx(Tooltip, { label: "An error occurred while fetching data", children: jsx(Box, { children: jsx(Icon, { as: BsExclamationCircleFill, color: "red.400" }) }) })), showFilter && (jsxs(Fragment, { children: [jsx(GlobalFilter, {}), jsx(EditFilterButton, { text: isMobile ? undefined : "Advanced Filter" })] }))] })] }), jsx(Flex, { gridColumn: "1 / span 2", flexFlow: "column", gap: "0.5rem", children: filterOptions.map((column) => {
364
464
  return (jsxs(Flex, { alignItems: "center", flexFlow: "wrap", gap: "0.5rem", children: [showFilterName && jsxs(Text, { children: [column, ":"] }), jsx(FilterOptions, { column: column })] }));
365
465
  }) }), jsx(Flex, { gridColumn: "1 / span 2", children: showFilterTags && jsx(TableFilterTags, {}) }), jsx(Box, { overflow: "auto", gridColumn: "1 / span 2", width: "100%", height: "100%", children: children }), jsxs(Flex, { gap: "1rem", alignItems: "center", children: [jsx(PageSizeControl, {}), jsxs(Flex, { children: [jsx(Text, { paddingRight: "0.5rem", children: totalText }), jsx(RowCountText, {})] })] }), jsx(Box, { justifySelf: "end", children: jsx(TablePagination, {}) })] }));
366
466
  };
367
467
 
368
- const useDataTable = () => {
369
- const { table, refreshData, globalFilter, setGlobalFilter, loading } = useContext(TableContext);
370
- return { table, refreshData, globalFilter, setGlobalFilter, loading };
371
- };
372
-
373
468
  const TableFooter = ({ pinnedBgColor = { light: "gray.50", dark: "gray.700" }, }) => {
374
469
  const table = useDataTable().table;
375
470
  const SELECTION_BOX_WIDTH = 20;
@@ -504,115 +599,6 @@ const DefaultTable = ({ totalText = "Total:", showFilter = false, showFooter = f
504
599
  return (jsx(TableControls, { totalText: totalText, showFilter: showFilter, fitTableWidth: fitTableWidth, fitTableHeight: fitTableHeight, isMobile: isMobile, filterOptions: filterOptions, showFilterName: showFilterName, showFilterTags: showFilterTags, children: jsxs(Table, { variant: "striped", children: [jsx(TableHeader, { canResize: true }), jsx(TableBody, {}), showFooter && jsx(TableFooter, {})] }) }));
505
600
  };
506
601
 
507
- const DensityToggleButton = ({ text, icon = jsx(AiOutlineColumnWidth, {}), }) => {
508
- const { table } = useDataTable();
509
- return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { variant: "ghost", "aria-label": "Toggle Density", icon: icon, onClick: () => {
510
- table.toggleDensity();
511
- } })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", "aria-label": "Toggle Density", onClick: () => {
512
- table.toggleDensity();
513
- }, children: text }))] }));
514
- };
515
-
516
- const EditFilterButton = ({ text, title = "Edit Filter", closeText = "Close", resetText = "Reset", icon = jsx(MdFilterAlt, {}), ...props }) => {
517
- const filterModal = useDisclosure();
518
- return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: filterModal.onOpen, "aria-label": "filter", ...props })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: filterModal.onOpen, ...props, children: text })), jsxs(Modal, { isOpen: filterModal.isOpen, onClose: filterModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsxs(Flex, { flexFlow: "column", gap: "1rem", children: [jsx(TableFilter, {}), jsx(ResetFilteringButton, { text: resetText })] }) }), jsx(ModalFooter, { children: jsx(Button, { onClick: filterModal.onClose, children: closeText }) })] })] })] }));
519
- };
520
-
521
- const EditOrderButton = ({ text, icon = jsx(MdOutlineMoveDown, {}), title = "Change Order", }) => {
522
- const orderModal = useDisclosure();
523
- return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: orderModal.onOpen, "aria-label": "change order" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: orderModal.onOpen, children: text })), jsxs(Modal, { isOpen: orderModal.isOpen, onClose: orderModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsx(Flex, { flexFlow: "column", gap: "0.25rem", children: jsx(TableOrderer, {}) }) })] })] })] }));
524
- };
525
-
526
- const TableSorter = () => {
527
- const { table } = useDataTable();
528
- return (jsx(Fragment, { children: table.getHeaderGroups().map((headerGroup) => (jsx(Fragment, { children: headerGroup.headers.map((header) => {
529
- const displayName = header.column.columnDef.meta === undefined
530
- ? header.column.id
531
- : header.column.columnDef.meta.displayName;
532
- return (jsx(Fragment, { children: header.column.getCanSort() && (jsxs(Flex, { alignItems: "center", gap: "0.5rem", padding: "0.5rem", children: [jsx(Text, { children: displayName }), jsxs(Button, { variant: "ghost", onClick: (e) => {
533
- header.column.toggleSorting();
534
- }, children: [header.column.getIsSorted() === false && (
535
- // <Text>To No sort</Text>
536
- jsx(UpDownIcon, {})), header.column.getIsSorted() === "asc" && (
537
- // <Text>To asc</Text>
538
- jsx(ChevronDownIcon, {})), header.column.getIsSorted() === "desc" && (
539
- // <Text>To desc</Text>
540
- jsx(ChevronUpIcon, {}))] }), header.column.getIsSorted() && (jsx(Button, { onClick: (e) => {
541
- header.column.clearSorting();
542
- }, children: jsx(CloseIcon, {}) }))] })) }));
543
- }) }))) }));
544
- };
545
-
546
- const EditSortingButton = ({ text, icon = jsx(MdOutlineSort, {}), title = "Edit Sorting", }) => {
547
- const sortingModal = useDisclosure();
548
- return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: sortingModal.onOpen, "aria-label": "change sorting" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: sortingModal.onOpen, children: text })), jsxs(Modal, { isOpen: sortingModal.isOpen, onClose: sortingModal.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsxs(Flex, { flexFlow: "column", gap: "0.25rem", children: [jsx(TableSorter, {}), jsx(ResetSortingButton, {})] }) })] })] })] }));
549
- };
550
-
551
- const EditViewButton = ({ text, icon = jsx(IoMdEye, {}), title = "Edit View", }) => {
552
- const viewModel = useDisclosure();
553
- return (jsxs(Fragment, { children: [!!text === false && (jsx(IconButton, { icon: icon, variant: "ghost", onClick: viewModel.onOpen, "aria-label": "change sorting" })), !!text !== false && (jsx(Button, { leftIcon: icon, variant: "ghost", onClick: viewModel.onOpen, children: text })), jsxs(Modal, { isOpen: viewModel.isOpen, onClose: viewModel.onClose, size: ["full", "full", "md", "md"], children: [jsx(ModalOverlay, {}), jsxs(ModalContent, { padding: "0 0 1rem 0", children: [jsx(ModalHeader, { children: title }), jsx(ModalCloseButton, {}), jsx(ModalBody, { children: jsx(TableViewer, {}) })] })] })] }));
554
- };
555
-
556
- const FilterOptions = ({ column }) => {
557
- const { table } = useDataTable();
558
- const tableColumn = table.getColumn(column);
559
- const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
560
- return (jsx(Fragment, { children: options.map((option) => {
561
- const selected = table.getColumn(column)?.getFilterValue() === option;
562
- return (jsxs(Button, { size: "sm", onClick: () => {
563
- if (selected) {
564
- table.setColumnFilters((state) => {
565
- return state.filter((filter) => {
566
- return filter.id !== column;
567
- });
568
- });
569
- return;
570
- }
571
- table.getColumn(column)?.setFilterValue(option);
572
- }, variant: selected ? "solid" : "outline", display: "flex", gap: "0.25rem", children: [option, selected && jsx(MdClose, {})] }, option));
573
- }) }));
574
- };
575
-
576
- const GlobalFilter = ({ icon = MdSearch }) => {
577
- const { globalFilter, setGlobalFilter } = useDataTable();
578
- return (jsx(Fragment, { children: jsx(Box, { children: jsxs(InputGroup, { children: [jsx(InputLeftElement, { pointerEvents: "none", children: jsx(Icon, { as: icon, color: "gray.300" }) }), jsx(Input, { value: globalFilter, onChange: (e) => {
579
- setGlobalFilter(e.target.value);
580
- } })] }) }) }));
581
- };
582
-
583
- const PageSizeControl = ({ pageSizes = [10, 20, 30, 40, 50], }) => {
584
- const { table } = useDataTable();
585
- return (jsx(Fragment, { children: jsxs(Menu, { children: [jsx(MenuButton, { as: Button, variant: "ghost", rightIcon: jsx(ChevronDownIcon, {}), gap: "0.5rem", children: table.getState().pagination.pageSize }), jsx(MenuList, { children: pageSizes.map((pageSize) => (jsx(MenuItem, { onClick: () => {
586
- table.setPageSize(Number(pageSize));
587
- }, children: pageSize }, crypto.randomUUID()))) })] }) }));
588
- };
589
-
590
- const ResetFilteringButton = ({ text = "Reset Filtering", }) => {
591
- const { table } = useDataTable();
592
- return (jsx(Button, { onClick: () => {
593
- table.resetColumnFilters();
594
- }, children: text }));
595
- };
596
-
597
- const ResetSelectionButton = ({ text = "Reset Selection", }) => {
598
- const { table } = useDataTable();
599
- return (jsx(Button, { onClick: () => {
600
- table.resetRowSelection();
601
- }, children: text }));
602
- };
603
-
604
- const ResetSortingButton = ({ text = "Reset Sorting", }) => {
605
- const { table } = useDataTable();
606
- return (jsx(Button, { onClick: () => {
607
- table.resetSorting();
608
- }, children: text }));
609
- };
610
-
611
- const RowCountText = () => {
612
- const { table } = useDataTable();
613
- return jsx(Text, { children: table.getRowCount() });
614
- };
615
-
616
602
  const Table = ({ children, showLoading = false, loadingComponent = jsx(Fragment, { children: "Loading..." }), ...props }) => {
617
603
  const { table, loading } = useDataTable();
618
604
  if (showLoading) {
@@ -877,4 +863,31 @@ const TextCell = ({ label, noOfLines = [1], padding = "0rem", children, tooltipP
877
863
  return (jsx(Flex, { alignItems: "center", height: "100%", padding: padding, children: jsx(Text, { as: "span", overflow: "hidden", textOverflow: "ellipsis", wordBreak: "break-all", noOfLines: noOfLines, ...props, children: children }) }));
878
864
  };
879
865
 
866
+ const FilterOptions = ({ column }) => {
867
+ const { table } = useDataTable();
868
+ const tableColumn = table.getColumn(column);
869
+ const options = tableColumn?.columnDef.meta?.filterOptions ?? [];
870
+ return (jsx(Fragment, { children: options.map((option) => {
871
+ const selected = table.getColumn(column)?.getFilterValue() === option;
872
+ return (jsxs(Button, { size: "sm", onClick: () => {
873
+ if (selected) {
874
+ table.setColumnFilters((state) => {
875
+ return state.filter((filter) => {
876
+ return filter.id !== column;
877
+ });
878
+ });
879
+ return;
880
+ }
881
+ table.getColumn(column)?.setFilterValue(option);
882
+ }, variant: selected ? "solid" : "outline", display: "flex", gap: "0.25rem", children: [option, selected && jsx(MdClose, {})] }, option));
883
+ }) }));
884
+ };
885
+
886
+ const GlobalFilter = ({ icon = MdSearch }) => {
887
+ const { globalFilter, setGlobalFilter } = useDataTable();
888
+ return (jsx(Fragment, { children: jsx(Box, { children: jsxs(InputGroup, { children: [jsx(InputLeftElement, { pointerEvents: "none", children: jsx(Icon, { as: icon, color: "gray.300" }) }), jsx(Input, { value: globalFilter, onChange: (e) => {
889
+ setGlobalFilter(e.target.value);
890
+ } })] }) }) }));
891
+ };
892
+
880
893
  export { DataTable, DataTableServer, DefaultTable, DensityToggleButton, EditFilterButton, EditOrderButton, EditSortingButton, EditViewButton, FilterOptions, GlobalFilter, PageSizeControl, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableOrderer, TablePagination, TableSelector, TableSorter, TableViewer, TextCell, useDataFromUrl, useDataTable };
@@ -6,5 +6,6 @@ export interface DataTableContext<TData> {
6
6
  globalFilter: string;
7
7
  setGlobalFilter: (filter: string) => void;
8
8
  loading: boolean;
9
+ hasError: boolean;
9
10
  }
10
11
  export declare const TableContext: import("react").Context<DataTableContext<any>>;
@@ -4,4 +4,5 @@ export declare const useDataTable: () => {
4
4
  globalFilter: string;
5
5
  setGlobalFilter: (filter: string) => void;
6
6
  loading: boolean;
7
+ hasError: boolean;
7
8
  };
@@ -2,36 +2,68 @@
2
2
  import { Column, RowData } from "@tanstack/react-table";
3
3
  declare module "@tanstack/react-table" {
4
4
  interface ColumnMeta<TData extends RowData, TValue> {
5
+ /**
6
+ * The display name of the column, used for rendering headers.
7
+ */
5
8
  displayName?: string;
6
9
  /**
7
- * @note you should provide a proper `filterfn` to handle the filtering when choosing `boolean`, `dateRange` and `custom`
10
+ * Specifies the type of filter to be used for the column.
11
+ *
12
+ * @remarks You should provide a proper `filterfn` to handle filtering when choosing `boolean`, `dateRange`, and `custom`.
13
+ *
14
+ * @remarks You should decide `renderFilter` to display filter ui when choosing `custom`.
15
+ *
16
+ * Possible values:
17
+ * - "text": A text input filter.
18
+ * - "range": A numerical range filter.
19
+ * - "select": A dropdown select filter.
20
+ * - "tag": A tag-based filter.
21
+ * - "boolean": A true/false filter.
22
+ * - "dateRange": A date range filter.
23
+ * - "custom": A custom filter function.
8
24
  */
9
25
  filterVariant?: "text" | "range" | "select" | "tag" | "boolean" | "dateRange" | "custom";
26
+ /**
27
+ * Options for the select filter variant, if applicable.
28
+ */
10
29
  filterOptions?: string[];
30
+ /**
31
+ * Configuration for the range filter variant, if applicable.
32
+ *
33
+ * Properties:
34
+ * - `min`: Minimum value for the range.
35
+ * - `max`: Maximum value for the range.
36
+ * - `step`: Step increment for the range.
37
+ * - `defaultValue`: Default range values for the filter.
38
+ */
11
39
  filterRangeConfig?: {
12
40
  min: number;
13
41
  max: number;
14
42
  step: number;
15
43
  defaultValue: [number, number];
16
44
  };
45
+ /**
46
+ * A function that renders the filter component for the column.
47
+ *
48
+ * @param column - The column for which the filter is being rendered.
49
+ * @returns A JSX element representing the filter UI.
50
+ */
17
51
  renderFilter?: (column: Column<TData>) => JSX.Element;
18
52
  }
19
53
  }
20
- export * from "./components/DataTable/DataTable";
21
- export * from "./components/DataTable/DataTableServer";
22
- export * from "./components/DataTable/DefaultTable";
23
54
  export * from "./components/Controls/DensityToggleButton";
24
55
  export * from "./components/Controls/EditFilterButton";
25
56
  export * from "./components/Controls/EditOrderButton";
26
57
  export * from "./components/Controls/EditSortingButton";
27
58
  export * from "./components/Controls/EditViewButton";
28
- export * from "./components/Filter/FilterOptions";
29
- export * from "./components/Filter/GlobalFilter";
30
59
  export * from "./components/Controls/PageSizeControl";
31
60
  export * from "./components/Controls/ResetFilteringButton";
32
61
  export * from "./components/Controls/ResetSelectionButton";
33
62
  export * from "./components/Controls/ResetSortingButton";
34
63
  export * from "./components/Controls/RowCountText";
64
+ export * from "./components/DataTable/DataTable";
65
+ export * from "./components/DataTable/DataTableServer";
66
+ export * from "./components/DataTable/DefaultTable";
35
67
  export * from "./components/DataTable/Table";
36
68
  export * from "./components/DataTable/TableBody";
37
69
  export * from "./components/DataTable/TableCardContainer";
@@ -52,3 +84,5 @@ export * from "./components/DataTable/TableViewer";
52
84
  export * from "./components/DataTable/TextCell";
53
85
  export * from "./components/DataTable/useDataFromUrl";
54
86
  export * from "./components/DataTable/useDataTable";
87
+ export * from "./components/Filter/FilterOptions";
88
+ export * from "./components/Filter/GlobalFilter";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsol-oss/react-datatable5",
3
- "version": "1.0.63",
3
+ "version": "1.0.64",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",