diff --git a/src/HeaderCell.tsx b/src/HeaderCell.tsx index 720701795f..03cfbfe617 100644 --- a/src/HeaderCell.tsx +++ b/src/HeaderCell.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useRef, useState } from 'react'; import { css } from '@linaria/core'; import { useRovingTabIndex } from './hooks'; @@ -87,7 +87,6 @@ export default function HeaderCell({ }: HeaderCellProps) { const [isDragging, setIsDragging] = useState(false); const [isOver, setIsOver] = useState(false); - const isRtl = direction === 'rtl'; const rowSpan = getHeaderCellRowSpan(column, rowIdx); const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellSelected); const sortIndex = sortColumns?.findIndex((sort) => sort.columnKey === column.key); @@ -107,43 +106,6 @@ export default function HeaderCell({ [cellOverClassname]: isOver }); - function onPointerDown(event: React.PointerEvent) { - if (event.pointerType === 'mouse' && event.buttons !== 1) { - return; - } - - // Fix column resizing on a draggable column in FF - event.preventDefault(); - - const { currentTarget, pointerId } = event; - const headerCell = currentTarget.parentElement!; - const { right, left } = headerCell.getBoundingClientRect(); - const offset = isRtl ? event.clientX - left : right - event.clientX; - function onPointerMove(event: PointerEvent) { - const { width, right, left } = headerCell.getBoundingClientRect(); - let newWidth = isRtl ? right + offset - event.clientX : event.clientX + offset - left; - newWidth = clampColumnWidth(newWidth, column); - if (width > 0 && newWidth !== width) { - onColumnResize(column, newWidth); - } - } - - function onLostPointerCapture() { - currentTarget.removeEventListener('pointermove', onPointerMove); - currentTarget.removeEventListener('lostpointercapture', onLostPointerCapture); - } - - currentTarget.setPointerCapture(pointerId); - currentTarget.addEventListener('pointermove', onPointerMove); - // we are not using pointerup because it does not fire in some cases - // pointer down -> alt+tab -> pointer up over another window -> pointerup event not fired - currentTarget.addEventListener('lostpointercapture', onLostPointerCapture); - } - - function onDoubleClick() { - onColumnResize(column, 'max-content'); - } - function onSort(ctrlClick: boolean) { if (onSortColumnsChange == null) return; const { sortDescendingFirst } = column; @@ -291,17 +253,69 @@ export default function HeaderCell({ })} {resizable && ( -
+ )}
); } +type ResizeHandleProps = Pick< + HeaderCellProps, + 'column' | 'onColumnResize' | 'direction' +>; + +function ResizeHandle({ column, onColumnResize, direction }: ResizeHandleProps) { + const resizingOffsetRef = useRef(undefined); + const isRtl = direction === 'rtl'; + + function onPointerDown(event: React.PointerEvent) { + if (event.pointerType === 'mouse' && event.buttons !== 1) { + return; + } + + // Fix column resizing on a draggable column in FF + event.preventDefault(); + + const { currentTarget, pointerId } = event; + currentTarget.setPointerCapture(pointerId); + const headerCell = currentTarget.parentElement!; + const { right, left } = headerCell.getBoundingClientRect(); + resizingOffsetRef.current = isRtl ? event.clientX - left : right - event.clientX; + } + + function onPointerMove(event: React.PointerEvent) { + const offset = resizingOffsetRef.current; + if (offset === undefined) return; + const { width, right, left } = event.currentTarget.parentElement!.getBoundingClientRect(); + let newWidth = isRtl ? right + offset - event.clientX : event.clientX + offset - left; + newWidth = clampColumnWidth(newWidth, column); + if (width > 0 && newWidth !== width) { + onColumnResize(column, newWidth); + } + } + + function onLostPointerCapture() { + resizingOffsetRef.current = undefined; + } + + function onDoubleClick() { + onColumnResize(column, 'max-content'); + } + + return ( +
alt+tab -> pointer up over another window -> pointerup event not fired + onLostPointerCapture={onLostPointerCapture} + onDoubleClick={onDoubleClick} + /> + ); +} + // only accept pertinent drag events: // - ignore drag events going from the container to an element inside the container // - ignore drag events going from an element inside the container to the container diff --git a/src/hooks/useCalculatedColumns.ts b/src/hooks/useCalculatedColumns.ts index 2ba770396d..0bbc33d0c9 100644 --- a/src/hooks/useCalculatedColumns.ts +++ b/src/hooks/useCalculatedColumns.ts @@ -5,7 +5,7 @@ import type { CalculatedColumn, CalculatedColumnParent, ColumnOrColumnGroup, Omi import { renderValue } from '../cellRenderers'; import { SELECT_COLUMN_KEY } from '../Columns'; import type { DataGridProps } from '../DataGrid'; -import defaultRenderHeaderCell from '../renderHeaderCell'; +import renderHeaderCell from '../renderHeaderCell'; type Mutable = { -readonly [P in keyof T]: T[P] extends ReadonlyArray ? Mutable[] : T[P]; @@ -48,9 +48,8 @@ export function useCalculatedColumns({ const defaultWidth = defaultColumnOptions?.width ?? DEFAULT_COLUMN_WIDTH; const defaultMinWidth = defaultColumnOptions?.minWidth ?? DEFAULT_COLUMN_MIN_WIDTH; const defaultMaxWidth = defaultColumnOptions?.maxWidth ?? undefined; - const defaultCellRenderer = defaultColumnOptions?.renderCell ?? renderValue; - const defaultHeaderCellRenderer = - defaultColumnOptions?.renderHeaderCell ?? defaultRenderHeaderCell; + const defaultRenderCell = defaultColumnOptions?.renderCell ?? renderValue; + const defaultRenderHeaderCell = defaultColumnOptions?.renderHeaderCell ?? renderHeaderCell; const defaultSortable = defaultColumnOptions?.sortable ?? false; const defaultResizable = defaultColumnOptions?.resizable ?? false; const defaultDraggable = defaultColumnOptions?.draggable ?? false; @@ -101,8 +100,8 @@ export function useCalculatedColumns({ sortable: rawColumn.sortable ?? defaultSortable, resizable: rawColumn.resizable ?? defaultResizable, draggable: rawColumn.draggable ?? defaultDraggable, - renderCell: rawColumn.renderCell ?? defaultCellRenderer, - renderHeaderCell: rawColumn.renderHeaderCell ?? defaultHeaderCellRenderer + renderCell: rawColumn.renderCell ?? defaultRenderCell, + renderHeaderCell: rawColumn.renderHeaderCell ?? defaultRenderHeaderCell }; columns.push(column); @@ -156,8 +155,8 @@ export function useCalculatedColumns({ defaultWidth, defaultMinWidth, defaultMaxWidth, - defaultCellRenderer, - defaultHeaderCellRenderer, + defaultRenderCell, + defaultRenderHeaderCell, defaultResizable, defaultSortable, defaultDraggable