Skip to content

Commit

Permalink
Prevent default refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
clauderic committed Jun 3, 2024
1 parent fb2c395 commit 69039eb
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 75 deletions.
2 changes: 0 additions & 2 deletions apps/docs/stories/react/Sortable/SortableExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ function SortableItem({
disabled,
dragHandle,
feedback,
optimistic,
transition,
style,
}: PropsWithChildren<SortableProps>) {
Expand All @@ -119,7 +118,6 @@ function SortableItem({
element,
feedback,
transition,
optimistic,
handle: handleRef,
disabled,
collisionDetector,
Expand Down
58 changes: 33 additions & 25 deletions packages/abstract/src/core/manager/dragOperation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
} from '../entities/index.js';

import type {DragDropManager} from './manager.js';
import {defaultPreventable} from './events.js';

export enum Status {
Idle = 'idle',
Expand Down Expand Up @@ -217,9 +218,12 @@ export function DragOperationManager<

targetIdentifier.value = id;

monitor.dispatch('dragover', {
operation: snapshot(operation),
});
monitor.dispatch(
'dragover',
defaultPreventable({
operation: snapshot(operation),
})
);

return manager.renderer.rendering;
},
Expand All @@ -230,15 +234,27 @@ export function DragOperationManager<
position.reset(coordinates);
});

monitor.dispatch('beforedragstart', {operation: snapshot(operation)});
const beforeStartEvent = defaultPreventable({
operation: snapshot(operation),
});

monitor.dispatch('beforedragstart', beforeStartEvent);

manager.renderer.rendering.then(() => {
if (beforeStartEvent.defaultPrevented) {
reset();
return;
}

status.value = Status.Initializing;

requestAnimationFrame(() => {
status.value = Status.Dragging;

monitor.dispatch('dragstart', {operation: snapshot(operation)});
monitor.dispatch('dragstart', {
operation: snapshot(operation),
cancelable: false,
});
});
});
},
Expand All @@ -253,27 +269,19 @@ export function DragOperationManager<
return;
}

let defaultPrevented = false;

monitor.dispatch('dragmove', {
operation: snapshot(operation),
by,
to,
cancelable,
get defaultPrevented() {
return defaultPrevented;
const event = defaultPreventable(
{
operation: snapshot(operation),
by,
to,
},
preventDefault() {
if (!cancelable) {
return;
}
cancelable
);

defaultPrevented = true;
},
});
monitor.dispatch('dragmove', event);

queueMicrotask(() => {
if (defaultPrevented) {
if (event.defaultPrevented) {
return;
}

Expand All @@ -285,7 +293,7 @@ export function DragOperationManager<
position.update(coordinates);
});
},
stop({canceled: isCanceled = false}: {canceled?: boolean} = {}) {
stop({canceled: eventCanceled = false}: {canceled?: boolean} = {}) {
let promise: Promise<void> | undefined;
const suspend = () => {
const output = {
Expand All @@ -308,11 +316,11 @@ export function DragOperationManager<
});
};

canceled.value = isCanceled;
canceled.value = eventCanceled;

monitor.dispatch('dragend', {
operation: snapshot(operation),
canceled: isCanceled,
canceled: eventCanceled,
suspend,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import type {DragOperation} from './dragOperation.js';

export type Events = Record<string, (...args: any[]) => void>;

export type Preventable<T> = T & {
cancelable: boolean;
defaultPrevented: boolean;
preventDefault(): void;
};

class Monitor<T extends Events> {
private registry = new Map<keyof T, Set<T[keyof T]>>();

Expand Down Expand Up @@ -48,32 +54,36 @@ export type DragDropEvents<
V extends DragDropManager<T, U>,
> = {
collision(
event: {
event: Preventable<{
collisions: Collisions;
defaultPrevented: boolean;
preventDefault(): void;
},
}>,
manager: V
): void;
beforedragstart(
event: Preventable<{operation: DragOperation<T, U>}>,
manager: V
): void;
beforedragstart(event: {operation: DragOperation<T, U>}, manager: V): void;
dragstart(
event: {
cancelable: false;
operation: DragOperation<T, U>;
},
manager: V
): void;
dragmove(
event: {
event: Preventable<{
operation: DragOperation<T, U>;
to?: Coordinates;
by?: Coordinates;
cancelable: boolean;
defaultPrevented: boolean;
preventDefault(): void;
},
}>,
manager: V
): void;
dragover(
event: Preventable<{
operation: DragOperation<T, U>;
}>,
manager: V
): void;
dragover(event: {operation: DragOperation<T, U>}, manager: V): void;
dragend(
event: {
operation: DragOperation<T, U>;
Expand Down Expand Up @@ -102,3 +112,25 @@ export class DragDropMonitor<
super.dispatch(type, ...args);
}
}

export function defaultPreventable<T>(
event: T,
cancelable = true
): Preventable<T> {
let defaultPrevented = false;

return {
...event,
cancelable,
get defaultPrevented() {
return defaultPrevented;
},
preventDefault() {
if (!cancelable) {
return;
}

defaultPrevented = true;
},
};
}
2 changes: 1 addition & 1 deletion packages/abstract/src/core/manager/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export {DragDropManager} from './manager.js';
export type {DragDropManagerInput, DragDropConfiguration} from './manager.js';
export type {DragDropEvents} from './monitor.js';
export type {DragDropEvents} from './events.js';
export {Status as DragOperationStatus} from './dragOperation.js';
export type {DragOperation, DragOperationManager} from './dragOperation.js';
export type {DragDropRegistry} from './registry.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/abstract/src/core/manager/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
type DragOperation,
type DragActions,
} from './dragOperation.js';
import {DragDropMonitor} from './monitor.js';
import {DragDropMonitor} from './events.js';
import {defaultRenderer, type Renderer} from './renderer.js';

export interface DragDropConfiguration<T extends DragDropManager> {
Expand Down
1 change: 0 additions & 1 deletion packages/dom/src/core/plugins/feedback/Feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ export class Feedback extends Plugin<DragDropManager> {
resizeObserver.disconnect();

styles.reset();
placeholder.replaceWith(element);
placeholder.remove();
element.removeAttribute(ATTRIBUTE);

Expand Down
8 changes: 2 additions & 6 deletions packages/dom/src/sortable/OptimisticSortingPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ export class OptimisticSortingPlugin extends Plugin<DragDropManager> {
};

const unsubscribe = [
manager.monitor.addEventListener('dragover', (_, manager) => {
manager.monitor.addEventListener('dragover', (event, manager) => {
queueMicrotask(() => {
if (this.disabled) {
if (this.disabled || event.defaultPrevented) {
return;
}

Expand All @@ -52,10 +52,6 @@ export class OptimisticSortingPlugin extends Plugin<DragDropManager> {
return;
}

if (!source.sortable.optimistic || !target.sortable.optimistic) {
return;
}

if (source.sortable.group !== target.sortable.group) {
return;
}
Expand Down
54 changes: 31 additions & 23 deletions packages/dom/src/sortable/sortable.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {batch, effects, reactive, untracked, type Effect} from '@dnd-kit/state';
import {CollisionPriority} from '@dnd-kit/abstract';
import type {Data, Type, UniqueIdentifier} from '@dnd-kit/abstract';
import type {
Data,
PluginConstructor,
Type,
UniqueIdentifier,
} from '@dnd-kit/abstract';
import {
defaultCollisionDetection,
type CollisionDetector,
Expand Down Expand Up @@ -38,6 +43,11 @@ export interface SortableTransition {
idle?: boolean;
}

const defaultPlugins: PluginConstructor[] = [
SortableKeyboardPlugin,
OptimisticSortingPlugin,
];

export interface SortableInput<T extends Data>
extends Omit<DraggableInput<T>, 'effects'>,
Omit<DroppableInput<T>, 'effects'> {
Expand All @@ -49,10 +59,6 @@ export interface SortableInput<T extends Data>
* The optional unique identifier of the group that the sortable item belongs to.
*/
group?: UniqueIdentifier;
/**
* Whether to optimistically update the position of the sortable item while dragging.
*/
optimistic?: boolean;
/**
* The transition configuration to use when the index of the sortable item changes.
*/
Expand All @@ -61,6 +67,11 @@ export interface SortableInput<T extends Data>
* Additional effects to set up when sortable item is instantiated.
*/
effects?: (instance: Sortable<T>) => Effect[];
/**
* Plugins to register when sortable item is instantiated.
* @default [SortableKeyboardPlugin, OptimisticSortingPlugin]
*/
plugins?: PluginConstructor[];
}

export const defaultSortableTransition: SortableTransition = {
Expand All @@ -76,26 +87,33 @@ export class Sortable<T extends Data = Data> {
@reactive
index: number;

previousIndex: number;

initialIndex: number;

@reactive
group: UniqueIdentifier | undefined;

transition: SortableTransition | null;
@reactive
element: Element | undefined;

optimistic: boolean;
@reactive
source: Element | undefined;

previousIndex: number;
@reactive
target: Element | undefined;

initialIndex: number;
transition: SortableTransition | null;

constructor(
{
effects: inputEffects,
group,
index,
optimistic = true,
sensors,
type,
transition = defaultSortableTransition,
plugins = defaultPlugins,
...input
}: SortableInput<T>,
public manager: DragDropManager<any, any>
Expand All @@ -107,16 +125,15 @@ export class Sortable<T extends Data = Data> {
);
this.droppable = new SortableDroppable<T>(input, manager, this);

// TO-DO: Can this be done conditionally if consumers want to use their own plugin?
manager.registry.register(SortableKeyboardPlugin);
manager.registry.register(OptimisticSortingPlugin);
for (const plugin of plugins) {
manager.registry.register(plugin);
}

this.index = index;
this.previousIndex = index;
this.initialIndex = index;
this.group = group;
this.type = type;
this.optimistic = optimistic;
this.transition = transition;

const {destroy} = this;
Expand Down Expand Up @@ -252,15 +269,6 @@ export class Sortable<T extends Data = Data> {
this.draggable.handle = handle;
}

@reactive
element: Element | undefined;

@reactive
source: Element | undefined;

@reactive
target: Element | undefined;

public set id(id: UniqueIdentifier) {
batch(() => {
this.draggable.id = id;
Expand Down
Loading

0 comments on commit 69039eb

Please sign in to comment.