@acorex/cdk 20.0.0 → 20.1.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.
- package/drag-drop/index.d.ts +153 -22
- package/fesm2022/acorex-cdk-accordion.mjs +19 -19
- package/fesm2022/acorex-cdk-accordion.mjs.map +1 -1
- package/fesm2022/acorex-cdk-carousel.mjs +3 -3
- package/fesm2022/acorex-cdk-carousel.mjs.map +1 -1
- package/fesm2022/acorex-cdk-clipboard.mjs +6 -6
- package/fesm2022/acorex-cdk-clipboard.mjs.map +1 -1
- package/fesm2022/acorex-cdk-common.mjs +91 -91
- package/fesm2022/acorex-cdk-common.mjs.map +1 -1
- package/fesm2022/acorex-cdk-dom.mjs +3 -3
- package/fesm2022/acorex-cdk-dom.mjs.map +1 -1
- package/fesm2022/acorex-cdk-drag-drop.mjs +623 -162
- package/fesm2022/acorex-cdk-drag-drop.mjs.map +1 -1
- package/fesm2022/acorex-cdk-drawer.mjs +10 -10
- package/fesm2022/acorex-cdk-drawer.mjs.map +1 -1
- package/fesm2022/acorex-cdk-focus-trap.mjs +3 -3
- package/fesm2022/acorex-cdk-focus-trap.mjs.map +1 -1
- package/fesm2022/acorex-cdk-input-mask.mjs +108 -16
- package/fesm2022/acorex-cdk-input-mask.mjs.map +1 -1
- package/fesm2022/acorex-cdk-list-navigation.mjs +10 -10
- package/fesm2022/acorex-cdk-list-navigation.mjs.map +1 -1
- package/fesm2022/acorex-cdk-outline.mjs +13 -10
- package/fesm2022/acorex-cdk-outline.mjs.map +1 -1
- package/fesm2022/acorex-cdk-overlay.mjs +3 -3
- package/fesm2022/acorex-cdk-overlay.mjs.map +1 -1
- package/fesm2022/acorex-cdk-pan-view.mjs +3 -3
- package/fesm2022/acorex-cdk-pan-view.mjs.map +1 -1
- package/fesm2022/acorex-cdk-resizable.mjs +3 -3
- package/fesm2022/acorex-cdk-resizable.mjs.map +1 -1
- package/fesm2022/acorex-cdk-selection.mjs +39 -71
- package/fesm2022/acorex-cdk-selection.mjs.map +1 -1
- package/fesm2022/acorex-cdk-sliding-item.mjs +7 -7
- package/fesm2022/acorex-cdk-sliding-item.mjs.map +1 -1
- package/fesm2022/acorex-cdk-sticky.mjs +3 -3
- package/fesm2022/acorex-cdk-sticky.mjs.map +1 -1
- package/fesm2022/acorex-cdk-virtual-scroll.mjs +10 -10
- package/fesm2022/acorex-cdk-virtual-scroll.mjs.map +1 -1
- package/input-mask/index.d.ts +13 -3
- package/outline/index.d.ts +3 -2
- package/package.json +1 -1
- package/selection/index.d.ts +4 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, signal, Directive, NgZone,
|
|
2
|
+
import { inject, ElementRef, signal, Directive, NgZone, Renderer2, ChangeDetectorRef, input, output, contentChildren, DOCUMENT, PLATFORM_ID, ViewContainerRef, contentChild, linkedSignal, computed, effect, RendererStyleFlags2, NgModule } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser } from '@angular/common';
|
|
4
4
|
import { clamp } from 'lodash-es';
|
|
5
5
|
import { NXComponent } from '@acorex/cdk/common';
|
|
@@ -9,16 +9,346 @@ class AXDragHandleDirective {
|
|
|
9
9
|
this.el = inject(ElementRef);
|
|
10
10
|
this.element = signal(this.el.nativeElement);
|
|
11
11
|
}
|
|
12
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
|
13
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.
|
|
12
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
13
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: AXDragHandleDirective, isStandalone: true, selector: "[axDragHandle]", ngImport: i0 }); }
|
|
14
14
|
}
|
|
15
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
|
15
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragHandleDirective, decorators: [{
|
|
16
16
|
type: Directive,
|
|
17
17
|
args: [{
|
|
18
18
|
selector: '[axDragHandle]',
|
|
19
19
|
}]
|
|
20
20
|
}] });
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* @Directive axDropList
|
|
24
|
+
*
|
|
25
|
+
* Manages a list of draggable items (`axDrag`), enabling sorting within the list
|
|
26
|
+
* and transferring items between compatible lists. It handles the visual shifting
|
|
27
|
+
* of items during a drag operation to provide a clear preview of the drop location.
|
|
28
|
+
*
|
|
29
|
+
* This directive automatically detects `gap` from flexbox/grid layouts and handles
|
|
30
|
+
* items with variable sizes and margins.
|
|
31
|
+
*/
|
|
32
|
+
class AXDropListDirective extends NXComponent {
|
|
33
|
+
constructor() {
|
|
34
|
+
super(...arguments);
|
|
35
|
+
this._zone = inject(NgZone);
|
|
36
|
+
this._renderer = inject(Renderer2);
|
|
37
|
+
this._cdr = inject(ChangeDetectorRef);
|
|
38
|
+
this._hostEl = inject(ElementRef);
|
|
39
|
+
// --- Public API: Inputs and Outputs ---
|
|
40
|
+
/** Whether sorting within this list is disabled. */
|
|
41
|
+
this.sortingDisabled = input(false);
|
|
42
|
+
/** The group this drop list belongs to. Dragging is only allowed between lists of the same group. */
|
|
43
|
+
this.dropListGroup = input();
|
|
44
|
+
/** The layout orientation of the list. */
|
|
45
|
+
this.dropListOrientation = input('vertical');
|
|
46
|
+
/** Emits when an item is dropped into the list. */
|
|
47
|
+
this.dropListDropped = output();
|
|
48
|
+
/** The `axDrag` directives that are direct children of this list. */
|
|
49
|
+
this._draggableItems = contentChildren(AXDragDirective, { descendants: false });
|
|
50
|
+
// --- Internal State Management ---
|
|
51
|
+
/** The native element of the drop list. */
|
|
52
|
+
this.element = this._hostEl.nativeElement;
|
|
53
|
+
/** The draggable item currently being moved over this list. */
|
|
54
|
+
this._activeDragItem = signal(null);
|
|
55
|
+
/** The calculated index where the placeholder/item should be. */
|
|
56
|
+
this._placeholderIndex = signal(-1);
|
|
57
|
+
/** A snapshot of the items' data and geometry at the start of the drag. */
|
|
58
|
+
this._cachedItems = signal([]);
|
|
59
|
+
/** The list's initial bounding box, used to calculate scroll delta. */
|
|
60
|
+
this._listInitialRect = signal(null);
|
|
61
|
+
/** The detected `gap` of the list for the current orientation. */
|
|
62
|
+
this._listGap = signal(0);
|
|
63
|
+
/** A signal-based alias for the orientation input for internal use. */
|
|
64
|
+
this._orientation = this.dropListOrientation;
|
|
65
|
+
}
|
|
66
|
+
ngOnInit() {
|
|
67
|
+
this.element.dataset['axDropList'] = 'true';
|
|
68
|
+
this.element.classList.add('ax-drop-list-sorting-transition');
|
|
69
|
+
}
|
|
70
|
+
ngAfterContentInit() {
|
|
71
|
+
this._cdr.detectChanges();
|
|
72
|
+
}
|
|
73
|
+
// --- Public Methods (for internal library use) ---
|
|
74
|
+
/** Checks if the given drag item is the one currently active in this list. */
|
|
75
|
+
isDragActiveForThisList(dragItem) {
|
|
76
|
+
return this._activeDragItem() === dragItem;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Prepares the list for sorting when a drag operation starts from within this list.
|
|
80
|
+
* @param dragItem The item that is being dragged.
|
|
81
|
+
*/
|
|
82
|
+
prepareSort(dragItem) {
|
|
83
|
+
if (this.sortingDisabled() || this._activeDragItem())
|
|
84
|
+
return;
|
|
85
|
+
this._activeDragItem.set(dragItem);
|
|
86
|
+
this.element.classList.add('ax-drop-list-sorting-active');
|
|
87
|
+
requestAnimationFrame(() => {
|
|
88
|
+
this._zone.run(() => {
|
|
89
|
+
this._cacheGeometry();
|
|
90
|
+
const placeholderIdx = this._cachedItems().findIndex((data) => data.item === dragItem);
|
|
91
|
+
this._placeholderIndex.set(placeholderIdx);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Prepares the list for receiving an item that started dragging from another list.
|
|
97
|
+
* @param dragItem The item entering this list.
|
|
98
|
+
*/
|
|
99
|
+
enter(dragItem) {
|
|
100
|
+
if (this.sortingDisabled() || this.isDragActiveForThisList(dragItem))
|
|
101
|
+
return;
|
|
102
|
+
this._activeDragItem.set(dragItem);
|
|
103
|
+
this.element.classList.add('ax-drop-list-sorting-active');
|
|
104
|
+
requestAnimationFrame(() => this._zone.run(() => this._cacheGeometry()));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Calculates the new placeholder index based on the pointer's position and applies visual shifts.
|
|
108
|
+
* @param event The pointer move event.
|
|
109
|
+
* @param dragItem The item being dragged.
|
|
110
|
+
*/
|
|
111
|
+
sort(event, dragItem) {
|
|
112
|
+
if (!this.isDragActiveForThisList(dragItem) || this.sortingDisabled() || !this._listInitialRect())
|
|
113
|
+
return;
|
|
114
|
+
const pointerPosition = this._orientation() === 'vertical' ? event.clientY : event.clientX;
|
|
115
|
+
const newPlaceholderIndex = this._calculatePlaceholderIndex(pointerPosition);
|
|
116
|
+
if (this._placeholderIndex() !== newPlaceholderIndex) {
|
|
117
|
+
this._placeholderIndex.set(newPlaceholderIndex);
|
|
118
|
+
this._applyVisualShifts();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Finalizes the drop, emits the drop event, and resets the list's state.
|
|
123
|
+
* @param event The pointer up event.
|
|
124
|
+
* @param droppedItem The item that was dropped.
|
|
125
|
+
* @param sourceList The list where the drag originated.
|
|
126
|
+
*/
|
|
127
|
+
finalizeSort(event, droppedItem, sourceList) {
|
|
128
|
+
if (!this.isDragActiveForThisList(droppedItem) || this.sortingDisabled()) {
|
|
129
|
+
this.resetSortStateAndStyles(sourceList);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const activeItem = this._activeDragItem();
|
|
133
|
+
const targetSlotIndex = this._placeholderIndex();
|
|
134
|
+
if (!activeItem || targetSlotIndex === -1) {
|
|
135
|
+
this.resetSortStateAndStyles(sourceList);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const previousIndex = sourceList._cachedItems().findIndex((d) => d.item === activeItem);
|
|
139
|
+
// Adjust the index for array mutation if moving an item to a later position in the same list.
|
|
140
|
+
const currentIndex = sourceList === this && previousIndex !== -1 && targetSlotIndex > previousIndex
|
|
141
|
+
? targetSlotIndex - 1
|
|
142
|
+
: targetSlotIndex;
|
|
143
|
+
this.dropListDropped.emit({
|
|
144
|
+
nativeEvent: event,
|
|
145
|
+
sender: this,
|
|
146
|
+
item: activeItem,
|
|
147
|
+
previousIndex,
|
|
148
|
+
currentIndex,
|
|
149
|
+
container: this,
|
|
150
|
+
previousContainer: sourceList,
|
|
151
|
+
});
|
|
152
|
+
this.resetSortStateAndStyles(sourceList);
|
|
153
|
+
}
|
|
154
|
+
/** Resets the transforms on all items and cancels the current sort operation. */
|
|
155
|
+
cancelSort(dragItem) {
|
|
156
|
+
if (dragItem && !this.isDragActiveForThisList(dragItem))
|
|
157
|
+
return;
|
|
158
|
+
this._resetAllTransforms();
|
|
159
|
+
this.resetSortState();
|
|
160
|
+
}
|
|
161
|
+
/** Resets transforms but keeps the active state, used when moving between lists. */
|
|
162
|
+
cancelSortPreview() {
|
|
163
|
+
if (!this._activeDragItem())
|
|
164
|
+
return;
|
|
165
|
+
this._resetAllTransforms();
|
|
166
|
+
const originalIndex = this._cachedItems().findIndex((d) => d.item === this._activeDragItem());
|
|
167
|
+
this._placeholderIndex.set(originalIndex > -1 ? originalIndex : -1);
|
|
168
|
+
}
|
|
169
|
+
// --- Private Helper Methods ---
|
|
170
|
+
/** Caches the geometry of the list and its items at the start of a drag. */
|
|
171
|
+
_cacheGeometry() {
|
|
172
|
+
this._listInitialRect.set(this.element.getBoundingClientRect());
|
|
173
|
+
this._detectAndCacheListGap();
|
|
174
|
+
const items = this._draggableItems().map((itemDraggable) => {
|
|
175
|
+
const el = itemDraggable.element();
|
|
176
|
+
const style = window.getComputedStyle(el);
|
|
177
|
+
const rect = el.getBoundingClientRect();
|
|
178
|
+
return {
|
|
179
|
+
item: itemDraggable,
|
|
180
|
+
element: el,
|
|
181
|
+
initialRect: rect,
|
|
182
|
+
width: rect.width,
|
|
183
|
+
height: rect.height,
|
|
184
|
+
margins: {
|
|
185
|
+
top: parseFloat(style.marginTop),
|
|
186
|
+
bottom: parseFloat(style.marginBottom),
|
|
187
|
+
left: parseFloat(style.marginLeft),
|
|
188
|
+
right: parseFloat(style.marginRight),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
this._cachedItems.set(items);
|
|
193
|
+
}
|
|
194
|
+
/** Detects and caches the `gap` property from the list's computed styles. */
|
|
195
|
+
_detectAndCacheListGap() {
|
|
196
|
+
const listStyle = window.getComputedStyle(this.element);
|
|
197
|
+
const gapValue = listStyle.getPropertyValue('gap');
|
|
198
|
+
if (gapValue && gapValue !== 'normal') {
|
|
199
|
+
const gapParts = gapValue.split(' ');
|
|
200
|
+
const rowGap = parseFloat(gapParts[0]);
|
|
201
|
+
const columnGap = parseFloat(gapParts[1] || gapParts[0]);
|
|
202
|
+
this._listGap.set(this._orientation() === 'vertical' ? rowGap : columnGap);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
this._listGap.set(0);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Determines the new placeholder index by comparing the pointer position against the
|
|
210
|
+
* midpoints of the other items in the list.
|
|
211
|
+
* @param pointerPosition The clientX or clientY of the pointer.
|
|
212
|
+
* @returns The calculated placeholder index.
|
|
213
|
+
*/
|
|
214
|
+
_calculatePlaceholderIndex(pointerPosition) {
|
|
215
|
+
const activeItem = this._activeDragItem();
|
|
216
|
+
const listRect = this._listInitialRect();
|
|
217
|
+
const siblings = this._cachedItems().filter((d) => d.item !== activeItem);
|
|
218
|
+
const scrollDelta = this._orientation() === 'vertical'
|
|
219
|
+
? this.element.getBoundingClientRect().top - listRect.top
|
|
220
|
+
: this.element.getBoundingClientRect().left - listRect.left;
|
|
221
|
+
let newIndexInSiblings = -1;
|
|
222
|
+
for (let i = 0; i < siblings.length; i++) {
|
|
223
|
+
const sibling = siblings[i];
|
|
224
|
+
const itemMidPoint = (this._orientation() === 'vertical' ? sibling.initialRect.top : sibling.initialRect.left) +
|
|
225
|
+
scrollDelta +
|
|
226
|
+
(this._orientation() === 'vertical' ? sibling.height : sibling.width) / 2;
|
|
227
|
+
if (pointerPosition < itemMidPoint) {
|
|
228
|
+
newIndexInSiblings = i;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (newIndexInSiblings === -1) {
|
|
233
|
+
newIndexInSiblings = siblings.length;
|
|
234
|
+
}
|
|
235
|
+
const originalIndex = this._cachedItems().findIndex((d) => d.item === activeItem);
|
|
236
|
+
// Map the index from the 'siblings' array back to the original `_cachedItems` array.
|
|
237
|
+
return originalIndex > -1 && newIndexInSiblings >= originalIndex ? newIndexInSiblings + 1 : newIndexInSiblings;
|
|
238
|
+
}
|
|
239
|
+
/** Applies `transform` styles to all items to create the visual sorting effect. */
|
|
240
|
+
_applyVisualShifts() {
|
|
241
|
+
const activeItem = this._activeDragItem();
|
|
242
|
+
const originalIndex = this._cachedItems().findIndex((d) => d.item === activeItem);
|
|
243
|
+
const isIntraListDrag = originalIndex > -1;
|
|
244
|
+
// A helper to get the total space an item occupies (size + margins).
|
|
245
|
+
const getItemSpace = (itemData) => this._orientation() === 'vertical'
|
|
246
|
+
? itemData.height + itemData.margins.top + itemData.margins.bottom
|
|
247
|
+
: itemData.width + itemData.margins.left + itemData.margins.right;
|
|
248
|
+
let draggedItemSize = 0;
|
|
249
|
+
if (isIntraListDrag) {
|
|
250
|
+
draggedItemSize = getItemSpace(this._cachedItems()[originalIndex]);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const rect = activeItem.elementRect();
|
|
254
|
+
if (rect) {
|
|
255
|
+
const style = window.getComputedStyle(activeItem.element());
|
|
256
|
+
draggedItemSize =
|
|
257
|
+
this._orientation() === 'vertical'
|
|
258
|
+
? rect.height + parseFloat(style.marginTop) + parseFloat(style.marginBottom)
|
|
259
|
+
: rect.width + parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
this._cachedItems().forEach((data, index) => {
|
|
263
|
+
const transform = this._calculateTransform(index, originalIndex, draggedItemSize, getItemSpace);
|
|
264
|
+
this._renderer.setStyle(data.element, 'transform', transform ? `${this._orientation() === 'vertical' ? 'translateY' : 'translateX'}(${transform}px)` : '');
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Calculates the required transform in pixels for a single item.
|
|
269
|
+
* @param index The index of the item to transform.
|
|
270
|
+
* @param originalIndex The original index of the dragged item (-1 if from another list).
|
|
271
|
+
* @param draggedItemSize The size (including margins) of the item being dragged.
|
|
272
|
+
* @param getItemSpace A helper function to get an item's size including margins.
|
|
273
|
+
* @returns The transform value in pixels.
|
|
274
|
+
*/
|
|
275
|
+
_calculateTransform(index, originalIndex, draggedItemSize, getItemSpace) {
|
|
276
|
+
const targetIndex = this._placeholderIndex();
|
|
277
|
+
const listGap = this._listGap();
|
|
278
|
+
if (originalIndex > -1) {
|
|
279
|
+
// --- Intra-list Drag ---
|
|
280
|
+
if (index === originalIndex) {
|
|
281
|
+
// The dragged item moves by the sum of the sizes of the items it passes over, PLUS the gaps between them.
|
|
282
|
+
let offset = 0;
|
|
283
|
+
if (targetIndex > originalIndex) {
|
|
284
|
+
// Dragging down/right
|
|
285
|
+
for (let i = originalIndex + 1; i < targetIndex; i++) {
|
|
286
|
+
offset += getItemSpace(this._cachedItems()[i]) + listGap;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// Dragging up/left
|
|
291
|
+
for (let i = targetIndex; i < originalIndex; i++) {
|
|
292
|
+
offset -= getItemSpace(this._cachedItems()[i]) + listGap;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return offset;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
// It's a sibling item that needs to make space.
|
|
299
|
+
// It moves by the size of the dragged item, plus ONE gap to fill the void.
|
|
300
|
+
const shift = draggedItemSize + listGap;
|
|
301
|
+
if (originalIndex < targetIndex && index > originalIndex && index < targetIndex) {
|
|
302
|
+
return -shift;
|
|
303
|
+
}
|
|
304
|
+
else if (originalIndex > targetIndex && index >= targetIndex && index < originalIndex) {
|
|
305
|
+
return shift;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
// --- Inter-list Drag (from another list) ---
|
|
311
|
+
if (index >= targetIndex) {
|
|
312
|
+
// An item from another list enters. Siblings shift by its size plus ONE gap.
|
|
313
|
+
return draggedItemSize + listGap;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return 0;
|
|
317
|
+
}
|
|
318
|
+
/** Resets the state of this list and the source list after a drop. */
|
|
319
|
+
resetSortStateAndStyles(sourceList) {
|
|
320
|
+
const listsToReset = new Set([this, sourceList]);
|
|
321
|
+
listsToReset.forEach((list) => {
|
|
322
|
+
if (list) {
|
|
323
|
+
list._resetAllTransforms();
|
|
324
|
+
list.resetSortState();
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
/** Removes all `transform` styles from the items in this list. */
|
|
329
|
+
_resetAllTransforms() {
|
|
330
|
+
this._cachedItems().forEach((data) => this._renderer.setStyle(data.element, 'transform', ''));
|
|
331
|
+
}
|
|
332
|
+
/** Resets the internal state of the directive to its initial values. */
|
|
333
|
+
resetSortState() {
|
|
334
|
+
this.element.classList.remove('ax-drop-list-sorting-active');
|
|
335
|
+
this._activeDragItem.set(null);
|
|
336
|
+
this._cachedItems.set([]);
|
|
337
|
+
this._placeholderIndex.set(-1);
|
|
338
|
+
this._listInitialRect.set(null);
|
|
339
|
+
this._listGap.set(0);
|
|
340
|
+
}
|
|
341
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDropListDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
342
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.0.4", type: AXDropListDirective, isStandalone: true, selector: "[axDropList]", inputs: { sortingDisabled: { classPropertyName: "sortingDisabled", publicName: "sortingDisabled", isSignal: true, isRequired: false, transformFunction: null }, dropListGroup: { classPropertyName: "dropListGroup", publicName: "dropListGroup", isSignal: true, isRequired: false, transformFunction: null }, dropListOrientation: { classPropertyName: "dropListOrientation", publicName: "dropListOrientation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dropListDropped: "dropListDropped" }, queries: [{ propertyName: "_draggableItems", predicate: AXDragDirective, isSignal: true }], exportAs: ["axDropList"], usesInheritance: true, ngImport: i0 }); }
|
|
343
|
+
}
|
|
344
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDropListDirective, decorators: [{
|
|
345
|
+
type: Directive,
|
|
346
|
+
args: [{
|
|
347
|
+
selector: '[axDropList]',
|
|
348
|
+
exportAs: 'axDropList',
|
|
349
|
+
}]
|
|
350
|
+
}] });
|
|
351
|
+
|
|
22
352
|
class AXDragDirective {
|
|
23
353
|
constructor() {
|
|
24
354
|
this.zone = inject(NgZone);
|
|
@@ -26,42 +356,51 @@ class AXDragDirective {
|
|
|
26
356
|
this.renderer = inject(Renderer2);
|
|
27
357
|
this.cdr = inject(ChangeDetectorRef);
|
|
28
358
|
this.platformId = inject(PLATFORM_ID);
|
|
359
|
+
this.viewContainerRef = inject(ViewContainerRef);
|
|
29
360
|
this.el = inject(ElementRef);
|
|
30
361
|
this.handleDirective = contentChild(AXDragHandleDirective);
|
|
31
362
|
this.dragData = input();
|
|
32
363
|
this.dragDisabled = input(false);
|
|
364
|
+
this.dragTransition = input(true);
|
|
33
365
|
this.dragElementClone = input(false);
|
|
34
366
|
this.dropZoneGroup = input();
|
|
35
367
|
this.dragStartDelay = input();
|
|
36
368
|
this.dragResetOnDblClick = input(true);
|
|
37
369
|
this.dragLockAxis = input(null);
|
|
370
|
+
this.dragClonedTemplate = input();
|
|
38
371
|
this.dragCursor = input('move');
|
|
39
372
|
this.dragBoundary = input();
|
|
373
|
+
this.dragTransitionDuration = input(150);
|
|
40
374
|
this.dragPositionChanged = output();
|
|
375
|
+
this.clonedElement = signal(null);
|
|
41
376
|
this.currentAxis = signal({ x: 0, y: 0 });
|
|
42
377
|
this.currentCloneAxis = signal({ x: 0, y: 0 });
|
|
43
|
-
this.
|
|
378
|
+
this.transitionDuration = linkedSignal(() => this.dragTransitionDuration());
|
|
44
379
|
this.element = signal(this.el.nativeElement);
|
|
45
|
-
this.elementOpacity = signal('1');
|
|
46
380
|
this.isMoving = signal(false);
|
|
47
381
|
this.isDragging = signal(false);
|
|
382
|
+
this.elementOpacity = signal('1');
|
|
48
383
|
this.isDelayStarted = signal(false);
|
|
384
|
+
this.prevDropZone = signal(null);
|
|
49
385
|
this.dragStartOffset = signal({ x: 0, y: 0 });
|
|
50
386
|
this.clonePointerOffset = signal({ x: 0, y: 0 });
|
|
51
|
-
this.
|
|
387
|
+
this.clonedElementViewRef = signal(null);
|
|
388
|
+
this._parentDropList = inject(AXDropListDirective, { optional: true, skipSelf: true, host: false });
|
|
389
|
+
this._currentDropList = signal(null);
|
|
390
|
+
this.createCloneElement = computed(() => this.dragElementClone() || !!this._parentDropList);
|
|
52
391
|
this.boundaryElement = computed(() => {
|
|
53
392
|
const boundary = this.dragBoundary();
|
|
54
393
|
if (!boundary) {
|
|
55
394
|
return null;
|
|
56
395
|
}
|
|
57
396
|
if (typeof boundary === 'string') {
|
|
58
|
-
return this.
|
|
397
|
+
return this.document.querySelector(boundary);
|
|
59
398
|
}
|
|
60
399
|
return boundary instanceof ElementRef ? boundary.nativeElement : boundary;
|
|
61
400
|
});
|
|
62
401
|
this.elementRect = computed(() => {
|
|
63
402
|
if (!isPlatformBrowser(this.platformId)) {
|
|
64
|
-
return null;
|
|
403
|
+
return null;
|
|
65
404
|
}
|
|
66
405
|
return this.element().getBoundingClientRect();
|
|
67
406
|
});
|
|
@@ -97,6 +436,9 @@ class AXDragDirective {
|
|
|
97
436
|
this.handle().addEventListener('dblclick', this.boundHandleDblClick);
|
|
98
437
|
this.handle().addEventListener('pointerdown', this.boundHandlePointerDown, { passive: false });
|
|
99
438
|
});
|
|
439
|
+
if (this._parentDropList) {
|
|
440
|
+
this.setElementTransition(this.element());
|
|
441
|
+
}
|
|
100
442
|
this.renderer.setStyle(this.element(), 'z-index', '1');
|
|
101
443
|
this.elementOpacity.set(getComputedStyle(this.element()).opacity);
|
|
102
444
|
}
|
|
@@ -106,27 +448,35 @@ class AXDragDirective {
|
|
|
106
448
|
this.handle().removeEventListener('dblclick', this.boundHandleDblClick);
|
|
107
449
|
this.handle().removeEventListener('pointerdown', this.boundHandlePointerDown);
|
|
108
450
|
this.removeDocumentListeners();
|
|
109
|
-
if (this.
|
|
451
|
+
if (this.createCloneElement()) {
|
|
110
452
|
this.removeCloneElement();
|
|
111
453
|
}
|
|
454
|
+
if (this._parentDropList && this.isDragging()) {
|
|
455
|
+
this._parentDropList.cancelSort();
|
|
456
|
+
}
|
|
112
457
|
}
|
|
113
458
|
}
|
|
459
|
+
setElementTransition(element) {
|
|
460
|
+
this.renderer.setStyle(element, 'transition-property', 'transform, opacity, translate');
|
|
461
|
+
this.renderer.setStyle(element, 'transition-duration', `var(--ax-sys-transition-duration,${this.transitionDuration()}ms)`);
|
|
462
|
+
this.renderer.setStyle(element, 'transition-timing-function', 'var(--ax-sys-transition-timing-function)');
|
|
463
|
+
}
|
|
464
|
+
removeElementTransition(element) {
|
|
465
|
+
this.renderer.setStyle(element, 'transition-property', 'opacity');
|
|
466
|
+
}
|
|
114
467
|
handlePointerDown(e) {
|
|
115
468
|
if (!isPlatformBrowser(this.platformId))
|
|
116
469
|
return;
|
|
117
470
|
if (this.dragDisabled() || e.button !== 0)
|
|
118
471
|
return;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
break;
|
|
472
|
+
this.isDragging.set(true);
|
|
473
|
+
if (this.dragCursor() === 'move') {
|
|
474
|
+
this.renderer.setStyle(this.document.body, 'cursor', 'move');
|
|
475
|
+
}
|
|
476
|
+
else if (this.dragCursor() === 'grab') {
|
|
477
|
+
this.renderer.setStyle(this.document.body, 'cursor', 'grabbing');
|
|
126
478
|
}
|
|
127
|
-
// e.preventDefault();
|
|
128
479
|
e.stopPropagation();
|
|
129
|
-
this.isDragging.set(true);
|
|
130
480
|
this.dragStartOffset.set({ x: e.clientX - this.currentAxis().x, y: e.clientY - this.currentAxis().y });
|
|
131
481
|
this.renderer.setStyle(this.handle(), 'userSelect', 'none');
|
|
132
482
|
this.handle().setPointerCapture(e.pointerId);
|
|
@@ -134,49 +484,76 @@ class AXDragDirective {
|
|
|
134
484
|
if (this.dragStartDelay()) {
|
|
135
485
|
this.isDelayStarted.set(true);
|
|
136
486
|
setTimeout(() => {
|
|
137
|
-
this.
|
|
487
|
+
if (this.isDragging()) {
|
|
488
|
+
this.isDelayStarted.set(false);
|
|
489
|
+
this.startDrag(e);
|
|
490
|
+
}
|
|
138
491
|
}, this.dragStartDelay());
|
|
139
492
|
}
|
|
140
|
-
|
|
141
|
-
|
|
493
|
+
else {
|
|
494
|
+
this.startDrag(e);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
startDrag(e) {
|
|
498
|
+
if (this._parentDropList) {
|
|
499
|
+
this._currentDropList.set(this._parentDropList);
|
|
500
|
+
this._parentDropList.prepareSort(this);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
this.dropZoneHoverHandler(e);
|
|
504
|
+
}
|
|
505
|
+
if (this.createCloneElement()) {
|
|
142
506
|
const elementRect = this.element().getBoundingClientRect();
|
|
143
507
|
this.clonePointerOffset.set({
|
|
144
508
|
x: e.clientX - elementRect.left,
|
|
145
509
|
y: e.clientY - elementRect.top,
|
|
146
510
|
});
|
|
147
|
-
this.
|
|
511
|
+
this.createCloneElementHandler(this.element());
|
|
148
512
|
}
|
|
149
513
|
}
|
|
150
514
|
handlePointerUp(e) {
|
|
515
|
+
const transform = this.element().style.transform;
|
|
516
|
+
let x = 0;
|
|
517
|
+
let y = 0;
|
|
518
|
+
if (transform) {
|
|
519
|
+
x = Number(transform.split('translateX(')[1]?.split('px)')[0]);
|
|
520
|
+
y = Number(transform.split('translateY(')[1]?.split('px)')[0]);
|
|
521
|
+
}
|
|
151
522
|
if (!isPlatformBrowser(this.platformId))
|
|
152
523
|
return;
|
|
153
|
-
if (!this.isDragging())
|
|
524
|
+
if (!this.isDragging())
|
|
154
525
|
return;
|
|
526
|
+
this.renderer.removeStyle(this.document.body, 'cursor');
|
|
527
|
+
const wasMoving = this.isMoving();
|
|
528
|
+
this.isDragging.set(false);
|
|
529
|
+
if (wasMoving) {
|
|
530
|
+
this.preventClicking();
|
|
155
531
|
}
|
|
156
|
-
|
|
157
|
-
|
|
532
|
+
const droppedIntoList = this._currentDropList();
|
|
533
|
+
if (droppedIntoList && this._parentDropList) {
|
|
534
|
+
droppedIntoList.finalizeSort(e, this, this._parentDropList);
|
|
158
535
|
}
|
|
159
|
-
if (this.
|
|
160
|
-
this.
|
|
536
|
+
else if (this._parentDropList) {
|
|
537
|
+
this._parentDropList.cancelSort(this);
|
|
161
538
|
}
|
|
162
|
-
|
|
539
|
+
else {
|
|
540
|
+
this.dropZoneDropHandler(e);
|
|
541
|
+
}
|
|
542
|
+
this._currentDropList.set(null);
|
|
543
|
+
this.isMoving.set(false);
|
|
163
544
|
this.renderer.removeStyle(this.handle(), 'userSelect');
|
|
164
|
-
this.handle().
|
|
545
|
+
if (this.handle().hasPointerCapture(e.pointerId)) {
|
|
546
|
+
this.handle().releasePointerCapture(e.pointerId);
|
|
547
|
+
}
|
|
165
548
|
this.removeDocumentListeners();
|
|
166
|
-
if (this.
|
|
167
|
-
this.
|
|
168
|
-
this.
|
|
169
|
-
this.dropZoneDropHandler(e);
|
|
549
|
+
if (this.createCloneElement()) {
|
|
550
|
+
const listUnderPointer = this.getDropListFromPoint(e.clientX, e.clientY);
|
|
551
|
+
this.removeCloneElementWithAnimation(x || 0, y || 0, listUnderPointer);
|
|
170
552
|
}
|
|
171
|
-
|
|
172
|
-
this.
|
|
553
|
+
else {
|
|
554
|
+
this.renderer.setStyle(this.element(), 'opacity', this.elementOpacity());
|
|
173
555
|
}
|
|
174
556
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Prevent click events immediately following pointerup, especially on touch devices
|
|
177
|
-
* or fast drags where the underlying element might receive an unintended click.
|
|
178
|
-
* Use a capturing listener added *after* pointerup and removed asynchronously.
|
|
179
|
-
*/
|
|
180
557
|
preventClicking() {
|
|
181
558
|
const blockClick = (event) => {
|
|
182
559
|
event.preventDefault();
|
|
@@ -190,17 +567,13 @@ class AXDragDirective {
|
|
|
190
567
|
this.setPosition(0, 0);
|
|
191
568
|
}
|
|
192
569
|
handlePointerMove(e) {
|
|
193
|
-
if (!isPlatformBrowser(this.platformId))
|
|
570
|
+
if (!isPlatformBrowser(this.platformId) || !this.isDragging() || this.isDelayStarted())
|
|
194
571
|
return;
|
|
195
|
-
if (!this.isDragging())
|
|
196
|
-
return;
|
|
197
|
-
if (this.isDelayStarted()) {
|
|
198
|
-
this.isDragging.set(false);
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
572
|
e.preventDefault();
|
|
202
|
-
this.isMoving
|
|
203
|
-
|
|
573
|
+
if (!this.isMoving()) {
|
|
574
|
+
this.isMoving.set(true);
|
|
575
|
+
}
|
|
576
|
+
if (this.createCloneElement()) {
|
|
204
577
|
const newCloneX = e.clientX - this.clonePointerOffset().x;
|
|
205
578
|
const newCloneY = e.clientY - this.clonePointerOffset().y;
|
|
206
579
|
this.setClonePosition(newCloneX, newCloneY);
|
|
@@ -210,73 +583,105 @@ class AXDragDirective {
|
|
|
210
583
|
const newY = e.clientY - this.dragStartOffset().y;
|
|
211
584
|
this.setPosition(newX, newY);
|
|
212
585
|
}
|
|
213
|
-
this.
|
|
586
|
+
if (this._parentDropList) {
|
|
587
|
+
this.handleDropListInteractions(e);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
this.dropZoneHoverHandler(e);
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
handleDropListInteractions(e) {
|
|
594
|
+
const listUnderPointer = this.getDropListFromPoint(e.clientX, e.clientY);
|
|
595
|
+
const previousList = this._currentDropList();
|
|
596
|
+
let targetList = null;
|
|
597
|
+
if (listUnderPointer && this.canDropInList(listUnderPointer)) {
|
|
598
|
+
targetList = listUnderPointer;
|
|
599
|
+
}
|
|
600
|
+
if (targetList !== previousList) {
|
|
601
|
+
if (previousList) {
|
|
602
|
+
previousList.cancelSortPreview();
|
|
603
|
+
if (previousList !== this._parentDropList) {
|
|
604
|
+
previousList.resetSortState();
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (targetList) {
|
|
608
|
+
targetList.enter(this);
|
|
609
|
+
}
|
|
610
|
+
this._currentDropList.set(targetList);
|
|
611
|
+
}
|
|
612
|
+
this._currentDropList()?.sort(e, this);
|
|
613
|
+
}
|
|
614
|
+
canDropInList(list) {
|
|
615
|
+
if (!list || list.sortingDisabled() || !this._parentDropList) {
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
if (list === this._parentDropList) {
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
const dragGroup = this._parentDropList.dropListGroup();
|
|
622
|
+
const targetGroup = list.dropListGroup();
|
|
623
|
+
return !!dragGroup && dragGroup === targetGroup;
|
|
214
624
|
}
|
|
215
625
|
dropZoneHoverHandler(e) {
|
|
216
626
|
const dropZones = this.getDropZonesFromPoint(e.clientX, e.clientY);
|
|
217
|
-
if (!dropZones.length && this.prevDropZone() && this.prevDropZone().isHovered()) {
|
|
218
|
-
this.leavePrevDropZone(e);
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
627
|
const dropZone = dropZones[0];
|
|
222
|
-
if (!
|
|
628
|
+
if (!dropZone) {
|
|
629
|
+
if (this.prevDropZone()) {
|
|
630
|
+
this.leavePrevDropZone(e);
|
|
631
|
+
}
|
|
223
632
|
return;
|
|
224
633
|
}
|
|
225
634
|
if (this.prevDropZone() && this.prevDropZone() !== dropZone) {
|
|
226
635
|
this.leavePrevDropZone(e);
|
|
227
636
|
}
|
|
228
|
-
this.
|
|
229
|
-
|
|
230
|
-
|
|
637
|
+
if (this.dropZoneValidation(dropZone) && !dropZone.isHovered()) {
|
|
638
|
+
this.prevDropZone.set(dropZone);
|
|
639
|
+
dropZone.onElementHover.emit({ sender: dropZone, dropped: this, nativeEvent: e, state: 'enter' });
|
|
640
|
+
dropZone.isHovered.set(true);
|
|
641
|
+
}
|
|
231
642
|
}
|
|
232
643
|
dropZoneDropHandler(e) {
|
|
233
644
|
const dropZones = this.getDropZonesFromPoint(e.clientX, e.clientY);
|
|
234
645
|
const dropZone = dropZones[0];
|
|
235
|
-
if (!this.dropZoneValidation(dropZone
|
|
646
|
+
if (!this.dropZoneValidation(dropZone)) {
|
|
236
647
|
return;
|
|
237
648
|
}
|
|
238
649
|
dropZone.isHovered.set(false);
|
|
239
650
|
dropZone.onElementDrop.emit({ sender: dropZone, dropped: this, nativeEvent: e });
|
|
240
651
|
}
|
|
241
652
|
getDropZonesFromPoint(x, y) {
|
|
242
|
-
const
|
|
243
|
-
return
|
|
244
|
-
.filter((el) =>
|
|
245
|
-
|
|
246
|
-
return el.dataset['dropZone'] === 'true';
|
|
247
|
-
}
|
|
248
|
-
return false;
|
|
249
|
-
})
|
|
250
|
-
.map((el) => {
|
|
251
|
-
return el['__axContext__'];
|
|
252
|
-
});
|
|
653
|
+
const elements = this.document.elementsFromPoint(x, y);
|
|
654
|
+
return elements
|
|
655
|
+
.filter((el) => el instanceof HTMLElement && el.dataset['axDropZone'] === 'true')
|
|
656
|
+
.map((el) => el['__axContext__']);
|
|
253
657
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
658
|
+
getDropListFromPoint(x, y) {
|
|
659
|
+
const dropListElement = this.document
|
|
660
|
+
.elementsFromPoint(x, y)
|
|
661
|
+
.find((el) => el instanceof HTMLElement && el.dataset['axDropList'] === 'true');
|
|
662
|
+
return dropListElement ? dropListElement['__axContext__'] : null;
|
|
663
|
+
}
|
|
664
|
+
dropZoneValidation(dropZone) {
|
|
665
|
+
if (!dropZone)
|
|
257
666
|
return false;
|
|
258
|
-
}
|
|
259
|
-
// They are in the same group
|
|
260
667
|
const dragGroup = this.dropZoneGroup();
|
|
261
668
|
const dropGroup = dropZone.dropZoneGroup();
|
|
262
|
-
if (dragGroup !== dropGroup) {
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
// Draggable element is under mouse
|
|
266
|
-
const elementsFromPoint = this.document.elementsFromPoint(e.clientX, e.clientY);
|
|
267
|
-
if (!elementsFromPoint.includes(this.element()) && !this.clonedElement()) {
|
|
669
|
+
if (dropGroup && dragGroup !== dropGroup) {
|
|
268
670
|
return false;
|
|
269
671
|
}
|
|
270
672
|
return true;
|
|
271
673
|
}
|
|
272
674
|
leavePrevDropZone(e) {
|
|
273
|
-
this.prevDropZone()
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
675
|
+
if (this.prevDropZone()) {
|
|
676
|
+
this.prevDropZone().onElementHover.emit({
|
|
677
|
+
dropped: this,
|
|
678
|
+
state: 'leave',
|
|
679
|
+
nativeEvent: e,
|
|
680
|
+
sender: this.prevDropZone(),
|
|
681
|
+
});
|
|
682
|
+
this.prevDropZone().isHovered.set(false);
|
|
683
|
+
this.prevDropZone.set(null);
|
|
684
|
+
}
|
|
280
685
|
}
|
|
281
686
|
setPosition(x, y) {
|
|
282
687
|
let constrainedX = x;
|
|
@@ -291,13 +696,10 @@ class AXDragDirective {
|
|
|
291
696
|
constrainedX = clamp(x, minX, maxX);
|
|
292
697
|
constrainedY = clamp(y, minY, maxY);
|
|
293
698
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (lockAxis === 'y') {
|
|
299
|
-
constrainedX = 0;
|
|
300
|
-
}
|
|
699
|
+
if (this.dragLockAxis() === 'x')
|
|
700
|
+
constrainedY = this.currentAxis().y;
|
|
701
|
+
if (this.dragLockAxis() === 'y')
|
|
702
|
+
constrainedX = this.currentAxis().x;
|
|
301
703
|
this.currentAxis.set({ x: constrainedX, y: constrainedY });
|
|
302
704
|
this.renderer.setStyle(this.element(), 'translate', `${constrainedX}px ${constrainedY}px`);
|
|
303
705
|
this.dragPositionChanged.emit(this.currentAxis());
|
|
@@ -306,43 +708,34 @@ class AXDragDirective {
|
|
|
306
708
|
let constrainedX = x;
|
|
307
709
|
let constrainedY = y;
|
|
308
710
|
const cloneEl = this.clonedElement();
|
|
309
|
-
const boundaryRect = this.
|
|
711
|
+
const boundaryRect = this.boundaryRect();
|
|
310
712
|
if (boundaryRect && cloneEl) {
|
|
311
713
|
const cloneWidth = cloneEl.offsetWidth;
|
|
312
714
|
const cloneHeight = cloneEl.offsetHeight;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const minAllowedY = boundaryRect.top;
|
|
316
|
-
const maxAllowedY = boundaryRect.bottom - cloneHeight;
|
|
317
|
-
constrainedX = clamp(x, minAllowedX, maxAllowedX);
|
|
318
|
-
constrainedY = clamp(y, minAllowedY, maxAllowedY);
|
|
319
|
-
}
|
|
320
|
-
const lockAxis = this.dragLockAxis();
|
|
321
|
-
if (lockAxis === 'x') {
|
|
322
|
-
constrainedY = 0;
|
|
323
|
-
}
|
|
324
|
-
if (lockAxis === 'y') {
|
|
325
|
-
constrainedX = 0;
|
|
715
|
+
constrainedX = clamp(x, boundaryRect.left, boundaryRect.right - cloneWidth);
|
|
716
|
+
constrainedY = clamp(y, boundaryRect.top, boundaryRect.bottom - cloneHeight);
|
|
326
717
|
}
|
|
718
|
+
if (this.dragLockAxis() === 'x')
|
|
719
|
+
constrainedY = this.currentCloneAxis().y;
|
|
720
|
+
if (this.dragLockAxis() === 'y')
|
|
721
|
+
constrainedX = this.currentCloneAxis().x;
|
|
327
722
|
this.currentCloneAxis.set({ x: constrainedX, y: constrainedY });
|
|
328
|
-
this.renderer.setStyle(
|
|
723
|
+
this.renderer.setStyle(cloneEl, 'translate', `${constrainedX}px ${constrainedY}px`);
|
|
329
724
|
this.dragPositionChanged.emit(this.currentCloneAxis());
|
|
330
725
|
}
|
|
331
|
-
|
|
726
|
+
createCloneElementHandler(originalElement) {
|
|
332
727
|
if (!isPlatformBrowser(this.platformId)) {
|
|
333
728
|
this.clonedElement.set(null);
|
|
334
729
|
return null;
|
|
335
730
|
}
|
|
336
|
-
|
|
731
|
+
let clonedElement;
|
|
732
|
+
const customTemplate = this.dragClonedTemplate();
|
|
337
733
|
const applyComputedStylesRecursive = (source, target) => {
|
|
338
734
|
if (!isPlatformBrowser(this.platformId))
|
|
339
735
|
return;
|
|
340
736
|
const computedStyles = window.getComputedStyle(source);
|
|
341
737
|
if (computedStyles.cssText && target.style.cssText !== undefined) {
|
|
342
|
-
// Check if cssText is supported and writable
|
|
343
|
-
// More efficient path if cssText is fully supported
|
|
344
738
|
let tempCssText = computedStyles.cssText;
|
|
345
|
-
// Remove problematic properties for the ROOT clone before assigning
|
|
346
739
|
if (target === clonedElement) {
|
|
347
740
|
tempCssText = tempCssText
|
|
348
741
|
.replace(/position:[^;]+;/gi, '')
|
|
@@ -353,34 +746,21 @@ class AXDragDirective {
|
|
|
353
746
|
.replace(/width:[^;]+;/gi, '')
|
|
354
747
|
.replace(/height:[^;]+;/gi, '')
|
|
355
748
|
.replace(/margin[^;]*:[^;]+;/gi, '')
|
|
749
|
+
.replace(/transition[^;]*:[^;]+;/gi, '')
|
|
356
750
|
.replace(/transform:[^;]+;/gi, '')
|
|
357
751
|
.replace(/translate:[^;]+;/gi, '')
|
|
358
752
|
.replace(/z-index:[^;]+;/gi, '')
|
|
359
753
|
.replace(/opacity:[^;]+;/gi, '');
|
|
360
754
|
}
|
|
361
|
-
// For ALL elements in the clone tree, ensure pointer-events is not copied from source,
|
|
362
|
-
// as the root clone will have 'pointer-events: none' and we want that to cascade.
|
|
363
755
|
tempCssText = tempCssText.replace(/pointer-events:[^;]+;/gi, '');
|
|
364
|
-
// Prepend existing inline styles (from cloneNode) to the computed styles.
|
|
365
|
-
// This gives inline styles higher precedence if there's a conflict not covered by the removals above.
|
|
366
|
-
// However, for most cases, we want computed styles to define the look.
|
|
367
|
-
// A safer bet might be to set properties individually or fully overwrite.
|
|
368
|
-
// For simplicity now, let's assume this ordering is acceptable or refine if needed.
|
|
369
|
-
// target.style.cssText = tempCssText + target.style.cssText;
|
|
370
|
-
// SAFER: Overwrite with computed, then re-apply critical ones.
|
|
371
756
|
target.style.cssText = tempCssText;
|
|
372
757
|
}
|
|
373
758
|
else {
|
|
374
|
-
// Fallback for browsers where cssText is not reliable or for more granular control
|
|
375
759
|
for (let i = 0; i < computedStyles.length; i++) {
|
|
376
760
|
const propName = computedStyles[i];
|
|
377
|
-
// Universal exclusion:
|
|
378
|
-
// For ALL elements in the clone tree (root and children), we don't want to copy 'pointer-events'
|
|
379
|
-
// because the root clonedElement will have 'pointer-events: none' set later, and we want that to cascade.
|
|
380
761
|
if (propName === 'pointer-events') {
|
|
381
762
|
continue;
|
|
382
763
|
}
|
|
383
|
-
// Specific exclusions for the ROOT clone only, as these are set manually later.
|
|
384
764
|
if (target === clonedElement &&
|
|
385
765
|
(propName === 'position' ||
|
|
386
766
|
propName === 'top' ||
|
|
@@ -389,27 +769,22 @@ class AXDragDirective {
|
|
|
389
769
|
propName === 'bottom' ||
|
|
390
770
|
propName === 'width' ||
|
|
391
771
|
propName === 'height' ||
|
|
392
|
-
propName.startsWith('margin') ||
|
|
772
|
+
propName.startsWith('margin') ||
|
|
773
|
+
propName.startsWith('transition') ||
|
|
393
774
|
propName === 'transform' ||
|
|
394
775
|
propName === 'translate' ||
|
|
395
776
|
propName === 'z-index' ||
|
|
396
777
|
propName === 'opacity')) {
|
|
397
778
|
continue;
|
|
398
779
|
}
|
|
399
|
-
// cssText += `${propName}: ${computedStyles.getPropertyValue(propName)}; `; // Building cssText string
|
|
400
|
-
// More robust: set property directly
|
|
401
780
|
try {
|
|
402
781
|
target.style.setProperty(propName, computedStyles.getPropertyValue(propName), computedStyles.getPropertyPriority(propName));
|
|
403
782
|
}
|
|
404
783
|
catch (e) {
|
|
405
|
-
|
|
784
|
+
console.log(e);
|
|
406
785
|
}
|
|
407
786
|
}
|
|
408
|
-
// if (!target.style.cssText && cssText) { // only apply if cssText was not directly set
|
|
409
|
-
// target.style.cssText = cssText + target.style.cssText;
|
|
410
|
-
// }
|
|
411
787
|
}
|
|
412
|
-
// Recursively apply to children
|
|
413
788
|
const sourceChildren = Array.from(source.children);
|
|
414
789
|
const targetChildren = Array.from(target.children);
|
|
415
790
|
for (let i = 0; i < sourceChildren.length; i++) {
|
|
@@ -418,43 +793,95 @@ class AXDragDirective {
|
|
|
418
793
|
}
|
|
419
794
|
}
|
|
420
795
|
};
|
|
421
|
-
|
|
796
|
+
if (customTemplate) {
|
|
797
|
+
const viewRef = this.viewContainerRef.createEmbeddedView(customTemplate);
|
|
798
|
+
this.clonedElementViewRef.set(viewRef);
|
|
799
|
+
if (viewRef.rootNodes.length > 0 && viewRef.rootNodes[0] instanceof HTMLElement) {
|
|
800
|
+
clonedElement = viewRef.rootNodes[0];
|
|
801
|
+
const viewIndex = this.viewContainerRef.indexOf(viewRef);
|
|
802
|
+
if (viewIndex !== -1) {
|
|
803
|
+
this.viewContainerRef.detach(viewIndex);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
if (this.clonedElementViewRef()) {
|
|
808
|
+
this.clonedElementViewRef().destroy();
|
|
809
|
+
this.clonedElementViewRef.set(null);
|
|
810
|
+
}
|
|
811
|
+
console.warn('AXDragDirective: dragClonedTemplate did not produce a valid HTMLElement root node. Falling back to default cloning.');
|
|
812
|
+
clonedElement = originalElement.cloneNode(true);
|
|
813
|
+
applyComputedStylesRecursive(originalElement, clonedElement);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
clonedElement = originalElement.cloneNode(true);
|
|
818
|
+
applyComputedStylesRecursive(originalElement, clonedElement);
|
|
819
|
+
}
|
|
422
820
|
if (clonedElement.id) {
|
|
423
821
|
this.renderer.removeAttribute(clonedElement, 'id');
|
|
424
822
|
}
|
|
425
|
-
this.renderer.setStyle(originalElement, 'opacity', '0.
|
|
823
|
+
this.renderer.setStyle(originalElement, 'opacity', '0.5');
|
|
426
824
|
const originalRect = originalElement.getBoundingClientRect();
|
|
427
825
|
this.renderer.setStyle(clonedElement, 'position', 'fixed', RendererStyleFlags2.Important);
|
|
428
826
|
this.renderer.setStyle(clonedElement, 'left', '0px');
|
|
429
827
|
this.renderer.setStyle(clonedElement, 'top', '0px');
|
|
430
|
-
|
|
431
|
-
|
|
828
|
+
if (!customTemplate) {
|
|
829
|
+
this.renderer.setStyle(clonedElement, 'width', `${originalRect.width}px`);
|
|
830
|
+
this.renderer.setStyle(clonedElement, 'height', `${originalRect.height}px`);
|
|
831
|
+
}
|
|
432
832
|
this.renderer.setStyle(clonedElement, 'margin', '0');
|
|
433
833
|
this.renderer.setStyle(clonedElement, 'box-sizing', 'border-box');
|
|
434
834
|
this.renderer.setStyle(clonedElement, 'opacity', '0.75');
|
|
435
835
|
this.renderer.setStyle(clonedElement, 'z-index', '10000');
|
|
436
|
-
// This is the crucial part for the ROOT clone.
|
|
437
|
-
// Because we prevented 'pointer-events' from being copied in applyComputedStylesRecursive,
|
|
438
|
-
// this style will effectively apply to the entire clone tree.
|
|
439
836
|
this.renderer.setStyle(clonedElement, 'pointer-events', 'none', RendererStyleFlags2.Important);
|
|
440
837
|
this.renderer.setStyle(clonedElement, 'user-select', 'none');
|
|
441
838
|
this.renderer.setStyle(clonedElement, 'touch-action', 'none');
|
|
442
839
|
this.renderer.setStyle(clonedElement, 'translate', `${originalRect.left}px ${originalRect.top}px`);
|
|
840
|
+
this.renderer.removeStyle(clonedElement, 'transition');
|
|
841
|
+
this.renderer.removeStyle(clonedElement, 'transition-property');
|
|
443
842
|
this.renderer.appendChild(this.document.body, clonedElement);
|
|
444
843
|
this.clonedElement.set(clonedElement);
|
|
445
|
-
this.
|
|
844
|
+
this.setClonePosition(originalRect.left, originalRect.top);
|
|
446
845
|
return clonedElement;
|
|
447
846
|
}
|
|
847
|
+
removeCloneElementWithAnimation(x, y, dropList) {
|
|
848
|
+
dropList?._draggableItems().forEach((item) => {
|
|
849
|
+
this.removeElementTransition(item.element());
|
|
850
|
+
});
|
|
851
|
+
const clone = this.clonedElement();
|
|
852
|
+
if (!clone)
|
|
853
|
+
return;
|
|
854
|
+
this.renderer.setStyle(this.element(), 'opacity', this.elementOpacity());
|
|
855
|
+
const elementRect = this.element().getBoundingClientRect();
|
|
856
|
+
if (elementRect) {
|
|
857
|
+
this.setElementTransition(clone);
|
|
858
|
+
this.renderer.setStyle(clone, 'opacity', '0');
|
|
859
|
+
this.setClonePosition(elementRect.left + x, elementRect.top + y);
|
|
860
|
+
}
|
|
861
|
+
if (!this.dragTransition()) {
|
|
862
|
+
this.removeCloneElement();
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
setTimeout(() => {
|
|
866
|
+
this.removeCloneElement();
|
|
867
|
+
dropList?._draggableItems().forEach((item) => {
|
|
868
|
+
this.setElementTransition(item.element());
|
|
869
|
+
});
|
|
870
|
+
}, this.transitionDuration());
|
|
871
|
+
}
|
|
872
|
+
}
|
|
448
873
|
removeCloneElement() {
|
|
449
874
|
if (!isPlatformBrowser(this.platformId))
|
|
450
875
|
return;
|
|
451
|
-
this.renderer.setStyle(this.element(), 'opacity', this.elementOpacity());
|
|
452
876
|
const clone = this.clonedElement();
|
|
453
|
-
if (clone
|
|
454
|
-
this.renderer.removeChild(
|
|
877
|
+
if (clone?.parentNode) {
|
|
878
|
+
this.renderer.removeChild(clone.parentNode, clone);
|
|
455
879
|
}
|
|
456
880
|
this.clonedElement.set(null);
|
|
457
|
-
this.
|
|
881
|
+
if (this.clonedElementViewRef()) {
|
|
882
|
+
this.clonedElementViewRef().destroy();
|
|
883
|
+
this.clonedElementViewRef.set(null);
|
|
884
|
+
}
|
|
458
885
|
this.cdr.markForCheck();
|
|
459
886
|
}
|
|
460
887
|
addDocumentListeners() {
|
|
@@ -475,10 +902,10 @@ class AXDragDirective {
|
|
|
475
902
|
this.document.removeEventListener('pointercancel', this.boundHandlePointerUp);
|
|
476
903
|
});
|
|
477
904
|
}
|
|
478
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
|
479
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.0.
|
|
905
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
906
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.0.4", type: AXDragDirective, isStandalone: true, selector: "[axDrag]", inputs: { dragData: { classPropertyName: "dragData", publicName: "dragData", isSignal: true, isRequired: false, transformFunction: null }, dragDisabled: { classPropertyName: "dragDisabled", publicName: "dragDisabled", isSignal: true, isRequired: false, transformFunction: null }, dragTransition: { classPropertyName: "dragTransition", publicName: "dragTransition", isSignal: true, isRequired: false, transformFunction: null }, dragElementClone: { classPropertyName: "dragElementClone", publicName: "dragElementClone", isSignal: true, isRequired: false, transformFunction: null }, dropZoneGroup: { classPropertyName: "dropZoneGroup", publicName: "dropZoneGroup", isSignal: true, isRequired: false, transformFunction: null }, dragStartDelay: { classPropertyName: "dragStartDelay", publicName: "dragStartDelay", isSignal: true, isRequired: false, transformFunction: null }, dragResetOnDblClick: { classPropertyName: "dragResetOnDblClick", publicName: "dragResetOnDblClick", isSignal: true, isRequired: false, transformFunction: null }, dragLockAxis: { classPropertyName: "dragLockAxis", publicName: "dragLockAxis", isSignal: true, isRequired: false, transformFunction: null }, dragClonedTemplate: { classPropertyName: "dragClonedTemplate", publicName: "dragClonedTemplate", isSignal: true, isRequired: false, transformFunction: null }, dragCursor: { classPropertyName: "dragCursor", publicName: "dragCursor", isSignal: true, isRequired: false, transformFunction: null }, dragBoundary: { classPropertyName: "dragBoundary", publicName: "dragBoundary", isSignal: true, isRequired: false, transformFunction: null }, dragTransitionDuration: { classPropertyName: "dragTransitionDuration", publicName: "dragTransitionDuration", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dragPositionChanged: "dragPositionChanged" }, queries: [{ propertyName: "handleDirective", first: true, predicate: AXDragHandleDirective, descendants: true, isSignal: true }], ngImport: i0 }); }
|
|
480
907
|
}
|
|
481
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
|
908
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragDirective, decorators: [{
|
|
482
909
|
type: Directive,
|
|
483
910
|
args: [{
|
|
484
911
|
selector: '[axDrag]',
|
|
@@ -495,12 +922,12 @@ class AXDropZoneDirective extends NXComponent {
|
|
|
495
922
|
this.onElementHover = output();
|
|
496
923
|
}
|
|
497
924
|
ngOnInit() {
|
|
498
|
-
this.element().dataset['
|
|
925
|
+
this.element().dataset['axDropZone'] = 'true';
|
|
499
926
|
}
|
|
500
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
|
501
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.
|
|
927
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDropZoneDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
928
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: AXDropZoneDirective, isStandalone: true, selector: "[axDropZone]", inputs: { dropZoneGroup: { classPropertyName: "dropZoneGroup", publicName: "dropZoneGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onElementDrop: "onElementDrop", onElementHover: "onElementHover" }, exportAs: ["axDropZone"], usesInheritance: true, ngImport: i0 }); }
|
|
502
929
|
}
|
|
503
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
|
930
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDropZoneDirective, decorators: [{
|
|
504
931
|
type: Directive,
|
|
505
932
|
args: [{
|
|
506
933
|
selector: '[axDropZone]',
|
|
@@ -510,11 +937,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImpor
|
|
|
510
937
|
|
|
511
938
|
const COMPONENT = [AXDragDirective, AXDragHandleDirective, AXDropZoneDirective];
|
|
512
939
|
class AXDragDropModule {
|
|
513
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.
|
|
514
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.
|
|
515
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.
|
|
940
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
941
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: AXDragDropModule, imports: [AXDragDirective, AXDragHandleDirective, AXDropZoneDirective], exports: [AXDragDirective, AXDragHandleDirective, AXDropZoneDirective] }); }
|
|
942
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragDropModule }); }
|
|
516
943
|
}
|
|
517
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.
|
|
944
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AXDragDropModule, decorators: [{
|
|
518
945
|
type: NgModule,
|
|
519
946
|
args: [{
|
|
520
947
|
imports: [...COMPONENT],
|
|
@@ -523,9 +950,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImpor
|
|
|
523
950
|
}]
|
|
524
951
|
}] });
|
|
525
952
|
|
|
953
|
+
/**
|
|
954
|
+
* Moves an item one index in an array to another.
|
|
955
|
+
* @param array Array in which to move the item.
|
|
956
|
+
* @param fromIndex Starting index of the item.
|
|
957
|
+
* @param toIndex Index to which the item should be moved.
|
|
958
|
+
*/
|
|
959
|
+
function moveItemInArray(array, fromIndex, toIndex) {
|
|
960
|
+
const from = clamp(fromIndex, array.length - 1);
|
|
961
|
+
const to = clamp(toIndex, array.length - 1);
|
|
962
|
+
if (from === to) {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
const target = array[from];
|
|
966
|
+
const delta = to < from ? -1 : 1;
|
|
967
|
+
for (let i = from; i !== to; i += delta) {
|
|
968
|
+
array[i] = array[i + delta];
|
|
969
|
+
}
|
|
970
|
+
array[to] = target;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Moves an item from one array to another.
|
|
974
|
+
* @param currentArray Array from which to transfer the item.
|
|
975
|
+
* @param targetArray Array into which to put the item.
|
|
976
|
+
* @param currentIndex Index of the item in its current array.
|
|
977
|
+
* @param targetIndex Index at which to insert the item.
|
|
978
|
+
*/
|
|
979
|
+
function transferArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
|
|
980
|
+
const from = clamp(currentIndex, currentArray.length - 1);
|
|
981
|
+
const to = clamp(targetIndex, targetArray.length);
|
|
982
|
+
if (currentArray.length) {
|
|
983
|
+
targetArray.splice(to, 0, currentArray.splice(from, 1)[0]);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
|
|
526
987
|
/**
|
|
527
988
|
* Generated bundle index. Do not edit.
|
|
528
989
|
*/
|
|
529
990
|
|
|
530
|
-
export { AXDragDirective, AXDragDropModule, AXDragHandleDirective, AXDropZoneDirective };
|
|
991
|
+
export { AXDragDirective, AXDragDropModule, AXDragHandleDirective, AXDropListDirective, AXDropZoneDirective, moveItemInArray, transferArrayItem };
|
|
531
992
|
//# sourceMappingURL=acorex-cdk-drag-drop.mjs.map
|