@dnd-kit/dom 0.0.1

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/index.js ADDED
@@ -0,0 +1,1295 @@
1
+ import { Sensor, configurator, Plugin, CorePlugin, DragDropManager as DragDropManager$1, Draggable as Draggable$1, descriptor, Droppable as Droppable$1 } from '@dnd-kit/abstract';
2
+ import { effect, batch, effects, untracked, reactive, computed, deepEqual, signal } from '@dnd-kit/state';
3
+ import { ScrollDirection, Listeners, getDocument, DOMRectangle, Styles, getWindow, createPlaceholder, isKeyboardEvent, supportsPopover, showPopover, supportsStyle, animateTransform, canScroll, detectScrollIntent, scheduler, getScrollableAncestors, scrollIntoViewIfNeeded, getFirstScrollableAncestor } from '@dnd-kit/dom/utilities';
4
+ import { exceedsDistance, Axes } from '@dnd-kit/geometry';
5
+ import { defaultCollisionDetection } from '@dnd-kit/collision';
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __decorateClass = (decorators, target, key, kind) => {
9
+ var result = void 0 ;
10
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
11
+ if (decorator = decorators[i])
12
+ result = (decorator(target, key, result) ) || result;
13
+ if (result)
14
+ __defProp(target, key, result);
15
+ return result;
16
+ };
17
+
18
+ // src/core/plugins/accessibility/defaults.ts
19
+ var defaultAttributes = {
20
+ role: "button",
21
+ roleDescription: "draggable",
22
+ tabIndex: 0
23
+ };
24
+ var defaultDescriptionIdPrefix = `dnd-kit-description`;
25
+ var defaultAnnouncementIdPrefix = `dnd-kit-announcement`;
26
+ var defaultScreenReaderInstructions = {
27
+ draggable: `To pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item in a given direction. Press space again to drop the item in its new position, or press escape to cancel.`
28
+ };
29
+ var defaultAnnouncements = {
30
+ dragstart({ operation: { source } }) {
31
+ if (!source)
32
+ return;
33
+ return `Picked up draggable item ${source.id}.`;
34
+ },
35
+ dragover({ operation: { source, target } }) {
36
+ if (!source)
37
+ return;
38
+ if (target) {
39
+ return `Draggable item ${source.id} was moved over droppable target ${target.id}.`;
40
+ }
41
+ return `Draggable item ${source.id} is no longer over a droppable target.`;
42
+ },
43
+ dragend({ operation: { source, target }, canceled }) {
44
+ if (!source)
45
+ return;
46
+ if (canceled) {
47
+ return `Dragging was cancelled. Draggable item ${source.id} was dropped.`;
48
+ }
49
+ if (target) {
50
+ return `Draggable item ${source.id} was dropped over droppable target ${target.id}`;
51
+ }
52
+ return `Draggable item ${source.id} was dropped.`;
53
+ }
54
+ };
55
+
56
+ // src/core/plugins/accessibility/utilities.ts
57
+ function isFocusable(element) {
58
+ return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement || element instanceof HTMLAnchorElement || element instanceof HTMLButtonElement || element instanceof HTMLAreaElement;
59
+ }
60
+ var ids = {};
61
+ function generateUniqueId(prefix) {
62
+ const id = ids[prefix] == null ? 0 : ids[prefix] + 1;
63
+ ids[prefix] = id;
64
+ return `${prefix}-${id}`;
65
+ }
66
+
67
+ // src/core/plugins/accessibility/HiddenText.ts
68
+ function createHiddenText(id, value) {
69
+ const element = document.createElement("div");
70
+ element.id = id;
71
+ element.style.setProperty("display", "none");
72
+ element.innerText = value;
73
+ return element;
74
+ }
75
+
76
+ // src/core/plugins/accessibility/LiveRegion.ts
77
+ function createLiveRegion(id) {
78
+ const element = document.createElement("div");
79
+ element.id = id;
80
+ element.setAttribute("role", "status");
81
+ element.setAttribute("aria-live", "polite");
82
+ element.setAttribute("aria-atomic", "true");
83
+ element.style.setProperty("position", "fixed");
84
+ element.style.setProperty("width", "1px");
85
+ element.style.setProperty("height", "1px");
86
+ element.style.setProperty("margin", "-1px");
87
+ element.style.setProperty("border", "0");
88
+ element.style.setProperty("padding", "0");
89
+ element.style.setProperty("overflow", "hidden");
90
+ element.style.setProperty("clip", "rect(0 0 0 0)");
91
+ element.style.setProperty("clip-path", "inset(100%)");
92
+ element.style.setProperty("white-space", "nowrap");
93
+ return element;
94
+ }
95
+
96
+ // src/core/plugins/accessibility/Accessibility.ts
97
+ var Accessibility = class extends Plugin {
98
+ constructor(manager, options) {
99
+ super(manager);
100
+ const {
101
+ id,
102
+ idPrefix: {
103
+ description: descriptionPrefix = defaultDescriptionIdPrefix,
104
+ announcement: announcementPrefix = defaultAnnouncementIdPrefix
105
+ } = {},
106
+ announcements = defaultAnnouncements,
107
+ screenReaderInstructions = defaultScreenReaderInstructions
108
+ } = options ?? {};
109
+ const descriptionId = id ? `${descriptionPrefix}-${id}` : generateUniqueId(descriptionPrefix);
110
+ const announcementId = id ? `${announcementPrefix}-${id}` : generateUniqueId(announcementPrefix);
111
+ let hiddenTextElement;
112
+ let liveRegionElement;
113
+ const eventListeners = Object.entries(announcements).map(
114
+ ([eventName, getAnnouncement]) => {
115
+ return this.manager.monitor.addEventListener(
116
+ eventName,
117
+ (event, manager2) => {
118
+ const announcement = getAnnouncement?.(event, manager2);
119
+ if (announcement && liveRegionElement) {
120
+ liveRegionElement.innerText = announcement;
121
+ }
122
+ }
123
+ );
124
+ }
125
+ );
126
+ const initialize = () => {
127
+ hiddenTextElement = createHiddenText(
128
+ descriptionId,
129
+ screenReaderInstructions.draggable
130
+ );
131
+ liveRegionElement = createLiveRegion(announcementId);
132
+ document.body.append(hiddenTextElement, liveRegionElement);
133
+ };
134
+ const cleanupEffects = effects(() => {
135
+ for (const draggable of manager.registry.draggables.value) {
136
+ const { element, handle } = draggable;
137
+ const activator = handle ?? element;
138
+ if (activator) {
139
+ if (!hiddenTextElement || !liveRegionElement) {
140
+ initialize();
141
+ }
142
+ if (!isFocusable(activator) && !activator.hasAttribute("tabindex")) {
143
+ activator.setAttribute("tabindex", "0");
144
+ }
145
+ if (!activator.hasAttribute("role") && !(activator instanceof HTMLButtonElement)) {
146
+ activator.setAttribute("role", defaultAttributes.role);
147
+ }
148
+ if (!activator.hasAttribute("role-description")) {
149
+ activator.setAttribute(
150
+ "aria-roledescription",
151
+ defaultAttributes.roleDescription
152
+ );
153
+ }
154
+ if (!activator.hasAttribute("aria-describedby")) {
155
+ activator.setAttribute("aria-describedby", descriptionId);
156
+ }
157
+ activator.setAttribute(
158
+ "aria-pressed",
159
+ String(draggable.isDragSource)
160
+ );
161
+ activator.setAttribute("aria-disabled", String(draggable.disabled));
162
+ }
163
+ }
164
+ this.destroy = () => {
165
+ hiddenTextElement?.remove();
166
+ liveRegionElement?.remove();
167
+ eventListeners.forEach((unsubscribe) => unsubscribe());
168
+ cleanupEffects();
169
+ };
170
+ });
171
+ }
172
+ };
173
+ var Cursor = class extends Plugin {
174
+ constructor(manager, options) {
175
+ super(manager, options);
176
+ this.manager = manager;
177
+ this.destroy = effect(() => {
178
+ const { dragOperation } = this.manager;
179
+ const { cursor = "grabbing" } = this.options ?? {};
180
+ if (dragOperation.status.initialized) {
181
+ const style = document.createElement("style");
182
+ style.innerText = `* { cursor: ${cursor} !important; }`;
183
+ document.head.appendChild(style);
184
+ return () => {
185
+ style.remove();
186
+ };
187
+ }
188
+ });
189
+ }
190
+ };
191
+ var ATTR_PREFIX = "data-dnd-kit-";
192
+ var CSS_PREFIX = "--dnd-kit-feedback-";
193
+ var cssRules = `[${ATTR_PREFIX}feedback] {position: fixed !important;pointer-events: none;touch-action: none;z-index: 999999;will-change: transform;top: var(${CSS_PREFIX}top, 0px) !important;left: var(${CSS_PREFIX}left, 0px) !important;width: var(${CSS_PREFIX}width, auto) !important;height: var(${CSS_PREFIX}height, auto) !important;margin: var(${CSS_PREFIX}margin, 0px) !important;padding: var(${CSS_PREFIX}padding, 0px) !important;}[${ATTR_PREFIX}feedback][style*="${CSS_PREFIX}translate"] {transition: var(${CSS_PREFIX}transition) !important;translate: var(${CSS_PREFIX}translate) !important;}[${ATTR_PREFIX}feedback][popover]{overflow:visible;}[popover]{background:unset;border:unset;}[${ATTR_PREFIX}feedback]::backdrop {display: none}`;
194
+ var ATTRIBUTE = `${ATTR_PREFIX}feedback`;
195
+ var IGNORED_ATTRIBUTES = [ATTRIBUTE, "popover"];
196
+ var IGNORED_STYLES = ["view-transition-name"];
197
+ var Feedback = class extends Plugin {
198
+ constructor(manager) {
199
+ super(manager);
200
+ let style;
201
+ let initialCoordinates;
202
+ let currentTransform;
203
+ let transformOrigin;
204
+ let moved = false;
205
+ const styleInjectionCleanup = effect(() => {
206
+ if (!style && manager.dragOperation.status.initialized) {
207
+ style = document.createElement("style");
208
+ style.innerText = cssRules;
209
+ document.head.prepend(style);
210
+ return styleInjectionCleanup;
211
+ }
212
+ });
213
+ const cleanupEffect = effect(() => {
214
+ const { dragOperation } = manager;
215
+ const { position, source, status } = dragOperation;
216
+ if (status.idle) {
217
+ initialCoordinates = void 0;
218
+ currentTransform = void 0;
219
+ transformOrigin = void 0;
220
+ moved = false;
221
+ return;
222
+ }
223
+ if (!source)
224
+ return;
225
+ const { element, feedback } = source;
226
+ if (!element || feedback === "none")
227
+ return;
228
+ const shape = new DOMRectangle(element, true);
229
+ const { width, height, top, left } = shape;
230
+ const styles = new Styles(element);
231
+ const { padding, margin, transition } = getWindow(element).getComputedStyle(element);
232
+ const droppable = manager.registry.droppables.get(source.id);
233
+ const clone = feedback === "clone";
234
+ const placeholder = createPlaceholder(element, clone);
235
+ const isKeyboardOperation = untracked(
236
+ () => isKeyboardEvent(manager.dragOperation.activatorEvent)
237
+ );
238
+ if (!initialCoordinates) {
239
+ initialCoordinates = {
240
+ x: left,
241
+ y: top
242
+ };
243
+ }
244
+ if (!transformOrigin) {
245
+ const currentPosition = untracked(() => position.current);
246
+ transformOrigin = {
247
+ x: (currentPosition.x - left) / width,
248
+ y: (currentPosition.y - top) / height
249
+ };
250
+ }
251
+ const delta = {
252
+ x: initialCoordinates.x - left,
253
+ y: initialCoordinates.y - top
254
+ };
255
+ const projected = {
256
+ top: top + delta.y,
257
+ left: left + delta.x
258
+ };
259
+ element.setAttribute(ATTRIBUTE, "");
260
+ styles.set(
261
+ {
262
+ width,
263
+ height,
264
+ top: projected.top,
265
+ left: projected.left,
266
+ padding,
267
+ margin,
268
+ translate: currentTransform ? `${currentTransform.x}px ${currentTransform.y}px 0` : ""
269
+ },
270
+ CSS_PREFIX
271
+ );
272
+ element.parentElement?.insertBefore(
273
+ placeholder,
274
+ element.nextElementSibling
275
+ );
276
+ if (supportsPopover(element)) {
277
+ element.setAttribute("popover", "");
278
+ showPopover(element);
279
+ }
280
+ const actual = new DOMRectangle(element, true);
281
+ const offset = {
282
+ top: projected.top - actual.top,
283
+ left: projected.left - actual.left
284
+ };
285
+ if (Math.abs(offset.top) || Math.abs(offset.left)) {
286
+ styles.set(
287
+ {
288
+ top: projected.top + offset.top,
289
+ left: projected.left + offset.left
290
+ },
291
+ CSS_PREFIX
292
+ );
293
+ }
294
+ const resizeObserver = new ResizeObserver(() => {
295
+ const placeholderShape = new DOMRectangle(placeholder, true);
296
+ const origin = transformOrigin ?? { x: 1, y: 1 };
297
+ const dX = (width - placeholderShape.width) * origin.x + delta.x;
298
+ const dY = (height - placeholderShape.height) * origin.y + delta.y;
299
+ styles.set(
300
+ {
301
+ width: placeholderShape.width,
302
+ height: placeholderShape.height,
303
+ top: top + dY + offset.top,
304
+ left: left + dX + offset.left
305
+ },
306
+ CSS_PREFIX
307
+ );
308
+ manager.dragOperation.shape = new DOMRectangle(element);
309
+ });
310
+ if (droppable) {
311
+ droppable.placeholder = placeholder;
312
+ untracked(droppable.refreshShape);
313
+ }
314
+ dragOperation.shape = shape;
315
+ resizeObserver.observe(placeholder);
316
+ const elementMutationObserver = new MutationObserver(() => {
317
+ for (const attribute of Array.from(element.attributes)) {
318
+ if (attribute.name.startsWith("aria-") || IGNORED_ATTRIBUTES.includes(attribute.name)) {
319
+ continue;
320
+ }
321
+ if (attribute.name === "style") {
322
+ if (supportsStyle(element) && supportsStyle(placeholder)) {
323
+ placeholder.setAttribute("style", clone ? "" : "opacity: 0;");
324
+ placeholder.style.setProperty("transition", "none");
325
+ for (const key of Object.values(element.style)) {
326
+ if (key.startsWith(CSS_PREFIX) || IGNORED_STYLES.includes(key)) {
327
+ continue;
328
+ }
329
+ placeholder.style.setProperty(
330
+ key,
331
+ element.style.getPropertyValue(key)
332
+ );
333
+ }
334
+ }
335
+ continue;
336
+ }
337
+ placeholder.setAttribute(attribute.name, attribute.value);
338
+ }
339
+ if (clone) {
340
+ placeholder.innerHTML = element.innerHTML;
341
+ }
342
+ });
343
+ elementMutationObserver.observe(element, {
344
+ attributes: true,
345
+ subtree: true
346
+ });
347
+ const documentMutationObserver = new MutationObserver((entries) => {
348
+ for (const entry of entries) {
349
+ if (Array.from(entry.addedNodes).includes(element)) {
350
+ entry.target.insertBefore(placeholder, element.nextElementSibling);
351
+ showPopover(element);
352
+ return;
353
+ }
354
+ }
355
+ });
356
+ documentMutationObserver.observe(element.ownerDocument.body, {
357
+ childList: true,
358
+ subtree: true
359
+ });
360
+ const cleanupEffect2 = effect(function updateTransform() {
361
+ const { transform, status: status2 } = dragOperation;
362
+ const { x, y } = transform;
363
+ if (!x && !y && !moved) {
364
+ return;
365
+ }
366
+ if (!moved) {
367
+ moved = true;
368
+ }
369
+ if (status2.dragging) {
370
+ const translateTransition = isKeyboardOperation ? "250ms ease" : "0ms linear";
371
+ const shape2 = new DOMRectangle(element);
372
+ styles.set(
373
+ {
374
+ transition: `${transition}, translate ${translateTransition}`,
375
+ translate: `${x}px ${y}px 0`
376
+ },
377
+ CSS_PREFIX
378
+ );
379
+ dragOperation.shape = shape2.translate(
380
+ x - (currentTransform?.x ?? 0),
381
+ y - (currentTransform?.y ?? 0)
382
+ );
383
+ currentTransform = {
384
+ x,
385
+ y,
386
+ z: 0,
387
+ scaleX: shape2.scale.x,
388
+ scaleY: shape2.scale.y
389
+ };
390
+ }
391
+ });
392
+ const id = manager.dragOperation.source?.id;
393
+ const restoreFocus = () => {
394
+ if (id == null) {
395
+ return;
396
+ }
397
+ const draggable = manager.registry.draggables.get(id);
398
+ const element2 = draggable?.handle ?? draggable?.element;
399
+ if (element2 instanceof HTMLElement) {
400
+ element2.focus();
401
+ }
402
+ };
403
+ let cleanup = () => {
404
+ elementMutationObserver.disconnect();
405
+ documentMutationObserver.disconnect();
406
+ resizeObserver.disconnect();
407
+ styles.reset();
408
+ placeholder.remove();
409
+ element.removeAttribute(ATTRIBUTE);
410
+ if (supportsPopover(element)) {
411
+ element.removeAttribute("popover");
412
+ }
413
+ cleanupEffect2();
414
+ dropEffectCleanup();
415
+ if (droppable) {
416
+ droppable.placeholder = void 0;
417
+ }
418
+ };
419
+ const dropEffectCleanup = effect(function dropAnimation() {
420
+ if (dragOperation.status.dropping) {
421
+ const onComplete = cleanup;
422
+ cleanup = void 0;
423
+ const transform = currentTransform;
424
+ if (!transform) {
425
+ onComplete?.();
426
+ return;
427
+ }
428
+ manager.renderer.rendering.then(() => {
429
+ showPopover(element);
430
+ const shape2 = new DOMRectangle(placeholder, true);
431
+ const currentShape = new DOMRectangle(element, true).translate(
432
+ transform.x,
433
+ transform.y
434
+ );
435
+ const delta2 = {
436
+ x: currentShape.center.x - shape2.center.x,
437
+ y: currentShape.center.y - shape2.center.y
438
+ };
439
+ const final = {
440
+ x: transform.x - delta2.x,
441
+ y: transform.y - delta2.y,
442
+ z: 0
443
+ };
444
+ animateTransform({
445
+ element,
446
+ keyframes: {
447
+ translate: [
448
+ `${transform.x}px ${transform.y}px ${transform.z ?? 0}`,
449
+ `${final.x}px ${final.y}px ${final.z}`
450
+ ]
451
+ },
452
+ options: {
453
+ duration: moved ? 250 : 0,
454
+ easing: "ease"
455
+ },
456
+ onReady() {
457
+ styles.remove(["translate", "transition"], CSS_PREFIX);
458
+ },
459
+ onFinish() {
460
+ requestAnimationFrame(restoreFocus);
461
+ onComplete?.();
462
+ }
463
+ });
464
+ });
465
+ }
466
+ });
467
+ return () => cleanup?.();
468
+ });
469
+ this.destroy = () => {
470
+ styleInjectionCleanup();
471
+ cleanupEffect();
472
+ style?.remove();
473
+ };
474
+ }
475
+ };
476
+ var LOCKED = true;
477
+ var UNLOCKED = false;
478
+ var _a, _b;
479
+ var ScrollLock = class {
480
+ constructor() {
481
+ this[_a] = LOCKED;
482
+ this[_b] = LOCKED;
483
+ }
484
+ static {
485
+ _a = ScrollDirection.Forward, _b = ScrollDirection.Reverse;
486
+ }
487
+ isLocked(direction) {
488
+ if (direction === ScrollDirection.Idle) {
489
+ return false;
490
+ }
491
+ if (direction == null) {
492
+ return this[ScrollDirection.Forward] === LOCKED && this[ScrollDirection.Reverse] === LOCKED;
493
+ }
494
+ return this[direction] === LOCKED;
495
+ }
496
+ unlock(direction) {
497
+ if (direction === ScrollDirection.Idle) {
498
+ return;
499
+ }
500
+ this[direction] = UNLOCKED;
501
+ }
502
+ };
503
+ __decorateClass([
504
+ reactive
505
+ ], ScrollLock.prototype, _a);
506
+ __decorateClass([
507
+ reactive
508
+ ], ScrollLock.prototype, _b);
509
+
510
+ // src/core/plugins/scrolling/ScrollIntent.ts
511
+ var DIRECTIONS = [ScrollDirection.Forward, ScrollDirection.Reverse];
512
+ var ScrollIntent = class {
513
+ constructor() {
514
+ this.x = new ScrollLock();
515
+ this.y = new ScrollLock();
516
+ }
517
+ isLocked() {
518
+ return this.x.isLocked() && this.y.isLocked();
519
+ }
520
+ };
521
+ var ScrollIntentTracker = class extends Plugin {
522
+ constructor(manager) {
523
+ super(manager);
524
+ const scrollIntent = signal(new ScrollIntent());
525
+ let previousDelta = null;
526
+ this.signal = scrollIntent;
527
+ effect(() => {
528
+ const { status } = manager.dragOperation;
529
+ if (!status.initialized) {
530
+ previousDelta = null;
531
+ scrollIntent.value = new ScrollIntent();
532
+ return;
533
+ }
534
+ const { delta } = manager.dragOperation.position;
535
+ if (previousDelta) {
536
+ const directions = {
537
+ x: getDirection(delta.x, previousDelta.x),
538
+ y: getDirection(delta.y, previousDelta.y)
539
+ };
540
+ const intent = scrollIntent.peek();
541
+ batch(() => {
542
+ for (const axis of Axes) {
543
+ for (const direction of DIRECTIONS) {
544
+ if (directions[axis] === direction) {
545
+ intent[axis].unlock(direction);
546
+ }
547
+ }
548
+ }
549
+ scrollIntent.value = intent;
550
+ });
551
+ }
552
+ previousDelta = delta;
553
+ });
554
+ }
555
+ get current() {
556
+ return this.signal.peek();
557
+ }
558
+ };
559
+ function getDirection(a, b) {
560
+ return Math.sign(a - b);
561
+ }
562
+
563
+ // src/core/plugins/scrolling/Scroller.ts
564
+ var Scroller = class extends CorePlugin {
565
+ constructor(manager) {
566
+ super(manager);
567
+ this.#scroll = () => {
568
+ if (!this.#meta) {
569
+ return;
570
+ }
571
+ const { element, by } = this.#meta;
572
+ element.scrollBy(by.x, by.y);
573
+ };
574
+ this.scroll = (options) => {
575
+ if (this.disabled) {
576
+ return false;
577
+ }
578
+ const elements = this.getScrollableElements();
579
+ if (!elements) {
580
+ return false;
581
+ }
582
+ const { position } = this.manager.dragOperation;
583
+ const currentPosition = position?.current;
584
+ if (currentPosition) {
585
+ const { by } = options ?? {};
586
+ const intent = by ? {
587
+ x: getScrollIntent(by.x),
588
+ y: getScrollIntent(by.y)
589
+ } : void 0;
590
+ const trackedScrollIntent = intent ? void 0 : this.scrollIntentTracker.current;
591
+ if (trackedScrollIntent?.isLocked()) {
592
+ return false;
593
+ }
594
+ for (const scrollableElement of elements) {
595
+ const elementCanScroll = canScroll(scrollableElement, by);
596
+ if (elementCanScroll.x || elementCanScroll.y) {
597
+ const { speed, direction } = detectScrollIntent(
598
+ scrollableElement,
599
+ currentPosition,
600
+ intent
601
+ );
602
+ if (trackedScrollIntent) {
603
+ for (const axis of Axes) {
604
+ if (trackedScrollIntent[axis].isLocked(direction[axis])) {
605
+ speed[axis] = 0;
606
+ direction[axis] = 0;
607
+ }
608
+ }
609
+ }
610
+ if (direction.x || direction.y) {
611
+ const { x, y } = by ?? direction;
612
+ const scrollLeftBy = x * speed.x;
613
+ const scrollTopBy = y * speed.y;
614
+ if (scrollLeftBy || scrollTopBy) {
615
+ this.#meta = {
616
+ element: scrollableElement,
617
+ by: {
618
+ x: scrollLeftBy,
619
+ y: scrollTopBy
620
+ }
621
+ };
622
+ scheduler.schedule(this.#scroll);
623
+ return true;
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+ return false;
630
+ };
631
+ let previousElementFromPoint = null;
632
+ const elementFromPoint = computed(() => {
633
+ const { position } = manager.dragOperation;
634
+ if (!position) {
635
+ return null;
636
+ }
637
+ const { x, y } = position.current;
638
+ const element = document.elementFromPoint(x, y);
639
+ if (element) {
640
+ previousElementFromPoint = element;
641
+ }
642
+ return document.elementFromPoint(x, y) ?? previousElementFromPoint;
643
+ });
644
+ const scrollableElements = computed(() => {
645
+ const element = elementFromPoint.value;
646
+ if (!element || element === document.documentElement) {
647
+ const { target } = manager.dragOperation;
648
+ const targetElement = target?.element;
649
+ if (targetElement) {
650
+ return getScrollableAncestors(targetElement, { excludeElement: false });
651
+ }
652
+ }
653
+ return element ? getScrollableAncestors(element, { excludeElement: false }) : null;
654
+ }, deepEqual);
655
+ this.getScrollableElements = () => {
656
+ return scrollableElements.value;
657
+ };
658
+ this.scrollIntentTracker = new ScrollIntentTracker(manager);
659
+ this.destroy = manager.monitor.addEventListener("dragmove", (event) => {
660
+ if (this.disabled || event.defaultPrevented || !isKeyboardEvent(manager.dragOperation.activatorEvent) || !event.by) {
661
+ return;
662
+ }
663
+ if (this.scroll({ by: event.by })) {
664
+ event.preventDefault();
665
+ }
666
+ });
667
+ }
668
+ #meta;
669
+ #scroll;
670
+ };
671
+ function getScrollIntent(value) {
672
+ if (value > 0) {
673
+ return ScrollDirection.Forward;
674
+ }
675
+ if (value < 0) {
676
+ return ScrollDirection.Reverse;
677
+ }
678
+ return ScrollDirection.Idle;
679
+ }
680
+ var AUTOSCROLL_INTERVAL = 10;
681
+ var AutoScroller = class extends Plugin {
682
+ constructor(manager, _options) {
683
+ super(manager);
684
+ const scroller = manager.registry.plugins.get(Scroller);
685
+ if (!scroller) {
686
+ throw new Error("AutoScroller plugin depends on Scroller plugin");
687
+ }
688
+ this.destroy = effect(() => {
689
+ if (this.disabled) {
690
+ return;
691
+ }
692
+ const { position: _, status } = manager.dragOperation;
693
+ if (status.dragging) {
694
+ const canScroll2 = scroller.scroll();
695
+ if (canScroll2) {
696
+ const interval = setInterval(scroller.scroll, AUTOSCROLL_INTERVAL);
697
+ return () => {
698
+ clearInterval(interval);
699
+ };
700
+ }
701
+ }
702
+ });
703
+ }
704
+ };
705
+ var listenerOptions = {
706
+ capture: true,
707
+ passive: true
708
+ };
709
+ var ScrollListener = class extends CorePlugin {
710
+ constructor(manager) {
711
+ super(manager);
712
+ this.handleScroll = () => {
713
+ if (this.#timeout == null) {
714
+ this.#timeout = setTimeout(() => {
715
+ this.manager.collisionObserver.forceUpdate();
716
+ this.#timeout = void 0;
717
+ }, 50);
718
+ }
719
+ };
720
+ const { dragOperation } = this.manager;
721
+ this.destroy = effect(() => {
722
+ const enabled = dragOperation.status.dragging;
723
+ if (enabled) {
724
+ document.addEventListener("scroll", this.handleScroll, listenerOptions);
725
+ return () => {
726
+ document.removeEventListener(
727
+ "scroll",
728
+ this.handleScroll,
729
+ listenerOptions
730
+ );
731
+ };
732
+ }
733
+ });
734
+ }
735
+ #timeout;
736
+ };
737
+ var PreventSelection = class extends Plugin {
738
+ constructor(manager) {
739
+ super(manager);
740
+ this.manager = manager;
741
+ this.destroy = effect(() => {
742
+ const { dragOperation } = this.manager;
743
+ if (dragOperation.status.initialized) {
744
+ const style = document.createElement("style");
745
+ style.innerText = `* { user-select: none !important;, -webkit-user-select: none !important; }`;
746
+ document.head.appendChild(style);
747
+ document.addEventListener("selectionchange", removeSelection, {
748
+ capture: true
749
+ });
750
+ return () => {
751
+ document.removeEventListener("selectionchange", removeSelection, {
752
+ capture: true
753
+ });
754
+ style.remove();
755
+ };
756
+ }
757
+ });
758
+ }
759
+ };
760
+ function removeSelection() {
761
+ document.getSelection()?.removeAllRanges();
762
+ }
763
+ var DEFAULT_KEYBOARD_CODES = {
764
+ start: ["Space", "Enter"],
765
+ cancel: ["Escape"],
766
+ end: ["Space", "Enter"],
767
+ up: ["ArrowUp"],
768
+ down: ["ArrowDown"],
769
+ left: ["ArrowLeft"],
770
+ right: ["ArrowRight"]
771
+ };
772
+ var DEFAULT_OFFSET = 10;
773
+ var KeyboardSensor = class extends Sensor {
774
+ constructor(manager, options) {
775
+ super(manager);
776
+ this.manager = manager;
777
+ this.options = options;
778
+ this.#cleanupFunctions = [];
779
+ this.listeners = new Listeners();
780
+ this.handleSourceKeyDown = (event, source, options) => {
781
+ if (this.disabled || event.defaultPrevented) {
782
+ return;
783
+ }
784
+ if (!(event.target instanceof Element)) {
785
+ return;
786
+ }
787
+ if (source.disabled || !source.element) {
788
+ return;
789
+ }
790
+ const { keyboardCodes = DEFAULT_KEYBOARD_CODES } = options ?? {};
791
+ if (!keyboardCodes.start.includes(event.code)) {
792
+ return;
793
+ }
794
+ if (!this.manager.dragOperation.status.idle) {
795
+ return;
796
+ }
797
+ this.handleStart(event, source, options);
798
+ };
799
+ }
800
+ #cleanupFunctions;
801
+ bind(source, options = this.options) {
802
+ const unbind = effect(() => {
803
+ const target = source.handle ?? source.element;
804
+ const listener = (event) => {
805
+ if (event instanceof KeyboardEvent) {
806
+ this.handleSourceKeyDown(event, source, options);
807
+ }
808
+ };
809
+ if (target) {
810
+ target.addEventListener("keydown", listener);
811
+ return () => {
812
+ target.removeEventListener("keydown", listener);
813
+ };
814
+ }
815
+ });
816
+ return unbind;
817
+ }
818
+ handleStart(event, source, options) {
819
+ const { element } = source;
820
+ if (!element) {
821
+ throw new Error("Source draggable does not have an associated element");
822
+ }
823
+ event.preventDefault();
824
+ event.stopImmediatePropagation();
825
+ scrollIntoViewIfNeeded(element);
826
+ const { center } = new DOMRectangle(element);
827
+ batch(() => {
828
+ this.manager.actions.setDragSource(source.id);
829
+ this.manager.actions.start({
830
+ event,
831
+ coordinates: {
832
+ x: center.x,
833
+ y: center.y
834
+ }
835
+ });
836
+ });
837
+ this.sideEffects();
838
+ const sourceDocument = getDocument(element);
839
+ const sourceWindow = getWindow(sourceDocument);
840
+ const listeners = [
841
+ this.listeners.bind(sourceDocument, [
842
+ {
843
+ type: "keydown",
844
+ listener: (event2) => this.handleKeyDown(event2, source, options),
845
+ options: { capture: true }
846
+ }
847
+ ]),
848
+ this.listeners.bind(sourceWindow, [
849
+ { type: "resize", listener: () => this.handleEnd(true) }
850
+ ])
851
+ ];
852
+ this.#cleanupFunctions.push(...listeners);
853
+ }
854
+ handleKeyDown(event, _source, options) {
855
+ const { keyboardCodes = DEFAULT_KEYBOARD_CODES } = options ?? {};
856
+ if (isKeycode(event, [...keyboardCodes.end, ...keyboardCodes.cancel])) {
857
+ event.preventDefault();
858
+ const canceled = isKeycode(event, keyboardCodes.cancel);
859
+ this.handleEnd(canceled);
860
+ return;
861
+ }
862
+ if (isKeycode(event, keyboardCodes.up)) {
863
+ this.handleMove("up", event);
864
+ } else if (isKeycode(event, keyboardCodes.down)) {
865
+ this.handleMove("down", event);
866
+ }
867
+ if (isKeycode(event, keyboardCodes.left)) {
868
+ this.handleMove("left", event);
869
+ } else if (isKeycode(event, keyboardCodes.right)) {
870
+ this.handleMove("right", event);
871
+ }
872
+ }
873
+ handleEnd(canceled) {
874
+ this.manager.actions.stop({
875
+ canceled
876
+ });
877
+ this.cleanup();
878
+ }
879
+ handleMove(direction, event) {
880
+ const { shape } = this.manager.dragOperation;
881
+ const factor = event.shiftKey ? 5 : 1;
882
+ let offset = {
883
+ x: 0,
884
+ y: 0
885
+ };
886
+ if (!shape) {
887
+ return;
888
+ }
889
+ switch (direction) {
890
+ case "up":
891
+ offset = { x: 0, y: -DEFAULT_OFFSET * factor };
892
+ break;
893
+ case "down":
894
+ offset = { x: 0, y: DEFAULT_OFFSET * factor };
895
+ break;
896
+ case "left":
897
+ offset = { x: -DEFAULT_OFFSET * factor, y: 0 };
898
+ break;
899
+ case "right":
900
+ offset = { x: DEFAULT_OFFSET * factor, y: 0 };
901
+ break;
902
+ }
903
+ if (offset?.x || offset?.y) {
904
+ event.preventDefault();
905
+ this.manager.actions.move({
906
+ by: offset
907
+ });
908
+ }
909
+ }
910
+ sideEffects() {
911
+ const autoScroller = this.manager.registry.plugins.get(AutoScroller);
912
+ if (autoScroller?.disabled === false) {
913
+ autoScroller.disable();
914
+ this.#cleanupFunctions.push(() => {
915
+ autoScroller.enable();
916
+ });
917
+ }
918
+ }
919
+ cleanup() {
920
+ this.#cleanupFunctions.forEach((cleanup) => cleanup());
921
+ }
922
+ destroy() {
923
+ this.cleanup();
924
+ this.listeners.clear();
925
+ }
926
+ };
927
+ function isKeycode(event, codes) {
928
+ return codes.includes(event.code);
929
+ }
930
+ var PointerSensor = class _PointerSensor extends Sensor {
931
+ constructor(manager, options) {
932
+ super(manager);
933
+ this.manager = manager;
934
+ this.options = options;
935
+ this.listeners = new Listeners();
936
+ this.listeners.bind(window, {
937
+ type: "touchmove",
938
+ listener() {
939
+ },
940
+ options: {
941
+ capture: false,
942
+ passive: false
943
+ }
944
+ });
945
+ }
946
+ #clearTimeout;
947
+ #document;
948
+ bind(source, options = this.options) {
949
+ const unbind = effect(() => {
950
+ const target = source.handle ?? source.element;
951
+ const listener = (event) => {
952
+ if (event instanceof PointerEvent) {
953
+ this.handlePointerDown(event, source, options);
954
+ }
955
+ };
956
+ if (target) {
957
+ target.addEventListener("pointerdown", listener);
958
+ return () => {
959
+ target.removeEventListener("pointerdown", listener);
960
+ };
961
+ }
962
+ });
963
+ return unbind;
964
+ }
965
+ handlePointerDown(event, source, options = {}) {
966
+ if (this.disabled) {
967
+ return;
968
+ }
969
+ if (!event.isPrimary || event.button !== 0 || !(event.target instanceof Element)) {
970
+ return;
971
+ }
972
+ if (source.disabled) {
973
+ return;
974
+ }
975
+ this.initialCoordinates = {
976
+ x: event.clientX,
977
+ y: event.clientY
978
+ };
979
+ const { activationConstraints } = options;
980
+ const constraints = typeof activationConstraints === "function" ? activationConstraints(event, source) : activationConstraints;
981
+ if (!constraints?.delay && !constraints?.distance) {
982
+ this.handleStart(source, event);
983
+ event.stopImmediatePropagation();
984
+ } else {
985
+ const { delay } = constraints;
986
+ if (delay) {
987
+ const timeout = setTimeout(
988
+ () => this.handleStart(source, event),
989
+ delay.value
990
+ );
991
+ this.#clearTimeout = () => {
992
+ clearTimeout(timeout);
993
+ this.#clearTimeout = void 0;
994
+ };
995
+ }
996
+ }
997
+ const ownerDocument = getDocument(event.target);
998
+ this.#document = ownerDocument;
999
+ const unbindListeners = this.listeners.bind(ownerDocument, [
1000
+ {
1001
+ type: "pointermove",
1002
+ listener: (event2) => this.handlePointerMove(event2, source, options)
1003
+ },
1004
+ {
1005
+ type: "pointerup",
1006
+ listener: this.handlePointerUp.bind(this)
1007
+ },
1008
+ {
1009
+ // Prevent scrolling on touch devices
1010
+ type: "touchmove",
1011
+ listener: preventDefault,
1012
+ options: {
1013
+ passive: false
1014
+ }
1015
+ },
1016
+ {
1017
+ // Cancel activation if there is a competing Drag and Drop interaction
1018
+ type: "dragstart",
1019
+ listener: this.handleCancel.bind(this)
1020
+ },
1021
+ {
1022
+ type: "keydown",
1023
+ listener: this.handleKeyDown.bind(this)
1024
+ }
1025
+ ]);
1026
+ this.cleanup = () => {
1027
+ unbindListeners();
1028
+ this.#clearTimeout?.();
1029
+ this.initialCoordinates = void 0;
1030
+ };
1031
+ }
1032
+ handlePointerMove(event, source, options) {
1033
+ const coordinates = {
1034
+ x: event.clientX,
1035
+ y: event.clientY
1036
+ };
1037
+ if (this.manager.dragOperation.status.dragging) {
1038
+ event.preventDefault();
1039
+ event.stopPropagation();
1040
+ this.manager.actions.move({ to: coordinates });
1041
+ return;
1042
+ }
1043
+ if (!this.initialCoordinates) {
1044
+ return;
1045
+ }
1046
+ const delta = {
1047
+ x: coordinates.x - this.initialCoordinates.x,
1048
+ y: coordinates.y - this.initialCoordinates.y
1049
+ };
1050
+ const { activationConstraints } = options;
1051
+ const constraints = typeof activationConstraints === "function" ? activationConstraints(event, source) : activationConstraints;
1052
+ const { distance, delay } = constraints ?? {};
1053
+ if (distance) {
1054
+ if (distance.tolerance != null && exceedsDistance(delta, distance.tolerance)) {
1055
+ return this.handleCancel();
1056
+ }
1057
+ if (exceedsDistance(delta, distance.value)) {
1058
+ return this.handleStart(source, event);
1059
+ }
1060
+ }
1061
+ if (delay) {
1062
+ if (exceedsDistance(delta, delay.tolerance)) {
1063
+ return this.handleCancel();
1064
+ }
1065
+ }
1066
+ }
1067
+ handlePointerUp(event) {
1068
+ event.preventDefault();
1069
+ event.stopPropagation();
1070
+ const { status } = this.manager.dragOperation;
1071
+ if (!status.idle) {
1072
+ const canceled = !status.initialized;
1073
+ this.manager.actions.stop({ canceled });
1074
+ }
1075
+ this.cleanup?.();
1076
+ }
1077
+ handleKeyDown(event) {
1078
+ if (event.key === "Escape") {
1079
+ event.preventDefault();
1080
+ this.handleCancel();
1081
+ }
1082
+ }
1083
+ handleStart(source, event) {
1084
+ const { manager, initialCoordinates } = this;
1085
+ this.#clearTimeout?.();
1086
+ if (!initialCoordinates || manager.dragOperation.status.initialized) {
1087
+ return;
1088
+ }
1089
+ batch(() => {
1090
+ manager.actions.setDragSource(source.id);
1091
+ manager.actions.start({ coordinates: initialCoordinates, event });
1092
+ });
1093
+ }
1094
+ handleCancel() {
1095
+ const { dragOperation } = this.manager;
1096
+ if (dragOperation.status.initialized) {
1097
+ this.manager.actions.stop({ canceled: true });
1098
+ }
1099
+ this.cleanup?.();
1100
+ }
1101
+ destroy() {
1102
+ this.listeners.clear();
1103
+ }
1104
+ static {
1105
+ this.configure = configurator(_PointerSensor);
1106
+ }
1107
+ };
1108
+ function preventDefault(event) {
1109
+ event.preventDefault();
1110
+ }
1111
+
1112
+ // src/core/manager/manager.ts
1113
+ var defaultPreset = {
1114
+ plugins: [Accessibility, AutoScroller, Cursor, Feedback, PreventSelection],
1115
+ sensors: [
1116
+ PointerSensor.configure({
1117
+ activationConstraints(event, source) {
1118
+ const { pointerType, target } = event;
1119
+ if (pointerType === "mouse" && target instanceof Element && (source.handle === target || source.handle?.contains(target))) {
1120
+ return void 0;
1121
+ }
1122
+ return {
1123
+ delay: { value: 200, tolerance: 10 },
1124
+ distance: { value: 5 }
1125
+ };
1126
+ }
1127
+ }),
1128
+ KeyboardSensor
1129
+ ]
1130
+ };
1131
+ var DragDropManager = class extends DragDropManager$1 {
1132
+ constructor(input = {}) {
1133
+ const {
1134
+ plugins = defaultPreset.plugins,
1135
+ sensors = defaultPreset.sensors,
1136
+ modifiers = []
1137
+ } = input;
1138
+ super({
1139
+ ...input,
1140
+ plugins: [ScrollListener, Scroller, ...plugins],
1141
+ sensors,
1142
+ modifiers
1143
+ });
1144
+ }
1145
+ };
1146
+ var Draggable = class extends Draggable$1 {
1147
+ constructor(input, manager) {
1148
+ const { feedback = "default" } = input;
1149
+ const config = { ...input, feedback };
1150
+ super(config, manager);
1151
+ this.manager = manager;
1152
+ this.feedback = feedback;
1153
+ const cleanupEffect = effect(() => {
1154
+ const sensors = this.sensors?.map(descriptor) ?? [...manager.sensors];
1155
+ const unbindFunctions = sensors.map((entry) => {
1156
+ const sensorInstance = entry instanceof Sensor ? entry : manager.registry.register(entry.plugin);
1157
+ const options = entry instanceof Sensor ? void 0 : entry.options;
1158
+ const unbind = sensorInstance.bind(this, options);
1159
+ return unbind;
1160
+ });
1161
+ return function cleanup() {
1162
+ unbindFunctions.forEach((unbind) => unbind());
1163
+ };
1164
+ });
1165
+ const { destroy } = this;
1166
+ this.destroy = () => {
1167
+ cleanupEffect();
1168
+ destroy();
1169
+ };
1170
+ }
1171
+ };
1172
+ __decorateClass([
1173
+ reactive
1174
+ ], Draggable.prototype, "handle");
1175
+ __decorateClass([
1176
+ reactive
1177
+ ], Draggable.prototype, "element");
1178
+ __decorateClass([
1179
+ reactive
1180
+ ], Draggable.prototype, "feedback");
1181
+ __decorateClass([
1182
+ reactive
1183
+ ], Draggable.prototype, "sensors");
1184
+ var Droppable = class extends Droppable$1 {
1185
+ constructor({ element, ...input }, manager) {
1186
+ const { collisionDetector = defaultCollisionDetection } = input;
1187
+ super({ ...input, collisionDetector }, manager);
1188
+ this.manager = manager;
1189
+ const { destroy } = this;
1190
+ this.internal = {
1191
+ element: signal(element)
1192
+ };
1193
+ this.refreshShape = this.refreshShape.bind(this);
1194
+ if (manager.dragOperation.status.initialized) {
1195
+ this.visible = true;
1196
+ }
1197
+ const cleanup = effects(
1198
+ () => {
1199
+ const { element: element2 } = this;
1200
+ const { dragOperation } = manager;
1201
+ if (element2 && dragOperation.status.initialized) {
1202
+ const scrollableAncestor = getFirstScrollableAncestor(element2);
1203
+ const doc = getDocument(element2);
1204
+ const root = scrollableAncestor === doc.scrollingElement ? doc : scrollableAncestor;
1205
+ const intersectionObserver = new IntersectionObserver(
1206
+ (entries) => {
1207
+ const [entry] = entries.slice(-1);
1208
+ const { width, height } = entry.boundingClientRect;
1209
+ if (!width && !height) {
1210
+ return;
1211
+ }
1212
+ this.visible = entry.isIntersecting;
1213
+ },
1214
+ {
1215
+ root: root ?? doc,
1216
+ rootMargin: "40%"
1217
+ }
1218
+ );
1219
+ const mutationObserver = new MutationObserver(
1220
+ () => scheduler.schedule(this.refreshShape)
1221
+ );
1222
+ const resizeObserver = new ResizeObserver(
1223
+ () => scheduler.schedule(this.refreshShape)
1224
+ );
1225
+ if (element2.parentElement) {
1226
+ mutationObserver.observe(element2.parentElement, {
1227
+ childList: true
1228
+ });
1229
+ }
1230
+ resizeObserver.observe(element2);
1231
+ intersectionObserver.observe(element2);
1232
+ return () => {
1233
+ this.shape = void 0;
1234
+ this.visible = void 0;
1235
+ resizeObserver.disconnect();
1236
+ mutationObserver.disconnect();
1237
+ intersectionObserver.disconnect();
1238
+ };
1239
+ }
1240
+ },
1241
+ () => {
1242
+ const { dragOperation } = manager;
1243
+ const { status } = dragOperation;
1244
+ const source = untracked(() => dragOperation.source);
1245
+ if (status.initialized) {
1246
+ if (source?.type != null && !this.accepts(source)) {
1247
+ return;
1248
+ }
1249
+ scheduler.schedule(this.refreshShape);
1250
+ }
1251
+ },
1252
+ () => {
1253
+ if (manager.dragOperation.status.initialized) {
1254
+ return () => {
1255
+ this.shape = void 0;
1256
+ };
1257
+ }
1258
+ }
1259
+ );
1260
+ this.destroy = () => {
1261
+ cleanup();
1262
+ destroy();
1263
+ };
1264
+ }
1265
+ set element(value) {
1266
+ this.internal.element.value = value;
1267
+ }
1268
+ get element() {
1269
+ return this.placeholder ?? this.internal?.element.value;
1270
+ }
1271
+ refreshShape(ignoreTransform) {
1272
+ const { element } = this;
1273
+ if (!element || this.visible === false) {
1274
+ this.shape = void 0;
1275
+ return void 0;
1276
+ }
1277
+ const { shape } = this;
1278
+ const updatedShape = new DOMRectangle(element, ignoreTransform);
1279
+ if (updatedShape && shape?.equals(updatedShape)) {
1280
+ return shape;
1281
+ }
1282
+ this.shape = updatedShape;
1283
+ return updatedShape;
1284
+ }
1285
+ };
1286
+ __decorateClass([
1287
+ reactive
1288
+ ], Droppable.prototype, "visible");
1289
+ __decorateClass([
1290
+ reactive
1291
+ ], Droppable.prototype, "placeholder");
1292
+
1293
+ export { Accessibility, AutoScroller, DragDropManager, Draggable, Droppable, Feedback, KeyboardSensor, PointerSensor, ScrollListener, Scroller, defaultPreset };
1294
+ //# sourceMappingURL=out.js.map
1295
+ //# sourceMappingURL=index.js.map