Skip to content

Commit

Permalink
Latest
Browse files Browse the repository at this point in the history
  • Loading branch information
clauderic committed Jul 28, 2023
1 parent d1be64f commit 12de769
Show file tree
Hide file tree
Showing 19 changed files with 354 additions and 162 deletions.
3 changes: 3 additions & 0 deletions packages/abstract/src/manager/dragOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {DragDropMonitor} from './manager';

export enum Status {
Idle = 'idle',
Initializing = 'initializing',
Dragging = 'dragging',
Dropping = 'dropped',
}
Expand Down Expand Up @@ -99,6 +100,8 @@ export function DragOperationManager<
targetIdentifier.value = identifier;
},
start(coordinates: Coordinates) {
status.value = Status.Initializing;

batch(() => {
status.value = Status.Dragging;
position.reset(coordinates);
Expand Down
2 changes: 1 addition & 1 deletion packages/abstract/src/manager/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class Registry<T> {
private pubSub = new PubSub();

public [Symbol.iterator]() {
return this.map.value.values();
return this.map.peek().values();
}

public get(identifier: UniqueIdentifier): T | undefined {
Expand Down
16 changes: 14 additions & 2 deletions packages/abstract/src/plugins/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import type {DragDropManager} from '../manager';

export abstract class Plugin<
export class Plugin<
T extends DragDropManager<any, any> = DragDropManager<any, any>,
> {
constructor(protected manager: T) {
this.manager = manager;
}

public abstract destroy(): void;
public disabled: boolean = false;

public enable() {
this.disabled = false;
}

public disable() {
this.disabled = true;
}

public destroy() {
// no-op
}
}
3 changes: 2 additions & 1 deletion packages/dom-utilities/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ export {cloneElement} from './element';
export {Listeners} from './event-listeners';

export {
canScroll,
shouldScroll,
getScrollableAncestors,
getScrollDirectionAndSpeed,
isDocumentScrollingElement,
ScrollDirection,
} from './scroll';
Expand Down
24 changes: 24 additions & 0 deletions packages/dom-utilities/src/scroll/canScroll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type {Coordinates} from '@dnd-kit/geometry';

import {getScrollPosition} from './getScrollPosition';

export function canScroll(scrollableElement: Element, by?: Coordinates) {
const {isTop, isBottom, isLeft, isRight, position} =
getScrollPosition(scrollableElement);

const {x, y} = by ?? {x: 0, y: 0};

const top = !isTop && position.current.y + y > 0;
const bottom = !isBottom && position.current.y + y < position.max.y;
const left = !isLeft && position.current.x + x > 0;
const right = !isRight && position.current.x + x < position.max.x;

return {
top,
bottom,
left,
right,
x: left || right,
y: top || bottom,
};
}
44 changes: 27 additions & 17 deletions packages/dom-utilities/src/scroll/getScrollPosition.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
import {isDocumentScrollingElement} from './documentScrollingElement';
import {
getViewportBoundingRectangle,
getBoundingRectangle,
} from '../bounding-rectangle';

export function getScrollPosition(scrollingContainer: Element) {
const minScroll = {
x: 0,
y: 0,
};
const dimensions = isDocumentScrollingElement(scrollingContainer)
export function getScrollPosition(scrollableElement: Element) {
const rect = isDocumentScrollingElement(scrollableElement)
? getViewportBoundingRectangle(scrollableElement)
: getBoundingRectangle(scrollableElement);

const dimensions = isDocumentScrollingElement(scrollableElement)
? {
height: window.innerHeight,
width: window.innerWidth,
}
: {
height: scrollingContainer.clientHeight,
width: scrollingContainer.clientWidth,
height: scrollableElement.clientHeight,
width: scrollableElement.clientWidth,
};
const maxScroll = {
x: scrollingContainer.scrollWidth - dimensions.width,
y: scrollingContainer.scrollHeight - dimensions.height,
const position = {
current: {
x: scrollableElement.scrollLeft,
y: scrollableElement.scrollTop,
},
max: {
x: scrollableElement.scrollWidth - dimensions.width,
y: scrollableElement.scrollHeight - dimensions.height,
},
};

const isTop = scrollingContainer.scrollTop <= minScroll.y;
const isLeft = scrollingContainer.scrollLeft <= minScroll.x;
const isBottom = scrollingContainer.scrollTop >= maxScroll.y;
const isRight = scrollingContainer.scrollLeft >= maxScroll.x;
const isTop = position.current.y <= 0;
const isLeft = position.current.x <= 0;
const isBottom = position.current.y >= position.max.y;
const isRight = position.current.x >= position.max.x;

return {
rect,
position,
isTop,
isLeft,
isBottom,
isRight,
maxScroll,
minScroll,
};
}
6 changes: 2 additions & 4 deletions packages/dom-utilities/src/scroll/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
export {canScroll} from './canScroll';
export {
getFirstScrollableAncestor,
getScrollableAncestors,
} from './getScrollableAncestors';
export {getScrollableElement} from './getScrollableElement';
export {getScrollCoordinates} from './getScrollCoordinates';
export {
getScrollDirectionAndSpeed,
ScrollDirection,
} from './getScrollDirectionAndSpeed';
export {shouldScroll, ScrollDirection} from './shouldScroll';
export {
getScrollOffsets,
getScrollXOffset,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {Axis, BoundingRectangle} from '@dnd-kit/geometry';
import type {Axis, BoundingRectangle, Coordinates} from '@dnd-kit/geometry';

import {getScrollPosition} from './getScrollPosition';

Expand All @@ -13,15 +13,19 @@ const defaultThreshold: Record<Axis, number> = {
y: 0.2,
};

export function getScrollDirectionAndSpeed(
scrollContainer: Element,
scrollContainerRect: BoundingRectangle,
rect: BoundingRectangle,
export function shouldScroll(
scrollableElement: Element,
coordinates: Coordinates,
acceleration = 10,
thresholdPercentage = defaultThreshold
) {
const {top, left, bottom, right} = rect;
const {isTop, isBottom, isLeft, isRight} = getScrollPosition(scrollContainer);
const {
rect: scrollContainerRect,
isTop,
isBottom,
isLeft,
isRight,
} = getScrollPosition(scrollableElement);

const direction: Record<Axis, ScrollDirection> = {
x: ScrollDirection.Idle,
Expand All @@ -36,43 +40,52 @@ export function getScrollDirectionAndSpeed(
width: scrollContainerRect.width * thresholdPercentage.x,
};

if (!isTop && top <= scrollContainerRect.top + threshold.height) {
if (!isTop && coordinates.y <= scrollContainerRect.top + threshold.height) {
// Scroll Up
direction.y = ScrollDirection.Reverse;
speed.y =
acceleration *
Math.abs(
(scrollContainerRect.top + threshold.height - top) / threshold.height
(scrollContainerRect.top + threshold.height - coordinates.y) /
threshold.height
);
} else if (
!isBottom &&
bottom >= scrollContainerRect.bottom - threshold.height
coordinates.y >= scrollContainerRect.bottom - threshold.height
) {
// Scroll Down
direction.y = ScrollDirection.Forward;
speed.y =
acceleration *
Math.abs(
(scrollContainerRect.bottom - threshold.height - bottom) /
(scrollContainerRect.bottom - threshold.height - coordinates.y) /
threshold.height
);
}

if (!isRight && right >= scrollContainerRect.right - threshold.width) {
if (
!isRight &&
coordinates.x >= scrollContainerRect.right - threshold.width
) {
// Scroll Right
direction.x = ScrollDirection.Forward;
speed.x =
acceleration *
Math.abs(
(scrollContainerRect.right - threshold.width - right) / threshold.width
(scrollContainerRect.right - threshold.width - coordinates.x) /
threshold.width
);
} else if (!isLeft && left <= scrollContainerRect.left + threshold.width) {
} else if (
!isLeft &&
coordinates.x <= scrollContainerRect.left + threshold.width
) {
// Scroll Left
direction.x = ScrollDirection.Reverse;
speed.x =
acceleration *
Math.abs(
(scrollContainerRect.left + threshold.width - left) / threshold.width
(scrollContainerRect.left + threshold.width - coordinates.x) /
threshold.width
);
}

Expand Down
37 changes: 31 additions & 6 deletions packages/dom/src/manager/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import {
PluginConstructor,
SensorConstructor,
} from '@dnd-kit/abstract';
import {batch, effect} from '@dnd-kit/state';

import type {Draggable, Droppable} from '../nodes';
import {AutoScroller, DraggablePlaceholder, ScrollManager} from '../plugins';
import {
AutoScroller,
DraggablePlaceholder,
ScrollManager,
Scroller,
} from '../plugins';
import {PointerSensor} from '../sensors';

export interface Input extends DragDropManagerInput<DragDropManager> {}
Expand All @@ -22,7 +28,7 @@ export class DragDropManager<
T extends Draggable = Draggable,
U extends Droppable = Droppable,
> extends AbstractDragDropManager<Draggable, Droppable> {
public scrollManager: ScrollManager;
public scroller: Scroller;

constructor({
plugins = defaultPlugins,
Expand All @@ -31,11 +37,30 @@ export class DragDropManager<
}: Input = {}) {
super({...input, plugins, sensors});

this.scrollManager = new ScrollManager(this);
const scrollManager = new ScrollManager(this);
this.scroller = new Scroller(this);

const effectCleanup = effect(() => {
if (this.dragOperation.status === 'initializing') {
batch(() => {
for (const droppable of this.registry.droppable) {
droppable.updateShape();
}
});
}
});

const {destroy} = this;

this.destroy = () => {
effectCleanup();
scrollManager.destroy();
destroy();
};
}

public destroy() {
public destroy = () => {
super.destroy();
this.scrollManager.destroy();
}
this.scroller.destroy();
};
}
19 changes: 16 additions & 3 deletions packages/dom/src/nodes/droppable/droppable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
Data,
DroppableInput as AbstractDroppableInput,
} from '@dnd-kit/abstract';
import {Shape} from '@dnd-kit/geometry';
import {defaultCollisionDetection} from '@dnd-kit/collision';
import type {CollisionDetector} from '@dnd-kit/collision';
import {effect, reactive} from '@dnd-kit/state';
Expand All @@ -17,6 +18,7 @@ type OptionalInput = 'collisionDetector';
export interface Input<T extends Data = Data>
extends Omit<AbstractDroppableInput<T>, OptionalInput> {
collisionDetector?: CollisionDetector;
shape?: Shape;
}

export class Droppable<T extends Data = Data> extends AbstractDroppable<T> {
Expand All @@ -29,12 +31,23 @@ export class Droppable<T extends Data = Data> extends AbstractDroppable<T> {
}: Input<T>) {
super({...input, collisionDetector});

this.destroy = effect(this.update);
this.destroy = effect(this.updateShape);
}

public update = () => {
public updateShape = () => {
const {disabled, element} = this;

this.shape = element && !disabled ? new DOMRectangle(element) : null;
if (!element || disabled) {
this.shape = null;
return;
}

const updatedShape = new DOMRectangle(element);

if (this.shape?.equals(updatedShape)) {
return;
}

this.shape = updatedShape;
};
}
2 changes: 1 addition & 1 deletion packages/dom/src/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {DraggableClone, DraggablePlaceholder} from './feedback';
export {AutoScroller, ScrollManager} from './scrolling';
export {AutoScroller, Scroller, ScrollManager} from './scrolling';
Loading

0 comments on commit 12de769

Please sign in to comment.