@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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +460 -0
  3. package/dist/controller/controller-internals.d.ts +5 -0
  4. package/dist/controller/controller-internals.js +11 -0
  5. package/dist/controller/create-drag-controller.d.ts +36 -0
  6. package/dist/controller/create-drag-controller.js +232 -0
  7. package/dist/draggable/create-draggable-binding.d.ts +8 -0
  8. package/dist/draggable/create-draggable-binding.js +52 -0
  9. package/dist/draggable/create-draggable.d.ts +46 -0
  10. package/dist/draggable/create-draggable.js +57 -0
  11. package/dist/droppable/create-drop-container-binding.d.ts +8 -0
  12. package/dist/droppable/create-drop-container-binding.js +28 -0
  13. package/dist/droppable/create-drop-container.d.ts +18 -0
  14. package/dist/droppable/create-drop-container.js +36 -0
  15. package/dist/droppable/create-droppable-binding.d.ts +9 -0
  16. package/dist/droppable/create-droppable-binding.js +29 -0
  17. package/dist/droppable/create-droppable.d.ts +17 -0
  18. package/dist/droppable/create-droppable.js +31 -0
  19. package/dist/geometry/measurement.d.ts +4 -0
  20. package/dist/geometry/measurement.js +33 -0
  21. package/dist/geometry/overlay.d.ts +19 -0
  22. package/dist/geometry/overlay.js +32 -0
  23. package/dist/geometry/rects.d.ts +17 -0
  24. package/dist/geometry/rects.js +34 -0
  25. package/dist/index.d.ts +16 -0
  26. package/dist/index.js +9 -0
  27. package/dist/input/config.d.ts +35 -0
  28. package/dist/input/config.js +56 -0
  29. package/dist/input/create-drag-handle.d.ts +4 -0
  30. package/dist/input/create-drag-handle.js +4 -0
  31. package/dist/input/drag-handle.d.ts +10 -0
  32. package/dist/input/drag-handle.js +74 -0
  33. package/dist/input/keyboard-drag.d.ts +28 -0
  34. package/dist/input/keyboard-drag.js +77 -0
  35. package/dist/input/pointer-activation.d.ts +31 -0
  36. package/dist/input/pointer-activation.js +97 -0
  37. package/dist/integration/index.d.ts +10 -0
  38. package/dist/integration/index.js +6 -0
  39. package/dist/modifiers/built-ins.d.ts +6 -0
  40. package/dist/modifiers/built-ins.js +62 -0
  41. package/dist/modifiers/pipeline.d.ts +18 -0
  42. package/dist/modifiers/pipeline.js +34 -0
  43. package/dist/modifiers/types.d.ts +32 -0
  44. package/dist/modifiers/types.js +1 -0
  45. package/dist/runtime/drag-runtime-handle.d.ts +22 -0
  46. package/dist/runtime/drag-runtime-handle.js +33 -0
  47. package/dist/runtime/drag-runtime.d.ts +96 -0
  48. package/dist/runtime/drag-runtime.js +798 -0
  49. package/dist/runtime/drop-target-registry.d.ts +101 -0
  50. package/dist/runtime/drop-target-registry.js +855 -0
  51. package/dist/runtime/lifecycle.d.ts +44 -0
  52. package/dist/runtime/lifecycle.js +1 -0
  53. package/dist/runtime/types.d.ts +65 -0
  54. package/dist/runtime/types.js +1 -0
  55. package/dist/sortable/create-sortable-binding.d.ts +10 -0
  56. package/dist/sortable/create-sortable-binding.js +58 -0
  57. package/dist/sortable/create-sortable.d.ts +19 -0
  58. package/dist/sortable/create-sortable.js +55 -0
  59. package/dist/sortable/sortable-options.d.ts +17 -0
  60. package/dist/sortable/sortable-options.js +20 -0
  61. package/dist/sortable/sortable-preview.d.ts +79 -0
  62. package/dist/sortable/sortable-preview.js +357 -0
  63. package/dist/sortable/sortable-registry.d.ts +113 -0
  64. package/dist/sortable/sortable-registry.js +145 -0
  65. package/dist/targeting/algorithms.d.ts +6 -0
  66. package/dist/targeting/algorithms.js +56 -0
  67. package/dist/targeting/constraints.d.ts +15 -0
  68. package/dist/targeting/constraints.js +58 -0
  69. package/dist/targeting/types.d.ts +23 -0
  70. package/dist/targeting/types.js +1 -0
  71. package/package.json +60 -0
@@ -0,0 +1,44 @@
1
+ import type { DragPoint, DragRect } from "../geometry/rects.js";
2
+ import type { SortableDropPlacement } from "./drop-target-registry.js";
3
+ export type DragSource = "pointer" | "keyboard";
4
+ export type DragEndResult = "dropped" | "no-target" | "invalid-target" | "canceled";
5
+ export type DragStartEvent = {
6
+ draggableId: string;
7
+ source: DragSource;
8
+ pointerPosition: DragPoint;
9
+ sourceRect: DragRect;
10
+ };
11
+ export type DragUpdateEvent = {
12
+ draggableId: string;
13
+ source: DragSource;
14
+ pointerPosition: DragPoint;
15
+ activeDropTargetId: string | null;
16
+ previousDropTargetId: string | null;
17
+ };
18
+ export type DragEndEvent = {
19
+ draggableId: string;
20
+ source: DragSource;
21
+ result: DragEndResult;
22
+ dropTargetId: string | null;
23
+ };
24
+ export type DropEvent = {
25
+ draggableId: string;
26
+ source: DragSource;
27
+ dropTargetId: string;
28
+ sortablePlacement?: SortableDropPlacement;
29
+ };
30
+ export type DragLifecycleHelpers = {
31
+ getDropTargetRect: (dropTargetId: string) => DragRect | null;
32
+ };
33
+ export type DragLifecycleCallbacks = {
34
+ onDragStart?: (event: DragStartEvent, helpers: DragLifecycleHelpers) => void;
35
+ onDragUpdate?: (event: DragUpdateEvent, helpers: DragLifecycleHelpers) => void;
36
+ onDragEnd?: (event: DragEndEvent, helpers: DragLifecycleHelpers) => void;
37
+ onDrop?: (event: DropEvent, helpers: DragLifecycleHelpers) => void;
38
+ };
39
+ export type DragRuntimeSubscription = {
40
+ onDragStart?: (event: DragStartEvent) => void;
41
+ onDragUpdate?: (event: DragUpdateEvent) => void;
42
+ onDragEnd?: (event: DragEndEvent) => void;
43
+ onDrop?: (event: DropEvent) => void;
44
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ import type { DragPoint, DragRect } from "../geometry/rects.js";
2
+ import type { KeyboardConfiguration, PointerConfiguration } from "../input/config.js";
3
+ import type { DragModifierInput } from "../modifiers/types.js";
4
+ import type { TargetingAlgorithm, TargetingConstraint } from "../targeting/types.js";
5
+ import type { DragLifecycleCallbacks } from "./lifecycle.js";
6
+ import type { KeyboardDragStartInput } from "../input/keyboard-drag.js";
7
+ import type { PointerDragActivationRequest } from "../input/pointer-activation.js";
8
+ import type { DragGroup } from "./drop-target-registry.js";
9
+ export type Point = DragPoint;
10
+ export type DragState = {
11
+ draggableId: string;
12
+ group: DragGroup;
13
+ sourceRect: DragRect;
14
+ startPointerPosition: Point;
15
+ pointerPosition: Point;
16
+ };
17
+ export type DragOverlayPhase = "dragging" | "released";
18
+ export type DragOverlayRenderState = {
19
+ dragState: DragState;
20
+ phase: DragOverlayPhase;
21
+ };
22
+ export type DragOverlayHostUpdate = {
23
+ type: "mount";
24
+ state: DragOverlayRenderState;
25
+ } | {
26
+ type: "move";
27
+ dragState: DragState;
28
+ } | {
29
+ type: "release";
30
+ state: DragOverlayRenderState;
31
+ } | {
32
+ type: "unmount";
33
+ };
34
+ export type RequestDragStartInput = PointerDragActivationRequest;
35
+ type BaseStartDragInput = {
36
+ draggableId: string;
37
+ group: DragGroup;
38
+ pointerPosition: Point;
39
+ sourceRect: DragRect;
40
+ };
41
+ export type StartDragInput = (BaseStartDragInput & {
42
+ inputType: "pointer";
43
+ pointerId: number;
44
+ }) | (BaseStartDragInput & {
45
+ inputType: "keyboard";
46
+ });
47
+ export type RequestKeyboardDragStartInput = KeyboardDragStartInput;
48
+ export type DragRuntimeOptions = {
49
+ updateOverlayHost?: (update: DragOverlayHostUpdate) => void;
50
+ targetingAlgorithm?: TargetingAlgorithm;
51
+ targetingConstraint?: TargetingConstraint;
52
+ hasDragOverlay?: boolean;
53
+ keepOverlayOnDrop?: boolean;
54
+ };
55
+ export type DragRuntimeConfigureInput = {
56
+ targetingAlgorithm: TargetingAlgorithm;
57
+ targetingConstraint: TargetingConstraint | undefined;
58
+ hasDragOverlay: boolean;
59
+ keepOverlayOnDrop: boolean;
60
+ lifecycleCallbacks: DragLifecycleCallbacks;
61
+ keyboardConfiguration?: KeyboardConfiguration;
62
+ modifiers?: readonly DragModifierInput[];
63
+ pointerConfiguration?: PointerConfiguration;
64
+ };
65
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { DragController } from "../controller/create-drag-controller.js";
2
+ import type { SortableOptions } from "./sortable-options.js";
3
+ export type CreateSortableInput = SortableOptions & {
4
+ controller: DragController;
5
+ element: HTMLElement;
6
+ draggableId: string;
7
+ group?: string;
8
+ containerId?: string | null;
9
+ };
10
+ export declare function createSortable(input: CreateSortableInput): void;
@@ -0,0 +1,58 @@
1
+ import { getControllerRuntime } from "../controller/controller-internals.js";
2
+ import { createDomSortable } from "./create-sortable.js";
3
+ const defaultSortableGroup = "default";
4
+ export function createSortable(input) {
5
+ const elementRef = new WeakRef(input.element);
6
+ const runtime = getControllerRuntime(input.controller);
7
+ const behavior = createDomSortable({
8
+ runtime,
9
+ draggableId: input.draggableId,
10
+ group: input.group ?? defaultSortableGroup,
11
+ containerId: input.containerId ?? null,
12
+ axis: input.axis,
13
+ placementBoundary: input.placementBoundary,
14
+ getElement: () => elementRef.deref() ?? null,
15
+ });
16
+ const hadPreviousTabIndex = input.element.hasAttribute("tabindex");
17
+ const previousTabIndex = input.element.getAttribute("tabindex");
18
+ let keyDownAttached = false;
19
+ let cleanedUp = false;
20
+ const onPointerDown = (event) => {
21
+ behavior.onPointerDown(event);
22
+ };
23
+ const onKeyDown = (event) => {
24
+ behavior.onKeyDown(event);
25
+ };
26
+ behavior.setElement(input.element);
27
+ input.element.addEventListener("pointerdown", onPointerDown);
28
+ if (behavior.tabIndex !== undefined) {
29
+ input.element.tabIndex = behavior.tabIndex;
30
+ input.element.addEventListener("keydown", onKeyDown);
31
+ keyDownAttached = true;
32
+ }
33
+ const cleanup = () => {
34
+ if (cleanedUp) {
35
+ return;
36
+ }
37
+ cleanedUp = true;
38
+ const element = elementRef.deref();
39
+ if (!element) {
40
+ return;
41
+ }
42
+ element.removeEventListener("pointerdown", onPointerDown);
43
+ if (keyDownAttached) {
44
+ element.removeEventListener("keydown", onKeyDown);
45
+ if (hadPreviousTabIndex) {
46
+ element.setAttribute("tabindex", previousTabIndex ?? "");
47
+ }
48
+ else {
49
+ element.removeAttribute("tabindex");
50
+ }
51
+ }
52
+ behavior.cleanup();
53
+ };
54
+ runtime.registerBindingCleanup({
55
+ cleanup,
56
+ isConnected: () => elementRef.deref()?.isConnected === true,
57
+ });
58
+ }
@@ -0,0 +1,19 @@
1
+ import { type DomDraggableKeyDownEvent, type DomDraggablePointerDownEvent } from "../draggable/create-draggable.js";
2
+ import { type DomSortableRuntime } from "./sortable-registry.js";
3
+ import type { SortableOptions } from "./sortable-options.js";
4
+ export type CreateDomSortableInput = SortableOptions & {
5
+ runtime: DomSortableRuntime;
6
+ draggableId: string;
7
+ group?: string;
8
+ containerId?: string | null;
9
+ getElement: () => HTMLElement | null;
10
+ keyboardDragEnabled?: boolean;
11
+ };
12
+ export type DomSortableBehavior = {
13
+ setElement: (element: HTMLElement | null) => void;
14
+ cleanup: () => void;
15
+ onPointerDown: (event: DomDraggablePointerDownEvent) => void;
16
+ onKeyDown: (event: DomDraggableKeyDownEvent) => void;
17
+ tabIndex: 0 | undefined;
18
+ };
19
+ export declare function createDomSortable(input: CreateDomSortableInput): DomSortableBehavior;
@@ -0,0 +1,55 @@
1
+ import { createDomDraggable, } from "../draggable/create-draggable.js";
2
+ import { getSortableRegistry, registerSortableElement, unregisterSortableElement, } from "./sortable-registry.js";
3
+ const defaultSortableGroup = "default";
4
+ export function createDomSortable(input) {
5
+ const group = input.group ?? defaultSortableGroup;
6
+ const registry = getSortableRegistry(input.runtime);
7
+ const draggable = createDomDraggable({
8
+ runtime: input.runtime,
9
+ draggableId: input.draggableId,
10
+ group,
11
+ getElement: input.getElement,
12
+ keyboardDragEnabled: input.keyboardDragEnabled,
13
+ });
14
+ let registeredElementRef = null;
15
+ let registeredDraggableId = null;
16
+ const cleanup = () => {
17
+ const registeredElement = registeredElementRef?.deref() ?? null;
18
+ unregisterSortableElement({
19
+ registry,
20
+ runtime: input.runtime,
21
+ draggableId: registeredDraggableId,
22
+ element: registeredElement,
23
+ });
24
+ registeredElementRef = null;
25
+ registeredDraggableId = null;
26
+ };
27
+ return {
28
+ setElement: (element) => {
29
+ const registeredElement = registeredElementRef?.deref() ?? null;
30
+ if (element === registeredElement &&
31
+ registeredDraggableId === input.draggableId) {
32
+ return;
33
+ }
34
+ cleanup();
35
+ if (!element) {
36
+ return;
37
+ }
38
+ registerSortableElement({
39
+ registry,
40
+ runtime: input.runtime,
41
+ draggableId: input.draggableId,
42
+ group,
43
+ containerId: input.containerId ?? null,
44
+ element,
45
+ options: input,
46
+ });
47
+ registeredElementRef = new WeakRef(element);
48
+ registeredDraggableId = input.draggableId;
49
+ },
50
+ cleanup,
51
+ onPointerDown: draggable.onPointerDown,
52
+ onKeyDown: draggable.onKeyDown,
53
+ tabIndex: draggable.tabIndex,
54
+ };
55
+ }
@@ -0,0 +1,17 @@
1
+ export type SortableAxis = "vertical" | "horizontal";
2
+ export type SortablePlacementBoundary = {
3
+ start?: number;
4
+ end?: number;
5
+ };
6
+ export type SortableOptions = {
7
+ axis?: SortableAxis;
8
+ placementBoundary?: SortablePlacementBoundary;
9
+ };
10
+ export type NormalizedSortableOptions = {
11
+ axis: SortableAxis;
12
+ placementBoundary: {
13
+ start: number;
14
+ end: number;
15
+ };
16
+ };
17
+ export declare function normalizeSortableOptions(options: SortableOptions | undefined): NormalizedSortableOptions;
@@ -0,0 +1,20 @@
1
+ const defaultSortableAxis = "vertical";
2
+ const defaultPlacementBoundary = {
3
+ start: 0.25,
4
+ end: 0.75,
5
+ };
6
+ export function normalizeSortableOptions(options) {
7
+ return {
8
+ axis: options?.axis === "horizontal" ? "horizontal" : defaultSortableAxis,
9
+ placementBoundary: {
10
+ start: normalizeBoundaryRatio(options?.placementBoundary?.start, defaultPlacementBoundary.start),
11
+ end: normalizeBoundaryRatio(options?.placementBoundary?.end, defaultPlacementBoundary.end),
12
+ },
13
+ };
14
+ }
15
+ function normalizeBoundaryRatio(value, defaultValue) {
16
+ if (value === undefined || !Number.isFinite(value)) {
17
+ return defaultValue;
18
+ }
19
+ return Math.min(1, Math.max(0, value));
20
+ }
@@ -0,0 +1,79 @@
1
+ import type { DomSortableRuntime, SortableRegistry } from "./sortable-registry.js";
2
+ import type { NormalizedSortableOptions, SortableAxis } from "./sortable-options.js";
3
+ export type SortablePlacementSide = "before" | "after";
4
+ export type SortableAxisMovementDirection = "forward" | "backward" | "none";
5
+ export type SortablePointerMovementState = {
6
+ previousPointerPosition: {
7
+ x: number;
8
+ y: number;
9
+ };
10
+ };
11
+ export type SortablePreviewPlacementState = {
12
+ activeDropTargetId: string | null;
13
+ placement: SortablePlacementSide | null;
14
+ movementDirection: SortableAxisMovementDirection;
15
+ };
16
+ export type SortablePreviewPlacementDecision = {
17
+ placement: SortablePlacementSide;
18
+ movementDirection: SortableAxisMovementDirection;
19
+ };
20
+ export declare function snapshotSortableElement(registry: SortableRegistry, draggableId: string): void;
21
+ export declare function isSortablePreviewTarget(input: {
22
+ activeDropTargetId: string | null;
23
+ }): boolean;
24
+ export declare function initializeSortablePointerMovement(registry: SortableRegistry, pointerPosition: {
25
+ x: number;
26
+ y: number;
27
+ }): void;
28
+ export declare function updateSortablePointerMovement(registry: SortableRegistry, pointerPosition: {
29
+ x: number;
30
+ y: number;
31
+ }): void;
32
+ export declare function clearSortablePointerMovement(registry: SortableRegistry): void;
33
+ export declare function clearSortablePreviewPlacement(registry: SortableRegistry): void;
34
+ export declare function moveSortablePreview(input: {
35
+ registry: SortableRegistry;
36
+ runtime: DomSortableRuntime;
37
+ draggedDraggableId: string;
38
+ activeDropTargetId: string | null;
39
+ pointerPosition: {
40
+ x: number;
41
+ y: number;
42
+ };
43
+ placementPosition: {
44
+ x: number;
45
+ y: number;
46
+ };
47
+ options: NormalizedSortableOptions;
48
+ }): void;
49
+ export declare function getSortablePreviewPlacement(input: {
50
+ activeDropTargetId: string;
51
+ targetElement: HTMLElement;
52
+ placementPosition: {
53
+ x: number;
54
+ y: number;
55
+ };
56
+ movement: SortablePointerMovementState | null;
57
+ previewPlacement: SortablePreviewPlacementState | null;
58
+ options: NormalizedSortableOptions;
59
+ }): SortablePreviewPlacementDecision;
60
+ export declare function isSortablePreviewAlreadyPlaced(input: {
61
+ draggedElement: HTMLElement;
62
+ targetElement: HTMLElement;
63
+ placement: SortablePlacementSide;
64
+ }): boolean;
65
+ export declare function restoreSortableSnapshot(registry: SortableRegistry, draggableId: string): boolean;
66
+ export declare function clearSortableDraggedState(registry: SortableRegistry, draggableId: string): void;
67
+ export declare function getAxisPosition(pointerPosition: {
68
+ x: number;
69
+ y: number;
70
+ }, axis: SortableAxis): number;
71
+ export declare function getAxisMovementDirection(previousAxisPosition: number, currentAxisPosition: number): SortableAxisMovementDirection;
72
+ export declare function getPlacementBoundary(input: {
73
+ targetRect: DOMRect;
74
+ axis: SortableAxis;
75
+ direction: SortableAxisMovementDirection;
76
+ startRatio: number;
77
+ endRatio: number;
78
+ }): number;
79
+ export declare function getPlacementSideFromBoundary(axisPosition: number, boundary: number): SortablePlacementSide;