diff --git a/src/components/Table/GridTable.tsx b/src/components/Table/GridTable.tsx index ae5cbad8d..7bc44385c 100644 --- a/src/components/Table/GridTable.tsx +++ b/src/components/Table/GridTable.tsx @@ -245,6 +245,13 @@ export function GridTable = an [props.api], ); + const [draggedRow, _setDraggedRow] = useState | undefined>(undefined); + const draggedRowRef = useRef(draggedRow); + const setDraggedRow = (row: GridDataRow | undefined) => { + draggedRowRef.current = row; + _setDraggedRow(row); + }; + const style = resolveStyles(maybeStyle); const { tableState } = api; @@ -293,14 +300,24 @@ export function GridTable = an return clientY > rect.top + pt + ((rect.height - pb) / 2); } + // allows us to unset children and grandchildren, etc. + function recursiveSetDraggedOver(rows: GridDataRow[], draggedOver: DraggedOver) { + rows.forEach((r) => { + tableState.maybeSetRowDraggedOver(r.id, draggedOver); + if(r.children) { + recursiveSetDraggedOver(r.children, draggedOver); + } + }); + } + function onDragStart (row: GridDataRow, evt: DragEventType) { if(!row.draggable || !droppedCallback) { return; } evt.dataTransfer.effectAllowed = "move"; - evt.dataTransfer.dropEffect = "move"; evt.dataTransfer.setData("text/plain", JSON.stringify({ row })); + setDraggedRow(row); }; const onDragEnd = (row: GridDataRow, evt: DragEventType) => { @@ -310,9 +327,7 @@ export function GridTable = an evt.preventDefault(); evt.dataTransfer.clearData(); - rows.forEach((r) => { - tableState.setRowDraggedOver(r.id, DraggedOver.None); - }); + recursiveSetDraggedOver(rows, DraggedOver.None); }; const onDrop = (row: GridDataRow, evt: DragEventType) => { @@ -323,9 +338,8 @@ export function GridTable = an evt.preventDefault(); evt.dataTransfer.clearData(); if (droppedCallback) { - rows.forEach((r) => {r - tableState.setRowDraggedOver(r.id, DraggedOver.None); - }); + recursiveSetDraggedOver(rows, DraggedOver.None); + try { const draggedRowData = JSON.parse(evt.dataTransfer.getData("text/plain")).row; @@ -349,15 +363,21 @@ export function GridTable = an evt.preventDefault(); + evt.cancelable + // set flags for css spacer - rows.forEach((r) => {r - tableState.setRowDraggedOver(r.id, DraggedOver.None); - }); + recursiveSetDraggedOver(rows, DraggedOver.None); - // determine above or below - const isBelow = isCursorBelowMidpoint(evt.currentTarget, evt.clientY); + if(draggedRowRef.current) { + + if(draggedRowRef.current.id === row.id) { + return; + } - tableState.setRowDraggedOver(row.id, isBelow ? DraggedOver.Below : DraggedOver.Above); + // determine above or below + const isBelow = isCursorBelowMidpoint(evt.currentTarget, evt.clientY); + tableState.maybeSetRowDraggedOver(row.id, isBelow ? DraggedOver.Below : DraggedOver.Above, draggedRowRef.current); + } }; const onDragOver = (row: GridDataRow, evt: DragEventType) => { @@ -367,9 +387,15 @@ export function GridTable = an evt.preventDefault(); - const isBelow = isCursorBelowMidpoint(evt.currentTarget, evt.clientY); - - tableState.setRowDraggedOver(row.id, isBelow ? DraggedOver.Below : DraggedOver.Above); + if(draggedRowRef.current) { + if(draggedRowRef.current.id === row.id) { + return; + } + + // continuously determine above or below + const isBelow = isCursorBelowMidpoint(evt.currentTarget, evt.clientY); + tableState.maybeSetRowDraggedOver(row.id, isBelow ? DraggedOver.Below : DraggedOver.Above, draggedRowRef.current); + } }; // Flatten, hide-if-filtered, hide-if-collapsed, and component-ize the sorted rows. @@ -391,7 +417,6 @@ export function GridTable = an // Get the flat list or rows from the header down... visibleRows.forEach((rs) => { - const row = ( (props: RowProps): ReactElement { } = props; const { tableState } = useContext(TableStateContext); - const { sm } = useBreakpoint(); // We're wrapped in observer, so can access these without useComputeds const { api, visibleColumns: columns } = tableState; const { row, api: rowApi, isActive, isKept: isKeptRow, isLastKeptRow, level } = rs; @@ -120,8 +118,8 @@ function RowImpl(props: RowProps): ReactElement { [`:hover > .${revealOnRowHoverClass} > *`]: Css.visible.$, }, ...(isLastKeptRow && Css.addIn("&>*", style.keptLastRowCss).$), - ...(rs.isDraggedOver === DraggedOver.Above && Css.add("paddingTop", "50px").$), - ...(rs.isDraggedOver === DraggedOver.Below && Css.add("paddingBottom", "50px").$), + ...(rs.isDraggedOver === DraggedOver.Above && Css.add("paddingTop", "35px").$), + ...(rs.isDraggedOver === DraggedOver.Below && Css.add("paddingBottom", "35px").$), }; let currentColspan = 1; diff --git a/src/components/Table/utils/RowStates.ts b/src/components/Table/utils/RowStates.ts index 5bd8fe129..e33118706 100644 --- a/src/components/Table/utils/RowStates.ts +++ b/src/components/Table/utils/RowStates.ts @@ -178,8 +178,26 @@ export class RowStates { return rs; } - setRowDraggedOver(id: string, draggedOver: DraggedOver): void { + maybeSetRowDraggedOver(id: string, draggedOver: DraggedOver, requireSameParentRow: GridDataRow | undefined = undefined): void { const rs = this.get(id); + + if(requireSameParentRow) { + const requireParentRowState = this.get(requireSameParentRow.id); + if(requireParentRowState.parent?.row?.id !== rs.parent?.row?.id) return; + } + + // if this is an expanded parent and draggedOver is Below then we want to set this on this rows bottom-most child + if(!rs.collapsed && rs.children && rs.children?.length > 0 && draggedOver === DraggedOver.Below) { + let rowState = rs; + // recursively find the bottom-most child + while(rowState.children && rowState.children?.length > 0) { + rowState = rowState.children[rowState.children.length - 1]; + } + + rowState.isDraggedOver = draggedOver; + return; + } + // this allows a single-row re-render rs.isDraggedOver = draggedOver; } diff --git a/src/components/Table/utils/TableState.ts b/src/components/Table/utils/TableState.ts index daea6d9bb..f6e078288 100644 --- a/src/components/Table/utils/TableState.ts +++ b/src/components/Table/utils/TableState.ts @@ -253,11 +253,8 @@ export class TableState { this.rowStates.delete(ids); } - setRowDraggedOver(id: string, draggedOver: DraggedOver): void { - // if we do rowStates.setRows here all of the rows will re-render - - // this.rows[index] can be undefined here? - this.rowStates.setRowDraggedOver(id, draggedOver); + maybeSetRowDraggedOver(id: string, draggedOver: DraggedOver, requireSameParentRow: GridDataRow | undefined = undefined): void { + this.rowStates.maybeSetRowDraggedOver(id, draggedOver, requireSameParentRow); } }