import * as React from 'react' import type { StoryFn, Meta } from '@storybook/react-webpack5' import type { Column, GridApi, GridConfirmPayload } from '..' import { GridEditorSwitch, Grid, GridCellDefault } from '..' import { ButtonEmpty } from '@planview/pv-uikit' import { Lock, PlusCircle, Trash } from '@planview/pv-icons' import styled from 'styled-components' import { theme, spacingPx } from '@planview/pv-utilities' export default { title: 'pv-grid/Examples/Editable', tags: ['hidden'], } satisfies Meta const PageWrapper = styled.div` max-width: 720px; width: 100%; margin: ${spacingPx.large} auto; ` const Actions = styled.div` display: flex; flex-direction: row; gap: ${spacingPx.small}; ` type Metric = { id: string name: string abbreviation: string weight: number inverted: boolean question: string } const INITIAL: Metric[] = [ { id: '1', name: 'Value', abbreviation: 'V', weight: 20, inverted: false, question: 'How valuable is this work?', }, { id: '2', name: 'Time Criticality', abbreviation: 'TC', weight: 20, inverted: false, question: 'How critical is it to do this work now?', }, { id: '3', name: 'Risk Reduction', abbreviation: 'RR', weight: 20, inverted: false, question: 'How much does this work reduce future risk?', }, { id: '4', name: 'Effort', abbreviation: 'E', weight: 40, inverted: true, question: 'How much effort is involved in this work?', }, ] const COLUMN_DEFAULTS: Partial> = { sortable: false, resizable: false, movable: false, cell: { editable: true, }, } export const CardScoring: StoryFn = () => { const [selection, setSelection] = React.useState>(new Set()) const [metrics, setMetrics] = React.useState(INITIAL) const gridRef = React.useRef(null) const canDelete = !!selection.size const canCreate = metrics.length < 6 const handleDelete = React.useCallback(() => { setSelection(new Set()) setMetrics((ms) => ms.filter((m) => !selection.has(m.id))) }, [selection]) const handleAdd = React.useCallback(() => { const id = Math.floor(Math.random() * 10000).toString() setMetrics((m) => [ ...m, { id, name: 'Untitled Metric', abbreviation: 'UM', weight: 1, inverted: false, question: 'Untitled question', }, ]) if (gridRef.current) { const api = gridRef.current setTimeout(() => { console.log('Start editing', id, 'name') api.edit.start({ columnId: 'name', rowId: id }) api.focus.set(id, 'name', 'body') }, 0) } }, []) const handleCellChange = React.useCallback( (payload: GridConfirmPayload) => { setMetrics((_metrics) => _metrics.map((metric) => { if (metric.id === payload.rowId) { if (payload.columnId === 'name') { return { ...metric, name: payload.nextValue, abbreviation: payload.nextValue ? payload.nextValue .split(' ') .map((v) => [...v][0].toUpperCase()) .join('') : metric.abbreviation, } } return { ...metric, [payload.columnId]: payload.nextValue, } } return metric }) ) }, [] ) return ( } disabled={!canCreate} onClick={handleAdd} > Add Metric } disabled={!canDelete} onClick={handleDelete} > Delete Selected []>( () => [ { ...COLUMN_DEFAULTS, id: 'name', label: 'Name', width: 172, }, { ...COLUMN_DEFAULTS, id: 'abbreviation', label: 'Abbreviation', width: 90, }, { ...COLUMN_DEFAULTS, id: 'weight', label: 'Weight', width: 70, header: { align: 'right', }, cell: { editable: true, Renderer({ value, tabIndex }) { return ( ) }, }, }, { ...COLUMN_DEFAULTS, id: 'inverted', label: 'Inverted', cell: { editable: ({ row }) => row.id !== '2', hybridEditor: true, Renderer: ({ tabIndex }) => ( } /> ), Editor: GridEditorSwitch, }, width: 70, }, { ...COLUMN_DEFAULTS, id: 'question', label: 'Question / Definition', width: 280, }, ], [] )} rows={metrics} onCellChange={handleCellChange} /> ) } CardScoring.parameters = { docs: { source: { code: ` const [selection, setSelection] = React.useState>(new Set()) const [metrics, setMetrics] = React.useState(INITIAL) const gridRef = React.useRef(null) const canDelete = !!selection.size const canCreate = metrics.length < 6 const handleDelete = React.useCallback(() => { setSelection(new Set()) setMetrics((ms) => ms.filter((m) => !selection.has(m.id))) }, [selection]) const handleAdd = React.useCallback(() => { const id = Math.floor(Math.random() * 10000).toString() setMetrics((m) => [ ...m, { id, name: 'Untitled Metric', abbreviation: 'UM', weight: 1, inverted: false, question: 'Untitled question', }, ]) if (gridRef.current) { const api = gridRef.current setTimeout(() => { console.log('Start editing', id, 'name') api.edit.start({ columnId: 'name', rowId: id }) api.focus.set(id, 'name', 'body') }, 0) } }, []) const handleCellChange = React.useCallback( (payload: GridConfirmPayload) => { setMetrics((_metrics) => _metrics.map((metric) => { if (metric.id === payload.rowId) { if (payload.columnId === 'name') { return { ...metric, name: payload.nextValue, abbreviation: payload.nextValue ? payload.nextValue .split(' ') .map((v) => [...v][0].toUpperCase()) .join('') : metric.abbreviation, } } return { ...metric, [payload.columnId]: payload.nextValue, } } return metric }) ) }, [] ) return ( } disabled={!canCreate} onClick={handleAdd} > Add Metric } disabled={!canDelete} onClick={handleDelete} > Delete Selected []>( () => [ { ...COLUMN_DEFAULTS, id: 'name', label: 'Name', width: 172, }, { ...COLUMN_DEFAULTS, id: 'abbreviation', label: 'Abbreviation', width: 90, }, { ...COLUMN_DEFAULTS, id: 'weight', label: 'Weight', width: 70, header: { align: 'right', }, cell: { editable: true, Renderer({ value, tabIndex }) { return ( ) }, }, }, { ...COLUMN_DEFAULTS, id: 'inverted', label: 'Inverted', cell: { editable: ({ row }) => row.id !== '2', hybridEditor: true, Renderer: ({ tabIndex }) => ( } /> ), Editor: GridEditorSwitch, }, width: 70, }, { ...COLUMN_DEFAULTS, id: 'question', label: 'Question / Definition', width: 280, }, ], [] )} rows={metrics} onCellChange={handleCellChange} /> ) `, }, }, }