ngx-kit 9.2.1 → 9.2.3
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.
|
@@ -593,6 +593,92 @@ class DragRef {
|
|
|
593
593
|
this.applyTransform();
|
|
594
594
|
}
|
|
595
595
|
}
|
|
596
|
+
/**
|
|
597
|
+
* Keyboard sorting for list items: jump by whole SLOTS instead of pixels (an 8px step can
|
|
598
|
+
* never cross the centre of a 190px card), and hop to the neighbouring connected list when the
|
|
599
|
+
* edge of the current one is reached — Left/Right between kanban columns, Up/Down between
|
|
600
|
+
* the sections of a column. Returns `false` for free drags (use `nudge`).
|
|
601
|
+
*/
|
|
602
|
+
nudgeToSlot(direction) {
|
|
603
|
+
if (!this.listDrag)
|
|
604
|
+
return false;
|
|
605
|
+
if (!this.isDragging())
|
|
606
|
+
this.startDrag(this.lastPointer);
|
|
607
|
+
const list = this.activeDropList;
|
|
608
|
+
if (!list?.el)
|
|
609
|
+
return true;
|
|
610
|
+
const vertical = direction === 'up' || direction === 'down';
|
|
611
|
+
const sign = direction === 'down' || direction === 'right' ? 1 : -1;
|
|
612
|
+
const cur = { x: this.startPointer.x + this.moveDx, y: this.startPointer.y + this.moveDy };
|
|
613
|
+
const listAxis = list.getAxis();
|
|
614
|
+
// A grid has no single main axis: step through its slots along the pressed key's axis.
|
|
615
|
+
const axis = listAxis === 'grid' ? (vertical ? 'y' : 'x') : listAxis;
|
|
616
|
+
let target = null;
|
|
617
|
+
if ((axis === 'y') === vertical)
|
|
618
|
+
target = this.neighbourSlot(list, axis, sign, cur);
|
|
619
|
+
target ??= this.neighbourList(list, vertical ? 'y' : 'x', sign, cur);
|
|
620
|
+
if (target)
|
|
621
|
+
this.dragMove(target);
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
neighbourSlot(list, axis, sign, cur) {
|
|
625
|
+
const mid = (r) => (axis === 'y' ? r.top + r.height / 2 : r.left + r.width / 2);
|
|
626
|
+
const slots = Array.from(list.el.children)
|
|
627
|
+
.filter((n) => n instanceof HTMLElement &&
|
|
628
|
+
n !== this.el &&
|
|
629
|
+
!n.classList.contains('ngx-drag-preview') &&
|
|
630
|
+
n.getClientRects().length > 0)
|
|
631
|
+
.map((el) => ({ el, r: el.getBoundingClientRect() }))
|
|
632
|
+
.sort((a, b) => mid(a.r) - mid(b.r));
|
|
633
|
+
const p = slots.findIndex((s) => s.el.classList.contains('ngx-drag-placeholder'));
|
|
634
|
+
const next = slots[p + sign];
|
|
635
|
+
if (p < 0 || !next)
|
|
636
|
+
return null;
|
|
637
|
+
// a little PAST the neighbour's centre, beyond the sort hysteresis
|
|
638
|
+
const past = mid(next.r) + 8 * sign;
|
|
639
|
+
return axis === 'y' ? { x: cur.x, y: past } : { x: past, y: cur.y };
|
|
640
|
+
}
|
|
641
|
+
neighbourList(from, along, sign, cur) {
|
|
642
|
+
const doc = this.el.ownerDocument;
|
|
643
|
+
const origin = visibleRect(from.el);
|
|
644
|
+
if (!origin)
|
|
645
|
+
return null;
|
|
646
|
+
let best = null;
|
|
647
|
+
for (const l of this.cachedLists) {
|
|
648
|
+
if (l === from || !l.el || l.el.ownerDocument !== doc)
|
|
649
|
+
continue;
|
|
650
|
+
const r = visibleRect(l.el);
|
|
651
|
+
if (!r || r.width < 8 || r.height < 8)
|
|
652
|
+
continue;
|
|
653
|
+
const dist = along === 'x'
|
|
654
|
+
? (r.left + r.width / 2 - (origin.left + origin.width / 2)) * sign
|
|
655
|
+
: (r.top + r.height / 2 - (origin.top + origin.height / 2)) * sign;
|
|
656
|
+
if (dist <= 4)
|
|
657
|
+
continue;
|
|
658
|
+
let score;
|
|
659
|
+
if (along === 'x') {
|
|
660
|
+
// prefer the list that is level with the pointer
|
|
661
|
+
const off = Math.max(r.top - cur.y, 0, cur.y - r.bottom);
|
|
662
|
+
score = dist + off * 0.5;
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
// Up/Down only moves between lists that overlap horizontally (sections of one column)
|
|
666
|
+
const overlap = Math.min(r.right, origin.right) - Math.max(r.left, origin.left);
|
|
667
|
+
if (overlap < Math.min(r.width, origin.width) * 0.5)
|
|
668
|
+
continue;
|
|
669
|
+
score = dist;
|
|
670
|
+
}
|
|
671
|
+
if (!best || score < best.score)
|
|
672
|
+
best = { rect: r, score };
|
|
673
|
+
}
|
|
674
|
+
if (!best)
|
|
675
|
+
return null;
|
|
676
|
+
const r = best.rect;
|
|
677
|
+
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
678
|
+
return along === 'y'
|
|
679
|
+
? { x: clamp(cur.x, r.left + 8, r.right - 8), y: sign > 0 ? r.top + 8 : r.bottom - 8 }
|
|
680
|
+
: { x: r.left + r.width / 2, y: clamp(cur.y, r.top + 8, r.bottom - 8) };
|
|
681
|
+
}
|
|
596
682
|
nudge(dx, dy) {
|
|
597
683
|
if (!this.isDragging())
|
|
598
684
|
this.startDrag(this.lastPointer);
|
|
@@ -922,6 +1008,34 @@ function isDescendantOfList(list, ancestor) {
|
|
|
922
1008
|
}
|
|
923
1009
|
return false;
|
|
924
1010
|
}
|
|
1011
|
+
/** The part of `el` that is actually on screen (clipped by scroll containers and the viewport). */
|
|
1012
|
+
function visibleRect(el) {
|
|
1013
|
+
const win = el.ownerDocument.defaultView;
|
|
1014
|
+
if (!win)
|
|
1015
|
+
return null;
|
|
1016
|
+
const r = el.getBoundingClientRect();
|
|
1017
|
+
let left = r.left;
|
|
1018
|
+
let top = r.top;
|
|
1019
|
+
let right = r.right;
|
|
1020
|
+
let bottom = r.bottom;
|
|
1021
|
+
for (let n = el.parentElement; n; n = n.parentElement) {
|
|
1022
|
+
const cs = win.getComputedStyle(n);
|
|
1023
|
+
if (cs.overflowX === 'visible' && cs.overflowY === 'visible')
|
|
1024
|
+
continue;
|
|
1025
|
+
const nr = n.getBoundingClientRect();
|
|
1026
|
+
left = Math.max(left, nr.left);
|
|
1027
|
+
top = Math.max(top, nr.top);
|
|
1028
|
+
right = Math.min(right, nr.right);
|
|
1029
|
+
bottom = Math.min(bottom, nr.bottom);
|
|
1030
|
+
}
|
|
1031
|
+
left = Math.max(left, 0);
|
|
1032
|
+
top = Math.max(top, 0);
|
|
1033
|
+
right = Math.min(right, win.innerWidth);
|
|
1034
|
+
bottom = Math.min(bottom, win.innerHeight);
|
|
1035
|
+
if (right <= left || bottom <= top)
|
|
1036
|
+
return null;
|
|
1037
|
+
return { left, top, right, bottom, width: right - left, height: bottom - top };
|
|
1038
|
+
}
|
|
925
1039
|
|
|
926
1040
|
class ElementHelper {
|
|
927
1041
|
static collectionHas(a, b) {
|
|
@@ -1713,6 +1827,10 @@ class DropListRef {
|
|
|
1713
1827
|
parentList = null;
|
|
1714
1828
|
childLists = new Set();
|
|
1715
1829
|
session = null;
|
|
1830
|
+
/** Main axis of this list: the measured one while sorting, else a CSS-based guess. */
|
|
1831
|
+
getAxis() {
|
|
1832
|
+
return this.session?.axis ?? fallbackAxis(this.el);
|
|
1833
|
+
}
|
|
1716
1834
|
placeholder;
|
|
1717
1835
|
customPlaceholder;
|
|
1718
1836
|
activeDrag = null;
|
|
@@ -2436,7 +2554,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
|
|
|
2436
2554
|
*/
|
|
2437
2555
|
class AutoScroller {
|
|
2438
2556
|
raf = 0;
|
|
2439
|
-
|
|
2557
|
+
/** Nearest scroller per axis: a kanban column scrolls vertically while its BOARD scrolls horizontally. */
|
|
2558
|
+
containerX;
|
|
2559
|
+
containerY;
|
|
2440
2560
|
win;
|
|
2441
2561
|
/** Document the pointer coordinates (`update(x, y)`) are expressed in. */
|
|
2442
2562
|
pointerDoc;
|
|
@@ -2453,36 +2573,40 @@ class AutoScroller {
|
|
|
2453
2573
|
start(fromEl, onTick) {
|
|
2454
2574
|
this.win = fromEl.ownerDocument.defaultView ?? undefined;
|
|
2455
2575
|
this.pointerDoc = fromEl.ownerDocument;
|
|
2456
|
-
this.
|
|
2576
|
+
this.retarget(fromEl);
|
|
2457
2577
|
this.onTick = onTick;
|
|
2458
2578
|
}
|
|
2459
2579
|
/** فقط container را عوض میکند بدون قطع حلقهی در حال اجرا یا صفر کردن speed. */
|
|
2460
2580
|
retarget(fromEl) {
|
|
2461
|
-
this.
|
|
2581
|
+
this.containerX = findScrollableAncestorForAxis(fromEl, 'x');
|
|
2582
|
+
this.containerY = findScrollableAncestorForAxis(fromEl, 'y');
|
|
2462
2583
|
}
|
|
2463
2584
|
update(clientX, clientY) {
|
|
2585
|
+
this.speed = {
|
|
2586
|
+
x: this.axisSpeed(this.containerX, 'x', clientX, clientY),
|
|
2587
|
+
y: this.axisSpeed(this.containerY, 'y', clientX, clientY),
|
|
2588
|
+
};
|
|
2589
|
+
if ((this.speed.x || this.speed.y) && !this.raf) {
|
|
2590
|
+
this.raf = this.win?.requestAnimationFrame(this.tick) ?? 0;
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
axisSpeed(container, axis, clientX, clientY) {
|
|
2464
2594
|
// The scroll container may live in another document (a page-builder iframe). Its rect is in
|
|
2465
2595
|
// THAT document's viewport pixels, so bring the pointer into the same space first.
|
|
2466
2596
|
let x = clientX;
|
|
2467
2597
|
let y = clientY;
|
|
2468
|
-
const containerDoc = documentOf(
|
|
2598
|
+
const containerDoc = documentOf(container);
|
|
2469
2599
|
if (this.pointerDoc && containerDoc && containerDoc !== this.pointerDoc) {
|
|
2470
2600
|
const p = convertPointBetweenDocuments({ x, y }, this.pointerDoc, containerDoc);
|
|
2471
|
-
if (!p)
|
|
2472
|
-
|
|
2473
|
-
return;
|
|
2474
|
-
}
|
|
2601
|
+
if (!p)
|
|
2602
|
+
return 0;
|
|
2475
2603
|
x = p.x;
|
|
2476
2604
|
y = p.y;
|
|
2477
2605
|
}
|
|
2478
|
-
const rect = getScrollRect(
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
};
|
|
2483
|
-
if ((this.speed.x || this.speed.y) && !this.raf) {
|
|
2484
|
-
this.raf = this.win?.requestAnimationFrame(this.tick) ?? 0;
|
|
2485
|
-
}
|
|
2606
|
+
const rect = getScrollRect(container);
|
|
2607
|
+
return axis === 'x'
|
|
2608
|
+
? edgeSpeed(x, rect.left, rect.right, this.edge, this.maxSpeed)
|
|
2609
|
+
: edgeSpeed(y, rect.top, rect.bottom, this.edge, this.maxSpeed);
|
|
2486
2610
|
}
|
|
2487
2611
|
stop() {
|
|
2488
2612
|
if (this.raf)
|
|
@@ -2494,14 +2618,14 @@ class AutoScroller {
|
|
|
2494
2618
|
this.win = undefined;
|
|
2495
2619
|
this.pointerDoc = undefined;
|
|
2496
2620
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2621
|
+
/** Scrolls one container by a speed measured in viewport pixels (carrying sub-pixel remainders). */
|
|
2622
|
+
scrollContainer(container, sx, sy) {
|
|
2623
|
+
if (!sx && !sy)
|
|
2500
2624
|
return;
|
|
2501
|
-
|
|
2502
|
-
const
|
|
2503
|
-
|
|
2504
|
-
|
|
2625
|
+
// An element's scrollLeft/Top are local to it; a window's are viewport pixels already.
|
|
2626
|
+
const local = isWindow(container)
|
|
2627
|
+
? { x: sx, y: sy }
|
|
2628
|
+
: viewportDeltaToLocal(container, { x: sx, y: sy });
|
|
2505
2629
|
// Browsers snap scroll offsets to whole pixels, so a slow speed (< 1px/frame, i.e. when the
|
|
2506
2630
|
// pointer has just entered the edge zone) would never move anything. Carry the remainder.
|
|
2507
2631
|
this.carry.x += local.x;
|
|
@@ -2510,11 +2634,23 @@ class AutoScroller {
|
|
|
2510
2634
|
const dy = Math.trunc(this.carry.y);
|
|
2511
2635
|
this.carry.x -= dx;
|
|
2512
2636
|
this.carry.y -= dy;
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2637
|
+
// `behavior: 'instant'` matters: with `scroll-behavior: smooth` on <html> or on the scroller
|
|
2638
|
+
// (very common in apps) every per-frame scroll would start a new animation that cancels the
|
|
2639
|
+
// previous one, and the list would not move at all.
|
|
2640
|
+
if (dx || dy)
|
|
2517
2641
|
container.scrollBy({ left: dx, top: dy, behavior: 'instant' });
|
|
2642
|
+
}
|
|
2643
|
+
tick = () => {
|
|
2644
|
+
if (!this.speed.x && !this.speed.y) {
|
|
2645
|
+
this.raf = 0;
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
if (this.containerX === this.containerY) {
|
|
2649
|
+
this.scrollContainer(this.containerX, this.speed.x, this.speed.y);
|
|
2650
|
+
}
|
|
2651
|
+
else {
|
|
2652
|
+
this.scrollContainer(this.containerX, this.speed.x, 0);
|
|
2653
|
+
this.scrollContainer(this.containerY, 0, this.speed.y);
|
|
2518
2654
|
}
|
|
2519
2655
|
// Pointer ثابت مانده ولی محتوا اسکرول شده؛
|
|
2520
2656
|
// بنابراین موقعیت placeholder/sort را دوباره محاسبه کن.
|
|
@@ -2557,7 +2693,8 @@ function findScrollableAncestor(el) {
|
|
|
2557
2693
|
break;
|
|
2558
2694
|
const style = win.getComputedStyle(node);
|
|
2559
2695
|
const scrollable = /(auto|scroll|overlay)/.test(style.overflowY + style.overflowX);
|
|
2560
|
-
if (scrollable &&
|
|
2696
|
+
if (scrollable &&
|
|
2697
|
+
(node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth)) {
|
|
2561
2698
|
// <html>/<body> scroll the whole document: their own rect spans the full (tall) page, so
|
|
2562
2699
|
// edge detection must use the window's viewport instead.
|
|
2563
2700
|
const doc = node.ownerDocument;
|
|
@@ -2569,6 +2706,26 @@ function findScrollableAncestor(el) {
|
|
|
2569
2706
|
}
|
|
2570
2707
|
return el.ownerDocument.defaultView ?? el;
|
|
2571
2708
|
}
|
|
2709
|
+
/** Nearest ancestor that can scroll along ONE axis (`<html>`/`<body>` resolve to the window). */
|
|
2710
|
+
function findScrollableAncestorForAxis(el, axis) {
|
|
2711
|
+
let node = el;
|
|
2712
|
+
while (node) {
|
|
2713
|
+
const win = node.ownerDocument.defaultView;
|
|
2714
|
+
if (!win)
|
|
2715
|
+
break;
|
|
2716
|
+
const style = win.getComputedStyle(node);
|
|
2717
|
+
const overflow = axis === 'x' ? style.overflowX : style.overflowY;
|
|
2718
|
+
const canScroll = axis === 'x' ? node.scrollWidth > node.clientWidth : node.scrollHeight > node.clientHeight;
|
|
2719
|
+
if (/(auto|scroll|overlay)/.test(overflow) && canScroll) {
|
|
2720
|
+
const doc = node.ownerDocument;
|
|
2721
|
+
if (node === doc.documentElement || node === doc.body)
|
|
2722
|
+
return win;
|
|
2723
|
+
return node;
|
|
2724
|
+
}
|
|
2725
|
+
node = node.parentElement;
|
|
2726
|
+
}
|
|
2727
|
+
return el.ownerDocument.defaultView ?? el;
|
|
2728
|
+
}
|
|
2572
2729
|
function getScrollPosition(container) {
|
|
2573
2730
|
if (isWindow(container)) {
|
|
2574
2731
|
return { left: container.scrollX, top: container.scrollY };
|
|
@@ -2781,7 +2938,7 @@ class NgxDraggable {
|
|
|
2781
2938
|
const after = this._ref.activeDropList;
|
|
2782
2939
|
// Follow the hovered list; outside every list, scroll the page.
|
|
2783
2940
|
if (after !== before)
|
|
2784
|
-
this.scroller.retarget(after?.el ?? this._ref.el.
|
|
2941
|
+
this.scroller.retarget(after?.el ?? this._ref.dropList?.el ?? this._ref.el);
|
|
2785
2942
|
}
|
|
2786
2943
|
this.dragMove.emit(p);
|
|
2787
2944
|
}
|
|
@@ -2953,7 +3110,13 @@ class NgxDraggable {
|
|
|
2953
3110
|
this.beginKeyboardSession();
|
|
2954
3111
|
this.dragStart.emit(origin);
|
|
2955
3112
|
}
|
|
2956
|
-
|
|
3113
|
+
// Holding the key down repeats faster than the 200ms slide animation settles.
|
|
3114
|
+
if (e.repeat && this._ref.isListDrag)
|
|
3115
|
+
return;
|
|
3116
|
+
const name = { ArrowLeft: 'left', ArrowRight: 'right', ArrowUp: 'up', ArrowDown: 'down' }[e.key];
|
|
3117
|
+
// List items hop by whole slots / neighbouring lists; free drags move by `keyboardStep` px.
|
|
3118
|
+
if (!this._ref.nudgeToSlot(name))
|
|
3119
|
+
this._ref.nudge(delta.x, delta.y);
|
|
2957
3120
|
this.dragMove.emit(this._ref.pointer);
|
|
2958
3121
|
return;
|
|
2959
3122
|
}
|
|
@@ -3006,11 +3169,11 @@ class NgxDraggable {
|
|
|
3006
3169
|
if (!this.dragHandle())
|
|
3007
3170
|
return true;
|
|
3008
3171
|
// TODO notsafe instanseof: node.nodeType === Node.ELEMENT_NODE
|
|
3009
|
-
return isElementTarget(target) && !!target.closest(this.dragHandle());
|
|
3172
|
+
return isElementTarget$1(target) && !!target.closest(this.dragHandle());
|
|
3010
3173
|
}
|
|
3011
3174
|
/** Should a press on `target` be left alone (no drag)? */
|
|
3012
3175
|
isExcluded(target) {
|
|
3013
|
-
if (!isElementTarget(target))
|
|
3176
|
+
if (!isElementTarget$1(target))
|
|
3014
3177
|
return false;
|
|
3015
3178
|
const selector = this.noDragSelector();
|
|
3016
3179
|
if (selector && target.closest(selector))
|
|
@@ -3044,11 +3207,11 @@ function isEditableOrInteractive(el) {
|
|
|
3044
3207
|
return !!el.closest('button,a[href],input,textarea,select,[contenteditable]:not([contenteditable="false"])');
|
|
3045
3208
|
}
|
|
3046
3209
|
function isEditableTarget(target) {
|
|
3047
|
-
if (!isElementTarget(target))
|
|
3210
|
+
if (!isElementTarget$1(target))
|
|
3048
3211
|
return false;
|
|
3049
3212
|
return !!target.closest('input,textarea,select,[contenteditable]:not([contenteditable="false"])');
|
|
3050
3213
|
}
|
|
3051
|
-
function isElementTarget(target) {
|
|
3214
|
+
function isElementTarget$1(target) {
|
|
3052
3215
|
return (!!target &&
|
|
3053
3216
|
typeof target === 'object' &&
|
|
3054
3217
|
'nodeType' in target &&
|
|
@@ -3058,6 +3221,43 @@ function isElementTarget(target) {
|
|
|
3058
3221
|
|
|
3059
3222
|
const ALL_DIRECTIONS = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];
|
|
3060
3223
|
const KEYBOARD_STEP = 8;
|
|
3224
|
+
/**
|
|
3225
|
+
* Elements matching this selector keep their normal pointer/touch behaviour.
|
|
3226
|
+
* Add data-ngx-resize-ignore to any custom interactive widget that should never
|
|
3227
|
+
* initiate resizing when it is close to the panel edge.
|
|
3228
|
+
*/
|
|
3229
|
+
const INTERACTIVE_SELECTOR = [
|
|
3230
|
+
'input',
|
|
3231
|
+
'textarea',
|
|
3232
|
+
'select',
|
|
3233
|
+
'option',
|
|
3234
|
+
'button',
|
|
3235
|
+
'a',
|
|
3236
|
+
'summary',
|
|
3237
|
+
'[contenteditable="true"]',
|
|
3238
|
+
'audio',
|
|
3239
|
+
'video',
|
|
3240
|
+
'iframe',
|
|
3241
|
+
'label',
|
|
3242
|
+
'[role="textbox"]',
|
|
3243
|
+
'[role="menuitem"]',
|
|
3244
|
+
'[role="tab"]',
|
|
3245
|
+
'mat-slider',
|
|
3246
|
+
'mat-select',
|
|
3247
|
+
'mat-checkbox',
|
|
3248
|
+
'mat-radio-button',
|
|
3249
|
+
'mat-slide-toggle',
|
|
3250
|
+
'.mat-mdc-slider',
|
|
3251
|
+
'.mat-mdc-select',
|
|
3252
|
+
'[role="button"]',
|
|
3253
|
+
'[role="slider"]',
|
|
3254
|
+
'[role="switch"]',
|
|
3255
|
+
'[role="checkbox"]',
|
|
3256
|
+
'[role="radio"]',
|
|
3257
|
+
'[role="combobox"]',
|
|
3258
|
+
'[role="listbox"]',
|
|
3259
|
+
'[data-ngx-resize-ignore]',
|
|
3260
|
+
].join(',');
|
|
3061
3261
|
class NgxResizable {
|
|
3062
3262
|
el;
|
|
3063
3263
|
disabled = model(false, /* @ts-ignore */
|
|
@@ -3087,14 +3287,16 @@ class NgxResizable {
|
|
|
3087
3287
|
...(ngDevMode ? [{ debugName: "resizing" }] : /* istanbul ignore next */ []));
|
|
3088
3288
|
direction = 'se';
|
|
3089
3289
|
start;
|
|
3090
|
-
pointer = {
|
|
3091
|
-
x: 0,
|
|
3092
|
-
y: 0,
|
|
3093
|
-
};
|
|
3290
|
+
pointer = { x: 0, y: 0 };
|
|
3094
3291
|
beforeTransition = '';
|
|
3095
3292
|
beforeWidth = '';
|
|
3096
3293
|
beforeHeight = '';
|
|
3097
|
-
|
|
3294
|
+
beforeTranslate = '';
|
|
3295
|
+
baseComputedTranslate = 'none';
|
|
3296
|
+
keyboardBaseTranslate = null;
|
|
3297
|
+
keyboardBaseInlineTranslate = '';
|
|
3298
|
+
startMatrix = { a: 1, b: 0, c: 0, d: 1 };
|
|
3299
|
+
pointerInverse = invertLinear({ a: 1, b: 0, c: 0, d: 1 });
|
|
3098
3300
|
pointerId = -1;
|
|
3099
3301
|
startWidth = 0;
|
|
3100
3302
|
startHeight = 0;
|
|
@@ -3110,47 +3312,43 @@ class NgxResizable {
|
|
|
3110
3312
|
}
|
|
3111
3313
|
}
|
|
3112
3314
|
onPointerDown(e) {
|
|
3113
|
-
if (this.disabled() || e.button !== 0)
|
|
3315
|
+
if (this.disabled() || e.button !== 0 || this.resizing())
|
|
3114
3316
|
return;
|
|
3115
|
-
}
|
|
3116
3317
|
const dir = this.hitDirection(e);
|
|
3117
|
-
if (
|
|
3318
|
+
if (dir)
|
|
3319
|
+
this.beginResize(e, dir);
|
|
3320
|
+
}
|
|
3321
|
+
/** Entry point used by the typed NgxResizeHandle directive. */
|
|
3322
|
+
beginResize(e, direction) {
|
|
3323
|
+
if (this.disabled() || e.button !== 0 || this.resizing())
|
|
3324
|
+
return;
|
|
3325
|
+
const dir = resolveLogicalDirection(direction, isRtl(this.el.nativeElement));
|
|
3326
|
+
if (!this.resolvedDirections().includes(dir))
|
|
3118
3327
|
return;
|
|
3119
|
-
}
|
|
3120
3328
|
e.preventDefault();
|
|
3121
|
-
e.stopPropagation();
|
|
3122
|
-
e.stopImmediatePropagation();
|
|
3123
3329
|
const element = this.el.nativeElement;
|
|
3124
3330
|
this.direction = dir;
|
|
3125
3331
|
this.pointerId = e.pointerId;
|
|
3126
|
-
/**
|
|
3127
|
-
* This is the actual visual rectangle.
|
|
3128
|
-
* It already contains any transform created by DragRef.
|
|
3129
|
-
*/
|
|
3130
3332
|
this.start = element.getBoundingClientRect();
|
|
3131
|
-
this.pointer = {
|
|
3132
|
-
x: e.clientX,
|
|
3133
|
-
y: e.clientY,
|
|
3134
|
-
};
|
|
3333
|
+
this.pointer = { x: e.clientX, y: e.clientY };
|
|
3135
3334
|
this.beforeTransition = element.style.transition;
|
|
3136
3335
|
this.beforeWidth = element.style.width;
|
|
3137
3336
|
this.beforeHeight = element.style.height;
|
|
3138
|
-
this.
|
|
3139
|
-
this.
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
this.beforeTransform = element.style.transform;
|
|
3337
|
+
this.beforeTranslate = element.style.translate;
|
|
3338
|
+
this.baseComputedTranslate =
|
|
3339
|
+
element.ownerDocument.defaultView?.getComputedStyle(element).translate ?? 'none';
|
|
3340
|
+
this.keyboardBaseTranslate = null;
|
|
3341
|
+
this.startMatrix = getLocalToViewportMatrix(element);
|
|
3342
|
+
this.pointerInverse = invertLinear(this.startMatrix);
|
|
3343
|
+
this.startWidth = readBorderBoxSize(element, 'x');
|
|
3344
|
+
this.startHeight = readBorderBoxSize(element, 'y');
|
|
3147
3345
|
this.resizing.set(true);
|
|
3148
3346
|
element.style.transition = 'none';
|
|
3149
3347
|
try {
|
|
3150
3348
|
element.setPointerCapture?.(e.pointerId);
|
|
3151
3349
|
}
|
|
3152
3350
|
catch {
|
|
3153
|
-
|
|
3351
|
+
// Document listeners remain as a fallback.
|
|
3154
3352
|
}
|
|
3155
3353
|
const doc = element.ownerDocument;
|
|
3156
3354
|
this.removeDocumentListeners = [
|
|
@@ -3165,29 +3363,23 @@ class NgxResizable {
|
|
|
3165
3363
|
this.resizeStart.emit(out);
|
|
3166
3364
|
}
|
|
3167
3365
|
onPointerMove(e) {
|
|
3168
|
-
if (!this.resizing() || e.pointerId !== this.pointerId)
|
|
3366
|
+
if (!this.resizing() || e.pointerId !== this.pointerId)
|
|
3169
3367
|
return;
|
|
3170
|
-
}
|
|
3171
3368
|
const out = this.calculate(e);
|
|
3172
3369
|
this.apply(out);
|
|
3173
3370
|
this.resizeMove.emit(out);
|
|
3174
3371
|
}
|
|
3175
3372
|
onPointerUp(e) {
|
|
3176
|
-
if (!this.resizing() || e.pointerId !== this.pointerId)
|
|
3373
|
+
if (!this.resizing() || e.pointerId !== this.pointerId)
|
|
3177
3374
|
return;
|
|
3178
|
-
}
|
|
3179
3375
|
const out = this.calculate(e);
|
|
3180
3376
|
this.apply(out);
|
|
3181
3377
|
this.resizeEnd.emit(out);
|
|
3182
3378
|
this.finish();
|
|
3183
3379
|
}
|
|
3184
3380
|
onDocumentKeyDown(e) {
|
|
3185
|
-
if (!this.resizing())
|
|
3381
|
+
if (!this.resizing() || e.key !== 'Escape')
|
|
3186
3382
|
return;
|
|
3187
|
-
}
|
|
3188
|
-
if (e.key !== 'Escape') {
|
|
3189
|
-
return;
|
|
3190
|
-
}
|
|
3191
3383
|
e.preventDefault();
|
|
3192
3384
|
this.restoreBeforeResize();
|
|
3193
3385
|
this.finish();
|
|
@@ -3202,115 +3394,187 @@ class NgxResizable {
|
|
|
3202
3394
|
const element = this.el.nativeElement;
|
|
3203
3395
|
element.style.width = this.beforeWidth;
|
|
3204
3396
|
element.style.height = this.beforeHeight;
|
|
3205
|
-
element.style.
|
|
3397
|
+
element.style.translate = this.beforeTranslate;
|
|
3206
3398
|
}
|
|
3399
|
+
/**
|
|
3400
|
+
* Keyboard resizing respects the configured directions.
|
|
3401
|
+
* The arrow keys move the active physical edge:
|
|
3402
|
+
* - if only west is enabled, horizontal keys operate on west;
|
|
3403
|
+
* - if only east is enabled, horizontal keys operate on east;
|
|
3404
|
+
* - north/south follow the same rule vertically.
|
|
3405
|
+
* Disabled axes are never modified.
|
|
3406
|
+
*/
|
|
3207
3407
|
onHandleKeyDown(e) {
|
|
3208
|
-
if (this.disabled())
|
|
3408
|
+
if (this.disabled() || this.resizing())
|
|
3209
3409
|
return;
|
|
3210
|
-
|
|
3211
|
-
// Only when the resizable element itself is focused: arrow keys pressed inside an input /
|
|
3212
|
-
// contenteditable that lives in the block are caret movement, not a resize request.
|
|
3213
|
-
if (e.target !== this.el.nativeElement) {
|
|
3410
|
+
if (e.target !== this.el.nativeElement)
|
|
3214
3411
|
return;
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
const
|
|
3412
|
+
if (this.isEditableTarget(e.target))
|
|
3413
|
+
return;
|
|
3414
|
+
const allowed = this.resolvedDirections();
|
|
3415
|
+
const horizontalEdge = this.chooseAxisEdge(allowed, 'x', e.key);
|
|
3416
|
+
const verticalEdge = this.chooseAxisEdge(allowed, 'y', e.key);
|
|
3218
3417
|
let dw = 0;
|
|
3219
3418
|
let dh = 0;
|
|
3220
|
-
|
|
3221
|
-
|
|
3419
|
+
const configuredStep = this.keyboardStep();
|
|
3420
|
+
const step = (Number.isFinite(configuredStep) ? Math.max(1, configuredStep) : KEYBOARD_STEP) *
|
|
3421
|
+
(e.shiftKey ? 4 : 1);
|
|
3422
|
+
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
|
|
3423
|
+
if (!horizontalEdge)
|
|
3424
|
+
return;
|
|
3425
|
+
const positive = e.key === 'ArrowRight';
|
|
3426
|
+
const rtl = isRtl(this.el.nativeElement);
|
|
3427
|
+
const physicalDelta = (positive ? 1 : -1) * (rtl ? -1 : 1);
|
|
3428
|
+
// East edge follows pointer direction; west edge moves the opposite way
|
|
3429
|
+
// relative to the resulting width.
|
|
3430
|
+
dw = horizontalEdge === 'e' ? physicalDelta * step : -physicalDelta * step;
|
|
3431
|
+
}
|
|
3432
|
+
else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
|
3433
|
+
if (!verticalEdge)
|
|
3434
|
+
return;
|
|
3435
|
+
const physicalDelta = e.key === 'ArrowDown' ? 1 : -1;
|
|
3436
|
+
dh = verticalEdge === 's' ? physicalDelta * step : -physicalDelta * step;
|
|
3437
|
+
}
|
|
3438
|
+
else {
|
|
3439
|
+
return;
|
|
3440
|
+
}
|
|
3441
|
+
e.preventDefault();
|
|
3442
|
+
const element = this.el.nativeElement;
|
|
3443
|
+
const oldWidth = readBorderBoxSize(element, 'x');
|
|
3444
|
+
const oldHeight = readBorderBoxSize(element, 'y');
|
|
3445
|
+
let width = oldWidth;
|
|
3446
|
+
let height = oldHeight;
|
|
3447
|
+
if (dw !== 0) {
|
|
3448
|
+
width = this.clampSize(oldWidth + dw, 'x');
|
|
3222
3449
|
}
|
|
3223
|
-
|
|
3224
|
-
|
|
3450
|
+
if (dh !== 0) {
|
|
3451
|
+
height = this.clampSize(oldHeight + dh, 'y');
|
|
3452
|
+
}
|
|
3453
|
+
// Keep the opposite edge fixed for west/north keyboard resizing.
|
|
3454
|
+
const rect = element.getBoundingClientRect();
|
|
3455
|
+
const matrix = getLocalToViewportMatrix(element);
|
|
3456
|
+
const scaleX = Math.hypot(matrix.a, matrix.b) || 1;
|
|
3457
|
+
const scaleY = Math.hypot(matrix.c, matrix.d) || 1;
|
|
3458
|
+
let moveLeft = horizontalEdge === 'w' ? (oldWidth - width) * scaleX : 0;
|
|
3459
|
+
let moveTop = verticalEdge === 'n' ? (oldHeight - height) * scaleY : 0;
|
|
3460
|
+
const boundary = this.boundary();
|
|
3461
|
+
if (boundary) {
|
|
3462
|
+
const clamped = clampResizeWithinBoundary(boundary.getBoundingClientRect(), rect, width * scaleX, height * scaleY, moveLeft, moveTop);
|
|
3463
|
+
width = clamped.width / scaleX;
|
|
3464
|
+
height = clamped.height / scaleY;
|
|
3465
|
+
moveLeft = clamped.left;
|
|
3466
|
+
moveTop = clamped.top;
|
|
3225
3467
|
}
|
|
3226
|
-
|
|
3227
|
-
|
|
3468
|
+
// Keyboard resize keeps a stable base translation and recomputes the total offset
|
|
3469
|
+
// on every key press. This prevents an ever-growing chain of calc()/translate values.
|
|
3470
|
+
if (this.keyboardBaseTranslate === null) {
|
|
3471
|
+
const computed = element.ownerDocument.defaultView?.getComputedStyle(element);
|
|
3472
|
+
this.keyboardBaseTranslate = computed?.translate ?? 'none';
|
|
3473
|
+
this.keyboardBaseInlineTranslate = element.style.translate;
|
|
3228
3474
|
}
|
|
3229
|
-
|
|
3230
|
-
|
|
3475
|
+
const style = this.toStyleSize(width, height);
|
|
3476
|
+
element.style.width = `${style.width}px`;
|
|
3477
|
+
element.style.height = `${style.height}px`;
|
|
3478
|
+
element.style.translate = this.keyboardBaseInlineTranslate;
|
|
3479
|
+
// Keep the opposite edge fixed without touching `transform` (owned by NgxDraggable).
|
|
3480
|
+
const current = element.getBoundingClientRect();
|
|
3481
|
+
const correctionX = rect.left + moveLeft - current.left;
|
|
3482
|
+
const correctionY = rect.top + moveTop - current.top;
|
|
3483
|
+
if (correctionX || correctionY) {
|
|
3484
|
+
const local = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
|
|
3485
|
+
writeTranslateWithOffset(element, this.keyboardBaseTranslate, local);
|
|
3231
3486
|
}
|
|
3232
3487
|
else {
|
|
3233
|
-
|
|
3488
|
+
element.style.translate = this.keyboardBaseInlineTranslate;
|
|
3234
3489
|
}
|
|
3235
|
-
e.preventDefault();
|
|
3236
|
-
const rect = this.el.nativeElement.getBoundingClientRect();
|
|
3237
|
-
const width = this.clampGrid(Math.max(this.minWidth(), Math.min(this.maxWidth(), this.el.nativeElement.offsetWidth + dw)), 'x');
|
|
3238
|
-
const height = this.clampGrid(Math.max(this.minHeight(), Math.min(this.maxHeight(), this.el.nativeElement.offsetHeight + dh)), 'y');
|
|
3239
|
-
const styled = this.toStyleSize(width, height);
|
|
3240
|
-
this.el.nativeElement.style.width = `${styled.width}px`;
|
|
3241
|
-
this.el.nativeElement.style.height = `${styled.height}px`;
|
|
3242
3490
|
const out = {
|
|
3243
3491
|
width,
|
|
3244
3492
|
height,
|
|
3245
|
-
moveLeft
|
|
3246
|
-
moveTop
|
|
3247
|
-
left: rect.left,
|
|
3248
|
-
top: rect.top,
|
|
3249
|
-
direction:
|
|
3493
|
+
moveLeft,
|
|
3494
|
+
moveTop,
|
|
3495
|
+
left: rect.left + moveLeft,
|
|
3496
|
+
top: rect.top + moveTop,
|
|
3497
|
+
direction: this.keyboardDirection(horizontalEdge, verticalEdge),
|
|
3250
3498
|
};
|
|
3499
|
+
this.resizeStart.emit(out);
|
|
3251
3500
|
this.resizeMove.emit(out);
|
|
3252
3501
|
this.resizeEnd.emit(out);
|
|
3253
3502
|
}
|
|
3503
|
+
chooseAxisEdge(allowed, axis, key) {
|
|
3504
|
+
if (axis === 'x') {
|
|
3505
|
+
const hasWest = allowed.some((d) => d.includes('w'));
|
|
3506
|
+
const hasEast = allowed.some((d) => d.includes('e'));
|
|
3507
|
+
if (key === 'ArrowLeft') {
|
|
3508
|
+
if (hasWest)
|
|
3509
|
+
return 'w';
|
|
3510
|
+
if (hasEast)
|
|
3511
|
+
return 'e';
|
|
3512
|
+
}
|
|
3513
|
+
if (key === 'ArrowRight') {
|
|
3514
|
+
if (hasEast)
|
|
3515
|
+
return 'e';
|
|
3516
|
+
if (hasWest)
|
|
3517
|
+
return 'w';
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
else {
|
|
3521
|
+
const hasNorth = allowed.some((d) => d.includes('n'));
|
|
3522
|
+
const hasSouth = allowed.some((d) => d.includes('s'));
|
|
3523
|
+
if (key === 'ArrowUp') {
|
|
3524
|
+
if (hasNorth)
|
|
3525
|
+
return 'n';
|
|
3526
|
+
if (hasSouth)
|
|
3527
|
+
return 's';
|
|
3528
|
+
}
|
|
3529
|
+
if (key === 'ArrowDown') {
|
|
3530
|
+
if (hasSouth)
|
|
3531
|
+
return 's';
|
|
3532
|
+
if (hasNorth)
|
|
3533
|
+
return 'n';
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
return null;
|
|
3537
|
+
}
|
|
3538
|
+
keyboardDirection(horizontal, vertical) {
|
|
3539
|
+
if (horizontal && vertical)
|
|
3540
|
+
return `${vertical}${horizontal}`;
|
|
3541
|
+
return horizontal ?? vertical ?? 'se';
|
|
3542
|
+
}
|
|
3543
|
+
isEditableTarget(target) {
|
|
3544
|
+
if (!isElementTarget(target))
|
|
3545
|
+
return false;
|
|
3546
|
+
return !!target.closest(INTERACTIVE_SELECTOR);
|
|
3547
|
+
}
|
|
3254
3548
|
calculate(e) {
|
|
3255
|
-
const
|
|
3549
|
+
const delta = applyLinear(this.pointerInverse, {
|
|
3256
3550
|
x: e.clientX - this.pointer.x,
|
|
3257
3551
|
y: e.clientY - this.pointer.y,
|
|
3258
3552
|
});
|
|
3259
|
-
const dx = localDelta.x;
|
|
3260
|
-
const dy = localDelta.y;
|
|
3261
3553
|
let width = this.startWidth;
|
|
3262
3554
|
let height = this.startHeight;
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
/**
|
|
3276
|
-
* South
|
|
3277
|
-
*/
|
|
3278
|
-
if (this.direction.includes('s')) {
|
|
3279
|
-
height += dy;
|
|
3280
|
-
}
|
|
3281
|
-
/**
|
|
3282
|
-
* North
|
|
3283
|
-
*/
|
|
3284
|
-
if (this.direction.includes('n')) {
|
|
3285
|
-
height -= dy;
|
|
3286
|
-
}
|
|
3287
|
-
width = this.clampGrid(Math.max(this.minWidth(), Math.min(this.maxWidth(), width)), 'x');
|
|
3288
|
-
height = this.clampGrid(Math.max(this.minHeight(), Math.min(this.maxHeight(), height)), 'y');
|
|
3289
|
-
/**
|
|
3290
|
-
* Calculate the intended visual position.
|
|
3291
|
-
*
|
|
3292
|
-
* This is useful for boundary calculations and
|
|
3293
|
-
* emitted resize events.
|
|
3294
|
-
*/
|
|
3295
|
-
const matrix = getLocalToViewportMatrix(this.el.nativeElement);
|
|
3296
|
-
const scaleX = Math.hypot(matrix.a, matrix.b) || 1;
|
|
3297
|
-
const scaleY = Math.hypot(matrix.c, matrix.d) || 1;
|
|
3555
|
+
if (this.direction.includes('e'))
|
|
3556
|
+
width += delta.x;
|
|
3557
|
+
if (this.direction.includes('w'))
|
|
3558
|
+
width -= delta.x;
|
|
3559
|
+
if (this.direction.includes('s'))
|
|
3560
|
+
height += delta.y;
|
|
3561
|
+
if (this.direction.includes('n'))
|
|
3562
|
+
height -= delta.y;
|
|
3563
|
+
width = this.clampSize(width, 'x');
|
|
3564
|
+
height = this.clampSize(height, 'y');
|
|
3565
|
+
const scaleX = Math.hypot(this.startMatrix.a, this.startMatrix.b) || 1;
|
|
3566
|
+
const scaleY = Math.hypot(this.startMatrix.c, this.startMatrix.d) || 1;
|
|
3298
3567
|
let left = this.start.left;
|
|
3299
3568
|
let top = this.start.top;
|
|
3300
|
-
if (this.direction.includes('w'))
|
|
3569
|
+
if (this.direction.includes('w'))
|
|
3301
3570
|
left = this.start.right - width * scaleX;
|
|
3302
|
-
|
|
3303
|
-
if (this.direction.includes('n')) {
|
|
3571
|
+
if (this.direction.includes('n'))
|
|
3304
3572
|
top = this.start.bottom - height * scaleY;
|
|
3305
|
-
}
|
|
3306
3573
|
let moveLeft = left - this.start.left;
|
|
3307
3574
|
let moveTop = top - this.start.top;
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
const boundaryEl = this.boundary();
|
|
3312
|
-
if (boundaryEl) {
|
|
3313
|
-
const clamped = clampResizeWithinBoundary(boundaryEl.getBoundingClientRect(), this.start, width * scaleX, height * scaleY, moveLeft, moveTop);
|
|
3575
|
+
const boundary = this.boundary();
|
|
3576
|
+
if (boundary) {
|
|
3577
|
+
const clamped = clampResizeWithinBoundary(boundary.getBoundingClientRect(), this.start, width * scaleX, height * scaleY, moveLeft, moveTop);
|
|
3314
3578
|
width = clamped.width / scaleX;
|
|
3315
3579
|
height = clamped.height / scaleY;
|
|
3316
3580
|
moveLeft = clamped.left;
|
|
@@ -3330,63 +3594,22 @@ class NgxResizable {
|
|
|
3330
3594
|
}
|
|
3331
3595
|
apply(out) {
|
|
3332
3596
|
const element = this.el.nativeElement;
|
|
3333
|
-
|
|
3334
|
-
* Always reset to the transform that existed before
|
|
3335
|
-
* this resize operation started.
|
|
3336
|
-
*
|
|
3337
|
-
* This prevents resize corrections from accumulating.
|
|
3338
|
-
*/
|
|
3339
|
-
element.style.transform = this.beforeTransform;
|
|
3340
|
-
/**
|
|
3341
|
-
* Apply the actual size first.
|
|
3342
|
-
*
|
|
3343
|
-
* Changing width/height may cause the browser to re-layout
|
|
3344
|
-
* the element, especially for relative/flex/grid/static layouts.
|
|
3345
|
-
*/
|
|
3597
|
+
element.style.translate = this.beforeTranslate;
|
|
3346
3598
|
const style = this.toStyleSize(out.width, out.height);
|
|
3347
3599
|
element.style.width = `${style.width}px`;
|
|
3348
3600
|
element.style.height = `${style.height}px`;
|
|
3349
|
-
/**
|
|
3350
|
-
* Force/read layout after changing the size.
|
|
3351
|
-
*/
|
|
3352
3601
|
const current = element.getBoundingClientRect();
|
|
3353
|
-
/**
|
|
3354
|
-
* These are the positions where the element MUST visually be.
|
|
3355
|
-
*
|
|
3356
|
-
* `out.moveLeft` / `out.moveTop` are calculated in `calculate()`
|
|
3357
|
-
* from the original visual rectangle.
|
|
3358
|
-
*/
|
|
3359
3602
|
const targetLeft = this.start.left + out.moveLeft;
|
|
3360
3603
|
const targetTop = this.start.top + out.moveTop;
|
|
3361
|
-
/**
|
|
3362
|
-
* Browser's actual position after width/height changed.
|
|
3363
|
-
*
|
|
3364
|
-
* The difference between target and current position is the
|
|
3365
|
-
* correction that must be applied using transform.
|
|
3366
|
-
*/
|
|
3367
3604
|
const correctionX = targetLeft - current.left;
|
|
3368
3605
|
const correctionY = targetTop - current.top;
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
element.style.transform = this.beforeTransform;
|
|
3606
|
+
if (!correctionX && !correctionY) {
|
|
3607
|
+
element.style.translate = this.beforeTranslate;
|
|
3372
3608
|
return;
|
|
3373
3609
|
}
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
* correction required by Resize.
|
|
3377
|
-
*/
|
|
3378
|
-
const baseTransform = this.beforeTransform && this.beforeTransform !== 'none' ? `${this.beforeTransform} ` : '';
|
|
3379
|
-
const localCorrection = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
|
|
3380
|
-
element.style.transform =
|
|
3381
|
-
`${baseTransform}translate3d(` + `${localCorrection.x}px, ` + `${localCorrection.y}px, 0)`;
|
|
3610
|
+
const local = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
|
|
3611
|
+
writeTranslateWithOffset(element, this.baseComputedTranslate, local);
|
|
3382
3612
|
}
|
|
3383
|
-
/**
|
|
3384
|
-
* `offsetWidth/Height` (what we measure and report) are BORDER-box sizes. The inline
|
|
3385
|
-
* `width/height` we write are interpreted according to `box-sizing`: for the CSS default
|
|
3386
|
-
* (`content-box`) writing the border-box number would make a padded/bordered block jump by
|
|
3387
|
-
* its padding+border the instant a resize starts. Convert so the box is exactly the size
|
|
3388
|
-
* reported in `IResizableOutput`.
|
|
3389
|
-
*/
|
|
3390
3613
|
toStyleSize(width, height) {
|
|
3391
3614
|
const el = this.el.nativeElement;
|
|
3392
3615
|
const cs = el.ownerDocument.defaultView?.getComputedStyle(el);
|
|
@@ -3395,17 +3618,25 @@ class NgxResizable {
|
|
|
3395
3618
|
const px = (v) => Number.parseFloat(v) || 0;
|
|
3396
3619
|
const extraX = px(cs.paddingLeft) + px(cs.paddingRight) + px(cs.borderLeftWidth) + px(cs.borderRightWidth);
|
|
3397
3620
|
const extraY = px(cs.paddingTop) + px(cs.paddingBottom) + px(cs.borderTopWidth) + px(cs.borderBottomWidth);
|
|
3398
|
-
return {
|
|
3621
|
+
return {
|
|
3622
|
+
width: Math.max(0, width - extraX),
|
|
3623
|
+
height: Math.max(0, height - extraY),
|
|
3624
|
+
};
|
|
3399
3625
|
}
|
|
3400
|
-
|
|
3401
|
-
const
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
const
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3626
|
+
clampSize(value, axis) {
|
|
3627
|
+
const minInput = axis === 'x' ? this.minWidth() : this.minHeight();
|
|
3628
|
+
const maxInput = axis === 'x' ? this.maxWidth() : this.maxHeight();
|
|
3629
|
+
const min = Number.isFinite(minInput) ? Math.max(0, minInput) : 0;
|
|
3630
|
+
const max = Number.isFinite(maxInput) ? Math.max(min, maxInput) : Infinity;
|
|
3631
|
+
const bounded = Math.min(max, Math.max(min, Number.isFinite(value) ? value : min));
|
|
3632
|
+
const grid = this.grid();
|
|
3633
|
+
const step = typeof grid === 'number' ? grid : grid?.[axis];
|
|
3634
|
+
if (!step || !Number.isFinite(step) || step <= 0)
|
|
3635
|
+
return bounded;
|
|
3636
|
+
// Snap relative to the minimum, then clamp again so grid rounding can never
|
|
3637
|
+
// violate the configured min/max constraints.
|
|
3638
|
+
const snapped = min + Math.round((bounded - min) / step) * step;
|
|
3639
|
+
return Math.min(max, Math.max(min, snapped));
|
|
3409
3640
|
}
|
|
3410
3641
|
finish() {
|
|
3411
3642
|
this.resizing.set(false);
|
|
@@ -3421,9 +3652,12 @@ class NgxResizable {
|
|
|
3421
3652
|
}
|
|
3422
3653
|
}
|
|
3423
3654
|
catch {
|
|
3424
|
-
|
|
3655
|
+
// Pointer capture may already have been released.
|
|
3425
3656
|
}
|
|
3426
|
-
this.
|
|
3657
|
+
this.beforeTranslate = '';
|
|
3658
|
+
this.baseComputedTranslate = 'none';
|
|
3659
|
+
this.keyboardBaseTranslate = null;
|
|
3660
|
+
this.keyboardBaseInlineTranslate = '';
|
|
3427
3661
|
}
|
|
3428
3662
|
resolvedDirections() {
|
|
3429
3663
|
const rtl = isRtl(this.el.nativeElement);
|
|
@@ -3435,68 +3669,59 @@ class NgxResizable {
|
|
|
3435
3669
|
}
|
|
3436
3670
|
hitDirection(e) {
|
|
3437
3671
|
const element = this.el.nativeElement;
|
|
3438
|
-
const
|
|
3439
|
-
|
|
3440
|
-
const
|
|
3441
|
-
|
|
3442
|
-
const isTop = e.clientY - rect.top <= edge;
|
|
3443
|
-
const isBottom = rect.bottom - e.clientY <= edge;
|
|
3444
|
-
/**
|
|
3445
|
-
* Explicit resize handle has priority.
|
|
3446
|
-
*/
|
|
3447
|
-
// TODO notsafe instanceof:node.nodeType === Node.ELEMENT_NODE
|
|
3448
|
-
const handle = isHTMLElementTarget(e.target)
|
|
3449
|
-
? e.target.closest('[data-ngx-resize-handle]')
|
|
3672
|
+
const target = e.target;
|
|
3673
|
+
// Explicit handles are allowed even when they are inside the panel.
|
|
3674
|
+
const handle = isElementTarget(target)
|
|
3675
|
+
? target.closest('[data-ngx-resize-handle]')
|
|
3450
3676
|
: null;
|
|
3451
3677
|
if (handle && element.contains(handle)) {
|
|
3452
3678
|
const raw = handle.dataset['ngxResizeHandle'];
|
|
3453
|
-
if (!raw)
|
|
3679
|
+
if (!raw)
|
|
3454
3680
|
return null;
|
|
3455
|
-
}
|
|
3456
3681
|
const resolved = resolveLogicalDirection(raw, isRtl(element));
|
|
3457
3682
|
return this.resolvedDirections().includes(resolved) ? resolved : null;
|
|
3458
3683
|
}
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
*
|
|
3462
|
-
* left -> w
|
|
3463
|
-
* right -> e
|
|
3464
|
-
*
|
|
3465
|
-
* RTL is handled only when a logical direction
|
|
3466
|
-
* such as "start" / "end" is requested.
|
|
3467
|
-
*/
|
|
3468
|
-
const direction = isTop && isLeft
|
|
3469
|
-
? 'nw'
|
|
3470
|
-
: isTop && isRight
|
|
3471
|
-
? 'ne'
|
|
3472
|
-
: isBottom && isLeft
|
|
3473
|
-
? 'sw'
|
|
3474
|
-
: isBottom && isRight
|
|
3475
|
-
? 'se'
|
|
3476
|
-
: isTop
|
|
3477
|
-
? 'n'
|
|
3478
|
-
: isRight
|
|
3479
|
-
? 'e'
|
|
3480
|
-
: isBottom
|
|
3481
|
-
? 's'
|
|
3482
|
-
: isLeft
|
|
3483
|
-
? 'w'
|
|
3484
|
-
: null;
|
|
3485
|
-
if (!direction) {
|
|
3684
|
+
// Never steal pointer events from nested interactive controls.
|
|
3685
|
+
if (isElementTarget(target) && target.closest(INTERACTIVE_SELECTOR))
|
|
3486
3686
|
return null;
|
|
3487
|
-
|
|
3488
|
-
|
|
3687
|
+
const rect = element.getBoundingClientRect();
|
|
3688
|
+
const edge = Math.min(12, Math.max(6, Math.min(rect.width, rect.height) * 0.18));
|
|
3689
|
+
const isLeft = e.clientX - rect.left <= edge;
|
|
3690
|
+
const isRight = rect.right - e.clientX <= edge;
|
|
3691
|
+
const isTop = e.clientY - rect.top <= edge;
|
|
3692
|
+
const isBottom = rect.bottom - e.clientY <= edge;
|
|
3693
|
+
const candidates = [];
|
|
3694
|
+
if (isTop && isLeft)
|
|
3695
|
+
candidates.push('nw', 'n', 'w');
|
|
3696
|
+
else if (isTop && isRight)
|
|
3697
|
+
candidates.push('ne', 'n', 'e');
|
|
3698
|
+
else if (isBottom && isLeft)
|
|
3699
|
+
candidates.push('sw', 's', 'w');
|
|
3700
|
+
else if (isBottom && isRight)
|
|
3701
|
+
candidates.push('se', 's', 'e');
|
|
3702
|
+
else if (isTop)
|
|
3703
|
+
candidates.push('n');
|
|
3704
|
+
else if (isRight)
|
|
3705
|
+
candidates.push('e');
|
|
3706
|
+
else if (isBottom)
|
|
3707
|
+
candidates.push('s');
|
|
3708
|
+
else if (isLeft)
|
|
3709
|
+
candidates.push('w');
|
|
3710
|
+
const allowed = new Set(this.resolvedDirections());
|
|
3711
|
+
return candidates.find((candidate) => allowed.has(candidate)) ?? null;
|
|
3489
3712
|
}
|
|
3490
3713
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
3491
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxResizable, isStandalone: true, selector: "[NgxResizable],[ngxResizable]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, directions: { classPropertyName: "directions", publicName: "directions", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, boundary: { classPropertyName: "boundary", publicName: "boundary", isSignal: true, isRequired: false, transformFunction: null }, keyboardStep: { classPropertyName: "keyboardStep", publicName: "keyboardStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", minWidth: "minWidthChange", minHeight: "minHeightChange", maxWidth: "maxWidthChange", maxHeight: "maxHeightChange", resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "keydown": "onHandleKeyDown($event)" }, properties: { "
|
|
3714
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxResizable, isStandalone: true, selector: "[NgxResizable],[ngxResizable]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, directions: { classPropertyName: "directions", publicName: "directions", isSignal: true, isRequired: false, transformFunction: null }, grid: { classPropertyName: "grid", publicName: "grid", isSignal: true, isRequired: false, transformFunction: null }, boundary: { classPropertyName: "boundary", publicName: "boundary", isSignal: true, isRequired: false, transformFunction: null }, keyboardStep: { classPropertyName: "keyboardStep", publicName: "keyboardStep", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", minWidth: "minWidthChange", minHeight: "minHeightChange", maxWidth: "maxWidthChange", maxHeight: "maxHeightChange", resizeStart: "resizeStart", resizeMove: "resizeMove", resizeEnd: "resizeEnd" }, host: { listeners: { "pointerdown": "onPointerDown($event)", "keydown": "onHandleKeyDown($event)" }, properties: { "attr.aria-keyshortcuts": "\"ArrowLeft ArrowRight ArrowUp ArrowDown\"" }, classAttribute: "ngx-resizable" }, ngImport: i0 });
|
|
3492
3715
|
}
|
|
3493
3716
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, decorators: [{
|
|
3494
3717
|
type: Directive,
|
|
3495
3718
|
args: [{
|
|
3496
3719
|
selector: '[NgxResizable],[ngxResizable]',
|
|
3497
3720
|
host: {
|
|
3498
|
-
'[style.touch-action]': '"none"',
|
|
3499
3721
|
class: 'ngx-resizable',
|
|
3722
|
+
// Do not set touch-action:none on the whole panel: it breaks nested controls.
|
|
3723
|
+
// '[style.touch-action]': '"none"',
|
|
3724
|
+
'[attr.aria-keyshortcuts]': '"ArrowLeft ArrowRight ArrowUp ArrowDown"',
|
|
3500
3725
|
},
|
|
3501
3726
|
}]
|
|
3502
3727
|
}], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }, { type: i0.Output, args: ["minWidthChange"] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }, { type: i0.Output, args: ["minHeightChange"] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }, { type: i0.Output, args: ["maxWidthChange"] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }, { type: i0.Output, args: ["maxHeightChange"] }], directions: [{ type: i0.Input, args: [{ isSignal: true, alias: "directions", required: false }] }], grid: [{ type: i0.Input, args: [{ isSignal: true, alias: "grid", required: false }] }], boundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "boundary", required: false }] }], keyboardStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "keyboardStep", required: false }] }], resizeStart: [{ type: i0.Output, args: ["resizeStart"] }], resizeMove: [{ type: i0.Output, args: ["resizeMove"] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], onPointerDown: [{
|
|
@@ -3506,13 +3731,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
|
|
|
3506
3731
|
type: HostListener,
|
|
3507
3732
|
args: ['keydown', ['$event']]
|
|
3508
3733
|
}] } });
|
|
3509
|
-
function
|
|
3734
|
+
function isElementTarget(target) {
|
|
3510
3735
|
return (!!target &&
|
|
3511
3736
|
typeof target === 'object' &&
|
|
3512
3737
|
'nodeType' in target &&
|
|
3513
3738
|
target.nodeType === 1 &&
|
|
3514
3739
|
'closest' in target);
|
|
3515
3740
|
}
|
|
3741
|
+
function readBorderBoxSize(element, axis) {
|
|
3742
|
+
const win = element.ownerDocument.defaultView;
|
|
3743
|
+
const style = win?.getComputedStyle(element);
|
|
3744
|
+
if (!style)
|
|
3745
|
+
return axis === 'x' ? element.offsetWidth : element.offsetHeight;
|
|
3746
|
+
const horizontal = axis === 'x';
|
|
3747
|
+
const size = Number.parseFloat(horizontal ? style.width : style.height) || 0;
|
|
3748
|
+
if (style.boxSizing === 'border-box')
|
|
3749
|
+
return size;
|
|
3750
|
+
const px = (value) => Number.parseFloat(value) || 0;
|
|
3751
|
+
return (size +
|
|
3752
|
+
(horizontal
|
|
3753
|
+
? px(style.paddingLeft) +
|
|
3754
|
+
px(style.paddingRight) +
|
|
3755
|
+
px(style.borderLeftWidth) +
|
|
3756
|
+
px(style.borderRightWidth)
|
|
3757
|
+
: px(style.paddingTop) +
|
|
3758
|
+
px(style.paddingBottom) +
|
|
3759
|
+
px(style.borderTopWidth) +
|
|
3760
|
+
px(style.borderBottomWidth)));
|
|
3761
|
+
}
|
|
3762
|
+
/**
|
|
3763
|
+
* Compose a resize-only offset with the existing CSS individual `translate` value.
|
|
3764
|
+
* Keeping the original CSS tokens (instead of parseFloat) preserves percentages, calc(),
|
|
3765
|
+
* and variables. The `transform` channel remains exclusively owned by NgxDraggable.
|
|
3766
|
+
*/
|
|
3767
|
+
function writeTranslateWithOffset(element, baseValue, offset) {
|
|
3768
|
+
const [baseX, baseY, baseZ] = splitCssComponents(!baseValue || baseValue === 'none' ? '0px 0px 0px' : baseValue);
|
|
3769
|
+
const x = offset.x ? `calc(${baseX ?? '0px'} ${formatOffset(offset.x)})` : (baseX ?? '0px');
|
|
3770
|
+
const y = offset.y ? `calc(${baseY ?? '0px'} ${formatOffset(offset.y)})` : (baseY ?? '0px');
|
|
3771
|
+
element.style.translate = `${x} ${y} ${baseZ ?? '0px'}`;
|
|
3772
|
+
}
|
|
3773
|
+
function splitCssComponents(value) {
|
|
3774
|
+
const result = [];
|
|
3775
|
+
let depth = 0;
|
|
3776
|
+
let token = '';
|
|
3777
|
+
for (const char of value.trim()) {
|
|
3778
|
+
if (char === '(')
|
|
3779
|
+
depth++;
|
|
3780
|
+
if (char === ')')
|
|
3781
|
+
depth = Math.max(0, depth - 1);
|
|
3782
|
+
if (/\s/.test(char) && depth === 0) {
|
|
3783
|
+
if (token)
|
|
3784
|
+
result.push(token);
|
|
3785
|
+
token = '';
|
|
3786
|
+
}
|
|
3787
|
+
else {
|
|
3788
|
+
token += char;
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
3791
|
+
if (token)
|
|
3792
|
+
result.push(token);
|
|
3793
|
+
return result;
|
|
3794
|
+
}
|
|
3795
|
+
function formatOffset(value) {
|
|
3796
|
+
return value < 0
|
|
3797
|
+
? `- ${Number(Math.abs(value).toFixed(4))}px`
|
|
3798
|
+
: `+ ${Number(value.toFixed(4))}px`;
|
|
3799
|
+
}
|
|
3516
3800
|
|
|
3517
3801
|
const NGX_PLACEHOLDER = new InjectionToken('ngx-place-holder');
|
|
3518
3802
|
/**
|
|
@@ -3656,6 +3940,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
|
|
|
3656
3940
|
}]
|
|
3657
3941
|
}] });
|
|
3658
3942
|
|
|
3943
|
+
/**
|
|
3944
|
+
* Typed handle API. Prefer ngxResizeHandle="se" in templates; the legacy
|
|
3945
|
+
* data-ngx-resize-handle attribute remains available for backwards compatibility.
|
|
3946
|
+
*/
|
|
3947
|
+
class NgxResizeHandle {
|
|
3948
|
+
ngxResizeHandle = input.required(/* @ts-ignore */
|
|
3949
|
+
...(ngDevMode ? [{ debugName: "ngxResizeHandle" }] : /* istanbul ignore next */ []));
|
|
3950
|
+
parent = inject(NgxResizable, { optional: true, skipSelf: true });
|
|
3951
|
+
onPointerDown(event) {
|
|
3952
|
+
this.parent?.beginResize(event, this.ngxResizeHandle());
|
|
3953
|
+
}
|
|
3954
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizeHandle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3955
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxResizeHandle, isStandalone: true, selector: "[ngxResizeHandle]", inputs: { ngxResizeHandle: { classPropertyName: "ngxResizeHandle", publicName: "ngxResizeHandle", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "pointerdown": "onPointerDown($event)" }, properties: { "style.touch-action": "\"none\"", "style.user-select": "\"none\"" } }, ngImport: i0 });
|
|
3956
|
+
}
|
|
3957
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizeHandle, decorators: [{
|
|
3958
|
+
type: Directive,
|
|
3959
|
+
args: [{
|
|
3960
|
+
selector: '[ngxResizeHandle]',
|
|
3961
|
+
standalone: true,
|
|
3962
|
+
host: {
|
|
3963
|
+
'[style.touch-action]': '"none"',
|
|
3964
|
+
'[style.user-select]': '"none"',
|
|
3965
|
+
},
|
|
3966
|
+
}]
|
|
3967
|
+
}], propDecorators: { ngxResizeHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxResizeHandle", required: true }] }], onPointerDown: [{
|
|
3968
|
+
type: HostListener,
|
|
3969
|
+
args: ['pointerdown', ['$event']]
|
|
3970
|
+
}] } });
|
|
3971
|
+
|
|
3659
3972
|
function moveItemInArray(array, from, to) {
|
|
3660
3973
|
const f = clamp(from, array.length - 1);
|
|
3661
3974
|
const t = clamp(to, array.length - 1);
|
|
@@ -3741,5 +4054,5 @@ function getCleanHtml(el, options) {
|
|
|
3741
4054
|
* Generated bundle index. Do not edit.
|
|
3742
4055
|
*/
|
|
3743
4056
|
|
|
3744
|
-
export { AutoScroller, DragDropService, DragRef, DropListGroupRef, DropListRef, NGX_DRAGGABLE, NGX_DRAG_PREVIEW, NGX_DROPLIST, NGX_DROPLIST_GROUP, NGX_PLACEHOLDER, NgxDragPreview, NgxDraggable, NgxDropList, NgxDropListGroup, NgxPlaceholder, NgxResizable, PlaceHolderRef, adjustForZoom, checkBoundX, checkBoundY, clampResizeWithinBoundary, copyArrayItem, findScrollableAncestor, getCleanHtml, getPageZoom, getScrollPosition, isRtl, moveItemInArray, resolveLogicalDirection, stripEditorArtifacts, transferArrayItem };
|
|
4057
|
+
export { AutoScroller, DragDropService, DragRef, DropListGroupRef, DropListRef, NGX_DRAGGABLE, NGX_DRAG_PREVIEW, NGX_DROPLIST, NGX_DROPLIST_GROUP, NGX_PLACEHOLDER, NgxDragPreview, NgxDraggable, NgxDropList, NgxDropListGroup, NgxPlaceholder, NgxResizable, NgxResizeHandle, PlaceHolderRef, adjustForZoom, checkBoundX, checkBoundY, clampResizeWithinBoundary, copyArrayItem, findScrollableAncestor, findScrollableAncestorForAxis, getCleanHtml, getPageZoom, getScrollPosition, isRtl, moveItemInArray, resolveLogicalDirection, stripEditorArtifacts, transferArrayItem };
|
|
3745
4058
|
//# sourceMappingURL=ngx-kit-drag-resize.mjs.map
|