ngx-kit 6.3.0 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/angle-selector/README.md +34 -34
  3. package/box-shadow/README.md +33 -33
  4. package/color-picker/README.md +52 -49
  5. package/data-table/README.md +120 -113
  6. package/date-picker/README.md +74 -69
  7. package/dialog/README.md +92 -92
  8. package/drag-resize/README.md +55 -0
  9. package/dropzone/README.md +422 -422
  10. package/fesm2022/ngx-kit-angle-selector.mjs +2 -2
  11. package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -1
  12. package/fesm2022/ngx-kit-box-shadow.mjs +2 -2
  13. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-color-picker.mjs +265 -73
  15. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-data-table.mjs +2 -2
  17. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-date-picker.mjs +7 -9
  19. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-dialog.mjs +3 -3
  21. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  22. package/fesm2022/ngx-kit-drag-resize.mjs +1664 -0
  23. package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -0
  24. package/fesm2022/ngx-kit-drawer-menu.mjs +389 -285
  25. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
  26. package/fesm2022/ngx-kit-dropzone.mjs +2 -2
  27. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  28. package/fesm2022/ngx-kit-form-field.mjs +3 -5
  29. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  30. package/fesm2022/ngx-kit-gallery.mjs +2 -2
  31. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  32. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  33. package/fesm2022/ngx-kit-grid-layout.mjs +994 -0
  34. package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -0
  35. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
  36. package/fesm2022/ngx-kit-menu.mjs +8 -8
  37. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  38. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  39. package/fesm2022/ngx-kit-notify.mjs +2 -2
  40. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  41. package/fesm2022/ngx-kit-shared.mjs +54 -3
  42. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  43. package/fesm2022/ngx-kit-time-picker.mjs +2 -2
  44. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
  45. package/fesm2022/ngx-kit-virtual-scroll.mjs +392 -0
  46. package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -0
  47. package/fesm2022/ngx-kit-webflow.mjs +709 -0
  48. package/fesm2022/ngx-kit-webflow.mjs.map +1 -0
  49. package/gallery/README.md +71 -71
  50. package/gradient-picker/README.md +41 -41
  51. package/grid-layout/README.md +64 -0
  52. package/image-editor/README.md +12 -12
  53. package/menu/README.md +85 -85
  54. package/message/README.md +70 -70
  55. package/notify/README.md +56 -58
  56. package/package.json +17 -1
  57. package/shared/README.md +117 -117
  58. package/time-picker/README.md +89 -95
  59. package/types/ngx-kit-color-picker.d.ts +72 -16
  60. package/types/ngx-kit-drag-resize.d.ts +368 -0
  61. package/types/ngx-kit-drawer-menu.d.ts +135 -86
  62. package/types/ngx-kit-grid-layout.d.ts +311 -0
  63. package/types/ngx-kit-image-editor.d.ts +1 -1
  64. package/types/ngx-kit-shared.d.ts +12 -1
  65. package/types/ngx-kit-virtual-scroll.d.ts +179 -0
  66. package/types/ngx-kit-webflow.d.ts +286 -0
  67. 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