generated from gravity-ui/package-example
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Table): table actions column added
- Loading branch information
alx-chernigin
committed
Oct 1, 2024
1 parent
8d506a9
commit a17560d
Showing
18 changed files
with
531 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
@use '@gravity-ui/uikit/styles/mixins'; | ||
@use '../variables'; | ||
|
||
$block: '.#{variables.$ns}table'; | ||
$popupBlock: '#{$block}-action-popup'; | ||
|
||
#{$popupBlock} { | ||
&__menu { | ||
@include mixins.max-height(200px); | ||
|
||
&-item { | ||
@include mixins.max-text-width(250px); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import React from 'react'; | ||
|
||
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 i18n from './i18n'; | ||
import type {TableActionConfig, TableActionGroup, TableActionsSettings} from './types'; | ||
|
||
import './DefaultRowActions.scss'; | ||
|
||
type DefaultRowActionsProps<I> = Pick< | ||
TableActionsSettings<I>, | ||
'getRowActions' | 'rowActionsSize' | ||
> & { | ||
item: I; | ||
index: number; | ||
}; | ||
|
||
const b = block('table'); | ||
const actionsCn = b('actions'); | ||
const actionsButtonCn = b('actions-button'); | ||
|
||
const bPopup = block('table-action-popup'); | ||
const menuCn = bPopup('menu'); | ||
const menuItemCn = bPopup('menu-item'); | ||
|
||
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); | ||
}; | ||
|
||
export const DefaultRowActions = <I extends unknown>({ | ||
index: rowIndex, | ||
item, | ||
getRowActions, | ||
rowActionsSize, | ||
}: DefaultRowActionsProps<I>) => { | ||
const [isPopupOpen, setIsPopupOpen] = React.useState(false); | ||
const anchorRef = React.useRef<HTMLButtonElement>(null); | ||
const rowId = useUniqId(); | ||
|
||
if (getRowActions === undefined) { | ||
return null; | ||
} | ||
|
||
const renderPopupMenuItem = (action: TableActionConfig<I>, index: number) => { | ||
if (isActionGroup(action)) { | ||
return ( | ||
<Menu.Group key={index} label={action.title}> | ||
{action.items.map(renderPopupMenuItem)} | ||
</Menu.Group> | ||
); | ||
} | ||
|
||
const {text, icon, handler, href, ...restProps} = action; | ||
|
||
return ( | ||
<Menu.Item | ||
key={index} | ||
onClick={(event) => { | ||
event.stopPropagation(); | ||
handler(item, index, event); | ||
|
||
setIsPopupOpen(false); | ||
}} | ||
href={typeof href === 'function' ? href(item, index) : href} | ||
iconStart={icon} | ||
className={menuItemCn} | ||
{...restProps} | ||
> | ||
{text} | ||
</Menu.Item> | ||
); | ||
}; | ||
|
||
const actions = getRowActions(item, rowIndex); | ||
|
||
if (actions.length === 0) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<div className={actionsCn}> | ||
<Popup | ||
open={isPopupOpen} | ||
anchorRef={anchorRef} | ||
placement={DEFAULT_PLACEMENT} | ||
onOutsideClick={() => setIsPopupOpen(false)} | ||
id={rowId} | ||
> | ||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} | ||
<div | ||
onClick={(event) => { | ||
event.stopPropagation(); | ||
}} | ||
> | ||
<Menu className={menuCn} size={rowActionsSize}> | ||
{actions.map(renderPopupMenuItem)} | ||
</Menu> | ||
</div> | ||
</Popup> | ||
<Button | ||
view="flat-secondary" | ||
className={actionsButtonCn} | ||
onClick={(event) => { | ||
setIsPopupOpen((value) => !value); | ||
event.stopPropagation(); | ||
}} | ||
size={rowActionsSize} | ||
ref={anchorRef} | ||
extraProps={{ | ||
'aria-label': i18n('label-actions'), | ||
'aria-expanded': isPopupOpen, | ||
'aria-controls': rowId, | ||
}} | ||
> | ||
<Icon data={Ellipsis} /> | ||
</Button> | ||
</div> | ||
); | ||
}; |
25 changes: 25 additions & 0 deletions
25
src/components/TableActions/__stories__/TableActions.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type {Meta, StoryObj} from '@storybook/react'; | ||
|
||
import {TableActionsColumnStory} from './stories/TableActionsColumnStory'; | ||
import {TableActionsColumnWithVirtualizationStory} from './stories/TableActionsColumnWithVirtualizationStory'; | ||
import {TableSettingsWithActionsColumnStory} from './stories/TableSettingsWithActionsColumnStory'; | ||
|
||
const meta: Meta = { | ||
title: 'Table actions', | ||
}; | ||
|
||
export default meta; | ||
|
||
export const ActionsColumn: StoryObj<typeof TableActionsColumnStory> = { | ||
render: TableActionsColumnStory, | ||
}; | ||
|
||
export const SettingsWithActionsColumn: StoryObj<typeof TableSettingsWithActionsColumnStory> = { | ||
render: TableSettingsWithActionsColumnStory, | ||
}; | ||
|
||
export const ActionsColumnWithVirtualizationStory: StoryObj< | ||
typeof TableActionsColumnWithVirtualizationStory | ||
> = { | ||
render: TableActionsColumnWithVirtualizationStory, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import React from 'react'; | ||
|
||
import {Pencil} from '@gravity-ui/icons'; | ||
import {Icon} from '@gravity-ui/uikit'; | ||
import type {ColumnDef} from '@tanstack/react-table'; | ||
|
||
import type {TableActionsSettings} from '../types'; | ||
|
||
import type {Item} from './types'; | ||
|
||
export const actionsSettings: TableActionsSettings<unknown> = { | ||
getRowActions: (item, index) => [ | ||
{ | ||
text: 'default', | ||
handler: () => { | ||
alert(JSON.stringify(item)); | ||
}, | ||
}, | ||
{ | ||
text: 'with icon', | ||
icon: <Icon data={Pencil} size={14} />, | ||
handler: () => {}, | ||
}, | ||
{ | ||
text: 'disabled', | ||
disabled: true, | ||
handler: () => {}, | ||
}, | ||
{ | ||
text: 'danger theme', | ||
theme: 'danger', | ||
handler: () => { | ||
alert(index); | ||
}, | ||
}, | ||
{ | ||
text: 'with href', | ||
theme: 'normal', | ||
href: 'https://gravity-ui.com', | ||
target: '_blank', | ||
rel: 'noopener noreferrer', | ||
handler: () => {}, | ||
}, | ||
], | ||
}; | ||
|
||
export const baseColumns: ColumnDef<Item>[] = [ | ||
{accessorKey: 'id', header: 'Index', size: 50}, | ||
{accessorKey: 'name', header: 'Name', size: 100}, | ||
{accessorKey: 'age', header: 'Age', size: 100}, | ||
{ | ||
id: 'name-age', | ||
accessorFn: (item) => `${item.name}: ${item.age}`, | ||
header: () => <b>Name: Age</b>, | ||
cell: (info) => <i>{info.getValue<string>()}</i>, | ||
maxSize: 200, | ||
minSize: 100, | ||
}, | ||
{ | ||
accessorKey: 'status', | ||
header: 'Status', | ||
size: 100, | ||
}, | ||
]; |
77 changes: 77 additions & 0 deletions
77
src/components/TableActions/__stories__/stories/TableActionsColumnStory.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
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 {Table} from '../../../Table/Table'; | ||
import {actionsSettings, baseColumns} from '../constants'; | ||
import type {Item} from '../types'; | ||
import {generateData} from '../utils'; | ||
|
||
const data = generateData(5); | ||
|
||
const defaultColumns: 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: ({index}) => { | ||
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 TableActionsColumnStory = () => { | ||
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({}); | ||
const table = useTable({ | ||
columns: defaultColumns, | ||
data, | ||
state: {rowSelection}, | ||
enableRowSelection: true, | ||
enableMultiRowSelection: true, | ||
onRowSelectionChange: setRowSelection, | ||
}); | ||
|
||
const tableWithRenderRowActions = useTable({ | ||
columns: columnsWithRenderRowActions, | ||
data, | ||
state: {rowSelection}, | ||
enableRowSelection: true, | ||
enableMultiRowSelection: true, | ||
onRowSelectionChange: setRowSelection, | ||
}); | ||
|
||
return ( | ||
<React.Fragment> | ||
<h3>{'with getRowActions property'}</h3> | ||
<Table table={table} /> | ||
<br /> | ||
<h3>{'with renderRowActions property'}</h3> | ||
<Table table={tableWithRenderRowActions} /> | ||
</React.Fragment> | ||
); | ||
}; |
38 changes: 38 additions & 0 deletions
38
...components/TableActions/__stories__/stories/TableActionsColumnWithVirtualizationStory.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import React from 'react'; | ||
|
||
import type {ColumnDef, RowSelectionState} from '@tanstack/react-table'; | ||
|
||
import {ACTIONS_COLUMN_ID, getActionsColumn, selectionColumn} from '../../../../constants'; | ||
import {useTable, useWindowRowVirtualizer} from '../../../../hooks'; | ||
import {Table} from '../../../Table/Table'; | ||
import {actionsSettings, baseColumns} from '../constants'; | ||
import type {Item} from '../types'; | ||
import {generateData} from '../utils'; | ||
|
||
const data = generateData(300); | ||
|
||
const columns: ColumnDef<Item>[] = [ | ||
selectionColumn as ColumnDef<Item>, | ||
...baseColumns, | ||
getActionsColumn<Item>(ACTIONS_COLUMN_ID, actionsSettings), | ||
]; | ||
|
||
export const TableActionsColumnWithVirtualizationStory = () => { | ||
const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({}); | ||
const table = useTable({ | ||
columns, | ||
data, | ||
state: {rowSelection}, | ||
enableRowSelection: true, | ||
enableMultiRowSelection: true, | ||
onRowSelectionChange: setRowSelection, | ||
}); | ||
|
||
const rowVirtualizer = useWindowRowVirtualizer({ | ||
count: table.getRowModel().rows.length, | ||
estimateSize: () => 50, | ||
overscan: 5, | ||
}); | ||
|
||
return <Table table={table} rowVirtualizer={rowVirtualizer} />; | ||
}; |
39 changes: 39 additions & 0 deletions
39
src/components/TableActions/__stories__/stories/TableSettingsWithActionsColumnStory.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from 'react'; | ||
|
||
import type {ColumnDef, ColumnPinningState} from '@tanstack/react-table'; | ||
|
||
import {SETTINGS_WITH_ACTIONS_COLUMN_ID, getSettingsWithActionsColumn} from '../../../../constants'; | ||
import {useTable} from '../../../../hooks'; | ||
import {Table} from '../../../Table/Table'; | ||
import {actionsSettings, baseColumns} from '../constants'; | ||
import type {Item} from '../types'; | ||
import {generateData} from '../utils'; | ||
|
||
const data = generateData(5); | ||
|
||
const columns: ColumnDef<Item>[] = [ | ||
...baseColumns, | ||
getSettingsWithActionsColumn<Item>(SETTINGS_WITH_ACTIONS_COLUMN_ID, { | ||
actions: actionsSettings, | ||
settings: { | ||
sortable: true, | ||
filterable: true, | ||
}, | ||
}), | ||
]; | ||
|
||
export const TableSettingsWithActionsColumnStory = () => { | ||
const [columnPinning, setColumnPinning] = React.useState<ColumnPinningState>({ | ||
left: [], | ||
right: [SETTINGS_WITH_ACTIONS_COLUMN_ID], | ||
}); | ||
const table = useTable({ | ||
columns, | ||
data, | ||
enableColumnPinning: true, | ||
state: {columnPinning}, | ||
onColumnPinningChange: setColumnPinning, | ||
}); | ||
|
||
return <Table table={table} />; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface Item { | ||
id: string; | ||
parentId?: string | undefined; | ||
name: string; | ||
age: number; | ||
status?: 'free' | 'busy' | 'unknown'; | ||
} |
Oops, something went wrong.