Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add columns resize #41

Merged
merged 1 commit into from
Apr 12, 2024
Merged
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
45 changes: 25 additions & 20 deletions README.md

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": ["@gravity-ui/eslint-config", "@gravity-ui/eslint-config/prettier"]
"extends": ["@gravity-ui/eslint-config", "@gravity-ui/eslint-config/prettier"],
"rules": {
"no-implicit-globals": "off"
}
}
20 changes: 20 additions & 0 deletions src/lib/DataTable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ $cell-border: 1px solid var(--data-table-border-color);
}

&__th {
box-sizing: border-box;
font-weight: 500;
cursor: default;
padding: var(--data-table-header-vertical-padding) var(--data-table-cell-horizontal-padding);
Expand Down Expand Up @@ -98,6 +99,7 @@ $cell-border: 1px solid var(--data-table-border-color);
}

&__td {
box-sizing: border-box;
padding: var(--data-table-cell-vertical-padding) var(--data-table-cell-horizontal-padding);
border: $cell-border;
vertical-align: var(--data-table-cell-align);
Expand Down Expand Up @@ -267,4 +269,22 @@ $cell-border: 1px solid var(--data-table-border-color);
--data-table-color-hover-area: #ffeba0;
--data-table-color-footer-area: var(--data-table-color-base);
}

&__resize-handler {
visibility: hidden;
position: absolute;
right: 0;
top: 0;
cursor: col-resize;
width: 6px;
height: 100%;
background-color: var(--g-color-base-generic);

&_resizing {
visibility: visible;
}
}
&__th:hover > &__resize-handler {
visibility: visible;
}
}
81 changes: 65 additions & 16 deletions src/lib/DataTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@
import ReactList from 'react-list';

import './DataTable.scss';
import {ResizeHandler} from './ResizeHandler';
import {ASCENDING, CENTER, DESCENDING, FIXED, INDEX_COLUMN, LEFT, MOVING, RIGHT} from './constants';
import {positionStickySupported} from './featureSupport';
import {HeightObserver} from './height-observer';
import {Column, DataTableProps, HeadPosition, OrderType, Settings, SortedDataItem} from './types';
import {
SlimColumn,
cn,
b,
externalToInternalSortOrder,
getSortOrder,
getSortedData,
internalToExternalSortOrder,
} from './util';

const b = cn('data-table');

const ICON_ASC = (
<svg className={b('icon')} viewBox="0 0 10 6" width="10" height="6">
<path fill="currentColor" d="M0 5h10l-5 -5z" />
Expand Down Expand Up @@ -122,19 +121,27 @@
}

const value = column._getValue(row);

let style = column.customStyle({
row,
index,
name: column.name,
header: false,
footer,
headerData,
});

// Fixed cell width for resizeable columns for proper content wrap
if (column.resizeable) {
style = {...style, width: column.width, maxWidth: column.width};
}

return (
<td
key={columnIndex}
className={column._className}
title={column._getTitle(row)}
style={column.customStyle({
row,
index,
name: column.name,
header: false,
footer,
headerData,
})}
style={style}
colSpan={colSpans ? colSpans[column.name] : undefined}
rowSpan={rowSpan}
onClick={column._getOnClick({row, index, footer, headerData})}
Expand All @@ -160,6 +167,7 @@
displayIndices?: boolean;

onSort?: TableProps<T>['onSort'];
onResize?: TableProps<T>['onResize'];
onColumnsUpdated?: (widths: number[]) => void;
renderedDataRows?: React.ReactNode;

Expand All @@ -169,7 +177,7 @@
class TableHead<T> extends React.Component<TableHeadProps<T>> {
_dataRowsRef: HTMLTableSectionElement | null = null;
dataRowsHeightObserver?: HeightObserver;
renderedColumns: HTMLTableHeaderCellElement[] = [];
renderedColumns: HTMLTableCellElement[] = [];

componentDidMount() {
this._calculateColumnsWidth();
Expand Down Expand Up @@ -238,6 +246,7 @@
: undefined;
}
renderHeadCell = (headCell: HeadCellsType<T>) => {
const {onResize} = this.props;
const {column, rowSpan, colSpan} = headCell;
const {
sortable = false,
Expand All @@ -246,26 +255,48 @@
index,
columnIndex,
align,
name,
width,
resizeable,
resizeMinWidth,
resizeMaxWidth,
} = column;

const {headerTitle = (typeof header === 'string' && header) || undefined} = column;

let style = column.customStyle?.({header: true, name});

// Fixed cell width for resizeable columns for proper content wrap
if (resizeable) {
style = {...style, width, maxWidth: width};
}

return (
<th
ref={column.dataColumn ? this._getColumnRef(columnIndex!) : null}

Check warning on line 276 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Forbidden non-null assertion
className={b('th', {sortable, align}, className)}
key={column.name}
key={name}
title={headerTitle}
data-index={index}
colSpan={colSpan}
rowSpan={rowSpan}
style={column.customStyle && column.customStyle({header: true, name: column.name})}
style={style}
onClick={this._getOnSortClick(column)}
>
<div className={b('head-cell')}>
{header}
{<ColumnSortIcon {...column} />}
</div>
{resizeable && (
<ResizeHandler
getColumn={this._getRenderedColumn}
columnIndex={columnIndex}
onResize={onResize}
columnId={name}
minWidth={resizeMinWidth}
maxWidth={resizeMaxWidth}
/>
)}
</th>
);
};
Expand All @@ -289,6 +320,12 @@
this.renderedColumns[index] = node;
};
};
_getRenderedColumn = (index?: number) => {
if (index) {
return this.renderedColumns[index];
}
return undefined;
};
}

interface StickyHeadProps<T> {
Expand All @@ -298,6 +335,7 @@
mode: HeadPositionInner;
displayIndices?: Settings['displayIndices'];
onSort?: TableProps<T>['onSort'];
onResize?: TableProps<T>['onResize'];
top: number;

renderedDataRows: React.ReactNode;
Expand Down Expand Up @@ -534,6 +572,7 @@
rowKey: (row: T, index: number) => string | number;
startIndex: DataTableProps<T>['startIndex'];
onSort: DataTableView<T>['onSort'];
onResize: DataTableProps<T>['onResize'];
renderEmptyRow: unknown;
nullBeforeNumbers?: boolean;
getColSpansOfRow?: (
Expand Down Expand Up @@ -673,7 +712,7 @@
}

renderHead() {
const {columns, onSort} = this.props;
const {columns, onSort, onResize} = this.props;
const {displayIndices} = this.props.settings;
const rows = this.renderHeaderRows();
return (
Expand All @@ -682,13 +721,14 @@
{...columns}
displayIndices={Boolean(displayIndices)}
onSort={onSort}
onResize={onResize}
onColumnsUpdated={this._onColumnsUpdated}
renderedDataRows={rows}
/>
);
}
renderStickyHead() {
const {columns, onSort} = this.props;
const {columns, onSort, onResize} = this.props;
const {displayIndices, stickyTop, stickyHead} = this.props.settings;
const top =
stickyTop === 'auto' && this._body && this._body.parentNode
Expand All @@ -703,6 +743,7 @@
{...columns}
displayIndices={displayIndices}
onSort={onSort}
onResize={onResize}
renderedDataRows={rows}
onDataRowsHeightChange={this.onMovingHeaderDataRowsHeightChange}
/>
Expand Down Expand Up @@ -780,7 +821,7 @@
/>
);
};
renderTable = (items: React.ReactNode[], ref?: any) => {

Check warning on line 824 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
const {
footerData,
columns: {dataColumns},
Expand Down Expand Up @@ -879,7 +920,7 @@

interface CellProps<T> {
column: Column<T>;
value?: any;

Check warning on line 923 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
row: T;
index: number;
footer?: boolean;
Expand All @@ -892,7 +933,7 @@
const {column, value, row, index, footer, headerData} = props;

return (
<React.Fragment>{column.render!({value, row, index, footer, headerData})}</React.Fragment>

Check warning on line 936 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Forbidden non-null assertion
);
}

Expand All @@ -916,8 +957,9 @@
sortable: true,
externalSort: false,
defaultOrder: ASCENDING as OrderType,
defaultResizeable: false,
},
rowKey: (row: any, index: number) =>

Check warning on line 962 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
Object.prototype.hasOwnProperty.call(row, 'id') ? row.id : index,
initialSortOrder: {},
initialSortColumns: [],
Expand All @@ -930,7 +972,7 @@
stickyHead: Settings['stickyHead'] | false = false,
): HeadPositionInner {
if (stickyHead === MOVING && !positionStickySupported) {
console.warn(

Check warning on line 975 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected console statement
'Your browser does not support position: sticky, moving sticky headers will be disabled.',
);
return false;
Expand Down Expand Up @@ -971,6 +1013,7 @@
return startIndex + index;
},
sortable: false,
resizeable: false,
width: 20 + Math.ceil(Math.log10(lastIndex)) * 10,
};
}
Expand All @@ -988,8 +1031,8 @@
}

state: DataTableViewState<T> = {
settings: {} as any, // see getDerivedStateFromProps

Check warning on line 1034 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
...externalToInternalSortOrder(this.props.initialSortOrder!, this.props.settings),

Check warning on line 1035 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Forbidden non-null assertion
};

table?: Table<T>;
Expand All @@ -1006,6 +1049,7 @@
rowClassName,
rowKey,
onRowClick,
onResize,
theme,
renderEmptyRow,
nullBeforeNumbers,
Expand All @@ -1022,7 +1066,7 @@

const dataColumns = this.getComplexColumns(columns);
if (settings.dynamicRender && dataColumns.dataColumns.some((column) => column.group)) {
console.warn(

Check warning on line 1069 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected console statement
'Simultaneously used grouping cells and dynamic render. The table will render unpredictable.',
);
}
Expand Down Expand Up @@ -1055,6 +1099,7 @@
)}
footerData={footerData}
onSort={this.onSort}
onResize={onResize}
/>
);
}
Expand All @@ -1079,6 +1124,7 @@
};

getColumn = (column: Column<T>, columnIndex: number) => {
const {onResize} = this.props;
const {settings} = this.state;
const {defaultOrder} = settings;
const {sortOrder = {}, sortColumns, indexColumn} = this.state;
Expand All @@ -1098,10 +1144,12 @@
const {sortAccessor, onClick} = column;
const _className = b('td', {align}, column.className);

const resizeable = (column.resizeable ?? settings.defaultResizeable) && Boolean(onResize);

const _getValue =
typeof accessor === 'function'
? (row: T) => accessor(row)
: (row: any) => {

Check warning on line 1152 in src/lib/DataTable.tsx

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type
return Object.prototype.hasOwnProperty.call(row, accessor)
? row[accessor]
: undefined;
Expand Down Expand Up @@ -1137,6 +1185,7 @@
dataColumn: true,
defaultOrder,
...column,
resizeable,
sortable: sortable && isSortEnabled,
_className,
_getValue,
Expand Down
Loading
Loading