@mk-drag-and-drop/dom 0.2.0 → 0.3.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/README.md
CHANGED
|
@@ -36,6 +36,8 @@ The root export includes:
|
|
|
36
36
|
- `createDropContainer`
|
|
37
37
|
- `createSortable`
|
|
38
38
|
- `createDragHandle`
|
|
39
|
+
- controller types: `DragController`, `DragControllerOptions`,
|
|
40
|
+
`DragControllerOverlayInput`, `DragControllerAnnouncements`
|
|
39
41
|
- lifecycle types: `DragStartEvent`, `DragUpdateEvent`, `DragEndEvent`,
|
|
40
42
|
`DropEvent`, `DragSource`, `DragEndResult`, `DragLifecycleCallbacks`,
|
|
41
43
|
`DragLifecycleHelpers`
|
|
@@ -94,6 +96,8 @@ The returned controller has:
|
|
|
94
96
|
|
|
95
97
|
- `remeasureDropTargets(input?)`: remeasures all targets, one target id, an
|
|
96
98
|
array of target ids, or `{ group }`
|
|
99
|
+
- `remeasureOverlay()`: remeasures the currently mounted drag overlay element;
|
|
100
|
+
it is a safe no-op when no overlay is mounted or no drag is active
|
|
97
101
|
|
|
98
102
|
The controller does not expose runtime teardown, disposal, update, or broad
|
|
99
103
|
overlay removal methods. Runtime objects are ordinary JavaScript objects; DOM
|
|
@@ -108,6 +112,14 @@ controller calls `dragOverlay` once more for the `"released"` phase and passes
|
|
|
108
112
|
`removeOverlay`; call that function when app-owned release animation is done.
|
|
109
113
|
Pointer movement does not call `dragOverlay`.
|
|
110
114
|
|
|
115
|
+
The overlay input includes:
|
|
116
|
+
|
|
117
|
+
- `dragState`: item id, group, source rect, start pointer, and current pointer.
|
|
118
|
+
- `phase`: `"dragging"` or `"released"`.
|
|
119
|
+
- `remeasureOverlay`: manually refreshes the cached overlay measurement.
|
|
120
|
+
- `removeOverlay`: present only for `"released"` overlays in manual release
|
|
121
|
+
mode; call it when app-owned release animation should remove the overlay.
|
|
122
|
+
|
|
111
123
|
`removeOverlay` is only present for released overlays in manual release mode.
|
|
112
124
|
Calling it more than once is safe. It removes the overlay host state only; it is
|
|
113
125
|
not a controller or runtime teardown API.
|
|
@@ -121,7 +133,31 @@ from the current pointer delta.
|
|
|
121
133
|
The controller measures the returned overlay element on mount/replacement. When
|
|
122
134
|
`ResizeObserver` is available, it also remeasures when that element changes
|
|
123
135
|
size. The runtime derives the current overlay rect from that cached measurement
|
|
124
|
-
plus pointer movement
|
|
136
|
+
plus modified pointer movement, and it does not measure overlay DOM on every
|
|
137
|
+
pointer move.
|
|
138
|
+
|
|
139
|
+
Manual `remeasureOverlay()` is for cases automatic observation cannot cover or
|
|
140
|
+
where the app knows visual geometry changed. CSS transforms can change visual
|
|
141
|
+
bounds without necessarily triggering `ResizeObserver`.
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
controller.remeasureOverlay();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const controller = createDragController({
|
|
149
|
+
dragOverlay({ dragState, remeasureOverlay }) {
|
|
150
|
+
const element = document.createElement("div");
|
|
151
|
+
element.textContent = dragState.draggableId;
|
|
152
|
+
|
|
153
|
+
element.addEventListener("transitionend", () => {
|
|
154
|
+
remeasureOverlay();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return element;
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
```
|
|
125
161
|
|
|
126
162
|
For dynamic overlay content, keep a reference to the element and update it from
|
|
127
163
|
lifecycle callbacks or subscriptions:
|
|
@@ -164,6 +200,7 @@ type DragUpdateEvent = {
|
|
|
164
200
|
draggableId: string;
|
|
165
201
|
source: DragSource;
|
|
166
202
|
pointerPosition: DragPoint;
|
|
203
|
+
overlayRect: DragRect | null;
|
|
167
204
|
activeDropTargetId: string | null;
|
|
168
205
|
previousDropTargetId: string | null;
|
|
169
206
|
};
|
|
@@ -181,6 +218,7 @@ type DragEndEvent = {
|
|
|
181
218
|
source: DragSource;
|
|
182
219
|
result: DragEndResult;
|
|
183
220
|
dropTargetId: string | null;
|
|
221
|
+
overlayRect: DragRect | null;
|
|
184
222
|
};
|
|
185
223
|
|
|
186
224
|
type DropEvent = {
|
|
@@ -200,6 +238,14 @@ type SortableDropPlacement = {
|
|
|
200
238
|
};
|
|
201
239
|
```
|
|
202
240
|
|
|
241
|
+
`DragUpdateEvent.overlayRect` is the current viewport-space rectangle for the
|
|
242
|
+
drag overlay. `DragEndEvent.overlayRect` is the final viewport-space rectangle
|
|
243
|
+
at the moment the drag ends. Both are `null` when no drag overlay is configured.
|
|
244
|
+
When an overlay is configured, the runtime uses cached overlay measurement plus
|
|
245
|
+
modified pointer movement. Before overlay content has been measured, it uses the
|
|
246
|
+
same translated source-rect fallback as the visual overlay. The drag update and
|
|
247
|
+
drag end paths do not read overlay DOM just to produce this field.
|
|
248
|
+
|
|
203
249
|
Helpers:
|
|
204
250
|
|
|
205
251
|
- `getDropTargetRect(dropTargetId)`
|
|
@@ -339,8 +385,14 @@ modifier state.
|
|
|
339
385
|
## Measurement
|
|
340
386
|
|
|
341
387
|
Targets are measured when registered and remeasured at drag start. The explicit
|
|
342
|
-
remeasurement entry point is `controller.remeasureDropTargets(input?)`;
|
|
343
|
-
when app-owned layout changes during a drag should affect targeting.
|
|
388
|
+
target remeasurement entry point is `controller.remeasureDropTargets(input?)`;
|
|
389
|
+
call it when app-owned layout changes during a drag should affect targeting.
|
|
390
|
+
|
|
391
|
+
Overlay measurement is separate from target measurement. Overlay content is
|
|
392
|
+
measured on mount/replacement and by `ResizeObserver` when available. Use
|
|
393
|
+
`controller.remeasureOverlay()` when the current overlay geometry should be
|
|
394
|
+
refreshed manually, such as after an app-owned transition or transform that
|
|
395
|
+
changes visual bounds without a normal size-observer notification.
|
|
344
396
|
|
|
345
397
|
`RemeasureDropTargetsInput` accepts:
|
|
346
398
|
|
|
@@ -13,10 +13,12 @@ export type DragControllerAnnouncements = {
|
|
|
13
13
|
export type DragControllerOverlayInput = {
|
|
14
14
|
dragState: DragState;
|
|
15
15
|
phase: "dragging";
|
|
16
|
+
remeasureOverlay: () => void;
|
|
16
17
|
removeOverlay?: never;
|
|
17
18
|
} | {
|
|
18
19
|
dragState: DragState;
|
|
19
20
|
phase: "released";
|
|
21
|
+
remeasureOverlay: () => void;
|
|
20
22
|
removeOverlay: () => void;
|
|
21
23
|
};
|
|
22
24
|
export type DragControllerOptions = {
|
|
@@ -32,5 +34,6 @@ export type DragControllerOptions = {
|
|
|
32
34
|
} & DragLifecycleCallbacks;
|
|
33
35
|
export type DragController = {
|
|
34
36
|
remeasureDropTargets: (input?: RemeasureDropTargetsInput) => void;
|
|
37
|
+
remeasureOverlay: () => void;
|
|
35
38
|
};
|
|
36
39
|
export declare function createDragController(options?: DragControllerOptions): DragController;
|
|
@@ -22,6 +22,7 @@ export function createDragController(options = {}) {
|
|
|
22
22
|
remeasureDropTargets: (input) => {
|
|
23
23
|
runtime.remeasureDropTargets(input);
|
|
24
24
|
},
|
|
25
|
+
remeasureOverlay,
|
|
25
26
|
};
|
|
26
27
|
setControllerRuntime(controller, runtime);
|
|
27
28
|
return controller;
|
|
@@ -124,6 +125,9 @@ export function createDragController(options = {}) {
|
|
|
124
125
|
}
|
|
125
126
|
runtime.setOverlayRect(rectToDragRect(overlayElement.getBoundingClientRect()));
|
|
126
127
|
}
|
|
128
|
+
function remeasureOverlay() {
|
|
129
|
+
measureOverlayElement();
|
|
130
|
+
}
|
|
127
131
|
function disconnectOverlayResizeObserver() {
|
|
128
132
|
overlayResizeObserver?.disconnect();
|
|
129
133
|
overlayResizeObserver = null;
|
|
@@ -149,12 +153,14 @@ export function createDragController(options = {}) {
|
|
|
149
153
|
return {
|
|
150
154
|
dragState: overlayState.dragState,
|
|
151
155
|
phase: "released",
|
|
156
|
+
remeasureOverlay,
|
|
152
157
|
removeOverlay: clearOverlayHost,
|
|
153
158
|
};
|
|
154
159
|
}
|
|
155
160
|
return {
|
|
156
161
|
dragState: overlayState.dragState,
|
|
157
162
|
phase: "dragging",
|
|
163
|
+
remeasureOverlay,
|
|
158
164
|
};
|
|
159
165
|
}
|
|
160
166
|
function syncLiveRegion() {
|
|
@@ -221,6 +221,7 @@ export class DragRuntime {
|
|
|
221
221
|
draggableId: nextSession.draggableId,
|
|
222
222
|
source: nextSession.source,
|
|
223
223
|
pointerPosition,
|
|
224
|
+
overlayRect,
|
|
224
225
|
activeDropTargetId: nextSession.activeDropTargetId,
|
|
225
226
|
previousDropTargetId,
|
|
226
227
|
};
|
|
@@ -499,6 +500,9 @@ export class DragRuntime {
|
|
|
499
500
|
? "dropped"
|
|
500
501
|
: "invalid-target"
|
|
501
502
|
: null;
|
|
503
|
+
const overlayRect = session && this.hasDragOverlay
|
|
504
|
+
? this.getCurrentDragRectAt(session.pointerPosition)
|
|
505
|
+
: null;
|
|
502
506
|
const sortablePlacement = session && dropTargetId
|
|
503
507
|
? this.getDropEventSortablePlacement(session, dropTargetId)
|
|
504
508
|
: undefined;
|
|
@@ -525,6 +529,7 @@ export class DragRuntime {
|
|
|
525
529
|
draggableId: session.draggableId,
|
|
526
530
|
source: session.source,
|
|
527
531
|
result,
|
|
532
|
+
overlayRect,
|
|
528
533
|
dropTargetId,
|
|
529
534
|
});
|
|
530
535
|
if (result === "dropped" && dropTargetId) {
|
|
@@ -12,6 +12,7 @@ export type DragUpdateEvent = {
|
|
|
12
12
|
draggableId: string;
|
|
13
13
|
source: DragSource;
|
|
14
14
|
pointerPosition: DragPoint;
|
|
15
|
+
overlayRect: DragRect | null;
|
|
15
16
|
activeDropTargetId: string | null;
|
|
16
17
|
previousDropTargetId: string | null;
|
|
17
18
|
};
|
|
@@ -19,6 +20,7 @@ export type DragEndEvent = {
|
|
|
19
20
|
draggableId: string;
|
|
20
21
|
source: DragSource;
|
|
21
22
|
result: DragEndResult;
|
|
23
|
+
overlayRect: DragRect | null;
|
|
22
24
|
dropTargetId: string | null;
|
|
23
25
|
};
|
|
24
26
|
export type DropEvent = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mk-drag-and-drop/dom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Headless DOM drag-and-drop primitives for draggable, droppable, sortable, and grouped interactions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://mkramer.dev",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"files": [
|
|
42
42
|
"dist"
|
|
43
43
|
],
|
|
44
|
+
"sideEffects": false,
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"eslint": "^8.57.0",
|
|
46
47
|
"jsdom": "^24.1.3",
|