@cocreate/position 1.16.0 → 2.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.
@@ -0,0 +1,698 @@
1
+ import { dispatch, normalizeEvent } from "../helpers/events.js";
2
+ import { hasSelection } from "@cocreate/utils";
3
+
4
+ let autoScrollPromise;
5
+
6
+ function mapPointToTop(doc, x, y) {
7
+ while (doc?.defaultView?.frameElement) {
8
+ const frame = doc.defaultView.frameElement;
9
+ const rect = frame.getBoundingClientRect();
10
+ const scaleX = frame.offsetWidth ? rect.width / frame.offsetWidth : 1;
11
+ const scaleY = frame.offsetHeight ? rect.height / frame.offsetHeight : 1;
12
+ x = rect.left + (frame.clientLeft + x) * scaleX;
13
+ y = rect.top + (frame.clientTop + y) * scaleY;
14
+ doc = frame.ownerDocument;
15
+ }
16
+ return { x, y, document: doc };
17
+ }
18
+
19
+ function loadAutoScroll() {
20
+ autoScrollPromise ||= import(/* webpackChunkName: "position-auto-scroll" */ "../autoScroll.js")
21
+ .catch(error => { autoScrollPromise = undefined; throw error; });
22
+ return autoScrollPromise;
23
+ }
24
+
25
+ function position(el, container, options) {
26
+ if (!(el && el.nodeType && el.nodeType === 1)) {
27
+ return;
28
+ }
29
+
30
+ this.options = Object.assign({ draggable: true }, options);
31
+ /** define constant **/
32
+ this.MARGIN = 5;
33
+ this.FULLSCREEN_MARGIN = -60;
34
+ this.NO_SNAP = -100;
35
+ this.SNAP_MARGIN = -10;
36
+ this.RIGHT_SCROL = 5;
37
+ this.dragHandle = el.querySelector('[drag-handle]')
38
+ this.container = container;
39
+ if (this.container && !this.container.positionIndex)
40
+ this.container.positionIndex = 10
41
+
42
+ this.el = el;
43
+ this.boundStatus = {};
44
+
45
+ this.selectedElement;
46
+ // this.selectedClass = "selectedPosition";
47
+ /**
48
+ * x: mouse x in element
49
+ * y: mouse y in element
50
+ * cx: x in document
51
+ * cy: y in document
52
+ * */
53
+ this.point = {};
54
+ this.rect = {};
55
+ this.clickedInfo = null;
56
+ this.preSnapped = null;
57
+ this.isSnap = false;
58
+ this.reference = null;
59
+
60
+ if (this.options.draggable) {
61
+ this._createSnapGhost(this.container?.getAttribute("data-ghost-class"));
62
+ this._initEvent();
63
+ this._selectElement();
64
+ }
65
+ }
66
+
67
+ const INTERACTIVE_SELECTOR = [
68
+ "a",
69
+ "button",
70
+ "input",
71
+ "select",
72
+ "textarea",
73
+ "label",
74
+ "summary",
75
+ "[contenteditable]:not([contenteditable='false'])",
76
+ "[moveable-ignore]"
77
+ ].join(",");
78
+
79
+ position.prototype = {
80
+ constructor: position,
81
+
82
+ _initEvent: function () {
83
+ if (!this.eventsInitialized) {
84
+ this.eventsInitialized = true;
85
+ const self = this;
86
+ this.iframe = this.el.querySelector('iframe')
87
+ if (this.iframe) {
88
+ this.iframe.addEventListener('load', function () {
89
+ const iframeContent = self.iframe.contentDocument;
90
+ iframeContent.addEventListener('mousedown', function (e) {
91
+ self._selectElement(e.detail.element)
92
+ })
93
+ if (self._usesPositionReference?.()) {
94
+ self._watchReferenceFrame?.(self.iframe, iframeContent);
95
+ }
96
+ });
97
+ }
98
+
99
+ this.__setRectInfo();
100
+
101
+ this._documentMouseMove = function (e) {
102
+ if (!self.clickedInfo?.isMoving) return;
103
+ if (e.detail?.document?.defaultView?.frameElement) return;
104
+ const pointerEvent = normalizeEvent(e);
105
+ pointerEvent.preventDefault();
106
+ self._clearDocumentSelection();
107
+ self._onMove(pointerEvent, self._getFrameReference?.(e));
108
+ };
109
+ this._documentMouseUp = function (e) {
110
+ if (!self.clickedInfo?.isMoving) return;
111
+ if (e.detail?.document?.defaultView?.frameElement) return;
112
+ const pointerEvent = normalizeEvent(e);
113
+ self._onUp(pointerEvent, false, self._getFrameReference?.(e));
114
+ pointerEvent.preventDefault();
115
+ };
116
+ this._documentTouchMove = function (e) {
117
+ const pointerEvent = normalizeEvent(e);
118
+ if (!self.clickedInfo?.isMoving || !pointerEvent.touches?.length) return;
119
+ pointerEvent.preventDefault();
120
+ self._clearDocumentSelection();
121
+ const touch = pointerEvent.touches[0];
122
+ self._onMove(touch, self._getFrameReference?.(e, touch));
123
+ };
124
+ this._documentTouchEnd = function (e) {
125
+ if (!self.clickedInfo?.isMoving) return;
126
+ if (e.detail?.document?.defaultView?.frameElement) return;
127
+ const pointerEvent = normalizeEvent(e);
128
+ const touch = pointerEvent.changedTouches?.[0] || pointerEvent;
129
+ self._onUp(touch, pointerEvent.type === "touchcancel", self._getFrameReference?.(e, touch));
130
+ };
131
+ this._documentBlur = function () {
132
+ self._onUp(null, true);
133
+ };
134
+ }
135
+
136
+ if (!this.options.delegated && !this.startEventsInitialized) {
137
+ this.startEventsInitialized = true;
138
+ const dragTargetEl = this.dragHandle || this.el;
139
+ dragTargetEl.addEventListener('touchstart', (e) => this._handlePointerDown(e));
140
+ dragTargetEl.addEventListener('mousedown', (e) => this._handlePointerDown(e));
141
+ }
142
+
143
+ },
144
+
145
+ _handlePointerDown: function (event) {
146
+ const delegated = !!event.__positionDelegated;
147
+ const pointerEvent = normalizeEvent(event);
148
+ if (pointerEvent.which > 1) return;
149
+ if (!delegated) {
150
+ if (this._shouldDelegateDrag?.()) return;
151
+ this.options.dragType = "draggable";
152
+ event.__positionHandled = true;
153
+ }
154
+ this._delayDragStart(pointerEvent, delegated);
155
+ },
156
+
157
+ _delayDragStart: function (event, delegated = false) {
158
+ this._cancelPendingDragStart();
159
+ const doc = this.el.ownerDocument;
160
+ this.pendingDragCancel = () => this._cancelPendingDragStart();
161
+ doc.addEventListener("mouseup", this.pendingDragCancel, true);
162
+ doc.addEventListener("touchend", this.pendingDragCancel, true);
163
+ doc.addEventListener("touchcancel", this.pendingDragCancel, true);
164
+
165
+ this.dragStartTimer = setTimeout(() => {
166
+ this._cancelPendingDragStart();
167
+ const target = event.target?.nodeType === 1 ? event.target : event.target?.parentElement;
168
+ if (target?.hasAttribute("dnd-exclude") || hasSelection(this.el)) return;
169
+
170
+ // Retain the original event until selection has been checked, then
171
+ // initialize drag state from its source and pointer coordinates.
172
+ this._onDown(event.touches?.[0] || event, delegated);
173
+ if (!this.clickedInfo?.isMoving) return;
174
+ this._selectElement();
175
+ this._bindDocumentDrag();
176
+ this._startAutoScroll(event.touches?.[0] || event);
177
+ }, 200);
178
+ },
179
+
180
+ _cancelPendingDragStart: function () {
181
+ if (this.dragStartTimer) {
182
+ clearTimeout(this.dragStartTimer);
183
+ this.dragStartTimer = null;
184
+ }
185
+ const doc = this.el.ownerDocument;
186
+ if (this.pendingDragCancel) {
187
+ doc.removeEventListener("mouseup", this.pendingDragCancel, true);
188
+ doc.removeEventListener("touchend", this.pendingDragCancel, true);
189
+ doc.removeEventListener("touchcancel", this.pendingDragCancel, true);
190
+ this.pendingDragCancel = null;
191
+ }
192
+ },
193
+
194
+ _bindDocumentDrag: function () {
195
+ this._unbindDocumentDrag();
196
+ document.addEventListener('mousemove', this._documentMouseMove);
197
+ document.addEventListener('mouseup', this._documentMouseUp, true);
198
+ document.addEventListener('touchmove', this._documentTouchMove, { passive: false });
199
+ document.addEventListener('touchend', this._documentTouchEnd, true);
200
+ document.addEventListener('touchcancel', this._documentTouchEnd, true);
201
+ window.addEventListener('blur', this._documentBlur);
202
+ },
203
+
204
+ _unbindDocumentDrag: function () {
205
+ document.removeEventListener('mousemove', this._documentMouseMove);
206
+ document.removeEventListener('mouseup', this._documentMouseUp, true);
207
+ document.removeEventListener('touchmove', this._documentTouchMove);
208
+ document.removeEventListener('touchend', this._documentTouchEnd, true);
209
+ document.removeEventListener('touchcancel', this._documentTouchEnd, true);
210
+ window.removeEventListener('blur', this._documentBlur);
211
+ },
212
+
213
+ _onDown: function (e, delegated = false) {
214
+ this.dragPreviewStarted = false;
215
+ if (!this.options.draggable) {
216
+ this.clickedInfo = null;
217
+ return;
218
+ }
219
+ this.dragScope = delegated && this.options.dragScope?.isConnected
220
+ ? this.options.dragScope
221
+ : null;
222
+ this.dragType = this.options.dragType || "draggable";
223
+ this._initSnappableDrag?.(delegated);
224
+ this.originalStyle = {
225
+ present: this.el.hasAttribute("style"),
226
+ value: this.el.getAttribute("style")
227
+ };
228
+ // A title-bar style drag handle may contain controls. Those controls
229
+ // must retain their native click, focus, and file-picker behavior.
230
+ const interactive = e.target?.closest?.(INTERACTIVE_SELECTOR);
231
+ if (this.dragHandle && interactive && this.dragHandle.contains(interactive)) {
232
+ this.clickedInfo = null;
233
+ return;
234
+ }
235
+
236
+ this.__getBoundStatus(e);
237
+
238
+ this.clickedInfo = {
239
+ x: this.point.x,
240
+ y: this.point.y,
241
+ cx: this.point.cx,
242
+ cy: this.point.cy,
243
+ w: this.rect.width,
244
+ h: this.rect.height,
245
+ isMoving: true,
246
+ boundStatus: this.boundStatus,
247
+ isChangeStart: true
248
+ }
249
+ this.dragOriginRect = this.el.getBoundingClientRect();
250
+ this.dragStartClientX = e.clientX;
251
+ this.dragStartClientY = e.clientY;
252
+ const sourceDocument = this.el.ownerDocument;
253
+ this.dragSourceFrame = sourceDocument.defaultView?.frameElement || null;
254
+ this.dragPreviewDocument = sourceDocument;
255
+ this.dragPreviewRect = this.dragOriginRect;
256
+ this.dragPreviewOffset = null;
257
+ if (this.dragSourceFrame) {
258
+ const topLeft = mapPointToTop(sourceDocument, this.dragOriginRect.left, this.dragOriginRect.top);
259
+ const bottomRight = mapPointToTop(sourceDocument, this.dragOriginRect.right, this.dragOriginRect.bottom);
260
+ const pointer = mapPointToTop(sourceDocument, this.dragStartClientX, this.dragStartClientY);
261
+ this.dragPreviewDocument = pointer.document;
262
+ this.dragPreviewRect = {
263
+ left: topLeft.x,
264
+ top: topLeft.y,
265
+ width: bottomRight.x - topLeft.x,
266
+ height: bottomRight.y - topLeft.y
267
+ };
268
+ this.dragPreviewOffset = { x: pointer.x - topLeft.x, y: pointer.y - topLeft.y };
269
+ }
270
+ this.dragOriginOffsetParent = this.el.offsetParent || this.el.parentElement;
271
+ const computed = getComputedStyle(this.el);
272
+ this.dragOriginPosition = computed.position;
273
+ this.dragOriginLeft = parseFloat(computed.left) || 0;
274
+ this.dragOriginTop = parseFloat(computed.top) || 0;
275
+ this.dragOriginalVisibility = [
276
+ this.el.style.getPropertyValue("visibility"),
277
+ this.el.style.getPropertyPriority("visibility")
278
+ ];
279
+ this.dragOriginalOpacity = computed.opacity;
280
+ const style = this.el.style;
281
+ this.dragSizeVariables = {
282
+ width: [style.getPropertyValue("--position-moving-width"), style.getPropertyPriority("--position-moving-width")],
283
+ height: [style.getPropertyValue("--position-moving-height"), style.getPropertyPriority("--position-moving-height")]
284
+ };
285
+ this._createFrameOverlays?.();
286
+ },
287
+
288
+ _onMove: function (e, reference) {
289
+ const pointerDocument = reference?.document ?? e.document ?? this.el.ownerDocument;
290
+ this.autoScrollPointer = {
291
+ x: reference?.x ?? e.clientX,
292
+ y: reference?.y ?? e.clientY,
293
+ document: pointerDocument
294
+ };
295
+ this.autoScroll?.update(this.autoScrollPointer);
296
+ this._startMoving(e);
297
+ this._updateSnappableReference?.(
298
+ reference?.x ?? e.clientX,
299
+ reference?.y ?? e.clientY,
300
+ pointerDocument,
301
+ reference?.element
302
+ );
303
+ this.__getBoundStatus(e)
304
+ this.__animate();
305
+ },
306
+
307
+ _startAutoScroll: function (event) {
308
+ const drag = this.clickedInfo;
309
+ this.autoScroll?.stop();
310
+ this.autoScrollPointer = { x: event.clientX, y: event.clientY, document: this.el.ownerDocument };
311
+ loadAutoScroll().then(({ createAutoScroll }) => {
312
+ if (this.clickedInfo !== drag || !this.el.isConnected) return;
313
+ this.autoScroll = createAutoScroll({
314
+ element: this.el,
315
+ isActive: () => this.clickedInfo === drag && drag.isMoving,
316
+ onScroll: (pointer, reference) => this._onMove(pointer, reference),
317
+ onCancel: () => this._onUp(null, true)
318
+ });
319
+ this.autoScroll.update(this.autoScrollPointer);
320
+ }).catch(error => {
321
+ dispatch(this.el, "position-error", { error, feature: "auto-scroll" });
322
+ });
323
+ },
324
+
325
+ _clearDocumentSelection: function () {
326
+ this.el.ownerDocument.getSelection()?.removeAllRanges();
327
+ },
328
+
329
+ _startMoving: function () {
330
+ if (!this.clickedInfo?.isMoving || this.dragPreviewStarted) return;
331
+ this.dragPreviewStarted = true;
332
+ this.el.classList.add("position-moving");
333
+ if (this.dragType === "clonable")
334
+ this.el.classList.add("position-cloning");
335
+ this.movingPosition = this.dragOriginPosition;
336
+ const rect = this.dragOriginRect;
337
+ this.el.style.setProperty("--position-moving-width", rect.width + "px");
338
+ this.el.style.setProperty("--position-moving-height", rect.height + "px");
339
+ this._createDragGhost();
340
+ if (this.dragType !== "clonable") {
341
+ this.el.style.setProperty("visibility", "hidden");
342
+ }
343
+ },
344
+
345
+ _createDragGhost: function () {
346
+ const doc = this.dragPreviewDocument || this.el.ownerDocument;
347
+ const ghost = doc === this.el.ownerDocument
348
+ ? this.el.cloneNode(true)
349
+ : doc.importNode(this.el, true);
350
+ const computed = this.el.ownerDocument.defaultView.getComputedStyle(this.el);
351
+ for (let i = 0; i < computed.length; i++) {
352
+ const property = computed[i];
353
+ ghost.style.setProperty(property, computed.getPropertyValue(property), computed.getPropertyPriority(property));
354
+ }
355
+ ghost.classList.add("position-moving");
356
+ ghost.classList.add("position-moving-preview");
357
+ ghost.classList.remove("position-cloning");
358
+ if (this.dragType === "clonable")
359
+ ghost.style.opacity = this.dragOriginalOpacity;
360
+ ghost.setAttribute("aria-hidden", "true");
361
+ const activationAttributes = ["draggable", "position-query", "position-element", "draggable-query", "clonable-query", "droppable-query", "snappable-query", "draggable-value", "clonable-value", "position-reference"];
362
+ const previewElements = [ghost, ...ghost.querySelectorAll("*")];
363
+ for (const element of previewElements) {
364
+ element.removeAttribute("id");
365
+ for (const attribute of activationAttributes) element.removeAttribute(attribute);
366
+ }
367
+ ghost.style.position = "fixed";
368
+ const rect = this.dragPreviewRect || this.dragOriginRect;
369
+ ghost.style.left = rect.left + "px";
370
+ ghost.style.top = rect.top + "px";
371
+ ghost.style.width = rect.width + "px";
372
+ ghost.style.height = rect.height + "px";
373
+ ghost.style.margin = "0";
374
+ ghost.style.pointerEvents = "none";
375
+ ghost.style.zIndex = "2147483647";
376
+ (doc.body || doc.documentElement).appendChild(ghost);
377
+ this.dragGhostEl = ghost;
378
+ },
379
+
380
+ _moveDragPreview: function () {
381
+ if (!this.clickedInfo) return;
382
+ const offset = this.dragPreviewOffset || this.clickedInfo;
383
+ const left = this.point.clientX - offset.x;
384
+ const top = this.point.clientY - offset.y;
385
+ if (this.dragGhostEl) {
386
+ this.dragGhostEl.style.left = left + "px";
387
+ this.dragGhostEl.style.top = top + "px";
388
+ }
389
+ if (this.dragType === "clonable") return;
390
+ if (this.dragSourceFrame) return;
391
+ // The moving class makes the element fixed while dragging, so every
392
+ // positioning mode must use viewport coordinates and preserve the
393
+ // pointer's original offset within the element.
394
+ this.el.style.left = left + "px";
395
+ this.el.style.top = top + "px";
396
+ this.el.style.right = "auto";
397
+ this.el.style.bottom = "auto";
398
+ },
399
+
400
+ _persistFreeDragPosition: function () {
401
+ if (!this.dragPreviewStarted || this.dragType === "clonable") return;
402
+ const left = this.point.clientX - this.clickedInfo.x;
403
+ const top = this.point.clientY - this.clickedInfo.y;
404
+ const style = this.el.style;
405
+
406
+ if (this.movingPosition === "fixed") {
407
+ style.left = left + "px";
408
+ style.top = top + "px";
409
+ } else if (this.movingPosition === "absolute") {
410
+ const offsetParent = this.dragOriginOffsetParent;
411
+ const parentRect = offsetParent.getBoundingClientRect();
412
+ style.left = left - parentRect.left - offsetParent.clientLeft + offsetParent.scrollLeft + "px";
413
+ style.top = top - parentRect.top - offsetParent.clientTop + offsetParent.scrollTop + "px";
414
+ } else if (this.movingPosition === "relative") {
415
+ style.left = this.dragOriginLeft + this.point.clientX - this.dragStartClientX + "px";
416
+ style.top = this.dragOriginTop + this.point.clientY - this.dragStartClientY + "px";
417
+ } else {
418
+ style.position = "fixed";
419
+ style.left = left + "px";
420
+ style.top = top + "px";
421
+ }
422
+ style.right = "auto";
423
+ style.bottom = "auto";
424
+ },
425
+
426
+ _finishMoving: function () {
427
+ this.el.classList.remove("position-moving");
428
+ this.el.classList.remove("position-cloning");
429
+ this.dragGhostEl?.remove();
430
+ this.dragGhostEl = null;
431
+ this.dragPreviewStarted = false;
432
+ const [visibility, priority] = this.dragOriginalVisibility || [];
433
+ if (visibility) this.el.style.setProperty("visibility", visibility, priority);
434
+ else this.el.style.removeProperty("visibility");
435
+ if (this.dragSizeVariables) {
436
+ for (const [name, [value, priority]] of Object.entries({
437
+ "--position-moving-width": this.dragSizeVariables.width,
438
+ "--position-moving-height": this.dragSizeVariables.height
439
+ })) {
440
+ if (value) this.el.style.setProperty(name, value, priority);
441
+ else this.el.style.removeProperty(name);
442
+ }
443
+ }
444
+ },
445
+
446
+ _onUp: function (e, cancelled = false, reference) {
447
+ this.autoScroll?.stop();
448
+ this.autoScroll = null;
449
+ this.autoScrollPointer = null;
450
+ this._unbindDocumentDrag();
451
+ if (!this.clickedInfo) {
452
+ this._finishMoving();
453
+ this._clearSnappableState?.();
454
+ return;
455
+ }
456
+ if (e) {
457
+ this.__getBoundStatus(e);
458
+ }
459
+ this._finishSnappableReference?.(e, reference);
460
+ if (this.clickedInfo.isMoving && !this.dropQuerySelector &&
461
+ !(this.snapQuerySelector && this.reference) && !this.isParked) {
462
+ const snap_info = this._getViewportSnapArea();
463
+
464
+ if (snap_info && !this.isSnap) {
465
+ this._applyViewportSnap(snap_info);
466
+ this.preSnapped = { x: this.rect.x, y: this.rect.y, width: this.rect.width, height: this.rect.height };
467
+ this.isSnap = true;
468
+ }
469
+
470
+ let ghost_info = {
471
+ x: this.point.clientX - this.clickedInfo.x,
472
+ y: this.point.clientY - this.clickedInfo.y,
473
+ w: this.dragOriginRect.width,
474
+ h: this.dragOriginRect.height
475
+ }
476
+
477
+ this._snapGhostProcess(ghost_info)
478
+ }
479
+
480
+ if (this.clickedInfo.isMoving) {
481
+ if (!cancelled && !this.dropQuerySelector &&
482
+ !(this.snapQuerySelector && this.reference) && !this.isSnap)
483
+ this._persistFreeDragPosition();
484
+ this._finishMoving();
485
+ this._completeSnappableDrop?.(cancelled);
486
+ }
487
+
488
+ this._clearSnappableState?.();
489
+
490
+ if (this.clickedInfo.isMoving) {
491
+ this.createEvent('element-moveend');
492
+ }
493
+
494
+ this.clickedInfo = null;
495
+ },
496
+
497
+ __setBound: function (el, x, y, w, h) {
498
+ el.style.left = x;
499
+ el.style.top = y;
500
+ el.style.width = w;
501
+ el.style.height = h;
502
+ },
503
+
504
+ __setRectInfo: function () {
505
+ let bound = this.el.getBoundingClientRect();
506
+ let parentRect = this.el.parentNode.getBoundingClientRect();
507
+ this.rect = {};
508
+ this.rect.x = bound.x - parentRect.x;
509
+ this.rect.y = bound.y - parentRect.y;
510
+ this.rect.width = bound.width;
511
+ this.rect.height = bound.height;
512
+ this.rect.top = bound.top - parentRect.top;
513
+ this.rect.bottom = bound.bottom - parentRect.top;
514
+ this.rect.left = bound.left - parentRect.left;
515
+ this.rect.right = bound.right - parentRect.left;
516
+ },
517
+
518
+ __getBoundStatus: function (e) {
519
+ let bound = this.el.getBoundingClientRect();
520
+ let parentRect = this.el.parentNode.getBoundingClientRect();
521
+ let x = e.clientX - bound.left;// - parentRect.left;
522
+ let y = e.clientY - bound.top;// - parentRect.top;
523
+
524
+ this.__setRectInfo();
525
+
526
+ this.point.x = x;
527
+ this.point.y = y;
528
+ this.point.clientX = e.clientX;
529
+ this.point.clientY = e.clientY;
530
+ this.point.cx = e.clientX - parentRect.left;
531
+ this.point.cy = e.clientY - parentRect.top;
532
+
533
+ this.boundStatus = {
534
+ isTop: y < this.MARGIN && y > -this.MARGIN,
535
+ isLeft: x < this.MARGIN && x > -this.MARGIN,
536
+ isRight: x >= bound.width - this.RIGHT_SCROL && x <= bound.width + this.MARGIN + (this.MARGIN - this.RIGHT_SCROL),
537
+ isBottom: y >= bound.height - this.MARGIN && y <= bound.height + this.MARGIN
538
+ }
539
+
540
+ return this.boundStatus;
541
+ },
542
+
543
+ __between: function (x, min, max) {
544
+ return x >= min && x <= max;
545
+ },
546
+
547
+ _getViewportSnapArea: function () {
548
+ if (!this.clickedInfo || !this.dragOriginRect) return null;
549
+ const doc = this.el.ownerDocument;
550
+ const view = doc.defaultView;
551
+ const width = doc.documentElement.clientWidth || view.innerWidth;
552
+ const height = doc.documentElement.clientHeight || view.innerHeight;
553
+ const left = this.point.clientX - this.clickedInfo.x;
554
+ const top = this.point.clientY - this.clickedInfo.y;
555
+ const right = width - left - this.dragOriginRect.width;
556
+ const bottom = height - top - this.dragOriginRect.height;
557
+
558
+ if (this.__between(top, this.NO_SNAP, this.FULLSCREEN_MARGIN) ||
559
+ this.__between(left, this.NO_SNAP, this.FULLSCREEN_MARGIN) ||
560
+ this.__between(right, this.NO_SNAP, this.FULLSCREEN_MARGIN) ||
561
+ this.__between(bottom, this.NO_SNAP, this.FULLSCREEN_MARGIN))
562
+ return { x: 0, y: 0, w: width, h: height };
563
+ if (this.__between(top, this.NO_SNAP, this.SNAP_MARGIN))
564
+ return { x: 0, y: 0, w: width, h: height / 2 };
565
+ if (this.__between(left, this.NO_SNAP, this.SNAP_MARGIN))
566
+ return { x: 0, y: 0, w: width / 2, h: height };
567
+ if (this.__between(right, this.NO_SNAP, this.SNAP_MARGIN))
568
+ return { x: width / 2, y: 0, w: width / 2, h: height };
569
+ if (this.__between(bottom, this.NO_SNAP, this.SNAP_MARGIN))
570
+ return { x: 0, y: height / 2, w: width, h: height / 2 };
571
+ return null;
572
+ },
573
+
574
+ _applyViewportSnap: function ({ x, y, w, h }) {
575
+ const style = this.el.style;
576
+ style.position = "fixed";
577
+ style.removeProperty("inset");
578
+ style.left = x + "px";
579
+ style.top = y + "px";
580
+ style.right = "auto";
581
+ style.bottom = "auto";
582
+ style.width = w + "px";
583
+ style.height = h + "px";
584
+ style.boxSizing = "border-box";
585
+ },
586
+
587
+ __animate: function () {
588
+ let c_info = this.clickedInfo;
589
+
590
+ let eventName = null;
591
+
592
+ if (c_info && c_info.isMoving) {
593
+ /**
594
+ * Ghost Process
595
+ **/
596
+
597
+ const snapArea = this._getViewportSnapArea();
598
+ const ghost_info = snapArea
599
+ ? { ...snapArea, type: "show" }
600
+ : {
601
+ x: this.point.clientX - this.clickedInfo.x,
602
+ y: this.point.clientY - this.clickedInfo.y,
603
+ w: this.dragOriginRect.width,
604
+ h: this.dragOriginRect.height,
605
+ type: "hide"
606
+ };
607
+
608
+ if (ghost_info && !this.dropQuerySelector &&
609
+ !(this.snapQuerySelector && this.reference) && !this.isParked && !this.isSnap) {
610
+ this._snapGhostProcess(ghost_info)
611
+ }
612
+
613
+ if (this.isSnap) this.isSnap = false;
614
+ this._moveDragPreview();
615
+
616
+ eventName = "element-moving";
617
+ if (c_info.isChangeStart) {
618
+ this.clickedInfo.isChangeStart = false;
619
+ eventName = "element-movestart";
620
+ }
621
+
622
+ this.createEvent(eventName)
623
+ return;
624
+ }
625
+ },
626
+
627
+ minMax() {
628
+ if (!this.isSnap) {
629
+ this.isSnap = true;
630
+ this.preSnapped = { x: this.rect.x, y: this.rect.y, width: this.rect.width, height: this.rect.height };
631
+ this.__setBound(this.el, 0, 0, "100%", "100%");
632
+ } else {
633
+ this.isSnap = false;
634
+ this.el.style.left = this.preSnapped.x + 'px';
635
+ this.el.style.top = this.preSnapped.y + 'px';
636
+ this.el.style.width = this.preSnapped.width + 'px';
637
+ this.el.style.height = this.preSnapped.height + 'px';
638
+ }
639
+ },
640
+
641
+
642
+ /**
643
+ * Position Events
644
+ * move: element-moving, element-moveend, element-movestart
645
+ **/
646
+ createEvent(eventName, detail = {}) {
647
+ return dispatch(this.el, eventName, { instance: this, reference: this.reference, ...detail });
648
+ },
649
+
650
+ _createSnapGhost: function (ghostClass) {
651
+ const doc = this.el.ownerDocument;
652
+ let node = doc.createElement("div");
653
+ if (!ghostClass) {
654
+ ghostClass = "snap-ghost";
655
+ }
656
+
657
+ node.classList.add(ghostClass);
658
+ node.style.position = "fixed";
659
+ node.style.pointerEvents = "none";
660
+ (doc.body || doc.documentElement).appendChild(node);
661
+ this.snapGhostEl = node;
662
+ },
663
+
664
+ _snapGhostProcess: function (info) {
665
+ this.snapGhostEl.style.left = info.x + 'px';
666
+ this.snapGhostEl.style.top = info.y + 'px';
667
+ this.snapGhostEl.style.width = info.w + 'px';
668
+ this.snapGhostEl.style.height = info.h + 'px';
669
+
670
+ if (info.type === "show") {
671
+ if (this.snapGhostEl.style.display === 'none') {
672
+ this.snapGhostEl.style.display = 'block'
673
+ }
674
+ this.snapGhostEl.style.opacity = 0.2;
675
+ } else {
676
+ this.snapGhostEl.setAttribute("style", "display: none;");
677
+ }
678
+ return;
679
+ },
680
+
681
+ _selectElement: function (el) {
682
+ this._releaseSelect();
683
+ if (this.container) this.container['selectedPositionElement'] = this.el
684
+ if (this.el) {
685
+ this.createEvent('elementSelected');
686
+ if (this.container) this.el.style.zIndex = this.container.positionIndex += 1;
687
+ this.el.classList.add('selectedPosition');
688
+ }
689
+ },
690
+
691
+ _releaseSelect: function () {
692
+ let el = this.container?.['selectedPositionElement'];
693
+ if (el)
694
+ el.classList.remove("selectedPosition");
695
+ },
696
+ }
697
+
698
+ export default position;