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/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 viewport edge that triggers auto-scrolling during drag.
33
- * When dragging near screen edges, the window automatically scrolls.
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 viewport edges.
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` attribute value for draggable elements.
63
- * Elements with this attribute can be picked up and dragged.
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` attribute value for droppable target elements.
72
- * Elements with this attribute can receive dropped items.
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; /** Called when drag starts (after threshold is met) */
86
- onDragStart?: (element: HTMLElement, position: TPosition, item: TItem) => void; /** Called continuously during drag */
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 (regardless of success) */
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
- private handleAutoScroll;
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 matching data-kind attribute
268
+ * Find closest ancestor element with a `data-kind` matching any expected kind.
127
269
  */
128
- private findElementByKind;
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