Skip to content
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
104 changes: 59 additions & 45 deletions src/HeaderCell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useRef, useState } from 'react';
import { css } from '@linaria/core';

import { useRovingTabIndex } from './hooks';
Expand Down Expand Up @@ -87,7 +87,6 @@ export default function HeaderCell<R, SR>({
}: HeaderCellProps<R, SR>) {
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);
Expand All @@ -107,43 +106,6 @@ export default function HeaderCell<R, SR>({
[cellOverClassname]: isOver
});

function onPointerDown(event: React.PointerEvent<HTMLDivElement>) {
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;
Expand Down Expand Up @@ -291,17 +253,69 @@ export default function HeaderCell<R, SR>({
})}

{resizable && (
<div
className={resizeHandleClassname}
onClick={stopPropagation}
onPointerDown={onPointerDown}
onDoubleClick={onDoubleClick}
/>
<ResizeHandle column={column} onColumnResize={onColumnResize} direction={direction} />
)}
</div>
);
}

type ResizeHandleProps<R, SR> = Pick<
HeaderCellProps<R, SR>,
'column' | 'onColumnResize' | 'direction'
>;

function ResizeHandle<R, SR>({ column, onColumnResize, direction }: ResizeHandleProps<R, SR>) {
const resizingOffsetRef = useRef<number>(undefined);
const isRtl = direction === 'rtl';

function onPointerDown(event: React.PointerEvent<HTMLDivElement>) {
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<HTMLDivElement>) {
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 (
<div
className={resizeHandleClassname}
onClick={stopPropagation}
onPointerDown={onPointerDown}
onPointerMove={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
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
Expand Down
15 changes: 7 additions & 8 deletions src/hooks/useCalculatedColumns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = {
-readonly [P in keyof T]: T[P] extends ReadonlyArray<infer V> ? Mutable<V>[] : T[P];
Expand Down Expand Up @@ -48,9 +48,8 @@ export function useCalculatedColumns<R, SR>({
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;
Expand Down Expand Up @@ -101,8 +100,8 @@ export function useCalculatedColumns<R, SR>({
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);
Expand Down Expand Up @@ -156,8 +155,8 @@ export function useCalculatedColumns<R, SR>({
defaultWidth,
defaultMinWidth,
defaultMaxWidth,
defaultCellRenderer,
defaultHeaderCellRenderer,
defaultRenderCell,
defaultRenderHeaderCell,
defaultResizable,
defaultSortable,
defaultDraggable
Expand Down
Loading