Skip to content

Commit 8476aed

Browse files
committed
[data-table] fixed animations in accordions
1 parent 05c1431 commit 8476aed

File tree

5 files changed

+63
-8
lines changed

5 files changed

+63
-8
lines changed

semcore/data-table/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG.md standards are inspired by [keepachangelog.com](https://keepachangel
88

99
- Render grouped header in some cases.
1010
- Styles for cells in accordion in different variants.
11+
- Laggy animation in accordions.
1112

1213
## [16.3.0] - 2025-09-12
1314

semcore/data-table/src/components/Body/Cell.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, Collapse, Flex } from '@semcore/base-components';
1+
import { Box, Flex } from '@semcore/base-components';
22
import { Component, Root, sstyled, createComponent } from '@semcore/core';
33
import { getFocusableIn } from '@semcore/core/lib/utils/focus-lock/getFocusableIn';
44
import { isFocusInside } from '@semcore/core/lib/utils/focus-lock/isFocusInside';
@@ -136,6 +136,7 @@ class CellRoot<Data extends DataTableData, UniqKeyType> extends Component<DataTa
136136
animationExpand,
137137
style,
138138
shadowVertical,
139+
calculatedHeight,
139140
} = this.asProps;
140141

141142
const cell = row[column.name];
@@ -161,13 +162,11 @@ class CellRoot<Data extends DataTableData, UniqKeyType> extends Component<DataTa
161162

162163
return sstyled(styles)(
163164
<SCellWrapper
165+
// @ts-ignore
164166
gridArea={gridArea}
165-
tag={isAccordionRow ? Collapse : undefined}
166-
visible={animationExpand}
167-
duration={duration}
168-
delay={delay}
169-
defaultHeight='100%'
170-
timingFunction='linear'
167+
duration={`${duration}ms`}
168+
delay={`${delay}ms`}
169+
h={isAccordionRow ? (animationExpand ? `${calculatedHeight}px` : `0px`) : undefined}
171170
style={style}
172171
fixed={column.fixed}
173172
shadowVertical={column.showShadowVertical ? shadowVertical : undefined}

semcore/data-table/src/components/Body/Cell.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export type CellPropsInner<Data extends DataTableData, UniqKeyType> = {
3939
lastLeftFixedIndex: number;
4040
firstRightFixedIndex: number;
4141
withoutBorder?: boolean;
42+
calculatedHeight: number;
4243
};
4344

4445
export type DataTableCellType = (<UniqKeyType, Tag extends Intergalactic.Tag = 'div'>(

semcore/data-table/src/components/Body/Row.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { isInteractiveElement } from '@semcore/core/lib/utils/isInteractiveEleme
77
import ChevronRightM from '@semcore/icon/ChevronRight/m';
88
import * as React from 'react';
99

10-
import { INDEX_OFFSET } from './Body';
1110
import { Cell } from './Cell';
1211
import type { DataTableCellProps, DataTableCellType } from './Cell.types';
1312
import { MergedColumnsCell, MergedRowsCell } from './MergedCells';
@@ -18,6 +17,7 @@ import type { DataTableData, DTValue } from '../DataTable/DataTable.types';
1817

1918
type State = {
2019
expandedForAnimation: boolean;
20+
calculatedHeight: number;
2121
};
2222

2323
export class RowRoot<Data extends DataTableData, UniqKeyType> extends Component<DataTableRowProps<Data, UniqKeyType>, {}, State, [], RowPropsInner<Data, UniqKeyType>> {
@@ -35,6 +35,7 @@ export class RowRoot<Data extends DataTableData, UniqKeyType> extends Component<
3535

3636
state: State = {
3737
expandedForAnimation: false,
38+
calculatedHeight: 0,
3839
};
3940

4041
constructor(props: DataTableRowProps<Data, UniqKeyType>) {
@@ -47,6 +48,16 @@ export class RowRoot<Data extends DataTableData, UniqKeyType> extends Component<
4748
this.asProps.componentRef?.(this);
4849
}
4950

51+
componentDidUpdate(prevProps: DataTableRowProps<Data, UniqKeyType>, prevState: State) {
52+
const { animationExpand } = this.asProps;
53+
54+
if (animationExpand && this.rowElementRef.current && prevState.calculatedHeight === 0) {
55+
const height = this.calculateRowHeight(this.rowElementRef.current);
56+
57+
this.setState({ calculatedHeight: height });
58+
}
59+
}
60+
5061
componentWillUnmount() {
5162
this.asProps.componentRef?.(null);
5263
}
@@ -221,6 +232,7 @@ export class RowRoot<Data extends DataTableData, UniqKeyType> extends Component<
221232
flatRows: this.asProps.flatRows,
222233
shadowVertical,
223234
withoutBorder,
235+
calculatedHeight: this.state.calculatedHeight,
224236
};
225237

226238
if (renderCell) {
@@ -531,6 +543,40 @@ export class RowRoot<Data extends DataTableData, UniqKeyType> extends Component<
531543
obj === null
532544
);
533545
}
546+
547+
private calculateRowHeight(rowElement: HTMLElement): number {
548+
const accordionFull = rowElement.cloneNode(true);
549+
550+
if (!(accordionFull instanceof HTMLElement)) {
551+
return 0;
552+
}
553+
554+
const columnsWidth: number[] = [];
555+
556+
const columns = Array.from(rowElement.children);
557+
columns.forEach((column) => {
558+
columnsWidth.push(column.getBoundingClientRect().width);
559+
});
560+
561+
accordionFull.style.display = 'grid';
562+
accordionFull.style.position = 'absolute';
563+
accordionFull.style.visibility = 'hidden';
564+
accordionFull.style.gridTemplateColumns = columnsWidth.join('px ') + 'px';
565+
566+
Array.from(accordionFull.children).forEach((child) => {
567+
if (child instanceof HTMLElement) {
568+
child.style.height = '100%';
569+
}
570+
});
571+
572+
document.body.appendChild(accordionFull);
573+
574+
const height = accordionFull.getBoundingClientRect().height;
575+
576+
document.body.removeChild(accordionFull);
577+
578+
return height;
579+
}
534580
}
535581

536582
export const Row = createComponent(RowRoot, {

semcore/data-table/src/components/Body/style.shadow.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,14 @@ SRow[sideIndents='wide'] {
295295
}
296296
}
297297

298+
SRow[isAccordionRow] > SCellWrapper {
299+
transition-property: height;
300+
transition-delay: var(--delay);
301+
transition-duration: var(--duration);
302+
transition-timing-function: linear;
303+
overflow: clip;
304+
}
305+
298306
SCellWrapper[fixed][shadowVertical] {
299307
&:after {
300308
content: '';

0 commit comments

Comments
 (0)