diff --git a/README.md b/README.md index d085252..a5737a2 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ The `name` field is the only mandatory field. The remaining fields are described | headerTitle | `string` | Header title | | className | `string` | Column class | | width         | `string \| number` | Column width | -| resizeable     | `boolean` | Determines whether column width can be changed. Applied only if numeric `width` is set and `onResize` function is passed. | +| resizeable     | `boolean` | Determines whether column width can be changed. Applied only if `onResize` function is passed. | | resizeMinWidth | `number` | Min column width for resize. | | resizeMaxWidth | `number` | Max column width for resize. | | align | `DataTable.LEFT DataTable.CENTER DataTable.RIGHT` | Text alignment in a cell | diff --git a/src/lib/DataTable.scss b/src/lib/DataTable.scss index 6cd8fdf..ef6ec50 100644 --- a/src/lib/DataTable.scss +++ b/src/lib/DataTable.scss @@ -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); @@ -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); diff --git a/src/lib/DataTable.tsx b/src/lib/DataTable.tsx index 00acb94..21168a7 100644 --- a/src/lib/DataTable.tsx +++ b/src/lib/DataTable.tsx @@ -122,19 +122,19 @@ class TableRow extends React.PureComponent> { 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}; - } + const style = { + ...column.customStyle({ + row, + index, + name: column.name, + header: false, + footer, + headerData, + }), + // Fixed cell width for proper content wrap + width: column.width, + maxWidth: column.width, + }; return ( extends React.Component> { 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}; - } - - // We set proper resizeable property in DataTableView getColumn method - // check column.resizeable should be sufficient - // However, it doesn't imply proper types - // So additional conditions to not add additional logic into ResizeHandler - const withResizeHandler = resizeable && onResize && typeof width === 'number'; + const style = { + ...column.customStyle?.({header: true, name}), + // Fixed cell width for proper content wrap + width, + maxWidth: width, + }; return ( extends React.Component> { {header} {} - {withResizeHandler && ( + {resizeable && ( @@ -325,6 +320,12 @@ class TableHead extends React.Component> { this.renderedColumns[index] = node; }; }; + _getRenderedColumn = (index?: number) => { + if (index) { + return this.renderedColumns[index]; + } + return undefined; + }; } interface StickyHeadProps { @@ -1143,10 +1144,7 @@ class DataTableView extends React.Component, DataTableViewS const {sortAccessor, onClick} = column; const _className = b('td', {align}, column.className); - const resizeable = - (column.resizeable ?? settings.defaultResizeable) && - typeof column.width === 'number' && - Boolean(onResize); + const resizeable = (column.resizeable ?? settings.defaultResizeable) && Boolean(onResize); const _getValue = typeof accessor === 'function' diff --git a/src/lib/ResizeHandler.tsx b/src/lib/ResizeHandler.tsx index 972f1f6..726e641 100644 --- a/src/lib/ResizeHandler.tsx +++ b/src/lib/ResizeHandler.tsx @@ -3,16 +3,18 @@ import React from 'react'; import {b, calculateColumnWidth, rafThrottle} from './util'; interface ResizeHandlerProps { + getColumn: (index?: number) => HTMLTableCellElement | undefined; + columnIndex?: number; columnId: string; - initialWidth: number; maxWidth?: number; minWidth?: number; - onResize: (columnId: string, width: number) => void; + onResize?: (columnId: string, width: number) => void; } export function ResizeHandler({ + getColumn, + columnIndex, columnId, - initialWidth, minWidth, maxWidth, onResize, @@ -28,14 +30,14 @@ export function ResizeHandler({ return undefined; } - let mouseXPosition: number | null = null; - let initialColumnWidth = initialWidth; - let currentColumnWidth = initialWidth; + let mouseXPosition: number | undefined; + let initialColumnWidth: number | undefined; + let currentColumnWidth: number | undefined; const onMouseMove = rafThrottle((e: MouseEvent) => { restrictMouseEvent(e); - if (typeof mouseXPosition !== 'number') { + if (typeof mouseXPosition !== 'number' || typeof initialColumnWidth !== 'number') { return; } @@ -48,22 +50,27 @@ export function ResizeHandler({ } currentColumnWidth = newWidth; - onResize(columnId, currentColumnWidth); + + onResize?.(columnId, currentColumnWidth); }); const onMouseUp = (e: MouseEvent) => { restrictMouseEvent(e); - onResize(columnId, currentColumnWidth); - initialColumnWidth = currentColumnWidth; + if (currentColumnWidth !== undefined) { + onResize?.(columnId, currentColumnWidth); + } setResizing(false); + mouseXPosition = undefined; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }; const onMouseDown = (e: MouseEvent) => { + initialColumnWidth = getColumn(columnIndex)?.getBoundingClientRect().width; + restrictMouseEvent(e); mouseXPosition = e.clientX; @@ -81,7 +88,7 @@ export function ResizeHandler({ document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }; - }, [columnId, onResize, minWidth, maxWidth]); + }, [columnId, onResize, minWidth, maxWidth, getColumn, columnIndex]); return ( any>(fn: Fn) { }; } -// 30px minWidth so sort icon won't overlap wrapped column title -export function calculateColumnWidth(newWidth: number, minWidth = 30, maxWidth = Infinity) { +// 40px minWidth so sort icon won't overlap wrapped column title +export function calculateColumnWidth(newWidth: number, minWidth = 40, maxWidth = Infinity) { return Math.max(minWidth, Math.min(newWidth, maxWidth)); } diff --git a/src/stories/Resizeable/Resizeable.tsx b/src/stories/Resizeable/Resizeable.tsx index 621284d..4f57054 100644 --- a/src/stories/Resizeable/Resizeable.tsx +++ b/src/stories/Resizeable/Resizeable.tsx @@ -39,15 +39,12 @@ type RowType = typeof data[number]; const columns: Column[] = [ { name: 'number', - width: 100, }, { name: 'col1', - width: 100, }, { name: 'col2', - width: 100, }, { name: 'string', @@ -90,7 +87,6 @@ const columns: Column[] = [ { name: 'sub3-1', accessor: 'something1', - width: 100, }, ], }, @@ -98,7 +94,6 @@ const columns: Column[] = [ }, { name: 'something2', - width: 100, }, ], },