Skip to content

Commit

Permalink
EPMRPP-90306 || code review fix - 2
Browse files Browse the repository at this point in the history
  • Loading branch information
maria-hambardzumian committed Jun 13, 2024
2 parents d30bf8f + 6c4ec55 commit 13ad988
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 98 deletions.
14 changes: 7 additions & 7 deletions src/components/checkbox/checkbox.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
background-position: center;
background-image: url("data:image/svg+xml,%3Csvg width='12' height='9' viewBox='0 0 12 9' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.5 4.25L4.5 7.25L10.5 0.75' stroke='white' stroke-width='2'/%3E%3C/svg%3E");
}
@mixin not-all-checked-state($border-color, $rect-fill) {
@mixin partially-checked-state($border-color, $rect-fill) {
border-color: $border-color;
background-repeat: no-repeat;
background-position: center;
Expand Down Expand Up @@ -87,22 +87,22 @@
border: 2px solid var(--rp-ui-color-primary-focused);
}

&.not-all-checked:not(:checked){
&.partially-checked:not(:checked){
& + .control {
@include not-all-checked-state(var(--rp-ui-color-field-border), var(--rp-ui-color-field-border-2));
@include partially-checked-state(var(--rp-ui-color-field-border), var(--rp-ui-color-field-border-2));
}

&:hover + .control {
@include not-all-checked-state(var(--rp-ui-color-field-border-2-hover), var(--rp-ui-color-primary-hover));
@include partially-checked-state(var(--rp-ui-color-field-border-2-hover), var(--rp-ui-color-primary-hover));
}

&:active:not(:disabled) + .control {
@include not-all-checked-state(var(--rp-ui-color-primary-focused), var(--rp-ui-color-field-border-2));
@include partially-checked-state(var(--rp-ui-color-primary-focused), var(--rp-ui-color-field-border-2));
}

&:disabled + .control {
@include not-all-checked-state(var(--rp-ui-color-field-borderd), var(--rp-ui-color-field-border));
@include partially-checked-state(var(--rp-ui-color-field-borderd), var(--rp-ui-color-field-border));
}

}
}

Expand Down
6 changes: 3 additions & 3 deletions src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface CheckboxProps extends HTMLAttributes<HTMLInputElement> {
disabled?: boolean;
className?: string;
onChange?: ChangeEventHandler<HTMLInputElement>;
notAllChecked?: boolean;
partiallyChecked?: boolean;
}

// DS link - https://www.figma.com/file/gjYQPbeyf4YsH3wZiVKoaj/%F0%9F%9B%A0-RP-DS-6?type=design&node-id=2350-8764&mode=design&t=GAXsAg9jOEgkVVlq-0
Expand All @@ -29,7 +29,7 @@ export const Checkbox: FC<CheckboxProps> = ({
onChange,
className,
value,
notAllChecked,
partiallyChecked,
...rest
}): ReactElement => {
const inputRef = useRef<HTMLInputElement | null>(null);
Expand Down Expand Up @@ -61,7 +61,7 @@ export const Checkbox: FC<CheckboxProps> = ({
tabIndex={0}
type="checkbox"
onKeyDown={handleKeyDown}
className={cx('input', { 'not-all-checked': notAllChecked })}
className={cx('input', { 'partially-checked': partiallyChecked })}
disabled={disabled}
onChange={onChange}
checked={value}
Expand Down
2 changes: 2 additions & 0 deletions src/components/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export { default as PlusIcon } from './svg/plus.svg';
export { default as MinusIcon } from './svg/minus.svg';
export { default as DeleteIcon } from './svg/delete.svg';
export { default as DropdownIcon } from './svg/dropdown.svg';
export { default as PrevPageIcon } from './svg/prevPage.svg';
export { default as PrevChapterIcon } from './svg/prevChapter.svg';
export { default as ArrowDownIcon } from './svg/arrowDown.svg';
export { default as ArrowUpIcon } from './svg/arrowUp.svg';
export { default as MeatballMenuIcon } from './svg/meatballMenu.svg';
17 changes: 16 additions & 1 deletion src/components/table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,25 @@ An array of objects representing the fixed columns of the table. Each object sho

A custom action menu to be displayed for each row in the table. It can be any valid ReactNode.

#### `checkboxSelection` (boolean, optional)
#### `selectable` (boolean, optional)

Indicates whether row selection using checkboxes is enabled. Set to true to enable checkbox selection.

#### `className` (string, optional)

Additional CSS classes to be applied to the table.

#### `selectedRowIds` ((string | number)[], optional)
An array containing the IDs of the currently selected rows.

#### `sortingDirection` (SortDirection, optional)
Specifies the current sorting direction ('asc' or 'desc').

#### `sortingColumn` (Column, optional)
Specifies the column by which the table is currently sorted.

#### `onChangeSorting` ((sortConfig?: SortConfig) => void, optional)
Callback function triggered when the sorting configuration changes.

#### `onToggleRowSelection` ((id: string | number) => void, optional)
Callback function triggered when a row's selection state changes.
2 changes: 2 additions & 0 deletions src/components/table/table.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ $HEIGHT-SMALL: 44px;
$HEIGHT-DEFAULT: 64px;
$HEIGHT-LARGE: 80px;


* {
box-sizing: border-box;
}

.table {
width: 100%;
max-width: 1200px;

}

.table-header {
Expand Down
72 changes: 27 additions & 45 deletions src/components/table/table.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type { Meta, StoryObj } from '@storybook/react';
import { Table } from './table';
import { Popover } from '@components/popover';
import { MeatballMenuIcon } from '@components/icons';
import { TableComponentProps, RowData, FixedColumn, Column, RowConfigs } from './types';
import { TableComponentProps, RowData, FixedColumn, Column, SortDirection } from './types';
import { useState } from 'react';
import { sortTableData } from '@components/table/utils';

const meta: Meta<typeof Table> = {
title: 'Table',
Expand All @@ -12,7 +14,7 @@ const meta: Meta<typeof Table> = {
},
tags: ['autodocs'],
args: {
checkboxSelection: true,
selectable: true,
},
};

Expand All @@ -36,6 +38,7 @@ const rowActionMenu = (

const data: RowData[] = [
{
id: 1,
name: {
content: 'Sam',
component: (
Expand All @@ -50,8 +53,8 @@ const data: RowData[] = [
age: 25,
city: 'New York',
},
{ name: 'Anna', age: 3, city: 'New York1' },
{ name: 'Mike', age: 30, city: 'Los Angeles', config: { size: 'small' } },
{ name: 'Anna', age: 3, city: 'New York1', id: 2 },
{ name: 'Mike', age: 30, city: 'Los Angeles', config: { size: 'small' }, id: 3 },
];

const primaryColumn: Column = {
Expand All @@ -75,52 +78,31 @@ const fixedColumns: FixedColumn[] = [
},
];

const dataWithRowConfigs: RowData[] = data.map((item: RowData, index: number) => ({
...item,
rowConfigs: {
size: ['small', 'default', 'large'][index % 3] as RowConfigs['size'],
},
}));

export const Default: Story = {
render: (args: TableComponentProps) => (
<div style={{ minWidth: '700px' }}>
<Table {...args} />
</div>
),
args: {
data,
primaryColumn,
fixedColumns,
rowActionMenu,
},
};

export const NoCheckbox: Story = {
render: (args: TableComponentProps) => (
<div style={{ minWidth: '700px' }}>
<Table {...args} />
</div>
),
args: {
data,
primaryColumn,
fixedColumns,
rowActionMenu,
checkboxSelection: false,
render: (args: TableComponentProps) => {
const defaultSortedData = sortTableData(data, {
key: primaryColumn.key,
direction: SortDirection.ASC,
});
// eslint-disable-next-line react-hooks/rules-of-hooks
const [tableData, setTableData] = useState(defaultSortedData);
return (
<div style={{ minWidth: '700px' }}>
<Table
{...args}
data={tableData}
onChangeSorting={(sortConfig) => {
const sortedData = sortTableData(tableData, sortConfig);
setTableData(sortedData);
}}
/>
</div>
);
},
};

export const DifferentRowSize: Story = {
render: (args: TableComponentProps) => (
<div style={{ minWidth: '700px' }}>
<Table {...args} />
</div>
),
args: {
data: dataWithRowConfigs,
primaryColumn,
fixedColumns,
rowActionMenu,
selectable: true,
},
};
66 changes: 37 additions & 29 deletions src/components/table/table.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CSSProperties, FC, useMemo, useState } from 'react';
import { CSSProperties, useMemo, useState, FC } from 'react';
import styles from './table.module.scss';
import classNames from 'classnames/bind';
import { ArrowDownIcon, ArrowUpIcon } from '@components/icons';
Expand All @@ -7,34 +7,33 @@ import {
PrimaryColumn,
RowData,
SortConfig,
SortDirection,
TableComponentProps,
SortDirection,
} from './types';
import { Checkbox } from '@/components';
import { sortTableData } from './utils';

const cx = classNames.bind(styles);

// https://www.figma.com/file/gjYQPbeyf4YsH3wZiVKoaj/%F0%9F%9B%A0-RP-DS-6?type=design&node-id=2864-9218&mode=design&t=cOfdh4tVVVKvWoEw-0
export const Table: FC<TableComponentProps> = ({
data,
primaryColumn,
fixedColumns,
rowActionMenu,
checkboxSelection = false,
className = '',
selectable = false,
selectedRowIds = [],
sortingDirection = SortDirection.ASC,
sortingColumn = primaryColumn,
onChangeSorting = () => {},
onToggleRowSelection = () => {},
}) => {
const [sortConfig, setSortConfig] = useState<SortConfig>({
key: primaryColumn.key,
direction: SortDirection.ASC,
key: sortingColumn.key,
direction: sortingDirection,
});
const [hoveredColumn, setHoveredColumn] = useState<string | null>(null);
const [hoveredRow, setHoveredRow] = useState<number | null>(null);
const [tableData, setTableData] = useState<RowData[]>(data);

const sortedData = useMemo(() => {
return sortTableData(tableData, sortConfig);
}, [tableData, sortConfig]);
const [checkedRows, setCheckedRows] = useState<Set<number | string>>(new Set(selectedRowIds));

const sortedColumns: (PrimaryColumn | FixedColumn)[] = useMemo(() => {
return [{ ...primaryColumn, primary: true }, ...fixedColumns.sort((a, b) => a.order - b.order)];
Expand All @@ -45,6 +44,7 @@ export const Table: FC<TableComponentProps> = ({
if (sortConfig && sortConfig.key === key && sortConfig.direction === SortDirection.ASC) {
direction = SortDirection.DESC;
}
onChangeSorting({ key, direction });
setSortConfig({ key, direction });
};

Expand All @@ -71,20 +71,28 @@ export const Table: FC<TableComponentProps> = ({
setHoveredRow(null);
};

const handleRowCheck = (index: number) => {
const updatedData = [...sortedData];
updatedData[index] = { ...updatedData[index], checked: !updatedData[index].checked };
setTableData(updatedData);
const handleRowCheck = (id: number | string) => {
const newCheckedRows = new Set(checkedRows);
if (newCheckedRows.has(id)) {
newCheckedRows.delete(id);
} else {
newCheckedRows.add(id);
}
setCheckedRows(newCheckedRows);
onToggleRowSelection(id);
};

const handleCheckAll = () => {
const allChecked = sortedData.every((item) => item.checked);
const updatedData = sortedData.map((item) => ({ ...item, checked: !allChecked }));
setTableData(updatedData);
if (checkedRows.size === data.length) {
setCheckedRows(new Set());
} else {
const allRows = new Set(data.map((item) => item.id));
setCheckedRows(allRows);
}
};

const isAllChecked: boolean = sortedData.every((item) => item.checked);
const isAnyChecked: boolean = sortedData.some((item) => item.checked);
const isAllChecked: boolean = data.every((item) => [...checkedRows].includes(item.id));
const isAnyChecked: boolean = data.some((item) => [...checkedRows].includes(item.id));

const getSizeClassName = (item: RowData): string => {
const size = item.rowConfigs?.size ?? 'default';
Expand All @@ -101,12 +109,12 @@ export const Table: FC<TableComponentProps> = ({
return (
<div className={cx('table', className)}>
<div className={cx('table-header')}>
{checkboxSelection && (
{selectable && (
<div className={cx('table-header-cell', 'checkbox-cell')}>
{isAnyChecked && (
<Checkbox
value={isAllChecked}
notAllChecked={isAnyChecked}
partiallyChecked={isAnyChecked}
onChange={handleCheckAll}
className={cx('checkbox-cell')}
/>
Expand Down Expand Up @@ -135,19 +143,19 @@ export const Table: FC<TableComponentProps> = ({
</div>

<div className={cx('table-body')}>
{sortedData.map((item, index) => (
{data.map((item, index) => (
<div
key={`'row-item-${item[Object.keys(item)[0]]}`}
key={item.id}
className={cx('table-row', getSizeClassName(item))}
onMouseEnter={() => handleRowMouseEnter(index)}
onMouseLeave={handleRowMouseLeave}
>
{checkboxSelection && (
{selectable && (
<div className={cx('table-cell', 'checkbox-cell')}>
{(isAnyChecked || hoveredRow === index) && (
<Checkbox
value={item.checked}
onChange={() => handleRowCheck(index)}
value={checkedRows.has(item.id)}
onChange={() => handleRowCheck(item.id)}
className={cx('checkbox-cell')}
/>
)}
Expand All @@ -162,7 +170,7 @@ export const Table: FC<TableComponentProps> = ({
})}
style={getCellStyle(column as FixedColumn)}
>
{item[column.key].component || item[column.key]}
{item[column.key].component || item[column.key].content || item[column.key]}
</div>
))}

Expand Down
Loading

0 comments on commit 13ad988

Please sign in to comment.