Skip to content

Commit 2d06930

Browse files
fix(PaginatedTable): fix table overflow, make column width optional (#1234)
1 parent 024fec4 commit 2d06930

File tree

8 files changed

+81
-59
lines changed

8 files changed

+81
-59
lines changed

src/components/PaginatedTable/PaginatedTable.scss

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,10 @@
2525
}
2626
}
2727

28-
&__colgroup {
29-
display: table;
30-
}
31-
32-
&__table-chunk {
33-
display: block;
34-
}
35-
3628
&__row {
29+
position: relative;
30+
z-index: 1;
31+
3732
&:hover {
3833
background: var(--paginated-table-hover-color);
3934
}
@@ -46,12 +41,8 @@
4641
}
4742

4843
&__head {
49-
z-index: 1;
44+
z-index: 2;
5045
@include sticky-top();
51-
52-
&-row {
53-
display: table;
54-
}
5546
}
5647

5748
&__sort-icon-container {
@@ -74,7 +65,7 @@
7465
&__head-cell-wrapper {
7566
position: relative;
7667

77-
display: flex;
68+
display: table-cell;
7869
overflow-x: hidden;
7970

8071
border-bottom: $cell-border;
@@ -177,4 +168,11 @@
177168
&__head-cell-wrapper:hover > &__resize-handler {
178169
visibility: visible;
179170
}
171+
172+
&__resizeable-table-container {
173+
width: max-content;
174+
175+
// padding for easier resize of the last column
176+
padding-right: 20px;
177+
}
180178
}

src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface PaginatedTableProps<T, F> {
3737
renderControls?: RenderControls;
3838
renderEmptyDataMessage?: RenderEmptyDataMessage;
3939
renderErrorMessage?: RenderErrorMessage;
40+
containerClassName?: string;
4041
}
4142

4243
export const PaginatedTable = <T, F>({
@@ -53,6 +54,7 @@ export const PaginatedTable = <T, F>({
5354
renderControls,
5455
renderErrorMessage,
5556
renderEmptyDataMessage,
57+
containerClassName,
5658
}: PaginatedTableProps<T, F>) => {
5759
const [sortParams, setSortParams] = React.useState<SortParams | undefined>(initialSortParams);
5860
const [totalEntities, setTotalEntities] = React.useState(limit);
@@ -153,7 +155,7 @@ export const PaginatedTable = <T, F>({
153155
};
154156

155157
return (
156-
<div ref={tableContainer} className={b(null)}>
158+
<div ref={tableContainer} className={b(null, containerClassName)}>
157159
{renderContent()}
158160
</div>
159161
);

src/components/PaginatedTable/ResizeablePaginatedTable.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {useTableResize} from '../../utils/hooks/useTableResize';
44

55
import type {PaginatedTableProps} from './PaginatedTable';
66
import {PaginatedTable} from './PaginatedTable';
7+
import {b} from './shared';
78
import type {Column} from './types';
89

910
function updateColumnsWidth<T>(columns: Column<T>[], columnsWidthSetup: ColumnWidthByName) {
@@ -30,6 +31,7 @@ export function ResizeablePaginatedTable<T, F>({
3031
<PaginatedTable
3132
columns={updatedColumns}
3233
onColumnsResize={setTableColumnsWidth}
34+
containerClassName={b('resizeable-table-container')}
3335
{...props}
3436
/>
3537
);

src/components/PaginatedTable/TableChunk.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {useAutoRefreshInterval} from '../../utils/hooks';
77
import {ResponseError} from '../Errors/ResponseError';
88

99
import {EmptyTableRow, LoadingTableRow, TableRow} from './TableRow';
10-
import {b} from './shared';
1110
import type {Column, FetchData, GetRowClassName, SortParams} from './types';
1211

1312
const DEBOUNCE_TIMEOUT = 200;
@@ -144,10 +143,15 @@ export const TableChunk = <T, F>({
144143

145144
return (
146145
<tbody
147-
className={b('table-chunk')}
148146
ref={ref}
149147
id={id.toString()}
150-
style={{height: `${chunkHeight}px`}}
148+
style={{
149+
height: `${chunkHeight}px`,
150+
// Default display: table-row-group doesn't work in Safari and breaks the table
151+
// display: block works in Safari, but disconnects thead and tbody cell grids
152+
// Hack to make it work in all cases
153+
display: isActive ? 'table-row-group' : 'block',
154+
}}
151155
>
152156
{renderContent()}
153157
</tbody>

src/components/PaginatedTable/TableHead.tsx

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const TableHeadCell = <T,>({
6666
onCellUnMount,
6767
onColumnsResize,
6868
}: TableHeadCellProps<T>) => {
69-
const cellWrapperRef = React.useRef<HTMLDivElement>(null);
69+
const cellWrapperRef = React.useRef<HTMLTableCellElement>(null);
7070

7171
React.useEffect(() => {
7272
const cellWrapper = cellWrapperRef.current;
@@ -93,44 +93,43 @@ export const TableHeadCell = <T,>({
9393

9494
const content = column.header ?? column.name;
9595

96+
const style = {
97+
height: `${rowHeight}px`,
98+
width: `${column.width}px`,
99+
// Additional minWidth and maxWidth for resizeable columns to ensure proper resize
100+
minWidth: resizeable ? `${column.width}px` : undefined,
101+
maxWidth: resizeable ? `${column.width}px` : undefined,
102+
};
103+
96104
return (
97-
<th>
105+
<th ref={cellWrapperRef} className={b('head-cell-wrapper')} style={style}>
98106
<div
99-
ref={cellWrapperRef}
100-
className={b('head-cell-wrapper')}
101-
style={{
102-
height: `${rowHeight}px`,
103-
width: `${column.width}px`,
107+
className={b(
108+
'head-cell',
109+
{align: column.align, sortable: column.sortable},
110+
column.className,
111+
)}
112+
onClick={() => {
113+
if (column.sortable) {
114+
onSort?.(column.name);
115+
}
104116
}}
105117
>
106-
<div
107-
className={b(
108-
'head-cell',
109-
{align: column.align, sortable: column.sortable},
110-
column.className,
111-
)}
112-
onClick={() => {
113-
if (column.sortable) {
114-
onSort?.(column.name);
115-
}
116-
}}
117-
>
118-
<div className={b('head-cell-content')}>{content}</div>
119-
<ColumnSortIcon
120-
sortOrder={sortOrder}
121-
sortable={column.sortable}
122-
defaultSortOrder={defaultSortOrder}
123-
/>
124-
</div>
125-
{resizeable ? (
126-
<ResizeHandler
127-
maxWidth={column.resizeMaxWidth}
128-
minWidth={column.resizeMinWidth}
129-
getCurrentColumnWidth={getCurrentColumnWidth}
130-
onResize={handleResize}
131-
/>
132-
) : null}
118+
<div className={b('head-cell-content')}>{content}</div>
119+
<ColumnSortIcon
120+
sortOrder={sortOrder}
121+
sortable={column.sortable}
122+
defaultSortOrder={defaultSortOrder}
123+
/>
133124
</div>
125+
{resizeable ? (
126+
<ResizeHandler
127+
maxWidth={column.resizeMaxWidth}
128+
minWidth={column.resizeMinWidth}
129+
getCurrentColumnWidth={getCurrentColumnWidth}
130+
onResize={handleResize}
131+
/>
132+
) : null}
134133
</th>
135134
);
136135
};
@@ -183,7 +182,7 @@ export const TableHead = <T,>({
183182

184183
const renderTableColGroups = () => {
185184
return (
186-
<colgroup className={b('colgroup')}>
185+
<colgroup>
187186
{columns.map((column) => {
188187
return <col key={column.name} style={{width: `${column.width}px`}} />;
189188
})}
@@ -194,7 +193,7 @@ export const TableHead = <T,>({
194193
const renderTableHead = () => {
195194
return (
196195
<thead className={b('head')}>
197-
<tr className={b('head-row')}>
196+
<tr>
198197
{columns.map((column) => {
199198
const sortOrder =
200199
sortParams.columnId === column.name ? sortParams.sortOrder : undefined;

src/components/PaginatedTable/TableRow.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import {Skeleton} from '@gravity-ui/uikit';
22

3-
import {DEFAULT_ALIGN} from './constants';
3+
import {DEFAULT_ALIGN, DEFAULT_RESIZEABLE} from './constants';
44
import {b} from './shared';
55
import type {AlignType, Column, GetRowClassName} from './types';
66

77
interface TableCellProps {
88
height: number;
9-
width: number;
9+
width?: number;
1010
align?: AlignType;
1111
children: React.ReactNode;
1212
className?: string;
13+
resizeable?: boolean;
1314
}
1415

1516
const TableRowCell = ({
@@ -18,12 +19,17 @@ const TableRowCell = ({
1819
height,
1920
width,
2021
align = DEFAULT_ALIGN,
22+
resizeable,
2123
}: TableCellProps) => {
22-
// Additional maxWidth to ensure overflow hidden for <td>
2324
return (
2425
<td
2526
className={b('row-cell', {align: align}, className)}
26-
style={{height: `${height}px`, width: `${width}px`, maxWidth: `${width}px`}}
27+
style={{
28+
height: `${height}px`,
29+
width: `${width}px`,
30+
// Additional maxWidth for resizeable columns to ensure overflow hidden for <td>
31+
maxWidth: resizeable ? `${width}px` : undefined,
32+
}}
2733
>
2834
{children}
2935
</td>
@@ -40,13 +46,16 @@ export const LoadingTableRow = <T,>({index, columns, height}: LoadingTableRowPro
4046
return (
4147
<tr className={b('row', {loading: true})}>
4248
{columns.map((column) => {
49+
const resizeable = column.resizeable ?? DEFAULT_RESIZEABLE;
50+
4351
return (
4452
<TableRowCell
4553
key={`${column.name}${index}`}
4654
height={height}
4755
width={column.width}
4856
align={column.align}
4957
className={column.className}
58+
resizeable={resizeable}
5059
>
5160
<Skeleton style={{width: '80%', height: '50%'}} />
5261
</TableRowCell>
@@ -70,13 +79,16 @@ export const TableRow = <T,>({row, index, columns, getRowClassName, height}: Tab
7079
return (
7180
<tr className={b('row', additionalClassName)}>
7281
{columns.map((column) => {
82+
const resizeable = column.resizeable ?? DEFAULT_RESIZEABLE;
83+
7384
return (
7485
<TableRowCell
7586
key={`${column.name}${index}`}
7687
height={height}
7788
width={column.width}
7889
align={column.align}
7990
className={column.className}
91+
resizeable={resizeable}
8092
>
8193
{column.render({row, index})}
8294
</TableRowCell>

src/components/PaginatedTable/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface Column<T> {
3030
sortable?: boolean;
3131
resizeable?: boolean;
3232
render: (props: {row: T; index: number}) => React.ReactNode;
33-
width: number;
33+
width?: number;
3434
resizeMaxWidth?: number;
3535
resizeMinWidth?: number;
3636
align: AlignType;

src/components/TableWithControlsLayout/TableWithControlsLayout.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
@include sticky-top();
2626
}
2727

28+
&__table {
29+
position: relative;
30+
z-index: 2;
31+
}
32+
2833
.ydb-paginated-table__head {
2934
top: 62px;
3035
}

0 commit comments

Comments
 (0)