ngx-kit 6.3.0 → 7.0.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/README.md +3 -3
- package/angle-selector/README.md +34 -34
- package/box-shadow/README.md +33 -33
- package/color-picker/README.md +52 -49
- package/data-table/README.md +120 -113
- package/date-picker/README.md +74 -69
- package/dialog/README.md +92 -92
- package/drag-resize/README.md +55 -0
- package/dropzone/README.md +422 -422
- package/fesm2022/ngx-kit-angle-selector.mjs +2 -2
- package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -1
- package/fesm2022/ngx-kit-box-shadow.mjs +2 -2
- package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
- package/fesm2022/ngx-kit-color-picker.mjs +265 -73
- package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-data-table.mjs +2 -2
- package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
- package/fesm2022/ngx-kit-date-picker.mjs +7 -9
- package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-dialog.mjs +3 -3
- package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
- package/fesm2022/ngx-kit-drag-resize.mjs +1664 -0
- package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -0
- package/fesm2022/ngx-kit-drawer-menu.mjs +389 -285
- package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
- package/fesm2022/ngx-kit-dropzone.mjs +2 -2
- package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
- package/fesm2022/ngx-kit-form-field.mjs +3 -5
- package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
- package/fesm2022/ngx-kit-gallery.mjs +2 -2
- package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
- package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-grid-layout.mjs +927 -0
- package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -0
- package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
- package/fesm2022/ngx-kit-menu.mjs +8 -8
- package/fesm2022/ngx-kit-menu.mjs.map +1 -1
- package/fesm2022/ngx-kit-message.mjs.map +1 -1
- package/fesm2022/ngx-kit-notify.mjs +2 -2
- package/fesm2022/ngx-kit-notify.mjs.map +1 -1
- package/fesm2022/ngx-kit-shared.mjs +54 -3
- package/fesm2022/ngx-kit-shared.mjs.map +1 -1
- package/fesm2022/ngx-kit-time-picker.mjs +2 -2
- package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
- package/fesm2022/ngx-kit-virtual-scroll.mjs +392 -0
- package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -0
- package/fesm2022/ngx-kit-webflow.mjs +709 -0
- package/fesm2022/ngx-kit-webflow.mjs.map +1 -0
- package/gallery/README.md +71 -71
- package/gradient-picker/README.md +41 -41
- package/grid-layout/README.md +64 -0
- package/image-editor/README.md +12 -12
- package/menu/README.md +85 -85
- package/message/README.md +70 -70
- package/notify/README.md +56 -58
- package/package.json +17 -1
- package/shared/README.md +117 -117
- package/time-picker/README.md +89 -95
- package/types/ngx-kit-color-picker.d.ts +72 -16
- package/types/ngx-kit-drag-resize.d.ts +368 -0
- package/types/ngx-kit-drawer-menu.d.ts +135 -86
- package/types/ngx-kit-grid-layout.d.ts +310 -0
- package/types/ngx-kit-image-editor.d.ts +1 -1
- package/types/ngx-kit-shared.d.ts +12 -1
- package/types/ngx-kit-virtual-scroll.d.ts +179 -0
- package/types/ngx-kit-webflow.d.ts +286 -0
- package/virtual-scroll/README.md +199 -0
|
@@ -0,0 +1,1664 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { signal, EventEmitter, Injectable, InjectionToken, Directive, inject, Output, Input, HostListener } from '@angular/core';
|
|
3
|
+
import { DOCUMENT } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Boundary clamping utilities.
|
|
7
|
+
* All functions work purely in viewport ("client") coordinates so they can be
|
|
8
|
+
* reused identically for translate-based dragging and left/top-based resizing.
|
|
9
|
+
*/
|
|
10
|
+
const TOLERANCE = 0.5;
|
|
11
|
+
/** Clamps a proposed vertical delta so the element's rect stays inside the boundary rect. */
|
|
12
|
+
function checkBoundY(selfRect, boundaryRect, offsetY) {
|
|
13
|
+
if (!boundaryRect)
|
|
14
|
+
return offsetY;
|
|
15
|
+
const newTop = selfRect.top + offsetY;
|
|
16
|
+
const newBottom = selfRect.bottom + offsetY;
|
|
17
|
+
if (newTop < boundaryRect.top + TOLERANCE)
|
|
18
|
+
return offsetY + (boundaryRect.top - newTop);
|
|
19
|
+
if (newBottom > boundaryRect.bottom - TOLERANCE)
|
|
20
|
+
return offsetY - (newBottom - boundaryRect.bottom);
|
|
21
|
+
return offsetY;
|
|
22
|
+
}
|
|
23
|
+
/** Clamps a proposed horizontal delta so the element's rect stays inside the boundary rect. */
|
|
24
|
+
function checkBoundX(selfRect, boundaryRect, offsetX) {
|
|
25
|
+
if (!boundaryRect)
|
|
26
|
+
return offsetX;
|
|
27
|
+
const newLeft = selfRect.left + offsetX;
|
|
28
|
+
const newRight = selfRect.right + offsetX;
|
|
29
|
+
if (newLeft < boundaryRect.left + TOLERANCE)
|
|
30
|
+
return offsetX + (boundaryRect.left - newLeft);
|
|
31
|
+
if (newRight > boundaryRect.right - TOLERANCE)
|
|
32
|
+
return offsetX - (newRight - boundaryRect.right);
|
|
33
|
+
return offsetX;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Clamps a resize result (width/height/left/top, all relative CSS px deltas from the
|
|
37
|
+
* element's start position) so the element never grows/moves outside `boundaryRect`.
|
|
38
|
+
* `startRect` is the element's `getBoundingClientRect()` captured at resize-start.
|
|
39
|
+
*/
|
|
40
|
+
function clampResizeWithinBoundary(boundaryRect, startRect, width, height, left, top) {
|
|
41
|
+
if (!boundaryRect)
|
|
42
|
+
return { width, height, left, top };
|
|
43
|
+
// Viewport position implied by the proposed left/top deltas.
|
|
44
|
+
const viewportLeft = startRect.left + left;
|
|
45
|
+
const viewportTop = startRect.top + top;
|
|
46
|
+
let clampedWidth = width;
|
|
47
|
+
let clampedHeight = height;
|
|
48
|
+
let clampedLeft = left;
|
|
49
|
+
let clampedTop = top;
|
|
50
|
+
if (viewportLeft < boundaryRect.left) {
|
|
51
|
+
const overflow = boundaryRect.left - viewportLeft;
|
|
52
|
+
clampedLeft = left + overflow;
|
|
53
|
+
clampedWidth = Math.max(0, clampedWidth - overflow);
|
|
54
|
+
}
|
|
55
|
+
if (viewportTop < boundaryRect.top) {
|
|
56
|
+
const overflow = boundaryRect.top - viewportTop;
|
|
57
|
+
clampedTop = top + overflow;
|
|
58
|
+
clampedHeight = Math.max(0, clampedHeight - overflow);
|
|
59
|
+
}
|
|
60
|
+
const clampedViewportLeft = startRect.left + clampedLeft;
|
|
61
|
+
const rightEdge = clampedViewportLeft + clampedWidth;
|
|
62
|
+
if (rightEdge > boundaryRect.right) {
|
|
63
|
+
clampedWidth = Math.max(0, boundaryRect.right - clampedViewportLeft);
|
|
64
|
+
}
|
|
65
|
+
const clampedViewportTop = startRect.top + clampedTop;
|
|
66
|
+
const bottomEdge = clampedViewportTop + clampedHeight;
|
|
67
|
+
if (bottomEdge > boundaryRect.bottom) {
|
|
68
|
+
clampedHeight = Math.max(0, boundaryRect.bottom - clampedViewportTop);
|
|
69
|
+
}
|
|
70
|
+
return { width: clampedWidth, height: clampedHeight, left: clampedLeft, top: clampedTop };
|
|
71
|
+
}
|
|
72
|
+
/** Current page zoom level (1 = 100%). Falls back to devicePixelRatio pre visualViewport. */
|
|
73
|
+
function getPageZoom() {
|
|
74
|
+
return window.visualViewport?.scale ?? window.devicePixelRatio ?? 1;
|
|
75
|
+
}
|
|
76
|
+
/** Adjusts a raw pointer-derived value for the current page zoom level. */
|
|
77
|
+
function adjustForZoom(value) {
|
|
78
|
+
const zoom = getPageZoom();
|
|
79
|
+
return zoom ? value / zoom : value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function cloneDragElementInBody(dragEl, rect, pointerX, pointerY) {
|
|
83
|
+
const preview = dragEl.cloneNode(true);
|
|
84
|
+
// Avoid duplicated ids in the document.
|
|
85
|
+
preview.removeAttribute('id');
|
|
86
|
+
preview.classList.add('ngx-drag-preview');
|
|
87
|
+
Object.assign(preview.style, {
|
|
88
|
+
position: 'fixed',
|
|
89
|
+
top: `${rect.top}px`,
|
|
90
|
+
left: `${rect.left}px`,
|
|
91
|
+
width: `${rect.width}px`,
|
|
92
|
+
height: `${rect.height}px`,
|
|
93
|
+
margin: '0',
|
|
94
|
+
pointerEvents: 'none',
|
|
95
|
+
boxSizing: 'border-box',
|
|
96
|
+
});
|
|
97
|
+
document.body.appendChild(preview);
|
|
98
|
+
return {
|
|
99
|
+
element: preview,
|
|
100
|
+
offsetX: pointerX - rect.left,
|
|
101
|
+
offsetY: pointerY - rect.top,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let zIndexCounter = 1000;
|
|
106
|
+
class DragRef {
|
|
107
|
+
data;
|
|
108
|
+
el;
|
|
109
|
+
boundary;
|
|
110
|
+
lockAxis;
|
|
111
|
+
dropList = null;
|
|
112
|
+
dropListGroup;
|
|
113
|
+
placeholder;
|
|
114
|
+
originDropList = null;
|
|
115
|
+
originIndex = -1;
|
|
116
|
+
isDragging = signal(false, /* @ts-ignore */
|
|
117
|
+
...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
118
|
+
position = signal({ x: 0, y: 0 }, /* @ts-ignore */
|
|
119
|
+
...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
120
|
+
startPointer = { x: 0, y: 0 };
|
|
121
|
+
startRect;
|
|
122
|
+
lastPointer = { x: 0, y: 0 };
|
|
123
|
+
previousTransform = '';
|
|
124
|
+
previousZIndex = '';
|
|
125
|
+
moveDx = 0;
|
|
126
|
+
moveDy = 0;
|
|
127
|
+
preview;
|
|
128
|
+
previewOffsetX = 0;
|
|
129
|
+
previewOffsetY = 0;
|
|
130
|
+
sourceVisibility = '';
|
|
131
|
+
sourceDisplay = '';
|
|
132
|
+
sourcePointerEvents = '';
|
|
133
|
+
init() {
|
|
134
|
+
this.previousTransform = getComputedStyle(this.el).getPropertyValue('transform');
|
|
135
|
+
}
|
|
136
|
+
withDropList(list) {
|
|
137
|
+
if (this.dropList === list)
|
|
138
|
+
return this;
|
|
139
|
+
this.dropList?.removeItem(this);
|
|
140
|
+
this.dropList = list;
|
|
141
|
+
list?.addItem(this);
|
|
142
|
+
return this;
|
|
143
|
+
}
|
|
144
|
+
clearDropList() {
|
|
145
|
+
this.dropList?.removeItem(this);
|
|
146
|
+
this.dropList = null;
|
|
147
|
+
}
|
|
148
|
+
pointerDown(pointer) {
|
|
149
|
+
this.startPointer = { ...pointer };
|
|
150
|
+
this.lastPointer = { ...pointer };
|
|
151
|
+
}
|
|
152
|
+
startDrag(pointer) {
|
|
153
|
+
this.startRect = this.el.getBoundingClientRect();
|
|
154
|
+
this.startPointer = { ...pointer };
|
|
155
|
+
this.lastPointer = { ...pointer };
|
|
156
|
+
this.moveDx = 0;
|
|
157
|
+
this.moveDy = 0;
|
|
158
|
+
this.originDropList = this.dropList;
|
|
159
|
+
this.originIndex = this.dropList?.getItemIndex(this) ?? -1;
|
|
160
|
+
this.previousTransform = getComputedStyle(this.el).getPropertyValue('transform');
|
|
161
|
+
this.isDragging.set(true);
|
|
162
|
+
this.previousZIndex = this.el.style.zIndex;
|
|
163
|
+
this.sourceVisibility = this.el.style.visibility;
|
|
164
|
+
this.sourceDisplay = this.el.style.display;
|
|
165
|
+
this.sourcePointerEvents = this.el.style.pointerEvents;
|
|
166
|
+
this.el.classList.add('ngx-draggable--dragging');
|
|
167
|
+
this.el.style.willChange = 'transform';
|
|
168
|
+
this.el.style.transition = 'none';
|
|
169
|
+
this.el.style.zIndex = String(++zIndexCounter);
|
|
170
|
+
/*
|
|
171
|
+
* IMPORTANT:
|
|
172
|
+
*
|
|
173
|
+
* Normal Drag:
|
|
174
|
+
* absolutely nothing changes in the element's rendering mechanism.
|
|
175
|
+
*
|
|
176
|
+
* DropList Drag:
|
|
177
|
+
* create a body-level preview because the original element can be
|
|
178
|
+
* inside an overflow:auto/hidden container such as a Kanban column.
|
|
179
|
+
*/
|
|
180
|
+
if (this.dropList) {
|
|
181
|
+
this.placeholder = this.dropList.createPlaceholder(this);
|
|
182
|
+
const preview = cloneDragElementInBody(this.el, this.startRect, pointer.x, pointer.y);
|
|
183
|
+
this.preview = preview.element;
|
|
184
|
+
this.previewOffsetX = preview.offsetX;
|
|
185
|
+
this.previewOffsetY = preview.offsetY;
|
|
186
|
+
this.el.style.visibility = 'hidden';
|
|
187
|
+
this.el.style.display = 'none';
|
|
188
|
+
this.el.style.pointerEvents = 'none';
|
|
189
|
+
this.updatePreview();
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// KEEP THE ORIGINAL DRAG BEHAVIOR.
|
|
193
|
+
this.applyTransform();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
dragMove(pointer) {
|
|
197
|
+
if (!this.isDragging())
|
|
198
|
+
return;
|
|
199
|
+
this.lastPointer = { ...pointer };
|
|
200
|
+
let dx = pointer.x - this.startPointer.x;
|
|
201
|
+
let dy = pointer.y - this.startPointer.y;
|
|
202
|
+
if (this.boundary) {
|
|
203
|
+
dx = checkBoundX(this.startRect, this.boundary.getBoundingClientRect(), dx);
|
|
204
|
+
dy = checkBoundY(this.startRect, this.boundary.getBoundingClientRect(), dy);
|
|
205
|
+
}
|
|
206
|
+
if (this.lockAxis === 'x')
|
|
207
|
+
dy = 0;
|
|
208
|
+
if (this.lockAxis === 'y')
|
|
209
|
+
dx = 0;
|
|
210
|
+
this.moveDx = dx;
|
|
211
|
+
this.moveDy = dy;
|
|
212
|
+
this.position.set({
|
|
213
|
+
x: dx,
|
|
214
|
+
y: dy,
|
|
215
|
+
});
|
|
216
|
+
if (this.dropList) {
|
|
217
|
+
this.updatePreview();
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
this.applyTransform();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
nudge(dx, dy) {
|
|
224
|
+
if (!this.isDragging())
|
|
225
|
+
this.startDrag(this.lastPointer);
|
|
226
|
+
this.dragMove({
|
|
227
|
+
x: this.startPointer.x + this.moveDx + dx,
|
|
228
|
+
y: this.startPointer.y + this.moveDy + dy,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
endDrag() {
|
|
232
|
+
if (!this.isDragging())
|
|
233
|
+
return;
|
|
234
|
+
const dropList = this.dropList;
|
|
235
|
+
this.isDragging.set(false);
|
|
236
|
+
// Normal Drag MUST behave exactly like before.
|
|
237
|
+
this.placeholder?.detach();
|
|
238
|
+
this.placeholder = undefined;
|
|
239
|
+
if (dropList) {
|
|
240
|
+
dropList.finishDrag(this);
|
|
241
|
+
this.el.style.transform = this.previousTransform;
|
|
242
|
+
}
|
|
243
|
+
// Remove body preview after DropList has finished reading its state.
|
|
244
|
+
this.preview?.remove();
|
|
245
|
+
this.preview = undefined;
|
|
246
|
+
this.el.classList.remove('ngx-draggable--dragging');
|
|
247
|
+
this.el.style.visibility = this.sourceVisibility;
|
|
248
|
+
this.el.style.display = this.sourceDisplay;
|
|
249
|
+
this.el.style.pointerEvents = this.sourcePointerEvents;
|
|
250
|
+
this.el.style.willChange = '';
|
|
251
|
+
this.el.style.zIndex = this.previousZIndex;
|
|
252
|
+
}
|
|
253
|
+
cancelDrag() {
|
|
254
|
+
if (!this.isDragging())
|
|
255
|
+
return;
|
|
256
|
+
this.moveDx = 0;
|
|
257
|
+
this.moveDy = 0;
|
|
258
|
+
this.position.set({ x: 0, y: 0 });
|
|
259
|
+
this.dropList?.exit(this);
|
|
260
|
+
this.clearDropList();
|
|
261
|
+
this.el.style.transform = this.previousTransform;
|
|
262
|
+
this.el.style.visibility = this.sourceVisibility;
|
|
263
|
+
this.el.style.pointerEvents = this.sourcePointerEvents;
|
|
264
|
+
this.endDrag();
|
|
265
|
+
}
|
|
266
|
+
get x() {
|
|
267
|
+
return this.moveDx;
|
|
268
|
+
}
|
|
269
|
+
get y() {
|
|
270
|
+
return this.moveDy;
|
|
271
|
+
}
|
|
272
|
+
get pointer() {
|
|
273
|
+
return this.lastPointer;
|
|
274
|
+
}
|
|
275
|
+
get start() {
|
|
276
|
+
return this.startRect;
|
|
277
|
+
}
|
|
278
|
+
getPlaceholderElement() {
|
|
279
|
+
return this.placeholder?.element;
|
|
280
|
+
}
|
|
281
|
+
applyTransform() {
|
|
282
|
+
const base = this.previousTransform && this.previousTransform !== 'none'
|
|
283
|
+
? this.previousTransform + ' '
|
|
284
|
+
: '';
|
|
285
|
+
this.el.style.transform = `${base}translate3d(${this.moveDx}px, ${this.moveDy}px, 0)`;
|
|
286
|
+
}
|
|
287
|
+
updatePreview() {
|
|
288
|
+
if (!this.preview)
|
|
289
|
+
return;
|
|
290
|
+
this.preview.style.transform = `translate3d(${this.moveDx}px, ${this.moveDy}px, 0)`;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Base (LTR) physical direction for every logical direction. */
|
|
295
|
+
const LTR_BASE = {
|
|
296
|
+
start: 'w',
|
|
297
|
+
end: 'e',
|
|
298
|
+
'n-start': 'nw',
|
|
299
|
+
'n-end': 'ne',
|
|
300
|
+
's-start': 'sw',
|
|
301
|
+
's-end': 'se',
|
|
302
|
+
};
|
|
303
|
+
/** Mirrors the horizontal component of a physical direction. 'n' / 's' pass through unchanged. */
|
|
304
|
+
const MIRROR = {
|
|
305
|
+
n: 'n',
|
|
306
|
+
s: 's',
|
|
307
|
+
e: 'w',
|
|
308
|
+
w: 'e',
|
|
309
|
+
ne: 'nw',
|
|
310
|
+
nw: 'ne',
|
|
311
|
+
se: 'sw',
|
|
312
|
+
sw: 'se',
|
|
313
|
+
};
|
|
314
|
+
function isLogicalDirection(dir) {
|
|
315
|
+
return Object.prototype.hasOwnProperty.call(LTR_BASE, dir);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* True when `element` sits inside a right-to-left context.
|
|
319
|
+
*
|
|
320
|
+
* Reads the *computed* `direction` style instead of `element.dir`, because
|
|
321
|
+
* `direction` is inherited and is almost never set on the resizable element
|
|
322
|
+
* itself - it's usually set on `<html>`, `<body>`, or some ancestor wrapper.
|
|
323
|
+
*/
|
|
324
|
+
function isRtl(element) {
|
|
325
|
+
if (typeof window === 'undefined') {
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
return window.getComputedStyle(element).direction === 'rtl';
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Resolves a logical direction ('start' | 'end' | 'n-start' | 'n-end' | 's-start' | 's-end')
|
|
332
|
+
* to a physical, viewport-space direction ('n' | 'e' | 's' | 'w' | 'ne' | 'nw' | 'se' | 'sw')
|
|
333
|
+
* based on `rtl`.
|
|
334
|
+
*
|
|
335
|
+
* Physical directions pass through untouched, so it's always safe to call this
|
|
336
|
+
* even when `dir` might already be physical (e.g. resolving a direction that was
|
|
337
|
+
* already resolved once before).
|
|
338
|
+
*/
|
|
339
|
+
function resolveLogicalDirection(dir, rtl) {
|
|
340
|
+
if (!isLogicalDirection(dir)) {
|
|
341
|
+
return dir;
|
|
342
|
+
}
|
|
343
|
+
const base = LTR_BASE[dir];
|
|
344
|
+
return rtl ? MIRROR[base] : base;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Live geometry sorting.
|
|
349
|
+
*
|
|
350
|
+
* Unlike the old snapshot-only implementation, every sort pass reads the
|
|
351
|
+
* current DOM order and current client rects. This matters when:
|
|
352
|
+
* - the placeholder changes layout,
|
|
353
|
+
* - a Kanban column is scrolled while dragging,
|
|
354
|
+
* - the dragged item enters another list,
|
|
355
|
+
* - CSS grid/flex reflows occur.
|
|
356
|
+
*/
|
|
357
|
+
class PositionalSortStrategy {
|
|
358
|
+
container;
|
|
359
|
+
dragging = null;
|
|
360
|
+
index = -1;
|
|
361
|
+
flow = 'free';
|
|
362
|
+
rtl = false;
|
|
363
|
+
withElementContainer(el) {
|
|
364
|
+
this.container = el;
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
start(_items) {
|
|
368
|
+
this.flow = detectFlow(this.container);
|
|
369
|
+
this.rtl = isRtl(this.container);
|
|
370
|
+
this.index = -1;
|
|
371
|
+
}
|
|
372
|
+
enter(drag, x, y) {
|
|
373
|
+
this.dragging = drag;
|
|
374
|
+
this.index = this.findInsertionIndex(drag, x, y);
|
|
375
|
+
this.movePlaceholder(drag, this.index);
|
|
376
|
+
}
|
|
377
|
+
sort(drag, x, y) {
|
|
378
|
+
this.dragging = drag;
|
|
379
|
+
const next = this.findInsertionIndex(drag, x, y);
|
|
380
|
+
const previous = this.getCurrentIndex();
|
|
381
|
+
if (next === previous)
|
|
382
|
+
return null;
|
|
383
|
+
this.movePlaceholder(drag, next);
|
|
384
|
+
return {
|
|
385
|
+
previousIndex: previous,
|
|
386
|
+
currentIndex: next,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
getCurrentIndex() {
|
|
390
|
+
if (!this.container)
|
|
391
|
+
return Math.max(0, this.index);
|
|
392
|
+
const placeholder = this.dragging?.getPlaceholderElement();
|
|
393
|
+
if (placeholder?.parentElement === this.container) {
|
|
394
|
+
const refs = new Set(this.container.__ngxDragItems ?? []);
|
|
395
|
+
let position = 0;
|
|
396
|
+
const itemElements = new Set(Array.from(refs, (item) => item.el));
|
|
397
|
+
for (const node of Array.from(this.container.children)) {
|
|
398
|
+
if (node === placeholder)
|
|
399
|
+
return position;
|
|
400
|
+
if (node instanceof HTMLElement &&
|
|
401
|
+
itemElements.has(node) &&
|
|
402
|
+
node !== this.dragging?.el) {
|
|
403
|
+
position++;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return Math.max(0, this.index);
|
|
408
|
+
}
|
|
409
|
+
getItemIndex(item) {
|
|
410
|
+
let index = 0;
|
|
411
|
+
const refs = new Set(this.container.__ngxDragItems ?? []);
|
|
412
|
+
const itemElements = new Set(Array.from(refs, (ref) => ref.el));
|
|
413
|
+
for (const node of Array.from(this.container.children)) {
|
|
414
|
+
if (node === item.el)
|
|
415
|
+
return index;
|
|
416
|
+
if (node instanceof HTMLElement &&
|
|
417
|
+
!node.classList.contains('ngx-drag-placeholder') &&
|
|
418
|
+
!node.classList.contains('ngx-drag-in-body') &&
|
|
419
|
+
(!refs.size || itemElements.has(node))) {
|
|
420
|
+
index++;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return -1;
|
|
424
|
+
}
|
|
425
|
+
reset() {
|
|
426
|
+
this.dragging = null;
|
|
427
|
+
this.index = -1;
|
|
428
|
+
}
|
|
429
|
+
movePlaceholder(drag, index) {
|
|
430
|
+
const ph = drag.getPlaceholderElement();
|
|
431
|
+
if (!ph || !this.container)
|
|
432
|
+
return;
|
|
433
|
+
const items = this.readItems(drag);
|
|
434
|
+
const reference = items[index]?.drag.el ?? null;
|
|
435
|
+
if (reference) {
|
|
436
|
+
if (ph !== reference.previousSibling) {
|
|
437
|
+
this.container.insertBefore(ph, reference);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
else if (ph.parentElement !== this.container || ph !== this.container.lastElementChild) {
|
|
441
|
+
this.container.appendChild(ph);
|
|
442
|
+
}
|
|
443
|
+
this.index = Math.max(0, Math.min(index, items.length));
|
|
444
|
+
}
|
|
445
|
+
findInsertionIndex(drag, x, y) {
|
|
446
|
+
const items = this.readItems(drag);
|
|
447
|
+
if (!items.length)
|
|
448
|
+
return 0;
|
|
449
|
+
switch (this.flow) {
|
|
450
|
+
case 'flex-row':
|
|
451
|
+
return this.findFlexRow(items, x);
|
|
452
|
+
case 'flex-column':
|
|
453
|
+
return this.findFlexColumn(items, y);
|
|
454
|
+
case 'grid':
|
|
455
|
+
case 'free':
|
|
456
|
+
default:
|
|
457
|
+
return this.findGrid(items, x, y);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
readItems(drag) {
|
|
461
|
+
const itemSet = new Set(
|
|
462
|
+
// DropListRef maintains the authoritative set; DOM order is authoritative
|
|
463
|
+
// for placement, so we only inspect direct children here.
|
|
464
|
+
this.container.__ngxDragItems ?? []);
|
|
465
|
+
const byElement = new Map(Array.from(itemSet, (item) => [item.el, item]));
|
|
466
|
+
const result = [];
|
|
467
|
+
Array.from(this.container.children).forEach((element, domIndex) => {
|
|
468
|
+
if (!(element instanceof HTMLElement) ||
|
|
469
|
+
element === drag.el ||
|
|
470
|
+
element.classList.contains('ngx-drag-placeholder') ||
|
|
471
|
+
element.classList.contains('ngx-drag-in-body')) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const ref = byElement.get(element);
|
|
475
|
+
if (!ref)
|
|
476
|
+
return;
|
|
477
|
+
result.push({
|
|
478
|
+
drag: ref,
|
|
479
|
+
rect: element.getBoundingClientRect(),
|
|
480
|
+
domIndex,
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
// Fallback for environments where the private bridge is not available.
|
|
484
|
+
if (!result.length) {
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
findFlexRow(items, x) {
|
|
490
|
+
for (let i = 0; i < items.length; i++) {
|
|
491
|
+
const r = items[i].rect;
|
|
492
|
+
const mid = r.left + r.width / 2;
|
|
493
|
+
const before = this.rtl ? x > mid : x < mid;
|
|
494
|
+
if (before)
|
|
495
|
+
return i;
|
|
496
|
+
}
|
|
497
|
+
return items.length;
|
|
498
|
+
}
|
|
499
|
+
findFlexColumn(items, y) {
|
|
500
|
+
for (let i = 0; i < items.length; i++) {
|
|
501
|
+
const r = items[i].rect;
|
|
502
|
+
if (y < r.top + r.height / 2)
|
|
503
|
+
return i;
|
|
504
|
+
}
|
|
505
|
+
return items.length;
|
|
506
|
+
}
|
|
507
|
+
findGrid(items, x, y) {
|
|
508
|
+
let best = items[0];
|
|
509
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
510
|
+
for (const item of items) {
|
|
511
|
+
const cx = item.rect.left + item.rect.width / 2;
|
|
512
|
+
const cy = item.rect.top + item.rect.height / 2;
|
|
513
|
+
const dx = Math.abs(x - cx) / Math.max(item.rect.width, 1);
|
|
514
|
+
const dy = Math.abs(y - cy) / Math.max(item.rect.height, 1);
|
|
515
|
+
const score = dx + dy * 1.2;
|
|
516
|
+
if (score < bestScore) {
|
|
517
|
+
bestScore = score;
|
|
518
|
+
best = item;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const target = best.rect;
|
|
522
|
+
const sameRow = y >= target.top - target.height * 0.35 &&
|
|
523
|
+
y <= target.bottom + target.height * 0.35;
|
|
524
|
+
const before = sameRow
|
|
525
|
+
? this.rtl
|
|
526
|
+
? x > target.left + target.width / 2
|
|
527
|
+
: x < target.left + target.width / 2
|
|
528
|
+
: y < target.top + target.height / 2;
|
|
529
|
+
return Math.max(0, Math.min(items.length, items.findIndex((x) => x === best) + (before ? 0 : 1)));
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
function detectFlow(el) {
|
|
533
|
+
const s = getComputedStyle(el);
|
|
534
|
+
if (s.display.includes('grid'))
|
|
535
|
+
return 'grid';
|
|
536
|
+
if (s.display.includes('flex')) {
|
|
537
|
+
if (s.flexWrap !== 'nowrap')
|
|
538
|
+
return 'grid';
|
|
539
|
+
return s.flexDirection.startsWith('column') ? 'flex-column' : 'flex-row';
|
|
540
|
+
}
|
|
541
|
+
return 'free';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
class PlaceHolderRef {
|
|
545
|
+
tpl;
|
|
546
|
+
dropList;
|
|
547
|
+
element;
|
|
548
|
+
_visible = false;
|
|
549
|
+
attach(container, source, reference) {
|
|
550
|
+
if (!this.element) {
|
|
551
|
+
// Keep the same tag/attributes as the dragged item so selectors such as
|
|
552
|
+
// ".list > article" and grid/flex item rules continue to apply.
|
|
553
|
+
this.element = source.cloneNode(false);
|
|
554
|
+
this.element.removeAttribute('id');
|
|
555
|
+
this.element.classList.add('ngx-drag-placeholder');
|
|
556
|
+
this.element.setAttribute('aria-hidden', 'true');
|
|
557
|
+
this.element.setAttribute('inert', '');
|
|
558
|
+
this.element.removeAttribute('tabindex');
|
|
559
|
+
}
|
|
560
|
+
// The placeholder must never inherit a live drag transform/animation.
|
|
561
|
+
this.element.style.setProperty('transform', 'none', 'important');
|
|
562
|
+
this.element.style.setProperty('transition', 'none', 'important');
|
|
563
|
+
this.element.style.setProperty('animation', 'none', 'important');
|
|
564
|
+
this.element.style.setProperty('pointer-events', 'none', 'important');
|
|
565
|
+
this.element.style.setProperty('visibility', 'visible', 'important');
|
|
566
|
+
this.element.style.setProperty('opacity', '0.16', 'important');
|
|
567
|
+
this.element.style.setProperty('outline', '2px dashed currentColor', 'important');
|
|
568
|
+
this.element.style.setProperty('outline-offset', '-2px', 'important');
|
|
569
|
+
this._visible = true;
|
|
570
|
+
if (reference && reference.parentNode === container) {
|
|
571
|
+
if (this.element !== reference)
|
|
572
|
+
container.insertBefore(this.element, reference);
|
|
573
|
+
}
|
|
574
|
+
else if (this.element.parentNode !== container) {
|
|
575
|
+
container.appendChild(this.element);
|
|
576
|
+
}
|
|
577
|
+
return this.element;
|
|
578
|
+
}
|
|
579
|
+
detach() {
|
|
580
|
+
this.element?.remove();
|
|
581
|
+
this._visible = false;
|
|
582
|
+
}
|
|
583
|
+
get visible() {
|
|
584
|
+
return this._visible && !!this.element?.isConnected;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* DropListRef is intentionally generic, while the positional sorting strategy
|
|
590
|
+
* works on DragRef<any>. The public DropList/DragRef relationship is invariant
|
|
591
|
+
* because IDropEvent<T> contains T in a callback position. Keep the strongly
|
|
592
|
+
* typed Set here, and narrow only at the DOM-local bridge / strategy boundary.
|
|
593
|
+
*/
|
|
594
|
+
class DropListRef {
|
|
595
|
+
data;
|
|
596
|
+
el;
|
|
597
|
+
disableSort = false;
|
|
598
|
+
connectedTo = [];
|
|
599
|
+
dropListGroup;
|
|
600
|
+
_draggables = new Set();
|
|
601
|
+
onDrop = new EventEmitter();
|
|
602
|
+
strategy = new PositionalSortStrategy();
|
|
603
|
+
active = false;
|
|
604
|
+
previousIndex = -1;
|
|
605
|
+
placeholder;
|
|
606
|
+
addItem(item) {
|
|
607
|
+
this._draggables.add(item);
|
|
608
|
+
this.publishDragItems();
|
|
609
|
+
}
|
|
610
|
+
removeItem(item) {
|
|
611
|
+
this._draggables.delete(item);
|
|
612
|
+
this.publishDragItems();
|
|
613
|
+
}
|
|
614
|
+
isConnectedTo(other) {
|
|
615
|
+
if (other === this)
|
|
616
|
+
return true;
|
|
617
|
+
if (this.connectedTo.includes(other.el) || other.connectedTo.includes(this.el))
|
|
618
|
+
return true;
|
|
619
|
+
return !!this.dropListGroup && this.dropListGroup.has(other);
|
|
620
|
+
}
|
|
621
|
+
createPlaceholder(drag) {
|
|
622
|
+
// There is exactly one placeholder for the active drag.
|
|
623
|
+
this.placeholder?.detach();
|
|
624
|
+
const ref = new PlaceHolderRef();
|
|
625
|
+
ref.dropList = this;
|
|
626
|
+
const source = drag.el;
|
|
627
|
+
const rect = source.getBoundingClientRect();
|
|
628
|
+
ref.attach(this.el, source);
|
|
629
|
+
this.copyPlaceholderGeometry(source, ref.element, rect);
|
|
630
|
+
this.placeholder = ref;
|
|
631
|
+
drag.placeholder = ref;
|
|
632
|
+
this.enter(drag, drag.pointer.x, drag.pointer.y);
|
|
633
|
+
return ref;
|
|
634
|
+
}
|
|
635
|
+
enter(drag, x = 0, y = 0) {
|
|
636
|
+
if (!this.active) {
|
|
637
|
+
this.active = true;
|
|
638
|
+
this.previousIndex = this.indexOf(drag);
|
|
639
|
+
// Sorting strategy reads the live DOM. Expose the authoritative refs
|
|
640
|
+
// through a DOM-local bridge with the intentionally wider any type.
|
|
641
|
+
this.publishDragItems();
|
|
642
|
+
this.strategy.withElementContainer(this.el).start(this.getStrategyItems());
|
|
643
|
+
this.el.classList.add('ngx-drop-list--active');
|
|
644
|
+
}
|
|
645
|
+
this.strategy.enter(this.asStrategyDrag(drag), x, y);
|
|
646
|
+
}
|
|
647
|
+
sortItem(drag, position) {
|
|
648
|
+
if (!this.active || this.disableSort)
|
|
649
|
+
return null;
|
|
650
|
+
return (this.strategy.sort(this.asStrategyDrag(drag), position.x, position.y)?.currentIndex ?? null);
|
|
651
|
+
}
|
|
652
|
+
finishDrag(drag) {
|
|
653
|
+
if (!this.active)
|
|
654
|
+
return;
|
|
655
|
+
const currentIndex = this.strategy.getCurrentIndex();
|
|
656
|
+
this.onDrop.emit({
|
|
657
|
+
previousIndex: Math.max(0, drag.originIndex >= 0 ? drag.originIndex : this.previousIndex),
|
|
658
|
+
currentIndex,
|
|
659
|
+
item: drag,
|
|
660
|
+
container: this,
|
|
661
|
+
previousContainer: drag.originDropList ?? this,
|
|
662
|
+
});
|
|
663
|
+
this.reset();
|
|
664
|
+
}
|
|
665
|
+
exit(_drag) {
|
|
666
|
+
if (!this.active)
|
|
667
|
+
return;
|
|
668
|
+
this.placeholder?.detach();
|
|
669
|
+
this.reset();
|
|
670
|
+
}
|
|
671
|
+
resetSortTransforms() {
|
|
672
|
+
this.reset();
|
|
673
|
+
}
|
|
674
|
+
getFinalIndex() {
|
|
675
|
+
return this.strategy.getCurrentIndex();
|
|
676
|
+
}
|
|
677
|
+
getItemIndex(item) {
|
|
678
|
+
return this.indexOf(item);
|
|
679
|
+
}
|
|
680
|
+
indexOf(item) {
|
|
681
|
+
const elements = new Set(this._draggables);
|
|
682
|
+
let index = 0;
|
|
683
|
+
for (const node of Array.from(this.el.children)) {
|
|
684
|
+
if (!(node instanceof HTMLElement))
|
|
685
|
+
continue;
|
|
686
|
+
if (node === this.placeholder?.element)
|
|
687
|
+
continue;
|
|
688
|
+
if (node.classList.contains('ngx-drag-in-body'))
|
|
689
|
+
continue;
|
|
690
|
+
const ref = Array.from(elements).find((candidate) => candidate.el === node);
|
|
691
|
+
if (!ref)
|
|
692
|
+
continue;
|
|
693
|
+
if (ref === item)
|
|
694
|
+
return index;
|
|
695
|
+
index++;
|
|
696
|
+
}
|
|
697
|
+
return -1;
|
|
698
|
+
}
|
|
699
|
+
reset() {
|
|
700
|
+
this.active = false;
|
|
701
|
+
this.strategy.reset();
|
|
702
|
+
this.placeholder?.detach();
|
|
703
|
+
this.placeholder = undefined;
|
|
704
|
+
this.publishDragItems();
|
|
705
|
+
this.el.classList.remove('ngx-drop-list--active');
|
|
706
|
+
}
|
|
707
|
+
copyPlaceholderGeometry(source, placeholder, rect) {
|
|
708
|
+
// copyComputedStyleTree(source, placeholder);
|
|
709
|
+
placeholder.style.setProperty('width', `${rect.width}px`, 'important');
|
|
710
|
+
placeholder.style.setProperty('height', `${rect.height}px`, 'important');
|
|
711
|
+
placeholder.style.setProperty('min-width', `${rect.width}px`, 'important');
|
|
712
|
+
placeholder.style.setProperty('min-height', `${rect.height}px`, 'important');
|
|
713
|
+
placeholder.style.setProperty('max-width', `${rect.width}px`, 'important');
|
|
714
|
+
placeholder.style.setProperty('max-height', `${rect.height}px`, 'important');
|
|
715
|
+
placeholder.style.setProperty('visibility', 'visible', 'important');
|
|
716
|
+
placeholder.style.setProperty('opacity', '0.16', 'important');
|
|
717
|
+
placeholder.style.setProperty('pointer-events', 'none', 'important');
|
|
718
|
+
placeholder.style.setProperty('transform', 'none', 'important');
|
|
719
|
+
placeholder.style.setProperty('transition', 'none', 'important');
|
|
720
|
+
placeholder.style.setProperty('animation', 'none', 'important');
|
|
721
|
+
placeholder.style.setProperty('box-sizing', 'border-box', 'important');
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* The sorting strategy only needs a read-only collection of draggable refs.
|
|
725
|
+
* Using DragRef<any> at this internal boundary avoids the invariant generic
|
|
726
|
+
* relationship between DragRef<T> and DragRef<unknown>.
|
|
727
|
+
*/
|
|
728
|
+
getStrategyItems() {
|
|
729
|
+
return Array.from(this._draggables);
|
|
730
|
+
}
|
|
731
|
+
asStrategyDrag(drag) {
|
|
732
|
+
return drag;
|
|
733
|
+
}
|
|
734
|
+
publishDragItems() {
|
|
735
|
+
this.el.__ngxDragItems = this._draggables;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Groups multiple drop lists so items can be dragged between them without
|
|
741
|
+
* needing an explicit `connectedTo` list on every single one.
|
|
742
|
+
* Lists register themselves automatically when `NgxDropListGroup` wraps them.
|
|
743
|
+
*/
|
|
744
|
+
class DropListGroupRef {
|
|
745
|
+
lists = new Set();
|
|
746
|
+
add(list) {
|
|
747
|
+
this.lists.add(list);
|
|
748
|
+
}
|
|
749
|
+
remove(list) {
|
|
750
|
+
this.lists.delete(list);
|
|
751
|
+
}
|
|
752
|
+
has(list) {
|
|
753
|
+
return !!list && this.lists.has(list);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
class DragDropService {
|
|
758
|
+
drags = signal([], /* @ts-ignore */
|
|
759
|
+
...(ngDevMode ? [{ debugName: "drags" }] : /* istanbul ignore next */ []));
|
|
760
|
+
dropLists = signal([], /* @ts-ignore */
|
|
761
|
+
...(ngDevMode ? [{ debugName: "dropLists" }] : /* istanbul ignore next */ []));
|
|
762
|
+
activeDrag = signal(null, /* @ts-ignore */
|
|
763
|
+
...(ngDevMode ? [{ debugName: "activeDrag" }] : /* istanbul ignore next */ []));
|
|
764
|
+
registerDragItem(ref) {
|
|
765
|
+
this.drags.update((items) => (items.includes(ref) ? items : [...items, ref]));
|
|
766
|
+
}
|
|
767
|
+
removeDragItem(ref) {
|
|
768
|
+
this.drags.update((items) => items.filter((x) => x !== ref));
|
|
769
|
+
if (this.activeDrag() === ref)
|
|
770
|
+
this.activeDrag.set(null);
|
|
771
|
+
}
|
|
772
|
+
registerDropList(ref) {
|
|
773
|
+
this.dropLists.update((items) => (items.includes(ref) ? items : [...items, ref]));
|
|
774
|
+
}
|
|
775
|
+
removeDropList(ref) {
|
|
776
|
+
this.dropLists.update((items) => items.filter((x) => x !== ref));
|
|
777
|
+
}
|
|
778
|
+
begin(ref) {
|
|
779
|
+
this.activeDrag.set(ref);
|
|
780
|
+
}
|
|
781
|
+
end(ref) {
|
|
782
|
+
if (this.activeDrag() === ref)
|
|
783
|
+
this.activeDrag.set(null);
|
|
784
|
+
}
|
|
785
|
+
cancelActive() {
|
|
786
|
+
const ref = this.activeDrag();
|
|
787
|
+
if (!ref)
|
|
788
|
+
return;
|
|
789
|
+
ref.cancelDrag();
|
|
790
|
+
this.activeDrag.set(null);
|
|
791
|
+
}
|
|
792
|
+
findDropList(point, current) {
|
|
793
|
+
const candidates = this.dropLists()
|
|
794
|
+
.filter((list) => {
|
|
795
|
+
const r = list.el?.getBoundingClientRect();
|
|
796
|
+
return (!!r &&
|
|
797
|
+
point.x >= r.left &&
|
|
798
|
+
point.x <= r.right &&
|
|
799
|
+
point.y >= r.top &&
|
|
800
|
+
point.y <= r.bottom);
|
|
801
|
+
});
|
|
802
|
+
// Staying over the current list should always win.
|
|
803
|
+
if (current && candidates.includes(current))
|
|
804
|
+
return current;
|
|
805
|
+
// Never jump into an unrelated list just because it overlaps the pointer.
|
|
806
|
+
// Prefer the smallest matching connected container (useful for nested lists).
|
|
807
|
+
return candidates
|
|
808
|
+
.filter((list) => !current || current.isConnectedTo(list))
|
|
809
|
+
.sort((a, b) => {
|
|
810
|
+
const ra = a.el.getBoundingClientRect();
|
|
811
|
+
const rb = b.el.getBoundingClientRect();
|
|
812
|
+
return ra.width * ra.height - rb.width * rb.height;
|
|
813
|
+
})[0] ?? null;
|
|
814
|
+
}
|
|
815
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DragDropService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
816
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DragDropService, providedIn: 'root' });
|
|
817
|
+
}
|
|
818
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: DragDropService, decorators: [{
|
|
819
|
+
type: Injectable,
|
|
820
|
+
args: [{ providedIn: 'root' }]
|
|
821
|
+
}] });
|
|
822
|
+
|
|
823
|
+
const NGX_DROPLIST_GROUP = new InjectionToken('ngx-drop-list-group');
|
|
824
|
+
/** Wrap several `ngxDropList`s to let items move freely between them. */
|
|
825
|
+
class NgxDropListGroup {
|
|
826
|
+
_ref = new DropListGroupRef();
|
|
827
|
+
ngOnDestroy() {
|
|
828
|
+
this._ref.lists.clear();
|
|
829
|
+
}
|
|
830
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropListGroup, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
831
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDropListGroup, isStandalone: true, selector: "[NgxDropListGroup],[ngxDropListGroup]", providers: [{ provide: NGX_DROPLIST_GROUP, useExisting: NgxDropListGroup }], ngImport: i0 });
|
|
832
|
+
}
|
|
833
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropListGroup, decorators: [{
|
|
834
|
+
type: Directive,
|
|
835
|
+
args: [{
|
|
836
|
+
selector: '[NgxDropListGroup],[ngxDropListGroup]',
|
|
837
|
+
providers: [{ provide: NGX_DROPLIST_GROUP, useExisting: NgxDropListGroup }],
|
|
838
|
+
}]
|
|
839
|
+
}] });
|
|
840
|
+
|
|
841
|
+
const NGX_DROPLIST = new InjectionToken('ngx-drop-list');
|
|
842
|
+
class NgxDropList {
|
|
843
|
+
el;
|
|
844
|
+
_ref = new DropListRef();
|
|
845
|
+
set data(value) {
|
|
846
|
+
this._ref.data = value;
|
|
847
|
+
}
|
|
848
|
+
set connectedTo(value) {
|
|
849
|
+
this._ref.connectedTo = value ?? [];
|
|
850
|
+
}
|
|
851
|
+
set disableSort(value) {
|
|
852
|
+
this._ref.disableSort = value === true;
|
|
853
|
+
}
|
|
854
|
+
drop = new EventEmitter();
|
|
855
|
+
service = inject(DragDropService);
|
|
856
|
+
group = inject(NGX_DROPLIST_GROUP, { optional: true, skipSelf: true });
|
|
857
|
+
constructor(el) {
|
|
858
|
+
this.el = el;
|
|
859
|
+
}
|
|
860
|
+
ngOnInit() {
|
|
861
|
+
this._ref.el = this.el.nativeElement;
|
|
862
|
+
this._ref.dropListGroup = this.group?._ref ?? null;
|
|
863
|
+
// Previously the group directive never actually tracked its lists — fixed here.
|
|
864
|
+
this.group?._ref.add(this._ref);
|
|
865
|
+
this._ref.onDrop.subscribe((e) => this.drop.emit(e));
|
|
866
|
+
this.service.registerDropList(this._ref);
|
|
867
|
+
}
|
|
868
|
+
ngOnDestroy() {
|
|
869
|
+
this.group?._ref.remove(this._ref);
|
|
870
|
+
this.service.removeDropList(this._ref);
|
|
871
|
+
}
|
|
872
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropList, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
873
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDropList, isStandalone: true, selector: "[NgxDropList],[ngxDropList]", inputs: { data: "data", connectedTo: "connectedTo", disableSort: "disableSort" }, outputs: { drop: "drop" }, host: { classAttribute: "ngx-drop-list" }, providers: [{ provide: NGX_DROPLIST, useExisting: NgxDropList }], ngImport: i0 });
|
|
874
|
+
}
|
|
875
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDropList, decorators: [{
|
|
876
|
+
type: Directive,
|
|
877
|
+
args: [{
|
|
878
|
+
selector: '[NgxDropList],[ngxDropList]',
|
|
879
|
+
providers: [{ provide: NGX_DROPLIST, useExisting: NgxDropList }],
|
|
880
|
+
host: { class: 'ngx-drop-list' },
|
|
881
|
+
}]
|
|
882
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { data: [{
|
|
883
|
+
type: Input,
|
|
884
|
+
args: ['data']
|
|
885
|
+
}], connectedTo: [{
|
|
886
|
+
type: Input
|
|
887
|
+
}], disableSort: [{
|
|
888
|
+
type: Input
|
|
889
|
+
}], drop: [{
|
|
890
|
+
type: Output
|
|
891
|
+
}] } });
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Auto-scrolls the nearest scrollable ancestor (or window) while the pointer
|
|
895
|
+
* is dragged near the edge of the scrollable viewport. Direction-agnostic —
|
|
896
|
+
* works the same in RTL and LTR since it operates on physical scroll deltas.
|
|
897
|
+
*/
|
|
898
|
+
class AutoScroller {
|
|
899
|
+
raf = 0;
|
|
900
|
+
container = window;
|
|
901
|
+
speed = { x: 0, y: 0 };
|
|
902
|
+
edge;
|
|
903
|
+
maxSpeed;
|
|
904
|
+
constructor(edge = 56, maxSpeed = 18) {
|
|
905
|
+
this.edge = edge;
|
|
906
|
+
this.maxSpeed = maxSpeed;
|
|
907
|
+
}
|
|
908
|
+
start(fromEl) {
|
|
909
|
+
this.container = findScrollableAncestor(fromEl);
|
|
910
|
+
}
|
|
911
|
+
/** Call on every pointermove with the current client coordinates. */
|
|
912
|
+
update(clientX, clientY) {
|
|
913
|
+
const rect = getScrollRect(this.container);
|
|
914
|
+
this.speed = {
|
|
915
|
+
x: edgeSpeed(clientX, rect.left, rect.right, this.edge, this.maxSpeed),
|
|
916
|
+
y: edgeSpeed(clientY, rect.top, rect.bottom, this.edge, this.maxSpeed),
|
|
917
|
+
};
|
|
918
|
+
if ((this.speed.x || this.speed.y) && !this.raf) {
|
|
919
|
+
this.raf = requestAnimationFrame(this.tick);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
stop() {
|
|
923
|
+
if (this.raf)
|
|
924
|
+
cancelAnimationFrame(this.raf);
|
|
925
|
+
this.raf = 0;
|
|
926
|
+
this.speed = { x: 0, y: 0 };
|
|
927
|
+
}
|
|
928
|
+
tick = () => {
|
|
929
|
+
if (!this.speed.x && !this.speed.y) {
|
|
930
|
+
this.raf = 0;
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
if (this.container instanceof Window) {
|
|
934
|
+
this.container.scrollBy(this.speed.x, this.speed.y);
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
this.container.scrollLeft += this.speed.x;
|
|
938
|
+
this.container.scrollTop += this.speed.y;
|
|
939
|
+
}
|
|
940
|
+
this.raf = requestAnimationFrame(this.tick);
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
function edgeSpeed(pos, min, max, edge, maxSpeed) {
|
|
944
|
+
if (pos < min + edge)
|
|
945
|
+
return -maxSpeed * (1 - Math.max(0, pos - min) / edge);
|
|
946
|
+
if (pos > max - edge)
|
|
947
|
+
return maxSpeed * (1 - Math.max(0, max - pos) / edge);
|
|
948
|
+
return 0;
|
|
949
|
+
}
|
|
950
|
+
function getScrollRect(container) {
|
|
951
|
+
if (container instanceof Window) {
|
|
952
|
+
return { left: 0, top: 0, right: window.innerWidth, bottom: window.innerHeight };
|
|
953
|
+
}
|
|
954
|
+
return container.getBoundingClientRect();
|
|
955
|
+
}
|
|
956
|
+
function findScrollableAncestor(el) {
|
|
957
|
+
let node = el;
|
|
958
|
+
while (node) {
|
|
959
|
+
const style = getComputedStyle(node);
|
|
960
|
+
const scrollable = /(auto|scroll|overlay)/.test(style.overflowY + style.overflowX);
|
|
961
|
+
if (scrollable && node.scrollHeight > node.clientHeight)
|
|
962
|
+
return node;
|
|
963
|
+
node = node.parentElement;
|
|
964
|
+
}
|
|
965
|
+
return window;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
const NGX_DRAGGABLE = new InjectionToken('ngx-draggable');
|
|
969
|
+
const DEFAULT_KEYBOARD_STEP = 8;
|
|
970
|
+
class NgxDraggable {
|
|
971
|
+
host;
|
|
972
|
+
renderer;
|
|
973
|
+
disabled = false;
|
|
974
|
+
/** Element whose rect constrains the drag. Now actually enforced. */
|
|
975
|
+
boundary;
|
|
976
|
+
dragRootElement = '';
|
|
977
|
+
/** CSS selector for a drag handle. When set, only pointerdowns inside it start a drag. */
|
|
978
|
+
dragHandle = '';
|
|
979
|
+
/** Restrict movement to a single axis. */
|
|
980
|
+
lockAxis;
|
|
981
|
+
/** Minimum pointer travel (px) before a drag starts, so clicks still register normally. */
|
|
982
|
+
dragThreshold = 3;
|
|
983
|
+
/** Pixel step used when dragging via the keyboard (arrow keys, focus required). */
|
|
984
|
+
keyboardStep = DEFAULT_KEYBOARD_STEP;
|
|
985
|
+
/** Auto-scroll the nearest scrollable ancestor while dragging near its edge. */
|
|
986
|
+
autoScroll = true;
|
|
987
|
+
set data(v) {
|
|
988
|
+
this._ref.data = v;
|
|
989
|
+
}
|
|
990
|
+
dragStart = new EventEmitter();
|
|
991
|
+
dragMove = new EventEmitter();
|
|
992
|
+
dragEnd = new EventEmitter();
|
|
993
|
+
_ref = new DragRef();
|
|
994
|
+
dragging = signal(false, /* @ts-ignore */
|
|
995
|
+
...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
|
|
996
|
+
doc = inject(DOCUMENT);
|
|
997
|
+
service = inject(DragDropService);
|
|
998
|
+
list = inject(NGX_DROPLIST, { optional: true, skipSelf: true });
|
|
999
|
+
group = inject(NGX_DROPLIST_GROUP, { optional: true, skipSelf: true });
|
|
1000
|
+
scroller = new AutoScroller();
|
|
1001
|
+
down = false;
|
|
1002
|
+
start = { x: 0, y: 0 };
|
|
1003
|
+
pointerId = -1;
|
|
1004
|
+
removeDown;
|
|
1005
|
+
removeMove;
|
|
1006
|
+
removeUp;
|
|
1007
|
+
removeKeydown;
|
|
1008
|
+
removeEscape;
|
|
1009
|
+
constructor(host, renderer) {
|
|
1010
|
+
this.host = host;
|
|
1011
|
+
this.renderer = renderer;
|
|
1012
|
+
}
|
|
1013
|
+
ngOnInit() {
|
|
1014
|
+
this._ref.el = this.dragRootElement
|
|
1015
|
+
? (this.host.nativeElement.closest(this.dragRootElement) ?? this.host.nativeElement)
|
|
1016
|
+
: this.host.nativeElement;
|
|
1017
|
+
this._ref.boundary = this.boundary;
|
|
1018
|
+
this._ref.lockAxis = this.lockAxis;
|
|
1019
|
+
this._ref.dropListGroup = this.group?._ref;
|
|
1020
|
+
this._ref.init();
|
|
1021
|
+
this._ref.withDropList(this.list?._ref ?? null);
|
|
1022
|
+
this.service.registerDragItem(this._ref);
|
|
1023
|
+
this.removeDown = this.renderer.listen(this.host.nativeElement, 'pointerdown', (e) => this.pointerDown(e));
|
|
1024
|
+
this.removeKeydown = this.renderer.listen(this.host.nativeElement, 'keydown', (e) => this.keyDown(e));
|
|
1025
|
+
}
|
|
1026
|
+
ngOnDestroy() {
|
|
1027
|
+
this.removeDown?.();
|
|
1028
|
+
this.removeMove?.();
|
|
1029
|
+
this.removeUp?.();
|
|
1030
|
+
this.removeKeydown?.();
|
|
1031
|
+
this.removeEscape?.();
|
|
1032
|
+
this.scroller.stop();
|
|
1033
|
+
this.service.removeDragItem(this._ref);
|
|
1034
|
+
this._ref.dropList?.removeItem(this._ref);
|
|
1035
|
+
}
|
|
1036
|
+
pointerDown(e) {
|
|
1037
|
+
if (this.disabled ||
|
|
1038
|
+
e.button !== 0 ||
|
|
1039
|
+
// this.isInteractive(e.target) ||
|
|
1040
|
+
!this.isOnHandle(e.target))
|
|
1041
|
+
return;
|
|
1042
|
+
e.preventDefault();
|
|
1043
|
+
this.down = true;
|
|
1044
|
+
this.pointerId = e.pointerId;
|
|
1045
|
+
this.start = { x: e.clientX, y: e.clientY };
|
|
1046
|
+
this._ref.boundary = this.boundary;
|
|
1047
|
+
this._ref.lockAxis = this.lockAxis;
|
|
1048
|
+
this._ref.pointerDown(this.start);
|
|
1049
|
+
this.removeMove = this.renderer.listen(this.doc, 'pointermove', (ev) => this.pointerMove(ev));
|
|
1050
|
+
this.removeUp = this.renderer.listen(this.doc, 'pointerup', (ev) => this.pointerUp(ev));
|
|
1051
|
+
this.removeEscape = this.renderer.listen(this.doc, 'keydown', (ev) => {
|
|
1052
|
+
if (ev.key === 'Escape' && this.dragging())
|
|
1053
|
+
this.cancel();
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
pointerMove(e) {
|
|
1057
|
+
if (!this.down || e.pointerId !== this.pointerId)
|
|
1058
|
+
return;
|
|
1059
|
+
const p = { x: e.clientX, y: e.clientY };
|
|
1060
|
+
if (!this.dragging() && Math.hypot(p.x - this.start.x, p.y - this.start.y) < this.dragThreshold)
|
|
1061
|
+
return;
|
|
1062
|
+
if (!this.dragging()) {
|
|
1063
|
+
this._ref.startDrag(p);
|
|
1064
|
+
this.dragging.set(true);
|
|
1065
|
+
this.service.begin(this._ref);
|
|
1066
|
+
if (this.autoScroll)
|
|
1067
|
+
this.scroller.start(this._ref.el);
|
|
1068
|
+
this.dragStart.emit(p);
|
|
1069
|
+
}
|
|
1070
|
+
this._ref.dragMove(p);
|
|
1071
|
+
const target = this.service.findDropList(p, this._ref.dropList);
|
|
1072
|
+
if (target !== this._ref.dropList) {
|
|
1073
|
+
this._ref.dropList?.exit(this._ref);
|
|
1074
|
+
this._ref.clearDropList();
|
|
1075
|
+
if (target) {
|
|
1076
|
+
this._ref.withDropList(target);
|
|
1077
|
+
target.createPlaceholder(this._ref);
|
|
1078
|
+
if (this.autoScroll) {
|
|
1079
|
+
this.scroller.stop();
|
|
1080
|
+
this.scroller.start(target.el);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
else if (this.autoScroll) {
|
|
1084
|
+
this.scroller.stop();
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
// Sorting uses the pointer against the currently active list. Its geometry
|
|
1088
|
+
// is read live, so the placeholder and auto-scroll are both reflected.
|
|
1089
|
+
this._ref.dropList?.sortItem(this._ref, p);
|
|
1090
|
+
if (this.autoScroll)
|
|
1091
|
+
this.scroller.update(p.x, p.y);
|
|
1092
|
+
this.dragMove.emit(p);
|
|
1093
|
+
}
|
|
1094
|
+
pointerUp(e) {
|
|
1095
|
+
if (!this.down || e.pointerId !== this.pointerId)
|
|
1096
|
+
return;
|
|
1097
|
+
if (this.dragging()) {
|
|
1098
|
+
if (this._ref.dropList) {
|
|
1099
|
+
this._ref.endDrag();
|
|
1100
|
+
}
|
|
1101
|
+
this.service.end(this._ref);
|
|
1102
|
+
}
|
|
1103
|
+
this.finish();
|
|
1104
|
+
this.dragEnd.emit(this._ref.pointer);
|
|
1105
|
+
}
|
|
1106
|
+
cancel() {
|
|
1107
|
+
this._ref.cancelDrag();
|
|
1108
|
+
this.service.end(this._ref);
|
|
1109
|
+
this.finish();
|
|
1110
|
+
}
|
|
1111
|
+
finish() {
|
|
1112
|
+
this.dragging.set(false);
|
|
1113
|
+
this.down = false;
|
|
1114
|
+
this.scroller.stop();
|
|
1115
|
+
this.removeMove?.();
|
|
1116
|
+
this.removeUp?.();
|
|
1117
|
+
this.removeEscape?.();
|
|
1118
|
+
this.removeMove = this.removeUp = this.removeEscape = undefined;
|
|
1119
|
+
}
|
|
1120
|
+
/** Arrow-key movement for keyboard/assistive-tech users. Shift multiplies the step by 4. */
|
|
1121
|
+
keyDown(e) {
|
|
1122
|
+
if (this.disabled)
|
|
1123
|
+
return;
|
|
1124
|
+
const step = this.keyboardStep * (e.shiftKey ? 4 : 1);
|
|
1125
|
+
const deltas = {
|
|
1126
|
+
ArrowLeft: { x: -step, y: 0 },
|
|
1127
|
+
ArrowRight: { x: step, y: 0 },
|
|
1128
|
+
ArrowUp: { x: 0, y: -step },
|
|
1129
|
+
ArrowDown: { x: 0, y: step },
|
|
1130
|
+
};
|
|
1131
|
+
const delta = deltas[e.key];
|
|
1132
|
+
if (delta) {
|
|
1133
|
+
e.preventDefault();
|
|
1134
|
+
if (!this.dragging()) {
|
|
1135
|
+
this._ref.pointerDown({ x: 0, y: 0 });
|
|
1136
|
+
this._ref.boundary = this.boundary;
|
|
1137
|
+
this._ref.lockAxis = this.lockAxis;
|
|
1138
|
+
this._ref.startDrag({ x: 0, y: 0 });
|
|
1139
|
+
this.dragging.set(true);
|
|
1140
|
+
this.service.begin(this._ref);
|
|
1141
|
+
this.dragStart.emit({ x: 0, y: 0 });
|
|
1142
|
+
}
|
|
1143
|
+
this._ref.nudge(delta.x, delta.y);
|
|
1144
|
+
this.dragMove.emit(this._ref.pointer);
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
if ((e.key === 'Enter' || e.key === ' ') && this.dragging()) {
|
|
1148
|
+
e.preventDefault();
|
|
1149
|
+
this._ref.endDrag();
|
|
1150
|
+
this.service.end(this._ref);
|
|
1151
|
+
this.dragEnd.emit(this._ref.pointer);
|
|
1152
|
+
this.dragging.set(false);
|
|
1153
|
+
}
|
|
1154
|
+
else if (e.key === 'Escape' && this.dragging()) {
|
|
1155
|
+
e.preventDefault();
|
|
1156
|
+
this._ref.cancelDrag();
|
|
1157
|
+
this.service.end(this._ref);
|
|
1158
|
+
this.dragging.set(false);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
isOnHandle(target) {
|
|
1162
|
+
if (!this.dragHandle)
|
|
1163
|
+
return true;
|
|
1164
|
+
return target instanceof HTMLElement && !!target.closest(this.dragHandle);
|
|
1165
|
+
}
|
|
1166
|
+
isInteractive(target) {
|
|
1167
|
+
return (target instanceof HTMLElement &&
|
|
1168
|
+
!!target.closest('button,a,input,textarea,select,[data-no-drag]'));
|
|
1169
|
+
}
|
|
1170
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDraggable, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1171
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxDraggable, isStandalone: true, selector: "[NgxDraggable],[ngxDraggable]", inputs: { disabled: "disabled", boundary: "boundary", dragRootElement: "dragRootElement", dragHandle: "dragHandle", lockAxis: "lockAxis", dragThreshold: "dragThreshold", keyboardStep: "keyboardStep", autoScroll: "autoScroll", data: "data" }, outputs: { dragStart: "dragStart", dragMove: "dragMove", dragEnd: "dragEnd" }, host: { properties: { "style.touch-action": "\"none\"", "attr.tabindex": "disabled ? null : 0", "attr.aria-grabbed": "dragging()" }, classAttribute: "ngx-draggable" }, providers: [{ provide: NGX_DRAGGABLE, useExisting: NgxDraggable }], ngImport: i0 });
|
|
1172
|
+
}
|
|
1173
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDraggable, decorators: [{
|
|
1174
|
+
type: Directive,
|
|
1175
|
+
args: [{
|
|
1176
|
+
selector: '[NgxDraggable],[ngxDraggable]',
|
|
1177
|
+
providers: [{ provide: NGX_DRAGGABLE, useExisting: NgxDraggable }],
|
|
1178
|
+
host: {
|
|
1179
|
+
'[style.touch-action]': '"none"',
|
|
1180
|
+
'[attr.tabindex]': 'disabled ? null : 0',
|
|
1181
|
+
'[attr.aria-grabbed]': 'dragging()',
|
|
1182
|
+
class: 'ngx-draggable',
|
|
1183
|
+
},
|
|
1184
|
+
}]
|
|
1185
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { disabled: [{
|
|
1186
|
+
type: Input
|
|
1187
|
+
}], boundary: [{
|
|
1188
|
+
type: Input
|
|
1189
|
+
}], dragRootElement: [{
|
|
1190
|
+
type: Input
|
|
1191
|
+
}], dragHandle: [{
|
|
1192
|
+
type: Input
|
|
1193
|
+
}], lockAxis: [{
|
|
1194
|
+
type: Input
|
|
1195
|
+
}], dragThreshold: [{
|
|
1196
|
+
type: Input
|
|
1197
|
+
}], keyboardStep: [{
|
|
1198
|
+
type: Input
|
|
1199
|
+
}], autoScroll: [{
|
|
1200
|
+
type: Input
|
|
1201
|
+
}], data: [{
|
|
1202
|
+
type: Input,
|
|
1203
|
+
args: ['data']
|
|
1204
|
+
}], dragStart: [{
|
|
1205
|
+
type: Output
|
|
1206
|
+
}], dragMove: [{
|
|
1207
|
+
type: Output
|
|
1208
|
+
}], dragEnd: [{
|
|
1209
|
+
type: Output
|
|
1210
|
+
}] } });
|
|
1211
|
+
|
|
1212
|
+
const ALL_DIRECTIONS = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];
|
|
1213
|
+
const KEYBOARD_STEP = 8;
|
|
1214
|
+
class NgxResizable {
|
|
1215
|
+
el;
|
|
1216
|
+
disabled = false;
|
|
1217
|
+
minWidth = 20;
|
|
1218
|
+
minHeight = 20;
|
|
1219
|
+
maxWidth = Infinity;
|
|
1220
|
+
maxHeight = Infinity;
|
|
1221
|
+
directions = [...ALL_DIRECTIONS];
|
|
1222
|
+
grid;
|
|
1223
|
+
/** Element whose rect constrains the resize. Previously accepted nowhere on this directive. */
|
|
1224
|
+
boundary;
|
|
1225
|
+
/** Pixel step used when resizing via the keyboard (arrow keys, focus required). */
|
|
1226
|
+
keyboardStep = KEYBOARD_STEP;
|
|
1227
|
+
resizeStart = new EventEmitter();
|
|
1228
|
+
resizeMove = new EventEmitter();
|
|
1229
|
+
resizeEnd = new EventEmitter();
|
|
1230
|
+
resizing = signal(false, /* @ts-ignore */
|
|
1231
|
+
...(ngDevMode ? [{ debugName: "resizing" }] : /* istanbul ignore next */ []));
|
|
1232
|
+
direction = 'se';
|
|
1233
|
+
start;
|
|
1234
|
+
pointer = {
|
|
1235
|
+
x: 0,
|
|
1236
|
+
y: 0,
|
|
1237
|
+
};
|
|
1238
|
+
beforeTransition = '';
|
|
1239
|
+
beforeWidth = '';
|
|
1240
|
+
beforeHeight = '';
|
|
1241
|
+
beforeTransform = '';
|
|
1242
|
+
pointerId = -1;
|
|
1243
|
+
constructor(el) {
|
|
1244
|
+
this.el = el;
|
|
1245
|
+
}
|
|
1246
|
+
onPointerDown(e) {
|
|
1247
|
+
if (this.disabled || e.button !== 0) {
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const dir = this.hitDirection(e);
|
|
1251
|
+
if (!dir) {
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
e.preventDefault();
|
|
1255
|
+
e.stopPropagation();
|
|
1256
|
+
e.stopImmediatePropagation();
|
|
1257
|
+
const element = this.el.nativeElement;
|
|
1258
|
+
this.direction = dir;
|
|
1259
|
+
this.pointerId = e.pointerId;
|
|
1260
|
+
/**
|
|
1261
|
+
* This is the actual visual rectangle.
|
|
1262
|
+
* It already contains any transform created by DragRef.
|
|
1263
|
+
*/
|
|
1264
|
+
this.start = element.getBoundingClientRect();
|
|
1265
|
+
this.pointer = {
|
|
1266
|
+
x: e.clientX,
|
|
1267
|
+
y: e.clientY,
|
|
1268
|
+
};
|
|
1269
|
+
this.beforeTransition = element.style.transition;
|
|
1270
|
+
/**
|
|
1271
|
+
* Keep DragRef's transform as the immutable base.
|
|
1272
|
+
*
|
|
1273
|
+
* Resize will temporarily add its own translation
|
|
1274
|
+
* on top of this transform.
|
|
1275
|
+
*/
|
|
1276
|
+
this.beforeTransform = element.style.transform;
|
|
1277
|
+
this.resizing.set(true);
|
|
1278
|
+
element.style.transition = 'none';
|
|
1279
|
+
element.setPointerCapture?.(e.pointerId);
|
|
1280
|
+
const out = this.calculate(e);
|
|
1281
|
+
this.apply(out);
|
|
1282
|
+
this.resizeStart.emit(out);
|
|
1283
|
+
}
|
|
1284
|
+
onPointerMove(e) {
|
|
1285
|
+
if (!this.resizing() || e.pointerId !== this.pointerId) {
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
const out = this.calculate(e);
|
|
1289
|
+
this.apply(out);
|
|
1290
|
+
this.resizeMove.emit(out);
|
|
1291
|
+
}
|
|
1292
|
+
onPointerUp(e) {
|
|
1293
|
+
if (!this.resizing() || e.pointerId !== this.pointerId) {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
const out = this.calculate(e);
|
|
1297
|
+
this.apply(out);
|
|
1298
|
+
this.resizeEnd.emit(out);
|
|
1299
|
+
this.finish();
|
|
1300
|
+
}
|
|
1301
|
+
onDocumentKeyDown(e) {
|
|
1302
|
+
if (!this.resizing()) {
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
if (e.key !== 'Escape') {
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
e.preventDefault();
|
|
1309
|
+
const element = this.el.nativeElement;
|
|
1310
|
+
element.style.width = this.beforeWidth;
|
|
1311
|
+
element.style.height = this.beforeHeight;
|
|
1312
|
+
element.style.transform = this.beforeTransform;
|
|
1313
|
+
this.finish();
|
|
1314
|
+
}
|
|
1315
|
+
onHandleKeyDown(e) {
|
|
1316
|
+
if (this.disabled) {
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
const rtl = isRtl(this.el.nativeElement);
|
|
1320
|
+
const step = this.keyboardStep * (e.shiftKey ? 4 : 1);
|
|
1321
|
+
let dw = 0;
|
|
1322
|
+
let dh = 0;
|
|
1323
|
+
if (e.key === 'ArrowRight') {
|
|
1324
|
+
dw = rtl ? -step : step;
|
|
1325
|
+
}
|
|
1326
|
+
else if (e.key === 'ArrowLeft') {
|
|
1327
|
+
dw = rtl ? step : -step;
|
|
1328
|
+
}
|
|
1329
|
+
else if (e.key === 'ArrowDown') {
|
|
1330
|
+
dh = step;
|
|
1331
|
+
}
|
|
1332
|
+
else if (e.key === 'ArrowUp') {
|
|
1333
|
+
dh = -step;
|
|
1334
|
+
}
|
|
1335
|
+
else {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
e.preventDefault();
|
|
1339
|
+
const rect = this.el.nativeElement.getBoundingClientRect();
|
|
1340
|
+
const width = this.clampGrid(Math.max(this.minWidth, Math.min(this.maxWidth, rect.width + dw)), 'x');
|
|
1341
|
+
const height = this.clampGrid(Math.max(this.minHeight, Math.min(this.maxHeight, rect.height + dh)), 'y');
|
|
1342
|
+
this.el.nativeElement.style.width = `${width}px`;
|
|
1343
|
+
this.el.nativeElement.style.height = `${height}px`;
|
|
1344
|
+
const out = {
|
|
1345
|
+
width,
|
|
1346
|
+
height,
|
|
1347
|
+
moveLeft: 0,
|
|
1348
|
+
moveTop: 0,
|
|
1349
|
+
left: rect.left,
|
|
1350
|
+
top: rect.top,
|
|
1351
|
+
direction: 'se',
|
|
1352
|
+
};
|
|
1353
|
+
this.resizeMove.emit(out);
|
|
1354
|
+
this.resizeEnd.emit(out);
|
|
1355
|
+
}
|
|
1356
|
+
calculate(e) {
|
|
1357
|
+
const dx = e.clientX - this.pointer.x;
|
|
1358
|
+
const dy = e.clientY - this.pointer.y;
|
|
1359
|
+
let width = this.start.width;
|
|
1360
|
+
let height = this.start.height;
|
|
1361
|
+
/**
|
|
1362
|
+
* East
|
|
1363
|
+
*/
|
|
1364
|
+
if (this.direction.includes('e')) {
|
|
1365
|
+
width += dx;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* West
|
|
1369
|
+
*/
|
|
1370
|
+
if (this.direction.includes('w')) {
|
|
1371
|
+
width -= dx;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* South
|
|
1375
|
+
*/
|
|
1376
|
+
if (this.direction.includes('s')) {
|
|
1377
|
+
height += dy;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* North
|
|
1381
|
+
*/
|
|
1382
|
+
if (this.direction.includes('n')) {
|
|
1383
|
+
height -= dy;
|
|
1384
|
+
}
|
|
1385
|
+
width = this.clampGrid(Math.max(this.minWidth, Math.min(this.maxWidth, width)), 'x');
|
|
1386
|
+
height = this.clampGrid(Math.max(this.minHeight, Math.min(this.maxHeight, height)), 'y');
|
|
1387
|
+
/**
|
|
1388
|
+
* Calculate the intended visual position.
|
|
1389
|
+
*
|
|
1390
|
+
* This is useful for boundary calculations and
|
|
1391
|
+
* emitted resize events.
|
|
1392
|
+
*/
|
|
1393
|
+
let left = this.start.left;
|
|
1394
|
+
let top = this.start.top;
|
|
1395
|
+
if (this.direction.includes('w')) {
|
|
1396
|
+
left = this.start.right - width;
|
|
1397
|
+
}
|
|
1398
|
+
if (this.direction.includes('n')) {
|
|
1399
|
+
top = this.start.bottom - height;
|
|
1400
|
+
}
|
|
1401
|
+
let moveLeft = left - this.start.left;
|
|
1402
|
+
let moveTop = top - this.start.top;
|
|
1403
|
+
/**
|
|
1404
|
+
* Boundary constraint.
|
|
1405
|
+
*/
|
|
1406
|
+
if (this.boundary) {
|
|
1407
|
+
const clamped = clampResizeWithinBoundary(this.boundary.getBoundingClientRect(), this.start, width, height, moveLeft, moveTop);
|
|
1408
|
+
width = clamped.width;
|
|
1409
|
+
height = clamped.height;
|
|
1410
|
+
moveLeft = clamped.left;
|
|
1411
|
+
moveTop = clamped.top;
|
|
1412
|
+
left = this.start.left + moveLeft;
|
|
1413
|
+
top = this.start.top + moveTop;
|
|
1414
|
+
}
|
|
1415
|
+
return {
|
|
1416
|
+
width,
|
|
1417
|
+
height,
|
|
1418
|
+
moveLeft,
|
|
1419
|
+
moveTop,
|
|
1420
|
+
left,
|
|
1421
|
+
top,
|
|
1422
|
+
direction: this.direction,
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
apply(out) {
|
|
1426
|
+
const element = this.el.nativeElement;
|
|
1427
|
+
/**
|
|
1428
|
+
* Always reset to the transform that existed before
|
|
1429
|
+
* this resize operation started.
|
|
1430
|
+
*
|
|
1431
|
+
* This prevents resize corrections from accumulating.
|
|
1432
|
+
*/
|
|
1433
|
+
element.style.transform = this.beforeTransform;
|
|
1434
|
+
/**
|
|
1435
|
+
* Apply the actual size first.
|
|
1436
|
+
*
|
|
1437
|
+
* Changing width/height may cause the browser to re-layout
|
|
1438
|
+
* the element, especially for relative/flex/grid/static layouts.
|
|
1439
|
+
*/
|
|
1440
|
+
element.style.width = `${out.width}px`;
|
|
1441
|
+
element.style.height = `${out.height}px`;
|
|
1442
|
+
/**
|
|
1443
|
+
* Force/read layout after changing the size.
|
|
1444
|
+
*/
|
|
1445
|
+
const current = element.getBoundingClientRect();
|
|
1446
|
+
/**
|
|
1447
|
+
* These are the positions where the element MUST visually be.
|
|
1448
|
+
*
|
|
1449
|
+
* `out.moveLeft` / `out.moveTop` are calculated in `calculate()`
|
|
1450
|
+
* from the original visual rectangle.
|
|
1451
|
+
*/
|
|
1452
|
+
const targetLeft = this.start.left + out.moveLeft;
|
|
1453
|
+
const targetTop = this.start.top + out.moveTop;
|
|
1454
|
+
/**
|
|
1455
|
+
* Browser's actual position after width/height changed.
|
|
1456
|
+
*
|
|
1457
|
+
* The difference between target and current position is the
|
|
1458
|
+
* correction that must be applied using transform.
|
|
1459
|
+
*/
|
|
1460
|
+
const correctionX = targetLeft - current.left;
|
|
1461
|
+
const correctionY = targetTop - current.top;
|
|
1462
|
+
const hasCorrection = correctionX !== 0 || correctionY !== 0;
|
|
1463
|
+
if (!hasCorrection) {
|
|
1464
|
+
element.style.transform = this.beforeTransform;
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Preserve DragRef's existing transform and add only the
|
|
1469
|
+
* correction required by Resize.
|
|
1470
|
+
*/
|
|
1471
|
+
const baseTransform = this.beforeTransform && this.beforeTransform !== 'none' ? `${this.beforeTransform} ` : '';
|
|
1472
|
+
element.style.transform =
|
|
1473
|
+
`${baseTransform}translate3d(` + `${correctionX}px, ` + `${correctionY}px, 0)`;
|
|
1474
|
+
}
|
|
1475
|
+
clampGrid(value, axis) {
|
|
1476
|
+
const grid = typeof this.grid === 'number' ? this.grid : this.grid?.[axis];
|
|
1477
|
+
if (!grid || grid <= 0) {
|
|
1478
|
+
return value;
|
|
1479
|
+
}
|
|
1480
|
+
return Math.round(value / grid) * grid;
|
|
1481
|
+
}
|
|
1482
|
+
finish() {
|
|
1483
|
+
this.resizing.set(false);
|
|
1484
|
+
this.el.nativeElement.style.transition = this.beforeTransition;
|
|
1485
|
+
this.pointerId = -1;
|
|
1486
|
+
this.beforeTransform = '';
|
|
1487
|
+
}
|
|
1488
|
+
resolvedDirections() {
|
|
1489
|
+
const rtl = isRtl(this.el.nativeElement);
|
|
1490
|
+
const set = new Set();
|
|
1491
|
+
for (const direction of this.directions) {
|
|
1492
|
+
set.add(resolveLogicalDirection(direction, rtl));
|
|
1493
|
+
}
|
|
1494
|
+
return [...set];
|
|
1495
|
+
}
|
|
1496
|
+
hitDirection(e) {
|
|
1497
|
+
const element = this.el.nativeElement;
|
|
1498
|
+
const rect = element.getBoundingClientRect();
|
|
1499
|
+
const edge = Math.min(12, Math.max(6, Math.min(rect.width, rect.height) * 0.18));
|
|
1500
|
+
const isLeft = e.clientX - rect.left <= edge;
|
|
1501
|
+
const isRight = rect.right - e.clientX <= edge;
|
|
1502
|
+
const isTop = e.clientY - rect.top <= edge;
|
|
1503
|
+
const isBottom = rect.bottom - e.clientY <= edge;
|
|
1504
|
+
/**
|
|
1505
|
+
* Explicit resize handle has priority.
|
|
1506
|
+
*/
|
|
1507
|
+
const handle = e.target instanceof HTMLElement
|
|
1508
|
+
? e.target.closest('[data-ngx-resize-handle]')
|
|
1509
|
+
: null;
|
|
1510
|
+
if (handle && element.contains(handle)) {
|
|
1511
|
+
const raw = handle.dataset['ngxResizeHandle'];
|
|
1512
|
+
if (!raw) {
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
const resolved = resolveLogicalDirection(raw, isRtl(element));
|
|
1516
|
+
return this.resolvedDirections().includes(resolved) ? resolved : null;
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* These are PHYSICAL screen directions.
|
|
1520
|
+
*
|
|
1521
|
+
* left -> w
|
|
1522
|
+
* right -> e
|
|
1523
|
+
*
|
|
1524
|
+
* RTL is handled only when a logical direction
|
|
1525
|
+
* such as "start" / "end" is requested.
|
|
1526
|
+
*/
|
|
1527
|
+
const direction = isTop && isLeft
|
|
1528
|
+
? 'nw'
|
|
1529
|
+
: isTop && isRight
|
|
1530
|
+
? 'ne'
|
|
1531
|
+
: isBottom && isLeft
|
|
1532
|
+
? 'sw'
|
|
1533
|
+
: isBottom && isRight
|
|
1534
|
+
? 'se'
|
|
1535
|
+
: isTop
|
|
1536
|
+
? 'n'
|
|
1537
|
+
: isRight
|
|
1538
|
+
? 'e'
|
|
1539
|
+
: isBottom
|
|
1540
|
+
? 's'
|
|
1541
|
+
: isLeft
|
|
1542
|
+
? 'w'
|
|
1543
|
+
: null;
|
|
1544
|
+
if (!direction) {
|
|
1545
|
+
return null;
|
|
1546
|
+
}
|
|
1547
|
+
return this.resolvedDirections().includes(direction) ? direction : null;
|
|
1548
|
+
}
|
|
1549
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1550
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxResizable, isStandalone: true, selector: "[NgxResizable],[ngxResizable]", inputs: { disabled: "disabled", minWidth: "minWidth", minHeight: "minHeight", maxWidth: "maxWidth", maxHeight: "maxHeight", directions: "directions", grid: "grid", boundary: "boundary", keyboardStep: "keyboardStep" }, outputs: { resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "document:pointermove": "onPointerMove($event)", "document:pointerup": "onPointerUp($event)", "document:keydown": "onDocumentKeyDown($event)", "keydown": "onHandleKeyDown($event)" }, properties: { "style.touch-action": "\"none\"" }, classAttribute: "ngx-resizable" }, ngImport: i0 });
|
|
1551
|
+
}
|
|
1552
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, decorators: [{
|
|
1553
|
+
type: Directive,
|
|
1554
|
+
args: [{
|
|
1555
|
+
selector: '[NgxResizable],[ngxResizable]',
|
|
1556
|
+
host: {
|
|
1557
|
+
'[style.touch-action]': '"none"',
|
|
1558
|
+
class: 'ngx-resizable',
|
|
1559
|
+
},
|
|
1560
|
+
}]
|
|
1561
|
+
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { disabled: [{
|
|
1562
|
+
type: Input
|
|
1563
|
+
}], minWidth: [{
|
|
1564
|
+
type: Input
|
|
1565
|
+
}], minHeight: [{
|
|
1566
|
+
type: Input
|
|
1567
|
+
}], maxWidth: [{
|
|
1568
|
+
type: Input
|
|
1569
|
+
}], maxHeight: [{
|
|
1570
|
+
type: Input
|
|
1571
|
+
}], directions: [{
|
|
1572
|
+
type: Input
|
|
1573
|
+
}], grid: [{
|
|
1574
|
+
type: Input
|
|
1575
|
+
}], boundary: [{
|
|
1576
|
+
type: Input
|
|
1577
|
+
}], keyboardStep: [{
|
|
1578
|
+
type: Input
|
|
1579
|
+
}], resizeStart: [{
|
|
1580
|
+
type: Output
|
|
1581
|
+
}], resizeMove: [{
|
|
1582
|
+
type: Output
|
|
1583
|
+
}], resizeEnd: [{
|
|
1584
|
+
type: Output
|
|
1585
|
+
}], onPointerDown: [{
|
|
1586
|
+
type: HostListener,
|
|
1587
|
+
args: ['pointerdown', ['$event']]
|
|
1588
|
+
}], onPointerMove: [{
|
|
1589
|
+
type: HostListener,
|
|
1590
|
+
args: ['document:pointermove', ['$event']]
|
|
1591
|
+
}], onPointerUp: [{
|
|
1592
|
+
type: HostListener,
|
|
1593
|
+
args: ['document:pointerup', ['$event']]
|
|
1594
|
+
}], onDocumentKeyDown: [{
|
|
1595
|
+
type: HostListener,
|
|
1596
|
+
args: ['document:keydown', ['$event']]
|
|
1597
|
+
}], onHandleKeyDown: [{
|
|
1598
|
+
type: HostListener,
|
|
1599
|
+
args: ['keydown', ['$event']]
|
|
1600
|
+
}] } });
|
|
1601
|
+
|
|
1602
|
+
const NGX_PLACEHOLDER = new InjectionToken('ngx-place-holder');
|
|
1603
|
+
class NgxPlaceholder {
|
|
1604
|
+
tpl;
|
|
1605
|
+
_ref = new PlaceHolderRef();
|
|
1606
|
+
list = inject(NGX_DROPLIST, { optional: true, skipSelf: true });
|
|
1607
|
+
constructor(tpl) {
|
|
1608
|
+
this.tpl = tpl;
|
|
1609
|
+
this._ref.tpl = tpl;
|
|
1610
|
+
this._ref.dropList = this.list?._ref;
|
|
1611
|
+
}
|
|
1612
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxPlaceholder, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1613
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxPlaceholder, isStandalone: true, selector: "[NgxPlaceholder],[ngxPlaceholder]", providers: [{ provide: NGX_PLACEHOLDER, useExisting: NgxPlaceholder }], ngImport: i0 });
|
|
1614
|
+
}
|
|
1615
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxPlaceholder, decorators: [{
|
|
1616
|
+
type: Directive,
|
|
1617
|
+
args: [{
|
|
1618
|
+
selector: '[NgxPlaceholder],[ngxPlaceholder]',
|
|
1619
|
+
providers: [{ provide: NGX_PLACEHOLDER, useExisting: NgxPlaceholder }],
|
|
1620
|
+
}]
|
|
1621
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }] });
|
|
1622
|
+
|
|
1623
|
+
function moveItemInArray(array, from, to) {
|
|
1624
|
+
const f = clamp(from, array.length - 1);
|
|
1625
|
+
const t = clamp(to, array.length - 1);
|
|
1626
|
+
if (f === t)
|
|
1627
|
+
return;
|
|
1628
|
+
const target = array[f];
|
|
1629
|
+
const delta = t < f ? -1 : 1;
|
|
1630
|
+
for (let i = f; i !== t; i += delta)
|
|
1631
|
+
array[i] = array[i + delta];
|
|
1632
|
+
array[t] = target;
|
|
1633
|
+
}
|
|
1634
|
+
function transferArrayItem(src, dst, from, to) {
|
|
1635
|
+
const f = clamp(from, src.length - 1);
|
|
1636
|
+
const t = clamp(to, dst.length);
|
|
1637
|
+
if (src.length)
|
|
1638
|
+
dst.splice(t, 0, src.splice(f, 1)[0]);
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Copies an item from one array to another, leaving it in its
|
|
1642
|
+
* original position in current array.
|
|
1643
|
+
* @param currentArray Array from which to copy the item.
|
|
1644
|
+
* @param targetArray Array into which is copy the item.
|
|
1645
|
+
* @param currentIndex Index of the item in its current array.
|
|
1646
|
+
* @param targetIndex Index at which to insert the item.
|
|
1647
|
+
*
|
|
1648
|
+
*/
|
|
1649
|
+
function copyArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
|
|
1650
|
+
const to = clamp(targetIndex, targetArray.length);
|
|
1651
|
+
if (currentArray.length) {
|
|
1652
|
+
targetArray.splice(to, 0, currentArray[currentIndex]);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
function clamp(v, max) {
|
|
1656
|
+
return Math.max(0, Math.min(max, v));
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
/**
|
|
1660
|
+
* Generated bundle index. Do not edit.
|
|
1661
|
+
*/
|
|
1662
|
+
|
|
1663
|
+
export { AutoScroller, DragDropService, DragRef, DropListGroupRef, DropListRef, NGX_DRAGGABLE, NGX_DROPLIST, NGX_DROPLIST_GROUP, NGX_PLACEHOLDER, NgxDraggable, NgxDropList, NgxDropListGroup, NgxPlaceholder, NgxResizable, PlaceHolderRef, adjustForZoom, checkBoundX, checkBoundY, clampResizeWithinBoundary, copyArrayItem, getPageZoom, isRtl, moveItemInArray, resolveLogicalDirection, transferArrayItem };
|
|
1664
|
+
//# sourceMappingURL=ngx-kit-drag-resize.mjs.map
|