Skip to content

Commit

Permalink
fix(table): #98 Table cellEditor not works with select component
Browse files Browse the repository at this point in the history
  • Loading branch information
trigoporres committed Nov 7, 2024
1 parent 6fefefd commit edc266a
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 8 deletions.
7 changes: 6 additions & 1 deletion packages/table/src/core/Cell/useRenderContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import * as React from 'react';
import { useOnEventOutside } from '@devoinc/genesys-ui';

import type { TColDef, TRow } from '../../declarations';
import { TableContext } from '../../context';

export const useRenderContent = (
colDef: TColDef,
data: unknown,
rowIndex: number,
row: TRow,
) => {
const { onCellDataChange } = React.useContext(TableContext);
const cellRef = React.useRef<HTMLTableCellElement>();

const viewContent = colDef.cellRenderer
? colDef.cellRenderer({
value: colDef.valueFormatter
Expand All @@ -28,7 +31,9 @@ export const useRenderContent = (
? colDef.cellEditor({
value: data,
colDef,
rowIndex,
onChange: (value) => {
onCellDataChange({ colDef, value, rowIndex });
},
})
: null;

Expand Down
2 changes: 2 additions & 0 deletions packages/table/src/core/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const Table: React.FC<TableProps> = ({
onCellMouseLeave,
highlightRowOnHover,
highlightRowOnHoverFn,
onCellDataChange,
data,
resizableColumns = false,
rowHeight = ROW_HEIGHT_MD,
Expand Down Expand Up @@ -59,6 +60,7 @@ export const Table: React.FC<TableProps> = ({
onFilter,
onCellMouseEnter,
onCellMouseLeave,
onCellDataChange,
highlightRowOnHover,
highlightRowOnHoverFn,
rowHeight,
Expand Down
4 changes: 2 additions & 2 deletions packages/table/src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export type TColDef = {
editable?: boolean;
cellEditor?:
| React.FC<TCellEditor>
| (({ value, onChange }: TCellEditor) => React.ReactNode);
| (({ value, onChange, colDef }: TCellEditor) => React.ReactNode);

valueFormatter?: (value: unknown, context: DateContext) => void;
cellRenderer?:
Expand Down Expand Up @@ -184,7 +184,6 @@ export type TCellEditor = {
value?: unknown;
onChange?: (value: unknown) => void;
colDef?: TColDef;
rowIndex: number;
};

export interface ITable {
Expand All @@ -201,6 +200,7 @@ export interface ITable {
rowHeight?: number;
// cell
cellDefs?: TCellDef[];
onCellDataChange?: ({ colDef, value, rowIndex }) => void;

context?: {
[key: string]: unknown;
Expand Down
4 changes: 3 additions & 1 deletion packages/table/src/editors/OptionsEditor/OptionsEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export const OptionsEditor: React.FC<TCellEditor> = ({
<SelectControl
defaultMenuIsOpen
hideSelectedOptions={!isMultiple}
onChange={onChange}
onChange={(event) => {
onChange(event.value)
}}
value={String(value)}
creatable
isMulti={isMultiple}
Expand Down
138 changes: 138 additions & 0 deletions packages/table/src/editors/Table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import * as React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Holo } from '@devoinc/holo';

import { Flex, Select } from '@devoinc/genesys-ui';

import { BasicTable, getSelectOptions, TColDef, TContextOptions } from '..';
import { ROW_HEIGHT_MD } from '../constants';

const meta: Meta<typeof BasicTable> = {
title: 'Components/Layout/Table/Editors/CellsEditor',
component: BasicTable,
parameters: {
layout: 'fullscreen',
},
};

export default meta;
type Story = StoryObj<typeof BasicTable>;

const data = Holo.of()
.addType('index', (args = {}) => args.index + 1)
.schema({
id: 'index',
booleanValue: 'bool',
name: 'name',
age: 'age',
status: () => Holo.chance.pickone(['TODO', 'inProgress', 'test', 'done']),
custom: () =>
Holo.chance.pickone(['read', 'view', 'inProgress', 'completed']),
picture: 'avatar',
})
.repeat(9)
.generate();

const colDefs: TColDef = [
{
id: 'id',
preset: 'text',
headerName: 'ID',
},
{
id: 'booleanValue',
headerName: 'Boolean value',
preset: 'boolean',
},
{
id: 'name',
headerName: 'Name',
preset: 'text',
},
{
id: 'age',
headerName: 'Age',
preset: 'number',
},
{
id: 'status',
headerName: 'Status',
preset: 'options',
context: {
options: {
done: { colorScheme: 'success' },
test: { colorScheme: 'warning' },
TODO: { colorScheme: 'data-purple' },
inProgress: { colorScheme: 'data-blue' },
},
},
},
{
id: 'custom',
headerName: 'Custom',
preset: 'options',
cellEditor: ({ value, onChange, colDef }) => {
const options = (colDef?.context as TContextOptions)?.options;

return (
<Select
id={'test'}
label={'custom'}
placeholder={'custom'}
menuAppendToBody
onChange={(event) => {
onChange(event.value)
}}
options={getSelectOptions(options)}
value={String(value)}
/>
);
},
context: {
options: {
read: { colorScheme: 'success' },
view: { colorScheme: 'warning' },
completed: { colorScheme: 'data-purple' },
inProgress: { colorScheme: 'data-blue' },
},
},
},
{
id: 'picture',
headerName: 'Image (URL)',
preset: 'link',
},
];

const BasicCmp = ({ data, colDefs }) => {
const [newData, setNewData] = React.useState(data);
return (
<Flex flexDirection="column" gap="cmp-md" height={'auto'}>
<Flex.Item>
<BasicTable
data={newData}
colDefs={colDefs}
defaultColDef={{
editable: true,
}}
maxHeight="80vh"
rowHeight={ROW_HEIGHT_MD}
onCellDataChange={({ colDef, value, rowIndex }) => {
setNewData(
newData.map((data, index) => {
if (index === rowIndex) {
data[colDef.id] = value;
}
return data;
}),
);
}}
/>
</Flex.Item>
</Flex>
);
};

export const TableCellsEditor: Story = {
render: () => <BasicCmp data={data} colDefs={colDefs} />,
};
57 changes: 57 additions & 0 deletions packages/table/src/editors/TableCellEditor.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Meta } from '@storybook/blocks';

import * as Stories from './Table.stories';

<Meta of={Stories} />

# Editors Table

Through the editable cells we can modify the value of a specific cell. The predefined columns already come with a cell editor defined. However whether it is a predefined column or a 100% custom column **you can use a custom cell editor**.

Editable cells receive the following parameters:

```ts
(({ value, onChange, colDef }: TCellEditor) => React.ReactNode)
```

```ts
// example cell editor custom
({ value, onChange, colDef }) => {
const options = (colDef?.context as TContextOptions)?.options;

return (
<Select
id={'test'}
label={'custom'}
placeholder={'custom'}
menuAppendToBody
onChange={(event) => {
onChange(event.value)
}}
options={getSelectOptions(options)}
value={String(value)}
/>
);
}
```

To “hook” to the data changes that happen in the editable cells we will pass to the table a parameter called: **onCellDataChange**.

```ts
onCellDataChange?: ({ colDef, value, rowIndex }) => void;
```

This will allow us to receive the necessary information from the modified cell and then do what we need to do. For example:

```ts
onCellDataChange={({ colDef, value, rowIndex }) => {
setNewData(
newData.map((data, index) => {
if (index === rowIndex) {
data[colDef.id] = value;
}
return data;
}),
);
}}
```
2 changes: 2 additions & 0 deletions packages/table/src/recipes/BasicTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const BasicTable: React.FC<TableProps> = ({
columnPresets,
rowPresets,
highlightRowOnHoverFn,
onCellDataChange,
...props
}) => (
<Table
Expand All @@ -15,6 +16,7 @@ export const BasicTable: React.FC<TableProps> = ({
...(columnPresets ?? []),
...Object.values(listColumnPresets),
]}
onCellDataChange={onCellDataChange}
rowPresets={[...(rowPresets ?? []), ...Object.values(listRowPresets)]}
highlightRowOnHoverFn={highlightRowOnHoverFn || ((rowDef) => rowDef.preset !== 'isAfterRow')}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/table/stories/table/BasicTable.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import * as Stories from './BasicTable.stories';

# Basic table

<Canvas of={Stories.Base} />
<Canvas of={Stories.Basic} />

This table is preloaded with column preset and [row preset](/docs/components-layout-table-row-presets--docs) that table package offers.
23 changes: 20 additions & 3 deletions packages/table/stories/table/BasicTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { Meta, StoryObj } from '@storybook/react';

import { Flex } from '@devoinc/genesys-ui';

import { BasicTable, orderDataByOrderStruct, TColDef, updateColDefsWithOrderStruct, useOrderStruct } from '../../src';
import {
BasicTable,
orderDataByOrderStruct,
TColDef,
updateColDefsWithOrderStruct,
useOrderStruct,
} from '../../src';
import { ROW_HEIGHT_MD } from '../../src/constants';
import { allTypesData } from './data/allTypesData';
import { AllTypesColumn } from './column/AllTypesColumn';
Expand All @@ -23,16 +29,19 @@ export default meta;
type Story = StoryObj<typeof BasicTable>;

const BasicCmp = ({ data, colDefs }) => {
const [newData, setNewData] = React.useState(data);
const { orderStruct, onSort } = useOrderStruct([{ id: 'id', sort: 'desc' }]);
const dataOrdered = [...data].sort(orderDataByOrderStruct(orderStruct));
React.useEffect(() => {
setNewData([...newData].sort(orderDataByOrderStruct(orderStruct)));
}, []);
return (
<Flex flexDirection="column" gap="cmp-md" height={'auto'}>
<Flex.Item>
<BasicTable
onSort={(colDef: TColDef) => {
onSort(colDef.id);
}}
data={dataOrdered}
data={newData}
colDefs={updateColDefsWithOrderStruct(colDefs, orderStruct)}
defaultColDef={{
editable: false,
Expand All @@ -42,6 +51,14 @@ const BasicCmp = ({ data, colDefs }) => {
rowHeight={ROW_HEIGHT_MD}
highlightRowOnHover={true}
showFilters={true}
onCellDataChange={({ colDef, value, rowIndex }) => {
setNewData(newData.map((data, index) => {
if(index === rowIndex) {
data[colDef.id] = value
}
return data
}))
}}
/>
</Flex.Item>
</Flex>
Expand Down

0 comments on commit edc266a

Please sign in to comment.