2022-10-24 13:12:53 +11:00
|
|
|
|
import { useMemo, useRef, useCallback, useState, useEffect } from "react";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
import { useAtom, useSetAtom } from "jotai";
|
2022-10-24 13:12:53 +11:00
|
|
|
|
import {
|
|
|
|
|
|
useDebounce,
|
|
|
|
|
|
useDebouncedCallback,
|
|
|
|
|
|
useThrottledCallback,
|
|
|
|
|
|
} from "use-debounce";
|
|
|
|
|
|
import { useSnackbar } from "notistack";
|
|
|
|
|
|
import useMemoValue from "use-memo-value";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
import { DndProvider } from "react-dnd";
|
|
|
|
|
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
2022-10-24 13:12:53 +11:00
|
|
|
|
import { isEmpty, isEqual } from "lodash-es";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
2022-10-14 16:15:41 +11:00
|
|
|
|
import {
|
|
|
|
|
|
createColumnHelper,
|
|
|
|
|
|
flexRender,
|
|
|
|
|
|
getCoreRowModel,
|
|
|
|
|
|
useReactTable,
|
|
|
|
|
|
} from "@tanstack/react-table";
|
2022-10-18 17:53:47 +11:00
|
|
|
|
import { useVirtual } from "react-virtual";
|
2022-10-14 16:15:41 +11:00
|
|
|
|
|
|
|
|
|
|
import { TOP_BAR_HEIGHT } from "@src/layouts/Navigation/TopBar";
|
|
|
|
|
|
import { TABLE_TOOLBAR_HEIGHT } from "@src/components/TableToolbar";
|
|
|
|
|
|
import { StyledTable } from "./Styled/StyledTable";
|
|
|
|
|
|
import { StyledRow } from "./Styled/StyledRow";
|
2022-10-24 13:12:53 +11:00
|
|
|
|
import { StyledResizer } from "./Styled/StyledResizer";
|
2022-10-14 16:15:41 +11:00
|
|
|
|
import ColumnHeaderComponent from "./Column";
|
|
|
|
|
|
|
2022-10-24 13:12:53 +11:00
|
|
|
|
import { IconButton, LinearProgress, Button } from "@mui/material";
|
|
|
|
|
|
import { LoadingButton } from "@mui/lab";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
import TableContainer, { OUT_OF_ORDER_MARGIN } from "./TableContainer";
|
2022-05-27 15:10:06 +10:00
|
|
|
|
import ColumnHeader, { COLUMN_HEADER_HEIGHT } from "./ColumnHeader";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
import FinalColumnHeader from "./FinalColumnHeader";
|
|
|
|
|
|
import FinalColumn from "./formatters/FinalColumn";
|
2022-10-14 16:15:41 +11:00
|
|
|
|
// import TableRow from "./TableRow";
|
2022-05-27 15:10:06 +10:00
|
|
|
|
import EmptyState from "@src/components/EmptyState";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
// import BulkActions from "./BulkActions";
|
2022-05-27 15:10:06 +10:00
|
|
|
|
import AddRow from "@src/components/TableToolbar/AddRow";
|
2022-06-02 14:55:47 +10:00
|
|
|
|
import { AddRow as AddRowIcon } from "@src/assets/icons";
|
2022-06-06 15:58:17 +10:00
|
|
|
|
import Loading from "@src/components/Loading";
|
|
|
|
|
|
import ContextMenu from "./ContextMenu";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
import {
|
2022-07-18 14:40:46 +10:00
|
|
|
|
projectScope,
|
2022-05-19 16:37:56 +10:00
|
|
|
|
userRolesAtom,
|
|
|
|
|
|
userSettingsAtom,
|
2022-07-18 14:40:46 +10:00
|
|
|
|
} from "@src/atoms/projectScope";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
import {
|
|
|
|
|
|
tableScope,
|
|
|
|
|
|
tableIdAtom,
|
|
|
|
|
|
tableSettingsAtom,
|
|
|
|
|
|
tableSchemaAtom,
|
|
|
|
|
|
tableColumnsOrderedAtom,
|
|
|
|
|
|
tableRowsAtom,
|
2022-05-30 12:48:27 +10:00
|
|
|
|
tableNextPageAtom,
|
2022-05-19 16:37:56 +10:00
|
|
|
|
tablePageAtom,
|
|
|
|
|
|
updateColumnAtom,
|
|
|
|
|
|
updateFieldAtom,
|
2022-06-02 17:36:30 +10:00
|
|
|
|
selectedCellAtom,
|
2022-10-17 17:57:26 +11:00
|
|
|
|
SelectedCell,
|
2022-05-19 16:37:56 +10:00
|
|
|
|
} from "@src/atoms/tableScope";
|
2022-10-17 17:57:26 +11:00
|
|
|
|
import { COLLECTION_PAGE_SIZE } from "@src/config/db";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
2022-05-24 20:34:28 +10:00
|
|
|
|
import { getFieldType, getFieldProp } from "@src/components/fields";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
import { FieldType } from "@src/constants/fields";
|
|
|
|
|
|
import { formatSubTableName } from "@src/utils/table";
|
2022-10-14 16:15:41 +11:00
|
|
|
|
import { TableRow, ColumnConfig } from "@src/types/table";
|
|
|
|
|
|
import { StyledCell } from "./Styled/StyledCell";
|
2022-10-18 17:53:47 +11:00
|
|
|
|
import { useKeyboardNavigation } from "./useKeyboardNavigation";
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
export const DEFAULT_ROW_HEIGHT = 41;
|
2022-06-13 16:02:38 +10:00
|
|
|
|
export const DEFAULT_COL_WIDTH = 150;
|
2022-10-24 13:12:53 +11:00
|
|
|
|
export const MIN_COL_WIDTH = 32;
|
2022-10-21 14:58:25 +11:00
|
|
|
|
export const TABLE_PADDING = 16;
|
|
|
|
|
|
export const TABLE_GUTTER = 8;
|
2022-10-24 13:12:53 +11:00
|
|
|
|
export const DEBOUNCE_DELAY = 500;
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
2022-10-14 16:15:41 +11:00
|
|
|
|
declare module "@tanstack/table-core" {
|
|
|
|
|
|
interface ColumnMeta<TData, TValue> extends ColumnConfig {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const columnHelper = createColumnHelper<TableRow>();
|
|
|
|
|
|
const getRowId = (row: TableRow) => row._rowy_ref.path || row._rowy_ref.id;
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
2022-10-14 16:15:41 +11:00
|
|
|
|
export default function TableComponent() {
|
2022-10-24 13:12:53 +11:00
|
|
|
|
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
|
|
|
|
|
|
2022-07-18 14:40:46 +10:00
|
|
|
|
const [userRoles] = useAtom(userRolesAtom, projectScope);
|
|
|
|
|
|
const [userSettings] = useAtom(userSettingsAtom, projectScope);
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
const [tableId] = useAtom(tableIdAtom, tableScope);
|
|
|
|
|
|
const [tableSettings] = useAtom(tableSettingsAtom, tableScope);
|
|
|
|
|
|
const [tableSchema] = useAtom(tableSchemaAtom, tableScope);
|
|
|
|
|
|
const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope);
|
|
|
|
|
|
const [tableRows] = useAtom(tableRowsAtom, tableScope);
|
2022-05-30 12:48:27 +10:00
|
|
|
|
const [tableNextPage] = useAtom(tableNextPageAtom, tableScope);
|
|
|
|
|
|
const setTablePage = useSetAtom(tablePageAtom, tableScope);
|
2022-06-03 18:17:27 +10:00
|
|
|
|
const [selectedCell, setSelectedCell] = useAtom(selectedCellAtom, tableScope);
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
const updateColumn = useSetAtom(updateColumnAtom, tableScope);
|
|
|
|
|
|
const updateField = useSetAtom(updateFieldAtom, tableScope);
|
|
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
2022-10-17 17:57:26 +11:00
|
|
|
|
const gridRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
|
2022-10-14 16:15:41 +11:00
|
|
|
|
const canAddColumn = userRoles.includes("ADMIN");
|
2022-10-17 17:57:26 +11:00
|
|
|
|
const canEditColumn = userRoles.includes("ADMIN");
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
2022-10-14 16:15:41 +11:00
|
|
|
|
// Get column defs from table schema
|
|
|
|
|
|
// Also add end column for admins
|
2022-05-19 16:37:56 +10:00
|
|
|
|
const columns = useMemo(() => {
|
2022-10-14 16:15:41 +11:00
|
|
|
|
const _columns = tableColumnsOrdered
|
2022-10-19 12:41:20 +11:00
|
|
|
|
// Hide column for all users using table schema
|
|
|
|
|
|
.filter((column) => !column.hidden)
|
2022-10-14 16:15:41 +11:00
|
|
|
|
.map((columnConfig) =>
|
|
|
|
|
|
columnHelper.accessor(columnConfig.fieldName, {
|
2022-10-17 17:57:26 +11:00
|
|
|
|
id: columnConfig.fieldName,
|
2022-10-14 16:15:41 +11:00
|
|
|
|
meta: columnConfig,
|
2022-10-24 13:12:53 +11:00
|
|
|
|
size: columnConfig.width,
|
|
|
|
|
|
enableResizing: columnConfig.resizable !== false,
|
|
|
|
|
|
minSize: MIN_COL_WIDTH,
|
2022-10-14 16:15:41 +11:00
|
|
|
|
// draggable: true,
|
|
|
|
|
|
// resizable: true,
|
|
|
|
|
|
// frozen: columnConfig.fixed,
|
|
|
|
|
|
// headerRenderer: ColumnHeader,
|
|
|
|
|
|
// formatter:
|
|
|
|
|
|
// getFieldProp("TableCell", getFieldType(columnConfig)) ??
|
|
|
|
|
|
// function InDev() {
|
|
|
|
|
|
// return null;
|
|
|
|
|
|
// },
|
|
|
|
|
|
// editor:
|
|
|
|
|
|
// getFieldProp("TableEditor", getFieldType(columnConfig)) ??
|
|
|
|
|
|
// function InDev() {
|
|
|
|
|
|
// return null;
|
|
|
|
|
|
// },
|
|
|
|
|
|
// ...columnConfig,
|
|
|
|
|
|
// editable:
|
|
|
|
|
|
// tableSettings.readOnly && !userRoles.includes("ADMIN")
|
|
|
|
|
|
// ? false
|
|
|
|
|
|
// : columnConfig.editable ?? true,
|
|
|
|
|
|
// width: columnConfig.width ?? DEFAULT_COL_WIDTH,
|
|
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2022-10-19 12:41:20 +11:00
|
|
|
|
if (canAddColumn || !tableSettings.readOnly) {
|
|
|
|
|
|
_columns.push(
|
|
|
|
|
|
columnHelper.display({
|
|
|
|
|
|
id: "_rowy_column_actions",
|
|
|
|
|
|
header: () => "Actions",
|
2022-10-21 14:58:25 +11:00
|
|
|
|
cell: () => (
|
|
|
|
|
|
<>
|
|
|
|
|
|
<IconButton>M</IconButton>
|
|
|
|
|
|
<IconButton>D</IconButton>
|
|
|
|
|
|
<IconButton>X</IconButton>
|
|
|
|
|
|
</>
|
|
|
|
|
|
),
|
2022-10-19 12:41:20 +11:00
|
|
|
|
})
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
return _columns;
|
2022-10-19 12:41:20 +11:00
|
|
|
|
}, [tableColumnsOrdered, canAddColumn, tableSettings.readOnly]);
|
|
|
|
|
|
|
|
|
|
|
|
// Get user’s hidden columns from user document
|
|
|
|
|
|
const userDocHiddenFields =
|
|
|
|
|
|
userSettings.tables?.[formatSubTableName(tableId)]?.hiddenFields;
|
|
|
|
|
|
// Memoize into a VisibilityState
|
|
|
|
|
|
const columnVisibility = useMemo(() => {
|
|
|
|
|
|
if (!Array.isArray(userDocHiddenFields)) return {};
|
|
|
|
|
|
return userDocHiddenFields.reduce((a, c) => ({ ...a, [c]: false }), {});
|
|
|
|
|
|
}, [userDocHiddenFields]);
|
2022-06-03 18:17:27 +10:00
|
|
|
|
|
2022-10-21 14:58:25 +11:00
|
|
|
|
// Get frozen columns
|
|
|
|
|
|
const columnPinning = useMemo(
|
|
|
|
|
|
() => ({
|
|
|
|
|
|
left: columns.filter((c) => c.meta?.fixed && c.id).map((c) => c.id!),
|
|
|
|
|
|
}),
|
|
|
|
|
|
[columns]
|
|
|
|
|
|
);
|
|
|
|
|
|
const lastFrozen: string | undefined =
|
|
|
|
|
|
columnPinning.left[columnPinning.left.length - 1];
|
|
|
|
|
|
|
2022-10-24 13:12:53 +11:00
|
|
|
|
// Call TanStack Table
|
2022-10-14 16:15:41 +11:00
|
|
|
|
const table = useReactTable({
|
|
|
|
|
|
data: tableRows,
|
|
|
|
|
|
columns,
|
|
|
|
|
|
getCoreRowModel: getCoreRowModel(),
|
|
|
|
|
|
getRowId,
|
|
|
|
|
|
columnResizeMode: "onChange",
|
|
|
|
|
|
});
|
2022-10-24 13:12:53 +11:00
|
|
|
|
|
|
|
|
|
|
const [columnSizing, setColumnSizing] = useState(
|
|
|
|
|
|
table.initialState.columnSizing
|
|
|
|
|
|
);
|
|
|
|
|
|
table.setOptions((prev) => ({
|
|
|
|
|
|
...prev,
|
|
|
|
|
|
state: { ...prev.state, columnVisibility, columnPinning, columnSizing },
|
|
|
|
|
|
onColumnSizingChange: setColumnSizing,
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// Debounce for saving to schema
|
|
|
|
|
|
const [debouncedColumnSizing] = useDebounce(columnSizing, DEBOUNCE_DELAY, {
|
|
|
|
|
|
equalityFn: isEqual,
|
|
|
|
|
|
});
|
|
|
|
|
|
// Offer to save when column sizing changes
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!canEditColumn || isEmpty(debouncedColumnSizing)) return;
|
|
|
|
|
|
|
|
|
|
|
|
const snackbarId = enqueueSnackbar("Save column sizes for all users?", {
|
|
|
|
|
|
action: (
|
|
|
|
|
|
<LoadingButton
|
|
|
|
|
|
variant="contained"
|
|
|
|
|
|
color="primary"
|
|
|
|
|
|
onClick={handleSaveToSchema}
|
|
|
|
|
|
>
|
|
|
|
|
|
Save
|
|
|
|
|
|
</LoadingButton>
|
|
|
|
|
|
),
|
|
|
|
|
|
anchorOrigin: { horizontal: "center", vertical: "top" },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
async function handleSaveToSchema() {
|
|
|
|
|
|
const promises = Object.entries(debouncedColumnSizing).map(
|
|
|
|
|
|
([key, value]) => updateColumn({ key, config: { width: value } })
|
|
|
|
|
|
);
|
|
|
|
|
|
await Promise.all(promises);
|
|
|
|
|
|
closeSnackbar(snackbarId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return () => closeSnackbar(snackbarId);
|
|
|
|
|
|
}, [
|
|
|
|
|
|
debouncedColumnSizing,
|
|
|
|
|
|
canEditColumn,
|
|
|
|
|
|
enqueueSnackbar,
|
|
|
|
|
|
closeSnackbar,
|
|
|
|
|
|
updateColumn,
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
const { rows } = table.getRowModel();
|
2022-10-19 12:41:20 +11:00
|
|
|
|
const leafColumns = table.getVisibleLeafColumns();
|
2022-10-18 14:49:17 +11:00
|
|
|
|
// console.log(table, selectedCell);
|
2022-10-17 17:57:26 +11:00
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
const {
|
|
|
|
|
|
virtualItems: virtualRows,
|
|
|
|
|
|
totalSize: totalHeight,
|
|
|
|
|
|
scrollToIndex: scrollToRowIndex,
|
|
|
|
|
|
} = useVirtual({
|
|
|
|
|
|
parentRef: containerRef,
|
|
|
|
|
|
size: tableRows.length,
|
|
|
|
|
|
overscan: 10,
|
2022-10-21 14:58:25 +11:00
|
|
|
|
paddingEnd: TABLE_PADDING,
|
2022-10-18 17:53:47 +11:00
|
|
|
|
estimateSize: useCallback(
|
|
|
|
|
|
() => tableSchema.rowHeight || DEFAULT_ROW_HEIGHT,
|
|
|
|
|
|
[tableSchema.rowHeight]
|
|
|
|
|
|
),
|
|
|
|
|
|
});
|
2022-10-18 14:49:17 +11:00
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
const {
|
|
|
|
|
|
virtualItems: virtualCols,
|
|
|
|
|
|
totalSize: totalWidth,
|
|
|
|
|
|
scrollToIndex: scrollToColIndex,
|
|
|
|
|
|
} = useVirtual({
|
|
|
|
|
|
parentRef: containerRef,
|
|
|
|
|
|
horizontal: true,
|
2022-10-19 12:41:20 +11:00
|
|
|
|
size: leafColumns.length,
|
2022-10-21 14:58:25 +11:00
|
|
|
|
overscan: 10,
|
|
|
|
|
|
paddingStart: TABLE_PADDING,
|
|
|
|
|
|
paddingEnd: TABLE_PADDING,
|
2022-10-18 17:53:47 +11:00
|
|
|
|
estimateSize: useCallback(
|
2022-10-19 12:41:20 +11:00
|
|
|
|
(index: number) => leafColumns[index].columnDef.size || DEFAULT_COL_WIDTH,
|
|
|
|
|
|
[leafColumns]
|
2022-10-18 17:53:47 +11:00
|
|
|
|
),
|
|
|
|
|
|
});
|
2022-10-18 14:49:17 +11:00
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!selectedCell) return;
|
|
|
|
|
|
if (selectedCell.path) {
|
|
|
|
|
|
const rowIndex = tableRows.findIndex(
|
|
|
|
|
|
(row) => row._rowy_ref.path === selectedCell.path
|
|
|
|
|
|
);
|
2022-10-21 14:58:25 +11:00
|
|
|
|
if (rowIndex > -1) scrollToRowIndex(rowIndex);
|
2022-10-17 17:57:26 +11:00
|
|
|
|
}
|
2022-10-18 17:53:47 +11:00
|
|
|
|
if (selectedCell.columnKey) {
|
2022-10-19 12:41:20 +11:00
|
|
|
|
const colIndex = leafColumns.findIndex(
|
2022-10-18 17:53:47 +11:00
|
|
|
|
(col) => col.id === selectedCell.columnKey
|
|
|
|
|
|
);
|
2022-10-21 14:58:25 +11:00
|
|
|
|
if (colIndex > -1) scrollToColIndex(colIndex);
|
2022-10-18 17:53:47 +11:00
|
|
|
|
}
|
2022-10-19 12:41:20 +11:00
|
|
|
|
}, [
|
|
|
|
|
|
selectedCell,
|
|
|
|
|
|
tableRows,
|
|
|
|
|
|
leafColumns,
|
|
|
|
|
|
scrollToRowIndex,
|
|
|
|
|
|
scrollToColIndex,
|
|
|
|
|
|
]);
|
2022-10-18 17:53:47 +11:00
|
|
|
|
|
|
|
|
|
|
const { handleKeyDown, focusInsideCell } = useKeyboardNavigation({
|
|
|
|
|
|
gridRef,
|
|
|
|
|
|
tableRows,
|
2022-10-19 12:41:20 +11:00
|
|
|
|
leafColumns,
|
2022-10-18 17:53:47 +11:00
|
|
|
|
});
|
2022-10-17 17:57:26 +11:00
|
|
|
|
|
2022-10-18 17:53:47 +11:00
|
|
|
|
const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0;
|
|
|
|
|
|
const paddingBottom =
|
|
|
|
|
|
virtualRows.length > 0
|
|
|
|
|
|
? totalHeight - (virtualRows?.[virtualRows.length - 1]?.end || 0)
|
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
|
|
const paddingLeft = virtualCols.length > 0 ? virtualCols?.[0]?.start || 0 : 0;
|
|
|
|
|
|
const paddingRight =
|
|
|
|
|
|
virtualCols.length > 0
|
|
|
|
|
|
? totalWidth - (virtualCols?.[virtualCols.length - 1]?.end || 0)
|
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
|
|
const fetchMoreOnBottomReached = useThrottledCallback(
|
|
|
|
|
|
(containerElement?: HTMLDivElement | null) => {
|
|
|
|
|
|
if (!containerElement) return;
|
|
|
|
|
|
|
|
|
|
|
|
const { scrollHeight, scrollTop, clientHeight } = containerElement;
|
|
|
|
|
|
if (scrollHeight - scrollTop - clientHeight < 300) {
|
|
|
|
|
|
setTablePage((p) => p + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2022-10-24 13:12:53 +11:00
|
|
|
|
DEBOUNCE_DELAY
|
2022-10-18 17:53:47 +11:00
|
|
|
|
);
|
2022-05-19 16:37:56 +10:00
|
|
|
|
|
|
|
|
|
|
return (
|
2022-10-18 17:53:47 +11:00
|
|
|
|
<div
|
|
|
|
|
|
ref={containerRef}
|
2022-10-19 12:54:31 +11:00
|
|
|
|
onScroll={(e) => fetchMoreOnBottomReached(e.target as HTMLDivElement)}
|
2022-10-18 17:53:47 +11:00
|
|
|
|
style={{ overflow: "auto", width: "100%", height: "100%" }}
|
|
|
|
|
|
>
|
2022-10-14 16:15:41 +11:00
|
|
|
|
<StyledTable
|
2022-10-17 17:57:26 +11:00
|
|
|
|
ref={gridRef}
|
2022-10-14 16:15:41 +11:00
|
|
|
|
role="grid"
|
2022-10-17 17:57:26 +11:00
|
|
|
|
aria-readonly={tableSettings.readOnly}
|
|
|
|
|
|
aria-colcount={columns.length}
|
|
|
|
|
|
aria-rowcount={tableRows.length + 1}
|
2022-10-19 12:54:31 +11:00
|
|
|
|
style={{ width: table.getTotalSize(), userSelect: "none" }}
|
2022-10-14 16:15:41 +11:00
|
|
|
|
onKeyDown={handleKeyDown}
|
|
|
|
|
|
>
|
2022-10-17 17:57:26 +11:00
|
|
|
|
<div
|
|
|
|
|
|
className="thead"
|
|
|
|
|
|
role="rowgroup"
|
2022-10-21 14:58:25 +11:00
|
|
|
|
style={{
|
|
|
|
|
|
position: "sticky",
|
|
|
|
|
|
top: 0,
|
|
|
|
|
|
zIndex: 10,
|
|
|
|
|
|
padding: `0 ${TABLE_PADDING}px`,
|
|
|
|
|
|
}}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
>
|
2022-10-14 16:15:41 +11:00
|
|
|
|
{table.getHeaderGroups().map((headerGroup) => (
|
2022-10-17 17:57:26 +11:00
|
|
|
|
<StyledRow key={headerGroup.id} role="row" aria-rowindex={1}>
|
|
|
|
|
|
{headerGroup.headers.map((header) => {
|
2022-10-18 14:49:17 +11:00
|
|
|
|
const isSelectedCell =
|
2022-10-17 17:57:26 +11:00
|
|
|
|
(!selectedCell && header.index === 0) ||
|
|
|
|
|
|
(selectedCell?.path === "_rowy_header" &&
|
|
|
|
|
|
selectedCell?.columnKey === header.id);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<ColumnHeaderComponent
|
|
|
|
|
|
key={header.id}
|
2022-10-21 14:58:25 +11:00
|
|
|
|
data-row-id={"_rowy_header"}
|
|
|
|
|
|
data-col-id={header.id}
|
|
|
|
|
|
data-frozen={header.column.getIsPinned() || undefined}
|
|
|
|
|
|
data-frozen-last={lastFrozen === header.id || undefined}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
role="columnheader"
|
2022-10-18 14:49:17 +11:00
|
|
|
|
tabIndex={isSelectedCell ? 0 : -1}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
aria-colindex={header.index + 1}
|
2022-10-21 14:58:25 +11:00
|
|
|
|
aria-readonly={!canEditColumn}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
// TODO: aria-sort={"none" | "ascending" | "descending" | "other" | undefined}
|
2022-10-18 14:49:17 +11:00
|
|
|
|
aria-selected={isSelectedCell}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
label={header.column.columnDef.meta?.name || header.id}
|
|
|
|
|
|
type={header.column.columnDef.meta?.type}
|
2022-10-21 14:58:25 +11:00
|
|
|
|
style={{
|
|
|
|
|
|
width: header.getSize(),
|
|
|
|
|
|
left: header.column.getIsPinned()
|
|
|
|
|
|
? virtualCols[header.index].start - TABLE_PADDING
|
|
|
|
|
|
: undefined,
|
|
|
|
|
|
}}
|
|
|
|
|
|
sx={{ "& + &": { borderLeft: "none" } }}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
setSelectedCell({
|
|
|
|
|
|
path: "_rowy_header",
|
|
|
|
|
|
columnKey: header.id,
|
|
|
|
|
|
});
|
|
|
|
|
|
(e.target as HTMLDivElement).focus();
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
2022-10-24 13:12:53 +11:00
|
|
|
|
{header.column.getCanResize() && (
|
|
|
|
|
|
<StyledResizer
|
|
|
|
|
|
isResizing={header.column.getIsResizing()}
|
|
|
|
|
|
onMouseDown={header.getResizeHandler()}
|
|
|
|
|
|
onTouchStart={header.getResizeHandler()}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2022-10-17 17:57:26 +11:00
|
|
|
|
</ColumnHeaderComponent>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
2022-10-14 16:15:41 +11:00
|
|
|
|
</StyledRow>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2022-10-17 17:57:26 +11:00
|
|
|
|
<div className="tbody" role="rowgroup">
|
2022-10-18 17:53:47 +11:00
|
|
|
|
{paddingTop > 0 && (
|
|
|
|
|
|
<div role="presentation" style={{ height: `${paddingTop}px` }} />
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{virtualRows.map((virtualRow) => {
|
|
|
|
|
|
const row = rows[virtualRow.index];
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2022-10-19 12:54:31 +11:00
|
|
|
|
<StyledRow
|
|
|
|
|
|
key={row.id}
|
|
|
|
|
|
role="row"
|
|
|
|
|
|
aria-rowindex={row.index + 2}
|
|
|
|
|
|
style={{ height: tableSchema.rowHeight }}
|
|
|
|
|
|
>
|
2022-10-18 17:53:47 +11:00
|
|
|
|
{paddingLeft > 0 && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
role="presentation"
|
|
|
|
|
|
style={{ width: `${paddingLeft}px` }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{virtualCols.map((virtualCell) => {
|
|
|
|
|
|
const cellIndex = virtualCell.index;
|
|
|
|
|
|
const cell = row.getVisibleCells()[cellIndex];
|
|
|
|
|
|
|
|
|
|
|
|
const isSelectedCell =
|
|
|
|
|
|
selectedCell?.path === row.original._rowy_ref.path &&
|
|
|
|
|
|
selectedCell?.columnKey === cell.column.id;
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<StyledCell
|
|
|
|
|
|
key={cell.id}
|
2022-10-21 14:58:25 +11:00
|
|
|
|
data-row-id={row.id}
|
|
|
|
|
|
data-col-id={cell.column.id}
|
|
|
|
|
|
data-frozen={cell.column.getIsPinned() || undefined}
|
|
|
|
|
|
data-frozen-last={
|
|
|
|
|
|
lastFrozen === cell.column.id || undefined
|
|
|
|
|
|
}
|
2022-10-18 17:53:47 +11:00
|
|
|
|
role="gridcell"
|
|
|
|
|
|
tabIndex={isSelectedCell && !focusInsideCell ? 0 : -1}
|
|
|
|
|
|
aria-colindex={cellIndex + 1}
|
|
|
|
|
|
aria-readonly={
|
|
|
|
|
|
cell.column.columnDef.meta?.editable === false
|
|
|
|
|
|
}
|
|
|
|
|
|
aria-selected={isSelectedCell}
|
2022-10-21 14:58:25 +11:00
|
|
|
|
style={{
|
|
|
|
|
|
width: cell.column.getSize(),
|
|
|
|
|
|
left: cell.column.getIsPinned()
|
|
|
|
|
|
? virtualCell.start - TABLE_PADDING
|
|
|
|
|
|
: undefined,
|
|
|
|
|
|
backgroundColor:
|
|
|
|
|
|
cell.column.id === "_rowy_column_actions"
|
|
|
|
|
|
? "transparent"
|
|
|
|
|
|
: undefined,
|
|
|
|
|
|
borderBottomWidth:
|
|
|
|
|
|
cell.column.id === "_rowy_column_actions"
|
|
|
|
|
|
? 0
|
|
|
|
|
|
: undefined,
|
|
|
|
|
|
borderRightWidth:
|
|
|
|
|
|
cell.column.id === "_rowy_column_actions"
|
|
|
|
|
|
? 0
|
|
|
|
|
|
: undefined,
|
|
|
|
|
|
}}
|
2022-10-18 17:53:47 +11:00
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
setSelectedCell({
|
|
|
|
|
|
path: row.original._rowy_ref.path,
|
|
|
|
|
|
columnKey: cell.column.id,
|
|
|
|
|
|
});
|
|
|
|
|
|
(e.target as HTMLDivElement).focus();
|
|
|
|
|
|
}}
|
2022-10-18 14:49:17 +11:00
|
|
|
|
>
|
2022-10-18 17:53:47 +11:00
|
|
|
|
{flexRender(
|
|
|
|
|
|
cell.column.columnDef.cell,
|
|
|
|
|
|
cell.getContext()
|
|
|
|
|
|
)}
|
2022-10-19 12:54:31 +11:00
|
|
|
|
{/* <button
|
2022-10-18 17:53:47 +11:00
|
|
|
|
tabIndex={isSelectedCell && focusInsideCell ? 0 : -1}
|
|
|
|
|
|
>
|
|
|
|
|
|
{isSelectedCell ? "f" : "x"}
|
2022-10-19 12:54:31 +11:00
|
|
|
|
</button> */}
|
2022-10-18 17:53:47 +11:00
|
|
|
|
</StyledCell>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
|
|
|
|
|
|
{paddingRight > 0 && (
|
|
|
|
|
|
<div
|
|
|
|
|
|
role="presentation"
|
|
|
|
|
|
style={{ width: `${paddingRight}px` }}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</StyledRow>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
|
|
|
|
|
|
{paddingBottom > 0 && (
|
|
|
|
|
|
<div role="presentation" style={{ height: `${paddingBottom}px` }} />
|
|
|
|
|
|
)}
|
2022-10-14 16:15:41 +11:00
|
|
|
|
</div>
|
|
|
|
|
|
</StyledTable>
|
2022-10-18 17:53:47 +11:00
|
|
|
|
</div>
|
2022-05-19 16:37:56 +10:00
|
|
|
|
);
|
|
|
|
|
|
}
|