From 80e89940ca48509f341e24718882a5f851878cb1 Mon Sep 17 00:00:00 2001 From: Marc Espin Date: Wed, 28 Aug 2024 12:47:26 +0200 Subject: [PATCH] refactor(tooling-ui-kit): Clean up of `Table` (#2072) * refactor(tooling-ui-kit): Clean up of `Table` * fix: Adapt LedgerAccountList.tsx --- .../lib/components/organisms/table/Table.tsx | 24 +++--- .../organisms/table/TableContext.tsx | 74 ++++++++----------- .../stories/organisms/Table.stories.tsx | 1 + .../components/ledger/LedgerAccountList.tsx | 1 + 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx index 2c687d71630..9f6d7c49069 100644 --- a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx +++ b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import React, { PropsWithChildren, useEffect } from 'react'; +import React, { PropsWithChildren } from 'react'; import cx from 'classnames'; import { TableRowType, TableProvider, useTableContext, TableProviderProps } from './TableContext'; import { Button, ButtonSize, ButtonType, TableCell, TableCellType, TableHeaderCell } from '@/lib'; @@ -40,6 +40,10 @@ export type TableProps = { * The supporting label of the table. */ supportingLabel?: string; + /** + * Numeric indexes of all the rows. + */ + rowIndexes: number[]; }; export function Table({ @@ -54,6 +58,7 @@ export function Table({ hasCheckboxColumn, onRowCheckboxChange, onHeaderCheckboxChange, + rowIndexes, children, }: PropsWithChildren): JSX.Element { return ( @@ -61,6 +66,7 @@ export function Table({ hasCheckboxColumn={hasCheckboxColumn} onRowCheckboxChange={onRowCheckboxChange} onHeaderCheckboxChange={onHeaderCheckboxChange} + rowIndexes={rowIndexes} >
@@ -144,13 +150,7 @@ function TableRow({ rowIndex, type = TableRowType.Body, }: PropsWithChildren<{ rowIndex?: number; type: TableRowType }>): JSX.Element { - const { hasCheckboxColumn, registerRowCheckbox } = useTableContext(); - - useEffect(() => { - if (rowIndex !== undefined && rowIndex !== null) { - registerRowCheckbox(rowIndex); - } - }, [registerRowCheckbox, rowIndex]); + const { hasCheckboxColumn } = useTableContext(); return ( @@ -177,8 +177,6 @@ function TableRowCheckbox({ rowsChecked, isHeaderChecked, isHeaderIndeterminate, - onRowCheckboxChange, - onHeaderCheckboxChange, } = useTableContext(); if (type === TableRowType.Header) { @@ -188,7 +186,6 @@ function TableRowCheckbox({ hasCheckbox onCheckboxChange={(event) => { toggleHeaderChecked(event.target.checked); - onHeaderCheckboxChange?.(event.target.checked); }} isChecked={isHeaderChecked} columnKey={1} @@ -202,12 +199,11 @@ function TableRowCheckbox({ isContentCentered onChange={(event) => { if (rowIndex !== undefined) { - const checkboxValues = toggleRowChecked?.(event.target.checked, rowIndex); - onRowCheckboxChange?.(event.target.checked, rowIndex, checkboxValues); + toggleRowChecked?.(event.target.checked, rowIndex); } }} type={TableCellType.Checkbox} - isChecked={rowIndex !== undefined && rowsChecked?.[rowIndex]} + isChecked={rowIndex !== undefined && rowsChecked.has(rowIndex)} /> ); } diff --git a/apps/ui-kit/src/lib/components/organisms/table/TableContext.tsx b/apps/ui-kit/src/lib/components/organisms/table/TableContext.tsx index a2e351bd5aa..44f7cd260d4 100644 --- a/apps/ui-kit/src/lib/components/organisms/table/TableContext.tsx +++ b/apps/ui-kit/src/lib/components/organisms/table/TableContext.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { createContext, useCallback, useContext, useEffect, useState } from 'react'; +import { createContext, useCallback, useContext, useState } from 'react'; export interface TableProviderProps { /** @@ -11,20 +11,25 @@ export interface TableProviderProps { /** * On checkbox change callback. */ - onRowCheckboxChange?: (value: boolean, index: number, tableValues: boolean[]) => void; + onRowCheckboxChange?: (value: boolean, index: number, tableValues: Set) => void; /** * On header checkbox change callback. */ onHeaderCheckboxChange?: (value: boolean) => void; + /** + * Numeric indexes of all the rows. + */ + rowIndexes: number[]; } type TableContextProps = { + hasCheckboxColumn?: boolean; + onRowCheckboxChange?: (value: boolean, index: number, tableValues: boolean[]) => void; isHeaderChecked: boolean; toggleHeaderChecked: (checked: boolean) => void; - rowsChecked: boolean[]; - toggleRowChecked: (checked: boolean, index: number) => boolean[]; + rowsChecked: Set; + toggleRowChecked: (checked: boolean, index: number) => void; isHeaderIndeterminate: boolean; - registerRowCheckbox: (index: number) => void; }; export enum TableRowType { @@ -32,15 +37,13 @@ export enum TableRowType { Header = 'header', } -export const TableContext = createContext({ +export const TableContext = createContext({ hasCheckboxColumn: false, isHeaderChecked: false, toggleHeaderChecked: () => {}, - rowsChecked: [], - toggleRowChecked: () => [], + rowsChecked: new Set(), + toggleRowChecked: () => new Set(), isHeaderIndeterminate: false, - onRowCheckboxChange: () => {}, - registerRowCheckbox: () => {}, }); export const useTableContext = () => { @@ -50,49 +53,37 @@ export const useTableContext = () => { export function TableProvider({ children, + onHeaderCheckboxChange, + onRowCheckboxChange, + rowIndexes, ...props }: TableProviderProps & { children: React.ReactNode }) { - const [rowsChecked, setRowsChecked] = useState([]); - const [isHeaderChecked, setIsHeaderChecked] = useState(false); - const [isHeaderIndeterminate, setIsHeaderIndeterminate] = useState(false); - - useEffect(() => { - if (rowsChecked.length > 0) { - if (rowsChecked.every((checked) => checked)) { - setIsHeaderChecked(true); - setIsHeaderIndeterminate(false); - } else if (rowsChecked.some((checked) => checked)) { - setIsHeaderIndeterminate(true); - } else { - setIsHeaderChecked(false); - setIsHeaderIndeterminate(false); - } - } - }, [rowsChecked]); + const [rowsChecked, setRowsChecked] = useState>(new Set()); + const isHeaderChecked = rowIndexes.length === rowsChecked.size; + const isHeaderIndeterminate = !isHeaderChecked && rowsChecked.size > 0; const toggleRowChecked = useCallback( (checked: boolean, index: number) => { - const newRowsChecked = [...rowsChecked]; - newRowsChecked[index] = checked; + const newRowsChecked = new Set(rowsChecked); + if (checked) { + newRowsChecked.add(index); + } else { + newRowsChecked.delete(index); + } setRowsChecked(newRowsChecked); - return newRowsChecked; + onRowCheckboxChange?.(checked, index, newRowsChecked); }, [rowsChecked], ); - const registerRowCheckbox = useCallback((index: number) => { - setRowsChecked((prevRowsChecked) => { - const newRowsChecked = [...prevRowsChecked]; - newRowsChecked[index] = false; - return newRowsChecked; - }); - }, []); - const toggleHeaderChecked = useCallback( (checked: boolean) => { - const newCheckedRows = Array(rowsChecked.length).fill(checked); - setIsHeaderChecked(checked); + let newCheckedRows = new Set(); + if (checked) { + newCheckedRows = new Set(rowIndexes); + } setRowsChecked(newCheckedRows); + onHeaderCheckboxChange?.(checked); }, [rowsChecked], ); @@ -102,9 +93,8 @@ export function TableProvider({ value={{ ...props, isHeaderChecked, - toggleRowChecked, toggleHeaderChecked, - registerRowCheckbox, + toggleRowChecked, rowsChecked, isHeaderIndeterminate, }} diff --git a/apps/ui-kit/src/storybook/stories/organisms/Table.stories.tsx b/apps/ui-kit/src/storybook/stories/organisms/Table.stories.tsx index 00cc8a49131..724141233c0 100644 --- a/apps/ui-kit/src/storybook/stories/organisms/Table.stories.tsx +++ b/apps/ui-kit/src/storybook/stories/organisms/Table.stories.tsx @@ -108,5 +108,6 @@ export const Default: Story = { hasPagination: true, actionLabel: 'Action', hasCheckboxColumn: true, + rowIndexes: [0, 1, 2], }, }; diff --git a/apps/wallet/src/ui/app/components/ledger/LedgerAccountList.tsx b/apps/wallet/src/ui/app/components/ledger/LedgerAccountList.tsx index 4c4f021c47f..e1f7431266d 100644 --- a/apps/wallet/src/ui/app/components/ledger/LedgerAccountList.tsx +++ b/apps/wallet/src/ui/app/components/ledger/LedgerAccountList.tsx @@ -57,6 +57,7 @@ export function LedgerAccountList({ accounts, onAccountClick, selectAll }: Ledge onAccountClick(accounts[index]); }} onHeaderCheckboxChange={() => selectAll()} + rowIndexes={rowsData.map((_, i) => i)} >