### Master-Detail Example with useMasterRowInfo Source: https://infinite-table.com/docs/reference/hooks/index.md This example demonstrates a master-detail setup. The master table displays cities and countries, while the detail view, rendered using useMasterRowInfo, shows developers within a specific city. It requires setting up two DataSources and InfiniteTables, one for the master and one for the detail. ```typescript import * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, useMasterRowInfo, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; city: string; currency: string; country: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; type City = { id: number; name: string; country: string; }; const masterColumns: InfiniteTablePropColumns = { id: { field: 'id', header: 'ID', defaultWidth: 70, renderRowDetailIcon: true, }, country: { field: 'country', header: 'Country' }, city: { field: 'name', header: 'City', defaultFlex: 1 }, }; const detailColumns: InfiniteTablePropColumns = { firstName: { field: 'firstName', header: 'First Name', }, salary: { field: 'salary', type: 'number', }, stack: { field: 'stack' }, currency: { field: 'currency' }, city: { field: 'city' }, }; const domProps = { style: { height: '100%', }, }; const shouldReloadData = { sortInfo: true, filterValue: true, }; function RowDetail() { const rowInfo = useMasterRowInfo()!; console.log('rendering detail for master row', rowInfo.id); return ( data={detailDataSource} primaryKey="id" shouldReloadData={shouldReloadData} > debugId="master-detail-component-example" columnDefaultWidth={150} columnMinWidth={50} columns={detailColumns} /> ); } const components = { RowDetail, }; export default () => { return ( <> data={citiesDataSource} primaryKey="id" defaultSortInfo={[ { field: 'country', dir: 1, }, { field: 'name', dir: 1, }, ]} > debugId="master-detail-component-example-2" domProps={domProps} columnDefaultWidth={150} columnMinWidth={50} columns={masterColumns} components={components} /> ); }; // fetch an array of cities from the server const citiesDataSource: DataSourceData = () => { const cityNames = new Set(); const result: City[] = []; return fetch(process.env.NEXT_PUBLIC_BASE_URL + `/developers1k-sql`) .then((response) => response.json()) .then((response) => { response.data.forEach((data: Developer) => { if (cityNames.has(data.city)) { return; } cityNames.add(data.city); result.push({ name: data.city, country: data.country, id: result.length, }); }); return result; }); }; const detailDataSource: DataSourceData = ({ filterValue, sortInfo, masterRowInfo, }) => { if (sortInfo && !Array.isArray(sortInfo)) { sortInfo = [sortInfo]; } if (!filterValue) { filterValue = []; } if (masterRowInfo) { // filter by master country and city filterValue = [ { field: 'city', filter: { operator: 'eq', type: 'string', value: masterRowInfo.data.name, }, }, { field: 'country', filter: { operator: 'eq', type: 'string', value: masterRowInfo.data.country, }, }, ...filterValue, ]; } const args = [ sortInfo ? 'sortInfo=' + JSON.stringify( sortInfo.map((s) => ({ field: s.field, dir: s.dir, })), ) : null, filterValue ? 'filterBy=' + JSON.stringify( filterValue.map(({ field, filter }) => { return { field: field, operator: filter.operator, value: filter.type === 'number' ? Number(filter.value) : filter.value, }; }), ) : null, ] .filter(Boolean) .join('&'); return fetch(process.env.NEXT_PUBLIC_BASE_URL + `/developers1k-sql?` + args) .then((r) => r.json()) .then((data: Developer[]) => data); }; ``` -------------------------------- ### Live Pagination with React Query Example Source: https://infinite-table.com/docs/reference/datasource-props/index.md Demonstrates how to implement live pagination using react-query with the DataSource component. It includes setup for QueryClientProvider and fetching data with useInfiniteQuery. ```tsx import '@infinite-table/infinite-react/index.css'; import { InfiniteTable, InfiniteTableColumn, DataSource, DataSourceSingleSortInfo, DataSourceDataParams, DataSourceLivePaginationCursorFn, } from '@infinite-table/infinite-react'; import * as React from 'react'; import { useCallback } from 'react'; import { QueryClient, QueryClientProvider, useInfiniteQuery, keepPreviousData, } from '@tanstack/react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, }, }, }); const emptyArray: Employee[] = []; export const columns: Record> = { id: { field: 'id' }, country: { field: 'country', }, city: { field: 'city' }, team: { field: 'team' }, department: { field: 'department' }, firstName: { field: 'firstName' }, lastName: { field: 'lastName' }, salary: { field: 'salary' }, age: { field: 'age' }, }; type Employee = { id: number; companyName: string; companySize: string; firstName: string; lastName: string; country: string; countryCode: string; city: string; streetName: string; streetNo: number; department: string; team: string; salary: number; age: number; email: string; }; const PAGE_SIZE = 10; const Example = () => { const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isPlaceholderData, } = useInfiniteQuery({ queryKey: ['table-data'], queryFn: async ({ pageParam = 0 }) => { const response = await fetch( `https://infinite-table.com/api/employees?limit=${PAGE_SIZE}&offset=${pageParam}` ); const data = await response.json(); return data; }, getNextPageParam: (lastPage, allPages) => { const offset = allPages.length * PAGE_SIZE; return offset; }, initialPageParam: 0, }); const livePaginationCursorFn: DataSourceLivePaginationCursorFn = useCallback( (params) => { return params.length; }, [] ); const onDataParamsChange = useCallback((params: DataSourceDataParams) => { if (params.shouldFetchMore) { fetchNextPage(); } }, []); const scrollTopId = React.useRef(0); return ( data={data?.pages || emptyArray} loading={isFetchingNextPage} onDataParamsChange={onDataParamsChange} livePagination livePaginationCursor={livePaginationCursorFn} > debugId="live-pagination-example" scrollTopKey={scrollTopId} columnDefaultWidth={200} columns={columns} /> ); }; function App() { return ( ); } export default App; ``` -------------------------------- ### Basic Infinite Table Setup with DataSource Source: https://infinite-table.com/docs/learn/getting-started/index.md This snippet demonstrates the fundamental setup of Infinite Table using the DataSource component. It shows how to bind data, configure filtering, sorting, and row selection. Use this as a starting point for integrating Infinite Table into your React application. ```jsx import React, { useState } from 'react'; import { InfiniteTable, DataSource } from '@infinite-table/infinite-react'; const columns = [ { field: 'id' }, { field: 'name' }, { field: 'country' }, { field: 'email' }, { field: 'salary' }, ]; const columnTypes = { number: { render: ({ value }) => { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD', }); }, }, }; const defaultFilterValue = [ { field: 'country', type: 'contains', value: 'United States', }, ]; const defaultRowSelection = { selectBy: 'id', toggle: true, }; const defaultGroupRowsState = { 'group-by': true, }; const groupBy = [ { field: 'country', }, ]; const aggregationReducers = [ { field: 'salary', reducer: 'average', type: 'number', }, ]; const groupColumn = { header: 'Group', field: 'country', }; const domProps = { style: { height: 500, }, }; const columns = [ { field: 'id' }, { field: 'name' }, { field: 'country' }, { field: 'email' }, { field: 'salary', type: 'number' }, ]; const columnTypes = { number: { render: ({ value }) => { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD', }); }, }, }; const defaultFilterValue = [ { field: 'country', type: 'contains', value: 'United States', }, ]; const defaultRowSelection = { selectBy: 'id', toggle: true, }; const defaultGroupRowsState = { 'group-by': true, }; const groupBy = [ { field: 'country', }, ]; const aggregationReducers = [ { field: 'salary', reducer: 'average', type: 'number', }, ]; const groupColumn = { header: 'Group', field: 'country', }; const domProps = { style: { height: 500, }, }; export default function App() { const [minMax, setMinMax] = useState({ min: 0, max: 0 }); return ( <> {minMax.min !== 0 && (
Min: {minMax.min.toLocaleString('en-US', { style: 'currency', currency: 'USD', })}, Max: {minMax.max.toLocaleString('en-US', { style: 'currency', currency: 'USD', })}, View source
) : null} data={dataSource} primaryKey="id" defaultFilterValue={defaultFilterValue} filterMode="local" useGroupKeysForMultiRowSelection defaultRowSelection={defaultRowSelection} defaultSortInfo={{ dir: -1, field: 'country', }} onDataArrayChange={(data) => { const min = Math.min(...data.map((data) => data.salary ?? 0)); const max = Math.max(...data.map((data) => data.salary ?? 0)); setMinMax({ min, max }); }} defaultGroupRowsState={defaultGroupRowsState} aggregationReducers={aggregationReducers} groupBy={groupBy} > debugId="full-demo" groupRenderStrategy="single-column" defaultColumnPinning={{ 'group-by': true, }} domProps={domProps} defaultActiveRowIndex={0} groupColumn={groupColumn} licenseKey={process.env.NEXT_PUBLIC_INFINITE_LICENSE_KEY} columns={columns} columnTypes={columnTypes} columnDefaultWidth={150} /> ); } const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers100') .then((r) => r.json()) .then((data: Developer[]) => data); }; ``` -------------------------------- ### Implement Multiple Cell Selection Example Source: https://infinite-table.com/docs/learn/selection/cell-selection.md This example demonstrates a full implementation of a data grid with multi-cell selection enabled. It includes data fetching, column definitions, and the InfiniteTable component setup. ```tsx import { InfiniteTable, DataSource, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns = { id: { field: 'id', defaultWidth: 60 }, firstName: { field: 'firstName' }, preferredLanguage: { field: 'preferredLanguage' }, stack: { field: 'stack' }, country: { field: 'country' }, age: { field: 'age', type: 'number' }, salary: { field: 'salary', type: 'number' }, currency: { field: 'currency', type: 'number' }, }; export default function App() { return ( primaryKey="id" data={dataSource} selectionMode="multi-cell" > debugId="cell-selection-default-example" columns={columns} columnDefaultWidth={100} /> ); } ``` -------------------------------- ### Live Pagination with React-Query Example Source: https://infinite-table.com/docs/reference/datasource-props/index.md Demonstrates how to implement live pagination using react-query with the Infinite Table DataSource. It includes setup for query client, data fetching logic, and state management for pagination parameters. ```typescript import '@infinite-table/infinite-react/index.css'; import { InfiniteTable, InfiniteTableColumn, DataSource, DataSourceSingleSortInfo, DataSourceDataParams, DataSourceLivePaginationCursorFn, } from '@infinite-table/infinite-react'; import * as React from 'react'; import { useCallback } from 'react'; import { QueryClient, QueryClientProvider, useInfiniteQuery, keepPreviousData, } from '@tanstack/react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, }, }, }); const emptyArray: Employee[] = []; export const columns: Record> = { id: { field: 'id' }, country: { field: 'country', }, city: { field: 'city' }, team: { field: 'team' }, department: { field: 'department' }, firstName: { field: 'firstName' }, lastName: { field: 'lastName' }, salary: { field: 'salary' }, age: { field: 'age' }, }; type Employee = { id: number; companyName: string; companySize: string; firstName: string; lastName: string; country: string; countryCode: string; city: string; streetName: string; streetNo: number; department: string; team: string; salary: number; age: number; email: string; }; const PAGE_SIZE = 10; const dataSource = ({ sortInfo, livePaginationCursor = 0, }: { sortInfo: DataSourceSingleSortInfo | null; livePaginationCursor: number; }) => { return fetch( process.env.NEXT_PUBLIC_BASE_URL + `/employees10k?_limit=${PAGE_SIZE}&_sort=${sortInfo?.field}&_order=${ sortInfo?.dir === 1 ? 'asc' : 'desc' }&_start=${livePaginationCursor}`, ) .then(async (r) => { const data = await r.json(); // we need the remote count, so we take it from headers const total = Number(r.headers.get('X-Total-Count')!); return { data, total }; }) .then(({ data, total }: { data: Employee[]; total: number }) => { const page = livePaginationCursor / PAGE_SIZE + 1; const prevPageCursor = Math.max(PAGE_SIZE * (page - 1), 0); return { data, hasMore: total > PAGE_SIZE * page, page, prevPageCursor, nextPageCursor: prevPageCursor + data.length, }; }) .then( ( response, ): Promise<{ data: Employee[]; hasMore: boolean; page: number; nextPageCursor: number; prevPageCursor: number; }> => { return new Promise((resolve) => { setTimeout(() => { resolve(response); }, 150); }); }, ); }; const Example = () => { const [dataParams, setDataParams] = React.useState< Partial> >({ groupBy: [], sortInfo: undefined, livePaginationCursor: null, }); const { data, fetchNextPage: fetchNext, isFetchingNextPage, } = useInfiniteQuery({ initialPageParam: 0, queryKey: ['employees', dataParams.sortInfo, dataParams.groupBy], queryFn: ({ pageParam = 0 }) => { const params = { livePaginationCursor: pageParam, sortInfo: dataParams.sortInfo as DataSourceSingleSortInfo | null, }; return dataSource(params); }, placeholderData: keepPreviousData, getPreviousPageParam: (firstPage) => firstPage.prevPageCursor || 0, getNextPageParam: (lastPage) => { const nextPageCursor = lastPage.hasMore ? lastPage.nextPageCursor : undefined; return nextPageCursor; }, select: (data) => { const flatData = data.pages.flatMap((x) => x.data); const nextPageCursor = data.pages[data.pages.length - 1].nextPageCursor; const result = { pages: flatData, pageParams: [nextPageCursor], }; return result; }, }); ``` -------------------------------- ### Live Pagination with React-Query Source: https://infinite-table.com/docs/reference/datasource-props/index.md Demonstrates how to implement live pagination using react-query for data fetching. This example shows the setup for fetching data in pages and handling cursor-based navigation. ```typescript import '@infinite-table/infinite-react/index.css'; import { InfiniteTable, InfiniteTableColumn, DataSource, DataSourceSingleSortInfo, DataSourceDataParams, DataSourceLivePaginationCursorFn, } from '@infinite-table/infinite-react'; import * as React from 'react'; import { useCallback } from 'react'; import { QueryClient, QueryClientProvider, useInfiniteQuery, keepPreviousData, } from '@tanstack/react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, }, }, }); const emptyArray: Employee[] = []; export const columns: Record> = { id: { field: 'id' }, country: { field: 'country', }, city: { field: 'city' }, team: { field: 'team' }, department: { field: 'department' }, firstName: { field: 'firstName' }, lastName: { field: 'lastName' }, salary: { field: 'salary' }, age: { field: 'age' }, }; type Employee = { id: number; companyName: string; companySize: string; firstName: string; lastName: string; country: string; countryCode: string; city: string; streetName: string; streetNo: number; department: string; team: string; salary: number; age: number; email: string; }; const PAGE_SIZE = 10; const dataSource = ({ sortInfo, livePaginationCursor = 0, }: { sortInfo: DataSourceSingleSortInfo | null; livePaginationCursor: number; }) => { return fetch( process.env.NEXT_PUBLIC_BASE_URL + `/employees10k?_limit=${PAGE_SIZE}&_sort=${sortInfo?.field}&_order=${ sortInfo?.dir === 1 ? 'asc' : 'desc' }&_start=${livePaginationCursor}`, ) .then(async (r) => { const data = await r.json(); // we need the remote count, so we take it from headers const total = Number(r.headers.get('X-Total-Count')!); return { data, total }; }) .then(({ data, total }: { data: Employee[]; total: number }) => { const page = livePaginationCursor / PAGE_SIZE + 1; const prevPageCursor = Math.max(PAGE_SIZE * (page - 1), 0); return { data, hasMore: total > PAGE_SIZE * page, page, prevPageCursor, nextPageCursor: prevPageCursor + data.length, }; }) .then( ( response, ): Promise<{ data: Employee[]; hasMore: boolean; page: number; nextPageCursor: number; prevPageCursor: number; }> => { return new Promise((resolve) => { setTimeout(() => { resolve(response); }, 150); }); }, ); }; const Example = () => { const [dataParams, setDataParams] = React.useState>>( { groupBy: [], sortInfo: undefined, livePaginationCursor: null, }, ); const { data, fetchNextPage: fetchNext, isFetchingNextPage, } = useInfiniteQuery({ initialPageParam: 0, queryKey: ['employees', dataParams.sortInfo, dataParams.groupBy], queryFn: ({ pageParam = 0 }) => { const params = { livePaginationCursor: pageParam, sortInfo: dataParams.sortInfo as DataSourceSingleSortInfo | null, }; return dataSource(params); }, placeholderData: keepPreviousData, getPreviousPageParam: (firstPage) => firstPage.prevPageCursor || 0, getNextPageParam: (lastPage) => { const nextPageCursor = lastPage.hasMore ? lastPage.nextPageCursor : undefined; return nextPageCursor; }, select: (data) => { const flatData = data.pages.flatMap((x) => x.data); const nextPageCursor = data.pages[data.pages.length - 1].nextPageCursor; const result = { pages: flatData, pageParams: [nextPageCursor], }; return result; }, }); const onDataParamsChange = useCallback( (dataParams: DataSourceDataParams) => { const params = { groupBy: dataParams.groupBy, sortInfo: dataParams.sortInfo, livePaginationCursor: dataParams.livePaginationCursor, }; setDataParams(params); }, [], ); const [scrollTopId, setScrollTop] = React.useState(0); React.useEffect(() => { // when sorting changes, scroll to the top setScrollTop(Date.now()); }, [dataParams.sortInfo]); const fetchNextPage = () => { if (isFetchingNextPage) { return; } fetchNext(); }; React.useEffect(() => { fetchNextPage(); }, [dataParams.livePaginationCursor]); const livePaginationCursorFn: DataSourceLivePaginationCursorFn = useCallback(({ length }) => { return length; }, []); return ( primaryKey="id" // take the data from `data.pages`, // as returned from our react-query select function ``` -------------------------------- ### Example: Using expandAll/collapseAll with Cloning Source: https://infinite-table.com/docs/reference/type-definitions/index.md An example demonstrating how to use `expandAll` and `collapseAll` methods by cloning the `GroupRowsState` instance and updating React state. ```APIDOC ## Example: Using expandAll/collapseAll with Cloning ### Description This example shows how to control the expansion and collapse of all group rows using buttons, by cloning the `GroupRowsState` instance and updating the component's state. ### Usage This code snippet is part of a React component that uses `useState` to manage the `groupRowsState` and provides buttons to trigger `expandAll` and `collapseAll` actions. ### Code Example ```tsx import { InfiniteTable, DataSource, GroupRowsState, } from '@infinite-table/infinite-react'; import type { DataSourcePropGroupBy, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; const groupBy: DataSourcePropGroupBy = [ { field: 'country', column: { header: 'Country group', renderGroupValue: ({ value }) => <>Country: {value}, }, }, { field: 'stack', }, ]; const columns: InfiniteTablePropColumns = { country: { field: 'country', style: { color: 'tomato', }, }, firstName: { field: 'firstName' }, age: { field: 'age' }, salary: { field: 'salary', type: 'number', }, canDesign: { field: 'canDesign' }, stack: { field: 'stack' }, }; export default function App() { const [groupRowsState, setGroupRowsState] = React.useState>(() => { const groupRowsState = new GroupRowsState({ collapsedRows: true, expandedRows: [['Mexico'], ['Mexico', 'backend'], ['India']], }); return groupRowsState; }); return ( <> data={dataSource} primaryKey="id" groupBy={groupBy} groupRowsState={groupRowsState} onGroupRowsStateChange={setGroupRowsState} > debugId="using-group-rows-state-controlled-example" columns={columns} /> ); } const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k') .then((r) => r.json()) .then((data: Developer[]) => data); }; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; email: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; ``` ``` -------------------------------- ### Pivoting with pivotTotalColumnPosition='start' Source: https://infinite-table.com/docs/reference/infinite-table-props.md Demonstrates how to configure pivot total columns to appear at the start of the pivot structure. This example uses multiple pivot fields ('stack', 'canDesign') and defines aggregations for 'salary' and 'age'. ```typescript import { InfiniteTable, DataSource, DataSourceGroupBy, DataSourcePivotBy, InfiniteTableColumnAggregator, DataSourcePropAggregationReducers, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns = { id: { field: 'id', defaultWidth: 80 }, preferredLanguage: { field: 'preferredLanguage' }, stack: { field: 'stack' }, }; const defaultGroupBy: DataSourceGroupBy[] = [ { field: 'country', }, { field: 'city', }, ]; const defaultPivotBy: DataSourcePivotBy[] = [ { field: 'stack', }, { field: 'canDesign', columnGroup: ({ columnGroup }) => { return { ...columnGroup, header: columnGroup.pivotGroupKey === 'yes' ? 'Designer' : 'Non-designer', }; }, }, ]; const avgReducer: InfiniteTableColumnAggregator = { initialValue: 0, reducer: (acc, sum) => acc + sum, done: (sum, arr) => Math.round(arr.length ? sum / arr.length : 0), }; const aggregations: DataSourcePropAggregationReducers = { salary: { ...avgReducer, name: 'Salary (avg)', field: 'salary', }, age: { ...avgReducer, name: 'Age (avg)', field: 'age', }, }; export default function ColumnValueGetterExample() { return ( <> primaryKey="id" defaultGroupBy={defaultGroupBy} defaultPivotBy={defaultPivotBy} aggregationReducers={aggregations} data={dataSource} > {({ pivotColumns, pivotColumnGroups }) => { return ( debugId="pivot-total-column-position-example" groupRenderStrategy="single-column" columns={columns} columnDefaultWidth={200} pivotColumns={pivotColumns} pivotColumnGroups={pivotColumnGroups} pivotTotalColumnPosition="start" /> ); }} ); } ``` -------------------------------- ### Example: Infinite Table with Custom valueGetter Column Source: https://infinite-table.com/docs/learn/columns/column-rendering.md Demonstrates a full Infinite Table setup using a custom `valueGetter` for the 'Full Name' column to combine first and last names. Ensure custom components are controlled due to virtualization. ```tsx import { InfiniteTable, DataSource } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns = { id: { field: 'id', defaultWidth: 80 }, name: { header: 'Full Name', valueGetter: ({ data }) => `${data.firstName} ${data.lastName}`, }, preferredLanguage: { field: 'preferredLanguage' }, stack: { field: 'stack' }, }; export default function ColumnValueGetterExample() { return ( <> primaryKey="id" data={dataSource}> debugId="column-valueGetter-example" columns={columns} columnDefaultWidth={200} /> ); } ``` -------------------------------- ### Full Infinite Table Example with Value Getter and Editable Cells Source: https://infinite-table.com/docs/learn/editing/excel-like-editing.md This example shows a complete Infinite Table setup with editable cells and a `salaryK` column that uses `valueGetter` to display salary in thousands. Changes in the 'salary' column will automatically update the 'Salary (thousands)' column. ```typescript import { InfiniteTable, DataSource, DataSourceData, keyboardShortcuts, } from '@infinite-table/infinite-react'; import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource: DataSourceData = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + `/developers1k-sql?`) .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns = { preferredLanguage: { field: 'preferredLanguage', header: 'Language' }, salary: { field: 'salary', type: 'number', }, salaryK: { valueGetter: ({ data }) => data.salary / 1000, header: 'Salary (thousands)', type: 'number', defaultEditable: false, }, country: { field: 'country', header: 'Country', }, age: { field: 'age' }, canDesign: { field: 'canDesign' }, firstName: { field: 'firstName' }, stack: { field: 'stack' }, id: { field: 'id', defaultEditable: false }, hobby: { field: 'hobby' }, city: { field: 'city' }, currency: { field: 'currency' }, }; export default function KeyboardShortcuts() { return ( <> primaryKey="id" data={dataSource}> debugId="keyboard-shortcuts-instant-edit-with-valuegetter-example" columns={columns} columnDefaultEditable keyboardShortcuts={[keyboardShortcuts.instantEdit]} /> ); } ``` -------------------------------- ### Full Example: Cell Selection API Integration Source: https://infinite-table.com/docs/reference/cell-selection-api/index.md Demonstrates integrating the Cell Selection API within a React component using Infinite Table. Includes setup for data source, columns, and event handlers for API access. ```typescript import { InfiniteTable, DataSource, InfiniteTableApi, InfiniteTablePropColumns, } from '@infinite-table/infinite-react'; import * as React from 'react'; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const dataSource = () => { return fetch(process.env.NEXT_PUBLIC_BASE_URL + '/developers1k') .then((r) => r.json()) .then((data: Developer[]) => data); }; const columns: InfiniteTablePropColumns = { id: { field: 'id' }, firstName: { field: 'firstName' }, preferredLanguage: { field: 'preferredLanguage' }, stack: { field: 'stack' }, country: { field: 'country' }, age: { field: 'age', type: 'number' }, salary: { field: 'salary', type: 'number' }, currency: { field: 'currency', type: 'number' }, }; export default function App() { const [api, setApi] = React.useState | null>( null, ); return ( <>
primaryKey="id" data={dataSource} selectionMode="multi-cell" > debugId="select-cell-example" onReady={({ api }) => { setApi(api); }} columns={columns} columnDefaultWidth={100} /> ); } ``` -------------------------------- ### Configuring InfiniteTable with Advanced Features Source: https://infinite-table.com/docs/learn/getting-started This example demonstrates a full configuration of `InfiniteTable` in a React application. It includes setup for data source, column definitions, grouping, aggregation, row selection, and custom cell rendering. Ensure all necessary components and types are imported. ```typescript 'use client'; import { InfiniteTable, DataSource, GroupRowsState, InfiniteTablePropColumnTypes, DataSourcePropRowSelection_MultiRow, InfiniteTableColumn, InfiniteTableColumnRenderValueParam, DataSourcePropAggregationReducers, DataSourceGroupBy, components, DataSourcePropFilterValue, } from '@infinite-table/infinite-react'; import * as React from 'react'; import { useState } from 'react'; const { CheckBox } = components; type Developer = { id: number; firstName: string; lastName: string; country: string; city: string; currency: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; hobby: string; salary: number; age: number; }; const showLogo = typeof window === 'undefined' ? true : window.location.host.startsWith('localhost:') || window.location.host.startsWith('infinite-table.com'); const avgReducer = { initialValue: 0, reducer: (acc: number, sum: number) => acc + sum, done: (value: number, arr: any[]) => arr.length ? Math.floor(value / arr.length) : 0, }; const aggregationReducers: DataSourcePropAggregationReducers = { salary: { field: 'salary', ...avgReducer, }, age: { field: 'age', ...avgReducer, }, currency: { field: 'currency', initialValue: new Set(), reducer: (acc: Set, value: string) => { acc.add(value); return acc; }, done: (value: Set) => { return value.size > 1 ? 'Mixed' : value.values().next().value; }, }, canDesign: { field: 'canDesign', initialValue: false, reducer: (acc: boolean | null, value: 'yes' | 'no') => { if (acc === null) { return acc; } if (acc === false && value === 'yes') { return null; } if (acc === true && value === 'no') { return null; } return acc; }, }, }; const flags = { 'United States': '🇺🇸', Canada: '🇨🇦', France: '🇫🇷', Germany: '🇩🇪', 'United Kingdom': '🇬🇧', 'South Africa': '🇿🇦', 'New Zealand': '🇳🇿', Sweden: '🇸🇪', China: '🇨🇳', Brazil: '🇧🇷', Turkey: '🇹🇷', Italy: '🇮🇹', India: '🇮🇳', Indonesia: '🇮🇩', Japan: '🇯🇵', Argentina: '🇦🇷', 'Saudi Arabia': '🇸🇦', Mexico: '🇲🇽', 'United Arab Emirates': '🇦🇪', }; function getColumns(): Record> { return { age: { field: 'age', header: 'Age', type: 'number', defaultWidth: 100, renderValue: ({ value }) => value, }, salary: { header: 'Compensation', field: 'salary', type: 'number', defaultWidth: 210, }, currency: { field: 'currency', header: 'Currency', defaultWidth: 100 }, preferredLanguage: { field: 'preferredLanguage', header: 'Programming Language', }, ``` -------------------------------- ### Example Custom Cell Component Implementation Source: https://infinite-table.com/docs/reference/infinite-table-props.md An example of a custom cell component that uses `useInfiniteColumnCell` to get `domRef` and applies additional styling and classes. ```tsx const ExampleCellComponent: React.FunctionComponent< React.HTMLProps > = (props) => { const { domRef } = useInfiniteColumnCell(); return (
{props.children}
{emoji}
); }; ``` -------------------------------- ### Example Custom Header Component with useInfiniteHeaderCell Source: https://infinite-table.com/docs/reference/infinite-table-props.md An example of a custom header component that uses `useInfiniteHeaderCell` to get `domRef` and applies extra classes and styles. It also demonstrates accessing column information and sort status. ```tsx const ExampleHeaderComponent: React.FunctionComponent< React.HTMLProps > = (props) => { const { domRef } = useInfiniteHeaderCell(); return (
{props.children}
{emoji}
); }; ```