Custom Editor
For writing a custom editor, you can use the useInfiniteColumnEditor
hook.
For any column (or column type - which can then get applied to multiple columns), you can specify a custom editor component to be used for editing the column's value, via the column.components.editor
property.
const columns: InfiniteTablePropColumns<Developer> = {
id: {
field: 'id',
defaultEditable: false,
},
firstName: {
field: 'firstName',
components: {
// this is using a custom editor component
editor: CustomEditor,
},
},
age: {
field: 'age',
type: 'number',
defaultEditable: false,
},
stack: { field: 'stack' },
currency: { field: 'currency' },
};
The editor component should use the useInfiniteColumnEditor
hook to have access to cell-related information and to confirm, cancel or reject the edit.
import { useInfiniteColumnEditor } from '@infinite-table/infinite-react';
const CustomEditor = () => {
const { initialValue, confirmEdit, cancelEdit } = useInfiniteColumnEditor();
const domRef = React.useRef<HTMLInputElement>(null);
const onKeyDown = useCallback((event: React.KeyboardEvent) => {
const { key } = event;
if (key === 'Enter' || key === 'Tab') {
confirmEdit(domRef.current?.value);
} else if (key === 'Escape') {
cancelEdit();
} else {
event.stopPropagation();
}
}, []);
return (
<div>
<input
style={{ width: '100%' }}
autoFocus
ref={domRef}
defaultValue={initialValue}
onKeyDown={onKeyDown}
/>
</div>
);
};
Note
Inside any custom editor component, you can use the useInfiniteColumnCell
hook to get access to the cell-related information.
In this example, the salary
column is configured with a custom editor component.
import { InfiniteTable, DataSource, InfiniteTablePropColumns, useInfiniteColumnEditor, } from '@infinite-table/infinite-react'; import { useRef, useCallback } from 'react'; type Developer = { id: number; firstName: string; currency: string; stack: string; hobby: string; salary: string; }; const dataSource: Developer[] = [ { id: 1, firstName: 'John', currency: 'USD', stack: 'frontend', hobby: 'gaming', salary: 'USD 1000', }, { id: 2, firstName: 'Jane', currency: 'EUR', stack: 'backend', hobby: 'reading', salary: 'EUR 2000', }, { id: 3, firstName: 'Jack', currency: 'GBP', stack: 'frontend', hobby: 'gaming', salary: 'GBP 3000', }, { id: 4, firstName: 'Jill', currency: 'USD', stack: 'backend', hobby: 'reading', salary: 'USD 4000', }, ]; const CustomEditor = () => { const { initialValue, confirmEdit, cancelEdit } = useInfiniteColumnEditor(); const domRef = useRef<HTMLInputElement>(null); const onKeyDown = useCallback((event: React.KeyboardEvent) => { const { key } = event; if (key === 'Enter' || key === 'Tab') { confirmEdit(domRef.current?.value); } else if (key === 'Escape') { cancelEdit(); } else { event.stopPropagation(); } }, []); return ( <div style={{ background: '#ad1', padding: 5, width: '100%', height: '100%', position: 'absolute', left: 0, top: 0, }} > <input style={{ width: '100%', height: '100%' }} autoFocus ref={domRef} defaultValue={initialValue} onKeyDown={onKeyDown} /> </div> ); }; const columns: InfiniteTablePropColumns<Developer> = { id: { field: 'id', defaultWidth: 80, defaultEditable: false }, salary: { components: { // reference to the custom editor component Editor: CustomEditor, }, defaultWidth: 320, field: 'salary', header: 'Salary - edit accepts numbers only', style: { color: 'tomato' }, getValueToEdit: ({ value }) => { return parseInt(value.substr(4), 10); }, getValueToPersist: ({ value, data }) => { return `${data!.currency} ${parseInt(value, 10)}`; }, shouldAcceptEdit: ({ value }) => { return parseInt(value, 10) == value; }, }, firstName: { field: 'firstName', header: 'Name', }, currency: { field: 'currency', header: 'Currency', }, }; export default function InlineEditingExample() { return ( <> <DataSource<Developer> primaryKey="id" data={dataSource}> <InfiniteTable<Developer> columns={columns} columnDefaultEditable /> </DataSource> </>
Using Custom Date Editors
A common use-case is integrating date editors, so in the following example we'll use the MUI X Date Picker component.
This is a basic example integrating with the MUI X Date Picker - click any cell in the Birth Date column to show the date picker.
import { InfiniteTable, DataSource, useInfiniteColumnEditor, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import { StyledEngineProvider } from '@mui/material/styles'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import dayjs from 'dayjs'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import * as React from 'react'; type Developer = { birthDate: Date; id: number; firstName: string; country: string; city: string; currency: string; email: string; preferredLanguage: string; hobby: string; salary: number; }; const DATE_FORMAT = 'YYYY-MM-DD'; const DateEditor = () => { const { value, confirmEdit, cancelEdit } = useInfiniteColumnEditor(); const day = dayjs(value); return ( <DatePicker slotProps={{ textField: { sx: { width: '100%', height: '100%', background: 'white', padding: '3px', }, }, }} value={day} open orientation="landscape" format={DATE_FORMAT} onError={cancelEdit} onClose={cancelEdit} onAccept={(day) => { if (day) { confirmEdit(day.toDate()); } }} /> ); }; const columns: InfiniteTablePropColumns<Developer> = { firstName: { field: 'firstName', header: 'First Name' }, birthDate: { field: 'birthDate', header: 'Birth Date', // we need to specify the type of the column as "date" type: 'date', defaultEditable: true, defaultWidth: 200, components: { Editor: DateEditor, }, style: ({ inEdit }) => { return inEdit ? { padding: 0 } : {}; }, renderValue: ({ value }: { value: Date }) => { return <b>{dayjs(value).format(DATE_FORMAT)}</b>; }, }, salary: { field: 'salary', header: 'Salary', type: 'number', }, country: { field: 'country', header: 'Country' }, preferredLanguage: { field: 'preferredLanguage' }, id: { field: 'id' }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; export default function LocalUncontrolledSingleSortingExample() { return ( <> <StyledEngineProvider injectFirst> <LocalizationProvider dateAdapter={AdapterDayjs}> <DataSource<Developer> primaryKey="id" data={dataSource}> <InfiniteTable<Developer> columns={columns} columnDefaultWidth={120} /> </DataSource> </LocalizationProvider> </StyledEngineProvider> </> ); } const dataSource: Developer[] = [ { id: 0, firstName: 'Nya', country: 'India', city: 'Unnao', birthDate: new Date(1997, 0, 1), currency: 'JPY', preferredLanguage: 'TypeScript', salary: 60000, hobby: 'sports', email: 'Nya44@gmail.com', }, { id: 1, firstName: 'Axel', country: 'Mexico', city: 'Cuitlahuac', birthDate: new Date(1993, 3, 10), currency: 'USD', preferredLanguage: 'TypeScript', salary: 100000, hobby: 'sports', email: 'Axel93@hotmail.com', }, { id: 2, firstName: 'Gonzalo', country: 'United Arab Emirates', city: 'Fujairah', birthDate: new Date(1997, 10, 30), currency: 'JPY', preferredLanguage: 'Go', salary: 120000, hobby: 'photography', email: 'Gonzalo_McGlynn34@gmail.com', }, { id: 3, firstName: 'Sherwood', country: 'Mexico', city: 'Tlacolula de Matamoros', birthDate: new Date(1990, 5, 20), currency: 'CHF', preferredLanguage: 'Rust', salary: 99000, hobby: 'cooking', email: 'Sherwood_McLaughlin65@hotmail.com', }, { id: 4, firstName: 'Alexandre', country: 'France', city: 'Persan', birthDate: new Date(1990, 3, 20), currency: 'EUR', preferredLanguage: 'Go', salary: 97000, hobby: 'reading', email: 'Alexandre_Harber@hotmail.com', }, { id: 5, firstName: 'Mariane', country: 'United States', city: 'Hays', birthDate: new Date(2002, 3, 20), currency: 'EUR', preferredLanguage: 'TypeScript', salary: 58000, hobby: 'cooking', email: 'Mariane0@hotmail.com', }, { id: 6, firstName: 'Rosalind', country: 'Mexico', city: 'Nuevo Casas Grandes', birthDate: new Date(1992, 11, 12), currency: 'AUD', preferredLanguage: 'JavaScript', salary: 198000, hobby: 'dancing', email: 'Rosalind69@gmail.com', }, { id: 7, firstName: 'Lolita', country: 'Sweden', city: 'Delsbo', birthDate: new Date(1990, 9, 5), currency: 'JPY', preferredLanguage: 'TypeScript', salary: 200000, hobby: 'cooking', email: 'Lolita.Hayes@hotmail.com', }, { id: 8, firstName: 'Tre', country: 'Germany', city: 'Bad Camberg', birthDate: new Date(1990, 9, 15), currency: 'GBP', preferredLanguage: 'TypeScript', salary: 200000, hobby: 'sports', email: 'Tre28@gmail.com', }, { id