Skip to content

Commit b47c5f4

Browse files
committed
add support for toggling wrapRowsHorizontally at runtime
1 parent 0a021e3 commit b47c5f4

File tree

9 files changed

+103
-38
lines changed

9 files changed

+103
-38
lines changed

examples/src/pages/tests/horizontal-layout/example.page.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export default () => {
162162
React.useState<DataSourceApi<Developer> | null>(null);
163163

164164
const [cols, setCols] = React.useState(columns);
165+
const [wrapRowsHorizontally, setWrapRowsHorizontally] = React.useState(true);
165166
return (
166167
<>
167168
{Object.keys(columns).map((colId) => {
@@ -187,6 +188,13 @@ export default () => {
187188
</label>
188189
);
189190
})}
191+
<button
192+
onClick={() => {
193+
setWrapRowsHorizontally((x) => !x);
194+
}}
195+
>
196+
toggle
197+
</button>
190198
<button
191199
onClick={() => {
192200
dataSourceApi?.updateData({
@@ -206,7 +214,7 @@ export default () => {
206214
shouldReloadData={{
207215
filterValue: false,
208216
}}
209-
defaultFilterValue={[]}
217+
// defaultFilterValue={[]}
210218
primaryKey="id"
211219
>
212220
<InfiniteTable<Developer>
@@ -224,12 +232,13 @@ export default () => {
224232
// },
225233
// },
226234
// }}
227-
wrapRowsHorizontally={true}
235+
wrapRowsHorizontally={wrapRowsHorizontally}
228236
columnDefaultWidth={120}
229237
columnDefaultEditable
230238
domProps={{
231239
style: {
232240
minHeight: '70vh',
241+
// width: '90vw',
233242
},
234243
}}
235244
/>

source/src/components/HeadlessTable/RawTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export function RawTableFn(props: RawTableProps) {
7979
});
8080

8181
return remove;
82-
}, [renderCell, renderDetailRow]);
82+
}, [renderCell, renderDetailRow, brain, onRenderUpdater]);
8383

8484
return <AvoidReactDiff updater={onRenderUpdater} />;
8585
}

source/src/components/HeadlessTable/index.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,15 +204,17 @@ export function HeadlessTable(
204204
const remove = setupResizeObserver(node, onResize, { debounce: 50 });
205205

206206
return remove;
207-
}, [wrapRowsHorizontally]);
207+
}, [wrapRowsHorizontally, brain]);
208+
209+
const updateDOMTransform = useCallback((scrollPos: ScrollPosition) => {
210+
domRef.current!.style.transform = `translate3d(${-scrollPos.scrollLeft}px, ${-scrollPos.scrollTop}px, 0px)`;
211+
}, []);
208212

209213
const onContainerScroll = useCallback(
210214
(scrollPos: ScrollPosition) => {
211-
brain.setScrollPosition(scrollPos, (scrollPos) => {
212-
domRef.current!.style.transform = `translate3d(${-scrollPos.scrollLeft}px, ${-scrollPos.scrollTop}px, 0px)`;
213-
});
215+
brain.setScrollPosition(scrollPos, updateDOMTransform);
214216
},
215-
[brain],
217+
[brain, updateDOMTransform],
216218
);
217219

218220
useEffect(() => {
@@ -222,6 +224,11 @@ export function HeadlessTable(
222224

223225
setTotalScrollSize(brain.getVirtualizedContentSize());
224226

227+
// useful when the brain is changed - when toggling the value of wrapRowsHorizontally
228+
updateDOMTransform(
229+
brain.getScrollPosition() || { scrollLeft: 0, scrollTop: 0 },
230+
);
231+
225232
return removeOnRenderCount;
226233
}, [brain]);
227234

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const DEBUG_NAME = 'InfiniteTable';

source/src/components/InfiniteTable/components/InfiniteTableHeader/InfiniteTableHeader.tsx

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,25 @@ function InfiniteTableHeaderFn<T>(
4545

4646
const { computedColumnsMap } = computed;
4747

48+
const domRef = useRef<HTMLDivElement | null>(null);
49+
50+
const updateDOMTransform = useCallback((scrollPosition: ScrollPosition) => {
51+
if (domRef.current) {
52+
domRef.current.style.transform = `translate3d(-${scrollPosition.scrollLeft}px, 0px, 0px)`;
53+
}
54+
}, []);
55+
4856
useEffect(() => {
49-
const onScroll = (scrollPosition: ScrollPosition) => {
50-
if (domRef.current) {
51-
domRef.current.style.transform = `translate3d(-${scrollPosition.scrollLeft}px, 0px, 0px)`;
52-
}
53-
};
57+
const removeOnScroll = brain.onScroll(updateDOMTransform);
5458

55-
const removeOnScroll = brain.onScroll(onScroll);
59+
// useful when the brain is changed - when toggling the value of wrapRowsHorizontally
60+
updateDOMTransform(
61+
brain.getScrollPosition() || { scrollLeft: 0, scrollTop: 0 },
62+
);
5663

5764
return removeOnScroll;
5865
}, [brain]);
5966

60-
const domRef = useRef<HTMLDivElement | null>(null);
61-
6267
const headerCls = HeaderClsRecipe({
6368
overflow: false,
6469
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useEffect } from 'react';
2+
import { usePrevious } from '../../hooks/usePrevious';
3+
import { DEBUG_NAME } from '../InfiniteDebugName';
4+
import { createBrains } from '../state/getInitialState';
5+
import { useInfiniteTable } from './useInfiniteTable';
6+
7+
export function useToggleWrapRowsHorizontally() {
8+
const { state, getState, actions } = useInfiniteTable();
9+
10+
const { wrapRowsHorizontally } = state;
11+
const oldWrapRowsHorizontally = usePrevious(wrapRowsHorizontally);
12+
13+
useEffect(() => {
14+
if (oldWrapRowsHorizontally !== wrapRowsHorizontally) {
15+
const { brain, headerBrain, renderer, onRenderUpdater } = getState();
16+
17+
brain.destroy();
18+
headerBrain.destroy();
19+
renderer.destroy();
20+
onRenderUpdater.destroy();
21+
22+
const newBrains = createBrains(DEBUG_NAME, !!wrapRowsHorizontally);
23+
24+
actions.brain = newBrains.brain;
25+
actions.headerBrain = newBrains.headerBrain;
26+
27+
actions.renderer = newBrains.renderer;
28+
actions.onRenderUpdater = newBrains.onRenderUpdater;
29+
}
30+
}, [oldWrapRowsHorizontally, wrapRowsHorizontally]);
31+
}

source/src/components/InfiniteTable/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ import { HScrollSyncContent } from './components/HScrollSyncContent';
8989
import { useGridScroll } from './hooks/useGridScroll';
9090
import { useVisibleColumnSizes } from './hooks/useVisibleColumnSizes';
9191

92+
import { DEBUG_NAME } from './InfiniteDebugName';
93+
import { useToggleWrapRowsHorizontally } from './hooks/useToggleWrapRowsHorizontally';
94+
9295
export const InfiniteTableClassName = internalProps.rootClassName;
9396

9497
const HOVERED_CLASS_NAMES = [RowHoverCls, 'InfiniteColumnCell--hovered'];
@@ -113,7 +116,7 @@ const { ManagedComponentContextProvider: InfiniteTableRoot } =
113116
mappedCallbacks: getMappedCallbacks(),
114117
// @ts-ignore
115118
getParentState: () => useDataSourceState(),
116-
debugName: 'InfiniteTable',
119+
debugName: DEBUG_NAME,
117120
});
118121

119122
function InfiniteTableHeader<T>() {
@@ -248,6 +251,8 @@ function InfiniteTableBody<T>() {
248251

249252
const { autoFocus, tabIndex } = domProps ?? {};
250253

254+
useToggleWrapRowsHorizontally();
255+
251256
return (
252257
<InfiniteTableBodyContainer onContextMenu={onContextMenu}>
253258
<HeadlessTable

source/src/components/InfiniteTable/state/getInitialState.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,7 @@ export function getCellSelector(cellPosition?: CellPositionByIndex) {
5454
return selector;
5555
}
5656

57-
/**
58-
* The computed state is independent from props and cannot
59-
* be affected by props.
60-
*/
61-
export function initSetupState<T>({
62-
debugId,
63-
wrapRowsHorizontally,
64-
}: {
65-
debugId: string;
66-
wrapRowsHorizontally?: boolean;
67-
}): InfiniteTableSetupState<T> {
68-
const columnsGeneratedForGrouping: InfiniteTablePropColumns<T> = {};
69-
57+
export function createBrains(debugId: string, wrapRowsHorizontally: boolean) {
7058
/**
7159
* This is the main virtualization brain that powers the table
7260
*/
@@ -109,9 +97,26 @@ export function initSetupState<T>({
10997
headerBrain.update({ width: size.width });
11098
});
11199

112-
if (__DEV__) {
113-
(globalThis as any).renderer = renderer;
114-
}
100+
return { brain, headerBrain, renderer, onRenderUpdater };
101+
}
102+
103+
/**
104+
* The computed state is independent from props and cannot
105+
* be affected by props.
106+
*/
107+
export function initSetupState<T>({
108+
debugId,
109+
wrapRowsHorizontally,
110+
}: {
111+
debugId: string;
112+
wrapRowsHorizontally?: boolean;
113+
}): InfiniteTableSetupState<T> {
114+
const columnsGeneratedForGrouping: InfiniteTablePropColumns<T> = {};
115+
116+
const { brain, headerBrain, renderer, onRenderUpdater } = createBrains(
117+
debugId,
118+
!!wrapRowsHorizontally,
119+
);
115120

116121
const domRef = createRef<HTMLDivElement>();
117122

@@ -226,8 +231,6 @@ export const forwardProps = <T>(
226231
onContextMenu: 1,
227232
onCellContextMenu: 1,
228233

229-
wrapRowsHorizontally: 1,
230-
231234
onRenderRangeChange: 1,
232235

233236
onScrollToTop: 1,
@@ -261,6 +264,8 @@ export const forwardProps = <T>(
261264
onScrollbarsChange: 1,
262265
autoSizeColumnsKey: 1,
263266

267+
wrapRowsHorizontally: 1,
268+
264269
columnDefaultFlex: 1,
265270

266271
draggableColumnsRestrictTo: (draggableColumnsRestrictTo) =>

source/src/components/InfiniteTable/types/InfiniteTableState.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,14 @@ export type ContextMenuLocationWithEvent = Partial<CellContextMenuLocation> & {
5858
};
5959

6060
export interface InfiniteTableSetupState<T> {
61+
brain: MatrixBrain;
62+
headerBrain: MatrixBrain;
6163
renderer: ReactHeadlessTableRenderer;
64+
onRenderUpdater: SubscriptionCallback<Renderable>;
65+
6266
lastRowToExpandRef: MutableRefObject<any | null>;
6367
lastRowToCollapseRef: MutableRefObject<any | null>;
6468
getDOMNodeForCell: (cellPos: CellPositionByIndex) => HTMLElement | null;
65-
onRenderUpdater: SubscriptionCallback<Renderable>;
6669
propsCache: Map<keyof InfiniteTableProps<T>, WeakMap<any, any>>;
6770
columnsWhenInlineGroupRenderStrategy?: Record<string, InfiniteTableColumn<T>>;
6871
domRef: MutableRefObject<HTMLDivElement | null>;
@@ -104,8 +107,7 @@ export interface InfiniteTableSetupState<T> {
104107
keyDown: SubscriptionCallback<KeyboardEvent>;
105108
columnsWhenGrouping?: InfiniteTablePropColumns<T>;
106109
bodySize: Size;
107-
brain: MatrixBrain;
108-
headerBrain: MatrixBrain;
110+
109111
focused: boolean;
110112
ready: boolean;
111113
columnReorderDragColumnId: false | string;

0 commit comments

Comments
 (0)