ngx-kit 9.2.2 → 9.2.4

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.
@@ -2804,6 +2804,7 @@ class NgxDraggable {
2804
2804
  * When `true`, presses on native interactive controls (`button, a, input, textarea, select`,
2805
2805
  * `[contenteditable]`) do not start a drag either. Off by default so that a page-builder canvas
2806
2806
  * block can be grabbed by its own button/link, which is exactly what you want while editing.
2807
+ * @default false
2807
2808
  */
2808
2809
  ignoreInteractive = input(false, /* @ts-ignore */
2809
2810
  ...(ngDevMode ? [{ debugName: "ignoreInteractive" }] : /* istanbul ignore next */ []));
@@ -2889,17 +2890,15 @@ class NgxDraggable {
2889
2890
  this._ref.dropList?.removeItem(this._ref);
2890
2891
  }
2891
2892
  pointerDown(e) {
2892
- if (this.disabled() ||
2893
- e.button !== 0 ||
2894
- this.isExcluded(e.target) ||
2895
- !this.isOnHandle(e.target))
2893
+ if (this.disabled() || e.button !== 0 || !this.isOnHandle(e.target))
2896
2894
  return;
2897
2895
  // Nested draggables: pointerdown bubbles, so without this an ancestor draggable would start
2898
2896
  // its own drag from the very same gesture. The innermost enabled draggable claims it.
2899
2897
  if (claimedPointerEvents.has(e))
2900
2898
  return;
2901
2899
  claimedPointerEvents.add(e);
2902
- e.preventDefault();
2900
+ if (this.ignoreInteractive())
2901
+ e.preventDefault();
2903
2902
  this.down = true;
2904
2903
  this.keyboardDrag = false;
2905
2904
  this.pointerId = e.pointerId;
@@ -3169,16 +3168,7 @@ class NgxDraggable {
3169
3168
  if (!this.dragHandle())
3170
3169
  return true;
3171
3170
  // TODO notsafe instanseof: node.nodeType === Node.ELEMENT_NODE
3172
- return isElementTarget(target) && !!target.closest(this.dragHandle());
3173
- }
3174
- /** Should a press on `target` be left alone (no drag)? */
3175
- isExcluded(target) {
3176
- if (!isElementTarget(target))
3177
- return false;
3178
- const selector = this.noDragSelector();
3179
- if (selector && target.closest(selector))
3180
- return true;
3181
- return this.ignoreInteractive() && isEditableOrInteractive(target);
3171
+ return isElementTarget$1(target) && !!target.closest(this.dragHandle());
3182
3172
  }
3183
3173
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxDraggable, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
3184
3174
  static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.4", type: NgxDraggable, isStandalone: true, selector: "[NgxDraggable],[ngxDraggable]", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, boundary: { classPropertyName: "boundary", publicName: "boundary", isSignal: true, isRequired: false, transformFunction: null }, dragRootElement: { classPropertyName: "dragRootElement", publicName: "dragRootElement", isSignal: true, isRequired: false, transformFunction: null }, dragHandle: { classPropertyName: "dragHandle", publicName: "dragHandle", isSignal: true, isRequired: false, transformFunction: null }, lockAxis: { classPropertyName: "lockAxis", publicName: "lockAxis", isSignal: true, isRequired: false, transformFunction: null }, dragThreshold: { classPropertyName: "dragThreshold", publicName: "dragThreshold", isSignal: true, isRequired: false, transformFunction: null }, keyboardStep: { classPropertyName: "keyboardStep", publicName: "keyboardStep", isSignal: true, isRequired: false, transformFunction: null }, autoScroll: { classPropertyName: "autoScroll", publicName: "autoScroll", isSignal: true, isRequired: false, transformFunction: null }, noDragSelector: { classPropertyName: "noDragSelector", publicName: "noDragSelector", isSignal: true, isRequired: false, transformFunction: null }, ignoreInteractive: { classPropertyName: "ignoreInteractive", publicName: "ignoreInteractive", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", dragRootElement: "dragRootElementChange", dragHandle: "dragHandleChange", dragStart: "dragStart", dragMove: "dragMove", dragEnd: "dragEnd" }, host: { properties: { "style.touch-action": "\"none\"", "attr.tabindex": "disabled() ? null : 0", "attr.aria-grabbed": "dragging()", "class.disable-drag": "disabled()" }, classAttribute: "ngx-draggable" }, providers: [{ provide: NGX_DRAGGABLE, useExisting: NgxDraggable }], queries: [{ propertyName: "customPreview", first: true, predicate: NgxDragPreview, descendants: true }], ngImport: i0 });
@@ -3203,15 +3193,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
3203
3193
  type: ContentChild,
3204
3194
  args: [NgxDragPreview]
3205
3195
  }], dragStart: [{ type: i0.Output, args: ["dragStart"] }], dragMove: [{ type: i0.Output, args: ["dragMove"] }], dragEnd: [{ type: i0.Output, args: ["dragEnd"] }] } });
3206
- function isEditableOrInteractive(el) {
3207
- return !!el.closest('button,a[href],input,textarea,select,[contenteditable]:not([contenteditable="false"])');
3208
- }
3209
3196
  function isEditableTarget(target) {
3210
- if (!isElementTarget(target))
3197
+ if (!isElementTarget$1(target))
3211
3198
  return false;
3212
3199
  return !!target.closest('input,textarea,select,[contenteditable]:not([contenteditable="false"])');
3213
3200
  }
3214
- function isElementTarget(target) {
3201
+ function isElementTarget$1(target) {
3215
3202
  return (!!target &&
3216
3203
  typeof target === 'object' &&
3217
3204
  'nodeType' in target &&
@@ -3221,6 +3208,43 @@ function isElementTarget(target) {
3221
3208
 
3222
3209
  const ALL_DIRECTIONS = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'];
3223
3210
  const KEYBOARD_STEP = 8;
3211
+ /**
3212
+ * Elements matching this selector keep their normal pointer/touch behaviour.
3213
+ * Add data-ngx-resize-ignore to any custom interactive widget that should never
3214
+ * initiate resizing when it is close to the panel edge.
3215
+ */
3216
+ const INTERACTIVE_SELECTOR = [
3217
+ 'input',
3218
+ 'textarea',
3219
+ 'select',
3220
+ 'option',
3221
+ 'button',
3222
+ 'a',
3223
+ 'summary',
3224
+ '[contenteditable="true"]',
3225
+ 'audio',
3226
+ 'video',
3227
+ 'iframe',
3228
+ 'label',
3229
+ '[role="textbox"]',
3230
+ '[role="menuitem"]',
3231
+ '[role="tab"]',
3232
+ 'mat-slider',
3233
+ 'mat-select',
3234
+ 'mat-checkbox',
3235
+ 'mat-radio-button',
3236
+ 'mat-slide-toggle',
3237
+ '.mat-mdc-slider',
3238
+ '.mat-mdc-select',
3239
+ '[role="button"]',
3240
+ '[role="slider"]',
3241
+ '[role="switch"]',
3242
+ '[role="checkbox"]',
3243
+ '[role="radio"]',
3244
+ '[role="combobox"]',
3245
+ '[role="listbox"]',
3246
+ '[data-ngx-resize-ignore]',
3247
+ ].join(',');
3224
3248
  class NgxResizable {
3225
3249
  el;
3226
3250
  disabled = model(false, /* @ts-ignore */
@@ -3250,14 +3274,16 @@ class NgxResizable {
3250
3274
  ...(ngDevMode ? [{ debugName: "resizing" }] : /* istanbul ignore next */ []));
3251
3275
  direction = 'se';
3252
3276
  start;
3253
- pointer = {
3254
- x: 0,
3255
- y: 0,
3256
- };
3277
+ pointer = { x: 0, y: 0 };
3257
3278
  beforeTransition = '';
3258
3279
  beforeWidth = '';
3259
3280
  beforeHeight = '';
3260
- beforeTransform = '';
3281
+ beforeTranslate = '';
3282
+ baseComputedTranslate = 'none';
3283
+ keyboardBaseTranslate = null;
3284
+ keyboardBaseInlineTranslate = '';
3285
+ startMatrix = { a: 1, b: 0, c: 0, d: 1 };
3286
+ pointerInverse = invertLinear({ a: 1, b: 0, c: 0, d: 1 });
3261
3287
  pointerId = -1;
3262
3288
  startWidth = 0;
3263
3289
  startHeight = 0;
@@ -3273,47 +3299,43 @@ class NgxResizable {
3273
3299
  }
3274
3300
  }
3275
3301
  onPointerDown(e) {
3276
- if (this.disabled() || e.button !== 0) {
3302
+ if (this.disabled() || e.button !== 0 || this.resizing())
3277
3303
  return;
3278
- }
3279
3304
  const dir = this.hitDirection(e);
3280
- if (!dir) {
3305
+ if (dir)
3306
+ this.beginResize(e, dir);
3307
+ }
3308
+ /** Entry point used by the typed NgxResizeHandle directive. */
3309
+ beginResize(e, direction) {
3310
+ if (this.disabled() || e.button !== 0 || this.resizing())
3311
+ return;
3312
+ const dir = resolveLogicalDirection(direction, isRtl(this.el.nativeElement));
3313
+ if (!this.resolvedDirections().includes(dir))
3281
3314
  return;
3282
- }
3283
3315
  e.preventDefault();
3284
- e.stopPropagation();
3285
- e.stopImmediatePropagation();
3286
3316
  const element = this.el.nativeElement;
3287
3317
  this.direction = dir;
3288
3318
  this.pointerId = e.pointerId;
3289
- /**
3290
- * This is the actual visual rectangle.
3291
- * It already contains any transform created by DragRef.
3292
- */
3293
3319
  this.start = element.getBoundingClientRect();
3294
- this.pointer = {
3295
- x: e.clientX,
3296
- y: e.clientY,
3297
- };
3320
+ this.pointer = { x: e.clientX, y: e.clientY };
3298
3321
  this.beforeTransition = element.style.transition;
3299
3322
  this.beforeWidth = element.style.width;
3300
3323
  this.beforeHeight = element.style.height;
3301
- this.startWidth = element.offsetWidth;
3302
- this.startHeight = element.offsetHeight;
3303
- /**
3304
- * Keep DragRef's transform as the immutable base.
3305
- *
3306
- * Resize will temporarily add its own translation
3307
- * on top of this transform.
3308
- */
3309
- this.beforeTransform = element.style.transform;
3324
+ this.beforeTranslate = element.style.translate;
3325
+ this.baseComputedTranslate =
3326
+ element.ownerDocument.defaultView?.getComputedStyle(element).translate ?? 'none';
3327
+ this.keyboardBaseTranslate = null;
3328
+ this.startMatrix = getLocalToViewportMatrix(element);
3329
+ this.pointerInverse = invertLinear(this.startMatrix);
3330
+ this.startWidth = readBorderBoxSize(element, 'x');
3331
+ this.startHeight = readBorderBoxSize(element, 'y');
3310
3332
  this.resizing.set(true);
3311
3333
  element.style.transition = 'none';
3312
3334
  try {
3313
3335
  element.setPointerCapture?.(e.pointerId);
3314
3336
  }
3315
3337
  catch {
3316
- /* synthetic / already-ended pointer: document listeners below still receive the events */
3338
+ // Document listeners remain as a fallback.
3317
3339
  }
3318
3340
  const doc = element.ownerDocument;
3319
3341
  this.removeDocumentListeners = [
@@ -3328,29 +3350,23 @@ class NgxResizable {
3328
3350
  this.resizeStart.emit(out);
3329
3351
  }
3330
3352
  onPointerMove(e) {
3331
- if (!this.resizing() || e.pointerId !== this.pointerId) {
3353
+ if (!this.resizing() || e.pointerId !== this.pointerId)
3332
3354
  return;
3333
- }
3334
3355
  const out = this.calculate(e);
3335
3356
  this.apply(out);
3336
3357
  this.resizeMove.emit(out);
3337
3358
  }
3338
3359
  onPointerUp(e) {
3339
- if (!this.resizing() || e.pointerId !== this.pointerId) {
3360
+ if (!this.resizing() || e.pointerId !== this.pointerId)
3340
3361
  return;
3341
- }
3342
3362
  const out = this.calculate(e);
3343
3363
  this.apply(out);
3344
3364
  this.resizeEnd.emit(out);
3345
3365
  this.finish();
3346
3366
  }
3347
3367
  onDocumentKeyDown(e) {
3348
- if (!this.resizing()) {
3368
+ if (!this.resizing() || e.key !== 'Escape')
3349
3369
  return;
3350
- }
3351
- if (e.key !== 'Escape') {
3352
- return;
3353
- }
3354
3370
  e.preventDefault();
3355
3371
  this.restoreBeforeResize();
3356
3372
  this.finish();
@@ -3365,115 +3381,187 @@ class NgxResizable {
3365
3381
  const element = this.el.nativeElement;
3366
3382
  element.style.width = this.beforeWidth;
3367
3383
  element.style.height = this.beforeHeight;
3368
- element.style.transform = this.beforeTransform;
3384
+ element.style.translate = this.beforeTranslate;
3369
3385
  }
3386
+ /**
3387
+ * Keyboard resizing respects the configured directions.
3388
+ * The arrow keys move the active physical edge:
3389
+ * - if only west is enabled, horizontal keys operate on west;
3390
+ * - if only east is enabled, horizontal keys operate on east;
3391
+ * - north/south follow the same rule vertically.
3392
+ * Disabled axes are never modified.
3393
+ */
3370
3394
  onHandleKeyDown(e) {
3371
- if (this.disabled()) {
3395
+ if (this.disabled() || this.resizing())
3372
3396
  return;
3373
- }
3374
- // Only when the resizable element itself is focused: arrow keys pressed inside an input /
3375
- // contenteditable that lives in the block are caret movement, not a resize request.
3376
- if (e.target !== this.el.nativeElement) {
3397
+ if (e.target !== this.el.nativeElement)
3377
3398
  return;
3378
- }
3379
- const rtl = isRtl(this.el.nativeElement);
3380
- const step = this.keyboardStep() * (e.shiftKey ? 4 : 1);
3399
+ if (this.isEditableTarget(e.target))
3400
+ return;
3401
+ const allowed = this.resolvedDirections();
3402
+ const horizontalEdge = this.chooseAxisEdge(allowed, 'x', e.key);
3403
+ const verticalEdge = this.chooseAxisEdge(allowed, 'y', e.key);
3381
3404
  let dw = 0;
3382
3405
  let dh = 0;
3383
- if (e.key === 'ArrowRight') {
3384
- dw = rtl ? -step : step;
3406
+ const configuredStep = this.keyboardStep();
3407
+ const step = (Number.isFinite(configuredStep) ? Math.max(1, configuredStep) : KEYBOARD_STEP) *
3408
+ (e.shiftKey ? 4 : 1);
3409
+ if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
3410
+ if (!horizontalEdge)
3411
+ return;
3412
+ const positive = e.key === 'ArrowRight';
3413
+ const rtl = isRtl(this.el.nativeElement);
3414
+ const physicalDelta = (positive ? 1 : -1) * (rtl ? -1 : 1);
3415
+ // East edge follows pointer direction; west edge moves the opposite way
3416
+ // relative to the resulting width.
3417
+ dw = horizontalEdge === 'e' ? physicalDelta * step : -physicalDelta * step;
3418
+ }
3419
+ else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
3420
+ if (!verticalEdge)
3421
+ return;
3422
+ const physicalDelta = e.key === 'ArrowDown' ? 1 : -1;
3423
+ dh = verticalEdge === 's' ? physicalDelta * step : -physicalDelta * step;
3385
3424
  }
3386
- else if (e.key === 'ArrowLeft') {
3387
- dw = rtl ? step : -step;
3425
+ else {
3426
+ return;
3388
3427
  }
3389
- else if (e.key === 'ArrowDown') {
3390
- dh = step;
3428
+ e.preventDefault();
3429
+ const element = this.el.nativeElement;
3430
+ const oldWidth = readBorderBoxSize(element, 'x');
3431
+ const oldHeight = readBorderBoxSize(element, 'y');
3432
+ let width = oldWidth;
3433
+ let height = oldHeight;
3434
+ if (dw !== 0) {
3435
+ width = this.clampSize(oldWidth + dw, 'x');
3436
+ }
3437
+ if (dh !== 0) {
3438
+ height = this.clampSize(oldHeight + dh, 'y');
3439
+ }
3440
+ // Keep the opposite edge fixed for west/north keyboard resizing.
3441
+ const rect = element.getBoundingClientRect();
3442
+ const matrix = getLocalToViewportMatrix(element);
3443
+ const scaleX = Math.hypot(matrix.a, matrix.b) || 1;
3444
+ const scaleY = Math.hypot(matrix.c, matrix.d) || 1;
3445
+ let moveLeft = horizontalEdge === 'w' ? (oldWidth - width) * scaleX : 0;
3446
+ let moveTop = verticalEdge === 'n' ? (oldHeight - height) * scaleY : 0;
3447
+ const boundary = this.boundary();
3448
+ if (boundary) {
3449
+ const clamped = clampResizeWithinBoundary(boundary.getBoundingClientRect(), rect, width * scaleX, height * scaleY, moveLeft, moveTop);
3450
+ width = clamped.width / scaleX;
3451
+ height = clamped.height / scaleY;
3452
+ moveLeft = clamped.left;
3453
+ moveTop = clamped.top;
3391
3454
  }
3392
- else if (e.key === 'ArrowUp') {
3393
- dh = -step;
3455
+ // Keyboard resize keeps a stable base translation and recomputes the total offset
3456
+ // on every key press. This prevents an ever-growing chain of calc()/translate values.
3457
+ if (this.keyboardBaseTranslate === null) {
3458
+ const computed = element.ownerDocument.defaultView?.getComputedStyle(element);
3459
+ this.keyboardBaseTranslate = computed?.translate ?? 'none';
3460
+ this.keyboardBaseInlineTranslate = element.style.translate;
3461
+ }
3462
+ const style = this.toStyleSize(width, height);
3463
+ element.style.width = `${style.width}px`;
3464
+ element.style.height = `${style.height}px`;
3465
+ element.style.translate = this.keyboardBaseInlineTranslate;
3466
+ // Keep the opposite edge fixed without touching `transform` (owned by NgxDraggable).
3467
+ const current = element.getBoundingClientRect();
3468
+ const correctionX = rect.left + moveLeft - current.left;
3469
+ const correctionY = rect.top + moveTop - current.top;
3470
+ if (correctionX || correctionY) {
3471
+ const local = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
3472
+ writeTranslateWithOffset(element, this.keyboardBaseTranslate, local);
3394
3473
  }
3395
3474
  else {
3396
- return;
3475
+ element.style.translate = this.keyboardBaseInlineTranslate;
3397
3476
  }
3398
- e.preventDefault();
3399
- const rect = this.el.nativeElement.getBoundingClientRect();
3400
- const width = this.clampGrid(Math.max(this.minWidth(), Math.min(this.maxWidth(), this.el.nativeElement.offsetWidth + dw)), 'x');
3401
- const height = this.clampGrid(Math.max(this.minHeight(), Math.min(this.maxHeight(), this.el.nativeElement.offsetHeight + dh)), 'y');
3402
- const styled = this.toStyleSize(width, height);
3403
- this.el.nativeElement.style.width = `${styled.width}px`;
3404
- this.el.nativeElement.style.height = `${styled.height}px`;
3405
3477
  const out = {
3406
3478
  width,
3407
3479
  height,
3408
- moveLeft: 0,
3409
- moveTop: 0,
3410
- left: rect.left,
3411
- top: rect.top,
3412
- direction: 'se',
3480
+ moveLeft,
3481
+ moveTop,
3482
+ left: rect.left + moveLeft,
3483
+ top: rect.top + moveTop,
3484
+ direction: this.keyboardDirection(horizontalEdge, verticalEdge),
3413
3485
  };
3486
+ this.resizeStart.emit(out);
3414
3487
  this.resizeMove.emit(out);
3415
3488
  this.resizeEnd.emit(out);
3416
3489
  }
3490
+ chooseAxisEdge(allowed, axis, key) {
3491
+ if (axis === 'x') {
3492
+ const hasWest = allowed.some((d) => d.includes('w'));
3493
+ const hasEast = allowed.some((d) => d.includes('e'));
3494
+ if (key === 'ArrowLeft') {
3495
+ if (hasWest)
3496
+ return 'w';
3497
+ if (hasEast)
3498
+ return 'e';
3499
+ }
3500
+ if (key === 'ArrowRight') {
3501
+ if (hasEast)
3502
+ return 'e';
3503
+ if (hasWest)
3504
+ return 'w';
3505
+ }
3506
+ }
3507
+ else {
3508
+ const hasNorth = allowed.some((d) => d.includes('n'));
3509
+ const hasSouth = allowed.some((d) => d.includes('s'));
3510
+ if (key === 'ArrowUp') {
3511
+ if (hasNorth)
3512
+ return 'n';
3513
+ if (hasSouth)
3514
+ return 's';
3515
+ }
3516
+ if (key === 'ArrowDown') {
3517
+ if (hasSouth)
3518
+ return 's';
3519
+ if (hasNorth)
3520
+ return 'n';
3521
+ }
3522
+ }
3523
+ return null;
3524
+ }
3525
+ keyboardDirection(horizontal, vertical) {
3526
+ if (horizontal && vertical)
3527
+ return `${vertical}${horizontal}`;
3528
+ return horizontal ?? vertical ?? 'se';
3529
+ }
3530
+ isEditableTarget(target) {
3531
+ if (!isElementTarget(target))
3532
+ return false;
3533
+ return !!target.closest(INTERACTIVE_SELECTOR);
3534
+ }
3417
3535
  calculate(e) {
3418
- const localDelta = viewportDeltaToLocal(this.el.nativeElement, {
3536
+ const delta = applyLinear(this.pointerInverse, {
3419
3537
  x: e.clientX - this.pointer.x,
3420
3538
  y: e.clientY - this.pointer.y,
3421
3539
  });
3422
- const dx = localDelta.x;
3423
- const dy = localDelta.y;
3424
3540
  let width = this.startWidth;
3425
3541
  let height = this.startHeight;
3426
- /**
3427
- * East
3428
- */
3429
- if (this.direction.includes('e')) {
3430
- width += dx;
3431
- }
3432
- /**
3433
- * West
3434
- */
3435
- if (this.direction.includes('w')) {
3436
- width -= dx;
3437
- }
3438
- /**
3439
- * South
3440
- */
3441
- if (this.direction.includes('s')) {
3442
- height += dy;
3443
- }
3444
- /**
3445
- * North
3446
- */
3447
- if (this.direction.includes('n')) {
3448
- height -= dy;
3449
- }
3450
- width = this.clampGrid(Math.max(this.minWidth(), Math.min(this.maxWidth(), width)), 'x');
3451
- height = this.clampGrid(Math.max(this.minHeight(), Math.min(this.maxHeight(), height)), 'y');
3452
- /**
3453
- * Calculate the intended visual position.
3454
- *
3455
- * This is useful for boundary calculations and
3456
- * emitted resize events.
3457
- */
3458
- const matrix = getLocalToViewportMatrix(this.el.nativeElement);
3459
- const scaleX = Math.hypot(matrix.a, matrix.b) || 1;
3460
- const scaleY = Math.hypot(matrix.c, matrix.d) || 1;
3542
+ if (this.direction.includes('e'))
3543
+ width += delta.x;
3544
+ if (this.direction.includes('w'))
3545
+ width -= delta.x;
3546
+ if (this.direction.includes('s'))
3547
+ height += delta.y;
3548
+ if (this.direction.includes('n'))
3549
+ height -= delta.y;
3550
+ width = this.clampSize(width, 'x');
3551
+ height = this.clampSize(height, 'y');
3552
+ const scaleX = Math.hypot(this.startMatrix.a, this.startMatrix.b) || 1;
3553
+ const scaleY = Math.hypot(this.startMatrix.c, this.startMatrix.d) || 1;
3461
3554
  let left = this.start.left;
3462
3555
  let top = this.start.top;
3463
- if (this.direction.includes('w')) {
3556
+ if (this.direction.includes('w'))
3464
3557
  left = this.start.right - width * scaleX;
3465
- }
3466
- if (this.direction.includes('n')) {
3558
+ if (this.direction.includes('n'))
3467
3559
  top = this.start.bottom - height * scaleY;
3468
- }
3469
3560
  let moveLeft = left - this.start.left;
3470
3561
  let moveTop = top - this.start.top;
3471
- /**
3472
- * Boundary constraint.
3473
- */
3474
- const boundaryEl = this.boundary();
3475
- if (boundaryEl) {
3476
- const clamped = clampResizeWithinBoundary(boundaryEl.getBoundingClientRect(), this.start, width * scaleX, height * scaleY, moveLeft, moveTop);
3562
+ const boundary = this.boundary();
3563
+ if (boundary) {
3564
+ const clamped = clampResizeWithinBoundary(boundary.getBoundingClientRect(), this.start, width * scaleX, height * scaleY, moveLeft, moveTop);
3477
3565
  width = clamped.width / scaleX;
3478
3566
  height = clamped.height / scaleY;
3479
3567
  moveLeft = clamped.left;
@@ -3493,63 +3581,22 @@ class NgxResizable {
3493
3581
  }
3494
3582
  apply(out) {
3495
3583
  const element = this.el.nativeElement;
3496
- /**
3497
- * Always reset to the transform that existed before
3498
- * this resize operation started.
3499
- *
3500
- * This prevents resize corrections from accumulating.
3501
- */
3502
- element.style.transform = this.beforeTransform;
3503
- /**
3504
- * Apply the actual size first.
3505
- *
3506
- * Changing width/height may cause the browser to re-layout
3507
- * the element, especially for relative/flex/grid/static layouts.
3508
- */
3584
+ element.style.translate = this.beforeTranslate;
3509
3585
  const style = this.toStyleSize(out.width, out.height);
3510
3586
  element.style.width = `${style.width}px`;
3511
3587
  element.style.height = `${style.height}px`;
3512
- /**
3513
- * Force/read layout after changing the size.
3514
- */
3515
3588
  const current = element.getBoundingClientRect();
3516
- /**
3517
- * These are the positions where the element MUST visually be.
3518
- *
3519
- * `out.moveLeft` / `out.moveTop` are calculated in `calculate()`
3520
- * from the original visual rectangle.
3521
- */
3522
3589
  const targetLeft = this.start.left + out.moveLeft;
3523
3590
  const targetTop = this.start.top + out.moveTop;
3524
- /**
3525
- * Browser's actual position after width/height changed.
3526
- *
3527
- * The difference between target and current position is the
3528
- * correction that must be applied using transform.
3529
- */
3530
3591
  const correctionX = targetLeft - current.left;
3531
3592
  const correctionY = targetTop - current.top;
3532
- const hasCorrection = correctionX !== 0 || correctionY !== 0;
3533
- if (!hasCorrection) {
3534
- element.style.transform = this.beforeTransform;
3593
+ if (!correctionX && !correctionY) {
3594
+ element.style.translate = this.beforeTranslate;
3535
3595
  return;
3536
3596
  }
3537
- /**
3538
- * Preserve DragRef's existing transform and add only the
3539
- * correction required by Resize.
3540
- */
3541
- const baseTransform = this.beforeTransform && this.beforeTransform !== 'none' ? `${this.beforeTransform} ` : '';
3542
- const localCorrection = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
3543
- element.style.transform =
3544
- `${baseTransform}translate3d(` + `${localCorrection.x}px, ` + `${localCorrection.y}px, 0)`;
3597
+ const local = viewportDeltaToLocal(element, { x: correctionX, y: correctionY });
3598
+ writeTranslateWithOffset(element, this.baseComputedTranslate, local);
3545
3599
  }
3546
- /**
3547
- * `offsetWidth/Height` (what we measure and report) are BORDER-box sizes. The inline
3548
- * `width/height` we write are interpreted according to `box-sizing`: for the CSS default
3549
- * (`content-box`) writing the border-box number would make a padded/bordered block jump by
3550
- * its padding+border the instant a resize starts. Convert so the box is exactly the size
3551
- * reported in `IResizableOutput`.
3552
- */
3553
3600
  toStyleSize(width, height) {
3554
3601
  const el = this.el.nativeElement;
3555
3602
  const cs = el.ownerDocument.defaultView?.getComputedStyle(el);
@@ -3558,17 +3605,25 @@ class NgxResizable {
3558
3605
  const px = (v) => Number.parseFloat(v) || 0;
3559
3606
  const extraX = px(cs.paddingLeft) + px(cs.paddingRight) + px(cs.borderLeftWidth) + px(cs.borderRightWidth);
3560
3607
  const extraY = px(cs.paddingTop) + px(cs.paddingBottom) + px(cs.borderTopWidth) + px(cs.borderBottomWidth);
3561
- return { width: Math.max(0, width - extraX), height: Math.max(0, height - extraY) };
3608
+ return {
3609
+ width: Math.max(0, width - extraX),
3610
+ height: Math.max(0, height - extraY),
3611
+ };
3562
3612
  }
3563
- clampGrid(value, axis) {
3564
- const g = this.grid();
3565
- // NOTE: the previous code returned the input *signal function* for a numeric grid, so every
3566
- // snapped size became NaN and the resize silently stopped working.
3567
- const grid = typeof g === 'number' ? g : g?.[axis];
3568
- if (!grid || !Number.isFinite(grid) || grid <= 0) {
3569
- return value;
3570
- }
3571
- return Math.round(value / grid) * grid;
3613
+ clampSize(value, axis) {
3614
+ const minInput = axis === 'x' ? this.minWidth() : this.minHeight();
3615
+ const maxInput = axis === 'x' ? this.maxWidth() : this.maxHeight();
3616
+ const min = Number.isFinite(minInput) ? Math.max(0, minInput) : 0;
3617
+ const max = Number.isFinite(maxInput) ? Math.max(min, maxInput) : Infinity;
3618
+ const bounded = Math.min(max, Math.max(min, Number.isFinite(value) ? value : min));
3619
+ const grid = this.grid();
3620
+ const step = typeof grid === 'number' ? grid : grid?.[axis];
3621
+ if (!step || !Number.isFinite(step) || step <= 0)
3622
+ return bounded;
3623
+ // Snap relative to the minimum, then clamp again so grid rounding can never
3624
+ // violate the configured min/max constraints.
3625
+ const snapped = min + Math.round((bounded - min) / step) * step;
3626
+ return Math.min(max, Math.max(min, snapped));
3572
3627
  }
3573
3628
  finish() {
3574
3629
  this.resizing.set(false);
@@ -3584,9 +3639,12 @@ class NgxResizable {
3584
3639
  }
3585
3640
  }
3586
3641
  catch {
3587
- /* already released */
3642
+ // Pointer capture may already have been released.
3588
3643
  }
3589
- this.beforeTransform = '';
3644
+ this.beforeTranslate = '';
3645
+ this.baseComputedTranslate = 'none';
3646
+ this.keyboardBaseTranslate = null;
3647
+ this.keyboardBaseInlineTranslate = '';
3590
3648
  }
3591
3649
  resolvedDirections() {
3592
3650
  const rtl = isRtl(this.el.nativeElement);
@@ -3598,68 +3656,59 @@ class NgxResizable {
3598
3656
  }
3599
3657
  hitDirection(e) {
3600
3658
  const element = this.el.nativeElement;
3601
- const rect = element.getBoundingClientRect();
3602
- const edge = Math.min(12, Math.max(6, Math.min(rect.width, rect.height) * 0.18));
3603
- const isLeft = e.clientX - rect.left <= edge;
3604
- const isRight = rect.right - e.clientX <= edge;
3605
- const isTop = e.clientY - rect.top <= edge;
3606
- const isBottom = rect.bottom - e.clientY <= edge;
3607
- /**
3608
- * Explicit resize handle has priority.
3609
- */
3610
- // TODO notsafe instanceof:node.nodeType === Node.ELEMENT_NODE
3611
- const handle = isHTMLElementTarget(e.target)
3612
- ? e.target.closest('[data-ngx-resize-handle]')
3659
+ const target = e.target;
3660
+ // Explicit handles are allowed even when they are inside the panel.
3661
+ const handle = isElementTarget(target)
3662
+ ? target.closest('[data-ngx-resize-handle]')
3613
3663
  : null;
3614
3664
  if (handle && element.contains(handle)) {
3615
3665
  const raw = handle.dataset['ngxResizeHandle'];
3616
- if (!raw) {
3666
+ if (!raw)
3617
3667
  return null;
3618
- }
3619
3668
  const resolved = resolveLogicalDirection(raw, isRtl(element));
3620
3669
  return this.resolvedDirections().includes(resolved) ? resolved : null;
3621
3670
  }
3622
- /**
3623
- * These are PHYSICAL screen directions.
3624
- *
3625
- * left -> w
3626
- * right -> e
3627
- *
3628
- * RTL is handled only when a logical direction
3629
- * such as "start" / "end" is requested.
3630
- */
3631
- const direction = isTop && isLeft
3632
- ? 'nw'
3633
- : isTop && isRight
3634
- ? 'ne'
3635
- : isBottom && isLeft
3636
- ? 'sw'
3637
- : isBottom && isRight
3638
- ? 'se'
3639
- : isTop
3640
- ? 'n'
3641
- : isRight
3642
- ? 'e'
3643
- : isBottom
3644
- ? 's'
3645
- : isLeft
3646
- ? 'w'
3647
- : null;
3648
- if (!direction) {
3671
+ // Never steal pointer events from nested interactive controls.
3672
+ if (isElementTarget(target) && target.closest(INTERACTIVE_SELECTOR))
3649
3673
  return null;
3650
- }
3651
- return this.resolvedDirections().includes(direction) ? direction : null;
3674
+ const rect = element.getBoundingClientRect();
3675
+ const edge = Math.min(12, Math.max(6, Math.min(rect.width, rect.height) * 0.18));
3676
+ const isLeft = e.clientX - rect.left <= edge;
3677
+ const isRight = rect.right - e.clientX <= edge;
3678
+ const isTop = e.clientY - rect.top <= edge;
3679
+ const isBottom = rect.bottom - e.clientY <= edge;
3680
+ const candidates = [];
3681
+ if (isTop && isLeft)
3682
+ candidates.push('nw', 'n', 'w');
3683
+ else if (isTop && isRight)
3684
+ candidates.push('ne', 'n', 'e');
3685
+ else if (isBottom && isLeft)
3686
+ candidates.push('sw', 's', 'w');
3687
+ else if (isBottom && isRight)
3688
+ candidates.push('se', 's', 'e');
3689
+ else if (isTop)
3690
+ candidates.push('n');
3691
+ else if (isRight)
3692
+ candidates.push('e');
3693
+ else if (isBottom)
3694
+ candidates.push('s');
3695
+ else if (isLeft)
3696
+ candidates.push('w');
3697
+ const allowed = new Set(this.resolvedDirections());
3698
+ return candidates.find((candidate) => allowed.has(candidate)) ?? null;
3652
3699
  }
3653
3700
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
3654
- 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: { "style.touch-action": "\"none\"" }, classAttribute: "ngx-resizable" }, ngImport: i0 });
3701
+ 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 });
3655
3702
  }
3656
3703
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizable, decorators: [{
3657
3704
  type: Directive,
3658
3705
  args: [{
3659
3706
  selector: '[NgxResizable],[ngxResizable]',
3660
3707
  host: {
3661
- '[style.touch-action]': '"none"',
3662
3708
  class: 'ngx-resizable',
3709
+ // Do not set touch-action:none on the whole panel: it breaks nested controls.
3710
+ // '[style.touch-action]': '"none"',
3711
+ '[attr.aria-keyshortcuts]': '"ArrowLeft ArrowRight ArrowUp ArrowDown"',
3663
3712
  },
3664
3713
  }]
3665
3714
  }], 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: [{
@@ -3669,13 +3718,72 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
3669
3718
  type: HostListener,
3670
3719
  args: ['keydown', ['$event']]
3671
3720
  }] } });
3672
- function isHTMLElementTarget(target) {
3721
+ function isElementTarget(target) {
3673
3722
  return (!!target &&
3674
3723
  typeof target === 'object' &&
3675
3724
  'nodeType' in target &&
3676
3725
  target.nodeType === 1 &&
3677
3726
  'closest' in target);
3678
3727
  }
3728
+ function readBorderBoxSize(element, axis) {
3729
+ const win = element.ownerDocument.defaultView;
3730
+ const style = win?.getComputedStyle(element);
3731
+ if (!style)
3732
+ return axis === 'x' ? element.offsetWidth : element.offsetHeight;
3733
+ const horizontal = axis === 'x';
3734
+ const size = Number.parseFloat(horizontal ? style.width : style.height) || 0;
3735
+ if (style.boxSizing === 'border-box')
3736
+ return size;
3737
+ const px = (value) => Number.parseFloat(value) || 0;
3738
+ return (size +
3739
+ (horizontal
3740
+ ? px(style.paddingLeft) +
3741
+ px(style.paddingRight) +
3742
+ px(style.borderLeftWidth) +
3743
+ px(style.borderRightWidth)
3744
+ : px(style.paddingTop) +
3745
+ px(style.paddingBottom) +
3746
+ px(style.borderTopWidth) +
3747
+ px(style.borderBottomWidth)));
3748
+ }
3749
+ /**
3750
+ * Compose a resize-only offset with the existing CSS individual `translate` value.
3751
+ * Keeping the original CSS tokens (instead of parseFloat) preserves percentages, calc(),
3752
+ * and variables. The `transform` channel remains exclusively owned by NgxDraggable.
3753
+ */
3754
+ function writeTranslateWithOffset(element, baseValue, offset) {
3755
+ const [baseX, baseY, baseZ] = splitCssComponents(!baseValue || baseValue === 'none' ? '0px 0px 0px' : baseValue);
3756
+ const x = offset.x ? `calc(${baseX ?? '0px'} ${formatOffset(offset.x)})` : (baseX ?? '0px');
3757
+ const y = offset.y ? `calc(${baseY ?? '0px'} ${formatOffset(offset.y)})` : (baseY ?? '0px');
3758
+ element.style.translate = `${x} ${y} ${baseZ ?? '0px'}`;
3759
+ }
3760
+ function splitCssComponents(value) {
3761
+ const result = [];
3762
+ let depth = 0;
3763
+ let token = '';
3764
+ for (const char of value.trim()) {
3765
+ if (char === '(')
3766
+ depth++;
3767
+ if (char === ')')
3768
+ depth = Math.max(0, depth - 1);
3769
+ if (/\s/.test(char) && depth === 0) {
3770
+ if (token)
3771
+ result.push(token);
3772
+ token = '';
3773
+ }
3774
+ else {
3775
+ token += char;
3776
+ }
3777
+ }
3778
+ if (token)
3779
+ result.push(token);
3780
+ return result;
3781
+ }
3782
+ function formatOffset(value) {
3783
+ return value < 0
3784
+ ? `- ${Number(Math.abs(value).toFixed(4))}px`
3785
+ : `+ ${Number(value.toFixed(4))}px`;
3786
+ }
3679
3787
 
3680
3788
  const NGX_PLACEHOLDER = new InjectionToken('ngx-place-holder');
3681
3789
  /**
@@ -3819,6 +3927,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
3819
3927
  }]
3820
3928
  }] });
3821
3929
 
3930
+ /**
3931
+ * Typed handle API. Prefer ngxResizeHandle="se" in templates; the legacy
3932
+ * data-ngx-resize-handle attribute remains available for backwards compatibility.
3933
+ */
3934
+ class NgxResizeHandle {
3935
+ ngxResizeHandle = input.required(/* @ts-ignore */
3936
+ ...(ngDevMode ? [{ debugName: "ngxResizeHandle" }] : /* istanbul ignore next */ []));
3937
+ parent = inject(NgxResizable, { optional: true, skipSelf: true });
3938
+ onPointerDown(event) {
3939
+ this.parent?.beginResize(event, this.ngxResizeHandle());
3940
+ }
3941
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizeHandle, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3942
+ 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 });
3943
+ }
3944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxResizeHandle, decorators: [{
3945
+ type: Directive,
3946
+ args: [{
3947
+ selector: '[ngxResizeHandle]',
3948
+ standalone: true,
3949
+ host: {
3950
+ '[style.touch-action]': '"none"',
3951
+ '[style.user-select]': '"none"',
3952
+ },
3953
+ }]
3954
+ }], propDecorators: { ngxResizeHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngxResizeHandle", required: true }] }], onPointerDown: [{
3955
+ type: HostListener,
3956
+ args: ['pointerdown', ['$event']]
3957
+ }] } });
3958
+
3822
3959
  function moveItemInArray(array, from, to) {
3823
3960
  const f = clamp(from, array.length - 1);
3824
3961
  const t = clamp(to, array.length - 1);
@@ -3904,5 +4041,5 @@ function getCleanHtml(el, options) {
3904
4041
  * Generated bundle index. Do not edit.
3905
4042
  */
3906
4043
 
3907
- 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, findScrollableAncestorForAxis, getCleanHtml, getPageZoom, getScrollPosition, isRtl, moveItemInArray, resolveLogicalDirection, stripEditorArtifacts, transferArrayItem };
4044
+ 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 };
3908
4045
  //# sourceMappingURL=ngx-kit-drag-resize.mjs.map