import * as React from 'react' import type { StoryFn, Meta } from '@storybook/react-webpack5' import { SpreadsheetGrid } from '.' import type { Column, GridProps, GridActionsMenuFullProps, GridConfirmPayload, } from '../../types' import { GridCellDefault } from '../../components' import { ListItem, ListItemDivider, ListItemInfo, Menu, } from '@planview/pv-uikit' import { Copy, Cut, Trash } from '@planview/pv-icons' import { GridEditorInputNumeric } from '../../editors' export default { title: 'pv-grid/Components/SpreadsheetGrid (Experimental)', id: 'pv-grid/Components/SpreadsheetGrid', component: SpreadsheetGrid, parameters: { badges: ['intl'], }, args: { rowHeight: 'medium', filterMode: 'default', sortMode: 'internal', }, argTypes: { onRangeCopy: { table: { category: 'Bulk editing', }, }, onBulkCellChange: { table: { category: 'Bulk editing', }, }, loading: { control: { type: 'radio' }, options: [false, true, 3, 6], table: { category: 'Status', }, }, emptyContent: { table: { category: 'Status', }, }, columns: { control: false, }, columnGroups: { control: { type: 'radio' }, options: ['without groups', 'with groups'], mapping: { 'without groups': [], 'with groups': [ { id: 'top-group', label: 'Group', children: ['title', 'price'], }, ], }, }, rows: { control: false, }, ref: { control: false, description: 'This will return an api for interacting with the grid externally.', table: { category: 'Advanced', }, }, defaultSort: { control: false, table: { category: 'Sorting', }, }, sort: { control: false, table: { category: 'Sorting', }, }, sortMode: { table: { category: 'Sorting', }, }, multiColumnSort: { table: { category: 'Sorting', }, }, onSortChange: { table: { category: 'Sorting', }, }, rangeSelection: { table: { category: 'Selection', }, }, onRangeSelectionChange: { table: { category: 'Selection', }, }, filter: { table: { category: 'Filtering', }, }, filterMode: { table: { category: 'Filtering', }, }, filteredIds: { control: { type: 'radio' }, options: ['not filtered', 'filtered', 'no matches'], mapping: { 'not filtered': undefined, filtered: ['1002'], 'no matches': [], }, table: { category: 'Filtering', }, }, preferencesAdapter: { control: false, table: { category: 'Advanced', }, }, expandedRows: { control: false, table: { category: 'Tree', }, }, onExpandedRowsChange: { table: { category: 'Tree', }, }, actionsMenu: { control: { type: 'radio' }, options: ['no actions menu', 'actions menu', 'actions menu async'], mapping: { 'no actions menu': undefined, 'actions menu': () => ( <> } label="Cut" /> } label="Copy" /> } label="Delete" /> ), 'actions menu async': { Menu({ row, menuProps }: GridActionsMenuFullProps) { const [loading, setLoading] = React.useState(true) React.useEffect(() => { const t = setTimeout(() => setLoading(false), 500) return () => clearTimeout(t) }, []) return ( {row.title} } label="Cut" /> } label="Copy" /> } label="Delete" /> ) }, }, }, table: { category: 'Context Menu', }, }, enableColumnVisibilityMenu: { control: { type: 'boolean' }, table: { category: 'Context Menu', }, }, rowDrag: { control: false, table: { category: 'Drag and Drop', }, }, onCellChange: { control: false, table: { category: 'Editing', }, }, }, } satisfies Meta type Row = { id: string title: string price?: number } const rows = [ { id: '1001', title: 'Journey to the Center of the Earth', price: 11.99 }, { id: '1002', title: 'Twenty Thousand Leagues Under the Sea', price: 35.65, }, { id: '1003', title: 'Around the World In Eighty Days', price: 29.98 }, ] const currencyFormatter = new Intl.NumberFormat(undefined, { style: 'currency', currency: 'USD', }) export const Default: StoryFn> = ({ columns: _columns, rows: _rows, ...rest }) => { const columns = React.useMemo[]>( () => [ { id: 'id', label: 'ID', width: 100, }, { id: 'title', label: 'Title', width: 400, }, { id: 'price', label: 'Price', width: 200, header: { align: 'right', }, cell: { label: ({ value }: { value: number }) => currencyFormatter.format(value), Renderer: ({ label, tabIndex }) => ( ), }, }, ], [] ) return } Default.parameters = { docs: { source: { code: ` type Book = { id: number title: string price: number } const rows = React.useMemo(() => [ { id: '1001', title: 'Journey to the Center of the Earth', price: 11.99 }, { id: '1002', title: 'Twenty Thousand Leagues Under the Sea', price: 35.65, }, { id: '1003', title: 'Around the World In Eighty Days', price: 29.98 }, ], []) const columns = React.useMemo[]>( () => [ { id: 'id', label: 'ID', width: 100, }, { id: 'title', label: 'Title', width: 400, }, { id: 'price', label: 'Price', width: 200, header: { align: 'right', }, cell: { label: ({ value }: { value: number }) => currencyFormatter.format(value), Renderer: ({ label, tabIndex }) => ( ), }, }, ], [] ) return `, }, }, } export const Editable: StoryFn> = ({ columns: _columns, rows: _rows, ...rest }) => { const [data, setData] = React.useState(rows) const columns = React.useMemo[]>( () => [ { id: 'id', label: 'ID', width: 100, }, { id: 'title', label: 'Title', width: 400, cell: { editable: true, }, }, { id: 'price', label: 'Price', width: 200, header: { align: 'right', }, cell: { editable: true, label: ({ value }: { value: number }) => currencyFormatter.format(value), Renderer: ({ label, tabIndex }) => ( ), Editor: GridEditorInputNumeric, }, }, ], [] ) return ( ) => { setData((prev) => prev.map((r) => r.id === payload.rowId ? { ...r, [payload.columnId]: payload.nextValue } : r ) ) }} {...rest} /> ) } Editable.parameters = { docs: { source: { code: ` type Book = { id: number title: string price: number } const rows = React.useMemo(() => [ { id: '1001', title: 'Journey to the Center of the Earth', price: 11.99 }, { id: '1002', title: 'Twenty Thousand Leagues Under the Sea', price: 35.65, }, { id: '1003', title: 'Around the World In Eighty Days', price: 29.98 }, ], []) const columns = React.useMemo[]>( () => [ { id: 'id', label: 'ID', width: 100, }, { id: 'title', label: 'Title', width: 400, }, { id: 'price', label: 'Price', width: 200, header: { align: 'right', }, cell: { label: ({ value }: { value: number }) => currencyFormatter.format(value), Renderer: ({ label, tabIndex }) => ( ), }, }, ], [] ) return `, }, }, }