Skip to content

Commit cc043e9

Browse files
committed
Add ability to customize className applied on hover over cells and release version patch
1 parent dd57a4f commit cc043e9

15 files changed

Lines changed: 262 additions & 185 deletions

examples/src/pages/tests/table/props/group-by/grouping-toolbar-vertical.page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const columns: InfiniteTablePropColumns<Developer> = {
5757
};
5858

5959
const dataSource: DataSourceData<Developer> = ({}) => {
60-
return fetch(process.env.NEXT_PUBLIC_BASE_URL + `/developers10k-sql`)
60+
return fetch(process.env.NEXT_PUBLIC_BASE_URL + `/developers100`)
6161
.then((r) => r.json())
6262
.then((data: Developer[]) => data);
6363
};
@@ -84,6 +84,9 @@ export default function App() {
8484
position: 'relative',
8585
},
8686
}}
87+
groupColumn={{
88+
field: 'id',
89+
}}
8790
columns={columns}
8891
columnDefaultWidth={200}
8992
columnDefaultGroupable
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { test, expect } from '@testing';
2+
3+
export default test.describe.parallel('InfiniteTable.Body', () => {
4+
test('should properly render the body', async ({
5+
page,
6+
7+
rowModel,
8+
}) => {
9+
await page.waitForInfinite();
10+
11+
expect(
12+
await rowModel.getTextForCell({
13+
rowIndex: 0,
14+
colId: 'group-by',
15+
}),
16+
).toBe('India');
17+
18+
expect(
19+
await rowModel.getTextForCell({
20+
rowIndex: 1,
21+
colId: 'group-by',
22+
}),
23+
).toBe('backend');
24+
25+
expect(
26+
await rowModel.getTextForCell({
27+
rowIndex: 2,
28+
colId: 'group-by',
29+
}),
30+
).toBe('0');
31+
});
32+
});

source/src/components/InfiniteTable/InfiniteCls.css.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ import { RowDetailRecipe } from './components/rowDetail.css';
88
import {
99
boxSizingBorderBox,
1010
display,
11-
flex,
1211
flexFlow,
1312
position,
14-
transformTranslateZero,
1513
} from './utilities.css';
1614

1715
export const InfiniteCls = style([
@@ -36,12 +34,6 @@ export const InfiniteCls = style([
3634
},
3735
]);
3836

39-
export const InfiniteBodyCls = style([
40-
position.relative,
41-
flex['1'],
42-
transformTranslateZero,
43-
]);
44-
4537
export const InfiniteClsScrolling = style(
4638
{
4739
vars: {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import * as React from 'react';
2+
import { join } from '../../../../utils/join';
3+
import { InfiniteBodyCls } from './body.css';
4+
import { InfiniteTableBodyClassName } from './bodyClassName';
5+
6+
const BodyClassName = join(InfiniteBodyCls, InfiniteTableBodyClassName);
7+
8+
export function InfiniteTableBodyContainer(
9+
props: React.HTMLAttributes<HTMLDivElement>,
10+
) {
11+
return (
12+
<div
13+
{...props}
14+
className={
15+
props.className ? join(BodyClassName, props.className) : BodyClassName
16+
}
17+
/>
18+
);
19+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export type InfiniteTableBodyProps<_T> = {
2+
rowHoverClassName?: string | string[];
3+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { style } from '@vanilla-extract/css';
2+
import { flex, position, transformTranslateZero } from '../../utilities.css';
3+
4+
export const InfiniteBodyCls = style([
5+
position.relative,
6+
flex['1'],
7+
transformTranslateZero,
8+
]);

source/src/components/InfiniteTable/bodyClassName.ts renamed to source/src/components/InfiniteTable/components/InfiniteTableBody/bodyClassName.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { rootClassName } from './internalProps';
1+
import { rootClassName } from '../../internalProps';
22

33
export const InfiniteTableBodyClassName = `${rootClassName}Body`;
44

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import * as React from 'react';
2+
import {
3+
useDataSourceContextValue,
4+
useMasterDetailContext,
5+
} from '../../../DataSource/publicHooks/useDataSourceState';
6+
import { HeadlessTable } from '../../../HeadlessTable';
7+
import { useCellRendering } from '../../hooks/useCellRendering';
8+
import { useInfiniteTable } from '../../hooks/useInfiniteTable';
9+
import { useToggleWrapRowsHorizontally } from '../../hooks/useToggleWrapRowsHorizontally';
10+
import {
11+
CellContextMenuLocationWithEvent,
12+
ContextMenuLocationWithEvent,
13+
} from '../../types/InfiniteTableState';
14+
import { InfiniteTableColumnCellClassName } from '../InfiniteTableRow/InfiniteTableColumnCellClassNames';
15+
import { RowHoverCls } from '../InfiniteTableRow/row.css';
16+
import { InfiniteTableBodyContainer } from './InfiniteTableBodyContainer';
17+
import { InfiniteTableBodyProps } from './InfiniteTableBodyProps';
18+
import { selectParentUntil } from '../../../../utils/selectParent';
19+
import { getCellSelector } from '../../state/getInitialState';
20+
import { LoadMask } from '../LoadMask';
21+
import { useMemo } from 'react';
22+
23+
const _HOVERED_CLASS_NAMES = [
24+
RowHoverCls,
25+
`${InfiniteTableColumnCellClassName}--hovered`,
26+
];
27+
28+
function InfiniteTableBody<T>(props: InfiniteTableBodyProps<T>) {
29+
const context = useInfiniteTable<T>();
30+
31+
const masterContext = useMasterDetailContext();
32+
const { state: componentState, getComputed, api } = context;
33+
const {
34+
renderer,
35+
onRenderUpdater,
36+
debugId,
37+
keyboardNavigation,
38+
activeRowIndex,
39+
loadingText,
40+
scrollStopDelay,
41+
brain,
42+
scrollerDOMRef,
43+
components,
44+
bodySize,
45+
activeCellIndex,
46+
rowDetailRenderer,
47+
showHoverRows,
48+
wrapRowsHorizontally,
49+
domProps,
50+
domRef,
51+
} = componentState;
52+
53+
const LoadMaskCmp = components?.LoadMask ?? LoadMask;
54+
55+
const computed = getComputed();
56+
const { computedRowHeight, computedRowSizeCacheForDetails } = computed;
57+
58+
const activeCellRowHeight =
59+
computedRowSizeCacheForDetails?.getRowHeight || computedRowHeight;
60+
61+
const {
62+
componentState: { loading },
63+
} = useDataSourceContextValue<T>();
64+
65+
const onContextMenu = React.useCallback((event: React.MouseEvent) => {
66+
const state = context.getState();
67+
const target = event.target as HTMLElement;
68+
69+
if (!masterContext && (event as any)._from_row_detail) {
70+
// originating from detail grid.
71+
return;
72+
}
73+
74+
if (masterContext) {
75+
(event as any)._from_row_detail = true;
76+
}
77+
78+
const cell = selectParentUntil(
79+
target,
80+
getCellSelector(),
81+
state.domRef.current,
82+
);
83+
84+
let columnId: string | undefined;
85+
let colIndex: number | undefined;
86+
let rowId: string | undefined;
87+
let rowIndex: number | undefined;
88+
89+
if (cell) {
90+
colIndex = Number(cell.dataset.colIndex);
91+
rowIndex = Number(cell.dataset.rowIndex);
92+
93+
columnId = context.getComputed().computedVisibleColumns[colIndex].id;
94+
rowId = context.dataSourceApi.getRowInfoArray()[rowIndex].id;
95+
}
96+
97+
const param: ContextMenuLocationWithEvent = {
98+
columnId,
99+
colIndex,
100+
rowId,
101+
rowIndex,
102+
event,
103+
target: cell ?? (event.target as HTMLElement),
104+
};
105+
106+
if (cell) {
107+
state.cellContextMenu(param as CellContextMenuLocationWithEvent);
108+
}
109+
state.contextMenu(param);
110+
}, []);
111+
112+
const { renderCell, renderDetailRow } = useCellRendering({
113+
imperativeApi: api,
114+
getComputed,
115+
domRef,
116+
117+
bodySize,
118+
computed,
119+
});
120+
121+
const { autoFocus, tabIndex } = domProps ?? {};
122+
123+
useToggleWrapRowsHorizontally();
124+
125+
const hoverClassNames = useMemo(() => {
126+
if (!showHoverRows) {
127+
return undefined;
128+
}
129+
130+
if (props.rowHoverClassName) {
131+
return Array.isArray(props.rowHoverClassName)
132+
? [...InfiniteTableBody.rowHoverClassNames, ...props.rowHoverClassName]
133+
: [...InfiniteTableBody.rowHoverClassNames, props.rowHoverClassName];
134+
}
135+
136+
return InfiniteTableBody.rowHoverClassNames;
137+
}, [
138+
showHoverRows,
139+
props.rowHoverClassName,
140+
InfiniteTableBody.rowHoverClassNames,
141+
]);
142+
143+
return (
144+
<InfiniteTableBodyContainer onContextMenu={onContextMenu}>
145+
<HeadlessTable
146+
forceRerenderTimestamp={componentState.forceBodyRerenderTimestamp}
147+
debugId={debugId}
148+
tabIndex={tabIndex ?? 0}
149+
autoFocus={autoFocus ?? undefined}
150+
activeRowIndex={
151+
componentState.ready && keyboardNavigation === 'row'
152+
? activeRowIndex
153+
: null
154+
}
155+
activeCellIndex={
156+
componentState.ready &&
157+
keyboardNavigation === 'cell' &&
158+
// we want to hide the active cell indicator while column reodering is happening
159+
!componentState.columnReorderDragColumnId
160+
? activeCellIndex
161+
: null
162+
}
163+
scrollStopDelay={scrollStopDelay}
164+
renderer={renderer}
165+
wrapRowsHorizontally={wrapRowsHorizontally}
166+
onRenderUpdater={onRenderUpdater}
167+
brain={brain}
168+
activeCellRowHeight={activeCellRowHeight}
169+
renderCell={renderCell}
170+
renderDetailRow={rowDetailRenderer ? renderDetailRow : undefined}
171+
cellHoverClassNames={hoverClassNames}
172+
scrollerDOMRef={scrollerDOMRef}
173+
scrollVarHostRef={domRef}
174+
></HeadlessTable>
175+
176+
<LoadMaskCmp visible={loading}>{loadingText}</LoadMaskCmp>
177+
</InfiniteTableBodyContainer>
178+
);
179+
}
180+
181+
InfiniteTableBody.rowHoverClassNames = _HOVERED_CLASS_NAMES;
182+
183+
export { InfiniteTableBody };

source/src/components/InfiniteTable/components/InfiniteTableRow/InfiniteTableColumnCell.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
InfiniteTableRowInfoDataDiscriminator,
66
InfiniteTable_Tree_RowInfoBase,
77
} from '../../../../utils/groupAndPivot';
8-
// const once = (fn: Function) => fn;
98

109
import { join } from '../../../../utils/join';
1110

@@ -14,7 +13,6 @@ import { useDataSourceContextValue } from '../../../DataSource/publicHooks/useDa
1413

1514
import { useCellClassName } from '../../hooks/useCellClassName';
1615
import { useInfiniteTable } from '../../hooks/useInfiniteTable';
17-
import { internalProps } from '../../internalProps';
1816
import { InternalVars } from '../../internalVars.css';
1917
import { InfiniteColumnEditorContextType } from '../../types';
2018

@@ -55,8 +53,7 @@ import {
5553
} from './InfiniteTableCellTypes';
5654
import { InfiniteTableColumnEditor } from './InfiniteTableColumnEditor';
5755
import { TreeColumnCellExpanderCls } from './row.css';
58-
59-
const { rootClassName } = internalProps;
56+
import { InfiniteTableColumnCellClassName } from './InfiniteTableColumnCellClassNames';
6057

6158
const columnZIndexAtIndex = stripVar(InternalVars.columnZIndexAtIndex);
6259
const columnVisibilityAtIndex = stripVar(InternalVars.columnVisibilityAtIndex);
@@ -79,8 +76,6 @@ export const InfiniteTableColumnCellContext = React.createContext<
7976
InfiniteTableColumnCellContextType<any>
8077
>(null as any as InfiniteTableColumnCellContextType<any>);
8178

82-
export const InfiniteTableColumnCellClassName = `${rootClassName}ColumnCell`;
83-
8479
export const defaultRenderRowDetailIcon: InfiniteTableColumnRenderFunction<
8580
any
8681
> = (params) => {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { internalProps } from '../../internalProps';
2+
3+
const { rootClassName } = internalProps;
4+
5+
export const InfiniteTableColumnCellClassName = `${rootClassName}ColumnCell`;

0 commit comments

Comments
 (0)