Skip to content

Commit

Permalink
implement repeat group rows in horizontal layout
Browse files Browse the repository at this point in the history
  • Loading branch information
radubrehar committed Oct 8, 2024
1 parent e68b303 commit 27b9e2c
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import * as React from 'react';

import {
InfiniteTable,
DataSource,
DataSourcePropCellSelection_MultiCell,
} from '@infinite-table/infinite-react';

import type { InfiniteTablePropColumns } from '@infinite-table/infinite-react';

import { useState } 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 + '/developers100')
.then((r) => r.json())
.then((data: Developer[]) => data);
};

const columns: InfiniteTablePropColumns<Developer> = {
id: { field: 'id', renderSelectionCheckBox: true },

firstName: {
field: 'firstName',
},

// preferredLanguage: { field: 'preferredLanguage' },
// stack: { field: 'stack' },
};

const domProps = {
style: {
height: '80vh',
margin: 10,
},
};

const group_COL = {};

export default function GroupByExample() {
const [cellSelection, _setCellSelection] =
useState<DataSourcePropCellSelection_MultiCell>({
selectedCells: [
// [2, 'firstName'],
['*', 'firstName'],
// [7, 'preferredLanguage'],
// [3, 'id'],
[3, '*'],
[4, '*'],
[5, '*'],
[11, 'preferredLanguage'],
[15, 'stack'],
],
// deselectedCells: [[3, 'stack']],
defaultSelection: false,
});

const [wrapRowsHorizontally, setWrapRowsHorizontally] = useState(true);
const [repeatWrappedGroupRows, setRepeatWrappedGroupRows] = useState(true);
return (
<>
<button
onClick={() => {
setWrapRowsHorizontally(!wrapRowsHorizontally);
}}
>
toggle horizontal layout
</button>
<button
onClick={() => {
setRepeatWrappedGroupRows(!repeatWrappedGroupRows);
}}
>
toggle repeat wrapped group rows
</button>
<DataSource<Developer>
primaryKey="id"
data={dataSource}
defaultGroupBy={[
{
field: 'stack',
},
{
field: 'preferredLanguage',
},
]}
selectionMode="multi-cell"
defaultCellSelection={cellSelection}
>
<InfiniteTable<Developer>
domProps={domProps}
columns={columns}
groupColumn={group_COL}
repeatWrappedGroupRows={repeatWrappedGroupRows}
keyboardSelection={true}
keyboardNavigation={'cell'}
wrapRowsHorizontally={wrapRowsHorizontally}
columnDefaultWidth={200}
/>
</DataSource>
</>
);
}
3 changes: 3 additions & 0 deletions source/src/components/DataSource/state/getInitialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export function initSetupState<T>(): DataSourceSetupState<T> {
// TODO cleanup indexer on unmount
indexer: new Indexer<T, any>(),

repeatWrappedGroupRows: false,

destroyedRef: {
current: false,
},
Expand All @@ -86,6 +88,7 @@ export function initSetupState<T>(): DataSourceSetupState<T> {
timestamp: 0,
mutations: undefined,
},
rowsPerPage: null,
lazyLoadCacheOfLoadedBatches: new DeepMap<string, true>(),
dataParams: undefined,
onCleanup: buildSubscriptionCallback<DataSourceState<T>>(),
Expand Down
6 changes: 6 additions & 0 deletions source/src/components/DataSource/state/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ export function concludeReducer<T>(params: {
'pivotTotalColumnPosition',
'pivotGrandTotalColumnPosition',
'showSeparatePivotColumnForSingleAggregation',
'repeatWrappedGroupRows',
'rowsPerPage',
]);

const rowInfoReducersChanged = haveDepsChanged(previousState, state, [
Expand Down Expand Up @@ -529,6 +531,10 @@ export function concludeReducer<T>(params: {

withRowInfo,

repeatWrappedGroupRows:
state.repeatWrappedGroupRows && state.rowsPerPage != null,
rowsPerPage: state.rowsPerPage,

groupRowsState: state.groupRowsState,
generateGroupRows: state.generateGroupRows,
});
Expand Down
5 changes: 5 additions & 0 deletions source/src/components/DataSource/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ export interface DataSourceSetupState<T> {
getDataSourceMasterContextRef: React.MutableRefObject<
() => DataSourceMasterDetailContextValue | undefined
>;
repeatWrappedGroupRows: boolean;
/**
* This is just used for horizontal layout and when repeatWrappedGroupRows is TRUE!!!
*/
rowsPerPage: number | null;
destroyedRef: React.MutableRefObject<boolean>;
idToIndexMap: Map<any, number>;
detailDataSourcesStateToRestore: Map<
Expand Down
12 changes: 10 additions & 2 deletions source/src/components/HeadlessTable/RawTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ export type RawTableProps = {
cellHoverClassNames?: string[];
renderer?: ReactHeadlessTableRenderer;
onRenderUpdater?: SubscriptionCallback<Renderable>;
forceRerenderTimestamp?: number;
};

export function RawTableFn(props: RawTableProps) {
const { brain, renderCell, renderDetailRow } = props;
const { brain, renderCell, renderDetailRow, forceRerenderTimestamp } = props;

const { renderer, onRenderUpdater } = useMemo(() => {
return props.onRenderUpdater && props.renderer
Expand Down Expand Up @@ -53,7 +54,14 @@ export function RawTableFn(props: RawTableProps) {
renderCell,
renderDetailRow,
});
}, [renderer, brain, renderCell, renderDetailRow, onRenderUpdater]);
}, [
renderer,
brain,
renderCell,
renderDetailRow,
onRenderUpdater,
forceRerenderTimestamp,
]);

useEffect(() => {
const remove = brain.onRenderRangeChange((renderRange) => {
Expand Down
3 changes: 3 additions & 0 deletions source/src/components/HeadlessTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type HeadlessTableProps = {
scrollerDOMRef?: MutableRefObject<HTMLElement | null>;
wrapRowsHorizontally?: boolean;
brain: MatrixBrain;
forceRerenderTimestamp?: number;
debugId?: string;
activeCellRowHeight: number | ((rowIndex: number) => number) | undefined;
renderCell: TableRenderCellFn;
Expand Down Expand Up @@ -164,6 +165,7 @@ export function HeadlessTable(
activeCellIndex,
onRenderUpdater,
wrapRowsHorizontally,
forceRerenderTimestamp,
...domProps
} = props;

Expand Down Expand Up @@ -244,6 +246,7 @@ export function HeadlessTable(
data-name="scroll-transform-target"
>
<RawTable
forceRerenderTimestamp={forceRerenderTimestamp}
renderer={renderer}
onRenderUpdater={onRenderUpdater}
renderCell={renderCell}
Expand Down
51 changes: 51 additions & 0 deletions source/src/components/InfiniteTable/hooks/useHorizontalLayout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useEffect } from 'react';
import { HorizontalLayoutMatrixBrain } from '../../VirtualBrain/HorizontalLayoutMatrixBrain';

import { useInfiniteTable } from './useInfiniteTable';

export function useHorizontalLayout() {
const { getState, actions, dataSourceActions, getDataSourceState } =
useInfiniteTable();

const { groupBy } = getDataSourceState();
const { brain, wrapRowsHorizontally, repeatWrappedGroupRows } = getState();

useEffect(() => {
if (!wrapRowsHorizontally) {
return;
}

const onVerticalRenderRangeChange = () => {
const {
rowsPerPage: currentRowsPerPage,
repeatWrappedGroupRows: currentRepeatWrappedGroupRows,
} = getDataSourceState();

const rowsPerPage = (brain as HorizontalLayoutMatrixBrain).rowsPerPage;
const newRowsPerPage = groupBy && groupBy.length > 0 ? rowsPerPage : null;

if (currentRowsPerPage != newRowsPerPage) {
dataSourceActions.rowsPerPage = newRowsPerPage;
}

if (currentRepeatWrappedGroupRows != !!repeatWrappedGroupRows) {
dataSourceActions.repeatWrappedGroupRows = !!repeatWrappedGroupRows;
}
};

onVerticalRenderRangeChange();

let timeoutId: any;
const off = brain.onVerticalRenderRangeChange(() => {
onVerticalRenderRangeChange();
timeoutId = setTimeout(() => {
actions.forceBodyRerenderTimestamp = Date.now();
});
});

return () => {
clearTimeout(timeoutId);
off();
};
}, [brain, wrapRowsHorizontally, groupBy, repeatWrappedGroupRows]);
}
5 changes: 5 additions & 0 deletions source/src/components/InfiniteTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import { useVisibleColumnSizes } from './hooks/useVisibleColumnSizes';

import { DEBUG_NAME } from './InfiniteDebugName';
import { useToggleWrapRowsHorizontally } from './hooks/useToggleWrapRowsHorizontally';
import { useHorizontalLayout } from './hooks/useHorizontalLayout';

export const InfiniteTableClassName = internalProps.rootClassName;

Expand Down Expand Up @@ -256,6 +257,7 @@ function InfiniteTableBody<T>() {
return (
<InfiniteTableBodyContainer onContextMenu={onContextMenu}>
<HeadlessTable
forceRerenderTimestamp={componentState.forceBodyRerenderTimestamp}
debugId={debugId}
tabIndex={tabIndex ?? 0}
autoFocus={autoFocus ?? undefined}
Expand Down Expand Up @@ -367,6 +369,8 @@ export const InfiniteTableComponent = React.memo(

useAutoSizeColumns();

useHorizontalLayout();

useEditingCallbackProps<T>();

const { menuPortal } = useColumnMenu();
Expand Down Expand Up @@ -570,6 +574,7 @@ const InfiniteTable: InfiniteTableComponent = function <T>(
const table = (
//@ts-ignore
<InfiniteTableRoot
repeatWrappedGroupRows={!!props.wrapRowsHorizontally}
rowHeight={DEFAULT_ROW_HEIGHT}
columnHeaderHeight={DEFAULT_COLUMN_HEADER_HEIGHT}
{...props}
Expand Down
3 changes: 3 additions & 0 deletions source/src/components/InfiniteTable/state/getInitialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export function initSetupState<T>({

columnsWhenInlineGroupRenderStrategy: undefined,
editingCell: null,
forceBodyRerenderTimestamp: 0,
};
}

Expand Down Expand Up @@ -258,6 +259,8 @@ export const forwardProps = <T>(
rowClassName: 1,
cellClassName: 1,

repeatWrappedGroupRows: 1,

pinnedStartMaxWidth: 1,
pinnedEndMaxWidth: 1,
pivotColumn: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,8 @@ export interface InfiniteTableProps<T> {

keyboardShortcuts?: InfiniteTablePropKeyboardShorcut[];

repeatWrappedGroupRows?: boolean;

viewportReservedWidth?: number;
onViewportReservedWidthChange?: (viewportReservedWidth: number) => void;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export interface InfiniteTableSetupState<T> {
renderer: ReactHeadlessTableRenderer;
onRenderUpdater: SubscriptionCallback<Renderable>;

forceBodyRerenderTimestamp: number;

lastRowToExpandRef: MutableRefObject<any | null>;
lastRowToCollapseRef: MutableRefObject<any | null>;
getDOMNodeForCell: (cellPos: CellPositionByIndex) => HTMLElement | null;
Expand Down Expand Up @@ -166,6 +168,8 @@ export interface InfiniteTableMappedState<T> {
onKeyDown: InfiniteTableProps<T>['onKeyDown'];
onCellClick: InfiniteTableProps<T>['onCellClick'];

repeatWrappedGroupRows: InfiniteTableProps<T>['repeatWrappedGroupRows'];

wrapRowsHorizontally: InfiniteTableProps<T>['wrapRowsHorizontally'];

rowDetailCache: RowDetailCache<RowDetailCacheKey, RowDetailCacheEntry>;
Expand Down
Loading

0 comments on commit 27b9e2c

Please sign in to comment.