From aa8a52c4787cb18c92ca18d1b1a5d6760ecd48cc Mon Sep 17 00:00:00 2001 From: Nithin <78612244+nithinrdy@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:36:44 +0530 Subject: [PATCH 1/8] Create atom to track active table's headers --- src/atoms/tableScope/table.ts | 3 +++ src/components/Table/Table.tsx | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/atoms/tableScope/table.ts b/src/atoms/tableScope/table.ts index f8d519c4..0f8b89f8 100644 --- a/src/atoms/tableScope/table.ts +++ b/src/atoms/tableScope/table.ts @@ -16,6 +16,7 @@ import { BulkWriteFunction, } from "@src/types/table"; import { updateRowData } from "@src/utils/table"; +import { Header } from "@tanstack/react-table"; /** Root atom from which others are derived */ export const tableIdAtom = atom(""); @@ -47,6 +48,8 @@ export const tableColumnsOrderedAtom = atom((get) => { ["desc", "asc"] ); }); +/** Store the headers of the table as an array. */ +export const tableHeadersAtom = atom[]>([]); /** Reducer function to convert from array of columns to columns object */ export const tableColumnsReducer = ( a: Record, diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 892eabf9..f2f7d551 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -9,6 +9,7 @@ import { } from "@tanstack/react-table"; import type { ColumnPinningState, + Header, VisibilityState, } from "@tanstack/react-table"; import { DropResult } from "react-beautiful-dnd"; @@ -25,6 +26,7 @@ import EmptyState from "@src/components/EmptyState"; import { tableScope, tableSchemaAtom, + tableHeadersAtom, tableColumnsOrderedAtom, tableRowsAtom, tableNextPageAtom, @@ -96,6 +98,7 @@ export default function Table({ }: ITableProps) { const [tableSchema] = useAtom(tableSchemaAtom, tableScope); const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope); + const setTableHeaders = useSetAtom(tableHeadersAtom, tableScope); const [tableRows] = useAtom(tableRowsAtom, tableScope); const [tableNextPage] = useAtom(tableNextPageAtom, tableScope); const [tablePage, setTablePage] = useAtom(tablePageAtom, tableScope); @@ -185,6 +188,17 @@ export default function Table({ state: { ...prev.state, columnVisibility, columnPinning, columnSizing }, onColumnSizingChange: setColumnSizing, })); + // Store the headers of the current table as an array. + // Initial value is an empty array, which progressively grows as headerGroups are cycled through + // and their headers are added to the array. + setTableHeaders( + table.getHeaderGroups().reduce((currentHeadersList, headerGroup) => { + return [ + ...currentHeadersList, + ...headerGroup.headers.map((header) => header), + ]; + }, [] as Header[]) + ); // Get rows and columns for virtualization const { rows } = table.getRowModel(); const leafColumns = table.getVisibleLeafColumns(); From 7deb40039dde5d4534780bbc61570e6ee59588b5 Mon Sep 17 00:00:00 2001 From: Nithin <78612244+nithinrdy@users.noreply.github.com> Date: Sun, 6 Aug 2023 13:38:14 +0530 Subject: [PATCH 2/8] Add modal to set column width --- src/atoms/tableScope/ui.ts | 2 +- src/components/ColumnMenu/ColumnMenu.tsx | 11 +++ src/components/ColumnModals/ColumnModals.tsx | 4 ++ .../ColumnModals/SetColumnWidthModal.tsx | 71 +++++++++++++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/components/ColumnModals/SetColumnWidthModal.tsx diff --git a/src/atoms/tableScope/ui.ts b/src/atoms/tableScope/ui.ts index b170d250..b5639790 100644 --- a/src/atoms/tableScope/ui.ts +++ b/src/atoms/tableScope/ui.ts @@ -41,7 +41,7 @@ export const columnMenuAtom = atom<{ * ``` */ export const columnModalAtom = atomWithHash<{ - type: "new" | "name" | "type" | "config"; + type: "new" | "name" | "type" | "config" | "setColumnWidth"; columnKey?: string; index?: number; } | null>("columnModal", null, { replaceState: true }); diff --git a/src/components/ColumnMenu/ColumnMenu.tsx b/src/components/ColumnMenu/ColumnMenu.tsx index b1944703..1a4d3246 100644 --- a/src/components/ColumnMenu/ColumnMenu.tsx +++ b/src/components/ColumnMenu/ColumnMenu.tsx @@ -24,6 +24,7 @@ import { } from "@src/assets/icons"; import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; +import StraightenIcon from "@mui/icons-material/Straighten"; import EditIcon from "@mui/icons-material/EditOutlined"; import SettingsIcon from "@mui/icons-material/SettingsOutlined"; import EvalIcon from "@mui/icons-material/PlayCircleOutline"; @@ -263,6 +264,16 @@ export default function ColumnMenu({ : column.type ), }, + { + key: "setColumnWidth", + label: "Set Column Width", + icon: , + onClick: () => { + openColumnModal({ type: "setColumnWidth", columnKey: column.key }); + handleClose(); + }, + disabled: !column.resizable, + }, ]; const configActions: IMenuContentsProps["menuItems"] = [ diff --git a/src/components/ColumnModals/ColumnModals.tsx b/src/components/ColumnModals/ColumnModals.tsx index 2dd37f20..99429f4c 100644 --- a/src/components/ColumnModals/ColumnModals.tsx +++ b/src/components/ColumnModals/ColumnModals.tsx @@ -5,6 +5,7 @@ import NewColumnModal from "./NewColumnModal"; import NameChangeModal from "./NameChangeModal"; import TypeChangeModal from "./TypeChangeModal"; import ColumnConfigModal from "./ColumnConfigModal"; +import SetColumnWidthModal from "./SetColumnWidthModal"; import { tableScope, @@ -40,5 +41,8 @@ export default function ColumnModals() { if (columnModal.type === "config") return ; + if (columnModal.type === "setColumnWidth") + return ; + return null; } diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx new file mode 100644 index 00000000..4bdb3496 --- /dev/null +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -0,0 +1,71 @@ +import { useEffect, useState } from "react"; +import { IColumnModalProps } from "."; +import { selectedCellAtom, tableHeadersAtom } from "@src/atoms/tableScope"; +import { tableScope } from "@src/atoms/tableScope"; +import { useAtom } from "jotai"; + +import { TextField } from "@mui/material"; +import Modal from "@src/components/Modal"; +import { TableRow } from "@src/types/table"; +import { Header } from "@tanstack/react-table"; + +export default function ResizeColumnModal({ + onClose, + column, +}: IColumnModalProps) { + const [newWidth, setWidth] = useState(0); + const [selectedCell] = useAtom(selectedCellAtom, tableScope); + const [tableHeaders] = useAtom(tableHeadersAtom, tableScope); + const [selectedHeader, setSelectedHeader] = useState | null>(null); + + useEffect(() => { + if (selectedCell && tableHeaders) { + setSelectedHeader( + tableHeaders.find((h) => h.id === selectedCell?.columnKey) ?? null + ); + } + }, [selectedCell, tableHeaders]); + + useEffect(() => { + selectedHeader && setWidth(selectedHeader.getSize()); + }, [selectedHeader]); + + return ( + setWidth(Number(e.target.value))} + /> + } + actions={{ + primary: { + onMouseDown: (e) => { + selectedHeader && + selectedHeader.getResizeHandler()({ + clientX: e.clientX - (newWidth - selectedHeader.getSize()), + } as any); + onClose(); + }, + children: "Update", + }, + secondary: { + onClick: onClose, + children: "Cancel", + }, + }} + /> + ); +} From 693f1fb91770e320f9c2fbb6089248b5e1c9f024 Mon Sep 17 00:00:00 2001 From: Nithin <78612244+nithinrdy@users.noreply.github.com> Date: Sun, 6 Aug 2023 18:41:32 +0530 Subject: [PATCH 3/8] Update on Mouse up instead Performing the update on mouse-down caused this issue where dragging the mouse around after clicking would result in the edge of the column to move along with it. Updating on mouse-up instead avoids this issue. --- src/components/ColumnModals/SetColumnWidthModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx index 4bdb3496..4a8a9d00 100644 --- a/src/components/ColumnModals/SetColumnWidthModal.tsx +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -52,7 +52,7 @@ export default function ResizeColumnModal({ } actions={{ primary: { - onMouseDown: (e) => { + onMouseUp: (e) => { selectedHeader && selectedHeader.getResizeHandler()({ clientX: e.clientX - (newWidth - selectedHeader.getSize()), From 3589c568b45c330b04fbf0bd847eb75748fbb088 Mon Sep 17 00:00:00 2001 From: Nithin <78612244+nithinrdy@users.noreply.github.com> Date: Mon, 7 Aug 2023 04:13:32 +0530 Subject: [PATCH 4/8] Minor changes - Better component name - Remove unnecessary map() call --- src/components/ColumnModals/SetColumnWidthModal.tsx | 2 +- src/components/Table/Table.tsx | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx index 4a8a9d00..1574064b 100644 --- a/src/components/ColumnModals/SetColumnWidthModal.tsx +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -9,7 +9,7 @@ import Modal from "@src/components/Modal"; import { TableRow } from "@src/types/table"; import { Header } from "@tanstack/react-table"; -export default function ResizeColumnModal({ +export default function SetColumnWidthModal({ onClose, column, }: IColumnModalProps) { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index f2f7d551..d5615b53 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -193,10 +193,7 @@ export default function Table({ // and their headers are added to the array. setTableHeaders( table.getHeaderGroups().reduce((currentHeadersList, headerGroup) => { - return [ - ...currentHeadersList, - ...headerGroup.headers.map((header) => header), - ]; + return [...currentHeadersList, ...headerGroup.headers]; }, [] as Header[]) ); // Get rows and columns for virtualization From e8e9d09894732ce276592d1fa8f00fbbd937fb20 Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Sun, 20 Aug 2023 13:00:25 +0530 Subject: [PATCH 5/8] Use the setColumnSizing method instead; store the entire table in an atom, not just the table headers. --- src/atoms/tableScope/table.ts | 4 +- .../ColumnModals/SetColumnWidthModal.tsx | 41 ++++++++----------- src/components/Table/Table.tsx | 16 +++----- 3 files changed, 23 insertions(+), 38 deletions(-) diff --git a/src/atoms/tableScope/table.ts b/src/atoms/tableScope/table.ts index 0f8b89f8..31792826 100644 --- a/src/atoms/tableScope/table.ts +++ b/src/atoms/tableScope/table.ts @@ -16,7 +16,7 @@ import { BulkWriteFunction, } from "@src/types/table"; import { updateRowData } from "@src/utils/table"; -import { Header } from "@tanstack/react-table"; +import { Table } from "@tanstack/react-table"; /** Root atom from which others are derived */ export const tableIdAtom = atom(""); @@ -49,7 +49,7 @@ export const tableColumnsOrderedAtom = atom((get) => { ); }); /** Store the headers of the table as an array. */ -export const tableHeadersAtom = atom[]>([]); +export const reactTableAtom = atom | null>(null); /** Reducer function to convert from array of columns to columns object */ export const tableColumnsReducer = ( a: Record, diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx index 1574064b..5c5e17fa 100644 --- a/src/components/ColumnModals/SetColumnWidthModal.tsx +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -1,37 +1,31 @@ import { useEffect, useState } from "react"; import { IColumnModalProps } from "."; -import { selectedCellAtom, tableHeadersAtom } from "@src/atoms/tableScope"; +import { reactTableAtom } from "@src/atoms/tableScope"; import { tableScope } from "@src/atoms/tableScope"; import { useAtom } from "jotai"; import { TextField } from "@mui/material"; import Modal from "@src/components/Modal"; -import { TableRow } from "@src/types/table"; -import { Header } from "@tanstack/react-table"; export default function SetColumnWidthModal({ onClose, column, }: IColumnModalProps) { + const [reactTable] = useAtom(reactTableAtom, tableScope); const [newWidth, setWidth] = useState(0); - const [selectedCell] = useAtom(selectedCellAtom, tableScope); - const [tableHeaders] = useAtom(tableHeadersAtom, tableScope); - const [selectedHeader, setSelectedHeader] = useState | null>(null); useEffect(() => { - if (selectedCell && tableHeaders) { - setSelectedHeader( - tableHeaders.find((h) => h.id === selectedCell?.columnKey) ?? null - ); - } - }, [selectedCell, tableHeaders]); + setWidth(reactTable?.getAllColumns()[column.index].getSize() || 0); + }, [reactTable, column]); - useEffect(() => { - selectedHeader && setWidth(selectedHeader.getSize()); - }, [selectedHeader]); + const handleUpdate = () => { + reactTable?.setColumnSizing((old) => { + const newSizing = { ...old }; + newSizing[column.name] = newWidth; + return newSizing; + }); + onClose(); + }; return ( setWidth(Number(e.target.value))} + onKeyDown={(e) => { + e.key === "Enter" && handleUpdate(); + }} /> } actions={{ primary: { - onMouseUp: (e) => { - selectedHeader && - selectedHeader.getResizeHandler()({ - clientX: e.clientX - (newWidth - selectedHeader.getSize()), - } as any); - onClose(); - }, + onClick: handleUpdate, children: "Update", }, secondary: { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index d5615b53..b0c46ae6 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -9,7 +9,6 @@ import { } from "@tanstack/react-table"; import type { ColumnPinningState, - Header, VisibilityState, } from "@tanstack/react-table"; import { DropResult } from "react-beautiful-dnd"; @@ -26,7 +25,7 @@ import EmptyState from "@src/components/EmptyState"; import { tableScope, tableSchemaAtom, - tableHeadersAtom, + reactTableAtom, tableColumnsOrderedAtom, tableRowsAtom, tableNextPageAtom, @@ -98,7 +97,6 @@ export default function Table({ }: ITableProps) { const [tableSchema] = useAtom(tableSchemaAtom, tableScope); const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope); - const setTableHeaders = useSetAtom(tableHeadersAtom, tableScope); const [tableRows] = useAtom(tableRowsAtom, tableScope); const [tableNextPage] = useAtom(tableNextPageAtom, tableScope); const [tablePage, setTablePage] = useAtom(tablePageAtom, tableScope); @@ -188,14 +186,10 @@ export default function Table({ state: { ...prev.state, columnVisibility, columnPinning, columnSizing }, onColumnSizingChange: setColumnSizing, })); - // Store the headers of the current table as an array. - // Initial value is an empty array, which progressively grows as headerGroups are cycled through - // and their headers are added to the array. - setTableHeaders( - table.getHeaderGroups().reduce((currentHeadersList, headerGroup) => { - return [...currentHeadersList, ...headerGroup.headers]; - }, [] as Header[]) - ); + const setReactTable = useSetAtom(reactTableAtom, tableScope); + useMemo(() => { + setReactTable(table); + }, [table, setReactTable]); // Get rows and columns for virtualization const { rows } = table.getRowModel(); const leafColumns = table.getVisibleLeafColumns(); From 8316e6ac6a22259e143cbdfe32f7b8c0f75f366d Mon Sep 17 00:00:00 2001 From: Vishnu Nithin Reddy <78612244+nithinrdy@users.noreply.github.com> Date: Sun, 20 Aug 2023 13:11:00 +0530 Subject: [PATCH 6/8] Add comments --- src/atoms/tableScope/table.ts | 2 +- src/components/ColumnModals/SetColumnWidthModal.tsx | 2 ++ src/components/Table/Table.tsx | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/atoms/tableScope/table.ts b/src/atoms/tableScope/table.ts index 31792826..a95995a0 100644 --- a/src/atoms/tableScope/table.ts +++ b/src/atoms/tableScope/table.ts @@ -48,7 +48,7 @@ export const tableColumnsOrderedAtom = atom((get) => { ["desc", "asc"] ); }); -/** Store the headers of the table as an array. */ +/** Store the table */ export const reactTableAtom = atom | null>(null); /** Reducer function to convert from array of columns to columns object */ export const tableColumnsReducer = ( diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx index 5c5e17fa..bdfde0d3 100644 --- a/src/components/ColumnModals/SetColumnWidthModal.tsx +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -15,12 +15,14 @@ export default function SetColumnWidthModal({ const [newWidth, setWidth] = useState(0); useEffect(() => { + // Set the initial width to the current column width once the table is fetched. setWidth(reactTable?.getAllColumns()[column.index].getSize() || 0); }, [reactTable, column]); const handleUpdate = () => { reactTable?.setColumnSizing((old) => { const newSizing = { ...old }; + // Set the new width for the column. newSizing[column.name] = newWidth; return newSizing; }); diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index b0c46ae6..a7e00871 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -100,6 +100,7 @@ export default function Table({ const [tableRows] = useAtom(tableRowsAtom, tableScope); const [tableNextPage] = useAtom(tableNextPageAtom, tableScope); const [tablePage, setTablePage] = useAtom(tablePageAtom, tableScope); + const setReactTable = useSetAtom(reactTableAtom, tableScope); const updateColumn = useSetAtom(updateColumnAtom, tableScope); @@ -186,7 +187,7 @@ export default function Table({ state: { ...prev.state, columnVisibility, columnPinning, columnSizing }, onColumnSizingChange: setColumnSizing, })); - const setReactTable = useSetAtom(reactTableAtom, tableScope); + // Update the reactTable atom when table state changes. useMemo(() => { setReactTable(table); }, [table, setReactTable]); From ef58d37ed6ace4e107550d31c5898ef0f8405bc5 Mon Sep 17 00:00:00 2001 From: il3ven Date: Sun, 20 Aug 2023 10:49:39 +0000 Subject: [PATCH 7/8] show set column width option even if column.resizable is undefined --- src/components/ColumnMenu/ColumnMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ColumnMenu/ColumnMenu.tsx b/src/components/ColumnMenu/ColumnMenu.tsx index 1a4d3246..d676f024 100644 --- a/src/components/ColumnMenu/ColumnMenu.tsx +++ b/src/components/ColumnMenu/ColumnMenu.tsx @@ -272,7 +272,7 @@ export default function ColumnMenu({ openColumnModal({ type: "setColumnWidth", columnKey: column.key }); handleClose(); }, - disabled: !column.resizable, + disabled: column.resizable === false, }, ]; From 7ca6fe3be6fdfab7354ec2cead7c5e9ae69ac46d Mon Sep 17 00:00:00 2001 From: il3ven Date: Sun, 20 Aug 2023 10:50:23 +0000 Subject: [PATCH 8/8] add
tag for handling submit and fix an error --- .../ColumnModals/SetColumnWidthModal.tsx | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/components/ColumnModals/SetColumnWidthModal.tsx b/src/components/ColumnModals/SetColumnWidthModal.tsx index bdfde0d3..a5071d64 100644 --- a/src/components/ColumnModals/SetColumnWidthModal.tsx +++ b/src/components/ColumnModals/SetColumnWidthModal.tsx @@ -23,7 +23,7 @@ export default function SetColumnWidthModal({ reactTable?.setColumnSizing((old) => { const newSizing = { ...old }; // Set the new width for the column. - newSizing[column.name] = newWidth; + newSizing[column.fieldName] = newWidth; return newSizing; }); onClose(); @@ -35,24 +35,30 @@ export default function SetColumnWidthModal({ title="Set Column Width" maxWidth="xs" children={ - setWidth(Number(e.target.value))} - onKeyDown={(e) => { - e.key === "Enter" && handleUpdate(); + { + e.preventDefault(); + handleUpdate(); }} - /> + > + setWidth(Number(e.target.value))} + /> + } actions={{ primary: { - onClick: handleUpdate, children: "Update", + type: "submit", + form: "column-width-modal", }, secondary: { onClick: onClose,