diff --git a/src/HeaderCell.tsx b/src/HeaderCell.tsx index 72c8c923a5..bba993e0e7 100644 --- a/src/HeaderCell.tsx +++ b/src/HeaderCell.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react'; import { css } from '@linaria/core'; import { useRovingTabIndex } from './hooks'; @@ -6,6 +7,12 @@ import type { CalculatedColumn, SortColumn } from './types'; import type { HeaderRowProps } from './HeaderRow'; import defaultRenderHeaderCell from './renderHeaderCell'; +const cellSortableClassname = css` + @layer rdg.HeaderCell { + cursor: pointer; + } +`; + const cellResizable = css` @layer rdg.HeaderCell { touch-action: none; @@ -51,6 +58,8 @@ export default function HeaderCell({ shouldFocusGrid, direction }: HeaderCellProps) { + const ignoreClickRef = useRef(false); + const isRtl = direction === 'rtl'; const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellSelected); const sortIndex = sortColumns?.findIndex((sort) => sort.columnKey === column.key); @@ -62,28 +71,36 @@ export default function HeaderCell({ sortDirection && !priority ? (sortDirection === 'ASC' ? 'ascending' : 'descending') : undefined; const className = getCellClassname(column, column.headerCellClass, { + [cellSortableClassname]: column.sortable, [cellResizableClassname]: column.resizable }); const renderHeaderCell = column.renderHeaderCell ?? defaultRenderHeaderCell; + function getPointerOffset(event: React.MouseEvent) { + const { right, left } = event.currentTarget.getBoundingClientRect(); + return isRtl ? event.clientX - left : right - event.clientX; + } + function onPointerDown(event: React.PointerEvent) { if (event.pointerType === 'mouse' && event.buttons !== 1) { return; } - const { currentTarget, pointerId } = event; - const { right, left } = currentTarget.getBoundingClientRect(); - const offset = isRtl ? event.clientX - left : right - event.clientX; + const offset = getPointerOffset(event); if (offset > 11) { // +1px to account for the border size return; } + // prevent selecting/sorting if we started resizing the column, including double-clicking + ignoreClickRef.current = true; + function onPointerMove(event: PointerEvent) { // prevents text selection in Chrome, which fixes scrolling the grid while dragging, and fixes re-size on an autosized column event.preventDefault(); + const { right, left } = currentTarget.getBoundingClientRect(); const width = isRtl ? right + offset - event.clientX : event.clientX + offset - left; if (width > 0) { @@ -92,10 +109,12 @@ export default function HeaderCell({ } function onLostPointerCapture() { + ignoreClickRef.current = false; currentTarget.removeEventListener('pointermove', onPointerMove); currentTarget.removeEventListener('lostpointercapture', onLostPointerCapture); } + const { currentTarget, pointerId } = event; currentTarget.setPointerCapture(pointerId); currentTarget.addEventListener('pointermove', onPointerMove); currentTarget.addEventListener('lostpointercapture', onLostPointerCapture); @@ -138,15 +157,18 @@ export default function HeaderCell({ } } - function onClick() { + function onClick(event: React.MouseEvent) { + if (ignoreClickRef.current) return; + selectCell(column.idx); + + if (column.sortable) { + onSort(event.ctrlKey || event.metaKey); + } } function onDoubleClick(event: React.MouseEvent) { - const { right, left } = event.currentTarget.getBoundingClientRect(); - const offset = isRtl ? event.clientX - left : right - event.clientX; - - if (offset > 11) { + if (getPointerOffset(event) > 11) { // +1px to account for the border size return; } @@ -162,6 +184,14 @@ export default function HeaderCell({ } } + function onKeyDown(event: React.KeyboardEvent) { + if (event.key === ' ' || event.key === 'Enter') { + // prevent scrolling + event.preventDefault(); + onSort(event.ctrlKey || event.metaKey); + } + } + return (
({ onClick={onClick} onDoubleClick={column.resizable ? onDoubleClick : undefined} onPointerDown={column.resizable ? onPointerDown : undefined} + onKeyDown={column.sortable ? onKeyDown : undefined} > {renderHeaderCell({ column, sortDirection, priority, - onSort, tabIndex: childTabIndex })}
diff --git a/src/renderHeaderCell.tsx b/src/renderHeaderCell.tsx index 9ff375f7fc..1338a932d3 100644 --- a/src/renderHeaderCell.tsx +++ b/src/renderHeaderCell.tsx @@ -3,23 +3,15 @@ import { css } from '@linaria/core'; import type { RenderHeaderCellProps } from './types'; import { useDefaultRenderers } from './DataGridDefaultRenderersProvider'; -const headerSortCell = css` +const headerSortCellClassname = css` @layer rdg.SortableHeaderCell { - cursor: pointer; display: flex; - - &:focus { - outline: none; - } } `; -const headerSortCellClassname = `rdg-header-sort-cell ${headerSortCell}`; - const headerSortName = css` @layer rdg.SortableHeaderCellName { flex-grow: 1; - overflow: hidden; overflow: clip; text-overflow: ellipsis; } @@ -30,19 +22,12 @@ const headerSortNameClassname = `rdg-header-sort-name ${headerSortName}`; export default function renderHeaderCell({ column, sortDirection, - priority, - onSort, - tabIndex + priority }: RenderHeaderCellProps) { if (!column.sortable) return column.name; return ( - + {column.name} ); @@ -50,7 +35,7 @@ export default function renderHeaderCell({ type SharedHeaderCellProps = Pick< RenderHeaderCellProps, - 'sortDirection' | 'onSort' | 'priority' | 'tabIndex' + 'sortDirection' | 'priority' >; interface SortableHeaderCellProps extends SharedHeaderCellProps { @@ -58,33 +43,14 @@ interface SortableHeaderCellProps extends SharedHeaderCellProps { } function SortableHeaderCell({ - onSort, sortDirection, priority, - children, - tabIndex + children }: SortableHeaderCellProps) { const renderSortStatus = useDefaultRenderers()!.renderSortStatus!; - function handleKeyDown(event: React.KeyboardEvent) { - if (event.key === ' ' || event.key === 'Enter') { - // stop propagation to prevent scrolling - event.preventDefault(); - onSort(event.ctrlKey || event.metaKey); - } - } - - function handleClick(event: React.MouseEvent) { - onSort(event.ctrlKey || event.metaKey); - } - return ( - + {children} {renderSortStatus({ sortDirection, priority })} diff --git a/src/style/cell.ts b/src/style/cell.ts index 5066d10e4c..2ca2a81463 100644 --- a/src/style/cell.ts +++ b/src/style/cell.ts @@ -17,7 +17,6 @@ export const cell = css` background-color: inherit; white-space: nowrap; - overflow: hidden; overflow: clip; text-overflow: ellipsis; outline: none; diff --git a/src/types.ts b/src/types.ts index f3b52c2f38..5152c23307 100644 --- a/src/types.ts +++ b/src/types.ts @@ -111,7 +111,6 @@ export interface RenderHeaderCellProps { sortDirection: SortDirection | undefined; priority: number | undefined; tabIndex: number; - onSort: (ctrlClick: boolean) => void; } export interface CellRendererProps diff --git a/website/root.tsx b/website/root.tsx index f9a9b7db97..0bcd99420c 100644 --- a/website/root.tsx +++ b/website/root.tsx @@ -33,7 +33,7 @@ const mainClassname = css` box-sizing: border-box; block-size: 100vh; padding: 8px; - overflow: hidden; + overflow: clip; `; function Root() {