Skip to content

Commit

Permalink
refactor(tooling-ui-kit): Clean up of Table (#2072)
Browse files Browse the repository at this point in the history
* refactor(tooling-ui-kit): Clean up of `Table`

* fix: Adapt LedgerAccountList.tsx
  • Loading branch information
marc2332 authored Aug 28, 2024
1 parent f9c152e commit 80e8994
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 56 deletions.
24 changes: 10 additions & 14 deletions apps/ui-kit/src/lib/components/organisms/table/Table.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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({
Expand All @@ -54,13 +58,15 @@ export function Table({
hasCheckboxColumn,
onRowCheckboxChange,
onHeaderCheckboxChange,
rowIndexes,
children,
}: PropsWithChildren<TableProps & TableProviderProps>): JSX.Element {
return (
<TableProvider
hasCheckboxColumn={hasCheckboxColumn}
onRowCheckboxChange={onRowCheckboxChange}
onHeaderCheckboxChange={onHeaderCheckboxChange}
rowIndexes={rowIndexes}
>
<div className="w-full">
<div className="overflow-auto">
Expand Down Expand Up @@ -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 (
<tr>
Expand All @@ -177,8 +177,6 @@ function TableRowCheckbox({
rowsChecked,
isHeaderChecked,
isHeaderIndeterminate,
onRowCheckboxChange,
onHeaderCheckboxChange,
} = useTableContext();

if (type === TableRowType.Header) {
Expand All @@ -188,7 +186,6 @@ function TableRowCheckbox({
hasCheckbox
onCheckboxChange={(event) => {
toggleHeaderChecked(event.target.checked);
onHeaderCheckboxChange?.(event.target.checked);
}}
isChecked={isHeaderChecked}
columnKey={1}
Expand All @@ -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)}
/>
);
}
74 changes: 32 additions & 42 deletions apps/ui-kit/src/lib/components/organisms/table/TableContext.tsx
Original file line number Diff line number Diff line change
@@ -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 {
/**
Expand All @@ -11,36 +11,39 @@ export interface TableProviderProps {
/**
* On checkbox change callback.
*/
onRowCheckboxChange?: (value: boolean, index: number, tableValues: boolean[]) => void;
onRowCheckboxChange?: (value: boolean, index: number, tableValues: Set<number>) => 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<number>;
toggleRowChecked: (checked: boolean, index: number) => void;
isHeaderIndeterminate: boolean;
registerRowCheckbox: (index: number) => void;
};

export enum TableRowType {
Body = 'body',
Header = 'header',
}

export const TableContext = createContext<TableContextProps & TableProviderProps>({
export const TableContext = createContext<TableContextProps>({
hasCheckboxColumn: false,
isHeaderChecked: false,
toggleHeaderChecked: () => {},
rowsChecked: [],
toggleRowChecked: () => [],
rowsChecked: new Set(),
toggleRowChecked: () => new Set(),
isHeaderIndeterminate: false,
onRowCheckboxChange: () => {},
registerRowCheckbox: () => {},
});

export const useTableContext = () => {
Expand All @@ -50,49 +53,37 @@ export const useTableContext = () => {

export function TableProvider({
children,
onHeaderCheckboxChange,
onRowCheckboxChange,
rowIndexes,
...props
}: TableProviderProps & { children: React.ReactNode }) {
const [rowsChecked, setRowsChecked] = useState<boolean[]>([]);
const [isHeaderChecked, setIsHeaderChecked] = useState<boolean>(false);
const [isHeaderIndeterminate, setIsHeaderIndeterminate] = useState<boolean>(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<Set<number>>(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<number>();
if (checked) {
newCheckedRows = new Set(rowIndexes);
}
setRowsChecked(newCheckedRows);
onHeaderCheckboxChange?.(checked);
},
[rowsChecked],
);
Expand All @@ -102,9 +93,8 @@ export function TableProvider({
value={{
...props,
isHeaderChecked,
toggleRowChecked,
toggleHeaderChecked,
registerRowCheckbox,
toggleRowChecked,
rowsChecked,
isHeaderIndeterminate,
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,6 @@ export const Default: Story = {
hasPagination: true,
actionLabel: 'Action',
hasCheckboxColumn: true,
rowIndexes: [0, 1, 2],
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export function LedgerAccountList({ accounts, onAccountClick, selectAll }: Ledge
onAccountClick(accounts[index]);
}}
onHeaderCheckboxChange={() => selectAll()}
rowIndexes={rowsData.map((_, i) => i)}
>
<TableHeader>
<TableHeaderRow>
Expand Down

0 comments on commit 80e8994

Please sign in to comment.