@angular/cdk 19.0.2 → 19.0.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, Component, ViewEncapsulation, ChangeDetectionStrategy, inject, NgZone, Injectable, InjectionToken, ElementRef, booleanAttribute, Directive, Input, ViewContainerRef, ChangeDetectorRef, EventEmitter, Injector, afterNextRender, numberAttribute, Output, TemplateRef, NgModule } from '@angular/core';
2
+ import { signal, Component, ViewEncapsulation, ChangeDetectionStrategy, inject, NgZone, Injectable, RendererFactory2, InjectionToken, ElementRef, booleanAttribute, Directive, Input, ViewContainerRef, ChangeDetectorRef, EventEmitter, Injector, afterNextRender, numberAttribute, Output, TemplateRef, NgModule } from '@angular/core';
3
3
  import { DOCUMENT } from '@angular/common';
4
4
  import { ViewportRuler, ScrollDispatcher, CdkScrollableModule } from '@angular/cdk/scrolling';
5
5
  import { isFakeTouchstartFromScreenReader, isFakeMousedownFromScreenReader, _IdGenerator } from '@angular/cdk/a11y';
@@ -333,6 +333,7 @@ class PreviewRef {
333
333
  _pickupPositionOnPage;
334
334
  _initialTransform;
335
335
  _zIndex;
336
+ _renderer;
336
337
  /** Reference to the view of the preview element. */
337
338
  _previewEmbeddedView;
338
339
  /** Reference to the preview element. */
@@ -340,7 +341,7 @@ class PreviewRef {
340
341
  get element() {
341
342
  return this._preview;
342
343
  }
343
- constructor(_document, _rootElement, _direction, _initialDomRect, _previewTemplate, _previewClass, _pickupPositionOnPage, _initialTransform, _zIndex) {
344
+ constructor(_document, _rootElement, _direction, _initialDomRect, _previewTemplate, _previewClass, _pickupPositionOnPage, _initialTransform, _zIndex, _renderer) {
344
345
  this._document = _document;
345
346
  this._rootElement = _rootElement;
346
347
  this._direction = _direction;
@@ -350,6 +351,7 @@ class PreviewRef {
350
351
  this._pickupPositionOnPage = _pickupPositionOnPage;
351
352
  this._initialTransform = _initialTransform;
352
353
  this._zIndex = _zIndex;
354
+ this._renderer = _renderer;
353
355
  }
354
356
  attach(parent) {
355
357
  this._preview = this._createPreview();
@@ -378,10 +380,7 @@ class PreviewRef {
378
380
  return getTransformTransitionDurationInMs(this._preview);
379
381
  }
380
382
  addEventListener(name, handler) {
381
- this._preview.addEventListener(name, handler);
382
- }
383
- removeEventListener(name, handler) {
384
- this._preview.removeEventListener(name, handler);
383
+ return this._renderer.listen(this._preview, name, handler);
385
384
  }
386
385
  _createPreview() {
387
386
  const previewConfig = this._previewTemplate;
@@ -475,6 +474,7 @@ class DragRef {
475
474
  _ngZone;
476
475
  _viewportRuler;
477
476
  _dragDropRegistry;
477
+ _renderer;
478
478
  /** Element displayed next to the user's pointer while the element is dragged. */
479
479
  _preview;
480
480
  /** Container into which to insert the preview. */
@@ -638,12 +638,13 @@ class DragRef {
638
638
  * Should return a point describing where the item should be rendered.
639
639
  */
640
640
  constrainPosition;
641
- constructor(element, _config, _document, _ngZone, _viewportRuler, _dragDropRegistry) {
641
+ constructor(element, _config, _document, _ngZone, _viewportRuler, _dragDropRegistry, _renderer) {
642
642
  this._config = _config;
643
643
  this._document = _document;
644
644
  this._ngZone = _ngZone;
645
645
  this._viewportRuler = _viewportRuler;
646
646
  this._dragDropRegistry = _dragDropRegistry;
647
+ this._renderer = _renderer;
647
648
  this.withRootElement(element).withParent(_config.parentDragRef || null);
648
649
  this._parentPositions = new ParentPositionTracker(_document);
649
650
  _dragDropRegistry.registerDragItem(this);
@@ -1040,7 +1041,7 @@ class DragRef {
1040
1041
  this._initialTransform = element.style.transform || '';
1041
1042
  // Create the preview after the initial transform has
1042
1043
  // been cached, because it can be affected by the transform.
1043
- this._preview = new PreviewRef(this._document, this._rootElement, this._direction, this._initialDomRect, this._previewTemplate || null, this.previewClass || null, this._pickupPositionOnPage, this._initialTransform, this._config.zIndex || 1000);
1044
+ this._preview = new PreviewRef(this._document, this._rootElement, this._direction, this._initialDomRect, this._previewTemplate || null, this.previewClass || null, this._pickupPositionOnPage, this._initialTransform, this._config.zIndex || 1000, this._renderer);
1044
1045
  this._preview.attach(this._getPreviewInsertionPoint(parent, shadowRoot));
1045
1046
  // We move the element out at the end of the body and we make it hidden, because keeping it in
1046
1047
  // place will throw off the consumer's `:last-child` selectors. We can't remove the element
@@ -1244,21 +1245,21 @@ class DragRef {
1244
1245
  }
1245
1246
  return this._ngZone.runOutsideAngular(() => {
1246
1247
  return new Promise(resolve => {
1247
- const handler = ((event) => {
1248
+ const handler = (event) => {
1248
1249
  if (!event ||
1249
1250
  (this._preview &&
1250
1251
  _getEventTarget(event) === this._preview.element &&
1251
1252
  event.propertyName === 'transform')) {
1252
- this._preview?.removeEventListener('transitionend', handler);
1253
+ cleanupListener();
1253
1254
  resolve();
1254
1255
  clearTimeout(timeout);
1255
1256
  }
1256
- });
1257
+ };
1257
1258
  // If a transition is short enough, the browser might not fire the `transitionend` event.
1258
1259
  // Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
1259
1260
  // fire if the transition hasn't completed when it was supposed to.
1260
1261
  const timeout = setTimeout(handler, duration * 1.5);
1261
- this._preview.addEventListener('transitionend', handler);
1262
+ const cleanupListener = this._preview.addEventListener('transitionend', handler);
1262
1263
  });
1263
1264
  });
1264
1265
  }
@@ -2988,6 +2989,12 @@ class DragDropRegistry {
2988
2989
  * because it'll be called a lot and we don't want to create a new function every time.
2989
2990
  */
2990
2991
  _draggingPredicate = (item) => item.isDragging();
2992
+ /**
2993
+ * Map tracking DOM nodes and their corresponding drag directives. Note that this is different
2994
+ * from looking through the `_dragInstances` and getting their root node, because the root node
2995
+ * isn't necessarily the node that the directive is set on.
2996
+ */
2997
+ _domNodesToDirectives = null;
2991
2998
  /**
2992
2999
  * Emits the `touchmove` or `mousemove` events that are dispatched
2993
3000
  * while the user is dragging a drag item instance.
@@ -3050,15 +3057,22 @@ class DragDropRegistry {
3050
3057
  this._styleLoader.load(_ResetsLoader);
3051
3058
  this._activeDragInstances.update(instances => [...instances, drag]);
3052
3059
  if (this._activeDragInstances().length === 1) {
3053
- const isTouchEvent = event.type.startsWith('touch');
3054
3060
  // We explicitly bind __active__ listeners here, because newer browsers will default to
3055
3061
  // passive ones for `mousemove` and `touchmove`. The events need to be active, because we
3056
3062
  // use `preventDefault` to prevent the page from scrolling while the user is dragging.
3057
- this._globalListeners
3058
- .set(isTouchEvent ? 'touchend' : 'mouseup', {
3063
+ const isTouchEvent = event.type.startsWith('touch');
3064
+ const endEventHandler = {
3059
3065
  handler: (e) => this.pointerUp.next(e),
3060
3066
  options: true,
3061
- })
3067
+ };
3068
+ if (isTouchEvent) {
3069
+ this._globalListeners.set('touchend', endEventHandler);
3070
+ this._globalListeners.set('touchcancel', endEventHandler);
3071
+ }
3072
+ else {
3073
+ this._globalListeners.set('mouseup', endEventHandler);
3074
+ }
3075
+ this._globalListeners
3062
3076
  .set('scroll', {
3063
3077
  handler: (e) => this.scroll.next(e),
3064
3078
  // Use capturing so that we pick up scroll changes in any scrollable nodes that aren't
@@ -3136,9 +3150,33 @@ class DragDropRegistry {
3136
3150
  }
3137
3151
  return merge(...streams);
3138
3152
  }
3153
+ /**
3154
+ * Tracks the DOM node which has a draggable directive.
3155
+ * @param node Node to track.
3156
+ * @param dragRef Drag directive set on the node.
3157
+ */
3158
+ registerDirectiveNode(node, dragRef) {
3159
+ this._domNodesToDirectives ??= new WeakMap();
3160
+ this._domNodesToDirectives.set(node, dragRef);
3161
+ }
3162
+ /**
3163
+ * Stops tracking a draggable directive node.
3164
+ * @param node Node to stop tracking.
3165
+ */
3166
+ removeDirectiveNode(node) {
3167
+ this._domNodesToDirectives?.delete(node);
3168
+ }
3169
+ /**
3170
+ * Gets the drag directive corresponding to a specific DOM node, if any.
3171
+ * @param node Node for which to do the lookup.
3172
+ */
3173
+ getDragDirectiveForNode(node) {
3174
+ return this._domNodesToDirectives?.get(node) || null;
3175
+ }
3139
3176
  ngOnDestroy() {
3140
3177
  this._dragInstances.forEach(instance => this.removeDragItem(instance));
3141
3178
  this._dropInstances.forEach(instance => this.removeDropContainer(instance));
3179
+ this._domNodesToDirectives = null;
3142
3180
  this._clearGlobalListeners();
3143
3181
  this.pointerMove.complete();
3144
3182
  this.pointerUp.complete();
@@ -3192,6 +3230,7 @@ class DragDrop {
3192
3230
  _ngZone = inject(NgZone);
3193
3231
  _viewportRuler = inject(ViewportRuler);
3194
3232
  _dragDropRegistry = inject(DragDropRegistry);
3233
+ _renderer = inject(RendererFactory2).createRenderer(null, null);
3195
3234
  constructor() { }
3196
3235
  /**
3197
3236
  * Turns an element into a draggable item.
@@ -3199,7 +3238,7 @@ class DragDrop {
3199
3238
  * @param config Object used to configure the dragging behavior.
3200
3239
  */
3201
3240
  createDrag(element, config = DEFAULT_CONFIG) {
3202
- return new DragRef(element, config, this._document, this._ngZone, this._viewportRuler, this._dragDropRegistry);
3241
+ return new DragRef(element, config, this._document, this._ngZone, this._viewportRuler, this._dragDropRegistry, this._renderer);
3203
3242
  }
3204
3243
  /**
3205
3244
  * Turns an element into a drop list.
@@ -3245,6 +3284,7 @@ const CDK_DRAG_HANDLE = new InjectionToken('CdkDragHandle');
3245
3284
  class CdkDragHandle {
3246
3285
  element = inject(ElementRef);
3247
3286
  _parentDrag = inject(CDK_DRAG_PARENT, { optional: true, skipSelf: true });
3287
+ _dragDropRegistry = inject(DragDropRegistry);
3248
3288
  /** Emits when the state of the handle has changed. */
3249
3289
  _stateChanges = new Subject();
3250
3290
  /** Whether starting to drag through this handle is disabled. */
@@ -3262,6 +3302,20 @@ class CdkDragHandle {
3262
3302
  }
3263
3303
  this._parentDrag?._addHandle(this);
3264
3304
  }
3305
+ ngAfterViewInit() {
3306
+ if (!this._parentDrag) {
3307
+ let parent = this.element.nativeElement.parentElement;
3308
+ while (parent) {
3309
+ const ref = this._dragDropRegistry.getDragDirectiveForNode(parent);
3310
+ if (ref) {
3311
+ this._parentDrag = ref;
3312
+ ref._addHandle(this);
3313
+ break;
3314
+ }
3315
+ parent = parent.parentElement;
3316
+ }
3317
+ }
3318
+ }
3265
3319
  ngOnDestroy() {
3266
3320
  this._parentDrag?._removeHandle(this);
3267
3321
  this._stateChanges.complete();
@@ -3289,7 +3343,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
3289
3343
  */
3290
3344
  const CDK_DRAG_CONFIG = new InjectionToken('CDK_DRAG_CONFIG');
3291
3345
 
3292
- const DRAG_HOST_CLASS = 'cdk-drag';
3293
3346
  /**
3294
3347
  * Injection token that can be used to reference instances of `CdkDropList`. It serves as
3295
3348
  * alternative token to the actual `CdkDropList` class which could cause unnecessary
@@ -3306,8 +3359,8 @@ class CdkDrag {
3306
3359
  _changeDetectorRef = inject(ChangeDetectorRef);
3307
3360
  _selfHandle = inject(CDK_DRAG_HANDLE, { optional: true, self: true });
3308
3361
  _parentDrag = inject(CDK_DRAG_PARENT, { optional: true, skipSelf: true });
3362
+ _dragDropRegistry = inject(DragDropRegistry);
3309
3363
  _destroyed = new Subject();
3310
- static _dragInstances = [];
3311
3364
  _handles = new BehaviorSubject([]);
3312
3365
  _previewTemplate;
3313
3366
  _placeholderTemplate;
@@ -3420,10 +3473,7 @@ class CdkDrag {
3420
3473
  zIndex: config?.zIndex,
3421
3474
  });
3422
3475
  this._dragRef.data = this;
3423
- // We have to keep track of the drag instances in order to be able to match an element to
3424
- // a drag instance. We can't go through the global registry of `DragRef`, because the root
3425
- // element could be different.
3426
- CdkDrag._dragInstances.push(this);
3476
+ this._dragDropRegistry.registerDirectiveNode(this.element.nativeElement, this);
3427
3477
  if (config) {
3428
3478
  this._assignDefaults(config);
3429
3479
  }
@@ -3507,10 +3557,7 @@ class CdkDrag {
3507
3557
  if (this.dropContainer) {
3508
3558
  this.dropContainer.removeItem(this);
3509
3559
  }
3510
- const index = CdkDrag._dragInstances.indexOf(this);
3511
- if (index > -1) {
3512
- CdkDrag._dragInstances.splice(index, 1);
3513
- }
3560
+ this._dragDropRegistry.removeDirectiveNode(this.element.nativeElement);
3514
3561
  // Unnecessary in most cases, but used to avoid extra change detections with `zone-paths-rxjs`.
3515
3562
  this._ngZone.runOutsideAngular(() => {
3516
3563
  this._handles.complete();
@@ -3626,10 +3673,9 @@ class CdkDrag {
3626
3673
  // the item was projected into another item by something like `ngTemplateOutlet`.
3627
3674
  let parent = this.element.nativeElement.parentElement;
3628
3675
  while (parent) {
3629
- if (parent.classList.contains(DRAG_HOST_CLASS)) {
3630
- ref.withParent(CdkDrag._dragInstances.find(drag => {
3631
- return drag.element.nativeElement === parent;
3632
- })?._dragRef || null);
3676
+ const parentDrag = this._dragDropRegistry.getDragDirectiveForNode(parent);
3677
+ if (parentDrag) {
3678
+ ref.withParent(parentDrag._dragRef);
3633
3679
  break;
3634
3680
  }
3635
3681
  parent = parent.parentElement;
@@ -3745,7 +3791,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.0", ngImpor
3745
3791
  selector: '[cdkDrag]',
3746
3792
  exportAs: 'cdkDrag',
3747
3793
  host: {
3748
- 'class': DRAG_HOST_CLASS,
3794
+ 'class': 'cdk-drag',
3749
3795
  '[class.cdk-drag-disabled]': 'disabled',
3750
3796
  '[class.cdk-drag-dragging]': '_dragRef.isDragging()',
3751
3797
  },