Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1377,11 +1377,23 @@ const columns: readonly Column<Row>[] = [
];
```

##### `frozen?: Maybe<boolean>`
##### `frozen?: Maybe<boolean | 'start' | 'end'>`

**Default**: `false`

Determines whether column is frozen. Frozen columns are pinned to the start edge (left in LTR, right in RTL). Per-column pinning to the end edge is not supported at the moment.
Determines whether the column is frozen, and on which edge. Frozen columns stay in place when the grid is scrolled horizontally.

- `'start'` (or `true` for backwards compatibility) — pins the column to the start edge (left in LTR, right in RTL).
- `'end'` — pins the column to the end edge (right in LTR, left in RTL).
- `false` (default) — the column scrolls with the rest of the grid.

```tsx
const columns: readonly Column<Row>[] = [
{ key: 'id', name: 'ID', frozen: 'start' },
{ key: 'name', name: 'Name' },
{ key: 'actions', name: 'Actions', frozen: 'end' }
];
```

##### `resizable?: Maybe<boolean>`

Expand Down
137 changes: 86 additions & 51 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ import { default as defaultRenderSortStatus } from './sortStatus';
import { cellDragHandleClassname, cellDragHandleFrozenClassname } from './style/cell';
import {
rootClassname,
frozenColumnShadowClassname,
viewportDraggingClassname,
frozenColumnShadowTopClassname
frozenColumnShadowEndClassname,
frozenColumnShadowEndTopClassname,
frozenColumnShadowStartClassname,
frozenColumnShadowStartTopClassname,
viewportDraggingClassname
} from './style/core';
import SummaryRow from './SummaryRow';

Expand Down Expand Up @@ -343,13 +345,15 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
const {
columns,
colSpanColumns,
lastFrozenColumnIndex,
lastStartFrozenColumnIndex,
firstEndFrozenColumnIndex,
headerRowsCount,
colOverscanStartIdx,
colOverscanEndIdx,
templateColumns,
layoutCssVars,
totalFrozenColumnWidth
totalStartFrozenColumnWidth,
totalEndFrozenColumnWidth
} = useCalculatedColumns({
rawColumns,
defaultColumnOptions,
Expand Down Expand Up @@ -379,8 +383,13 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
const { leftKey, rightKey } = getLeftRightKey(direction);
const ariaRowCount = rawAriaRowCount ?? headerRowsCount + rows.length + summaryRowsCount;
const frozenShadowStyles: React.CSSProperties = {
gridColumnStart: lastFrozenColumnIndex + 2,
insetInlineStart: totalFrozenColumnWidth
gridColumnStart: lastStartFrozenColumnIndex + 2,
insetInlineStart: totalStartFrozenColumnWidth
};
const frozenEndShadowStyles: React.CSSProperties = {
gridColumnStart: firstEndFrozenColumnIndex + 1,
gridColumnEnd: -1,
insetInlineEnd: totalEndFrozenColumnWidth
};

const {
Expand Down Expand Up @@ -463,7 +472,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
colSpanColumns,
colOverscanStartIdx,
colOverscanEndIdx,
lastFrozenColumnIndex,
lastStartFrozenColumnIndex,
firstEndFrozenColumnIndex,
rowOverscanStartIdx,
rowOverscanEndIdx,
rows,
Expand Down Expand Up @@ -509,7 +519,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
element: gridRef.current,
scrollToCell({ idx, rowIdx }) {
const scrollToIdx =
idx != null && idx > lastFrozenColumnIndex && idx < columns.length ? idx : undefined;
idx != null && idx > lastStartFrozenColumnIndex && idx < columns.length ? idx : undefined;
const scrollToRowIdx =
rowIdx != null && validatePosition({ idx: 0, rowIdx }).isPositionInViewport
? rowIdx + headerAndTopSummaryRowsCount
Expand Down Expand Up @@ -902,7 +912,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
minRowIdx,
mainHeaderRowIdx,
maxRowIdx,
lastFrozenColumnIndex,
lastStartFrozenColumnIndex,
firstEndFrozenColumnIndex,
cellNavigationMode,
activePosition,
nextPosition,
Expand Down Expand Up @@ -967,6 +978,53 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
);
}

function renderFrozenShadow(
shadowStyles: React.CSSProperties,
bodyClassname: string,
topClassname: string
) {
return (
<>
<div
className={topClassname}
style={{
...shadowStyles,
gridRowStart: 1,
gridRowEnd: headerRowsCount + 1 + topSummaryRowsCount,
insetBlockStart: 0
}}
/>

{rows.length > 0 && (
<div
className={bodyClassname}
style={{
...shadowStyles,
gridRowStart: headerAndTopSummaryRowsCount + rowOverscanStartIdx + 1,
gridRowEnd: headerAndTopSummaryRowsCount + rowOverscanEndIdx + 2
}}
/>
)}

{bottomSummaryRows != null && bottomSummaryRowsCount > 0 && (
<div
className={topClassname}
style={{
...shadowStyles,
gridRowStart: headerAndTopSummaryRowsCount + rows.length + 1,
gridRowEnd: headerAndTopSummaryRowsCount + rows.length + 1 + bottomSummaryRowsCount,
insetBlockStart:
clientHeight > totalRowHeight
? gridHeight - summaryRowHeight * bottomSummaryRowsCount
: undefined,
insetBlockEnd: clientHeight > totalRowHeight ? undefined : 0
}}
/>
)}
</>
);
}

function getCellEditor(rowIdx: number) {
if (
!activePositionIsCellInViewport ||
Expand All @@ -978,7 +1036,10 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr

const { row } = activePosition;
const column = getActiveColumn();
const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'ROW', row });
const colSpan = getColSpan(column, lastStartFrozenColumnIndex, firstEndFrozenColumnIndex, {
type: 'ROW',
row
});

function closeEditor(shouldFocus: boolean) {
const newPosition: ActivePosition = { idx: activePosition.idx, rowIdx, mode: 'ACTIVE' };
Expand Down Expand Up @@ -1113,7 +1174,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
style={{
...style,
// set scrollPadding to correctly scroll to non-sticky cells/rows
scrollPaddingInlineStart: totalFrozenColumnWidth,
scrollPaddingInlineStart: totalStartFrozenColumnWidth,
scrollPaddingInlineEnd: totalEndFrozenColumnWidth,
scrollPaddingBlockStart: headerRowsHeight + topSummaryRowsCount * summaryRowHeight,
scrollPaddingBlockEnd: bottomSummaryRowsCount * summaryRowHeight,
gridTemplateColumns,
Expand Down Expand Up @@ -1227,46 +1289,19 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
)}
</DataGridDefaultRenderersContext>

{lastFrozenColumnIndex > -1 && (
<>
<div
className={frozenColumnShadowTopClassname}
style={{
...frozenShadowStyles,
gridRowStart: 1,
gridRowEnd: headerRowsCount + 1 + topSummaryRowsCount,
insetBlockStart: 0
}}
/>
{lastStartFrozenColumnIndex > -1 &&
renderFrozenShadow(
frozenShadowStyles,
frozenColumnShadowStartClassname,
frozenColumnShadowStartTopClassname
)}

{rows.length > 0 && (
<div
className={frozenColumnShadowClassname}
style={{
...frozenShadowStyles,
gridRowStart: headerAndTopSummaryRowsCount + rowOverscanStartIdx + 1,
gridRowEnd: headerAndTopSummaryRowsCount + rowOverscanEndIdx + 2
}}
/>
)}

{bottomSummaryRows != null && bottomSummaryRowsCount > 0 && (
<div
className={frozenColumnShadowTopClassname}
style={{
...frozenShadowStyles,
gridRowStart: headerAndTopSummaryRowsCount + rows.length + 1,
gridRowEnd: headerAndTopSummaryRowsCount + rows.length + 1 + bottomSummaryRowsCount,
insetBlockStart:
clientHeight > totalRowHeight
? gridHeight - summaryRowHeight * bottomSummaryRowsCount
: undefined,
insetBlockEnd: clientHeight > totalRowHeight ? undefined : 0
}}
/>
)}
</>
)}
{firstEndFrozenColumnIndex > -1 &&
renderFrozenShadow(
frozenEndShadowStyles,
frozenColumnShadowEndClassname,
frozenColumnShadowEndTopClassname
)}

{getDragHandle()}

Expand Down
7 changes: 4 additions & 3 deletions src/GroupRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { classnames } from './utils';
import type { BaseRenderRowProps, GroupRow, Omit } from './types';
import { SELECT_COLUMN_KEY } from './Columns';
import GroupCell from './GroupCell';
import { cell, cellFrozen } from './style/cell';
import { cell, cellFrozenStart } from './style/cell';
import { rowClassname, rowActiveClassname } from './style/row';

const groupRow = css`
Expand All @@ -15,8 +15,9 @@ const groupRow = css`
background-color: var(--rdg-header-background-color);
}

> .${cell}:not(:last-child, .${cellFrozen}),
> :nth-last-child(n + 2 of .${cellFrozen}) {
> .${cell}:not(:last-child, .${cellFrozenStart}),
> :nth-last-child(n + 2 of .rdg-cell-frozen-start),
> :nth-child(n + 2 of .rdg-cell-frozen-end) {
border-inline-end: none;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/HeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type {
} from './types';
import type { DataGridProps } from './DataGrid';
import HeaderCell from './HeaderCell';
import { cell, cellFrozen } from './style/cell';
import { cell, cellFrozenStart } from './style/cell';
import { rowActiveClassname } from './style/row';

type SharedDataGridProps<R, SR, K extends React.Key> = Pick<
Expand Down Expand Up @@ -44,7 +44,7 @@ const headerRow = css`
position: sticky;
}

& > .${cellFrozen} {
& > .${cellFrozenStart} {
z-index: 3;
}
}
Expand Down
Loading