dnd-manager 1.1.0 → 1.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/CHANGELOG.md +25 -0
- package/LICENSE +0 -0
- package/README.md +286 -761
- package/dist/index.d.mts +162 -20
- package/dist/index.mjs +480 -75
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -15
package/dist/index.d.mts
CHANGED
|
@@ -18,6 +18,24 @@ type DragDropConfig = {
|
|
|
18
18
|
* dragThreshold: 15 // Harder to start drag (better for mobile scroll)
|
|
19
19
|
*/
|
|
20
20
|
dragThreshold?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Milliseconds a press must be held, moving at most `dragDelayTolerance`, before it becomes a
|
|
23
|
+
* drag: a long press, so a touch list still scrolls under a swiping finger. A number applies to
|
|
24
|
+
* every pointer type; an object sets it per type (`{ touch: 250 }`: a mouse still drags at once).
|
|
25
|
+
* Moving further during the delay releases the press and leaves the gesture to the browser. Once
|
|
26
|
+
* the delay passes the drag starts at once, without waiting for a move.
|
|
27
|
+
* @default 0
|
|
28
|
+
*/
|
|
29
|
+
dragDelay?: number | {
|
|
30
|
+
mouse?: number;
|
|
31
|
+
pen?: number;
|
|
32
|
+
touch?: number;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Pixels a press may move during `dragDelay` before it is released.
|
|
36
|
+
* @default 5
|
|
37
|
+
*/
|
|
38
|
+
dragDelayTolerance?: number;
|
|
21
39
|
/**
|
|
22
40
|
* Maximum distance in pixels between pointerdown and pointerup to treat as a click/tap.
|
|
23
41
|
* Used to distinguish intentional clicks from cancelled drag attempts.
|
|
@@ -29,8 +47,11 @@ type DragDropConfig = {
|
|
|
29
47
|
*/
|
|
30
48
|
clickThreshold?: number;
|
|
31
49
|
/**
|
|
32
|
-
* Distance in pixels from
|
|
33
|
-
*
|
|
50
|
+
* Distance in pixels from an edge that triggers auto-scrolling during drag.
|
|
51
|
+
* Near an edge of the closest scroll container under the pointer that can still scroll that way
|
|
52
|
+
* (an `overflow: auto | scroll` element), that container scrolls; its zone is at most a quarter
|
|
53
|
+
* of its size. Otherwise the window scrolls near the viewport's edges. Scrolling continues while
|
|
54
|
+
* the pointer rests in the zone.
|
|
34
55
|
* @default 100
|
|
35
56
|
* @example
|
|
36
57
|
* scrollThreshold: 50 // Start scrolling closer to edges
|
|
@@ -38,8 +59,8 @@ type DragDropConfig = {
|
|
|
38
59
|
*/
|
|
39
60
|
scrollThreshold?: number;
|
|
40
61
|
/**
|
|
41
|
-
* Scroll speed in pixels per animation frame during auto-scroll.
|
|
42
|
-
* Higher values = faster scrolling when dragging near
|
|
62
|
+
* Scroll speed in pixels per animation frame during auto-scroll (`0` disables it).
|
|
63
|
+
* Higher values = faster scrolling when dragging near edges.
|
|
43
64
|
* @default 10
|
|
44
65
|
* @example
|
|
45
66
|
* scrollSpeed: 5 // Slower, smoother scroll
|
|
@@ -59,34 +80,79 @@ type DragDropConfig = {
|
|
|
59
80
|
*/
|
|
60
81
|
cancelOnPointerLeave?: boolean;
|
|
61
82
|
/**
|
|
62
|
-
* The `data-kind`
|
|
63
|
-
*
|
|
83
|
+
* The `data-kind` value(s) for draggable elements.
|
|
84
|
+
* Can be a single kind or multiple kinds.
|
|
85
|
+
* Each draggable element should still expose a single `data-kind` value.
|
|
64
86
|
* @example
|
|
65
87
|
* draggableKind: 'cell' // <div data-kind="cell">
|
|
88
|
+
* draggableKind: ['quest', 'bounty'] // <div data-kind="quest">
|
|
66
89
|
* draggableKind: 'card' // <div data-kind="card">
|
|
67
90
|
* draggableKind: 'list-item' // <div data-kind="list-item">
|
|
68
91
|
*/
|
|
69
|
-
draggableKind: string;
|
|
92
|
+
draggableKind: string | string[];
|
|
70
93
|
/**
|
|
71
|
-
* The `data-kind`
|
|
72
|
-
*
|
|
94
|
+
* The `data-kind` value(s) for droppable target elements.
|
|
95
|
+
* Can be a single kind or multiple kinds.
|
|
96
|
+
* Elements with matching kinds can receive dropped items.
|
|
97
|
+
* Each droppable element should still expose a single `data-kind` value.
|
|
73
98
|
* Often the same as `draggableKind` for reorderable lists.
|
|
74
99
|
* @example
|
|
75
100
|
* droppableKind: 'cell' // Can drop on cells
|
|
101
|
+
* droppableKind: ['quest', 'bounty'] // Can drop on either kind
|
|
76
102
|
* droppableKind: 'zone' // Can drop on zones
|
|
77
103
|
*/
|
|
78
|
-
droppableKind: string;
|
|
104
|
+
droppableKind: string | string[];
|
|
105
|
+
/**
|
|
106
|
+
* Where droppables are looked for under the pointer.
|
|
107
|
+
* - `'document'`: anywhere in the page, so items can move to another manager's container (a box
|
|
108
|
+
* and a party panel each with its own manager).
|
|
109
|
+
* - `'container'`: only inside this manager's container, for independent widgets on one page
|
|
110
|
+
* that share kinds.
|
|
111
|
+
* @default 'document'
|
|
112
|
+
*/
|
|
113
|
+
dropScope?: 'document' | 'container';
|
|
114
|
+
/**
|
|
115
|
+
* Keyboard pick-and-place. Space or Enter on a focused draggable (make it focusable: a
|
|
116
|
+
* `<button>`, or `tabindex="0"`) picks it up; the arrow keys move the target to the nearest
|
|
117
|
+
* droppable in that direction (scrolled into view); Space or Enter drops there (ignored on a
|
|
118
|
+
* target `canDrop` rejects); Escape cancels (whatever `cancelOnEscape` says), and so do Tab and
|
|
119
|
+
* focus leaving the source. The callbacks fire as for a pointer drag, `onDragMove` with the
|
|
120
|
+
* target's center. Announce the moves from them in an `aria-live` region.
|
|
121
|
+
* @default false
|
|
122
|
+
*/
|
|
123
|
+
keyboard?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Let a press focus the draggable, as a click would. By default the manager cancels the
|
|
126
|
+
* `pointerdown`, which keeps the browser from selecting text or dragging an image natively, but
|
|
127
|
+
* also from moving focus. With `true` it cancels `selectstart` and `dragstart` during the press
|
|
128
|
+
* instead: the source is focused (no focus ring for a mouse, per `:focus-visible`), so focus
|
|
129
|
+
* styles, keyboard follow-ups and a virtual list that keeps its focused row rendered all work.
|
|
130
|
+
* @default false
|
|
131
|
+
*/
|
|
132
|
+
focusOnPress?: boolean;
|
|
79
133
|
};
|
|
80
134
|
type PointerPosition = {
|
|
81
135
|
x: number;
|
|
82
136
|
y: number;
|
|
83
137
|
};
|
|
138
|
+
/** Result passed to onDragEnd when the item was dropped on a valid target; null when drag was cancelled or dropped on invalid target. */
|
|
139
|
+
type DragEndResult<TItem, TPosition> = {
|
|
140
|
+
sourcePosition: TPosition;
|
|
141
|
+
targetPosition: TPosition;
|
|
142
|
+
sourceItem: TItem;
|
|
143
|
+
};
|
|
84
144
|
type DragDropCallbacks<TItem, TPosition> = {
|
|
85
|
-
/** Called when determining if an element can be dragged */canDrag?: (element: HTMLElement, position: TPosition) => boolean;
|
|
86
|
-
|
|
145
|
+
/** Called when determining if an element can be dragged */canDrag?: (element: HTMLElement, position: TPosition) => boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Called for the droppable under the pointer on every drag frame, and again at the drop: return
|
|
148
|
+
* `false` to reject it. A rejected droppable gets `data-drop-invalid` instead of `data-hovered`,
|
|
149
|
+
* and a drop on it ends the drag with `onDragEnd(null)`. Keep it cheap.
|
|
150
|
+
*/
|
|
151
|
+
canDrop?: (sourcePosition: TPosition, targetPosition: TPosition, sourceItem: TItem) => boolean; /** Called when drag starts (after threshold is met) */
|
|
152
|
+
onDragStart?: (element: HTMLElement, position: TPosition, item: TItem) => void; /** Called continuously during drag, with the droppable that would receive a drop (or null) */
|
|
87
153
|
onDragMove?: (pos: PointerPosition, hoveredElement: HTMLElement | null) => void; /** Called when item is dropped on a valid target */
|
|
88
|
-
onDrop?: (sourcePosition: TPosition, targetPosition: TPosition, sourceItem: TItem) => void; /** Called when drag ends (
|
|
89
|
-
onDragEnd?: () => void; /** Called on simple click/tap (no drag) */
|
|
154
|
+
onDrop?: (sourcePosition: TPosition, targetPosition: TPosition, sourceItem: TItem) => void; /** Called when drag ends (success or cancel). Receives drop result when dropped on valid target, null otherwise. Use for reordering DOM/state and cleanup. */
|
|
155
|
+
onDragEnd?: (result: DragEndResult<TItem, TPosition> | null) => void; /** Called on simple click/tap (no drag) */
|
|
90
156
|
onClick?: (element: HTMLElement, position: TPosition) => void; /** Called to extract item data from an element */
|
|
91
157
|
getItemData?: (element: HTMLElement, position: TPosition) => TItem | null; /** Called to get the custom position/coordinates of an element */
|
|
92
158
|
getItemPosition: (element: HTMLElement, kind: string) => TPosition | null;
|
|
@@ -96,36 +162,112 @@ type DragState<TItem, TPosition> = {
|
|
|
96
162
|
sourceElement: HTMLElement | null;
|
|
97
163
|
sourcePosition: TPosition | null;
|
|
98
164
|
sourceItem: TItem | null;
|
|
99
|
-
activePointerId: number | null;
|
|
165
|
+
activePointerId: number | null; /** What drives the current press or drag. */
|
|
166
|
+
input: 'pointer' | 'keyboard' | null;
|
|
100
167
|
isDragging: boolean;
|
|
101
|
-
lastHoveredElement: HTMLElement | null;
|
|
168
|
+
lastHoveredElement: HTMLElement | null; /** The droppable under the pointer that `canDrop` rejected (marked `data-drop-invalid`). */
|
|
169
|
+
lastInvalidElement: HTMLElement | null; /** Set when drop on valid target; passed to onDragEnd in cleanup */
|
|
170
|
+
lastDropResult: DragEndResult<TItem, TPosition> | null;
|
|
102
171
|
};
|
|
103
172
|
declare class DragDropManager<TItem = unknown, TPosition = unknown> {
|
|
104
173
|
private container;
|
|
105
174
|
private config;
|
|
175
|
+
private draggableKinds;
|
|
176
|
+
private droppableKinds;
|
|
106
177
|
private callbacks;
|
|
107
178
|
private state;
|
|
108
179
|
private rafId;
|
|
109
180
|
private lastPointerPos;
|
|
181
|
+
/**
|
|
182
|
+
* Set while a drag holds the pointer down: the browser follows the release with a native
|
|
183
|
+
* `click` (on the source element under pointer capture), which must not activate it.
|
|
184
|
+
*/
|
|
185
|
+
private suppressClickOnRelease;
|
|
186
|
+
private releaseClickBlocker;
|
|
187
|
+
/** The pending `dragDelay` of the current press. */
|
|
188
|
+
private delayTimer;
|
|
189
|
+
private activePointerType;
|
|
190
|
+
/** The droppable a keyboard drag points at. */
|
|
191
|
+
private keyboardTarget;
|
|
192
|
+
/**
|
|
193
|
+
* The key that picked up or dropped: its `keyup` would activate a focused button (Space clicks
|
|
194
|
+
* on keyup), so it is swallowed.
|
|
195
|
+
*/
|
|
196
|
+
private swallowKeyUp;
|
|
110
197
|
private boundHandlers;
|
|
111
198
|
constructor(containerRef: {
|
|
112
199
|
current: HTMLElement | null;
|
|
113
200
|
} | string | HTMLElement, config: DragDropConfig, callbacks: DragDropCallbacks<TItem, TPosition>);
|
|
114
201
|
private attachListeners;
|
|
202
|
+
/**
|
|
203
|
+
* The source position and item of the draggable `match`, if it may be dragged: it has a
|
|
204
|
+
* position, is not `data-empty`, `canDrag` allows it and it has item data.
|
|
205
|
+
*/
|
|
206
|
+
private resolveSource;
|
|
115
207
|
private handlePointerDown;
|
|
116
208
|
private handlePointerMove;
|
|
209
|
+
private startDrag;
|
|
210
|
+
/** The `dragDelay` for a pointer type (`''` from a constructed event counts as a mouse). */
|
|
211
|
+
private delayFor;
|
|
212
|
+
/**
|
|
213
|
+
* Once a touch press is a drag, the finger moves the item, not the page: a browser that starts
|
|
214
|
+
* panning would cancel the pointer. Before that, touches stay the browser's.
|
|
215
|
+
*/
|
|
216
|
+
private handleTouchMove;
|
|
217
|
+
/**
|
|
218
|
+
* The press's pointer events, heard on the source itself. While it is in the DOM they also reach
|
|
219
|
+
* the window's listeners, which handle them; once it is detached only these hear them.
|
|
220
|
+
*/
|
|
221
|
+
private handleDetachedSourcePointer;
|
|
222
|
+
/** A long press opens no context menu (Android, iOS) while it is a drag or about to be one. */
|
|
223
|
+
private handleContextMenu;
|
|
224
|
+
private scheduleFrame;
|
|
225
|
+
/** One drag frame: hover feedback, auto-scroll and `onDragMove` at the latest pointer position. */
|
|
226
|
+
private runFrame;
|
|
117
227
|
private handlePointerUp;
|
|
118
228
|
private handlePointerCancel;
|
|
119
229
|
private handleKeyDown;
|
|
120
230
|
private handleMouseOut;
|
|
121
|
-
|
|
231
|
+
/** Space or Enter on a focused draggable picks it up (`keyboard: true`). */
|
|
232
|
+
private handlePickUpKey;
|
|
233
|
+
/** The keys of a keyboard drag, ahead of anything else on the page. */
|
|
234
|
+
private handleKeyboardDragKey;
|
|
235
|
+
private handleKeyUp;
|
|
236
|
+
/** Focus leaving the source (Tab, a click elsewhere) cancels a keyboard drag. */
|
|
237
|
+
private handleFocusOut;
|
|
238
|
+
/** Makes `match` the keyboard drag's target: marked, scrolled into view, sent to `onDragMove`. */
|
|
239
|
+
private pointKeyboardAt;
|
|
240
|
+
/**
|
|
241
|
+
* The droppable nearest the current target (or the source) in a direction: its center lies that
|
|
242
|
+
* way, and it is closest along the axis, with distance across the axis counting double, so the
|
|
243
|
+
* next cell in the same row or column wins over a diagonal one.
|
|
244
|
+
*/
|
|
245
|
+
private nearestDroppable;
|
|
246
|
+
/** Drops a keyboard drag on its target, unless there is none or `canDrop` rejects it. */
|
|
247
|
+
private dropWithKeyboard;
|
|
248
|
+
/**
|
|
249
|
+
* Swallows the `click` the browser dispatches right after the release that ended a drag, in the
|
|
250
|
+
* same task; a timeout lets the blocker go when no click comes.
|
|
251
|
+
*/
|
|
252
|
+
private blockNextClick;
|
|
122
253
|
private cleanup;
|
|
123
254
|
private getPointerId;
|
|
124
255
|
private isActivePointer;
|
|
256
|
+
private normalizeKindList;
|
|
257
|
+
/** The target position of the droppable `match` if the current source may drop there. */
|
|
258
|
+
private acceptedPosition;
|
|
259
|
+
/**
|
|
260
|
+
* Marks the droppable under the pointer: `data-hovered` when it would receive a drop (also the
|
|
261
|
+
* source itself, for "drag over itself" styling), `data-drop-invalid` when `canDrop` rejects it.
|
|
262
|
+
* Without `canDrop` every droppable is marked hovered.
|
|
263
|
+
*/
|
|
264
|
+
private markTarget;
|
|
265
|
+
/** The droppable around `element` (the one under the pointer), within `dropScope`. */
|
|
266
|
+
private findDroppable;
|
|
125
267
|
/**
|
|
126
|
-
* Find closest ancestor element with
|
|
268
|
+
* Find closest ancestor element with a `data-kind` matching any expected kind.
|
|
127
269
|
*/
|
|
128
|
-
private
|
|
270
|
+
private findElementByKinds;
|
|
129
271
|
/**
|
|
130
272
|
* Calculate distance between two points
|
|
131
273
|
*/
|
|
@@ -163,5 +305,5 @@ declare class DragPreviewController {
|
|
|
163
305
|
destroy(): void;
|
|
164
306
|
}
|
|
165
307
|
//#endregion
|
|
166
|
-
export { type DragDropCallbacks, type DragDropConfig, DragDropManager, DragPreviewController, type DragPreviewControllerOptions, type PointerPosition };
|
|
308
|
+
export { type DragDropCallbacks, type DragDropConfig, DragDropManager, type DragEndResult, DragPreviewController, type DragPreviewControllerOptions, type PointerPosition };
|
|
167
309
|
//# sourceMappingURL=index.d.mts.map
|