import React, { useEffect, useMemo, useRef, useState } from 'react'; import { getCoreRowModel, getExpandedRowModel, getFacetedRowModel, getFilteredRowModel, getGroupedRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table'; import Box from '@mui/material/Box'; import Dialog from '@mui/material/Dialog'; import Grow from '@mui/material/Grow'; import { MRT_ExpandAllButton } from '../buttons/MRT_ExpandAllButton'; import { MRT_ExpandButton } from '../buttons/MRT_ExpandButton'; import { MRT_ToggleRowActionMenuButton } from '../buttons/MRT_ToggleRowActionMenuButton'; import { MRT_SelectCheckbox } from '../inputs/MRT_SelectCheckbox'; import { MRT_TablePaper } from './MRT_TablePaper'; import { MRT_EditRowModal } from '../body/MRT_EditRowModal'; import { prepareColumns, getAllLeafColumnDefs, getDefaultColumnOrderIds, getDefaultColumnFilterFn, showExpandColumn, getColumnId, } from '../column.utils'; import type { MRT_Cell, MRT_Column, MRT_ColumnDef, MRT_FilterOption, MRT_Localization, MRT_Row, MRT_TableInstance, MRT_TableState, MaterialReactTableProps, MRT_DensityState, MRT_ColumnOrderState, MRT_GroupingState, } from '..'; export const MRT_TableRoot: any = = {}>( props: MaterialReactTableProps & { localization: MRT_Localization }, ): JSX.Element => { const bottomToolbarRef = useRef(null); const editInputRefs = useRef>({}); const filterInputRefs = useRef>({}); const searchInputRef = useRef(null); const tableContainerRef = useRef(null); const tableHeadCellRefs = useRef>({}); const tablePaperRef = useRef(null); const topToolbarRef = useRef(null); const initialState: Partial> = useMemo(() => { const initState = props.initialState ?? {}; initState.columnOrder = initState.columnOrder ?? getDefaultColumnOrderIds(props); initState.globalFilterFn = props.globalFilterFn ?? 'fuzzy'; return initState; }, []); const [columnFilterFns, setColumnFilterFns] = useState<{ [key: string]: MRT_FilterOption; }>(() => Object.assign( {}, ...getAllLeafColumnDefs(props.columns as MRT_ColumnDef[]).map( (col) => ({ [getColumnId(col)]: col.filterFn instanceof Function ? col.filterFn.name ?? 'custom' : col.filterFn ?? initialState?.columnFilterFns?.[getColumnId(col)] ?? getDefaultColumnFilterFn(col), }), ), ), ); const [columnOrder, setColumnOrder] = useState( initialState.columnOrder ?? [], ); const [density, setDensity] = useState( initialState?.density ?? 'comfortable', ); const [draggingColumn, setDraggingColumn] = useState | null>(initialState.draggingColumn ?? null); const [draggingRow, setDraggingRow] = useState | null>( initialState.draggingRow ?? null, ); const [editingCell, setEditingCell] = useState | null>( initialState.editingCell ?? null, ); const [editingRow, setEditingRow] = useState | null>( initialState.editingRow ?? null, ); const [globalFilterFn, setGlobalFilterFn] = useState( initialState.globalFilterFn ?? 'fuzzy', ); const [grouping, setGrouping] = useState( initialState.grouping ?? [], ); const [hoveredColumn, setHoveredColumn] = useState< MRT_Column | { id: string } | null >(initialState.hoveredColumn ?? null); const [hoveredRow, setHoveredRow] = useState< MRT_Row | { id: string } | null >(initialState.hoveredRow ?? null); const [isFullScreen, setIsFullScreen] = useState( initialState?.isFullScreen ?? false, ); const [showAlertBanner, setShowAlertBanner] = useState( props.initialState?.showAlertBanner ?? false, ); const [showColumnFilters, setShowFilters] = useState( initialState?.showColumnFilters ?? false, ); const [showGlobalFilter, setShowGlobalFilter] = useState( initialState?.showGlobalFilter ?? false, ); const [showToolbarDropZone, setShowToolbarDropZone] = useState( initialState?.showToolbarDropZone ?? false, ); const displayColumns = useMemo( () => ( [ (props.state?.columnOrder ?? columnOrder).includes( 'mrt-row-drag', ) && { header: props.localization.move, size: 60, ...props.defaultDisplayColumn, ...props.displayColumnDefOptions?.['mrt-row-drag'], id: 'mrt-row-drag', }, (props.state?.columnOrder ?? columnOrder).includes( 'mrt-row-actions', ) && { Cell: ({ cell, row }) => ( ), header: props.localization.actions, size: 70, ...props.defaultDisplayColumn, ...props.displayColumnDefOptions?.['mrt-row-actions'], id: 'mrt-row-actions', }, (props.state?.columnOrder ?? columnOrder).includes( 'mrt-row-expand', ) && showExpandColumn(props, props.state?.grouping ?? grouping) && { Cell: ({ row }) => ( ), Header: props.enableExpandAll ? () => : null, header: props.localization.expand, size: 60, ...props.defaultDisplayColumn, ...props.displayColumnDefOptions?.['mrt-row-expand'], id: 'mrt-row-expand', }, (props.state?.columnOrder ?? columnOrder).includes( 'mrt-row-select', ) && { Cell: ({ row }) => ( ), Header: props.enableSelectAll && props.enableMultiRowSelection ? () => : null, header: props.localization.select, size: 60, ...props.defaultDisplayColumn, ...props.displayColumnDefOptions?.['mrt-row-select'], id: 'mrt-row-select', }, (props.state?.columnOrder ?? columnOrder).includes( 'mrt-row-numbers', ) && { Cell: ({ row }) => row.index + 1, Header: () => props.localization.rowNumber, header: props.localization.rowNumbers, size: 60, ...props.defaultDisplayColumn, ...props.displayColumnDefOptions?.['mrt-row-numbers'], id: 'mrt-row-numbers', }, ] as MRT_ColumnDef[] ).filter(Boolean), [ columnOrder, grouping, props.displayColumnDefOptions, props.editingMode, props.enableColumnDragging, props.enableColumnFilterModes, props.enableColumnOrdering, props.enableEditing, props.enableExpandAll, props.enableExpanding, props.enableGrouping, props.enableRowActions, props.enableRowDragging, props.enableRowNumbers, props.enableRowOrdering, props.enableRowSelection, props.enableSelectAll, props.localization, props.positionActionsColumn, props.renderDetailPanel, props.state?.columnOrder, props.state?.grouping, ], ); const columnDefs = useMemo( () => prepareColumns({ aggregationFns: props.aggregationFns as any, columnDefs: [...displayColumns, ...props.columns], columnFilterFns: props.state?.columnFilterFns ?? columnFilterFns, defaultDisplayColumn: props.defaultDisplayColumn ?? {}, filterFns: props.filterFns as any, sortingFns: props.sortingFns as any, }), [ columnFilterFns, displayColumns, props.columns, props.state?.columnFilterFns, ], ); const data: TData[] = useMemo( () => (props.state?.isLoading || props.state?.showSkeletons) && !props.data.length ? [ ...Array( props.state?.pagination?.pageSize || initialState?.pagination?.pageSize || 10, ).fill(null), ].map(() => Object.assign( {}, ...getAllLeafColumnDefs(props.columns as MRT_ColumnDef[]).map( (col) => ({ [getColumnId(col)]: null, }), ), ), ) : props.data, [props.data, props.state?.isLoading, props.state?.showSkeletons], ); //@ts-ignore const table = { ...useReactTable({ getCoreRowModel: getCoreRowModel(), getExpandedRowModel: getExpandedRowModel(), getFacetedRowModel: getFacetedRowModel(), getFilteredRowModel: getFilteredRowModel(), getGroupedRowModel: getGroupedRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), onColumnOrderChange: setColumnOrder, onGroupingChange: setGrouping, getSubRows: (row) => row?.subRows, ...props, //@ts-ignore columns: columnDefs, data, globalFilterFn: props.filterFns?.[globalFilterFn] ?? props.filterFns?.fuzzy, initialState, state: { columnFilterFns, columnOrder, density, draggingColumn, draggingRow, editingCell, editingRow, globalFilterFn, grouping, hoveredColumn, hoveredRow, isFullScreen, showAlertBanner, showColumnFilters, showGlobalFilter, showToolbarDropZone, ...props.state, }, }), refs: { bottomToolbarRef, editInputRefs, filterInputRefs, searchInputRef, tableContainerRef, tableHeadCellRefs, tablePaperRef, topToolbarRef, }, setColumnFilterFns: props.onColumnFilterFnsChange ?? setColumnFilterFns, setDensity: props.onDensityChange ?? setDensity, setDraggingColumn: props.onDraggingColumnChange ?? setDraggingColumn, setDraggingRow: props.onDraggingRowChange ?? setDraggingRow, setEditingCell: props.onEditingCellChange ?? setEditingCell, setEditingRow: props.onEditingRowChange ?? setEditingRow, setGlobalFilterFn: props.onGlobalFilterFnChange ?? setGlobalFilterFn, setHoveredColumn: props.onHoveredColumnChange ?? setHoveredColumn, setHoveredRow: props.onHoveredRowChange ?? setHoveredRow, setIsFullScreen: props.onIsFullScreenChange ?? setIsFullScreen, setShowAlertBanner: props.onShowAlertBannerChange ?? setShowAlertBanner, setShowFilters: props.onShowFiltersChange ?? setShowFilters, setShowGlobalFilter: props.onShowGlobalFilterChange ?? setShowGlobalFilter, setShowToolbarDropZone: props.onShowToolbarDropZoneChange ?? setShowToolbarDropZone, } as MRT_TableInstance; if (props.tableFeatures) { props.tableFeatures.forEach((feature) => { Object.assign(table, feature(table)); }); } if (props.tableInstanceRef) { props.tableInstanceRef.current = table; } const initialBodyHeight = useRef(); useEffect(() => { if (typeof window !== 'undefined') { initialBodyHeight.current = document.body.style.height; } }, []); useEffect(() => { if (typeof window !== 'undefined') { if (table.getState().isFullScreen) { document.body.style.height = '100vh'; } else { document.body.style.height = initialBodyHeight.current as string; } } }, [table.getState().isFullScreen]); return ( <> table.setIsFullScreen(false)} open={table.getState().isFullScreen} transitionDuration={400} > {!table.getState().isFullScreen && ( )} {editingRow && props.editingMode === 'modal' && ( )} ); };