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