dockview-core 6.2.2 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +1 -0
  2. package/dist/cjs/api/dockviewGroupPanelApi.d.ts +10 -1
  3. package/dist/cjs/api/dockviewGroupPanelApi.js +16 -0
  4. package/dist/cjs/dnd/backend.d.ts +70 -0
  5. package/dist/cjs/dnd/backend.js +171 -0
  6. package/dist/cjs/dnd/dropOverlay.d.ts +20 -0
  7. package/dist/cjs/dnd/dropOverlay.js +197 -0
  8. package/dist/cjs/dnd/droptarget.d.ts +20 -6
  9. package/dist/cjs/dnd/droptarget.js +14 -208
  10. package/dist/cjs/dnd/pointer/index.d.ts +11 -0
  11. package/dist/cjs/dnd/pointer/index.js +13 -0
  12. package/dist/cjs/dnd/pointer/longPress.d.ts +32 -0
  13. package/dist/cjs/dnd/pointer/longPress.js +151 -0
  14. package/dist/cjs/dnd/pointer/pointerDragController.d.ts +60 -0
  15. package/dist/cjs/dnd/pointer/pointerDragController.js +241 -0
  16. package/dist/cjs/dnd/pointer/pointerDragSource.d.ts +61 -0
  17. package/dist/cjs/dnd/pointer/pointerDragSource.js +195 -0
  18. package/dist/cjs/dnd/pointer/pointerDropTarget.d.ts +39 -0
  19. package/dist/cjs/dnd/pointer/pointerDropTarget.js +198 -0
  20. package/dist/cjs/dnd/pointer/pointerGhost.d.ts +30 -0
  21. package/dist/cjs/dnd/pointer/pointerGhost.js +44 -0
  22. package/dist/cjs/dnd/pointer/types.d.ts +16 -0
  23. package/dist/cjs/dnd/pointer/types.js +2 -0
  24. package/dist/cjs/dockview/components/panel/content.d.ts +3 -1
  25. package/dist/cjs/dockview/components/panel/content.js +33 -16
  26. package/dist/cjs/dockview/components/popupService.js +34 -0
  27. package/dist/cjs/dockview/components/tab/tab.d.ts +11 -3
  28. package/dist/cjs/dockview/components/tab/tab.js +151 -117
  29. package/dist/cjs/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
  30. package/dist/cjs/dockview/components/titlebar/tabGroupChip.js +15 -6
  31. package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.js +2 -2
  32. package/dist/cjs/dockview/components/titlebar/tabGroups.d.ts +33 -5
  33. package/dist/cjs/dockview/components/titlebar/tabGroups.js +231 -40
  34. package/dist/cjs/dockview/components/titlebar/tabs.d.ts +38 -1
  35. package/dist/cjs/dockview/components/titlebar/tabs.js +381 -253
  36. package/dist/cjs/dockview/components/titlebar/tabsContainer.d.ts +5 -3
  37. package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +6 -2
  38. package/dist/cjs/dockview/components/titlebar/voidContainer.js +190 -22
  39. package/dist/cjs/dockview/contextMenu.js +19 -4
  40. package/dist/cjs/dockview/dndCapabilities.d.ts +19 -0
  41. package/dist/cjs/dockview/dndCapabilities.js +39 -0
  42. package/dist/cjs/dockview/dockviewComponent.d.ts +2 -0
  43. package/dist/cjs/dockview/dockviewComponent.js +241 -158
  44. package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +10 -5
  45. package/dist/cjs/dockview/dockviewGroupPanelModel.js +34 -11
  46. package/dist/cjs/dockview/dockviewPanel.js +5 -0
  47. package/dist/cjs/dockview/dockviewPanelModel.d.ts +2 -0
  48. package/dist/cjs/dockview/dockviewPanelModel.js +8 -0
  49. package/dist/cjs/dockview/events.d.ts +2 -1
  50. package/dist/cjs/dockview/events.js +1 -0
  51. package/dist/cjs/dockview/framework.d.ts +8 -0
  52. package/dist/cjs/dockview/options.d.ts +31 -5
  53. package/dist/cjs/dockview/options.js +3 -0
  54. package/dist/cjs/dom.d.ts +5 -1
  55. package/dist/cjs/dom.js +21 -5
  56. package/dist/cjs/index.d.ts +1 -1
  57. package/dist/cjs/overlay/overlay.d.ts +12 -0
  58. package/dist/cjs/overlay/overlay.js +84 -16
  59. package/dist/cjs/paneview/draggablePaneviewPanel.d.ts +3 -1
  60. package/dist/cjs/paneview/draggablePaneviewPanel.js +27 -26
  61. package/dist/cjs/paneview/options.d.ts +4 -3
  62. package/dist/cjs/popoutWindow.d.ts +2 -0
  63. package/dist/cjs/popoutWindow.js +3 -1
  64. package/dist/dockview-core.js +2431 -937
  65. package/dist/dockview-core.min.js +2 -2
  66. package/dist/dockview-core.min.js.map +1 -1
  67. package/dist/dockview-core.min.noStyle.js +2 -2
  68. package/dist/dockview-core.min.noStyle.js.map +1 -1
  69. package/dist/dockview-core.noStyle.js +2430 -936
  70. package/dist/esm/api/dockviewGroupPanelApi.d.ts +10 -1
  71. package/dist/esm/api/dockviewGroupPanelApi.js +12 -0
  72. package/dist/esm/dnd/backend.d.ts +70 -0
  73. package/dist/esm/dnd/backend.js +148 -0
  74. package/dist/esm/dnd/dropOverlay.d.ts +20 -0
  75. package/dist/esm/dnd/dropOverlay.js +192 -0
  76. package/dist/esm/dnd/droptarget.d.ts +20 -6
  77. package/dist/esm/dnd/droptarget.js +16 -210
  78. package/dist/esm/dnd/pointer/index.d.ts +11 -0
  79. package/dist/esm/dnd/pointer/index.js +5 -0
  80. package/dist/esm/dnd/pointer/longPress.d.ts +32 -0
  81. package/dist/esm/dnd/pointer/longPress.js +127 -0
  82. package/dist/esm/dnd/pointer/pointerDragController.d.ts +60 -0
  83. package/dist/esm/dnd/pointer/pointerDragController.js +191 -0
  84. package/dist/esm/dnd/pointer/pointerDragSource.d.ts +61 -0
  85. package/dist/esm/dnd/pointer/pointerDragSource.js +171 -0
  86. package/dist/esm/dnd/pointer/pointerDropTarget.d.ts +39 -0
  87. package/dist/esm/dnd/pointer/pointerDropTarget.js +168 -0
  88. package/dist/esm/dnd/pointer/pointerGhost.d.ts +30 -0
  89. package/dist/esm/dnd/pointer/pointerGhost.js +39 -0
  90. package/dist/esm/dnd/pointer/types.d.ts +16 -0
  91. package/dist/esm/dnd/pointer/types.js +1 -0
  92. package/dist/esm/dockview/components/panel/content.d.ts +3 -1
  93. package/dist/esm/dockview/components/panel/content.js +33 -16
  94. package/dist/esm/dockview/components/popupService.js +34 -0
  95. package/dist/esm/dockview/components/tab/tab.d.ts +11 -3
  96. package/dist/esm/dockview/components/tab/tab.js +139 -114
  97. package/dist/esm/dockview/components/titlebar/tabGroupChip.d.ts +9 -2
  98. package/dist/esm/dockview/components/titlebar/tabGroupChip.js +15 -6
  99. package/dist/esm/dockview/components/titlebar/tabGroupIndicator.js +2 -2
  100. package/dist/esm/dockview/components/titlebar/tabGroups.d.ts +33 -5
  101. package/dist/esm/dockview/components/titlebar/tabGroups.js +177 -12
  102. package/dist/esm/dockview/components/titlebar/tabs.d.ts +38 -1
  103. package/dist/esm/dockview/components/titlebar/tabs.js +360 -229
  104. package/dist/esm/dockview/components/titlebar/tabsContainer.d.ts +5 -3
  105. package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +6 -2
  106. package/dist/esm/dockview/components/titlebar/voidContainer.js +180 -26
  107. package/dist/esm/dockview/contextMenu.js +19 -4
  108. package/dist/esm/dockview/dndCapabilities.d.ts +19 -0
  109. package/dist/esm/dockview/dndCapabilities.js +36 -0
  110. package/dist/esm/dockview/dockviewComponent.d.ts +2 -0
  111. package/dist/esm/dockview/dockviewComponent.js +104 -41
  112. package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +10 -5
  113. package/dist/esm/dockview/dockviewGroupPanelModel.js +33 -11
  114. package/dist/esm/dockview/dockviewPanel.js +5 -0
  115. package/dist/esm/dockview/dockviewPanelModel.d.ts +2 -0
  116. package/dist/esm/dockview/dockviewPanelModel.js +8 -0
  117. package/dist/esm/dockview/events.d.ts +2 -1
  118. package/dist/esm/dockview/events.js +1 -0
  119. package/dist/esm/dockview/framework.d.ts +8 -0
  120. package/dist/esm/dockview/options.d.ts +31 -5
  121. package/dist/esm/dockview/options.js +3 -0
  122. package/dist/esm/dom.d.ts +5 -1
  123. package/dist/esm/dom.js +20 -5
  124. package/dist/esm/index.d.ts +1 -1
  125. package/dist/esm/overlay/overlay.d.ts +12 -0
  126. package/dist/esm/overlay/overlay.js +85 -17
  127. package/dist/esm/paneview/draggablePaneviewPanel.d.ts +3 -1
  128. package/dist/esm/paneview/draggablePaneviewPanel.js +26 -20
  129. package/dist/esm/paneview/options.d.ts +4 -3
  130. package/dist/esm/popoutWindow.d.ts +2 -0
  131. package/dist/esm/popoutWindow.js +3 -1
  132. package/dist/package/main.cjs.js +2430 -936
  133. package/dist/package/main.cjs.min.js +2 -2
  134. package/dist/package/main.esm.min.mjs +2 -2
  135. package/dist/package/main.esm.mjs +2430 -936
  136. package/dist/styles/dockview.css +117 -1
  137. package/package.json +3 -1
  138. package/dist/cjs/dnd/abstractDragHandler.d.ts +0 -14
  139. package/dist/cjs/dnd/abstractDragHandler.js +0 -86
  140. package/dist/cjs/dnd/groupDragHandler.d.ts +0 -12
  141. package/dist/cjs/dnd/groupDragHandler.js +0 -82
  142. package/dist/esm/dnd/abstractDragHandler.d.ts +0 -14
  143. package/dist/esm/dnd/abstractDragHandler.js +0 -63
  144. package/dist/esm/dnd/groupDragHandler.d.ts +0 -12
  145. package/dist/esm/dnd/groupDragHandler.js +0 -59
@@ -1,50 +1,7 @@
1
- import { toggleClass } from '../dom';
2
1
  import { DockviewEvent, Emitter } from '../events';
3
2
  import { CompositeDisposable } from '../lifecycle';
4
3
  import { DragAndDropObserver } from './dnd';
5
- import { clamp } from '../math';
6
- function setGPUOptimizedBounds(element, bounds) {
7
- const { top, left, width, height } = bounds;
8
- const topPx = `${Math.round(top)}px`;
9
- const leftPx = `${Math.round(left)}px`;
10
- const widthPx = `${Math.round(width)}px`;
11
- const heightPx = `${Math.round(height)}px`;
12
- // Use traditional positioning but maintain GPU layer
13
- element.style.top = topPx;
14
- element.style.left = leftPx;
15
- element.style.width = widthPx;
16
- element.style.height = heightPx;
17
- element.style.visibility = 'visible';
18
- // Ensure GPU layer is maintained
19
- if (!element.style.transform || element.style.transform === '') {
20
- element.style.transform = 'translate3d(0, 0, 0)';
21
- }
22
- }
23
- function setGPUOptimizedBoundsFromStrings(element, bounds) {
24
- const { top, left, width, height } = bounds;
25
- // Use traditional positioning but maintain GPU layer
26
- element.style.top = top;
27
- element.style.left = left;
28
- element.style.width = width;
29
- element.style.height = height;
30
- element.style.visibility = 'visible';
31
- // Ensure GPU layer is maintained
32
- if (!element.style.transform || element.style.transform === '') {
33
- element.style.transform = 'translate3d(0, 0, 0)';
34
- }
35
- }
36
- function checkBoundsChanged(element, bounds) {
37
- const { top, left, width, height } = bounds;
38
- const topPx = `${Math.round(top)}px`;
39
- const leftPx = `${Math.round(left)}px`;
40
- const widthPx = `${Math.round(width)}px`;
41
- const heightPx = `${Math.round(height)}px`;
42
- // Check if position or size changed (back to traditional method)
43
- return (element.style.top !== topPx ||
44
- element.style.left !== leftPx ||
45
- element.style.width !== widthPx ||
46
- element.style.height !== heightPx);
47
- }
4
+ import { createOverlayElements, renderAnchoredOverlay, renderInPlaceOverlay, } from './dropOverlay';
48
5
  export class WillShowOverlayEvent extends DockviewEvent {
49
6
  get nativeEvent() {
50
7
  return this.options.nativeEvent;
@@ -93,12 +50,6 @@ const DEFAULT_ACTIVATION_SIZE = {
93
50
  value: 20,
94
51
  type: 'percentage',
95
52
  };
96
- const DEFAULT_SIZE = {
97
- value: 50,
98
- type: 'percentage',
99
- };
100
- const SMALL_WIDTH_BOUNDARY = 100;
101
- const SMALL_HEIGHT_BOUNDARY = 100;
102
53
  export class Droptarget extends CompositeDisposable {
103
54
  get disabled() {
104
55
  return this._disabled;
@@ -181,20 +132,12 @@ export class Droptarget extends CompositeDisposable {
181
132
  //
182
133
  }
183
134
  else if (!this.targetElement) {
184
- this.targetElement = document.createElement('div');
185
- this.targetElement.className = 'dv-drop-target-dropzone';
186
- this.overlayElement = document.createElement('div');
187
- this.overlayElement.className = 'dv-drop-target-selection';
135
+ const els = createOverlayElements();
136
+ this.targetElement = els.dropzone;
137
+ this.overlayElement = els.selection;
188
138
  this._state = 'center';
189
- this.targetElement.appendChild(this.overlayElement);
190
139
  target.classList.add('dv-drop-target');
191
140
  target.append(this.targetElement);
192
- // this.overlayElement.style.opacity = '0';
193
- // requestAnimationFrame(() => {
194
- // if (this.overlayElement) {
195
- // this.overlayElement.style.opacity = '';
196
- // }
197
- // });
198
141
  }
199
142
  this.toggleClasses(quadrant, width, height);
200
143
  this._state = quadrant;
@@ -264,162 +207,25 @@ export class Droptarget extends CompositeDisposable {
264
207
  return typeof value === 'boolean' && value;
265
208
  }
266
209
  toggleClasses(quadrant, width, height) {
267
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
210
+ var _a, _b, _c, _d, _e;
268
211
  const target = (_b = (_a = this.options).getOverrideTarget) === null || _b === void 0 ? void 0 : _b.call(_a);
269
- if (!target && !this.overlayElement) {
270
- return;
271
- }
272
- const smallWidthBoundary = (_d = (_c = this.options.overlayModel) === null || _c === void 0 ? void 0 : _c.smallWidthBoundary) !== null && _d !== void 0 ? _d : SMALL_WIDTH_BOUNDARY;
273
- const smallHeightBoundary = (_f = (_e = this.options.overlayModel) === null || _e === void 0 ? void 0 : _e.smallHeightBoundary) !== null && _f !== void 0 ? _f : SMALL_HEIGHT_BOUNDARY;
274
- const isSmallX = width < smallWidthBoundary;
275
- const isSmallY = height < smallHeightBoundary;
276
- const isLeft = quadrant === 'left';
277
- const isRight = quadrant === 'right';
278
- const isTop = quadrant === 'top';
279
- const isBottom = quadrant === 'bottom';
280
- const rightClass = !isSmallX && isRight;
281
- const leftClass = !isSmallX && isLeft;
282
- const topClass = !isSmallY && isTop;
283
- const bottomClass = !isSmallY && isBottom;
284
- let size = 1;
285
- const sizeOptions = (_h = (_g = this.options.overlayModel) === null || _g === void 0 ? void 0 : _g.size) !== null && _h !== void 0 ? _h : DEFAULT_SIZE;
286
- if (sizeOptions.type === 'percentage') {
287
- size = clamp(sizeOptions.value, 0, 100) / 100;
288
- }
289
- else {
290
- if (rightClass || leftClass) {
291
- size = clamp(0, sizeOptions.value, width) / width;
292
- }
293
- if (topClass || bottomClass) {
294
- size = clamp(0, sizeOptions.value, height) / height;
295
- }
296
- }
297
212
  if (target) {
298
- const outlineEl = (_l = (_k = (_j = this.options).getOverlayOutline) === null || _k === void 0 ? void 0 : _k.call(_j)) !== null && _l !== void 0 ? _l : this.element;
299
- const elBox = outlineEl.getBoundingClientRect();
300
- const ta = target.getElements(undefined, outlineEl);
301
- const el = ta.root;
302
- const overlay = ta.overlay;
303
- const bigbox = el.getBoundingClientRect();
304
- const rootTop = elBox.top - bigbox.top;
305
- const rootLeft = elBox.left - bigbox.left;
306
- const box = {
307
- top: rootTop,
308
- left: rootLeft,
309
- width: width,
310
- height: height,
311
- };
312
- if (rightClass) {
313
- box.left = rootLeft + width * (1 - size);
314
- box.width = width * size;
315
- }
316
- else if (leftClass) {
317
- box.width = width * size;
318
- }
319
- else if (topClass) {
320
- box.height = height * size;
321
- }
322
- else if (bottomClass) {
323
- box.top = rootTop + height * (1 - size);
324
- box.height = height * size;
325
- }
326
- if (isSmallX && isLeft) {
327
- box.width = 4;
328
- }
329
- if (isSmallX && isRight) {
330
- box.left = rootLeft + width - 4;
331
- box.width = 4;
332
- }
333
- if (isSmallY && isTop) {
334
- box.height = 4;
335
- }
336
- if (isSmallY && isBottom) {
337
- box.top = rootTop + height - 4;
338
- box.height = 4;
339
- }
340
- // Use GPU-optimized bounds checking and setting
341
- if (!checkBoundsChanged(overlay, box)) {
342
- return;
343
- }
344
- setGPUOptimizedBounds(overlay, box);
345
- overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
346
- toggleClass(overlay, 'dv-drop-target-left', isLeft);
347
- toggleClass(overlay, 'dv-drop-target-right', isRight);
348
- toggleClass(overlay, 'dv-drop-target-top', isTop);
349
- toggleClass(overlay, 'dv-drop-target-bottom', isBottom);
350
- toggleClass(overlay, 'dv-drop-target-anchor-line', (isSmallX && (isLeft || isRight)) ||
351
- (isSmallY && (isTop || isBottom)));
352
- toggleClass(overlay, 'dv-drop-target-center', quadrant === 'center');
353
- if (ta.changed) {
354
- toggleClass(overlay, 'dv-drop-target-anchor-container-changed', true);
355
- setTimeout(() => {
356
- toggleClass(overlay, 'dv-drop-target-anchor-container-changed', false);
357
- }, 10);
358
- }
213
+ const outlineEl = (_e = (_d = (_c = this.options).getOverlayOutline) === null || _d === void 0 ? void 0 : _d.call(_c)) !== null && _e !== void 0 ? _e : this.element;
214
+ renderAnchoredOverlay({
215
+ outlineElement: outlineEl,
216
+ targetModel: target,
217
+ quadrant,
218
+ width,
219
+ height,
220
+ overlayModel: this.options.overlayModel,
221
+ className: this.options.className,
222
+ });
359
223
  return;
360
224
  }
361
225
  if (!this.overlayElement) {
362
226
  return;
363
227
  }
364
- const box = { top: '0px', left: '0px', width: '100%', height: '100%' };
365
- /**
366
- * You can also achieve the overlay placement using the transform CSS property
367
- * to translate and scale the element however this has the undesired effect of
368
- * 'skewing' the element. Comment left here for anybody that ever revisits this.
369
- *
370
- * @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform
371
- *
372
- * right
373
- * translateX(${100 * (1 - size) / 2}%) scaleX(${scale})
374
- *
375
- * left
376
- * translateX(-${100 * (1 - size) / 2}%) scaleX(${scale})
377
- *
378
- * top
379
- * translateY(-${100 * (1 - size) / 2}%) scaleY(${scale})
380
- *
381
- * bottom
382
- * translateY(${100 * (1 - size) / 2}%) scaleY(${scale})
383
- */
384
- if (rightClass) {
385
- box.left = `${100 * (1 - size)}%`;
386
- box.width = `${100 * size}%`;
387
- }
388
- else if (leftClass) {
389
- box.width = `${100 * size}%`;
390
- }
391
- else if (topClass) {
392
- box.height = `${100 * size}%`;
393
- }
394
- else if (bottomClass) {
395
- box.top = `${100 * (1 - size)}%`;
396
- box.height = `${100 * size}%`;
397
- }
398
- if (isSmallX && isLeft) {
399
- box.width = '4px';
400
- }
401
- if (isSmallX && isRight) {
402
- box.left = `${width - 4}px`;
403
- box.width = '4px';
404
- }
405
- if (isSmallY && isTop) {
406
- box.height = '4px';
407
- }
408
- if (isSmallY && isBottom) {
409
- box.top = `${height - 4}px`;
410
- box.height = '4px';
411
- }
412
- setGPUOptimizedBoundsFromStrings(this.overlayElement, box);
413
- const isLine = (isSmallX && (isLeft || isRight)) ||
414
- (isSmallY && (isTop || isBottom));
415
- toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
416
- toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
417
- toggleClass(this.overlayElement, 'dv-drop-target-selection-line', isLine);
418
- toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
419
- toggleClass(this.overlayElement, 'dv-drop-target-right', isRight);
420
- toggleClass(this.overlayElement, 'dv-drop-target-top', isTop);
421
- toggleClass(this.overlayElement, 'dv-drop-target-bottom', isBottom);
422
- toggleClass(this.overlayElement, 'dv-drop-target-center', quadrant === 'center');
228
+ renderInPlaceOverlay(this.overlayElement, quadrant, width, height, this.options.overlayModel);
423
229
  }
424
230
  calculateQuadrant(overlayType, x, y, width, height) {
425
231
  var _a, _b;
@@ -0,0 +1,11 @@
1
+ export { PointerDragController } from './pointerDragController';
2
+ export type { ActiveDrag } from './pointerDragController';
3
+ export { PointerDragSource } from './pointerDragSource';
4
+ export type { PointerDragSourceOptions } from './pointerDragSource';
5
+ export { PointerDropTarget } from './pointerDropTarget';
6
+ export type { PointerDropTargetOptions } from './pointerDropTarget';
7
+ export type { PointerDragEvent, PointerDroptargetEvent, IPointerDropTargetHandle, } from './types';
8
+ export { LongPressDetector } from './longPress';
9
+ export type { LongPressOptions } from './longPress';
10
+ export { PointerGhost } from './pointerGhost';
11
+ export type { PointerGhostOptions } from './pointerGhost';
@@ -0,0 +1,5 @@
1
+ export { PointerDragController } from './pointerDragController';
2
+ export { PointerDragSource } from './pointerDragSource';
3
+ export { PointerDropTarget } from './pointerDropTarget';
4
+ export { LongPressDetector } from './longPress';
5
+ export { PointerGhost } from './pointerGhost';
@@ -0,0 +1,32 @@
1
+ import { CompositeDisposable } from '../../lifecycle';
2
+ export interface LongPressOptions {
3
+ /** Default 500ms. */
4
+ delay?: number;
5
+ /** Default 8px. */
6
+ tolerance?: number;
7
+ /** Default true: mouse users have right-click and don't need this. */
8
+ touchOnly?: boolean;
9
+ /** Receives the `pointerdown` event so consumers can read `clientX/Y`. */
10
+ onLongPress: (event: PointerEvent) => void;
11
+ }
12
+ /**
13
+ * Passive — does not consume the pointer; movement past `tolerance`
14
+ * cancels silently so a sibling `PointerDragSource` can take over.
15
+ */
16
+ export declare class LongPressDetector extends CompositeDisposable {
17
+ private readonly element;
18
+ private readonly options;
19
+ private _pointerId;
20
+ private _startX;
21
+ private _startY;
22
+ private _timer;
23
+ private _moveListener;
24
+ private _upListener;
25
+ private _cancelListener;
26
+ constructor(element: HTMLElement, options: LongPressOptions);
27
+ private _onPointerDown;
28
+ private _installContextMenuGuard;
29
+ private _installClickGuard;
30
+ private _cancelPending;
31
+ dispose(): void;
32
+ }
@@ -0,0 +1,127 @@
1
+ import { addDisposableListener } from '../../events';
2
+ import { CompositeDisposable } from '../../lifecycle';
3
+ const DEFAULT_DELAY = 500;
4
+ const DEFAULT_TOLERANCE = 8;
5
+ /**
6
+ * Passive — does not consume the pointer; movement past `tolerance`
7
+ * cancels silently so a sibling `PointerDragSource` can take over.
8
+ */
9
+ export class LongPressDetector extends CompositeDisposable {
10
+ constructor(element, options) {
11
+ super();
12
+ this.element = element;
13
+ this.options = options;
14
+ this._startX = 0;
15
+ this._startY = 0;
16
+ this.addDisposables(addDisposableListener(this.element, 'pointerdown', (e) => {
17
+ this._onPointerDown(e);
18
+ }));
19
+ }
20
+ _onPointerDown(event) {
21
+ var _a, _b, _c, _d, _e;
22
+ const touchOnly = (_a = this.options.touchOnly) !== null && _a !== void 0 ? _a : true;
23
+ if (touchOnly &&
24
+ event.pointerType !== 'touch' &&
25
+ event.pointerType !== 'pen') {
26
+ return;
27
+ }
28
+ // Defensive — supersede any in-flight press.
29
+ this._cancelPending();
30
+ this._pointerId = event.pointerId;
31
+ this._startX = event.clientX;
32
+ this._startY = event.clientY;
33
+ const delay = (_b = this.options.delay) !== null && _b !== void 0 ? _b : DEFAULT_DELAY;
34
+ const tolerance = (_c = this.options.tolerance) !== null && _c !== void 0 ? _c : DEFAULT_TOLERANCE;
35
+ // Source's owning window — popout drags fire on their own window.
36
+ const targetWindow = (_e = (_d = this.element.ownerDocument) === null || _d === void 0 ? void 0 : _d.defaultView) !== null && _e !== void 0 ? _e : window;
37
+ this._timer = setTimeout(() => {
38
+ this._timer = undefined;
39
+ this._cancelPending();
40
+ // Touch browsers synthesize a compatibility `contextmenu` event
41
+ // for long-press. preventDefault on the original pointerdown is
42
+ // too late (already dispatched), so install a one-shot
43
+ // capture-phase guard for the next contextmenu. Without this,
44
+ // consumers that don't preventDefault inside their onLongPress
45
+ // (or that early-return before doing so) leak the browser's
46
+ // native menu on top of theirs.
47
+ this._installContextMenuGuard(targetWindow);
48
+ // Same idea for `click`: when the user releases their finger
49
+ // after the long-press, touch browsers dispatch a `click` to
50
+ // the element the touch ended on (the source). Consumers
51
+ // typically wire click to a primary action (e.g. tab activate,
52
+ // tab-group chip collapse-toggle). Without this guard, the
53
+ // long-press immediately fires both the context menu AND the
54
+ // primary action — and the action's side effects (e.g. a chip
55
+ // collapse animation) read as a screen wobble while the menu
56
+ // is supposed to be open. Scoped to the source element so
57
+ // clicks on menu items elsewhere remain effective.
58
+ this._installClickGuard(targetWindow);
59
+ this.options.onLongPress(event);
60
+ }, delay);
61
+ this._moveListener = addDisposableListener(targetWindow, 'pointermove', (moveEvent) => {
62
+ if (moveEvent.pointerId !== this._pointerId) {
63
+ return;
64
+ }
65
+ const dx = moveEvent.clientX - this._startX;
66
+ const dy = moveEvent.clientY - this._startY;
67
+ if (Math.hypot(dx, dy) > tolerance) {
68
+ this._cancelPending();
69
+ }
70
+ });
71
+ this._upListener = addDisposableListener(targetWindow, 'pointerup', (upEvent) => {
72
+ if (upEvent.pointerId !== this._pointerId) {
73
+ return;
74
+ }
75
+ this._cancelPending();
76
+ });
77
+ this._cancelListener = addDisposableListener(targetWindow, 'pointercancel', (cancelEvent) => {
78
+ if (cancelEvent.pointerId !== this._pointerId) {
79
+ return;
80
+ }
81
+ this._cancelPending();
82
+ });
83
+ }
84
+ _installContextMenuGuard(targetWindow) {
85
+ let guard;
86
+ const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
87
+ guard = addDisposableListener(targetWindow, 'contextmenu', (event) => {
88
+ event.preventDefault();
89
+ clearTimeout(timeout);
90
+ guard === null || guard === void 0 ? void 0 : guard.dispose();
91
+ }, { capture: true });
92
+ }
93
+ _installClickGuard(targetWindow) {
94
+ let guard;
95
+ const timeout = setTimeout(() => guard === null || guard === void 0 ? void 0 : guard.dispose(), 500);
96
+ guard = addDisposableListener(targetWindow, 'click', (event) => {
97
+ // Only suppress clicks targeted at the long-pressed element
98
+ // or its descendants. A user tap on a context menu item (or
99
+ // anywhere else) still gets through unchanged.
100
+ const target = event.target;
101
+ if (target && this.element.contains(target)) {
102
+ event.preventDefault();
103
+ event.stopPropagation();
104
+ }
105
+ clearTimeout(timeout);
106
+ guard === null || guard === void 0 ? void 0 : guard.dispose();
107
+ }, { capture: true });
108
+ }
109
+ _cancelPending() {
110
+ var _a, _b, _c;
111
+ if (this._timer !== undefined) {
112
+ clearTimeout(this._timer);
113
+ this._timer = undefined;
114
+ }
115
+ this._pointerId = undefined;
116
+ (_a = this._moveListener) === null || _a === void 0 ? void 0 : _a.dispose();
117
+ (_b = this._upListener) === null || _b === void 0 ? void 0 : _b.dispose();
118
+ (_c = this._cancelListener) === null || _c === void 0 ? void 0 : _c.dispose();
119
+ this._moveListener = undefined;
120
+ this._upListener = undefined;
121
+ this._cancelListener = undefined;
122
+ }
123
+ dispose() {
124
+ this._cancelPending();
125
+ super.dispose();
126
+ }
127
+ }
@@ -0,0 +1,60 @@
1
+ import { Event } from '../../events';
2
+ import { CompositeDisposable, IDisposable } from '../../lifecycle';
3
+ import { PointerGhost } from './pointerGhost';
4
+ import { IPointerDropTargetHandle, PointerDragEvent } from './types';
5
+ export interface ActiveDrag {
6
+ readonly pointerId: number;
7
+ readonly startX: number;
8
+ readonly startY: number;
9
+ readonly source: HTMLElement;
10
+ }
11
+ /**
12
+ * Singleton — only one pointer-driven drag active at a time.
13
+ *
14
+ * State is shared across every Dockview instance on the page. Targets
15
+ * from instance B receive hit-tests from drags originating in instance A;
16
+ * that's intentional for cross-instance drops since `LocalSelectionTransfer`
17
+ * is also process-wide. The corollary is that every Tabs subscriber to
18
+ * `onDragMove` fires for every pointer drag globally — each subscriber
19
+ * hit-tests against its own DOM, so this is O(N) per pointermove where N
20
+ * is the number of registered listeners across all instances.
21
+ */
22
+ export declare class PointerDragController extends CompositeDisposable {
23
+ private static _instance;
24
+ static getInstance(): PointerDragController;
25
+ private readonly _targets;
26
+ /** Kept in sync with `_targets` so hit-testing is allocation-free. */
27
+ private readonly _targetByElement;
28
+ private _active;
29
+ private _currentTarget;
30
+ private _dataDisposable;
31
+ private _ghost;
32
+ private _moveListener;
33
+ private _upListener;
34
+ private _cancelListener;
35
+ private _iframeShield;
36
+ private _onDragMoveCallback?;
37
+ private _onDragEndCallback?;
38
+ private readonly _onDragStart;
39
+ readonly onDragStart: Event<PointerDragEvent>;
40
+ private readonly _onDragMove;
41
+ readonly onDragMove: Event<PointerDragEvent>;
42
+ private readonly _onDragEnd;
43
+ readonly onDragEnd: Event<PointerDragEvent>;
44
+ private constructor();
45
+ get active(): ActiveDrag | undefined;
46
+ registerTarget(target: IPointerDropTargetHandle): IDisposable;
47
+ beginDrag(args: {
48
+ pointerEvent: PointerEvent;
49
+ source: HTMLElement;
50
+ getData: () => IDisposable;
51
+ ghost?: PointerGhost;
52
+ onDragMove?: (e: PointerDragEvent) => void;
53
+ onDragEnd?: (e: PointerDragEvent, dropped: boolean) => void;
54
+ }): void;
55
+ cancel(): void;
56
+ private _findTargetUnder;
57
+ private _handleMove;
58
+ private _handleEnd;
59
+ private _teardown;
60
+ }