Skip to content

Commit

Permalink
Allow sortable element to be distinct
Browse files Browse the repository at this point in the history
  • Loading branch information
clauderic committed Sep 12, 2024
1 parent a5933d8 commit 8053e4b
Show file tree
Hide file tree
Showing 10 changed files with 56 additions and 32 deletions.
2 changes: 1 addition & 1 deletion .changeset/batch-sortable.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
'@dnd-kit/sortable': patch
'@dnd-kit/dom': patch
---

Batch write operations to `draggable` and `droppable`. Also ensured that droppable instance is registered before draggable instance.
5 changes: 5 additions & 0 deletions .changeset/distinct-sortable-element.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@dnd-kit/dom': patch
---

Allow `Sortable` to have a distinct `element` from the underlying `source` and `target` elements. This can be useful if you want the collision detection to operate on a subset of the sortable element, but the entirety of the element to move when its index changes.
2 changes: 1 addition & 1 deletion .changeset/fix-idle-transitions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
'@dnd-kit/sortable': patch
'@dnd-kit/dom': patch
---

Fix an issue where we would update the shape of sortable items while the drag operation status was idle.
6 changes: 2 additions & 4 deletions packages/dom/src/sortable/OptimisticSortingPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,7 @@ export class OptimisticSortingPlugin extends Plugin<DragDropManager> {
targetIndex
);

const sourceElement =
source.sortable.droppable.internal.element.peek() ??
source.sortable.droppable.placeholder;
const sourceElement = source.sortable.element;
const targetElement = target.element;

if (!targetElement || !sourceElement) {
Expand Down Expand Up @@ -131,7 +129,7 @@ export class OptimisticSortingPlugin extends Plugin<DragDropManager> {
sortableInstances.values()
).sort((a, b) => a.index - b.index);

const sourceElement = source.sortable.droppable.element;
const sourceElement = source.sortable.element;
const targetElement =
orderedSortables[source.sortable.initialIndex]?.element;

Expand Down
12 changes: 5 additions & 7 deletions packages/dom/src/sortable/SortableKeyboardPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {effect} from '@dnd-kit/state';
import {Plugin} from '@dnd-kit/abstract';
import {closestCorners} from '@dnd-kit/collision';
import {
DOMRectangle,
isKeyboardEvent,
scheduler,
scrollIntoViewIfNeeded,
Expand Down Expand Up @@ -128,21 +129,18 @@ export class SortableKeyboardPlugin extends Plugin<DragDropManager> {
actions.setDropTarget(id).then(() => {
const {source} = dragOperation;

if (!source) {
if (!source || !isSortable(source)) {
return;
}

const droppable = registry.droppables.get(source.id);
const {element} = source.sortable;

if (!droppable?.element) {
return;
}
if (!element) return;

const {element} = droppable;
scrollIntoViewIfNeeded(element);

scheduler.schedule(() => {
const shape = droppable.refreshShape();
const shape = new DOMRectangle(element);

if (!shape) {
return;
Expand Down
1 change: 1 addition & 0 deletions packages/dom/src/sortable/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export {Sortable, defaultSortableTransition} from './sortable.ts';
export type {SortableInput, SortableTransition} from './sortable.ts';
export {isSortable} from './utilities.ts';
50 changes: 33 additions & 17 deletions packages/dom/src/sortable/sortable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
animateTransform,
computeTranslate,
scheduler,
ProxiedElements,
} from '@dnd-kit/dom/utilities';

import {SortableKeyboardPlugin} from './SortableKeyboardPlugin.ts';
Expand Down Expand Up @@ -114,6 +115,8 @@ export class Sortable<T extends Data = Data> {
}: SortableInput<T>,
manager: DragDropManager<any, any> | undefined
) {
let previousGroup = group;

this.droppable = new SortableDroppable<T>(input, manager, this);
this.draggable = new SortableDraggable<T>(
{
Expand All @@ -125,7 +128,13 @@ export class Sortable<T extends Data = Data> {
this.previousIndex = this.index;
}),
() => {
const {index, previousIndex, manager: _} = this;
const {index, group, previousIndex, manager: _} = this;

if (group !== previousGroup) {
previousGroup = group;
this.previousIndex = index;
return;
}

// Re-run this effect whenever the index changes
if (index === previousIndex) {
Expand Down Expand Up @@ -234,13 +243,32 @@ export class Sortable<T extends Data = Data> {
});
}

#element: Element | undefined;

public set element(element: Element | undefined) {
this.draggable.element = element;
batch(() => {
const previousElement = this.#element;
const droppableElement = this.droppable.element;
const draggableElement = this.draggable.element;

if (!droppableElement || droppableElement === previousElement) {
this.droppable.element = element;
}

if (!draggableElement || draggableElement === previousElement) {
this.draggable.element = element;
}

this.#element = element;
});
}

public get element() {
return this.droppable.element ?? this.draggable.element;
const element = this.#element;

if (!element) return;

return ProxiedElements.get(element) ?? element ?? this.droppable.element;
}

public set target(target: Element | undefined) {
Expand Down Expand Up @@ -342,8 +370,8 @@ export class Sortable<T extends Data = Data> {
return this.draggable.status;
}

public refreshShape(ignoreTransforms: boolean = false) {
return this.droppable.refreshShape(ignoreTransforms);
public refreshShape() {
return this.droppable.refreshShape();
}

public accepts(draggable: Draggable): boolean {
Expand Down Expand Up @@ -382,10 +410,6 @@ export class SortableDraggable<T extends Data> extends Draggable<T> {
) {
super(input, manager);
}

public get index() {
return this.sortable.index;
}
}

export class SortableDroppable<T extends Data> extends Droppable<T> {
Expand All @@ -396,12 +420,4 @@ export class SortableDroppable<T extends Data> extends Droppable<T> {
) {
super(input, manager);
}

public refreshShape(ignoreTransforms = false) {
return super.refreshShape(ignoreTransforms);
}

public get index() {
return this.sortable.index;
}
}
2 changes: 1 addition & 1 deletion packages/dom/src/utilities/element/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {cloneElement} from './cloneElement.ts';
export {createPlaceholder} from './createPlaceholder.ts';
export {ProxiedElements} from './proxiedElements.ts';
1 change: 1 addition & 0 deletions packages/dom/src/utilities/element/proxiedElements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ProxiedElements = new WeakMap<Element, Element>();
7 changes: 6 additions & 1 deletion packages/dom/src/utilities/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
export {
getBoundingRectangle,
getViewportBoundingRectangle,
PositionObserver,
} from './bounding-rectangle/index.ts';

export {canUseDOM, getDocument, getWindow} from './execution-context/index.ts';

export {cloneElement, createPlaceholder} from './element/index.ts';
export {
cloneElement,
createPlaceholder,
ProxiedElements,
} from './element/index.ts';

export {Listeners} from './event-listeners/index.ts';

Expand Down

0 comments on commit 8053e4b

Please sign in to comment.