@acorex/cdk 21.0.0-next.12 → 21.0.0-next.14

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.
@@ -39,7 +39,6 @@ declare class AXDragDirective implements OnInit, OnDestroy {
39
39
  private dragStartTime;
40
40
  private isDragging;
41
41
  private elementOpacity;
42
- private isDelayStarted;
43
42
  private movedAfterDelay;
44
43
  private activePointerId;
45
44
  private prevDropZone;
@@ -116,7 +115,7 @@ interface AXDropListDroppedEvent extends NXNativeEvent<AXDropListDirective, Mous
116
115
  * This directive automatically detects `gap` from flexbox/grid layouts and handles
117
116
  * items with variable sizes and margins.
118
117
  */
119
- declare class AXDropListDirective extends NXComponent implements OnInit, AfterContentInit {
118
+ declare class AXDropListDirective extends NXComponent implements OnInit, AfterContentInit, OnDestroy {
120
119
  private readonly _zone;
121
120
  private readonly _renderer;
122
121
  private readonly _cdr;
@@ -148,8 +147,11 @@ declare class AXDropListDirective extends NXComponent implements OnInit, AfterCo
148
147
  private readonly _listGap;
149
148
  /** A signal-based alias for the orientation input for internal use. */
150
149
  private readonly _orientation;
150
+ /** DOM placeholder element for inter-list drags */
151
+ private _placeholderElement;
151
152
  ngOnInit(): void;
152
153
  ngAfterContentInit(): void;
154
+ ngOnDestroy(): void;
153
155
  /** Checks if the given drag item is the one currently active in this list. */
154
156
  isDragActiveForThisList(dragItem: AXDragDirective): boolean;
155
157
  /**
@@ -190,8 +192,12 @@ declare class AXDropListDirective extends NXComponent implements OnInit, AfterCo
190
192
  * @returns The calculated placeholder index.
191
193
  */
192
194
  private _calculatePlaceholderIndex;
193
- /** Applies `transform` styles to all items to create the visual sorting effect. */
195
+ /** Applies visual shifts - uses placeholder for inter-list, transforms for intra-list. */
194
196
  private _applyVisualShifts;
197
+ /** Creates or moves the placeholder element for inter-list drags */
198
+ private _updatePlaceholderElement;
199
+ /** Removes the placeholder element if it exists */
200
+ private _removePlaceholderElement;
195
201
  /**
196
202
  * Calculates the required transform in pixels for a single item.
197
203
  * @param index The index of the item to transform.
@@ -65,16 +65,24 @@ class AXDropListDirective extends NXComponent {
65
65
  this._listGap = signal(0, ...(ngDevMode ? [{ debugName: "_listGap" }] : []));
66
66
  /** A signal-based alias for the orientation input for internal use. */
67
67
  this._orientation = this.dropListOrientation;
68
+ /** DOM placeholder element for inter-list drags */
69
+ this._placeholderElement = null;
68
70
  }
69
71
  ngOnInit() {
70
72
  if (isPlatformBrowser(this._platformId)) {
71
73
  this.element.dataset['axDropList'] = 'true';
72
74
  this.element.classList.add('ax-drop-list-sorting-transition');
75
+ // Store reference to this directive instance on the element for drag directive access
76
+ this.element['__axContext__'] = this;
73
77
  }
74
78
  }
75
79
  ngAfterContentInit() {
76
80
  this._cdr.detectChanges();
77
81
  }
82
+ ngOnDestroy() {
83
+ // Clean up placeholder element if directive destroyed during drag
84
+ this._removePlaceholderElement();
85
+ }
78
86
  // --- Public Methods (for internal library use) ---
79
87
  /** Checks if the given drag item is the one currently active in this list. */
80
88
  isDragActiveForThisList(dragItem) {
@@ -104,6 +112,8 @@ class AXDropListDirective extends NXComponent {
104
112
  enter(dragItem) {
105
113
  if (!this.axDropList() || this.sortingDisabled() || this.isDragActiveForThisList(dragItem))
106
114
  return;
115
+ // Clean up any existing placeholder from previous list
116
+ this._removePlaceholderElement();
107
117
  this._activeDragItem.set(dragItem);
108
118
  this.element.classList.add('ax-drop-list-sorting-active');
109
119
  requestAnimationFrame(() => this._zone.run(() => this._cacheGeometry()));
@@ -267,38 +277,77 @@ class AXDropListDirective extends NXComponent {
267
277
  }
268
278
  return potentialPlaceholderIndex;
269
279
  }
270
- /** Applies `transform` styles to all items to create the visual sorting effect. */
280
+ /** Applies visual shifts - uses placeholder for inter-list, transforms for intra-list. */
271
281
  _applyVisualShifts() {
272
282
  const activeItem = this._activeDragItem();
273
283
  const originalIndex = this._cachedItems().findIndex((d) => d.item === activeItem);
274
284
  const isIntraListDrag = originalIndex > -1;
275
- // A helper to get the total space an item occupies (size + margins).
276
- const getItemSpace = (itemData) => this._orientation() === 'vertical'
277
- ? itemData.height + itemData.margins.top + itemData.margins.bottom
278
- : itemData.width + itemData.margins.left + itemData.margins.right;
279
- let draggedItemSize = 0;
280
- if (isIntraListDrag) {
281
- draggedItemSize = getItemSpace(this._cachedItems()[originalIndex]);
282
- }
283
- else if (activeItem) {
284
- const rect = activeItem.elementRect();
285
- if (rect) {
286
- const style = window.getComputedStyle(activeItem.element());
287
- draggedItemSize =
288
- this._orientation() === 'vertical'
289
- ? rect.height + parseFloat(style.marginTop) + parseFloat(style.marginBottom)
290
- : rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);
291
- }
285
+ const placeholderIndex = this._placeholderIndex();
286
+ // Check if this is an "onto-node" drop list (no items, just a drop target)
287
+ const isOntoNodeList = this.element.dataset['dropType'] === 'onto-node';
288
+ if (!isIntraListDrag && activeItem && !isOntoNodeList && this._cachedItems().length > 0) {
289
+ // --- INTER-LIST DRAG: Use DOM placeholder for reorder lists with items ---
290
+ this._updatePlaceholderElement(activeItem, placeholderIndex);
292
291
  }
293
- this._cachedItems().forEach((data, index) => {
294
- // --- New logic: Do not transform disabled items ---
295
- if (data.item.dragDisabled()) {
296
- this._renderer.removeStyle(data.element, 'transform');
297
- return;
292
+ else {
293
+ // --- INTRA-LIST DRAG: Use transforms (works well for same-list reordering) ---
294
+ this._removePlaceholderElement();
295
+ const getItemSpace = (itemData) => this._orientation() === 'vertical'
296
+ ? itemData.height + itemData.margins.top + itemData.margins.bottom
297
+ : itemData.width + itemData.margins.left + itemData.margins.right;
298
+ const draggedItemSize = isIntraListDrag ? getItemSpace(this._cachedItems()[originalIndex]) : 0;
299
+ this._cachedItems().forEach((data, index) => {
300
+ if (data.item.dragDisabled()) {
301
+ this._renderer.removeStyle(data.element, 'transform');
302
+ return;
303
+ }
304
+ const transform = this._calculateTransform(index, originalIndex, draggedItemSize, getItemSpace);
305
+ this._renderer.setStyle(data.element, 'transform', transform ? `${this._orientation() === 'vertical' ? 'translateY' : 'translateX'}(${transform}px)` : '');
306
+ });
307
+ }
308
+ }
309
+ /** Creates or moves the placeholder element for inter-list drags */
310
+ _updatePlaceholderElement(activeItem, targetIndex) {
311
+ const rect = activeItem.elementRect();
312
+ if (!rect)
313
+ return;
314
+ // Create placeholder as a clone of the dragged element
315
+ if (!this._placeholderElement) {
316
+ // Clone the entire dragged element
317
+ const sourceElement = activeItem.element();
318
+ this._placeholderElement = sourceElement.cloneNode(true);
319
+ // Mark it as a placeholder
320
+ this._renderer.addClass(this._placeholderElement, 'ax-drop-placeholder');
321
+ this._renderer.addClass(this._placeholderElement, 'ax-drag-placeholder');
322
+ // Prevent interaction with cloned content
323
+ this._renderer.setStyle(this._placeholderElement, 'pointerEvents', 'none');
324
+ // Add faded styling to indicate it's a placeholder
325
+ this._renderer.setStyle(this._placeholderElement, 'opacity', '0.4');
326
+ this._renderer.setStyle(this._placeholderElement, 'transition', 'all 200ms ease');
327
+ }
328
+ // Insert/move placeholder at target index
329
+ const items = this._cachedItems();
330
+ if (targetIndex >= 0 && targetIndex < items.length) {
331
+ const targetItem = items[targetIndex];
332
+ if (targetItem && targetItem.element) {
333
+ this._renderer.insertBefore(this.element, this._placeholderElement, targetItem.element);
298
334
  }
299
- const transform = this._calculateTransform(index, originalIndex, draggedItemSize, getItemSpace);
300
- this._renderer.setStyle(data.element, 'transform', transform ? `${this._orientation() === 'vertical' ? 'translateY' : 'translateX'}(${transform}px)` : '');
301
- });
335
+ else {
336
+ // Fallback: append at end if target item invalid
337
+ this._renderer.appendChild(this.element, this._placeholderElement);
338
+ }
339
+ }
340
+ else {
341
+ // Insert at end
342
+ this._renderer.appendChild(this.element, this._placeholderElement);
343
+ }
344
+ }
345
+ /** Removes the placeholder element if it exists */
346
+ _removePlaceholderElement() {
347
+ if (this._placeholderElement) {
348
+ this._renderer.removeChild(this.element, this._placeholderElement);
349
+ this._placeholderElement = null;
350
+ }
302
351
  }
303
352
  /**
304
353
  * Calculates the required transform in pixels for a single item.
@@ -364,6 +413,7 @@ class AXDropListDirective extends NXComponent {
364
413
  /** Removes all `transform` styles from the items in this list. */
365
414
  _resetAllTransforms() {
366
415
  this._cachedItems().forEach((data) => this._renderer.setStyle(data.element, 'transform', ''));
416
+ this._removePlaceholderElement(); // Clean up inter-list placeholder
367
417
  }
368
418
  /** Resets the internal state of the directive to its initial values. */
369
419
  resetSortState() {
@@ -385,6 +435,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.6", ngImpor
385
435
  }]
386
436
  }], propDecorators: { axDropList: [{ type: i0.Input, args: [{ isSignal: true, alias: "axDropList", required: false }] }], sortingDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortingDisabled", required: false }] }], dropListGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropListGroup", required: false }] }], dropListOrientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropListOrientation", required: false }] }], dropListDropped: [{ type: i0.Output, args: ["dropListDropped"] }], _draggableItems: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => AXDragDirective), { ...{ descendants: false }, isSignal: true }] }] } });
387
437
 
438
+ // Zone detection constants for nested drop lists (tree nodes)
439
+ const ZONE_TOP_THRESHOLD = 0.3; // Top 30% triggers reorder BEFORE
440
+ const ZONE_BOTTOM_THRESHOLD = 0.7; // Bottom 30% triggers reorder AFTER
441
+ // Middle 40% (between thresholds) triggers drop INTO
388
442
  class AXDragDirective {
389
443
  constructor() {
390
444
  this.zone = inject(NgZone);
@@ -418,7 +472,6 @@ class AXDragDirective {
418
472
  this.dragStartTime = signal(0, ...(ngDevMode ? [{ debugName: "dragStartTime" }] : []));
419
473
  this.isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
420
474
  this.elementOpacity = signal('1', ...(ngDevMode ? [{ debugName: "elementOpacity" }] : []));
421
- this.isDelayStarted = signal(false, ...(ngDevMode ? [{ debugName: "isDelayStarted" }] : []));
422
475
  this.movedAfterDelay = signal(false, ...(ngDevMode ? [{ debugName: "movedAfterDelay" }] : []));
423
476
  this.activePointerId = signal(null, ...(ngDevMode ? [{ debugName: "activePointerId" }] : []));
424
477
  this.prevDropZone = signal(null, ...(ngDevMode ? [{ debugName: "prevDropZone" }] : []));
@@ -552,7 +605,6 @@ class AXDragDirective {
552
605
  }
553
606
  handlePointerMove(e) {
554
607
  if (!this.isDragging() ||
555
- this.isDelayStarted() ||
556
608
  !isPlatformBrowser(this.platformId) ||
557
609
  e.pointerId !== this.activePointerId()) {
558
610
  return;
@@ -796,10 +848,37 @@ class AXDragDirective {
796
848
  .map((el) => el['__axContext__']);
797
849
  }
798
850
  getDropListFromPoint(x, y) {
799
- const dropListElement = this.document
851
+ const dropListElements = this.document
800
852
  .elementsFromPoint(x, y)
801
- .find((el) => el instanceof HTMLElement && el.dataset['axDropList'] === 'true');
802
- return dropListElement ? dropListElement['__axContext__'] : null;
853
+ .filter((el) => el instanceof HTMLElement && el.dataset['axDropList'] === 'true');
854
+ if (dropListElements.length === 0) {
855
+ return null;
856
+ }
857
+ // If only one drop list, use it
858
+ if (dropListElements.length === 1) {
859
+ return dropListElements[0]['__axContext__'];
860
+ }
861
+ // Multiple drop lists detected (nested scenario like tree2)
862
+ // Prioritize based on pointer position and drop type
863
+ const ontoNodeList = dropListElements.find((el) => el.dataset['dropType'] === 'onto-node');
864
+ const reorderList = dropListElements.find((el) => el.dataset['dropType'] !== 'onto-node');
865
+ // If no special handling needed, return first
866
+ if (!ontoNodeList || !reorderList) {
867
+ return dropListElements[0]['__axContext__'];
868
+ }
869
+ // Calculate pointer position relative to the "onto-node" element
870
+ const ontoNodeRect = ontoNodeList.getBoundingClientRect();
871
+ const relativeY = y - ontoNodeRect.top;
872
+ const heightRatio = relativeY / ontoNodeRect.height;
873
+ // Smart zone detection based on pointer position
874
+ if (heightRatio < ZONE_TOP_THRESHOLD || heightRatio > ZONE_BOTTOM_THRESHOLD) {
875
+ // Top or bottom zone: reorder (drop BEFORE/AFTER node)
876
+ return reorderList['__axContext__'];
877
+ }
878
+ else {
879
+ // Center zone: onto-node (drop INTO node as child)
880
+ return ontoNodeList['__axContext__'];
881
+ }
803
882
  }
804
883
  dropZoneValidation(dropZone) {
805
884
  if (!dropZone)
@@ -930,8 +1009,8 @@ class AXDragDirective {
930
1009
  try {
931
1010
  target.style.setProperty(propName, computedStyles.getPropertyValue(propName), computedStyles.getPropertyPriority(propName));
932
1011
  }
933
- catch (e) {
934
- console.log(e);
1012
+ catch {
1013
+ // Some CSS properties cannot be set directly, skip silently
935
1014
  }
936
1015
  }
937
1016
  }