Skip to content

Commit

Permalink
feat(Table): review fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
alx-chernigin committed Oct 22, 2024
1 parent 3dee229 commit f63db62
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 99 deletions.
3 changes: 3 additions & 0 deletions src/components/RowActions/RowActions.classname.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import {block} from '../../utils';

export const b = block('row-actions');
12 changes: 5 additions & 7 deletions src/components/RowActions/RowActions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ $block: '.#{variables.$ns}row-actions';
display: flex;
align-items: center;

&-popup {
&__menu {
@include mixins.max-height(200px);
&__popup-menu {
@include mixins.max-height(200px);
}

&-item {
@include mixins.max-text-width(250px);
}
}
&__popup-menu-item {
@include mixins.max-text-width(250px);
}
}
86 changes: 49 additions & 37 deletions src/components/RowActions/RowActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,65 @@ import {Ellipsis} from '@gravity-ui/icons';
import type {PopupPlacement} from '@gravity-ui/uikit';
import {Button, Icon, Menu, Popup, useUniqId} from '@gravity-ui/uikit';

import {block} from '../../utils';

import {b} from './RowActions.classname';
import i18n from './i18n';
import type {TableActionConfig, TableActionGroup, TableActionsSettings} from './types';

import './RowActions.scss';

type RowActionsProps<I> = Pick<TableActionsSettings<I>, 'getRowActions' | 'rowActionsSize'> & {
item: I;
type RowActionsProps<TValue> = Pick<
TableActionsSettings<TValue>,
'getRowActions' | 'rowActionsSize'
> & {
item: TValue;
index: number;
};

const b = block('row-actions');
const bPopup = block('row-actions-popup');

const DEFAULT_PLACEMENT: PopupPlacement = ['bottom-end', 'top-end', 'auto'];

const isActionGroup = <I extends unknown>(
config: TableActionConfig<I>,
): config is TableActionGroup<I> => {
return Array.isArray((config as TableActionGroup<I>).items);
const isActionGroup = <TValue extends unknown>(
config: TableActionConfig<TValue>,
): config is TableActionGroup<TValue> => {
return Array.isArray((config as TableActionGroup<TValue>).items);
};

export const RowActions = <I extends unknown>({
export const RowActions = <TValue extends unknown>({
index: rowIndex,
item,
getRowActions,
rowActionsSize,
}: RowActionsProps<I>) => {
}: RowActionsProps<TValue>) => {
const [isPopupOpen, setIsPopupOpen] = React.useState(false);
const anchorRef = React.useRef<HTMLButtonElement>(null);
const rowId = useUniqId();

const buttonExtraProps = React.useMemo(
() => ({
'aria-label': i18n('label-actions'),
'aria-expanded': isPopupOpen,
'aria-controls': rowId,
}),
[isPopupOpen, rowId],
);
const handleButtonClick = React.useCallback(
(event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => {
setIsPopupOpen((value) => !value);
event.stopPropagation();
},
[],
);

if (getRowActions === undefined) {
return null;
}

const renderPopupMenuItem = (action: TableActionConfig<I>, index: number) => {
const actions = getRowActions(item, rowIndex);

if (actions.length === 0) {
return null;
}

const renderPopupMenuItem = (action: TableActionConfig<TValue>, index: number) => {
if (isActionGroup(action)) {
return (
<Menu.Group key={index} label={action.title}>
Expand All @@ -52,31 +73,29 @@ export const RowActions = <I extends unknown>({

const {text, icon, handler, href, ...restProps} = action;

const handleMenuItemClick = (
event: React.MouseEvent<HTMLDivElement | HTMLAnchorElement, MouseEvent>,
) => {
event.stopPropagation();
handler(item, index, event);

setIsPopupOpen(false);
};

return (
<Menu.Item
key={index}
onClick={(event) => {
event.stopPropagation();
handler(item, index, event);

setIsPopupOpen(false);
}}
onClick={handleMenuItemClick}
href={typeof href === 'function' ? href(item, index) : href}
iconStart={icon}
className={bPopup('menu-item')}
className={b('popup-menu-item')}
{...restProps}
>
{text}
</Menu.Item>
);
};

const actions = getRowActions(item, rowIndex);

if (actions.length === 0) {
return null;
}

return (
<div className={b()}>
<Popup
Expand All @@ -92,25 +111,18 @@ export const RowActions = <I extends unknown>({
event.stopPropagation();
}}
>
<Menu className={bPopup('menu')} size={rowActionsSize}>
<Menu className={b('popup-menu')} size={rowActionsSize}>
{actions.map(renderPopupMenuItem)}
</Menu>
</div>
</Popup>
<Button
view="flat-secondary"
className={b('actions-button')}
onClick={(event) => {
setIsPopupOpen((value) => !value);
event.stopPropagation();
}}
onClick={handleButtonClick}
size={rowActionsSize}
ref={anchorRef}
extraProps={{
'aria-label': i18n('label-actions'),
'aria-expanded': isPopupOpen,
'aria-controls': rowId,
}}
extraProps={buttonExtraProps}
>
<Icon data={Ellipsis} />
</Button>
Expand Down
5 changes: 5 additions & 0 deletions src/components/RowActions/__stories__/RowActions.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {Meta, StoryObj} from '@storybook/react';

import {RowActionsColumnStory} from './stories/RowActionsColumnStory';
import {RowActionsWithActionsColumnStory} from './stories/RowActionsWithActionsColumnStory';
import {RowActionsWithCustomRendering} from './stories/RowActionsWithCustomRendering';

const meta: Meta = {
title: 'Table actions',
Expand All @@ -13,6 +14,10 @@ export const ActionsColumn: StoryObj<typeof RowActionsColumnStory> = {
render: RowActionsColumnStory,
};

export const CustomActions: StoryObj<typeof RowActionsWithCustomRendering> = {
render: RowActionsWithCustomRendering,
};

export const SettingsWithActionsColumn: StoryObj<typeof RowActionsWithActionsColumnStory> = {
render: RowActionsWithActionsColumnStory,
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from 'react';

import {Select} from '@gravity-ui/uikit';
import type {ColumnDef, RowSelectionState} from '@tanstack/react-table';

import {ACTIONS_COLUMN_ID, getActionsColumn, selectionColumn} from '../../../../constants';
Expand All @@ -12,69 +11,24 @@ import {actionsSettings, baseColumns} from '../constants';

const data = generateData(5);

const defaultColumns: ColumnDef<Item>[] = [
const columns: ColumnDef<Item>[] = [
selectionColumn as ColumnDef<Item>,
...baseColumns,
getActionsColumn<Item>(ACTIONS_COLUMN_ID, {
...actionsSettings,
}),
];

const columnsWithRenderRowActions: ColumnDef<Item>[] = [
selectionColumn as ColumnDef<Item>,
...baseColumns,
getActionsColumn<Item>(ACTIONS_COLUMN_ID, {
...actionsSettings,
renderRowActions: ({row}) => {
const {index} = row;
if (index % 2) {
return null;
}

return (
<Select
options={[
{value: '1', text: 'action 1', content: 'action 1'},
{value: '2', text: 'action 2', content: 'action 2'},
{value: '3', text: 'action 3', content: 'action 3'},
]}
size="s"
title="Actions select example"
/>
);
},
}),
];

export const RowActionsColumnStory = () => {
const [rowSelectionForTable, setRowSelectionForTable] = React.useState<RowSelectionState>({});
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});
const table = useTable({
columns: defaultColumns,
data,
state: {rowSelection: rowSelectionForTable},
enableRowSelection: true,
enableMultiRowSelection: true,
onRowSelectionChange: setRowSelectionForTable,
});

const [rowSelectionForTableWithRenderRowActions, setRowSelectionForTableWithRenderRowActions] =
React.useState<RowSelectionState>({});
const tableWithRenderRowActions = useTable({
columns: columnsWithRenderRowActions,
columns,
data,
state: {rowSelection: rowSelectionForTableWithRenderRowActions},
state: {rowSelection},
enableRowSelection: true,
enableMultiRowSelection: true,
onRowSelectionChange: setRowSelectionForTableWithRenderRowActions,
onRowSelectionChange: setRowSelection,
});

return (
<React.Fragment>
<h3>{'with getRowActions property'}</h3>
<Table table={table} />
<br />
<h3>{'with renderRowActions property'}</h3>
<Table table={tableWithRenderRowActions} />
</React.Fragment>
);
return <Table table={table} />;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';

import {Select} from '@gravity-ui/uikit';
import type {ColumnDef, RowSelectionState} from '@tanstack/react-table';

import {ACTIONS_COLUMN_ID, getActionsColumn, selectionColumn} from '../../../../constants';
import {useTable} from '../../../../hooks';
import type {Item} from '../../../BaseTable/__stories__/types';
import {generateData} from '../../../BaseTable/__stories__/utils';
import {Table} from '../../../Table/Table';
import {actionsSettings, baseColumns} from '../constants';

const data = generateData(5);

const columns: ColumnDef<Item>[] = [
selectionColumn as ColumnDef<Item>,
...baseColumns,
getActionsColumn<Item>(ACTIONS_COLUMN_ID, {
...actionsSettings,
renderRowActions: ({row}) => {
const {index} = row;
if (index % 2) {
return null;
}

return (
<Select
options={[
{value: '1', text: 'action 1', content: 'action 1'},
{value: '2', text: 'action 2', content: 'action 2'},
{value: '3', text: 'action 3', content: 'action 3'},
]}
size="s"
title="Actions select example"
/>
);
},
}),
];

export const RowActionsWithCustomRendering = () => {
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});
const table = useTable({
columns,
data,
state: {rowSelection},
enableRowSelection: true,
enableMultiRowSelection: true,
onRowSelectionChange: setRowSelection,
});

return <Table table={table} />;
};
7 changes: 4 additions & 3 deletions src/constants/settingsWithActionsColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@ export const getSettingsWithActionsColumn = <TData extends unknown>(
settings?: TableSettingsOptions;
},
): ColumnDef<TData> => {
const {cell} = getActionsColumn(columnId, options.actions);
const {header} = getSettingsColumn<TData>(columnId, options.settings);
return {
...getActionsColumn(columnId, options.actions),
...getSettingsColumn(columnId, options.settings),

id: columnId,
size: SETTINGS_WITH_ACTIONS_COLUMN_SIZE,
minSize: SETTINGS_WITH_ACTIONS_COLUMN_SIZE,
cell,
header,
};
};

0 comments on commit f63db62

Please sign in to comment.