@mk-drag-and-drop/dom 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +460 -0
- package/dist/controller/controller-internals.d.ts +5 -0
- package/dist/controller/controller-internals.js +11 -0
- package/dist/controller/create-drag-controller.d.ts +36 -0
- package/dist/controller/create-drag-controller.js +232 -0
- package/dist/draggable/create-draggable-binding.d.ts +8 -0
- package/dist/draggable/create-draggable-binding.js +52 -0
- package/dist/draggable/create-draggable.d.ts +46 -0
- package/dist/draggable/create-draggable.js +57 -0
- package/dist/droppable/create-drop-container-binding.d.ts +8 -0
- package/dist/droppable/create-drop-container-binding.js +28 -0
- package/dist/droppable/create-drop-container.d.ts +18 -0
- package/dist/droppable/create-drop-container.js +36 -0
- package/dist/droppable/create-droppable-binding.d.ts +9 -0
- package/dist/droppable/create-droppable-binding.js +29 -0
- package/dist/droppable/create-droppable.d.ts +17 -0
- package/dist/droppable/create-droppable.js +31 -0
- package/dist/geometry/measurement.d.ts +4 -0
- package/dist/geometry/measurement.js +33 -0
- package/dist/geometry/overlay.d.ts +19 -0
- package/dist/geometry/overlay.js +32 -0
- package/dist/geometry/rects.d.ts +17 -0
- package/dist/geometry/rects.js +34 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +9 -0
- package/dist/input/config.d.ts +35 -0
- package/dist/input/config.js +56 -0
- package/dist/input/create-drag-handle.d.ts +4 -0
- package/dist/input/create-drag-handle.js +4 -0
- package/dist/input/drag-handle.d.ts +10 -0
- package/dist/input/drag-handle.js +74 -0
- package/dist/input/keyboard-drag.d.ts +28 -0
- package/dist/input/keyboard-drag.js +77 -0
- package/dist/input/pointer-activation.d.ts +31 -0
- package/dist/input/pointer-activation.js +97 -0
- package/dist/integration/index.d.ts +10 -0
- package/dist/integration/index.js +6 -0
- package/dist/modifiers/built-ins.d.ts +6 -0
- package/dist/modifiers/built-ins.js +62 -0
- package/dist/modifiers/pipeline.d.ts +18 -0
- package/dist/modifiers/pipeline.js +34 -0
- package/dist/modifiers/types.d.ts +32 -0
- package/dist/modifiers/types.js +1 -0
- package/dist/runtime/drag-runtime-handle.d.ts +22 -0
- package/dist/runtime/drag-runtime-handle.js +33 -0
- package/dist/runtime/drag-runtime.d.ts +96 -0
- package/dist/runtime/drag-runtime.js +798 -0
- package/dist/runtime/drop-target-registry.d.ts +101 -0
- package/dist/runtime/drop-target-registry.js +855 -0
- package/dist/runtime/lifecycle.d.ts +44 -0
- package/dist/runtime/lifecycle.js +1 -0
- package/dist/runtime/types.d.ts +65 -0
- package/dist/runtime/types.js +1 -0
- package/dist/sortable/create-sortable-binding.d.ts +10 -0
- package/dist/sortable/create-sortable-binding.js +58 -0
- package/dist/sortable/create-sortable.d.ts +19 -0
- package/dist/sortable/create-sortable.js +55 -0
- package/dist/sortable/sortable-options.d.ts +17 -0
- package/dist/sortable/sortable-options.js +20 -0
- package/dist/sortable/sortable-preview.d.ts +79 -0
- package/dist/sortable/sortable-preview.js +357 -0
- package/dist/sortable/sortable-registry.d.ts +113 -0
- package/dist/sortable/sortable-registry.js +145 -0
- package/dist/targeting/algorithms.d.ts +6 -0
- package/dist/targeting/algorithms.js +56 -0
- package/dist/targeting/constraints.d.ts +15 -0
- package/dist/targeting/constraints.js +58 -0
- package/dist/targeting/types.d.ts +23 -0
- package/dist/targeting/types.js +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type DragPoint = {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
};
|
|
5
|
+
export type DragRect = {
|
|
6
|
+
x: number;
|
|
7
|
+
y: number;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
top: number;
|
|
11
|
+
right: number;
|
|
12
|
+
bottom: number;
|
|
13
|
+
left: number;
|
|
14
|
+
};
|
|
15
|
+
export declare const emptyDragRect: DragRect;
|
|
16
|
+
export declare function rectToDragRect(rect: DOMRectReadOnly): DragRect;
|
|
17
|
+
export declare function translateRect(rect: DragRect, deltaX: number, deltaY: number): DragRect;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const emptyDragRect = {
|
|
2
|
+
x: 0,
|
|
3
|
+
y: 0,
|
|
4
|
+
top: 0,
|
|
5
|
+
right: 0,
|
|
6
|
+
bottom: 0,
|
|
7
|
+
left: 0,
|
|
8
|
+
width: 0,
|
|
9
|
+
height: 0,
|
|
10
|
+
};
|
|
11
|
+
export function rectToDragRect(rect) {
|
|
12
|
+
return {
|
|
13
|
+
x: rect.x,
|
|
14
|
+
y: rect.y,
|
|
15
|
+
top: rect.top,
|
|
16
|
+
right: rect.right,
|
|
17
|
+
bottom: rect.bottom,
|
|
18
|
+
left: rect.left,
|
|
19
|
+
width: rect.width,
|
|
20
|
+
height: rect.height,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function translateRect(rect, deltaX, deltaY) {
|
|
24
|
+
return {
|
|
25
|
+
x: rect.x + deltaX,
|
|
26
|
+
y: rect.y + deltaY,
|
|
27
|
+
top: rect.top + deltaY,
|
|
28
|
+
right: rect.right + deltaX,
|
|
29
|
+
bottom: rect.bottom + deltaY,
|
|
30
|
+
left: rect.left + deltaX,
|
|
31
|
+
width: rect.width,
|
|
32
|
+
height: rect.height,
|
|
33
|
+
};
|
|
34
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { createDragController, type DragController, type DragControllerAnnouncements, type DragControllerOptions, type DragControllerOverlayInput, } from "./controller/create-drag-controller.js";
|
|
2
|
+
export { createDraggable, type CreateDraggableInput, } from "./draggable/create-draggable-binding.js";
|
|
3
|
+
export { createDroppable, type CreateDroppableInput, } from "./droppable/create-droppable-binding.js";
|
|
4
|
+
export { createDropContainer, type CreateDropContainerInput, } from "./droppable/create-drop-container-binding.js";
|
|
5
|
+
export { createSortable, type CreateSortableInput, } from "./sortable/create-sortable-binding.js";
|
|
6
|
+
export type { SortableAxis, SortablePlacementBoundary, } from "./sortable/sortable-options.js";
|
|
7
|
+
export { createDragHandle, type CreateDragHandleInput, } from "./input/create-drag-handle.js";
|
|
8
|
+
export type { DragEndResult, DragEndEvent, DragLifecycleCallbacks, DragLifecycleHelpers, DragSource, DragStartEvent, DragUpdateEvent, DropEvent, } from "./runtime/lifecycle.js";
|
|
9
|
+
export type { RemeasureDropTargetsInput, SortableDropPlacement, } from "./runtime/drop-target-registry.js";
|
|
10
|
+
export { centerToCenter, pointerToCenter, pointerToRectDistance, } from "./targeting/algorithms.js";
|
|
11
|
+
export { getDistanceToRect, maxOverlayCenterDistanceToRect, maxPointerDistanceToRect, } from "./targeting/constraints.js";
|
|
12
|
+
export type { DropTarget, TargetingAlgorithm, TargetingAlgorithmInput, TargetingConstraint, TargetingConstraintInput, } from "./targeting/types.js";
|
|
13
|
+
export { lockToXAxis, lockToYAxis, restrictToContainer, type RestrictToContainerResolver, } from "./modifiers/built-ins.js";
|
|
14
|
+
export type { DragModifier, DragModifierInput, DragModifierSetupInput, DragModifierTransformInput, } from "./modifiers/types.js";
|
|
15
|
+
export type { KeyboardCommand, KeyboardConfiguration, PointerConfiguration, } from "./input/config.js";
|
|
16
|
+
export type { DragPoint, DragRect } from "./geometry/rects.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createDragController, } from "./controller/create-drag-controller.js";
|
|
2
|
+
export { createDraggable, } from "./draggable/create-draggable-binding.js";
|
|
3
|
+
export { createDroppable, } from "./droppable/create-droppable-binding.js";
|
|
4
|
+
export { createDropContainer, } from "./droppable/create-drop-container-binding.js";
|
|
5
|
+
export { createSortable, } from "./sortable/create-sortable-binding.js";
|
|
6
|
+
export { createDragHandle, } from "./input/create-drag-handle.js";
|
|
7
|
+
export { centerToCenter, pointerToCenter, pointerToRectDistance, } from "./targeting/algorithms.js";
|
|
8
|
+
export { getDistanceToRect, maxOverlayCenterDistanceToRect, maxPointerDistanceToRect, } from "./targeting/constraints.js";
|
|
9
|
+
export { lockToXAxis, lockToYAxis, restrictToContainer, } from "./modifiers/built-ins.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type PointerConfiguration = {
|
|
2
|
+
activationDelay?: number | null;
|
|
3
|
+
activationDistance?: number | null;
|
|
4
|
+
};
|
|
5
|
+
export type NormalizedPointerConfiguration = {
|
|
6
|
+
activationDelay: number | null;
|
|
7
|
+
activationDistance: number | null;
|
|
8
|
+
};
|
|
9
|
+
export type KeyboardCommand = string | readonly string[];
|
|
10
|
+
export type KeyboardConfiguration = {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
start?: KeyboardCommand;
|
|
13
|
+
drop?: KeyboardCommand;
|
|
14
|
+
cancel?: KeyboardCommand;
|
|
15
|
+
moveUp?: KeyboardCommand;
|
|
16
|
+
moveDown?: KeyboardCommand;
|
|
17
|
+
moveLeft?: KeyboardCommand;
|
|
18
|
+
moveRight?: KeyboardCommand;
|
|
19
|
+
moveDistance?: number;
|
|
20
|
+
};
|
|
21
|
+
export type NormalizedKeyboardConfiguration = {
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
start: readonly string[];
|
|
24
|
+
drop: readonly string[];
|
|
25
|
+
cancel: readonly string[];
|
|
26
|
+
moveUp: readonly string[];
|
|
27
|
+
moveDown: readonly string[];
|
|
28
|
+
moveLeft: readonly string[];
|
|
29
|
+
moveRight: readonly string[];
|
|
30
|
+
moveDistance: number;
|
|
31
|
+
};
|
|
32
|
+
export declare const defaultKeyboardConfiguration: NormalizedKeyboardConfiguration;
|
|
33
|
+
export declare function normalizePointerConfiguration(pointerConfiguration: PointerConfiguration | undefined): NormalizedPointerConfiguration;
|
|
34
|
+
export declare function normalizeKeyboardConfiguration(keyboardConfiguration: KeyboardConfiguration | undefined): NormalizedKeyboardConfiguration;
|
|
35
|
+
export declare function isKeyboardCommandMatch(key: string, command: readonly string[]): boolean;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const defaultKeyboardConfiguration = {
|
|
2
|
+
enabled: true,
|
|
3
|
+
start: ["Space", "Enter"],
|
|
4
|
+
drop: ["Space", "Enter"],
|
|
5
|
+
cancel: ["Escape"],
|
|
6
|
+
moveUp: ["ArrowUp"],
|
|
7
|
+
moveDown: ["ArrowDown"],
|
|
8
|
+
moveLeft: ["ArrowLeft"],
|
|
9
|
+
moveRight: ["ArrowRight"],
|
|
10
|
+
moveDistance: 24,
|
|
11
|
+
};
|
|
12
|
+
export function normalizePointerConfiguration(pointerConfiguration) {
|
|
13
|
+
return {
|
|
14
|
+
activationDelay: normalizePointerActivationValue(pointerConfiguration?.activationDelay),
|
|
15
|
+
activationDistance: normalizePointerActivationValue(pointerConfiguration?.activationDistance),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function normalizeKeyboardConfiguration(keyboardConfiguration) {
|
|
19
|
+
return {
|
|
20
|
+
enabled: keyboardConfiguration?.enabled ?? defaultKeyboardConfiguration.enabled,
|
|
21
|
+
start: normalizeKeyboardCommand(keyboardConfiguration?.start, defaultKeyboardConfiguration.start),
|
|
22
|
+
drop: normalizeKeyboardCommand(keyboardConfiguration?.drop, defaultKeyboardConfiguration.drop),
|
|
23
|
+
cancel: normalizeKeyboardCommand(keyboardConfiguration?.cancel, defaultKeyboardConfiguration.cancel),
|
|
24
|
+
moveUp: normalizeKeyboardCommand(keyboardConfiguration?.moveUp, defaultKeyboardConfiguration.moveUp),
|
|
25
|
+
moveDown: normalizeKeyboardCommand(keyboardConfiguration?.moveDown, defaultKeyboardConfiguration.moveDown),
|
|
26
|
+
moveLeft: normalizeKeyboardCommand(keyboardConfiguration?.moveLeft, defaultKeyboardConfiguration.moveLeft),
|
|
27
|
+
moveRight: normalizeKeyboardCommand(keyboardConfiguration?.moveRight, defaultKeyboardConfiguration.moveRight),
|
|
28
|
+
moveDistance: normalizeKeyboardMoveDistance(keyboardConfiguration?.moveDistance),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function isKeyboardCommandMatch(key, command) {
|
|
32
|
+
return command.includes(normalizeKeyboardKey(key));
|
|
33
|
+
}
|
|
34
|
+
function normalizeKeyboardCommand(command, defaultCommand) {
|
|
35
|
+
const commandKeys = command === undefined
|
|
36
|
+
? defaultCommand
|
|
37
|
+
: typeof command === "string"
|
|
38
|
+
? [command]
|
|
39
|
+
: command;
|
|
40
|
+
return commandKeys.map(normalizeKeyboardKey);
|
|
41
|
+
}
|
|
42
|
+
function normalizeKeyboardKey(key) {
|
|
43
|
+
return key === " " ? "Space" : key;
|
|
44
|
+
}
|
|
45
|
+
function normalizeKeyboardMoveDistance(moveDistance) {
|
|
46
|
+
return typeof moveDistance === "number" &&
|
|
47
|
+
Number.isFinite(moveDistance) &&
|
|
48
|
+
moveDistance > 0
|
|
49
|
+
? moveDistance
|
|
50
|
+
: defaultKeyboardConfiguration.moveDistance;
|
|
51
|
+
}
|
|
52
|
+
function normalizePointerActivationValue(value) {
|
|
53
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
54
|
+
? value
|
|
55
|
+
: null;
|
|
56
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const domDragHandleAttribute = "data-dnd-drag-handle";
|
|
2
|
+
export declare const domDragHandleSelector = "[data-dnd-drag-handle]";
|
|
3
|
+
export declare function shouldStartDragFromTarget(input: {
|
|
4
|
+
draggableElement: HTMLElement;
|
|
5
|
+
eventTarget: EventTarget | null;
|
|
6
|
+
}): boolean;
|
|
7
|
+
export declare function shouldHandleKeyboardDragFromTarget(input: {
|
|
8
|
+
draggableElement: HTMLElement;
|
|
9
|
+
eventTarget: EventTarget | null;
|
|
10
|
+
}): boolean;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const domDragHandleAttribute = "data-dnd-drag-handle";
|
|
2
|
+
export const domDragHandleSelector = `[${domDragHandleAttribute}]`;
|
|
3
|
+
const interactiveElementSelector = [
|
|
4
|
+
"a[href]",
|
|
5
|
+
"button",
|
|
6
|
+
"input",
|
|
7
|
+
"option",
|
|
8
|
+
"select",
|
|
9
|
+
"textarea",
|
|
10
|
+
"[role='button']",
|
|
11
|
+
"[role='link']",
|
|
12
|
+
"[role='textbox']",
|
|
13
|
+
].join(",");
|
|
14
|
+
export function shouldStartDragFromTarget(input) {
|
|
15
|
+
const eventTarget = getEventTargetElement(input.eventTarget);
|
|
16
|
+
if (!eventTarget) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const hasDragHandle = input.draggableElement.querySelector(domDragHandleSelector) !== null;
|
|
20
|
+
if (!hasDragHandle) {
|
|
21
|
+
return !isInteractiveDragTarget({
|
|
22
|
+
draggableElement: input.draggableElement,
|
|
23
|
+
eventTarget,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const closestDragHandle = eventTarget.closest(domDragHandleSelector);
|
|
27
|
+
return (closestDragHandle !== null &&
|
|
28
|
+
input.draggableElement.contains(closestDragHandle));
|
|
29
|
+
}
|
|
30
|
+
export function shouldHandleKeyboardDragFromTarget(input) {
|
|
31
|
+
const eventTarget = getEventTargetElement(input.eventTarget);
|
|
32
|
+
if (!eventTarget) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (isInteractiveDragTarget({
|
|
36
|
+
draggableElement: input.draggableElement,
|
|
37
|
+
eventTarget,
|
|
38
|
+
})) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (eventTarget === input.draggableElement) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const closestDragHandle = eventTarget.closest(domDragHandleSelector);
|
|
45
|
+
return (closestDragHandle !== null &&
|
|
46
|
+
input.draggableElement.contains(closestDragHandle));
|
|
47
|
+
}
|
|
48
|
+
function getEventTargetElement(target) {
|
|
49
|
+
return target instanceof Element ? target : null;
|
|
50
|
+
}
|
|
51
|
+
function isInteractiveDragTarget(input) {
|
|
52
|
+
return (closestWithin(input.eventTarget, interactiveElementSelector, input.draggableElement) !== null ||
|
|
53
|
+
getEditableElement(input.eventTarget, input.draggableElement) !== null);
|
|
54
|
+
}
|
|
55
|
+
function closestWithin(element, selector, boundary) {
|
|
56
|
+
const closestElement = element.closest(selector);
|
|
57
|
+
return closestElement && boundary.contains(closestElement)
|
|
58
|
+
? closestElement
|
|
59
|
+
: null;
|
|
60
|
+
}
|
|
61
|
+
function getEditableElement(element, boundary) {
|
|
62
|
+
let currentElement = element;
|
|
63
|
+
while (currentElement && boundary.contains(currentElement)) {
|
|
64
|
+
if (currentElement instanceof HTMLElement &&
|
|
65
|
+
currentElement.isContentEditable) {
|
|
66
|
+
return currentElement;
|
|
67
|
+
}
|
|
68
|
+
if (currentElement === boundary) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
currentElement = currentElement.parentElement;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type NormalizedKeyboardConfiguration } from "./config.js";
|
|
2
|
+
export type KeyboardMoveDirection = "up" | "down" | "left" | "right";
|
|
3
|
+
export type KeyboardDragActiveInput = "pointer" | "keyboard";
|
|
4
|
+
export type KeyboardDragStartInput = {
|
|
5
|
+
draggableId: string;
|
|
6
|
+
group: string;
|
|
7
|
+
element: HTMLElement;
|
|
8
|
+
};
|
|
9
|
+
export type SourceKeyboardDragKeyDownInput = KeyboardDragStartInput & {
|
|
10
|
+
key: string;
|
|
11
|
+
};
|
|
12
|
+
export type KeyboardDragControllerOptions = {
|
|
13
|
+
getConfiguration: () => NormalizedKeyboardConfiguration;
|
|
14
|
+
isDragging: () => boolean;
|
|
15
|
+
getActiveInput: () => KeyboardDragActiveInput | null;
|
|
16
|
+
start: (input: KeyboardDragStartInput) => void;
|
|
17
|
+
move: (direction: KeyboardMoveDirection) => void;
|
|
18
|
+
drop: () => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
};
|
|
21
|
+
export declare class KeyboardDragController {
|
|
22
|
+
private options;
|
|
23
|
+
constructor(options: KeyboardDragControllerOptions);
|
|
24
|
+
isEnabled(): boolean;
|
|
25
|
+
handleSourceKeyDown(input: SourceKeyboardDragKeyDownInput): boolean;
|
|
26
|
+
handleActiveKeyDown(key: string): boolean;
|
|
27
|
+
bindWindowListeners(): () => void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { isKeyboardCommandMatch, } from "./config.js";
|
|
2
|
+
export class KeyboardDragController {
|
|
3
|
+
options;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
isEnabled() {
|
|
8
|
+
return this.options.getConfiguration().enabled;
|
|
9
|
+
}
|
|
10
|
+
handleSourceKeyDown(input) {
|
|
11
|
+
const configuration = this.options.getConfiguration();
|
|
12
|
+
if (!configuration.enabled) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (!this.options.isDragging()) {
|
|
16
|
+
if (!isKeyboardCommandMatch(input.key, configuration.start)) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
this.options.start({
|
|
20
|
+
draggableId: input.draggableId,
|
|
21
|
+
group: input.group,
|
|
22
|
+
element: input.element,
|
|
23
|
+
});
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
if (this.options.getActiveInput() !== "keyboard") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return this.handleActiveKeyDown(input.key);
|
|
30
|
+
}
|
|
31
|
+
handleActiveKeyDown(key) {
|
|
32
|
+
const configuration = this.options.getConfiguration();
|
|
33
|
+
if (isKeyboardCommandMatch(key, configuration.moveUp)) {
|
|
34
|
+
this.options.move("up");
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
if (isKeyboardCommandMatch(key, configuration.moveDown)) {
|
|
38
|
+
this.options.move("down");
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (isKeyboardCommandMatch(key, configuration.moveLeft)) {
|
|
42
|
+
this.options.move("left");
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (isKeyboardCommandMatch(key, configuration.moveRight)) {
|
|
46
|
+
this.options.move("right");
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
if (isKeyboardCommandMatch(key, configuration.drop)) {
|
|
50
|
+
this.options.drop();
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (isKeyboardCommandMatch(key, configuration.cancel)) {
|
|
54
|
+
this.options.cancel();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
bindWindowListeners() {
|
|
60
|
+
let isCleanedUp = false;
|
|
61
|
+
const handleKeyDown = (event) => {
|
|
62
|
+
if (!this.handleActiveKeyDown(event.key)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
event.preventDefault();
|
|
66
|
+
event.stopPropagation();
|
|
67
|
+
};
|
|
68
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
69
|
+
return () => {
|
|
70
|
+
if (isCleanedUp) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
isCleanedUp = true;
|
|
74
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { DragPoint } from "../geometry/rects.js";
|
|
2
|
+
import type { NormalizedPointerConfiguration } from "./config.js";
|
|
3
|
+
export type PointerDragActivationRequest = {
|
|
4
|
+
draggableId: string;
|
|
5
|
+
group: string;
|
|
6
|
+
element: HTMLElement;
|
|
7
|
+
pointerId: number;
|
|
8
|
+
pointerPosition: DragPoint;
|
|
9
|
+
};
|
|
10
|
+
export type ActivatedPointerDrag = {
|
|
11
|
+
draggableId: string;
|
|
12
|
+
group: string;
|
|
13
|
+
element: HTMLElement;
|
|
14
|
+
pointerId: number;
|
|
15
|
+
initialPointerPosition: DragPoint;
|
|
16
|
+
latestPointerPosition: DragPoint;
|
|
17
|
+
};
|
|
18
|
+
export type PointerActivationControllerOptions = {
|
|
19
|
+
getConfiguration: () => NormalizedPointerConfiguration;
|
|
20
|
+
isDragging: () => boolean;
|
|
21
|
+
startImmediately: (request: PointerDragActivationRequest) => void;
|
|
22
|
+
activate: (activation: ActivatedPointerDrag) => void;
|
|
23
|
+
};
|
|
24
|
+
export declare class PointerActivationController {
|
|
25
|
+
private options;
|
|
26
|
+
private pendingActivation;
|
|
27
|
+
constructor(options: PointerActivationControllerOptions);
|
|
28
|
+
request(request: PointerDragActivationRequest): void;
|
|
29
|
+
cancel(): void;
|
|
30
|
+
private activatePending;
|
|
31
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export class PointerActivationController {
|
|
2
|
+
options;
|
|
3
|
+
pendingActivation = null;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
request(request) {
|
|
8
|
+
this.cancel();
|
|
9
|
+
if (this.options.isDragging()) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const { activationDelay, activationDistance } = this.options.getConfiguration();
|
|
13
|
+
if (activationDelay === null && activationDistance === null) {
|
|
14
|
+
this.options.startImmediately(request);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const initialPointerPosition = {
|
|
18
|
+
x: request.pointerPosition.x,
|
|
19
|
+
y: request.pointerPosition.y,
|
|
20
|
+
};
|
|
21
|
+
const pendingActivation = {
|
|
22
|
+
draggableId: request.draggableId,
|
|
23
|
+
group: request.group,
|
|
24
|
+
element: request.element,
|
|
25
|
+
pointerId: request.pointerId,
|
|
26
|
+
initialPointerPosition,
|
|
27
|
+
latestPointerPosition: initialPointerPosition,
|
|
28
|
+
timeoutId: null,
|
|
29
|
+
cleanupWindowListeners: () => { },
|
|
30
|
+
};
|
|
31
|
+
const handlePointerMove = (event) => {
|
|
32
|
+
if (event.pointerId !== pendingActivation.pointerId) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const pointerPosition = {
|
|
36
|
+
x: event.clientX,
|
|
37
|
+
y: event.clientY,
|
|
38
|
+
};
|
|
39
|
+
pendingActivation.latestPointerPosition = pointerPosition;
|
|
40
|
+
if (activationDistance === null) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const distanceX = pointerPosition.x - initialPointerPosition.x;
|
|
44
|
+
const distanceY = pointerPosition.y - initialPointerPosition.y;
|
|
45
|
+
const distanceSquared = distanceX * distanceX + distanceY * distanceY;
|
|
46
|
+
const activationDistanceSquared = activationDistance * activationDistance;
|
|
47
|
+
if (distanceSquared >= activationDistanceSquared) {
|
|
48
|
+
this.activatePending(pendingActivation);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const handlePointerEnd = (event) => {
|
|
52
|
+
if (event.pointerId !== pendingActivation.pointerId) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.cancel();
|
|
56
|
+
};
|
|
57
|
+
window.addEventListener("pointermove", handlePointerMove);
|
|
58
|
+
window.addEventListener("pointerup", handlePointerEnd);
|
|
59
|
+
window.addEventListener("pointercancel", handlePointerEnd);
|
|
60
|
+
pendingActivation.cleanupWindowListeners = () => {
|
|
61
|
+
window.removeEventListener("pointermove", handlePointerMove);
|
|
62
|
+
window.removeEventListener("pointerup", handlePointerEnd);
|
|
63
|
+
window.removeEventListener("pointercancel", handlePointerEnd);
|
|
64
|
+
};
|
|
65
|
+
if (activationDelay !== null) {
|
|
66
|
+
pendingActivation.timeoutId = window.setTimeout(() => {
|
|
67
|
+
this.activatePending(pendingActivation);
|
|
68
|
+
}, activationDelay);
|
|
69
|
+
}
|
|
70
|
+
this.pendingActivation = pendingActivation;
|
|
71
|
+
}
|
|
72
|
+
cancel() {
|
|
73
|
+
const pendingActivation = this.pendingActivation;
|
|
74
|
+
if (!pendingActivation) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (pendingActivation.timeoutId !== null) {
|
|
78
|
+
window.clearTimeout(pendingActivation.timeoutId);
|
|
79
|
+
}
|
|
80
|
+
pendingActivation.cleanupWindowListeners();
|
|
81
|
+
this.pendingActivation = null;
|
|
82
|
+
}
|
|
83
|
+
activatePending(pendingActivation) {
|
|
84
|
+
if (this.pendingActivation !== pendingActivation) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.cancel();
|
|
88
|
+
this.options.activate({
|
|
89
|
+
draggableId: pendingActivation.draggableId,
|
|
90
|
+
group: pendingActivation.group,
|
|
91
|
+
element: pendingActivation.element,
|
|
92
|
+
pointerId: pendingActivation.pointerId,
|
|
93
|
+
initialPointerPosition: pendingActivation.initialPointerPosition,
|
|
94
|
+
latestPointerPosition: pendingActivation.latestPointerPosition,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { createDragRuntimeHandle, type DragRuntimeHandle, type DragRuntimeHandleConfigureInput, type DragRuntimeHandleOptions, } from "../runtime/drag-runtime-handle.js";
|
|
2
|
+
export type { DragOverlayHostUpdate, DragOverlayPhase, DragOverlayRenderState, DragState, } from "../runtime/types.js";
|
|
3
|
+
export type { DragRuntimeSubscription } from "../runtime/lifecycle.js";
|
|
4
|
+
export { createDomDraggable, type CreateDomDraggableInput, type DomDraggableBehavior, type DomDraggableKeyDownEvent, type DomDraggablePointerDownEvent, type DomDraggableRuntime, } from "../draggable/create-draggable.js";
|
|
5
|
+
export { createDomDroppable, type CreateDomDroppableInput, type DomDroppableBehavior, type DomDroppableRuntime, } from "../droppable/create-droppable.js";
|
|
6
|
+
export { createDomDropContainer, type CreateDomDropContainerInput, type DomDropContainerBehavior, type DomDropContainerRuntime, } from "../droppable/create-drop-container.js";
|
|
7
|
+
export { createDomSortable, type CreateDomSortableInput, type DomSortableBehavior, } from "../sortable/create-sortable.js";
|
|
8
|
+
export type { DomSortableRuntime } from "../sortable/sortable-registry.js";
|
|
9
|
+
export type { SortableAxis, SortablePlacementBoundary, } from "../sortable/sortable-options.js";
|
|
10
|
+
export { domDragHandleAttribute } from "../input/drag-handle.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createDragRuntimeHandle, } from "../runtime/drag-runtime-handle.js";
|
|
2
|
+
export { createDomDraggable, } from "../draggable/create-draggable.js";
|
|
3
|
+
export { createDomDroppable, } from "../droppable/create-droppable.js";
|
|
4
|
+
export { createDomDropContainer, } from "../droppable/create-drop-container.js";
|
|
5
|
+
export { createDomSortable, } from "../sortable/create-sortable.js";
|
|
6
|
+
export { domDragHandleAttribute } from "../input/drag-handle.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DragRect } from "../geometry/rects.js";
|
|
2
|
+
import type { DragModifier, DragModifierSetupInput } from "./types.js";
|
|
3
|
+
export type RestrictToContainerResolver = (input: DragModifierSetupInput) => HTMLElement | null;
|
|
4
|
+
export declare function lockToXAxis(): DragModifier;
|
|
5
|
+
export declare function lockToYAxis(): DragModifier;
|
|
6
|
+
export declare function restrictToContainer(getContainer: RestrictToContainerResolver): DragModifier<DragRect | null>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { rectToDragRect } from "../geometry/rects.js";
|
|
2
|
+
export function lockToXAxis() {
|
|
3
|
+
return {
|
|
4
|
+
transform: (input) => ({
|
|
5
|
+
x: input.pointerPosition.x,
|
|
6
|
+
y: input.initialPointerPosition.y,
|
|
7
|
+
}),
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function lockToYAxis() {
|
|
11
|
+
return {
|
|
12
|
+
transform: (input) => ({
|
|
13
|
+
x: input.initialPointerPosition.x,
|
|
14
|
+
y: input.pointerPosition.y,
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function restrictToContainer(getContainer) {
|
|
19
|
+
return {
|
|
20
|
+
setup: (input) => {
|
|
21
|
+
const container = getContainer(input);
|
|
22
|
+
return container
|
|
23
|
+
? rectToDragRect(container.getBoundingClientRect())
|
|
24
|
+
: null;
|
|
25
|
+
},
|
|
26
|
+
transform: (input) => {
|
|
27
|
+
if (input.state === null) {
|
|
28
|
+
return input.pointerPosition;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
x: clampPointerAxis({
|
|
32
|
+
pointerPosition: input.pointerPosition.x,
|
|
33
|
+
overlayStart: input.overlayRect.left,
|
|
34
|
+
overlayEnd: input.overlayRect.right,
|
|
35
|
+
containerStart: input.state.left,
|
|
36
|
+
containerEnd: input.state.right,
|
|
37
|
+
}),
|
|
38
|
+
y: clampPointerAxis({
|
|
39
|
+
pointerPosition: input.pointerPosition.y,
|
|
40
|
+
overlayStart: input.overlayRect.top,
|
|
41
|
+
overlayEnd: input.overlayRect.bottom,
|
|
42
|
+
containerStart: input.state.top,
|
|
43
|
+
containerEnd: input.state.bottom,
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function clampPointerAxis(input) {
|
|
50
|
+
const overlaySize = input.overlayEnd - input.overlayStart;
|
|
51
|
+
const containerSize = input.containerEnd - input.containerStart;
|
|
52
|
+
if (overlaySize > containerSize) {
|
|
53
|
+
return input.pointerPosition + input.containerStart - input.overlayStart;
|
|
54
|
+
}
|
|
55
|
+
if (input.overlayStart < input.containerStart) {
|
|
56
|
+
return input.pointerPosition + input.containerStart - input.overlayStart;
|
|
57
|
+
}
|
|
58
|
+
if (input.overlayEnd > input.containerEnd) {
|
|
59
|
+
return input.pointerPosition - (input.overlayEnd - input.containerEnd);
|
|
60
|
+
}
|
|
61
|
+
return input.pointerPosition;
|
|
62
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DragPoint, DragRect } from "../geometry/rects.js";
|
|
2
|
+
import { type DragOverlayMeasurement } from "../geometry/overlay.js";
|
|
3
|
+
import type { ActiveDragModifier, DragModifier, DragModifierInput, DragModifierSetupInput } from "./types.js";
|
|
4
|
+
export declare function createActiveModifier<State>(modifier: DragModifier<State>, setupInput: DragModifierSetupInput): ActiveDragModifier;
|
|
5
|
+
export declare function createActiveModifier(modifier: DragModifierInput, setupInput: DragModifierSetupInput): ActiveDragModifier;
|
|
6
|
+
export declare function createActiveDragModifiers(input: {
|
|
7
|
+
modifiers: readonly DragModifierInput[];
|
|
8
|
+
setupInput: DragModifierSetupInput;
|
|
9
|
+
}): ActiveDragModifier[];
|
|
10
|
+
export declare function applyDragModifiers(input: {
|
|
11
|
+
activeModifiers: readonly ActiveDragModifier[];
|
|
12
|
+
draggableId: string;
|
|
13
|
+
group: string;
|
|
14
|
+
sourceRect: DragRect;
|
|
15
|
+
initialPointerPosition: DragPoint;
|
|
16
|
+
rawPointerPosition: DragPoint;
|
|
17
|
+
overlayMeasurement?: DragOverlayMeasurement | null;
|
|
18
|
+
}): DragPoint;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { getOverlayRect, } from "../geometry/overlay.js";
|
|
2
|
+
export function createActiveModifier(modifier, setupInput) {
|
|
3
|
+
const state = modifier.setup?.(setupInput);
|
|
4
|
+
return {
|
|
5
|
+
transform: (input) => modifier.transform({
|
|
6
|
+
...input,
|
|
7
|
+
state,
|
|
8
|
+
}),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function createActiveDragModifiers(input) {
|
|
12
|
+
return input.modifiers.map((modifier) => createActiveModifier(modifier, input.setupInput));
|
|
13
|
+
}
|
|
14
|
+
export function applyDragModifiers(input) {
|
|
15
|
+
let pointerPosition = input.rawPointerPosition;
|
|
16
|
+
for (const activeModifier of input.activeModifiers) {
|
|
17
|
+
const overlayRect = getOverlayRect({
|
|
18
|
+
sourceRect: input.sourceRect,
|
|
19
|
+
initialPointerPosition: input.initialPointerPosition,
|
|
20
|
+
pointerPosition,
|
|
21
|
+
overlayMeasurement: input.overlayMeasurement,
|
|
22
|
+
});
|
|
23
|
+
pointerPosition = activeModifier.transform({
|
|
24
|
+
draggableId: input.draggableId,
|
|
25
|
+
group: input.group,
|
|
26
|
+
sourceRect: input.sourceRect,
|
|
27
|
+
initialPointerPosition: input.initialPointerPosition,
|
|
28
|
+
rawPointerPosition: input.rawPointerPosition,
|
|
29
|
+
pointerPosition,
|
|
30
|
+
overlayRect,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return pointerPosition;
|
|
34
|
+
}
|