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

Move drag handle outside the cell #3334

Merged
merged 12 commits into from
Sep 6, 2023
2 changes: 0 additions & 2 deletions src/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ function Cell<R, SR>({
isDraggedOver,
row,
rowIdx,
dragHandle,
onClick,
onDoubleClick,
onContextMenu,
Expand Down Expand Up @@ -112,7 +111,6 @@ function Cell<R, SR>({
tabIndex: childTabIndex,
onRowChange: handleRowChange
})}
{dragHandle}
</div>
);
}
Expand Down
12 changes: 9 additions & 3 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -799,13 +799,18 @@ function DataGrid<R, SR, K extends Key>(
return isDraggedOver ? selectedPosition.idx : undefined;
}

function getDragHandle(rowIdx: number) {
if (selectedPosition.rowIdx !== rowIdx || selectedPosition.mode === 'EDIT' || onFill == null) {
function renderDragHandle() {
if (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check whether the selected cell is not in a summary row?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isCellWithinViewportBounds would return false for header and summary rows. There is another function isCellWithinSelectionBounds that can be used to check header and summary rows as well

onFill == null ||
selectedPosition.mode === 'EDIT' ||
!isCellWithinViewportBounds(selectedPosition)
) {
return;
}

return (
<DragHandle
gridRowStart={headerAndTopSummaryRowsCount + selectedPosition.rowIdx + 1}
rows={rows}
columns={columns}
selectedPosition={selectedPosition}
Expand Down Expand Up @@ -952,7 +957,6 @@ function DataGrid<R, SR, K extends Key>(
lastFrozenColumnIndex,
onRowChange: handleFormatterRowChangeLatest,
selectCell: selectCellLatest,
selectedCellDragHandle: getDragHandle(rowIdx),
selectedCellEditor: getCellEditor(rowIdx)
})
);
Expand Down Expand Up @@ -1121,6 +1125,8 @@ function DataGrid<R, SR, K extends Key>(
</RowSelectionChangeProvider>
</DataGridDefaultRenderersProvider>

{renderDragHandle()}

{/* render empty cells that span only 1 column so we can safely measure column widths, regardless of colSpan */}
{renderMeasuringCells(viewportColumns)}

Expand Down
44 changes: 33 additions & 11 deletions src/DragHandle.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
import { css } from '@linaria/core';
import clsx from 'clsx';

import { getCellStyle } from './utils';
import type { CalculatedColumn, FillEvent, Position } from './types';
import type { DataGridProps, SelectCellState } from './DataGrid';

const cellDragHandle = css`
@layer rdg.DragHandle {
--rdg-drag-handle-size: 8px;
z-index: 0;
cursor: move;
position: absolute;
inset-inline-end: 0;
inset-block-end: 0;
inline-size: 8px;
block-size: 8px;
inline-size: var(--rdg-drag-handle-size);
block-size: var(--rdg-drag-handle-size);
background-color: var(--rdg-selection-color);
place-self: end;

&:hover {
inline-size: 16px;
block-size: 16px;
--rdg-drag-handle-size: 16px;
border: 2px solid var(--rdg-selection-color);
background-color: var(--rdg-background-color);
}
}
`;

const cellDragHandleFrozenClassname = css`
@layer rdg.DragHandle {
z-index: 1;
position: sticky;
}
`;

const cellDragHandleClassname = `rdg-cell-drag-handle ${cellDragHandle}`;

interface Props<R, SR> extends Pick<DataGridProps<R, SR>, 'rows' | 'onRowsChange'> {
gridRowStart: number;
columns: readonly CalculatedColumn<R, SR>[];
selectedPosition: SelectCellState;
latestDraggedOverRowIdx: React.MutableRefObject<number | undefined>;
Expand All @@ -35,6 +44,7 @@ interface Props<R, SR> extends Pick<DataGridProps<R, SR>, 'rows' | 'onRowsChange
}

export default function DragHandle<R, SR>({
gridRowStart,
rows,
columns,
selectedPosition,
Expand All @@ -45,6 +55,9 @@ export default function DragHandle<R, SR>({
setDragging,
setDraggedOverRowIdx
}: Props<R, SR>) {
const { idx, rowIdx } = selectedPosition;
const column = columns[idx];

function handleMouseDown(event: React.MouseEvent<HTMLDivElement>) {
if (event.buttons !== 1) return;
setDragging(true);
Expand All @@ -70,7 +83,6 @@ export default function DragHandle<R, SR>({
const overRowIdx = latestDraggedOverRowIdx.current;
if (overRowIdx === undefined) return;

const { rowIdx } = selectedPosition;
const startRowIndex = rowIdx < overRowIdx ? rowIdx + 1 : overRowIdx;
const endRowIndex = rowIdx < overRowIdx ? overRowIdx + 1 : rowIdx;
updateRows(startRowIndex, endRowIndex);
Expand All @@ -79,11 +91,10 @@ export default function DragHandle<R, SR>({

function handleDoubleClick(event: React.MouseEvent<HTMLDivElement>) {
event.stopPropagation();
updateRows(selectedPosition.rowIdx + 1, rows.length);
updateRows(rowIdx + 1, rows.length);
}

function updateRows(startRowIdx: number, endRowIdx: number) {
const { idx, rowIdx } = selectedPosition;
const column = columns[idx];
const sourceRow = rows[rowIdx];
const updatedRows = [...rows];
Expand All @@ -103,9 +114,20 @@ export default function DragHandle<R, SR>({
}
}

const colSpan = column.colSpan?.({ type: 'ROW', row: rows[rowIdx] }) ?? 1;
const style = getCellStyle(column, colSpan);

return (
<div
className={cellDragHandleClassname}
style={{
...style,
gridRowStart,
insetInlineStart:
style.insetInlineStart && typeof column.width === 'number'
? `calc(${style.insetInlineStart} + ${column.width}px - var(--rdg-drag-handle-size))`
: undefined
}}
className={clsx(cellDragHandleClassname, column.frozen && cellDragHandleFrozenClassname)}
onMouseDown={handleMouseDown}
onDoubleClick={handleDoubleClick}
/>
Expand Down
2 changes: 0 additions & 2 deletions src/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ function Row<R, SR>(
row,
viewportColumns,
selectedCellEditor,
selectedCellDragHandle,
onCellClick,
onCellDoubleClick,
onCellContextMenu,
Expand Down Expand Up @@ -78,7 +77,6 @@ function Row<R, SR>(
isCopied={copiedCellIdx === idx}
isDraggedOver={draggedOverCellIdx === idx}
isCellSelected={isCellSelected}
dragHandle={isCellSelected ? selectedCellDragHandle : undefined}
onClick={onCellClick}
onDoubleClick={onCellDoubleClick}
onContextMenu={onCellContextMenu}
Expand Down
4 changes: 1 addition & 3 deletions src/TreeDataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,6 @@ function TreeDataGrid<R, SR, K extends Key>(
draggedOverCellIdx,
setDraggedOverRowIdx,
selectedCellEditor,
selectedCellDragHandle,
...rowProps
}: RenderRowProps<R, SR>
) {
Expand Down Expand Up @@ -402,8 +401,7 @@ function TreeDataGrid<R, SR, K extends Key>(
copiedCellIdx,
draggedOverCellIdx,
setDraggedOverRowIdx,
selectedCellEditor,
selectedCellDragHandle
selectedCellEditor
});
}

Expand Down
2 changes: 0 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ export interface CellRendererProps<TRow, TSummaryRow>
isCopied: boolean;
isDraggedOver: boolean;
isCellSelected: boolean;
dragHandle: ReactElement<React.HTMLAttributes<HTMLDivElement>> | undefined;
onClick: RenderRowProps<TRow, TSummaryRow>['onCellClick'];
onDoubleClick: RenderRowProps<TRow, TSummaryRow>['onCellDoubleClick'];
onContextMenu: RenderRowProps<TRow, TSummaryRow>['onCellContextMenu'];
Expand Down Expand Up @@ -213,7 +212,6 @@ export interface RenderRowProps<TRow, TSummaryRow = unknown>
copiedCellIdx: number | undefined;
draggedOverCellIdx: number | undefined;
selectedCellEditor: ReactElement<RenderEditCellProps<TRow>> | undefined;
selectedCellDragHandle: ReactElement<React.HTMLAttributes<HTMLDivElement>> | undefined;
onRowChange: (column: CalculatedColumn<TRow, TSummaryRow>, rowIdx: number, newRow: TRow) => void;
rowClass: Maybe<(row: TRow, rowIdx: number) => Maybe<string>>;
setDraggedOverRowIdx: ((overRowIdx: number) => void) | undefined;
Expand Down