Skip to content

Commit

Permalink
fix: disable vertical auto-scroll of table on attribute drag (#1383)
Browse files Browse the repository at this point in the history
  • Loading branch information
kswenson authored Jul 31, 2024
1 parent 1465ac1 commit b80596b
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 34 deletions.
80 changes: 77 additions & 3 deletions v3/patches/@dnd-kit+core+6.1.0.patch
Original file line number Diff line number Diff line change
@@ -1,11 +1,60 @@
diff --git a/node_modules/@dnd-kit/core/dist/core.cjs.development.js b/node_modules/@dnd-kit/core/dist/core.cjs.development.js
index c07336f..8a241b0 100644
--- a/node_modules/@dnd-kit/core/dist/core.cjs.development.js
+++ b/node_modules/@dnd-kit/core/dist/core.cjs.development.js
@@ -1790,10 +1790,6 @@ function useAutoScroller(_ref) {
}

for (const scrollContainer of sortedScrollableAncestors) {
- if ((canScroll == null ? void 0 : canScroll(scrollContainer)) === false) {
- continue;
- }
-
const index = scrollableAncestors.indexOf(scrollContainer);
const scrollContainerRect = scrollableAncestorRects[index];

@@ -1806,6 +1802,10 @@ function useAutoScroller(_ref) {
speed
} = getScrollDirectionAndSpeed(scrollContainer, scrollContainerRect, rect, acceleration, threshold);

+ if ((canScroll == null ? void 0 : canScroll(scrollContainer, direction)) === false) {
+ continue;
+ }
+
for (const axis of ['x', 'y']) {
if (!scrollIntent[axis][direction[axis]]) {
speed[axis] = 0;
diff --git a/node_modules/@dnd-kit/core/dist/core.esm.js b/node_modules/@dnd-kit/core/dist/core.esm.js
index ed699d9..4538723 100644
index ed699d9..6aa2da3 100644
--- a/node_modules/@dnd-kit/core/dist/core.esm.js
+++ b/node_modules/@dnd-kit/core/dist/core.esm.js
@@ -2354,17 +2354,10 @@ function useRects(elements, measure) {
@@ -1789,10 +1789,6 @@ function useAutoScroller(_ref) {
}

for (const scrollContainer of sortedScrollableAncestors) {
- if ((canScroll == null ? void 0 : canScroll(scrollContainer)) === false) {
- continue;
- }
-
const index = scrollableAncestors.indexOf(scrollContainer);
const scrollContainerRect = scrollableAncestorRects[index];

@@ -1805,6 +1801,10 @@ function useAutoScroller(_ref) {
speed
} = getScrollDirectionAndSpeed(scrollContainer, scrollContainerRect, rect, acceleration, threshold);

+ if ((canScroll == null ? void 0 : canScroll(scrollContainer, direction)) === false) {
+ continue;
+ }
+
for (const axis of ['x', 'y']) {
if (!scrollIntent[axis][direction[axis]]) {
speed[axis] = 0;
@@ -2353,18 +2353,10 @@ function useRects(elements, measure) {
const resizeObserver = useResizeObserver({
callback: measureRects
});
-
- if (elements.length > 0 && rects === defaultValue$2) {
- measureRects();
- }
Expand All @@ -23,3 +72,28 @@ index ed699d9..4538723 100644
}, [elements]);
return rects;

diff --git a/node_modules/@dnd-kit/core/dist/hooks/utilities/useAutoScroller.d.ts b/node_modules/@dnd-kit/core/dist/hooks/utilities/useAutoScroller.d.ts
index 3159f04..01f66e3 100644
--- a/node_modules/@dnd-kit/core/dist/hooks/utilities/useAutoScroller.d.ts
+++ b/node_modules/@dnd-kit/core/dist/hooks/utilities/useAutoScroller.d.ts
@@ -1,3 +1,4 @@
+import { Direction } from '../../types';
import type { Coordinates, ClientRect } from '../../types';
export declare type ScrollAncestorSortingFn = (ancestors: Element[]) => Element[];
export declare enum AutoScrollActivator {
@@ -28,10 +29,14 @@ interface Arguments extends Options {
scrollableAncestorRects: ClientRect[];
delta: Coordinates;
}
-export declare type CanScroll = (element: Element) => boolean;
+export declare type CanScroll = (element: Element, direction: ScrollDirection) => boolean;
export declare enum TraversalOrder {
TreeOrder = 0,
ReversedTreeOrder = 1
}
+interface ScrollDirection {
+ x: 0 | Direction;
+ y: 0 | Direction;
+}
export declare function useAutoScroller({ acceleration, activator, canScroll, draggingRect, enabled, interval, order, pointerCoordinates, scrollableAncestors, scrollableAncestorRects, delta, threshold, }: Arguments): void;
export {};
2 changes: 1 addition & 1 deletion v3/src/components/app.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { observer } from "mobx-react-lite"
import React, { useCallback, useEffect } from "react"
import { CodapDndContext } from "./codap-dnd-context"
import { CodapDndContext } from "../lib/dnd-kit/codap-dnd-context"
import { Container } from "./container/container"
import { ToolShelf } from "./tool-shelf/tool-shelf"
import { kCodapAppElementId } from "./constants"
Expand Down
2 changes: 1 addition & 1 deletion v3/src/components/case-card/case-card-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useDataSet } from "../../hooks/use-data-set"
import { DataSetContext } from "../../hooks/use-data-set-context"
import { useTileDropOverlay } from "../../hooks/use-drag-drop"
import { InstanceIdContext, useNextInstanceId } from "../../hooks/use-instance-id-context"
import { registerTileCollisionDetection } from "../dnd-detect-collision"
import { registerTileCollisionDetection } from "../../lib/dnd-kit/dnd-detect-collision"
import { ITileBaseProps } from "../tiles/tile-base-props"
import { CaseCard } from "./case-card"
import { ICaseCardModel, isCaseCardModel } from "./case-card-model"
Expand Down
2 changes: 1 addition & 1 deletion v3/src/components/case-table/case-table-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useDataSet } from "../../hooks/use-data-set"
import { DataSetContext } from "../../hooks/use-data-set-context"
import { useTileDropOverlay } from "../../hooks/use-drag-drop"
import { InstanceIdContext, useNextInstanceId } from "../../hooks/use-instance-id-context"
import { registerTileCollisionDetection } from "../dnd-detect-collision"
import { registerTileCollisionDetection } from "../../lib/dnd-kit/dnd-detect-collision"
import { ITileBaseProps } from "../tiles/tile-base-props"
import { CaseTable } from "./case-table"
import { caseTableCollisionDetection } from "./case-table-drag-drop"
Expand Down
51 changes: 26 additions & 25 deletions v3/src/components/case-table/case-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useSyncScrolling } from "./use-sync-scrolling"
import { CollectionContext, ParentCollectionContext } from "../../hooks/use-collection-context"
import { useDataSetContext } from "../../hooks/use-data-set-context"
import { useInstanceIdContext } from "../../hooks/use-instance-id-context"
import { registerCanAutoScrollCallback } from "../../lib/dnd-kit/dnd-can-auto-scroll"
import { ICollectionModel } from "../../models/data/collection"
import { IDataSet } from "../../models/data/data-set"
import { createCollectionNotification, deleteCollectionNotification } from "../../models/data/data-set-notifications"
Expand All @@ -27,13 +28,15 @@ export const CaseTable = observer(function CaseTable({ setNodeRef }: IProps) {
const instanceId = useInstanceIdContext() || "case-table"
const data = useDataSetContext()
const tableModel = useCaseTableModel()
const contentRef = useRef<HTMLDivElement | null>(null)
const contentRef = useRef<HTMLDivElement>(null)
const lastNewCollectionDrop = useRef<{ newCollectionId: string, beforeCollectionId: string } | undefined>()

function setTableRef(elt: HTMLDivElement | null) {
contentRef.current = elt?.querySelector((".case-table-content")) ?? null
setNodeRef(elt)
}
useEffect(() => {
// disable vertical auto-scroll of table (column headers can't scroll out of view)
return registerCanAutoScrollCallback((element, direction) => {
return element !== contentRef.current || direction.y === 0
})
}, [])

useEffect(() => {
const updateScroll = (horizontalScrollOffset?: number) => {
Expand Down Expand Up @@ -114,27 +117,25 @@ export const CaseTable = observer(function CaseTable({ setNodeRef }: IProps) {
}

return (
<>
<div ref={setTableRef} className="case-table" data-testid="case-table">
<div className="case-table-content" onScroll={handleHorizontalScroll}>
{collections.map((collection, i) => {
const key = collection.id
const parent = i > 0 ? collections[i - 1] : undefined
return (
<ParentCollectionContext.Provider key={key} value={parent?.id}>
<CollectionContext.Provider value={collection.id}>
<CollectionTable onMount={handleCollectionTableMount}
onNewCollectionDrop={handleNewCollectionDrop} onTableScroll={handleTableScroll}
onScrollClosestRowIntoView={handleScrollClosestRowIntoView} />
</CollectionContext.Provider>
</ParentCollectionContext.Provider>
)
})}
<AttributeDragOverlay activeDragId={overlayDragId} />
<NoCasesMessage />
</div>
<div ref={setNodeRef} className="case-table" data-testid="case-table">
<div className="case-table-content" ref={contentRef} onScroll={handleHorizontalScroll}>
{collections.map((collection, i) => {
const key = collection.id
const parent = i > 0 ? collections[i - 1] : undefined
return (
<ParentCollectionContext.Provider key={key} value={parent?.id}>
<CollectionContext.Provider value={collection.id}>
<CollectionTable onMount={handleCollectionTableMount}
onNewCollectionDrop={handleNewCollectionDrop} onTableScroll={handleTableScroll}
onScrollClosestRowIntoView={handleScrollClosestRowIntoView} />
</CollectionContext.Provider>
</ParentCollectionContext.Provider>
)
})}
<AttributeDragOverlay activeDragId={overlayDragId} />
<NoCasesMessage />
</div>
</>
</div>
)
})
})
Expand Down
10 changes: 9 additions & 1 deletion v3/src/components/case-table/collection-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useDataSetContext } from "../../hooks/use-data-set-context"
import { useTileDroppable } from "../../hooks/use-drag-drop"
import { useForceUpdate } from "../../hooks/use-force-update"
import { useVisibleAttributes } from "../../hooks/use-visible-attributes"
import { registerCanAutoScrollCallback } from "../../lib/dnd-kit/dnd-can-auto-scroll"
import { IAttribute } from "../../models/data/attribute"
import { IDataSet } from "../../models/data/data-set"
import { createAttributesNotification } from "../../models/data/data-set-notifications"
Expand Down Expand Up @@ -55,13 +56,20 @@ export const CollectionTable = observer(function CollectionTable(props: IProps)
const forceUpdate = useForceUpdate()

useEffect(function setGridElement() {
const element = gridRef.current?.element ?? undefined
const element = gridRef.current?.element
if (element && collectionTableModel) {
collectionTableModel.setElement(element)
onMount(collectionId)
}
}, [collectionId, collectionTableModel, gridRef.current?.element, onMount])

useEffect(() => {
return registerCanAutoScrollCallback((element) => {
// prevent auto-scroll on grid since there's nothing droppable in the grid
return element !== gridRef.current?.element
})
}, [])

// columns
const indexColumn = useIndexColumn()
const columns = useColumns({ data, indexColumn })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import {
MouseSensor, PointerSensor, TraversalOrder, useSensor, useSensors
} from "@dnd-kit/core"
import React, { ReactNode } from "react"
import { containerSnapToGridModifier } from "../hooks/use-drag-drop"
import { urlParams } from "../utilities/url-params"
import { containerSnapToGridModifier } from "../../hooks/use-drag-drop"
import { urlParams } from "../../utilities/url-params"
import { canAutoScroll } from "./dnd-can-auto-scroll"
import { dndDetectCollision } from "./dnd-detect-collision"

interface IProps {
Expand All @@ -15,6 +16,10 @@ export const CodapDndContext = ({ children }: IProps) => {
// Note that as of this writing, the auto-scroll options are not documented in the official docs,
// but they are described in this PR: https://github.com/clauderic/dnd-kit/pull/140.
const autoScrollOptions: AutoScrollOptions = {
canScroll: (element, direction) => {
// allow clients to intercede in auto-scroll determination via client-provided callbacks
return canAutoScroll(element, direction)
},
// scroll components before scrolling the document
order: TraversalOrder.ReversedTreeOrder,
// reduce the auto-scroll area to 5% (default is 20%)
Expand Down
32 changes: 32 additions & 0 deletions v3/src/lib/dnd-kit/dnd-can-auto-scroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { CanScroll } from "@dnd-kit/core/dist/hooks/utilities/useAutoScroller"
import { uniqueId } from "../../utilities/js-utils"

const canAutoScrollRegistry = new Map<string, CanScroll>()

/**
* Allows clients (e.g. tiles) to register a callback that can prevent auto-scroll
* on particular elements (pre-existing behavior of DnDKit's `canScroll` property)
* and depending on the direction of scroll (requires extension of DnDKit's
* `canScroll` callback function to provide direction information).
*
* @param canScroll callback function that determines whether the scroll is allowed
* @returns disposer for the callback
*/
export function registerCanAutoScrollCallback(canScroll: CanScroll) {
const id = uniqueId()
canAutoScrollRegistry.set(id, canScroll)
// returns disposer so clients can unregister the callback
return () => { canAutoScrollRegistry.delete(id) }
}

/**
* Designed to be called by DnDKit's `canScroll` callback in its auto-scroll configuration.
*
* @param element element being considered for auto-scroll
* @param direction direction of scroll
* @returns false if autoscroll should be prevented for the specified element & direction
*/
export const canAutoScroll: CanScroll = (element, direction) => {
// prevent auto-scroll if any handler returns false
return !Array.from(canAutoScrollRegistry.values()).some(canScroll => canScroll(element, direction) === false)
}
File renamed without changes.

0 comments on commit b80596b

Please sign in to comment.