mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 07:15:44 +00:00
chore: add new props (withPagination, getRowCanExpand, renderSubComponent, expanded, and getSubRows)
This commit is contained in:
+116
-55
@@ -1,11 +1,12 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ReactNode, useCallback, useEffect, useState } from 'react';
|
import { Fragment, ReactNode, useCallback, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
getFilteredRowModel,
|
getFilteredRowModel,
|
||||||
getPaginationRowModel,
|
getPaginationRowModel,
|
||||||
|
getExpandedRowModel,
|
||||||
getSortedRowModel,
|
getSortedRowModel,
|
||||||
TableOptions,
|
TableOptions,
|
||||||
useReactTable,
|
useReactTable,
|
||||||
@@ -15,6 +16,7 @@ import {
|
|||||||
OnChangeFn,
|
OnChangeFn,
|
||||||
Row,
|
Row,
|
||||||
HeaderContext,
|
HeaderContext,
|
||||||
|
ExpandedState,
|
||||||
} from '@tanstack/react-table';
|
} from '@tanstack/react-table';
|
||||||
import { rankItem } from '@tanstack/match-sorter-utils';
|
import { rankItem } from '@tanstack/match-sorter-utils';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
@@ -33,6 +35,9 @@ interface TableClassNames {
|
|||||||
bodyRowClassName?: string;
|
bodyRowClassName?: string;
|
||||||
selectedBodyRowClassName?: string;
|
selectedBodyRowClassName?: string;
|
||||||
bodyColumnClassName?: string;
|
bodyColumnClassName?: string;
|
||||||
|
bodySubRowClassName?: (depth: number) => string;
|
||||||
|
selectedBodySubRowClassName?: (depth: number) => string;
|
||||||
|
bodySubRowColumnClassName?: (depth: number) => string;
|
||||||
tableFooterClassName?: string;
|
tableFooterClassName?: string;
|
||||||
footerRowClassName?: string;
|
footerRowClassName?: string;
|
||||||
footerColumnClassName?: string;
|
footerColumnClassName?: string;
|
||||||
@@ -60,6 +65,7 @@ export interface TableProps<TData extends object> {
|
|||||||
enableRowSelection?: boolean | ((row: Row<TData>) => boolean);
|
enableRowSelection?: boolean | ((row: Row<TData>) => boolean);
|
||||||
renderFooter?: boolean;
|
renderFooter?: boolean;
|
||||||
withCheckbox?: boolean;
|
withCheckbox?: boolean;
|
||||||
|
withPagination?: boolean;
|
||||||
rowOptions?: number[];
|
rowOptions?: number[];
|
||||||
/**
|
/**
|
||||||
* Custom row renderer. Should return a complete <tr> element or null.
|
* Custom row renderer. Should return a complete <tr> element or null.
|
||||||
@@ -67,6 +73,10 @@ export interface TableProps<TData extends object> {
|
|||||||
* Return null to render the default row.
|
* Return null to render the default row.
|
||||||
*/
|
*/
|
||||||
renderCustomRow?: (row: Row<TData>) => ReactNode | null;
|
renderCustomRow?: (row: Row<TData>) => ReactNode | null;
|
||||||
|
getRowCanExpand?: (row: Row<TData>) => boolean;
|
||||||
|
renderSubComponent?: (props: { row: Row<TData> }) => React.ReactElement;
|
||||||
|
expanded?: ExpandedState;
|
||||||
|
getSubRows?: (originalRow: TData, index: number) => TData[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}];
|
const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}];
|
||||||
@@ -92,7 +102,12 @@ export const TABLE_DEFAULT_STYLING = {
|
|||||||
bodyRowClassName:
|
bodyRowClassName:
|
||||||
'transition-all duration-200 border-t border-base-content/10 bg-transparent',
|
'transition-all duration-200 border-t border-base-content/10 bg-transparent',
|
||||||
selectedBodyRowClassName: 'bg-primary/5',
|
selectedBodyRowClassName: 'bg-primary/5',
|
||||||
bodyColumnClassName: 'px-4 py-3 text-base-content',
|
bodyColumnClassName: 'px-4 py-3 text-base-content font-medium',
|
||||||
|
bodySubRowClassName: (depth: number) =>
|
||||||
|
'transition-all duration-200 border-t border-base-content/10 bg-transparent',
|
||||||
|
selectedBodySubRowClassName: (depth: number) => 'bg-primary/5',
|
||||||
|
bodySubRowColumnClassName: (depth: number) =>
|
||||||
|
'px-4 py-3 text-base-content font-medium',
|
||||||
paginationClassName: 'px-3',
|
paginationClassName: 'px-3',
|
||||||
tableFooterClassName: 'font-semibold border-base-content/10',
|
tableFooterClassName: 'font-semibold border-base-content/10',
|
||||||
footerRowClassName: 'bg-base-200 border-t-2 border-base-content/10',
|
footerRowClassName: 'bg-base-200 border-t-2 border-base-content/10',
|
||||||
@@ -120,8 +135,13 @@ const Table = <TData extends object>({
|
|||||||
enableRowSelection,
|
enableRowSelection,
|
||||||
renderFooter = false,
|
renderFooter = false,
|
||||||
withCheckbox = false,
|
withCheckbox = false,
|
||||||
|
withPagination = true,
|
||||||
rowOptions = [10, 20, 50, 100],
|
rowOptions = [10, 20, 50, 100],
|
||||||
renderCustomRow,
|
renderCustomRow,
|
||||||
|
getRowCanExpand,
|
||||||
|
renderSubComponent,
|
||||||
|
expanded = {},
|
||||||
|
getSubRows,
|
||||||
}: TableProps<TData>) => {
|
}: TableProps<TData>) => {
|
||||||
const isServerSideTable =
|
const isServerSideTable =
|
||||||
totalItems !== undefined &&
|
totalItems !== undefined &&
|
||||||
@@ -154,10 +174,14 @@ const Table = <TData extends object>({
|
|||||||
getSortedRowModel: getSortedRowModel(),
|
getSortedRowModel: getSortedRowModel(),
|
||||||
getPaginationRowModel: getPaginationRowModel(),
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
onPaginationChange: setPagination,
|
onPaginationChange: setPagination,
|
||||||
|
getExpandedRowModel: getExpandedRowModel(),
|
||||||
|
getRowCanExpand: getRowCanExpand ?? (getSubRows ? undefined : () => false),
|
||||||
|
getSubRows,
|
||||||
manualSorting,
|
manualSorting,
|
||||||
state: {
|
state: {
|
||||||
pagination,
|
pagination,
|
||||||
globalFilter: fuzzySearchValue,
|
globalFilter: fuzzySearchValue,
|
||||||
|
expanded,
|
||||||
},
|
},
|
||||||
filterFns: {
|
filterFns: {
|
||||||
fuzzy: fuzzyFilter,
|
fuzzy: fuzzyFilter,
|
||||||
@@ -228,7 +252,10 @@ const Table = <TData extends object>({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
TABLE_DEFAULT_STYLING.containerClassName,
|
TABLE_DEFAULT_STYLING.containerClassName,
|
||||||
tableClassNames.containerClassName
|
tableClassNames.containerClassName,
|
||||||
|
{
|
||||||
|
'mb-0': !withPagination,
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -352,36 +379,67 @@ const Table = <TData extends object>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<Fragment key={row.id}>
|
||||||
key={row.id}
|
<tr
|
||||||
className={cn(
|
data-depth={row.depth}
|
||||||
TABLE_DEFAULT_STYLING.bodyRowClassName,
|
className={cn(
|
||||||
tableClassNames.bodyRowClassName,
|
row.depth > 0
|
||||||
{
|
? tableClassNames.bodySubRowClassName(row.depth)
|
||||||
[tableClassNames.selectedBodyRowClassName]:
|
: tableClassNames.bodyRowClassName,
|
||||||
row.getIsSelected(),
|
{
|
||||||
}
|
[tableClassNames.selectedBodyRowClassName!]:
|
||||||
)}
|
row.getIsSelected() && row.depth === 0,
|
||||||
>
|
[tableClassNames.selectedBodySubRowClassName(
|
||||||
{row.getVisibleCells().map((cell) => (
|
row.depth
|
||||||
<td
|
)!]: row.getIsSelected() && row.depth > 0,
|
||||||
key={cell.id}
|
}
|
||||||
className={cn(
|
)}
|
||||||
{ 'first:w-9 first:pr-0': withCheckbox },
|
>
|
||||||
TABLE_DEFAULT_STYLING.bodyColumnClassName,
|
{row.getVisibleCells().map((cell) => (
|
||||||
tableClassNames.bodyColumnClassName
|
<td
|
||||||
)}
|
key={cell.id}
|
||||||
>
|
className={cn(
|
||||||
{!isLoading &&
|
{ 'first:w-9 first:pr-0': withCheckbox },
|
||||||
flexRender(
|
TABLE_DEFAULT_STYLING.bodyColumnClassName,
|
||||||
cell.column.columnDef.cell,
|
row.depth > 0
|
||||||
cell.getContext()
|
? tableClassNames.bodySubRowColumnClassName(
|
||||||
|
row.depth
|
||||||
|
)
|
||||||
|
: tableClassNames.bodyColumnClassName
|
||||||
)}
|
)}
|
||||||
|
>
|
||||||
|
{!isLoading &&
|
||||||
|
flexRender(
|
||||||
|
cell.column.columnDef.cell,
|
||||||
|
cell.getContext()
|
||||||
|
)}
|
||||||
|
|
||||||
{isLoading && <div className='skeleton w-full h-4' />}
|
{isLoading && <div className='skeleton w-full h-4' />}
|
||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
{row.getIsExpanded() && (
|
||||||
|
<>
|
||||||
|
{renderSubComponent && (
|
||||||
|
<tr
|
||||||
|
className={cn(
|
||||||
|
TABLE_DEFAULT_STYLING.bodySubRowClassName(1),
|
||||||
|
tableClassNames.bodySubRowClassName(1),
|
||||||
|
{
|
||||||
|
[tableClassNames.selectedBodySubRowClassName(1)]:
|
||||||
|
row.getIsSelected(),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<td colSpan={row.getVisibleCells().length}>
|
||||||
|
{renderSubComponent({ row })}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -425,30 +483,33 @@ const Table = <TData extends object>({
|
|||||||
!isLoading &&
|
!isLoading &&
|
||||||
emptyContent}
|
emptyContent}
|
||||||
|
|
||||||
{data.length > 0 && table.getRowModel().rows.length > 0 && !isLoading && (
|
{data.length > 0 &&
|
||||||
<div
|
table.getRowModel().rows.length > 0 &&
|
||||||
className={cn(
|
!isLoading &&
|
||||||
'mt-5',
|
withPagination && (
|
||||||
TABLE_DEFAULT_STYLING.paginationClassName,
|
<div
|
||||||
tableClassNames.paginationClassName
|
className={cn(
|
||||||
)}
|
'mt-5',
|
||||||
>
|
TABLE_DEFAULT_STYLING.paginationClassName,
|
||||||
<Pagination
|
tableClassNames.paginationClassName
|
||||||
totalItems={isServerSideTable ? totalItems : table.getRowCount()}
|
)}
|
||||||
itemsPerPage={table.getState().pagination.pageSize}
|
>
|
||||||
currentPage={
|
<Pagination
|
||||||
isServerSideTable
|
totalItems={isServerSideTable ? totalItems : table.getRowCount()}
|
||||||
? page
|
itemsPerPage={table.getState().pagination.pageSize}
|
||||||
: table.getState().pagination.pageIndex + 1
|
currentPage={
|
||||||
}
|
isServerSideTable
|
||||||
onPrevPage={prevPageClickHandler}
|
? page
|
||||||
onNextPage={nextPageClickHandler}
|
: table.getState().pagination.pageIndex + 1
|
||||||
onPageChange={pageChangeHandler}
|
}
|
||||||
rowOptions={rowOptions}
|
onPrevPage={prevPageClickHandler}
|
||||||
onRowChange={onPageSizeChange}
|
onNextPage={nextPageClickHandler}
|
||||||
/>
|
onPageChange={pageChangeHandler}
|
||||||
</div>
|
rowOptions={rowOptions}
|
||||||
)}
|
onRowChange={onPageSizeChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user