dynim-core 1.0.3 → 1.0.5

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.
Files changed (40) hide show
  1. package/README.md +9 -282
  2. package/dist/builder/builder-client.d.ts +1 -5
  3. package/dist/builder/builder-client.d.ts.map +1 -1
  4. package/dist/builder/builder-client.js +2 -22
  5. package/dist/builder/builder.d.ts +0 -4
  6. package/dist/builder/builder.d.ts.map +1 -1
  7. package/dist/builder/builder.js +21 -232
  8. package/dist/builder/code-client.js +1 -1
  9. package/dist/builder/editor-overlays.d.ts +1 -10
  10. package/dist/builder/editor-overlays.d.ts.map +1 -1
  11. package/dist/builder/editor-overlays.js +1 -103
  12. package/dist/builder/editor-state.d.ts +2 -21
  13. package/dist/builder/editor-state.d.ts.map +1 -1
  14. package/dist/builder/editor-state.js +2 -34
  15. package/dist/builder/element-utils.d.ts +0 -11
  16. package/dist/builder/element-utils.d.ts.map +1 -1
  17. package/dist/builder/element-utils.js +0 -58
  18. package/dist/builder/freeze-overlay.d.ts +1 -1
  19. package/dist/builder/freeze-overlay.d.ts.map +1 -1
  20. package/dist/builder/freeze-overlay.js +1 -2
  21. package/dist/builder/index.d.ts +5 -9
  22. package/dist/builder/index.d.ts.map +1 -1
  23. package/dist/builder/index.js +3 -7
  24. package/dist/builder/{drag-engine.d.ts → interaction-engine.d.ts} +6 -20
  25. package/dist/builder/interaction-engine.d.ts.map +1 -0
  26. package/dist/builder/interaction-engine.js +101 -0
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +1 -1
  29. package/package.json +1 -1
  30. package/src/README.md +10 -0
  31. package/src/styles/builder.css +0 -192
  32. package/src/styles/editor.css +2 -61
  33. package/dist/builder/diff-state.d.ts +0 -24
  34. package/dist/builder/diff-state.d.ts.map +0 -1
  35. package/dist/builder/diff-state.js +0 -134
  36. package/dist/builder/drag-engine.d.ts.map +0 -1
  37. package/dist/builder/drag-engine.js +0 -686
  38. package/dist/builder/history-state.d.ts +0 -41
  39. package/dist/builder/history-state.d.ts.map +0 -1
  40. package/dist/builder/history-state.js +0 -76
@@ -1,686 +0,0 @@
1
- /**
2
- * Drag & drop engine - handles all drag detection and drop target calculation
3
- */
4
- import { buildPlacementTarget, canDropInZone } from './element-utils';
5
- const DRAG_THRESHOLD = 5;
6
- const EDGE_MARGIN = 40;
7
- const WRAPPER_ATTR = 'data-dnd-wrapper';
8
- export function createDragEngine(config) {
9
- const { contentRoot, editorState, historyState, diffState, overlays, onRescan } = config;
10
- let freezeOverlay = config.freezeOverlay || null;
11
- function setFreezeOverlay(overlay) {
12
- freezeOverlay = overlay;
13
- }
14
- let mouseDownInfo = null;
15
- let dragInfo = null;
16
- let dragEndTime = 0;
17
- function isEditorElement(el) {
18
- const skipIds = ['__editor-freeze-overlay__', '__editor-overlays__', '__inspector-overlay__'];
19
- return skipIds.some(id => el.id === id || el.closest(`#${id}`));
20
- }
21
- function isContainerHorizontal(element) {
22
- const style = window.getComputedStyle(element);
23
- const display = style.display;
24
- const flexDirection = style.flexDirection;
25
- if (display === 'flex' || display === 'inline-flex') {
26
- return flexDirection !== 'column' && flexDirection !== 'column-reverse';
27
- }
28
- if (display === 'grid' || display === 'inline-grid') {
29
- const gridAutoFlow = style.gridAutoFlow || '';
30
- return !gridAutoFlow.includes('column');
31
- }
32
- return false;
33
- }
34
- function isParentHorizontalFlex(element) {
35
- const parent = element.parentElement;
36
- if (!parent)
37
- return false;
38
- const style = window.getComputedStyle(parent);
39
- if (style.display === 'flex' || style.display === 'inline-flex') {
40
- return style.flexDirection !== 'column' && style.flexDirection !== 'column-reverse';
41
- }
42
- return false;
43
- }
44
- function getDropZone(x, y, rect) {
45
- const normX = (x - rect.left) / rect.width;
46
- const normY = (y - rect.top) / rect.height;
47
- const edgeThreshold = 0.3;
48
- if (normY < edgeThreshold)
49
- return 'top';
50
- if (normY > 1 - edgeThreshold)
51
- return 'bottom';
52
- if (normX < 0.5)
53
- return 'left';
54
- return 'right';
55
- }
56
- function getSiblingDropPosition(x, y, rect, isParentHorizontal) {
57
- if (isParentHorizontal) {
58
- const midX = rect.left + rect.width / 2;
59
- return x < midX ? 'left' : 'right';
60
- }
61
- else {
62
- const midY = rect.top + rect.height / 2;
63
- return y < midY ? 'top' : 'bottom';
64
- }
65
- }
66
- function distanceToBounds(x, y, rect) {
67
- const distX = x < rect.left ? rect.left - x : x > rect.right ? x - rect.right : 0;
68
- const distY = y < rect.top ? rect.top - y : y > rect.bottom ? y - rect.bottom : 0;
69
- return Math.sqrt(distX * distX + distY * distY);
70
- }
71
- function findClosestChildWithinMargin(container, x, y, draggedElement) {
72
- let closestChild = null;
73
- let closestDist = Infinity;
74
- for (const child of Array.from(container.children)) {
75
- if (child === draggedElement || draggedElement.contains(child))
76
- continue;
77
- const childEl = child;
78
- const rect = childEl.getBoundingClientRect();
79
- const dist = distanceToBounds(x, y, rect);
80
- if (dist < closestDist && dist <= EDGE_MARGIN) {
81
- closestDist = dist;
82
- closestChild = childEl;
83
- }
84
- }
85
- return closestChild;
86
- }
87
- function findNearestChild(parent, x, y, isHorizontal, draggedElement) {
88
- const children = Array.from(parent.children).filter(child => child !== draggedElement && !draggedElement.contains(child));
89
- if (children.length === 0)
90
- return null;
91
- let nearestChild = null;
92
- let nearestDistance = Infinity;
93
- let nearestPosition = null;
94
- for (const child of children) {
95
- const rect = child.getBoundingClientRect();
96
- let distance;
97
- let position;
98
- if (isHorizontal) {
99
- const distToLeft = Math.abs(x - rect.left);
100
- const distToRight = Math.abs(x - rect.right);
101
- if (distToLeft <= distToRight) {
102
- distance = distToLeft;
103
- position = 'left';
104
- }
105
- else {
106
- distance = distToRight;
107
- position = 'right';
108
- }
109
- }
110
- else {
111
- const distToTop = Math.abs(y - rect.top);
112
- const distToBottom = Math.abs(y - rect.bottom);
113
- if (distToTop <= distToBottom) {
114
- distance = distToTop;
115
- position = 'top';
116
- }
117
- else {
118
- distance = distToBottom;
119
- position = 'bottom';
120
- }
121
- }
122
- if (distance < nearestDistance) {
123
- nearestDistance = distance;
124
- nearestChild = child;
125
- nearestPosition = position;
126
- }
127
- }
128
- if (!nearestChild && children.length > 0) {
129
- nearestChild = children[0];
130
- nearestPosition = isHorizontal ? 'left' : 'top';
131
- }
132
- if (!nearestChild)
133
- return null;
134
- return { child: nearestChild, position: nearestPosition };
135
- }
136
- function isValidVisibilityDrop(targetElement, draggedElement) {
137
- return canDropInZone(draggedElement, targetElement);
138
- }
139
- function findDropTarget(x, y, draggedElement) {
140
- if (!contentRoot) {
141
- return null;
142
- }
143
- const overlay = document.getElementById('__editor-freeze-overlay__');
144
- const overlaysContainer = document.getElementById('__editor-overlays__');
145
- if (overlay)
146
- overlay.style.pointerEvents = 'none';
147
- if (overlaysContainer)
148
- overlaysContainer.style.display = 'none';
149
- let targetElement = document.elementFromPoint(x, y);
150
- if (overlay)
151
- overlay.style.pointerEvents = 'auto';
152
- if (overlaysContainer)
153
- overlaysContainer.style.display = '';
154
- if (!targetElement) {
155
- return null;
156
- }
157
- if (isEditorElement(targetElement)) {
158
- return null;
159
- }
160
- if (targetElement === draggedElement || draggedElement.contains(targetElement)) {
161
- targetElement = draggedElement.parentElement;
162
- while (targetElement &&
163
- targetElement !== contentRoot &&
164
- targetElement.hasAttribute(WRAPPER_ATTR) &&
165
- targetElement.children.length <= 1) {
166
- targetElement = targetElement.parentElement;
167
- }
168
- if (!targetElement || targetElement === contentRoot) {
169
- return null;
170
- }
171
- }
172
- if (targetElement === contentRoot || !contentRoot.contains(targetElement)) {
173
- return null;
174
- }
175
- function getParentRect(el) {
176
- const parent = el.parentElement;
177
- if (parent && parent !== contentRoot) {
178
- return parent.getBoundingClientRect();
179
- }
180
- return null;
181
- }
182
- if (targetElement.children.length > 0) {
183
- const isHorizontal = isContainerHorizontal(targetElement);
184
- const containerRect = targetElement.getBoundingClientRect();
185
- let directChild = null;
186
- for (const child of Array.from(targetElement.children)) {
187
- if (child === draggedElement || draggedElement.contains(child))
188
- continue;
189
- const childRect = child.getBoundingClientRect();
190
- if (x >= childRect.left && x <= childRect.right &&
191
- y >= childRect.top && y <= childRect.bottom) {
192
- directChild = child;
193
- break;
194
- }
195
- }
196
- if (directChild) {
197
- if (directChild.children.length > 0) {
198
- const childIsHorizontal = isContainerHorizontal(directChild);
199
- const childRect = directChild.getBoundingClientRect();
200
- const deeperTarget = findClosestChildWithinMargin(directChild, x, y, draggedElement);
201
- if (deeperTarget) {
202
- if (!isValidVisibilityDrop(deeperTarget, draggedElement)) {
203
- return null;
204
- }
205
- const rect = deeperTarget.getBoundingClientRect();
206
- const position = getSiblingDropPosition(x, y, rect, childIsHorizontal);
207
- const parentRect = deeperTarget.parentElement?.getBoundingClientRect() ?? null;
208
- return { element: deeperTarget, position, rect, parentRect };
209
- }
210
- const nearestInChild = findNearestChild(directChild, x, y, childIsHorizontal, draggedElement);
211
- if (nearestInChild) {
212
- if (!isValidVisibilityDrop(nearestInChild.child, draggedElement)) {
213
- return null;
214
- }
215
- const rect = nearestInChild.child.getBoundingClientRect();
216
- return {
217
- element: nearestInChild.child,
218
- position: nearestInChild.position,
219
- rect,
220
- parentRect: childRect
221
- };
222
- }
223
- }
224
- if (!isValidVisibilityDrop(directChild, draggedElement)) {
225
- return null;
226
- }
227
- const rect = directChild.getBoundingClientRect();
228
- const position = getSiblingDropPosition(x, y, rect, isHorizontal);
229
- return { element: directChild, position, rect, parentRect: containerRect };
230
- }
231
- const nearbyChild = findClosestChildWithinMargin(targetElement, x, y, draggedElement);
232
- if (nearbyChild) {
233
- if (!isValidVisibilityDrop(nearbyChild, draggedElement)) {
234
- return null;
235
- }
236
- const childRect = nearbyChild.getBoundingClientRect();
237
- const position = getSiblingDropPosition(x, y, childRect, isHorizontal);
238
- return { element: nearbyChild, position, rect: childRect, parentRect: containerRect };
239
- }
240
- const nearest = findNearestChild(targetElement, x, y, isHorizontal, draggedElement);
241
- if (nearest) {
242
- if (!isValidVisibilityDrop(nearest.child, draggedElement)) {
243
- return null;
244
- }
245
- const childRect = nearest.child.getBoundingClientRect();
246
- return {
247
- element: nearest.child,
248
- position: nearest.position,
249
- rect: childRect,
250
- parentRect: containerRect
251
- };
252
- }
253
- }
254
- if (!isValidVisibilityDrop(targetElement, draggedElement)) {
255
- return null;
256
- }
257
- const rect = targetElement.getBoundingClientRect();
258
- const position = getDropZone(x, y, rect);
259
- const parentRect = getParentRect(targetElement);
260
- return { element: targetElement, position, rect, parentRect };
261
- }
262
- function cleanupWrapper(wrapper) {
263
- const parent = wrapper.parentElement;
264
- if (!parent)
265
- return;
266
- if (wrapper.children.length === 0) {
267
- parent.removeChild(wrapper);
268
- }
269
- else if (wrapper.children.length === 1) {
270
- const child = wrapper.children[0];
271
- parent.insertBefore(child, wrapper);
272
- parent.removeChild(wrapper);
273
- }
274
- }
275
- function executeMove(sourceElement, dropTarget) {
276
- if (!dropTarget)
277
- return;
278
- const originalParent = sourceElement.parentElement;
279
- const originalNextSibling = sourceElement.nextSibling;
280
- if (!originalParent)
281
- return;
282
- const fromPlacement = buildPlacementTarget(sourceElement);
283
- const originalParentWasWrapper = originalParent.hasAttribute(WRAPPER_ATTR);
284
- const wrapperToCleanup = originalParentWasWrapper ? originalParent : null;
285
- const { element: targetElement, position } = dropTarget;
286
- const targetParent = targetElement.parentElement;
287
- if (!targetParent)
288
- return;
289
- let newParent;
290
- let newNextSibling;
291
- let createdWrapper = null;
292
- if (position === 'left' || position === 'right') {
293
- if (isParentHorizontalFlex(targetElement)) {
294
- newParent = targetParent;
295
- if (position === 'left') {
296
- newNextSibling = targetElement;
297
- targetParent.insertBefore(sourceElement, targetElement);
298
- }
299
- else {
300
- newNextSibling = targetElement.nextSibling;
301
- targetParent.insertBefore(sourceElement, newNextSibling);
302
- }
303
- }
304
- else {
305
- const targetStyle = window.getComputedStyle(targetElement);
306
- const targetDisplay = targetStyle.display;
307
- const isTargetInline = targetDisplay === 'inline' || targetDisplay === 'inline-block' ||
308
- targetDisplay === 'inline-flex' || targetDisplay === 'inline-grid';
309
- const wrapper = document.createElement('div');
310
- wrapper.setAttribute(WRAPPER_ATTR, 'true');
311
- wrapper.style.display = isTargetInline ? 'inline-flex' : 'flex';
312
- wrapper.style.flexDirection = 'row';
313
- wrapper.style.alignItems = 'center';
314
- wrapper.style.gap = '8px';
315
- const wrapperInsertedBefore = targetElement.nextSibling;
316
- targetParent.insertBefore(wrapper, targetElement);
317
- wrapper.appendChild(targetElement);
318
- if (position === 'left') {
319
- wrapper.insertBefore(sourceElement, targetElement);
320
- newNextSibling = targetElement;
321
- }
322
- else {
323
- wrapper.appendChild(sourceElement);
324
- newNextSibling = null;
325
- }
326
- newParent = wrapper;
327
- createdWrapper = {
328
- type: 'horizontal',
329
- position: position,
330
- wrapperParent: targetParent,
331
- insertedBefore: wrapperInsertedBefore,
332
- targetElement: targetElement,
333
- styles: {
334
- display: wrapper.style.display,
335
- flexDirection: wrapper.style.flexDirection,
336
- alignItems: wrapper.style.alignItems,
337
- gap: wrapper.style.gap
338
- }
339
- };
340
- }
341
- }
342
- else {
343
- const wrapper = document.createElement('div');
344
- wrapper.setAttribute(WRAPPER_ATTR, 'true');
345
- wrapper.style.textAlign = 'inherit';
346
- const insertionRef = position === 'top' ? targetElement : targetElement.nextSibling;
347
- wrapper.appendChild(sourceElement);
348
- newParent = wrapper;
349
- newNextSibling = null;
350
- if (position === 'top') {
351
- targetParent.insertBefore(wrapper, targetElement);
352
- }
353
- else {
354
- targetParent.insertBefore(wrapper, targetElement.nextSibling);
355
- }
356
- createdWrapper = {
357
- type: 'vertical',
358
- position: position,
359
- wrapperParent: targetParent,
360
- insertedBefore: insertionRef,
361
- targetElement: targetElement,
362
- styles: {
363
- textAlign: wrapper.style.textAlign
364
- }
365
- };
366
- }
367
- if (wrapperToCleanup) {
368
- cleanupWrapper(wrapperToCleanup);
369
- }
370
- historyState.pushChange({
371
- type: 'move',
372
- element: sourceElement,
373
- originalParent,
374
- originalNextSibling,
375
- originalParentWasWrapper,
376
- newParent,
377
- newNextSibling,
378
- createdWrapper
379
- });
380
- if (fromPlacement && diffState) {
381
- diffState.trackElement(sourceElement, fromPlacement);
382
- }
383
- setTimeout(() => onRescan?.(), 50);
384
- }
385
- function executeUndo() {
386
- const entry = historyState.undo();
387
- if (!entry || entry.type !== 'move')
388
- return;
389
- const { element, originalParent, originalNextSibling, createdWrapper } = entry;
390
- if (!document.body.contains(element)) {
391
- console.warn('Undo failed: element no longer in DOM');
392
- return;
393
- }
394
- const currentParent = element.parentElement;
395
- if (createdWrapper) {
396
- const wrapper = currentParent;
397
- if (wrapper?.hasAttribute(WRAPPER_ATTR)) {
398
- const wrapperParent = wrapper.parentElement;
399
- if (wrapperParent) {
400
- const wrapperNextSibling = wrapper.nextSibling;
401
- while (wrapper.firstChild) {
402
- wrapperParent.insertBefore(wrapper.firstChild, wrapperNextSibling);
403
- }
404
- wrapperParent.removeChild(wrapper);
405
- }
406
- }
407
- }
408
- else if (currentParent?.hasAttribute(WRAPPER_ATTR)) {
409
- element.remove();
410
- cleanupWrapper(currentParent);
411
- }
412
- if (!document.body.contains(originalParent)) {
413
- console.warn('Undo: original parent no longer in DOM, element left in place');
414
- setTimeout(() => onRescan?.(), 50);
415
- return;
416
- }
417
- originalParent.insertBefore(element, originalNextSibling);
418
- setTimeout(() => onRescan?.(), 50);
419
- }
420
- function executeRedo() {
421
- const entry = historyState.redo();
422
- if (!entry || entry.type !== 'move')
423
- return;
424
- const { element, createdWrapper } = entry;
425
- if (!document.body.contains(element)) {
426
- console.warn('Redo failed: element no longer in DOM');
427
- return;
428
- }
429
- const currentParent = element.parentElement;
430
- if (currentParent?.hasAttribute(WRAPPER_ATTR)) {
431
- element.remove();
432
- cleanupWrapper(currentParent);
433
- }
434
- if (createdWrapper) {
435
- const { type, position, wrapperParent, targetElement, styles } = createdWrapper;
436
- if (!document.body.contains(wrapperParent) || !document.body.contains(targetElement)) {
437
- console.warn('Redo failed: wrapper parent or target element no longer in DOM');
438
- return;
439
- }
440
- if (type === 'horizontal') {
441
- const wrapper = document.createElement('div');
442
- wrapper.setAttribute(WRAPPER_ATTR, 'true');
443
- Object.assign(wrapper.style, styles);
444
- wrapperParent.insertBefore(wrapper, targetElement);
445
- wrapper.appendChild(targetElement);
446
- if (position === 'left') {
447
- wrapper.insertBefore(element, targetElement);
448
- }
449
- else {
450
- wrapper.appendChild(element);
451
- }
452
- }
453
- else {
454
- const wrapper = document.createElement('div');
455
- wrapper.setAttribute(WRAPPER_ATTR, 'true');
456
- Object.assign(wrapper.style, styles);
457
- wrapper.appendChild(element);
458
- if (position === 'top') {
459
- wrapperParent.insertBefore(wrapper, targetElement);
460
- }
461
- else {
462
- wrapperParent.insertBefore(wrapper, targetElement.nextSibling);
463
- }
464
- }
465
- }
466
- else {
467
- const { newParent, newNextSibling } = entry;
468
- if (!document.body.contains(newParent)) {
469
- console.warn('Redo failed: new parent no longer in DOM');
470
- return;
471
- }
472
- newParent.insertBefore(element, newNextSibling);
473
- }
474
- setTimeout(() => onRescan?.(), 50);
475
- }
476
- function handleMouseDown(e, element) {
477
- const state = editorState.getState();
478
- if (!element) {
479
- if (state.selectedElement) {
480
- editorState.clearSelection();
481
- overlays.hideSelection();
482
- }
483
- return;
484
- }
485
- mouseDownInfo = {
486
- x: e.clientX,
487
- y: e.clientY,
488
- element
489
- };
490
- if (element !== state.selectedElement && state.selectedElement) {
491
- editorState.clearSelection();
492
- overlays.hideSelection();
493
- }
494
- }
495
- function handleMouseMove(e, element) {
496
- if (mouseDownInfo && !dragInfo) {
497
- const dx = e.clientX - mouseDownInfo.x;
498
- const dy = e.clientY - mouseDownInfo.y;
499
- const distance = Math.sqrt(dx * dx + dy * dy);
500
- if (distance >= DRAG_THRESHOLD) {
501
- const dragElement = mouseDownInfo.element;
502
- const rect = dragElement.getBoundingClientRect();
503
- const grabOffsetX = mouseDownInfo.x - rect.left;
504
- const grabOffsetY = mouseDownInfo.y - rect.top;
505
- dragInfo = {
506
- element: dragElement,
507
- rect,
508
- startX: mouseDownInfo.x,
509
- startY: mouseDownInfo.y,
510
- grabOffsetX,
511
- grabOffsetY
512
- };
513
- editorState.startDrag(dragElement, rect);
514
- editorState.clearHover();
515
- overlays.hideHover();
516
- overlays.hideSelection();
517
- freezeOverlay?.setCursor('grabbing');
518
- }
519
- }
520
- if (dragInfo) {
521
- const dropTarget = findDropTarget(e.clientX, e.clientY, dragInfo.element);
522
- const ghostPos = { x: e.clientX, y: e.clientY };
523
- editorState.updateDrag(ghostPos, dropTarget);
524
- overlays.showDragGhost(dragInfo.rect, ghostPos, dragInfo.grabOffsetX, dragInfo.grabOffsetY);
525
- if (dropTarget) {
526
- overlays.showDropIndicator(dropTarget.rect, dropTarget.position, dropTarget.parentRect);
527
- overlays.hideNoDropIndicator();
528
- freezeOverlay?.setCursor('grabbing');
529
- }
530
- else {
531
- overlays.hideDropIndicator();
532
- const overlay = document.getElementById('__editor-freeze-overlay__');
533
- const overlaysContainer = document.getElementById('__editor-overlays__');
534
- if (overlay)
535
- overlay.style.pointerEvents = 'none';
536
- if (overlaysContainer)
537
- overlaysContainer.style.display = 'none';
538
- const elementUnderCursor = document.elementFromPoint(e.clientX, e.clientY);
539
- if (overlay)
540
- overlay.style.pointerEvents = 'auto';
541
- if (overlaysContainer)
542
- overlaysContainer.style.display = '';
543
- if (elementUnderCursor &&
544
- contentRoot.contains(elementUnderCursor) &&
545
- !isEditorElement(elementUnderCursor) &&
546
- elementUnderCursor !== dragInfo.element &&
547
- !canDropInZone(dragInfo.element, elementUnderCursor)) {
548
- const rect = elementUnderCursor.getBoundingClientRect();
549
- overlays.showNoDropIndicator(rect);
550
- freezeOverlay?.setCursor('not-allowed');
551
- }
552
- else {
553
- overlays.hideNoDropIndicator();
554
- freezeOverlay?.setCursor('grabbing');
555
- }
556
- }
557
- return;
558
- }
559
- if (element) {
560
- const rect = element.getBoundingClientRect();
561
- editorState.setHover(null, element, rect);
562
- overlays.showHover(rect);
563
- }
564
- else {
565
- editorState.clearHover();
566
- overlays.hideHover();
567
- }
568
- }
569
- function handleMouseUp(e, _element) {
570
- if (dragInfo) {
571
- const dropTarget = findDropTarget(e.clientX, e.clientY, dragInfo.element);
572
- if (dropTarget) {
573
- executeMove(dragInfo.element, dropTarget);
574
- }
575
- dragEndTime = Date.now();
576
- editorState.endDrag();
577
- overlays.hideDragGhost();
578
- overlays.hideDropIndicator();
579
- overlays.hideNoDropIndicator();
580
- editorState.clearHover();
581
- overlays.hideHover();
582
- freezeOverlay?.setCursor('default');
583
- }
584
- mouseDownInfo = null;
585
- dragInfo = null;
586
- }
587
- function handleMouseLeave(_e) {
588
- editorState.clearHover();
589
- overlays.hideHover();
590
- if (dragInfo) {
591
- editorState.endDrag();
592
- overlays.hideDragGhost();
593
- overlays.hideDropIndicator();
594
- overlays.hideNoDropIndicator();
595
- freezeOverlay?.setCursor('default');
596
- }
597
- mouseDownInfo = null;
598
- dragInfo = null;
599
- }
600
- function handleClick(e, element) {
601
- if (Date.now() - dragEndTime < 200) {
602
- return;
603
- }
604
- if (element) {
605
- const rect = element.getBoundingClientRect();
606
- const state = editorState.getState();
607
- if (state.selectedElement === element) {
608
- editorState.clearSelection();
609
- overlays.hideSelection();
610
- return;
611
- }
612
- editorState.setSelection(element, rect);
613
- overlays.showSelection(rect);
614
- }
615
- else {
616
- editorState.clearSelection();
617
- overlays.hideSelection();
618
- }
619
- }
620
- function handleDoubleClick(_e, element) {
621
- if (element && element.children.length > 0) {
622
- editorState.incrementDrillDepth();
623
- }
624
- }
625
- function handleWheel(_e) {
626
- requestAnimationFrame(() => {
627
- const state = editorState.getState();
628
- if (state.hoveredElement) {
629
- const rect = state.hoveredElement.getBoundingClientRect();
630
- editorState.setHover(null, state.hoveredElement, rect);
631
- overlays.showHover(rect);
632
- }
633
- if (state.selectedElement) {
634
- const rect = state.selectedElement.getBoundingClientRect();
635
- editorState.setSelection(state.selectedElement, rect);
636
- overlays.showSelection(rect);
637
- }
638
- });
639
- }
640
- function handleKeyDown(e) {
641
- const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
642
- const modifier = isMac ? e.metaKey : e.ctrlKey;
643
- if (modifier && e.key === 'z') {
644
- e.preventDefault();
645
- if (e.shiftKey) {
646
- if (historyState.canRedo()) {
647
- executeRedo();
648
- }
649
- }
650
- else {
651
- if (historyState.canUndo()) {
652
- executeUndo();
653
- }
654
- }
655
- }
656
- if (modifier && e.key === 'y') {
657
- e.preventDefault();
658
- if (historyState.canRedo()) {
659
- executeRedo();
660
- }
661
- }
662
- }
663
- function attach() {
664
- window.addEventListener('keydown', handleKeyDown);
665
- }
666
- function detach() {
667
- window.removeEventListener('keydown', handleKeyDown);
668
- mouseDownInfo = null;
669
- dragInfo = null;
670
- }
671
- return {
672
- attach,
673
- detach,
674
- setFreezeOverlay,
675
- handleMouseDown,
676
- handleMouseMove,
677
- handleMouseUp,
678
- handleMouseLeave,
679
- handleClick,
680
- handleDoubleClick,
681
- handleWheel,
682
- executeUndo,
683
- executeRedo,
684
- findDropTarget
685
- };
686
- }