@angular/cdk 7.1.1 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/LICENSE +1 -1
  2. package/_a11y.scss +1 -1
  3. package/a11y/typings/focus-monitor/focus-monitor.d.ts +0 -1
  4. package/a11y/typings/focus-trap/focus-trap.d.ts +2 -0
  5. package/a11y/typings/index.metadata.json +1 -1
  6. package/bundles/cdk-a11y.umd.js +30 -24
  7. package/bundles/cdk-a11y.umd.js.map +1 -1
  8. package/bundles/cdk-a11y.umd.min.js +1 -1
  9. package/bundles/cdk-a11y.umd.min.js.map +1 -1
  10. package/bundles/cdk-coercion.umd.js +20 -4
  11. package/bundles/cdk-coercion.umd.js.map +1 -1
  12. package/bundles/cdk-coercion.umd.min.js +1 -1
  13. package/bundles/cdk-coercion.umd.min.js.map +1 -1
  14. package/bundles/cdk-drag-drop.umd.js +3246 -1894
  15. package/bundles/cdk-drag-drop.umd.js.map +1 -1
  16. package/bundles/cdk-drag-drop.umd.min.js +2 -1
  17. package/bundles/cdk-drag-drop.umd.min.js.map +1 -1
  18. package/bundles/cdk-observers.umd.js +2 -2
  19. package/bundles/cdk-observers.umd.js.map +1 -1
  20. package/bundles/cdk-observers.umd.min.js +1 -1
  21. package/bundles/cdk-observers.umd.min.js.map +1 -1
  22. package/bundles/cdk-overlay.umd.js +107 -45
  23. package/bundles/cdk-overlay.umd.js.map +1 -1
  24. package/bundles/cdk-overlay.umd.min.js +2 -2
  25. package/bundles/cdk-overlay.umd.min.js.map +1 -1
  26. package/bundles/cdk-portal.umd.js +3 -3
  27. package/bundles/cdk-portal.umd.js.map +1 -1
  28. package/bundles/cdk-portal.umd.min.js.map +1 -1
  29. package/bundles/cdk-scrolling.umd.js +9 -6
  30. package/bundles/cdk-scrolling.umd.js.map +1 -1
  31. package/bundles/cdk-scrolling.umd.min.js +1 -1
  32. package/bundles/cdk-scrolling.umd.min.js.map +1 -1
  33. package/bundles/cdk-stepper.umd.js +36 -16
  34. package/bundles/cdk-stepper.umd.js.map +1 -1
  35. package/bundles/cdk-stepper.umd.min.js +1 -1
  36. package/bundles/cdk-stepper.umd.min.js.map +1 -1
  37. package/bundles/cdk-table.umd.js +8 -4
  38. package/bundles/cdk-table.umd.js.map +1 -1
  39. package/bundles/cdk-table.umd.min.js +1 -1
  40. package/bundles/cdk-table.umd.min.js.map +1 -1
  41. package/bundles/cdk-text-field.umd.js +47 -22
  42. package/bundles/cdk-text-field.umd.js.map +1 -1
  43. package/bundles/cdk-text-field.umd.min.js +1 -1
  44. package/bundles/cdk-text-field.umd.min.js.map +1 -1
  45. package/bundles/cdk-tree.umd.js +1 -1
  46. package/bundles/cdk-tree.umd.js.map +1 -1
  47. package/bundles/cdk-tree.umd.min.js +1 -1
  48. package/bundles/cdk-tree.umd.min.js.map +1 -1
  49. package/bundles/cdk.umd.js +1 -1
  50. package/bundles/cdk.umd.js.map +1 -1
  51. package/bundles/cdk.umd.min.js +1 -1
  52. package/bundles/cdk.umd.min.js.map +1 -1
  53. package/coercion/typings/element.d.ts +13 -0
  54. package/coercion/typings/index.metadata.json +1 -1
  55. package/coercion/typings/public-api.d.ts +1 -0
  56. package/drag-drop/typings/{drag-handle.d.ts → directives/drag-handle.d.ts} +6 -2
  57. package/drag-drop/typings/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  58. package/drag-drop/typings/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  59. package/drag-drop/typings/directives/drag.d.ts +114 -0
  60. package/{typings/esm5/drag-drop → drag-drop/typings/directives}/drop-list-group.d.ts +3 -0
  61. package/drag-drop/typings/{drop-list.d.ts → directives/drop-list.d.ts} +44 -70
  62. package/drag-drop/typings/drag-drop-registry.d.ts +8 -3
  63. package/drag-drop/typings/drag-drop.d.ts +33 -0
  64. package/drag-drop/typings/drag-events.d.ts +14 -7
  65. package/{typings/esm5/drag-drop/drag.d.ts → drag-drop/typings/drag-ref.d.ts} +162 -86
  66. package/drag-drop/typings/drop-list-container.d.ts +19 -3
  67. package/drag-drop/typings/drop-list-ref.d.ts +238 -0
  68. package/drag-drop/typings/index.d.ts +2 -1
  69. package/drag-drop/typings/index.metadata.json +1 -1
  70. package/drag-drop/typings/public-api.d.ts +16 -6
  71. package/esm2015/a11y.js +30 -20
  72. package/esm2015/a11y.js.map +1 -1
  73. package/esm2015/cdk.js +1 -1
  74. package/esm2015/cdk.js.map +1 -1
  75. package/esm2015/coercion.js +18 -1
  76. package/esm2015/coercion.js.map +1 -1
  77. package/esm2015/drag-drop.js +2281 -1289
  78. package/esm2015/drag-drop.js.map +1 -1
  79. package/esm2015/observers.js +3 -3
  80. package/esm2015/observers.js.map +1 -1
  81. package/esm2015/overlay.js +75 -31
  82. package/esm2015/overlay.js.map +1 -1
  83. package/esm2015/portal.js +1 -1
  84. package/esm2015/portal.js.map +1 -1
  85. package/esm2015/scrolling.js +9 -6
  86. package/esm2015/scrolling.js.map +1 -1
  87. package/esm2015/stepper.js +30 -16
  88. package/esm2015/stepper.js.map +1 -1
  89. package/esm2015/table.js +8 -4
  90. package/esm2015/table.js.map +1 -1
  91. package/esm2015/text-field.js +31 -19
  92. package/esm2015/text-field.js.map +1 -1
  93. package/esm2015/tree.js +2 -2
  94. package/esm2015/tree.js.map +1 -1
  95. package/esm5/a11y.es5.js +31 -25
  96. package/esm5/a11y.es5.js.map +1 -1
  97. package/esm5/cdk.es5.js +1 -1
  98. package/esm5/cdk.es5.js.map +1 -1
  99. package/esm5/coercion.es5.js +18 -1
  100. package/esm5/coercion.es5.js.map +1 -1
  101. package/esm5/drag-drop.es5.js +3247 -1899
  102. package/esm5/drag-drop.es5.js.map +1 -1
  103. package/esm5/observers.es5.js +3 -3
  104. package/esm5/observers.es5.js.map +1 -1
  105. package/esm5/overlay.es5.js +107 -45
  106. package/esm5/overlay.es5.js.map +1 -1
  107. package/esm5/portal.es5.js +3 -3
  108. package/esm5/portal.es5.js.map +1 -1
  109. package/esm5/scrolling.es5.js +9 -6
  110. package/esm5/scrolling.es5.js.map +1 -1
  111. package/esm5/stepper.es5.js +36 -17
  112. package/esm5/stepper.es5.js.map +1 -1
  113. package/esm5/table.es5.js +8 -4
  114. package/esm5/table.es5.js.map +1 -1
  115. package/esm5/text-field.es5.js +44 -19
  116. package/esm5/text-field.es5.js.map +1 -1
  117. package/esm5/tree.es5.js +2 -2
  118. package/esm5/tree.es5.js.map +1 -1
  119. package/overlay/typings/index.metadata.json +1 -1
  120. package/overlay/typings/overlay-directives.d.ts +0 -2
  121. package/overlay/typings/overlay-ref.d.ts +5 -1
  122. package/overlay/typings/position/flexible-connected-position-strategy.d.ts +17 -4
  123. package/overlay/typings/position/overlay-position-builder.d.ts +3 -3
  124. package/package.json +4 -4
  125. package/portal/typings/portal.d.ts +1 -1
  126. package/schematics/migration.json +5 -0
  127. package/schematics/ng-generate/drag-drop/files/__path__/__name@dasherize@if-flat__/__name@dasherize__.component.ts +2 -2
  128. package/schematics/ng-update/index.d.ts +2 -0
  129. package/schematics/ng-update/index.js +5 -0
  130. package/schematics/ng-update/index.js.map +1 -1
  131. package/schematics/ng-update/target-version.d.ts +7 -1
  132. package/schematics/ng-update/target-version.js +10 -0
  133. package/schematics/ng-update/target-version.js.map +1 -1
  134. package/schematics/ng-update/upgrade-data.js +2 -1
  135. package/schematics/ng-update/upgrade-data.js.map +1 -1
  136. package/schematics/ng-update/upgrade-rules/index.js +3 -2
  137. package/schematics/ng-update/upgrade-rules/index.js.map +1 -1
  138. package/schematics/utils/ast/ng-module-imports.d.ts +1 -1
  139. package/schematics/utils/ast/ng-module-imports.js +25 -13
  140. package/schematics/utils/ast/ng-module-imports.js.map +1 -1
  141. package/schematics/utils/get-project.js +2 -1
  142. package/schematics/utils/get-project.js.map +1 -1
  143. package/schematics/utils/parse5-element.js +3 -2
  144. package/schematics/utils/parse5-element.js.map +1 -1
  145. package/schematics/utils/project-targets.js +2 -1
  146. package/schematics/utils/project-targets.js.map +1 -1
  147. package/schematics/utils/version-agnostic-typescript.js +3 -2
  148. package/schematics/utils/version-agnostic-typescript.js.map +1 -1
  149. package/stepper/typings/index.metadata.json +1 -1
  150. package/stepper/typings/stepper.d.ts +14 -2
  151. package/text-field/typings/autosize.d.ts +6 -0
  152. package/text-field/typings/index.metadata.json +1 -1
  153. package/tree/typings/control/base-tree-control.d.ts +1 -1
  154. package/tree/typings/control/nested-tree-control.d.ts +2 -2
  155. package/tree/typings/control/tree-control.d.ts +1 -1
  156. package/typings/a11y/focus-monitor/focus-monitor.d.ts +0 -1
  157. package/typings/a11y/focus-trap/focus-trap.d.ts +2 -0
  158. package/typings/a11y/index.metadata.json +1 -1
  159. package/typings/coercion/element.d.ts +13 -0
  160. package/typings/coercion/index.metadata.json +1 -1
  161. package/typings/coercion/public-api.d.ts +1 -0
  162. package/typings/drag-drop/{drag-handle.d.ts → directives/drag-handle.d.ts} +6 -2
  163. package/typings/drag-drop/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  164. package/typings/drag-drop/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  165. package/typings/drag-drop/directives/drag.d.ts +114 -0
  166. package/typings/drag-drop/{drop-list-group.d.ts → directives/drop-list-group.d.ts} +3 -0
  167. package/typings/{esm5/drag-drop → drag-drop/directives}/drop-list.d.ts +44 -70
  168. package/typings/drag-drop/drag-drop-registry.d.ts +8 -3
  169. package/typings/drag-drop/drag-drop.d.ts +33 -0
  170. package/typings/drag-drop/drag-events.d.ts +14 -7
  171. package/typings/drag-drop/{drag.d.ts → drag-ref.d.ts} +162 -86
  172. package/typings/drag-drop/drop-list-container.d.ts +19 -3
  173. package/typings/drag-drop/drop-list-ref.d.ts +238 -0
  174. package/typings/drag-drop/index.d.ts +2 -1
  175. package/typings/drag-drop/index.metadata.json +1 -1
  176. package/typings/drag-drop/public-api.d.ts +16 -6
  177. package/typings/esm5/a11y/focus-monitor/focus-monitor.d.ts +0 -1
  178. package/typings/esm5/a11y/focus-trap/focus-trap.d.ts +2 -0
  179. package/typings/esm5/a11y/index.metadata.json +1 -1
  180. package/typings/esm5/coercion/element.d.ts +13 -0
  181. package/typings/esm5/coercion/index.metadata.json +1 -1
  182. package/typings/esm5/coercion/public-api.d.ts +1 -0
  183. package/typings/esm5/drag-drop/{drag-handle.d.ts → directives/drag-handle.d.ts} +6 -2
  184. package/typings/esm5/drag-drop/{drag-placeholder.d.ts → directives/drag-placeholder.d.ts} +0 -0
  185. package/typings/esm5/drag-drop/{drag-preview.d.ts → directives/drag-preview.d.ts} +0 -0
  186. package/typings/esm5/drag-drop/directives/drag.d.ts +114 -0
  187. package/{drag-drop/typings → typings/esm5/drag-drop/directives}/drop-list-group.d.ts +3 -0
  188. package/typings/{drag-drop → esm5/drag-drop/directives}/drop-list.d.ts +44 -70
  189. package/typings/esm5/drag-drop/drag-drop-registry.d.ts +8 -3
  190. package/typings/esm5/drag-drop/drag-drop.d.ts +33 -0
  191. package/typings/esm5/drag-drop/drag-events.d.ts +14 -7
  192. package/{drag-drop/typings/drag.d.ts → typings/esm5/drag-drop/drag-ref.d.ts} +162 -86
  193. package/typings/esm5/drag-drop/drop-list-container.d.ts +19 -3
  194. package/typings/esm5/drag-drop/drop-list-ref.d.ts +238 -0
  195. package/typings/esm5/drag-drop/index.d.ts +2 -1
  196. package/typings/esm5/drag-drop/index.metadata.json +1 -1
  197. package/typings/esm5/drag-drop/public-api.d.ts +16 -6
  198. package/typings/esm5/index.metadata.json +1 -1
  199. package/typings/esm5/overlay/index.metadata.json +1 -1
  200. package/typings/esm5/overlay/overlay-directives.d.ts +0 -2
  201. package/typings/esm5/overlay/overlay-ref.d.ts +5 -1
  202. package/typings/esm5/overlay/position/flexible-connected-position-strategy.d.ts +17 -4
  203. package/typings/esm5/overlay/position/overlay-position-builder.d.ts +3 -3
  204. package/typings/esm5/portal/portal.d.ts +1 -1
  205. package/typings/esm5/stepper/index.metadata.json +1 -1
  206. package/typings/esm5/stepper/stepper.d.ts +14 -2
  207. package/typings/esm5/text-field/autosize.d.ts +6 -0
  208. package/typings/esm5/text-field/index.metadata.json +1 -1
  209. package/typings/esm5/tree/control/base-tree-control.d.ts +1 -1
  210. package/typings/esm5/tree/control/nested-tree-control.d.ts +2 -2
  211. package/typings/esm5/tree/control/tree-control.d.ts +1 -1
  212. package/typings/index.metadata.json +1 -1
  213. package/typings/overlay/index.metadata.json +1 -1
  214. package/typings/overlay/overlay-directives.d.ts +0 -2
  215. package/typings/overlay/overlay-ref.d.ts +5 -1
  216. package/typings/overlay/position/flexible-connected-position-strategy.d.ts +17 -4
  217. package/typings/overlay/position/overlay-position-builder.d.ts +3 -3
  218. package/typings/portal/portal.d.ts +1 -1
  219. package/typings/schematics/ng-update/index.d.ts +2 -0
  220. package/typings/schematics/ng-update/target-version.d.ts +7 -1
  221. package/typings/schematics/utils/ast/ng-module-imports.d.ts +1 -1
  222. package/typings/stepper/index.metadata.json +1 -1
  223. package/typings/stepper/stepper.d.ts +14 -2
  224. package/typings/text-field/autosize.d.ts +6 -0
  225. package/typings/text-field/index.metadata.json +1 -1
  226. package/typings/tree/control/base-tree-control.d.ts +1 -1
  227. package/typings/tree/control/nested-tree-control.d.ts +2 -2
  228. package/typings/tree/control/tree-control.d.ts +1 -1
@@ -5,243 +5,14 @@
5
5
  * Use of this source code is governed by an MIT-style license that can be
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
- import { Injectable, NgZone, Inject, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, Output, Optional, Directive, ChangeDetectorRef, SkipSelf, ContentChild, InjectionToken, ViewContainerRef, TemplateRef, NgModule, defineInjectable, inject } from '@angular/core';
9
- import { DOCUMENT } from '@angular/common';
10
8
  import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
11
- import { Subject, Observable, Subscription } from 'rxjs';
12
- import { coerceBooleanProperty, coerceArray } from '@angular/cdk/coercion';
13
- import { Directionality } from '@angular/cdk/bidi';
9
+ import { coerceBooleanProperty, coerceElement, coerceArray } from '@angular/cdk/coercion';
10
+ import { Subscription, Subject, Observable, merge } from 'rxjs';
11
+ import { ElementRef, Injectable, NgZone, Inject, InjectionToken, NgModule, ContentChildren, EventEmitter, forwardRef, Input, Output, Optional, Directive, ChangeDetectorRef, SkipSelf, ContentChild, ViewContainerRef, TemplateRef, defineInjectable, inject } from '@angular/core';
12
+ import { DOCUMENT } from '@angular/common';
14
13
  import { ViewportRuler } from '@angular/cdk/scrolling';
15
- import { startWith, take } from 'rxjs/operators';
16
-
17
- /**
18
- * @fileoverview added by tsickle
19
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
20
- */
21
- /**
22
- * Event options that can be used to bind an active, capturing event.
23
- * @type {?}
24
- */
25
- const activeCapturingEventOptions = normalizePassiveListenerOptions({
26
- passive: false,
27
- capture: true
28
- });
29
- /**
30
- * Service that keeps track of all the drag item and drop container
31
- * instances, and manages global event listeners on the `document`.
32
- * \@docs-private
33
- * @template I, C
34
- */
35
- // Note: this class is generic, rather than referencing CdkDrag and CdkDropList directly, in order
36
- // to avoid circular imports. If we were to reference them here, importing the registry into the
37
- // classes that are registering themselves will introduce a circular import.
38
- class DragDropRegistry {
39
- /**
40
- * @param {?} _ngZone
41
- * @param {?} _document
42
- */
43
- constructor(_ngZone, _document) {
44
- this._ngZone = _ngZone;
45
- /**
46
- * Registered drop container instances.
47
- */
48
- this._dropInstances = new Set();
49
- /**
50
- * Registered drag item instances.
51
- */
52
- this._dragInstances = new Set();
53
- /**
54
- * Drag item instances that are currently being dragged.
55
- */
56
- this._activeDragInstances = new Set();
57
- /**
58
- * Keeps track of the event listeners that we've bound to the `document`.
59
- */
60
- this._globalListeners = new Map();
61
- /**
62
- * Emits the `touchmove` or `mousemove` events that are dispatched
63
- * while the user is dragging a drag item instance.
64
- */
65
- this.pointerMove = new Subject();
66
- /**
67
- * Emits the `touchend` or `mouseup` events that are dispatched
68
- * while the user is dragging a drag item instance.
69
- */
70
- this.pointerUp = new Subject();
71
- /**
72
- * Listener used to prevent `touchmove` and `wheel` events while the element is being dragged.
73
- */
74
- this._preventScrollListener = (event) => {
75
- if (this._activeDragInstances.size) {
76
- event.preventDefault();
77
- }
78
- };
79
- this._document = _document;
80
- }
81
- /**
82
- * Adds a drop container to the registry.
83
- * @param {?} drop
84
- * @return {?}
85
- */
86
- registerDropContainer(drop) {
87
- if (!this._dropInstances.has(drop)) {
88
- if (this.getDropContainer(drop.id)) {
89
- throw Error(`Drop instance with id "${drop.id}" has already been registered.`);
90
- }
91
- this._dropInstances.add(drop);
92
- }
93
- }
94
- /**
95
- * Adds a drag item instance to the registry.
96
- * @param {?} drag
97
- * @return {?}
98
- */
99
- registerDragItem(drag) {
100
- this._dragInstances.add(drag);
101
- // The `touchmove` event gets bound once, ahead of time, because WebKit
102
- // won't preventDefault on a dynamically-added `touchmove` listener.
103
- // See https://bugs.webkit.org/show_bug.cgi?id=184250.
104
- if (this._dragInstances.size === 1) {
105
- this._ngZone.runOutsideAngular(() => {
106
- // The event handler has to be explicitly active,
107
- // because newer browsers make it passive by default.
108
- this._document.addEventListener('touchmove', this._preventScrollListener, activeCapturingEventOptions);
109
- });
110
- }
111
- }
112
- /**
113
- * Removes a drop container from the registry.
114
- * @param {?} drop
115
- * @return {?}
116
- */
117
- removeDropContainer(drop) {
118
- this._dropInstances.delete(drop);
119
- }
120
- /**
121
- * Removes a drag item instance from the registry.
122
- * @param {?} drag
123
- * @return {?}
124
- */
125
- removeDragItem(drag) {
126
- this._dragInstances.delete(drag);
127
- this.stopDragging(drag);
128
- if (this._dragInstances.size === 0) {
129
- this._document.removeEventListener('touchmove', this._preventScrollListener, activeCapturingEventOptions);
130
- }
131
- }
132
- /**
133
- * Starts the dragging sequence for a drag instance.
134
- * @param {?} drag Drag instance which is being dragged.
135
- * @param {?} event Event that initiated the dragging.
136
- * @return {?}
137
- */
138
- startDragging(drag, event) {
139
- this._activeDragInstances.add(drag);
140
- if (this._activeDragInstances.size === 1) {
141
- /** @type {?} */
142
- const isTouchEvent = event.type.startsWith('touch');
143
- /** @type {?} */
144
- const moveEvent = isTouchEvent ? 'touchmove' : 'mousemove';
145
- /** @type {?} */
146
- const upEvent = isTouchEvent ? 'touchend' : 'mouseup';
147
- // We explicitly bind __active__ listeners here, because newer browsers will default to
148
- // passive ones for `mousemove` and `touchmove`. The events need to be active, because we
149
- // use `preventDefault` to prevent the page from scrolling while the user is dragging.
150
- this._globalListeners
151
- .set(moveEvent, {
152
- handler: e => this.pointerMove.next(e),
153
- options: activeCapturingEventOptions
154
- })
155
- .set(upEvent, {
156
- handler: e => this.pointerUp.next(e),
157
- options: true
158
- });
159
- // TODO(crisbeto): prevent mouse wheel scrolling while
160
- // dragging until we've set up proper scroll handling.
161
- if (!isTouchEvent) {
162
- this._globalListeners.set('wheel', {
163
- handler: this._preventScrollListener,
164
- options: activeCapturingEventOptions
165
- });
166
- }
167
- this._ngZone.runOutsideAngular(() => {
168
- this._globalListeners.forEach((config, name) => {
169
- this._document.addEventListener(name, config.handler, config.options);
170
- });
171
- });
172
- }
173
- }
174
- /**
175
- * Stops dragging a drag item instance.
176
- * @param {?} drag
177
- * @return {?}
178
- */
179
- stopDragging(drag) {
180
- this._activeDragInstances.delete(drag);
181
- if (this._activeDragInstances.size === 0) {
182
- this._clearGlobalListeners();
183
- }
184
- }
185
- /**
186
- * Gets whether a drag item instance is currently being dragged.
187
- * @param {?} drag
188
- * @return {?}
189
- */
190
- isDragging(drag) {
191
- return this._activeDragInstances.has(drag);
192
- }
193
- /**
194
- * Gets a drop container by its id.
195
- * @param {?} id
196
- * @return {?}
197
- */
198
- getDropContainer(id) {
199
- return Array.from(this._dropInstances).find(instance => instance.id === id);
200
- }
201
- /**
202
- * @return {?}
203
- */
204
- ngOnDestroy() {
205
- this._dragInstances.forEach(instance => this.removeDragItem(instance));
206
- this._dropInstances.forEach(instance => this.removeDropContainer(instance));
207
- this._clearGlobalListeners();
208
- this.pointerMove.complete();
209
- this.pointerUp.complete();
210
- }
211
- /**
212
- * Clears out the global event listeners from the `document`.
213
- * @private
214
- * @return {?}
215
- */
216
- _clearGlobalListeners() {
217
- this._globalListeners.forEach((config, name) => {
218
- this._document.removeEventListener(name, config.handler, config.options);
219
- });
220
- this._globalListeners.clear();
221
- }
222
- }
223
- DragDropRegistry.decorators = [
224
- { type: Injectable, args: [{ providedIn: 'root' },] },
225
- ];
226
- /** @nocollapse */
227
- DragDropRegistry.ctorParameters = () => [
228
- { type: NgZone },
229
- { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
230
- ];
231
- /** @nocollapse */ DragDropRegistry.ngInjectableDef = defineInjectable({ factory: function DragDropRegistry_Factory() { return new DragDropRegistry(inject(NgZone), inject(DOCUMENT)); }, token: DragDropRegistry, providedIn: "root" });
232
-
233
- /**
234
- * @fileoverview added by tsickle
235
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
236
- */
237
- /**
238
- * Injection token that can be used for a `CdkDrag` to provide itself as a parent to the
239
- * drag-specific child directive (`CdkDragHandle`, `CdkDragPreview` etc.). Used primarily
240
- * to avoid circular imports.
241
- * \@docs-private
242
- * @type {?}
243
- */
244
- const CDK_DRAG_PARENT = new InjectionToken('CDK_DRAG_PARENT');
14
+ import { Directionality } from '@angular/cdk/bidi';
15
+ import { startWith, take, map, takeUntil, switchMap, tap } from 'rxjs/operators';
245
16
 
246
17
  /**
247
18
  * @fileoverview added by tsickle
@@ -287,130 +58,11 @@ function toggleNativeDragInteractions(element, enable) {
287
58
  * @fileoverview added by tsickle
288
59
  * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
289
60
  */
61
+
290
62
  /**
291
- * Handle that can be used to drag and CdkDrag instance.
292
- */
293
- class CdkDragHandle {
294
- /**
295
- * @param {?} element
296
- * @param {?=} parentDrag
297
- */
298
- constructor(element, parentDrag) {
299
- this.element = element;
300
- this._disabled = false;
301
- this._parentDrag = parentDrag;
302
- toggleNativeDragInteractions(element.nativeElement, false);
303
- }
304
- /**
305
- * Whether starting to drag through this handle is disabled.
306
- * @return {?}
307
- */
308
- get disabled() { return this._disabled; }
309
- /**
310
- * @param {?} value
311
- * @return {?}
312
- */
313
- set disabled(value) {
314
- this._disabled = coerceBooleanProperty(value);
315
- }
316
- }
317
- CdkDragHandle.decorators = [
318
- { type: Directive, args: [{
319
- selector: '[cdkDragHandle]',
320
- host: {
321
- 'class': 'cdk-drag-handle'
322
- }
323
- },] },
324
- ];
325
- /** @nocollapse */
326
- CdkDragHandle.ctorParameters = () => [
327
- { type: ElementRef },
328
- { type: undefined, decorators: [{ type: Inject, args: [CDK_DRAG_PARENT,] }, { type: Optional }] }
329
- ];
330
- CdkDragHandle.propDecorators = {
331
- disabled: [{ type: Input, args: ['cdkDragHandleDisabled',] }]
332
- };
333
-
334
- /**
335
- * @fileoverview added by tsickle
336
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
337
- */
338
- /**
339
- * Element that will be used as a template for the placeholder of a CdkDrag when
340
- * it is being dragged. The placeholder is displayed in place of the element being dragged.
341
- * @template T
342
- */
343
- class CdkDragPlaceholder {
344
- /**
345
- * @param {?} templateRef
346
- */
347
- constructor(templateRef) {
348
- this.templateRef = templateRef;
349
- }
350
- }
351
- CdkDragPlaceholder.decorators = [
352
- { type: Directive, args: [{
353
- selector: 'ng-template[cdkDragPlaceholder]'
354
- },] },
355
- ];
356
- /** @nocollapse */
357
- CdkDragPlaceholder.ctorParameters = () => [
358
- { type: TemplateRef }
359
- ];
360
- CdkDragPlaceholder.propDecorators = {
361
- data: [{ type: Input }]
362
- };
363
-
364
- /**
365
- * @fileoverview added by tsickle
366
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
367
- */
368
- /**
369
- * Element that will be used as a template for the preview
370
- * of a CdkDrag when it is being dragged.
371
- * @template T
372
- */
373
- class CdkDragPreview {
374
- /**
375
- * @param {?} templateRef
376
- */
377
- constructor(templateRef) {
378
- this.templateRef = templateRef;
379
- }
380
- }
381
- CdkDragPreview.decorators = [
382
- { type: Directive, args: [{
383
- selector: 'ng-template[cdkDragPreview]'
384
- },] },
385
- ];
386
- /** @nocollapse */
387
- CdkDragPreview.ctorParameters = () => [
388
- { type: TemplateRef }
389
- ];
390
- CdkDragPreview.propDecorators = {
391
- data: [{ type: Input }]
392
- };
393
-
394
- /**
395
- * @fileoverview added by tsickle
396
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
397
- */
398
- /**
399
- * Injection token that is used to provide a CdkDropList instance to CdkDrag.
400
- * Used for avoiding circular imports.
401
- * @type {?}
402
- */
403
- const CDK_DROP_LIST_CONTAINER = new InjectionToken('CDK_DROP_LIST_CONTAINER');
404
-
405
- /**
406
- * @fileoverview added by tsickle
407
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
408
- */
409
-
410
- /**
411
- * Parses a CSS time value to milliseconds.
412
- * @param {?} value
413
- * @return {?}
63
+ * Parses a CSS time value to milliseconds.
64
+ * @param {?} value
65
+ * @return {?}
414
66
  */
415
67
  function parseCssTimeUnitsToMs(value) {
416
68
  // Some browsers will return it in seconds, whereas others will return milliseconds.
@@ -461,21 +113,6 @@ function parseCssPropertyValue(computedStyle, name) {
461
113
  * @fileoverview added by tsickle
462
114
  * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
463
115
  */
464
- /**
465
- * Injection token that can be used to configure the behavior of `CdkDrag`.
466
- * @type {?}
467
- */
468
- const CDK_DRAG_CONFIG = new InjectionToken('CDK_DRAG_CONFIG', {
469
- providedIn: 'root',
470
- factory: CDK_DRAG_CONFIG_FACTORY
471
- });
472
- /**
473
- * \@docs-private
474
- * @return {?}
475
- */
476
- function CDK_DRAG_CONFIG_FACTORY() {
477
- return { dragStartThreshold: 5, pointerDirectionChangeThreshold: 5 };
478
- }
479
116
  /**
480
117
  * Options that can be used to bind a passive event listener.
481
118
  * @type {?}
@@ -495,30 +132,25 @@ const activeEventListenerOptions = normalizePassiveListenerOptions({ passive: fa
495
132
  */
496
133
  const MOUSE_EVENT_IGNORE_TIME = 800;
497
134
  /**
498
- * Element that can be moved inside a CdkDropList container.
135
+ * Reference to a draggable item. Used to manipulate or dispose of the item.
136
+ * \@docs-private
499
137
  * @template T
500
138
  */
501
- class CdkDrag {
139
+ class DragRef {
502
140
  /**
503
141
  * @param {?} element
504
- * @param {?} dropContainer
505
- * @param {?} document
142
+ * @param {?} _config
143
+ * @param {?} _document
506
144
  * @param {?} _ngZone
507
- * @param {?} _viewContainerRef
508
145
  * @param {?} _viewportRuler
509
146
  * @param {?} _dragDropRegistry
510
- * @param {?} _config
511
- * @param {?} _dir
512
147
  */
513
- constructor(element, dropContainer, document, _ngZone, _viewContainerRef, _viewportRuler, _dragDropRegistry, _config, _dir) {
514
- this.element = element;
515
- this.dropContainer = dropContainer;
148
+ constructor(element, _config, _document, _ngZone, _viewportRuler, _dragDropRegistry) {
149
+ this._config = _config;
150
+ this._document = _document;
516
151
  this._ngZone = _ngZone;
517
- this._viewContainerRef = _viewContainerRef;
518
152
  this._viewportRuler = _viewportRuler;
519
153
  this._dragDropRegistry = _dragDropRegistry;
520
- this._config = _config;
521
- this._dir = _dir;
522
154
  /**
523
155
  * CSS `transform` applied to the element when it isn't being dragged. We need a
524
156
  * passive transform in order for the dragged element to retain its new position
@@ -548,35 +180,59 @@ class CdkDrag {
548
180
  */
549
181
  this._pointerUpSubscription = Subscription.EMPTY;
550
182
  /**
551
- * Subscription to the stream that initializes the root element.
183
+ * Cached reference to the boundary element.
184
+ */
185
+ this._boundaryElement = null;
186
+ /**
187
+ * Whether the native dragging interactions have been enabled on the root element.
188
+ */
189
+ this._nativeInteractionsEnabled = true;
190
+ /**
191
+ * Elements that can be used to drag the draggable item.
192
+ */
193
+ this._handles = [];
194
+ /**
195
+ * Registered handles that are currently disabled.
196
+ */
197
+ this._disabledHandles = new Set();
198
+ /**
199
+ * Layout direction of the item.
552
200
  */
553
- this._rootElementInitSubscription = Subscription.EMPTY;
201
+ this._direction = 'ltr';
554
202
  this._disabled = false;
203
+ /**
204
+ * Emits as the drag sequence is being prepared.
205
+ */
206
+ this.beforeStarted = new Subject();
555
207
  /**
556
208
  * Emits when the user starts dragging the item.
557
209
  */
558
- this.started = new EventEmitter();
210
+ this.started = new Subject();
211
+ /**
212
+ * Emits when the user has released a drag item, before any animations have started.
213
+ */
214
+ this.released = new Subject();
559
215
  /**
560
216
  * Emits when the user stops dragging an item in the container.
561
217
  */
562
- this.ended = new EventEmitter();
218
+ this.ended = new Subject();
563
219
  /**
564
220
  * Emits when the user has moved the item into a new container.
565
221
  */
566
- this.entered = new EventEmitter();
222
+ this.entered = new Subject();
567
223
  /**
568
224
  * Emits when the user removes the item its container by dragging it into another container.
569
225
  */
570
- this.exited = new EventEmitter();
226
+ this.exited = new Subject();
571
227
  /**
572
228
  * Emits when the user drops the item inside a container.
573
229
  */
574
- this.dropped = new EventEmitter();
230
+ this.dropped = new Subject();
575
231
  /**
576
232
  * Emits as the user is dragging the item. Use with caution,
577
233
  * because this event will fire for every pixel that the user has dragged.
578
234
  */
579
- this.moved = Observable.create((observer) => {
235
+ this.moved = new Observable((observer) => {
580
236
  /** @type {?} */
581
237
  const subscription = this._moveEvents.subscribe(observer);
582
238
  this._moveEventSubscriptions++;
@@ -589,20 +245,17 @@ class CdkDrag {
589
245
  * Handler for the `mousedown`/`touchstart` events.
590
246
  */
591
247
  this._pointerDown = (event) => {
592
- /** @type {?} */
593
- const handles = this.getChildHandles();
248
+ this.beforeStarted.next();
594
249
  // Delegate the event based on whether it started from a handle or the element itself.
595
- if (handles.length) {
250
+ if (this._handles.length) {
596
251
  /** @type {?} */
597
- const targetHandle = handles.find(handle => {
598
- /** @type {?} */
599
- const element = handle.element.nativeElement;
252
+ const targetHandle = this._handles.find(handle => {
600
253
  /** @type {?} */
601
254
  const target = event.target;
602
- return !!target && (target === element || element.contains((/** @type {?} */ (target))));
255
+ return !!target && (target === handle || handle.contains((/** @type {?} */ (target))));
603
256
  });
604
- if (targetHandle && !targetHandle.disabled && !this.disabled) {
605
- this._initializeDragSequence(targetHandle.element.nativeElement, event);
257
+ if (targetHandle && !this._disabledHandles.has(targetHandle) && !this.disabled) {
258
+ this._initializeDragSequence(targetHandle, event);
606
259
  }
607
260
  }
608
261
  else if (!this.disabled) {
@@ -613,9 +266,9 @@ class CdkDrag {
613
266
  * Handler that is invoked when the user moves their pointer after they've initiated a drag.
614
267
  */
615
268
  this._pointerMove = (event) => {
616
- /** @type {?} */
617
- const pointerPosition = this._getConstrainedPointerPosition(event);
618
269
  if (!this._hasStartedDragging) {
270
+ /** @type {?} */
271
+ const pointerPosition = this._getPointerPositionOnPage(event);
619
272
  /** @type {?} */
620
273
  const distanceX = Math.abs(pointerPosition.x - this._pickupPositionOnPage.x);
621
274
  /** @type {?} */
@@ -630,24 +283,36 @@ class CdkDrag {
630
283
  }
631
284
  return;
632
285
  }
286
+ // We only need the preview dimensions if we have a boundary element.
287
+ if (this._boundaryElement) {
288
+ // Cache the preview element rect if we haven't cached it already or if
289
+ // we cached it too early before the element dimensions were computed.
290
+ if (!this._previewRect || (!this._previewRect.width && !this._previewRect.height)) {
291
+ this._previewRect = (this._preview || this._rootElement).getBoundingClientRect();
292
+ }
293
+ }
294
+ /** @type {?} */
295
+ const constrainedPointerPosition = this._getConstrainedPointerPosition(event);
633
296
  this._hasMoved = true;
634
297
  event.preventDefault();
635
- this._updatePointerDirectionDelta(pointerPosition);
636
- if (this.dropContainer) {
637
- this._updateActiveDropContainer(pointerPosition);
298
+ this._updatePointerDirectionDelta(constrainedPointerPosition);
299
+ if (this._dropContainer) {
300
+ this._updateActiveDropContainer(constrainedPointerPosition);
638
301
  }
639
302
  else {
640
303
  /** @type {?} */
641
304
  const activeTransform = this._activeTransform;
642
305
  activeTransform.x =
643
- pointerPosition.x - this._pickupPositionOnPage.x + this._passiveTransform.x;
306
+ constrainedPointerPosition.x - this._pickupPositionOnPage.x + this._passiveTransform.x;
644
307
  activeTransform.y =
645
- pointerPosition.y - this._pickupPositionOnPage.y + this._passiveTransform.y;
308
+ constrainedPointerPosition.y - this._pickupPositionOnPage.y + this._passiveTransform.y;
646
309
  /** @type {?} */
647
310
  const transform = getTransform(activeTransform.x, activeTransform.y);
648
- // Preserve the previous `transform` value, if there was one.
311
+ // Preserve the previous `transform` value, if there was one. Note that we apply our own
312
+ // transform before the user's, because things like rotation can affect which direction
313
+ // the element will be translated towards.
649
314
  this._rootElement.style.transform = this._initialTransform ?
650
- this._initialTransform + ' ' + transform : transform;
315
+ transform + ' ' + this._initialTransform : transform;
651
316
  // Apply transform as attribute if dragging and svg element to work for IE
652
317
  if (typeof SVGElement !== 'undefined' && this._rootElement instanceof SVGElement) {
653
318
  /** @type {?} */
@@ -662,7 +327,7 @@ class CdkDrag {
662
327
  this._ngZone.run(() => {
663
328
  this._moveEvents.next({
664
329
  source: this,
665
- pointerPosition,
330
+ pointerPosition: constrainedPointerPosition,
666
331
  event,
667
332
  delta: this._pointerDirectionDelta
668
333
  });
@@ -672,31 +337,39 @@ class CdkDrag {
672
337
  /**
673
338
  * Handler that is invoked when the user lifts their pointer up, after initiating a drag.
674
339
  */
675
- this._pointerUp = () => {
676
- if (!this._isDragging()) {
340
+ this._pointerUp = (event) => {
341
+ // Note that here we use `isDragging` from the service, rather than from `this`.
342
+ // The difference is that the one from the service reflects whether a dragging sequence
343
+ // has been initiated, whereas the one on `this` includes whether the user has passed
344
+ // the minimum dragging threshold.
345
+ if (!this._dragDropRegistry.isDragging(this)) {
677
346
  return;
678
347
  }
679
348
  this._removeSubscriptions();
680
349
  this._dragDropRegistry.stopDragging(this);
350
+ if (this._handles) {
351
+ this._rootElement.style.webkitTapHighlightColor = this._rootElementTapHighlight;
352
+ }
681
353
  if (!this._hasStartedDragging) {
682
354
  return;
683
355
  }
684
- if (!this.dropContainer) {
356
+ this.released.next({ source: this });
357
+ if (!this._dropContainer) {
685
358
  // Convert the active transform into a passive one. This means that next time
686
359
  // the user starts dragging the item, its position will be calculated relatively
687
360
  // to the new passive transform.
688
361
  this._passiveTransform.x = this._activeTransform.x;
689
362
  this._passiveTransform.y = this._activeTransform.y;
690
- this._ngZone.run(() => this.ended.emit({ source: this }));
363
+ this._ngZone.run(() => this.ended.next({ source: this }));
691
364
  this._dragDropRegistry.stopDragging(this);
692
365
  return;
693
366
  }
694
367
  this._animatePreviewToPlaceholder().then(() => {
695
- this._cleanupDragArtifacts();
368
+ this._cleanupDragArtifacts(event);
696
369
  this._dragDropRegistry.stopDragging(this);
697
370
  });
698
371
  };
699
- this._document = document;
372
+ this.withRootElement(element);
700
373
  _dragDropRegistry.registerDragItem(this);
701
374
  }
702
375
  /**
@@ -704,14 +377,19 @@ class CdkDrag {
704
377
  * @return {?}
705
378
  */
706
379
  get disabled() {
707
- return this._disabled || (this.dropContainer && this.dropContainer.disabled);
380
+ return this._disabled || !!(this._dropContainer && this._dropContainer.disabled);
708
381
  }
709
382
  /**
710
383
  * @param {?} value
711
384
  * @return {?}
712
385
  */
713
386
  set disabled(value) {
714
- this._disabled = coerceBooleanProperty(value);
387
+ /** @type {?} */
388
+ const newValue = coerceBooleanProperty(value);
389
+ if (newValue !== this._disabled) {
390
+ this._disabled = newValue;
391
+ this._toggleNativeDragInteractions();
392
+ }
715
393
  }
716
394
  /**
717
395
  * Returns the element that is being used as a placeholder
@@ -729,163 +407,302 @@ class CdkDrag {
729
407
  return this._rootElement;
730
408
  }
731
409
  /**
732
- * Resets a standalone drag item to its initial position.
733
- * @return {?}
410
+ * Registers the handles that can be used to drag the element.
411
+ * @template THIS
412
+ * @this {THIS}
413
+ * @param {?} handles
414
+ * @return {THIS}
734
415
  */
735
- reset() {
736
- this._rootElement.style.transform = '';
737
- this._activeTransform = { x: 0, y: 0 };
738
- this._passiveTransform = { x: 0, y: 0 };
416
+ withHandles(handles) {
417
+ (/** @type {?} */ (this))._handles = handles.map(handle => coerceElement(handle));
418
+ (/** @type {?} */ (this))._handles.forEach(handle => toggleNativeDragInteractions(handle, false));
419
+ (/** @type {?} */ (this))._toggleNativeDragInteractions();
420
+ return (/** @type {?} */ (this));
739
421
  }
740
422
  /**
741
- * @return {?}
423
+ * Registers the template that should be used for the drag preview.
424
+ * @template THIS
425
+ * @this {THIS}
426
+ * @param {?} template Template that from which to stamp out the preview.
427
+ * @return {THIS}
742
428
  */
743
- ngAfterViewInit() {
744
- // We need to wait for the zone to stabilize, in order for the reference
745
- // element to be in the proper place in the DOM. This is mostly relevant
746
- // for draggable elements inside portals since they get stamped out in
747
- // their original DOM position and then they get transferred to the portal.
748
- this._rootElementInitSubscription = this._ngZone.onStable.asObservable()
749
- .pipe(take(1))
750
- .subscribe(() => {
751
- /** @type {?} */
752
- const rootElement = this._rootElement = this._getRootElement();
753
- rootElement.addEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
754
- rootElement.addEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
755
- this._handles.changes.pipe(startWith(null)).subscribe(() => toggleNativeDragInteractions(rootElement, this.getChildHandles().length > 0));
756
- });
429
+ withPreviewTemplate(template) {
430
+ (/** @type {?} */ (this))._previewTemplate = template;
431
+ return (/** @type {?} */ (this));
757
432
  }
758
433
  /**
759
- * @return {?}
434
+ * Registers the template that should be used for the drag placeholder.
435
+ * @template THIS
436
+ * @this {THIS}
437
+ * @param {?} template Template that from which to stamp out the placeholder.
438
+ * @return {THIS}
760
439
  */
761
- ngOnDestroy() {
762
- // The directive might have been destroyed before the root element is initialized.
763
- if (this._rootElement) {
764
- this._rootElement.removeEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
765
- this._rootElement.removeEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
766
- // Do this check before removing from the registry since it'll
767
- // stop being considered as dragged once it is removed.
768
- if (this._isDragging()) {
769
- // Since we move out the element to the end of the body while it's being
770
- // dragged, we have to make sure that it's removed if it gets destroyed.
771
- this._removeElement(this._rootElement);
440
+ withPlaceholderTemplate(template) {
441
+ (/** @type {?} */ (this))._placeholderTemplate = template;
442
+ return (/** @type {?} */ (this));
443
+ }
444
+ /**
445
+ * Sets an alternate drag root element. The root element is the element that will be moved as
446
+ * the user is dragging. Passing an alternate root element is useful when trying to enable
447
+ * dragging on an element that you might not have access to.
448
+ * @template THIS
449
+ * @this {THIS}
450
+ * @param {?} rootElement
451
+ * @return {THIS}
452
+ */
453
+ withRootElement(rootElement) {
454
+ /** @type {?} */
455
+ const element = coerceElement(rootElement);
456
+ if (element !== (/** @type {?} */ (this))._rootElement) {
457
+ if ((/** @type {?} */ (this))._rootElement) {
458
+ (/** @type {?} */ (this))._removeRootElementListeners((/** @type {?} */ (this))._rootElement);
772
459
  }
460
+ element.addEventListener('mousedown', (/** @type {?} */ (this))._pointerDown, activeEventListenerOptions);
461
+ element.addEventListener('touchstart', (/** @type {?} */ (this))._pointerDown, passiveEventListenerOptions);
462
+ (/** @type {?} */ (this))._initialTransform = undefined;
463
+ (/** @type {?} */ (this))._rootElement = element;
464
+ }
465
+ return (/** @type {?} */ (this));
466
+ }
467
+ /**
468
+ * Element to which the draggable's position will be constrained.
469
+ * @template THIS
470
+ * @this {THIS}
471
+ * @param {?} boundaryElement
472
+ * @return {THIS}
473
+ */
474
+ withBoundaryElement(boundaryElement) {
475
+ (/** @type {?} */ (this))._boundaryElement = boundaryElement ? coerceElement(boundaryElement) : null;
476
+ return (/** @type {?} */ (this));
477
+ }
478
+ /**
479
+ * Removes the dragging functionality from the DOM element.
480
+ * @return {?}
481
+ */
482
+ dispose() {
483
+ this._removeRootElementListeners(this._rootElement);
484
+ // Do this check before removing from the registry since it'll
485
+ // stop being considered as dragged once it is removed.
486
+ if (this.isDragging()) {
487
+ // Since we move out the element to the end of the body while it's being
488
+ // dragged, we have to make sure that it's removed if it gets destroyed.
489
+ removeElement(this._rootElement);
773
490
  }
774
- this._rootElementInitSubscription.unsubscribe();
775
491
  this._destroyPreview();
776
492
  this._destroyPlaceholder();
777
- this._nextSibling = null;
778
493
  this._dragDropRegistry.removeDragItem(this);
779
494
  this._removeSubscriptions();
495
+ this.beforeStarted.complete();
496
+ this.started.complete();
497
+ this.released.complete();
498
+ this.ended.complete();
499
+ this.entered.complete();
500
+ this.exited.complete();
501
+ this.dropped.complete();
780
502
  this._moveEvents.complete();
503
+ this._handles = [];
504
+ this._disabledHandles.clear();
505
+ this._dropContainer = undefined;
506
+ this._boundaryElement = this._rootElement = this._placeholderTemplate =
507
+ this._previewTemplate = this._nextSibling = (/** @type {?} */ (null));
781
508
  }
782
509
  /**
783
510
  * Checks whether the element is currently being dragged.
784
511
  * @return {?}
785
512
  */
786
- _isDragging() {
787
- return this._dragDropRegistry.isDragging(this);
513
+ isDragging() {
514
+ return this._hasStartedDragging && this._dragDropRegistry.isDragging(this);
788
515
  }
789
516
  /**
790
- * Gets only handles that are not inside descendant `CdkDrag` instances.
791
- * @private
517
+ * Resets a standalone drag item to its initial position.
792
518
  * @return {?}
793
519
  */
794
- getChildHandles() {
795
- return this._handles.filter(handle => handle._parentDrag === this);
520
+ reset() {
521
+ this._rootElement.style.transform = this._initialTransform || '';
522
+ this._activeTransform = { x: 0, y: 0 };
523
+ this._passiveTransform = { x: 0, y: 0 };
796
524
  }
797
525
  /**
798
- * Sets up the different variables and subscriptions
799
- * that will be necessary for the dragging sequence.
800
- * @private
801
- * @param {?} referenceElement Element that started the drag sequence.
802
- * @param {?} event Browser event object that started the sequence.
526
+ * Sets a handle as disabled. While a handle is disabled, it'll capture and interrupt dragging.
527
+ * @param {?} handle Handle element that should be disabled.
803
528
  * @return {?}
804
529
  */
805
- _initializeDragSequence(referenceElement, event) {
806
- // Always stop propagation for the event that initializes
807
- // the dragging sequence, in order to prevent it from potentially
808
- // starting another sequence for a draggable parent somewhere up the DOM tree.
809
- event.stopPropagation();
810
- /** @type {?} */
811
- const isDragging = this._isDragging();
812
- /** @type {?} */
813
- const isTouchEvent = this._isTouchEvent(event);
814
- /** @type {?} */
815
- const isAuxiliaryMouseButton = !isTouchEvent && ((/** @type {?} */ (event))).button !== 0;
816
- /** @type {?} */
817
- const isSyntheticEvent = !isTouchEvent && this._lastTouchEventTime &&
818
- this._lastTouchEventTime + MOUSE_EVENT_IGNORE_TIME > Date.now();
819
- // If the event started from an element with the native HTML drag&drop, it'll interfere
820
- // with our own dragging (e.g. `img` tags do it by default). Prevent the default action
821
- // to stop it from happening. Note that preventing on `dragstart` also seems to work, but
822
- // it's flaky and it fails if the user drags it away quickly. Also note that we only want
823
- // to do this for `mousedown` since doing the same for `touchstart` will stop any `click`
824
- // events from firing on touch devices.
825
- if (event.target && ((/** @type {?} */ (event.target))).draggable && event.type === 'mousedown') {
826
- event.preventDefault();
827
- }
828
- // Abort if the user is already dragging or is using a mouse button other than the primary one.
829
- if (isDragging || isAuxiliaryMouseButton || isSyntheticEvent) {
830
- return;
530
+ disableHandle(handle) {
531
+ if (this._handles.indexOf(handle) > -1) {
532
+ this._disabledHandles.add(handle);
831
533
  }
832
- // Cache the previous transform amount only after the first drag sequence, because
833
- // we don't want our own transforms to stack on top of each other.
834
- if (this._initialTransform == null) {
835
- this._initialTransform = this._rootElement.style.transform || '';
836
- }
837
- this._hasStartedDragging = this._hasMoved = false;
838
- this._initialContainer = this.dropContainer;
839
- this._pointerMoveSubscription = this._dragDropRegistry.pointerMove.subscribe(this._pointerMove);
840
- this._pointerUpSubscription = this._dragDropRegistry.pointerUp.subscribe(this._pointerUp);
841
- this._scrollPosition = this._viewportRuler.getViewportScrollPosition();
842
- // If we have a custom preview template, the element won't be visible anyway so we avoid the
843
- // extra `getBoundingClientRect` calls and just move the preview next to the cursor.
844
- this._pickupPositionInElement = this._previewTemplate ? { x: 0, y: 0 } :
845
- this._getPointerPositionInElement(referenceElement, event);
846
- /** @type {?} */
847
- const pointerPosition = this._pickupPositionOnPage = this._getPointerPositionOnPage(event);
848
- this._pointerDirectionDelta = { x: 0, y: 0 };
849
- this._pointerPositionAtLastDirectionChange = { x: pointerPosition.x, y: pointerPosition.y };
850
- this._dragDropRegistry.startDragging(this, event);
851
534
  }
852
535
  /**
853
- * Starts the dragging sequence.
854
- * @private
855
- * @param {?} event
536
+ * Enables a handle, if it has been disabled.
537
+ * @param {?} handle Handle element to be enabled.
856
538
  * @return {?}
857
539
  */
858
- _startDragSequence(event) {
859
- // Emit the event on the item before the one on the container.
860
- this.started.emit({ source: this });
861
- if (this._isTouchEvent(event)) {
862
- this._lastTouchEventTime = Date.now();
863
- }
864
- if (this.dropContainer) {
865
- /** @type {?} */
866
- const element = this._rootElement;
867
- // Grab the `nextSibling` before the preview and placeholder
868
- // have been created so we don't get the preview by accident.
869
- this._nextSibling = element.nextSibling;
870
- /** @type {?} */
871
- const preview = this._preview = this._createPreviewElement();
872
- /** @type {?} */
873
- const placeholder = this._placeholder = this._createPlaceholderElement();
874
- // We move the element out at the end of the body and we make it hidden, because keeping it in
875
- // place will throw off the consumer's `:last-child` selectors. We can't remove the element
876
- // from the DOM completely, because iOS will stop firing all subsequent events in the chain.
877
- element.style.display = 'none';
878
- this._document.body.appendChild((/** @type {?} */ (element.parentNode)).replaceChild(placeholder, element));
879
- this._document.body.appendChild(preview);
880
- this.dropContainer.start();
881
- }
540
+ enableHandle(handle) {
541
+ this._disabledHandles.delete(handle);
542
+ }
543
+ /**
544
+ * Sets the layout direction of the draggable item.
545
+ * @template THIS
546
+ * @this {THIS}
547
+ * @param {?} direction
548
+ * @return {THIS}
549
+ */
550
+ withDirection(direction) {
551
+ (/** @type {?} */ (this))._direction = direction;
552
+ return (/** @type {?} */ (this));
553
+ }
554
+ /**
555
+ * Sets the container that the item is part of.
556
+ * @param {?} container
557
+ * @return {?}
558
+ */
559
+ _withDropContainer(container) {
560
+ this._dropContainer = container;
561
+ }
562
+ /**
563
+ * Unsubscribes from the global subscriptions.
564
+ * @private
565
+ * @return {?}
566
+ */
567
+ _removeSubscriptions() {
568
+ this._pointerMoveSubscription.unsubscribe();
569
+ this._pointerUpSubscription.unsubscribe();
570
+ }
571
+ /**
572
+ * Destroys the preview element and its ViewRef.
573
+ * @private
574
+ * @return {?}
575
+ */
576
+ _destroyPreview() {
577
+ if (this._preview) {
578
+ removeElement(this._preview);
579
+ }
580
+ if (this._previewRef) {
581
+ this._previewRef.destroy();
582
+ }
583
+ this._preview = this._previewRef = (/** @type {?} */ (null));
584
+ }
585
+ /**
586
+ * Destroys the placeholder element and its ViewRef.
587
+ * @private
588
+ * @return {?}
589
+ */
590
+ _destroyPlaceholder() {
591
+ if (this._placeholder) {
592
+ removeElement(this._placeholder);
593
+ }
594
+ if (this._placeholderRef) {
595
+ this._placeholderRef.destroy();
596
+ }
597
+ this._placeholder = this._placeholderRef = (/** @type {?} */ (null));
598
+ }
599
+ /**
600
+ * Starts the dragging sequence.
601
+ * @private
602
+ * @param {?} event
603
+ * @return {?}
604
+ */
605
+ _startDragSequence(event) {
606
+ // Emit the event on the item before the one on the container.
607
+ this.started.next({ source: this });
608
+ if (isTouchEvent(event)) {
609
+ this._lastTouchEventTime = Date.now();
610
+ }
611
+ if (this._dropContainer) {
612
+ /** @type {?} */
613
+ const element = this._rootElement;
614
+ // Grab the `nextSibling` before the preview and placeholder
615
+ // have been created so we don't get the preview by accident.
616
+ this._nextSibling = element.nextSibling;
617
+ /** @type {?} */
618
+ const preview = this._preview = this._createPreviewElement();
619
+ /** @type {?} */
620
+ const placeholder = this._placeholder = this._createPlaceholderElement();
621
+ // We move the element out at the end of the body and we make it hidden, because keeping it in
622
+ // place will throw off the consumer's `:last-child` selectors. We can't remove the element
623
+ // from the DOM completely, because iOS will stop firing all subsequent events in the chain.
624
+ element.style.display = 'none';
625
+ this._document.body.appendChild((/** @type {?} */ (element.parentNode)).replaceChild(placeholder, element));
626
+ this._document.body.appendChild(preview);
627
+ this._dropContainer.start();
628
+ }
629
+ }
630
+ /**
631
+ * Sets up the different variables and subscriptions
632
+ * that will be necessary for the dragging sequence.
633
+ * @private
634
+ * @param {?} referenceElement Element that started the drag sequence.
635
+ * @param {?} event Browser event object that started the sequence.
636
+ * @return {?}
637
+ */
638
+ _initializeDragSequence(referenceElement, event) {
639
+ // Always stop propagation for the event that initializes
640
+ // the dragging sequence, in order to prevent it from potentially
641
+ // starting another sequence for a draggable parent somewhere up the DOM tree.
642
+ event.stopPropagation();
643
+ /** @type {?} */
644
+ const isDragging = this.isDragging();
645
+ /** @type {?} */
646
+ const isTouchSequence = isTouchEvent(event);
647
+ /** @type {?} */
648
+ const isAuxiliaryMouseButton = !isTouchSequence && ((/** @type {?} */ (event))).button !== 0;
649
+ /** @type {?} */
650
+ const rootElement = this._rootElement;
651
+ /** @type {?} */
652
+ const isSyntheticEvent = !isTouchSequence && this._lastTouchEventTime &&
653
+ this._lastTouchEventTime + MOUSE_EVENT_IGNORE_TIME > Date.now();
654
+ // If the event started from an element with the native HTML drag&drop, it'll interfere
655
+ // with our own dragging (e.g. `img` tags do it by default). Prevent the default action
656
+ // to stop it from happening. Note that preventing on `dragstart` also seems to work, but
657
+ // it's flaky and it fails if the user drags it away quickly. Also note that we only want
658
+ // to do this for `mousedown` since doing the same for `touchstart` will stop any `click`
659
+ // events from firing on touch devices.
660
+ if (event.target && ((/** @type {?} */ (event.target))).draggable && event.type === 'mousedown') {
661
+ event.preventDefault();
662
+ }
663
+ // Abort if the user is already dragging or is using a mouse button other than the primary one.
664
+ if (isDragging || isAuxiliaryMouseButton || isSyntheticEvent) {
665
+ return;
666
+ }
667
+ // Cache the previous transform amount only after the first drag sequence, because
668
+ // we don't want our own transforms to stack on top of each other.
669
+ if (this._initialTransform == null) {
670
+ this._initialTransform = this._rootElement.style.transform || '';
671
+ }
672
+ // If we've got handles, we need to disable the tap highlight on the entire root element,
673
+ // otherwise iOS will still add it, even though all the drag interactions on the handle
674
+ // are disabled.
675
+ if (this._handles.length) {
676
+ this._rootElementTapHighlight = rootElement.style.webkitTapHighlightColor;
677
+ rootElement.style.webkitTapHighlightColor = 'transparent';
678
+ }
679
+ this._toggleNativeDragInteractions();
680
+ this._hasStartedDragging = this._hasMoved = false;
681
+ this._initialContainer = (/** @type {?} */ (this._dropContainer));
682
+ this._pointerMoveSubscription = this._dragDropRegistry.pointerMove.subscribe(this._pointerMove);
683
+ this._pointerUpSubscription = this._dragDropRegistry.pointerUp.subscribe(this._pointerUp);
684
+ this._scrollPosition = this._viewportRuler.getViewportScrollPosition();
685
+ if (this._boundaryElement) {
686
+ this._boundaryRect = this._boundaryElement.getBoundingClientRect();
687
+ }
688
+ // If we have a custom preview template, the element won't be visible anyway so we avoid the
689
+ // extra `getBoundingClientRect` calls and just move the preview next to the cursor.
690
+ this._pickupPositionInElement = this._previewTemplate && this._previewTemplate.template ?
691
+ { x: 0, y: 0 } :
692
+ this._getPointerPositionInElement(referenceElement, event);
693
+ /** @type {?} */
694
+ const pointerPosition = this._pickupPositionOnPage = this._getPointerPositionOnPage(event);
695
+ this._pointerDirectionDelta = { x: 0, y: 0 };
696
+ this._pointerPositionAtLastDirectionChange = { x: pointerPosition.x, y: pointerPosition.y };
697
+ this._dragDropRegistry.startDragging(this, event);
882
698
  }
883
699
  /**
884
700
  * Cleans up the DOM artifacts that were added to facilitate the element being dragged.
885
701
  * @private
702
+ * @param {?} event
886
703
  * @return {?}
887
704
  */
888
- _cleanupDragArtifacts() {
705
+ _cleanupDragArtifacts(event) {
889
706
  // Restore the element's visibility and insert it at its old position in the DOM.
890
707
  // It's important that we maintain the position, because moving the element around in the DOM
891
708
  // can throw off `NgFor` which does smart diffing and re-creates elements only when necessary,
@@ -895,24 +712,31 @@ class CdkDrag {
895
712
  (/** @type {?} */ (this._nextSibling.parentNode)).insertBefore(this._rootElement, this._nextSibling);
896
713
  }
897
714
  else {
898
- this._initialContainer.element.nativeElement.appendChild(this._rootElement);
715
+ this._initialContainer.element.appendChild(this._rootElement);
899
716
  }
900
717
  this._destroyPreview();
901
718
  this._destroyPlaceholder();
719
+ this._boundaryRect = this._previewRect = undefined;
902
720
  // Re-enter the NgZone since we bound `document` events on the outside.
903
721
  this._ngZone.run(() => {
904
722
  /** @type {?} */
905
- const currentIndex = this.dropContainer.getItemIndex(this);
906
- this.ended.emit({ source: this });
907
- this.dropped.emit({
723
+ const container = (/** @type {?} */ (this._dropContainer));
724
+ /** @type {?} */
725
+ const currentIndex = container.getItemIndex(this);
726
+ const { x, y } = this._getPointerPositionOnPage(event);
727
+ /** @type {?} */
728
+ const isPointerOverContainer = container._isOverContainer(x, y);
729
+ this.ended.next({ source: this });
730
+ this.dropped.next({
908
731
  item: this,
909
732
  currentIndex,
910
733
  previousIndex: this._initialContainer.getItemIndex(this),
911
- container: this.dropContainer,
912
- previousContainer: this._initialContainer
734
+ container: container,
735
+ previousContainer: this._initialContainer,
736
+ isPointerOverContainer
913
737
  });
914
- this.dropContainer.drop(this, currentIndex, this._initialContainer);
915
- this.dropContainer = this._initialContainer;
738
+ container.drop(this, currentIndex, this._initialContainer, isPointerOverContainer);
739
+ this._dropContainer = this._initialContainer;
916
740
  });
917
741
  }
918
742
  /**
@@ -925,27 +749,28 @@ class CdkDrag {
925
749
  _updateActiveDropContainer({ x, y }) {
926
750
  // Drop container that draggable has been moved into.
927
751
  /** @type {?} */
928
- let newContainer = this.dropContainer._getSiblingContainerFromPosition(this, x, y);
752
+ let newContainer = (/** @type {?} */ (this._dropContainer))._getSiblingContainerFromPosition(this, x, y) ||
753
+ this._initialContainer._getSiblingContainerFromPosition(this, x, y);
929
754
  // If we couldn't find a new container to move the item into, and the item has left it's
930
- // initial container, check whether the it's allowed to return into its original container.
931
- // This handles the case where two containers are connected one way and the user tries to
932
- // undo dragging an item into a new container.
933
- if (!newContainer && this.dropContainer !== this._initialContainer &&
934
- this._initialContainer._canReturnItem(x, y)) {
755
+ // initial container, check whether the it's over the initial container. This handles the
756
+ // case where two containers are connected one way and the user tries to undo dragging an
757
+ // item into a new container.
758
+ if (!newContainer && this._dropContainer !== this._initialContainer &&
759
+ this._initialContainer._isOverContainer(x, y)) {
935
760
  newContainer = this._initialContainer;
936
761
  }
937
- if (newContainer) {
762
+ if (newContainer && newContainer !== this._dropContainer) {
938
763
  this._ngZone.run(() => {
939
764
  // Notify the old container that the item has left.
940
- this.exited.emit({ item: this, container: this.dropContainer });
941
- this.dropContainer.exit(this);
765
+ this.exited.next({ item: this, container: (/** @type {?} */ (this._dropContainer)) });
766
+ (/** @type {?} */ (this._dropContainer)).exit(this);
942
767
  // Notify the new container that the item has entered.
943
- this.entered.emit({ item: this, container: (/** @type {?} */ (newContainer)) });
944
- this.dropContainer = (/** @type {?} */ (newContainer));
945
- this.dropContainer.enter(this, x, y);
768
+ this.entered.next({ item: this, container: (/** @type {?} */ (newContainer)) });
769
+ this._dropContainer = (/** @type {?} */ (newContainer));
770
+ this._dropContainer.enter(this, x, y);
946
771
  });
947
772
  }
948
- this.dropContainer._sortItem(this, x, y, this._pointerDirectionDelta);
773
+ (/** @type {?} */ (this._dropContainer))._sortItem(this, x, y, this._pointerDirectionDelta);
949
774
  this._preview.style.transform =
950
775
  getTransform(x - this._pickupPositionInElement.x, y - this._pickupPositionInElement.y);
951
776
  }
@@ -956,11 +781,15 @@ class CdkDrag {
956
781
  * @return {?}
957
782
  */
958
783
  _createPreviewElement() {
784
+ /** @type {?} */
785
+ const previewConfig = this._previewTemplate;
786
+ /** @type {?} */
787
+ const previewTemplate = previewConfig ? previewConfig.template : null;
959
788
  /** @type {?} */
960
789
  let preview;
961
- if (this._previewTemplate) {
790
+ if (previewTemplate) {
962
791
  /** @type {?} */
963
- const viewRef = this._viewContainerRef.createEmbeddedView(this._previewTemplate.templateRef, this._previewTemplate.data);
792
+ const viewRef = (/** @type {?} */ (previewConfig)).viewContainer.createEmbeddedView(previewTemplate, (/** @type {?} */ (previewConfig)).context);
964
793
  preview = viewRef.rootNodes[0];
965
794
  this._previewRef = viewRef;
966
795
  preview.style.transform =
@@ -977,244 +806,1716 @@ class CdkDrag {
977
806
  preview.style.transform = getTransform(elementRect.left, elementRect.top);
978
807
  }
979
808
  extendStyles(preview.style, {
809
+ // It's important that we disable the pointer events on the preview, because
810
+ // it can throw off the `document.elementFromPoint` calls in the `CdkDropList`.
811
+ pointerEvents: 'none',
980
812
  position: 'fixed',
981
813
  top: '0',
982
814
  left: '0',
983
815
  zIndex: '1000'
984
816
  });
817
+ toggleNativeDragInteractions(preview, false);
985
818
  preview.classList.add('cdk-drag-preview');
986
- preview.setAttribute('dir', this._dir ? this._dir.value : 'ltr');
819
+ preview.setAttribute('dir', this._direction);
987
820
  return preview;
988
821
  }
822
+ /**
823
+ * Animates the preview element from its current position to the location of the drop placeholder.
824
+ * @private
825
+ * @return {?} Promise that resolves when the animation completes.
826
+ */
827
+ _animatePreviewToPlaceholder() {
828
+ // If the user hasn't moved yet, the transitionend event won't fire.
829
+ if (!this._hasMoved) {
830
+ return Promise.resolve();
831
+ }
832
+ /** @type {?} */
833
+ const placeholderRect = this._placeholder.getBoundingClientRect();
834
+ // Apply the class that adds a transition to the preview.
835
+ this._preview.classList.add('cdk-drag-animating');
836
+ // Move the preview to the placeholder position.
837
+ this._preview.style.transform = getTransform(placeholderRect.left, placeholderRect.top);
838
+ // If the element doesn't have a `transition`, the `transitionend` event won't fire. Since
839
+ // we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
840
+ // apply its style, we take advantage of the available info to figure out whether we need to
841
+ // bind the event in the first place.
842
+ /** @type {?} */
843
+ const duration = getTransformTransitionDurationInMs(this._preview);
844
+ if (duration === 0) {
845
+ return Promise.resolve();
846
+ }
847
+ return this._ngZone.runOutsideAngular(() => {
848
+ return new Promise(resolve => {
849
+ /** @type {?} */
850
+ const handler = (/** @type {?} */ (((event) => {
851
+ if (!event || (event.target === this._preview && event.propertyName === 'transform')) {
852
+ this._preview.removeEventListener('transitionend', handler);
853
+ resolve();
854
+ clearTimeout(timeout);
855
+ }
856
+ })));
857
+ // If a transition is short enough, the browser might not fire the `transitionend` event.
858
+ // Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
859
+ // fire if the transition hasn't completed when it was supposed to.
860
+ /** @type {?} */
861
+ const timeout = setTimeout((/** @type {?} */ (handler)), duration * 1.5);
862
+ this._preview.addEventListener('transitionend', handler);
863
+ });
864
+ });
865
+ }
989
866
  /**
990
867
  * Creates an element that will be shown instead of the current element while dragging.
991
868
  * @private
992
869
  * @return {?}
993
870
  */
994
871
  _createPlaceholderElement() {
872
+ /** @type {?} */
873
+ const placeholderConfig = this._placeholderTemplate;
874
+ /** @type {?} */
875
+ const placeholderTemplate = placeholderConfig ? placeholderConfig.template : null;
995
876
  /** @type {?} */
996
877
  let placeholder;
997
- if (this._placeholderTemplate) {
998
- this._placeholderRef = this._viewContainerRef.createEmbeddedView(this._placeholderTemplate.templateRef, this._placeholderTemplate.data);
878
+ if (placeholderTemplate) {
879
+ this._placeholderRef = (/** @type {?} */ (placeholderConfig)).viewContainer.createEmbeddedView(placeholderTemplate, (/** @type {?} */ (placeholderConfig)).context);
999
880
  placeholder = this._placeholderRef.rootNodes[0];
1000
881
  }
1001
882
  else {
1002
- placeholder = deepCloneNode(this._rootElement);
883
+ placeholder = deepCloneNode(this._rootElement);
884
+ }
885
+ placeholder.classList.add('cdk-drag-placeholder');
886
+ return placeholder;
887
+ }
888
+ /**
889
+ * Figures out the coordinates at which an element was picked up.
890
+ * @private
891
+ * @param {?} referenceElement Element that initiated the dragging.
892
+ * @param {?} event Event that initiated the dragging.
893
+ * @return {?}
894
+ */
895
+ _getPointerPositionInElement(referenceElement, event) {
896
+ /** @type {?} */
897
+ const elementRect = this._rootElement.getBoundingClientRect();
898
+ /** @type {?} */
899
+ const handleElement = referenceElement === this._rootElement ? null : referenceElement;
900
+ /** @type {?} */
901
+ const referenceRect = handleElement ? handleElement.getBoundingClientRect() : elementRect;
902
+ /** @type {?} */
903
+ const point = isTouchEvent(event) ? event.targetTouches[0] : event;
904
+ /** @type {?} */
905
+ const x = point.pageX - referenceRect.left - this._scrollPosition.left;
906
+ /** @type {?} */
907
+ const y = point.pageY - referenceRect.top - this._scrollPosition.top;
908
+ return {
909
+ x: referenceRect.left - elementRect.left + x,
910
+ y: referenceRect.top - elementRect.top + y
911
+ };
912
+ }
913
+ /**
914
+ * Determines the point of the page that was touched by the user.
915
+ * @private
916
+ * @param {?} event
917
+ * @return {?}
918
+ */
919
+ _getPointerPositionOnPage(event) {
920
+ // `touches` will be empty for start/end events so we have to fall back to `changedTouches`.
921
+ /** @type {?} */
922
+ const point = isTouchEvent(event) ? (event.touches[0] || event.changedTouches[0]) : event;
923
+ return {
924
+ x: point.pageX - this._scrollPosition.left,
925
+ y: point.pageY - this._scrollPosition.top
926
+ };
927
+ }
928
+ /**
929
+ * Gets the pointer position on the page, accounting for any position constraints.
930
+ * @private
931
+ * @param {?} event
932
+ * @return {?}
933
+ */
934
+ _getConstrainedPointerPosition(event) {
935
+ /** @type {?} */
936
+ const point = this._getPointerPositionOnPage(event);
937
+ /** @type {?} */
938
+ const dropContainerLock = this._dropContainer ? this._dropContainer.lockAxis : null;
939
+ if (this.lockAxis === 'x' || dropContainerLock === 'x') {
940
+ point.y = this._pickupPositionOnPage.y;
941
+ }
942
+ else if (this.lockAxis === 'y' || dropContainerLock === 'y') {
943
+ point.x = this._pickupPositionOnPage.x;
944
+ }
945
+ if (this._boundaryRect) {
946
+ const { x: pickupX, y: pickupY } = this._pickupPositionInElement;
947
+ /** @type {?} */
948
+ const boundaryRect = this._boundaryRect;
949
+ /** @type {?} */
950
+ const previewRect = (/** @type {?} */ (this._previewRect));
951
+ /** @type {?} */
952
+ const minY = boundaryRect.top + pickupY;
953
+ /** @type {?} */
954
+ const maxY = boundaryRect.bottom - (previewRect.height - pickupY);
955
+ /** @type {?} */
956
+ const minX = boundaryRect.left + pickupX;
957
+ /** @type {?} */
958
+ const maxX = boundaryRect.right - (previewRect.width - pickupX);
959
+ point.x = clamp(point.x, minX, maxX);
960
+ point.y = clamp(point.y, minY, maxY);
961
+ }
962
+ return point;
963
+ }
964
+ /**
965
+ * Updates the current drag delta, based on the user's current pointer position on the page.
966
+ * @private
967
+ * @param {?} pointerPositionOnPage
968
+ * @return {?}
969
+ */
970
+ _updatePointerDirectionDelta(pointerPositionOnPage) {
971
+ const { x, y } = pointerPositionOnPage;
972
+ /** @type {?} */
973
+ const delta = this._pointerDirectionDelta;
974
+ /** @type {?} */
975
+ const positionSinceLastChange = this._pointerPositionAtLastDirectionChange;
976
+ // Amount of pixels the user has dragged since the last time the direction changed.
977
+ /** @type {?} */
978
+ const changeX = Math.abs(x - positionSinceLastChange.x);
979
+ /** @type {?} */
980
+ const changeY = Math.abs(y - positionSinceLastChange.y);
981
+ // Because we handle pointer events on a per-pixel basis, we don't want the delta
982
+ // to change for every pixel, otherwise anything that depends on it can look erratic.
983
+ // To make the delta more consistent, we track how much the user has moved since the last
984
+ // delta change and we only update it after it has reached a certain threshold.
985
+ if (changeX > this._config.pointerDirectionChangeThreshold) {
986
+ delta.x = x > positionSinceLastChange.x ? 1 : -1;
987
+ positionSinceLastChange.x = x;
988
+ }
989
+ if (changeY > this._config.pointerDirectionChangeThreshold) {
990
+ delta.y = y > positionSinceLastChange.y ? 1 : -1;
991
+ positionSinceLastChange.y = y;
992
+ }
993
+ return delta;
994
+ }
995
+ /**
996
+ * Toggles the native drag interactions, based on how many handles are registered.
997
+ * @private
998
+ * @return {?}
999
+ */
1000
+ _toggleNativeDragInteractions() {
1001
+ if (!this._rootElement || !this._handles) {
1002
+ return;
1003
+ }
1004
+ /** @type {?} */
1005
+ const shouldEnable = this.disabled || this._handles.length > 0;
1006
+ if (shouldEnable !== this._nativeInteractionsEnabled) {
1007
+ this._nativeInteractionsEnabled = shouldEnable;
1008
+ toggleNativeDragInteractions(this._rootElement, shouldEnable);
1009
+ }
1010
+ }
1011
+ /**
1012
+ * Removes the manually-added event listeners from the root element.
1013
+ * @private
1014
+ * @param {?} element
1015
+ * @return {?}
1016
+ */
1017
+ _removeRootElementListeners(element) {
1018
+ element.removeEventListener('mousedown', this._pointerDown, activeEventListenerOptions);
1019
+ element.removeEventListener('touchstart', this._pointerDown, passiveEventListenerOptions);
1020
+ }
1021
+ }
1022
+ /**
1023
+ * Gets a 3d `transform` that can be applied to an element.
1024
+ * @param {?} x Desired position of the element along the X axis.
1025
+ * @param {?} y Desired position of the element along the Y axis.
1026
+ * @return {?}
1027
+ */
1028
+ function getTransform(x, y) {
1029
+ // Round the transforms since some browsers will
1030
+ // blur the elements for sub-pixel transforms.
1031
+ return `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`;
1032
+ }
1033
+ /**
1034
+ * Creates a deep clone of an element.
1035
+ * @param {?} node
1036
+ * @return {?}
1037
+ */
1038
+ function deepCloneNode(node) {
1039
+ /** @type {?} */
1040
+ const clone = (/** @type {?} */ (node.cloneNode(true)));
1041
+ // Remove the `id` to avoid having multiple elements with the same id on the page.
1042
+ clone.removeAttribute('id');
1043
+ return clone;
1044
+ }
1045
+ /**
1046
+ * Clamps a value between a minimum and a maximum.
1047
+ * @param {?} value
1048
+ * @param {?} min
1049
+ * @param {?} max
1050
+ * @return {?}
1051
+ */
1052
+ function clamp(value, min, max) {
1053
+ return Math.max(min, Math.min(max, value));
1054
+ }
1055
+ /**
1056
+ * Helper to remove an element from the DOM and to do all the necessary null checks.
1057
+ * @param {?} element Element to be removed.
1058
+ * @return {?}
1059
+ */
1060
+ function removeElement(element) {
1061
+ if (element && element.parentNode) {
1062
+ element.parentNode.removeChild(element);
1063
+ }
1064
+ }
1065
+ /**
1066
+ * Determines whether an event is a touch event.
1067
+ * @param {?} event
1068
+ * @return {?}
1069
+ */
1070
+ function isTouchEvent(event) {
1071
+ return event.type.startsWith('touch');
1072
+ }
1073
+
1074
+ /**
1075
+ * @fileoverview added by tsickle
1076
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1077
+ */
1078
+
1079
+ /**
1080
+ * Moves an item one index in an array to another.
1081
+ * @template T
1082
+ * @param {?} array Array in which to move the item.
1083
+ * @param {?} fromIndex Starting index of the item.
1084
+ * @param {?} toIndex Index to which the item should be moved.
1085
+ * @return {?}
1086
+ */
1087
+ function moveItemInArray(array, fromIndex, toIndex) {
1088
+ /** @type {?} */
1089
+ const from = clamp$1(fromIndex, array.length - 1);
1090
+ /** @type {?} */
1091
+ const to = clamp$1(toIndex, array.length - 1);
1092
+ if (from === to) {
1093
+ return;
1094
+ }
1095
+ /** @type {?} */
1096
+ const target = array[from];
1097
+ /** @type {?} */
1098
+ const delta = to < from ? -1 : 1;
1099
+ for (let i = from; i !== to; i += delta) {
1100
+ array[i] = array[i + delta];
1101
+ }
1102
+ array[to] = target;
1103
+ }
1104
+ /**
1105
+ * Moves an item from one array to another.
1106
+ * @template T
1107
+ * @param {?} currentArray Array from which to transfer the item.
1108
+ * @param {?} targetArray Array into which to put the item.
1109
+ * @param {?} currentIndex Index of the item in its current array.
1110
+ * @param {?} targetIndex Index at which to insert the item.
1111
+ * @return {?}
1112
+ */
1113
+ function transferArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
1114
+ /** @type {?} */
1115
+ const from = clamp$1(currentIndex, currentArray.length - 1);
1116
+ /** @type {?} */
1117
+ const to = clamp$1(targetIndex, targetArray.length);
1118
+ if (currentArray.length) {
1119
+ targetArray.splice(to, 0, currentArray.splice(from, 1)[0]);
1120
+ }
1121
+ }
1122
+ /**
1123
+ * Copies an item from one array to another, leaving it in its
1124
+ * original position in current array.
1125
+ * @template T
1126
+ * @param {?} currentArray Array from which to copy the item.
1127
+ * @param {?} targetArray Array into which is copy the item.
1128
+ * @param {?} currentIndex Index of the item in its current array.
1129
+ * @param {?} targetIndex Index at which to insert the item.
1130
+ *
1131
+ * @return {?}
1132
+ */
1133
+ function copyArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
1134
+ /** @type {?} */
1135
+ const to = clamp$1(targetIndex, targetArray.length);
1136
+ if (currentArray.length) {
1137
+ targetArray.splice(to, 0, currentArray[currentIndex]);
1138
+ }
1139
+ }
1140
+ /**
1141
+ * Clamps a number between zero and a maximum.
1142
+ * @param {?} value
1143
+ * @param {?} max
1144
+ * @return {?}
1145
+ */
1146
+ function clamp$1(value, max) {
1147
+ return Math.max(0, Math.min(max, value));
1148
+ }
1149
+
1150
+ /**
1151
+ * @fileoverview added by tsickle
1152
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1153
+ */
1154
+ /**
1155
+ * Counter used to generate unique ids for drop refs.
1156
+ * @type {?}
1157
+ */
1158
+ let _uniqueIdCounter = 0;
1159
+ /**
1160
+ * Proximity, as a ratio to width/height, at which a
1161
+ * dragged item will affect the drop container.
1162
+ * @type {?}
1163
+ */
1164
+ const DROP_PROXIMITY_THRESHOLD = 0.05;
1165
+ /**
1166
+ * Reference to a drop list. Used to manipulate or dispose of the container.
1167
+ * \@docs-private
1168
+ * @template T
1169
+ */
1170
+ class DropListRef {
1171
+ /**
1172
+ * @param {?} element
1173
+ * @param {?} _dragDropRegistry
1174
+ * @param {?} _document
1175
+ */
1176
+ constructor(element, _dragDropRegistry, _document) {
1177
+ this._dragDropRegistry = _dragDropRegistry;
1178
+ /**
1179
+ * Unique ID for the drop list.
1180
+ * @deprecated No longer being used. To be removed.
1181
+ * \@breaking-change 8.0.0
1182
+ */
1183
+ this.id = `cdk-drop-list-ref-${_uniqueIdCounter++}`;
1184
+ /**
1185
+ * Whether starting a dragging sequence from this container is disabled.
1186
+ */
1187
+ this.disabled = false;
1188
+ /**
1189
+ * Function that is used to determine whether an item
1190
+ * is allowed to be moved into a drop container.
1191
+ */
1192
+ this.enterPredicate = () => true;
1193
+ /**
1194
+ * Emits right before dragging has started.
1195
+ */
1196
+ this.beforeStarted = new Subject();
1197
+ /**
1198
+ * Emits when the user has moved a new drag item into this container.
1199
+ */
1200
+ this.entered = new Subject();
1201
+ /**
1202
+ * Emits when the user removes an item from the container
1203
+ * by dragging it into another container.
1204
+ */
1205
+ this.exited = new Subject();
1206
+ /**
1207
+ * Emits when the user drops an item inside the container.
1208
+ */
1209
+ this.dropped = new Subject();
1210
+ /**
1211
+ * Emits as the user is swapping items while actively dragging.
1212
+ */
1213
+ this.sorted = new Subject();
1214
+ /**
1215
+ * Whether an item in the list is being dragged.
1216
+ */
1217
+ this._isDragging = false;
1218
+ /**
1219
+ * Cache of the dimensions of all the items inside the container.
1220
+ */
1221
+ this._itemPositions = [];
1222
+ /**
1223
+ * Keeps track of the item that was last swapped with the dragged item, as
1224
+ * well as what direction the pointer was moving in when the swap occured.
1225
+ */
1226
+ this._previousSwap = { drag: (/** @type {?} */ (null)), delta: 0 };
1227
+ /**
1228
+ * Drop lists that are connected to the current one.
1229
+ */
1230
+ this._siblings = [];
1231
+ /**
1232
+ * Direction in which the list is oriented.
1233
+ */
1234
+ this._orientation = 'vertical';
1235
+ /**
1236
+ * Connected siblings that currently have a dragged item.
1237
+ */
1238
+ this._activeSiblings = new Set();
1239
+ /**
1240
+ * Layout direction of the drop list.
1241
+ */
1242
+ this._direction = 'ltr';
1243
+ _dragDropRegistry.registerDropContainer(this);
1244
+ this._document = _document;
1245
+ this.element = element instanceof ElementRef ? element.nativeElement : element;
1246
+ }
1247
+ /**
1248
+ * Removes the drop list functionality from the DOM element.
1249
+ * @return {?}
1250
+ */
1251
+ dispose() {
1252
+ this.beforeStarted.complete();
1253
+ this.entered.complete();
1254
+ this.exited.complete();
1255
+ this.dropped.complete();
1256
+ this.sorted.complete();
1257
+ this._activeSiblings.clear();
1258
+ this._dragDropRegistry.removeDropContainer(this);
1259
+ }
1260
+ /**
1261
+ * Whether an item from this list is currently being dragged.
1262
+ * @return {?}
1263
+ */
1264
+ isDragging() {
1265
+ return this._isDragging;
1266
+ }
1267
+ /**
1268
+ * Starts dragging an item.
1269
+ * @return {?}
1270
+ */
1271
+ start() {
1272
+ this.beforeStarted.next();
1273
+ this._isDragging = true;
1274
+ this._activeDraggables = this._draggables.slice();
1275
+ this._cacheOwnPosition();
1276
+ this._cacheItemPositions();
1277
+ this._siblings.forEach(sibling => sibling._startReceiving(this));
1278
+ }
1279
+ /**
1280
+ * Emits an event to indicate that the user moved an item into the container.
1281
+ * @param {?} item Item that was moved into the container.
1282
+ * @param {?} pointerX Position of the item along the X axis.
1283
+ * @param {?} pointerY Position of the item along the Y axis.
1284
+ * @return {?}
1285
+ */
1286
+ enter(item, pointerX, pointerY) {
1287
+ this.entered.next({ item, container: this });
1288
+ this.start();
1289
+ // We use the coordinates of where the item entered the drop
1290
+ // zone to figure out at which index it should be inserted.
1291
+ /** @type {?} */
1292
+ const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY);
1293
+ /** @type {?} */
1294
+ const currentIndex = this._activeDraggables.indexOf(item);
1295
+ /** @type {?} */
1296
+ const newPositionReference = this._activeDraggables[newIndex];
1297
+ /** @type {?} */
1298
+ const placeholder = item.getPlaceholderElement();
1299
+ // Since the item may be in the `activeDraggables` already (e.g. if the user dragged it
1300
+ // into another container and back again), we have to ensure that it isn't duplicated.
1301
+ if (currentIndex > -1) {
1302
+ this._activeDraggables.splice(currentIndex, 1);
1303
+ }
1304
+ // Don't use items that are being dragged as a reference, because
1305
+ // their element has been moved down to the bottom of the body.
1306
+ if (newPositionReference && !this._dragDropRegistry.isDragging(newPositionReference)) {
1307
+ /** @type {?} */
1308
+ const element = newPositionReference.getRootElement();
1309
+ (/** @type {?} */ (element.parentElement)).insertBefore(placeholder, element);
1310
+ this._activeDraggables.splice(newIndex, 0, item);
1311
+ }
1312
+ else {
1313
+ this.element.appendChild(placeholder);
1314
+ this._activeDraggables.push(item);
1315
+ }
1316
+ // The transform needs to be cleared so it doesn't throw off the measurements.
1317
+ placeholder.style.transform = '';
1318
+ // Note that the positions were already cached when we called `start` above,
1319
+ // but we need to refresh them since the amount of items has changed.
1320
+ this._cacheItemPositions();
1321
+ }
1322
+ /**
1323
+ * Removes an item from the container after it was dragged into another container by the user.
1324
+ * @param {?} item Item that was dragged out.
1325
+ * @return {?}
1326
+ */
1327
+ exit(item) {
1328
+ this._reset();
1329
+ this.exited.next({ item, container: this });
1330
+ }
1331
+ /**
1332
+ * Drops an item into this container.
1333
+ * @param {?} item Item being dropped into the container.
1334
+ * @param {?} currentIndex Index at which the item should be inserted.
1335
+ * @param {?} previousContainer Container from which the item got dragged in.
1336
+ * @param {?} isPointerOverContainer Whether the user's pointer was over the
1337
+ * container when the item was dropped.
1338
+ * @return {?}
1339
+ */
1340
+ drop(item, currentIndex, previousContainer, isPointerOverContainer) {
1341
+ this._reset();
1342
+ this.dropped.next({
1343
+ item,
1344
+ currentIndex,
1345
+ previousIndex: previousContainer.getItemIndex(item),
1346
+ container: this,
1347
+ previousContainer,
1348
+ isPointerOverContainer
1349
+ });
1350
+ }
1351
+ /**
1352
+ * Sets the draggable items that are a part of this list.
1353
+ * @template THIS
1354
+ * @this {THIS}
1355
+ * @param {?} items Items that are a part of this list.
1356
+ * @return {THIS}
1357
+ */
1358
+ withItems(items) {
1359
+ (/** @type {?} */ (this))._draggables = items.slice();
1360
+ items.forEach(item => item._withDropContainer((/** @type {?} */ (this))));
1361
+ return (/** @type {?} */ (this));
1362
+ }
1363
+ /**
1364
+ * Sets the layout direction of the drop list.
1365
+ * @template THIS
1366
+ * @this {THIS}
1367
+ * @param {?} direction
1368
+ * @return {THIS}
1369
+ */
1370
+ withDirection(direction) {
1371
+ (/** @type {?} */ (this))._direction = direction;
1372
+ return (/** @type {?} */ (this));
1373
+ }
1374
+ /**
1375
+ * Sets the containers that are connected to this one. When two or more containers are
1376
+ * connected, the user will be allowed to transfer items between them.
1377
+ * @template THIS
1378
+ * @this {THIS}
1379
+ * @param {?} connectedTo Other containers that the current containers should be connected to.
1380
+ * @return {THIS}
1381
+ */
1382
+ connectedTo(connectedTo) {
1383
+ (/** @type {?} */ (this))._siblings = connectedTo.slice();
1384
+ return (/** @type {?} */ (this));
1385
+ }
1386
+ /**
1387
+ * Sets the orientation of the container.
1388
+ * @template THIS
1389
+ * @this {THIS}
1390
+ * @param {?} orientation New orientation for the container.
1391
+ * @return {THIS}
1392
+ */
1393
+ withOrientation(orientation) {
1394
+ (/** @type {?} */ (this))._orientation = orientation;
1395
+ return (/** @type {?} */ (this));
1396
+ }
1397
+ /**
1398
+ * Figures out the index of an item in the container.
1399
+ * @param {?} item Item whose index should be determined.
1400
+ * @return {?}
1401
+ */
1402
+ getItemIndex(item) {
1403
+ if (!this._isDragging) {
1404
+ return this._draggables.indexOf(item);
1405
+ }
1406
+ // Items are sorted always by top/left in the cache, however they flow differently in RTL.
1407
+ // The rest of the logic still stands no matter what orientation we're in, however
1408
+ // we need to invert the array when determining the index.
1409
+ /** @type {?} */
1410
+ const items = this._orientation === 'horizontal' && this._direction === 'rtl' ?
1411
+ this._itemPositions.slice().reverse() : this._itemPositions;
1412
+ return findIndex(items, currentItem => currentItem.drag === item);
1413
+ }
1414
+ /**
1415
+ * Whether the list is able to receive the item that
1416
+ * is currently being dragged inside a connected drop list.
1417
+ * @return {?}
1418
+ */
1419
+ isReceiving() {
1420
+ return this._activeSiblings.size > 0;
1421
+ }
1422
+ /**
1423
+ * Sorts an item inside the container based on its position.
1424
+ * @param {?} item Item to be sorted.
1425
+ * @param {?} pointerX Position of the item along the X axis.
1426
+ * @param {?} pointerY Position of the item along the Y axis.
1427
+ * @param {?} pointerDelta Direction in which the pointer is moving along each axis.
1428
+ * @return {?}
1429
+ */
1430
+ _sortItem(item, pointerX, pointerY, pointerDelta) {
1431
+ // Don't sort the item if it's out of range.
1432
+ if (!this._isPointerNearDropContainer(pointerX, pointerY)) {
1433
+ return;
1434
+ }
1435
+ /** @type {?} */
1436
+ const siblings = this._itemPositions;
1437
+ /** @type {?} */
1438
+ const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY, pointerDelta);
1439
+ if (newIndex === -1 && siblings.length > 0) {
1440
+ return;
1441
+ }
1442
+ /** @type {?} */
1443
+ const isHorizontal = this._orientation === 'horizontal';
1444
+ /** @type {?} */
1445
+ const currentIndex = findIndex(siblings, currentItem => currentItem.drag === item);
1446
+ /** @type {?} */
1447
+ const siblingAtNewPosition = siblings[newIndex];
1448
+ /** @type {?} */
1449
+ const currentPosition = siblings[currentIndex].clientRect;
1450
+ /** @type {?} */
1451
+ const newPosition = siblingAtNewPosition.clientRect;
1452
+ /** @type {?} */
1453
+ const delta = currentIndex > newIndex ? 1 : -1;
1454
+ this._previousSwap.drag = siblingAtNewPosition.drag;
1455
+ this._previousSwap.delta = isHorizontal ? pointerDelta.x : pointerDelta.y;
1456
+ // How many pixels the item's placeholder should be offset.
1457
+ /** @type {?} */
1458
+ const itemOffset = this._getItemOffsetPx(currentPosition, newPosition, delta);
1459
+ // How many pixels all the other items should be offset.
1460
+ /** @type {?} */
1461
+ const siblingOffset = this._getSiblingOffsetPx(currentIndex, siblings, delta);
1462
+ // Save the previous order of the items before moving the item to its new index.
1463
+ // We use this to check whether an item has been moved as a result of the sorting.
1464
+ /** @type {?} */
1465
+ const oldOrder = siblings.slice();
1466
+ // Shuffle the array in place.
1467
+ moveItemInArray(siblings, currentIndex, newIndex);
1468
+ this.sorted.next({
1469
+ previousIndex: currentIndex,
1470
+ currentIndex: newIndex,
1471
+ container: this,
1472
+ item
1473
+ });
1474
+ siblings.forEach((sibling, index) => {
1475
+ // Don't do anything if the position hasn't changed.
1476
+ if (oldOrder[index] === sibling) {
1477
+ return;
1478
+ }
1479
+ /** @type {?} */
1480
+ const isDraggedItem = sibling.drag === item;
1481
+ /** @type {?} */
1482
+ const offset = isDraggedItem ? itemOffset : siblingOffset;
1483
+ /** @type {?} */
1484
+ const elementToOffset = isDraggedItem ? item.getPlaceholderElement() :
1485
+ sibling.drag.getRootElement();
1486
+ // Update the offset to reflect the new position.
1487
+ sibling.offset += offset;
1488
+ // Since we're moving the items with a `transform`, we need to adjust their cached
1489
+ // client rects to reflect their new position, as well as swap their positions in the cache.
1490
+ // Note that we shouldn't use `getBoundingClientRect` here to update the cache, because the
1491
+ // elements may be mid-animation which will give us a wrong result.
1492
+ if (isHorizontal) {
1493
+ // Round the transforms since some browsers will
1494
+ // blur the elements, for sub-pixel transforms.
1495
+ elementToOffset.style.transform = `translate3d(${Math.round(sibling.offset)}px, 0, 0)`;
1496
+ adjustClientRect(sibling.clientRect, 0, offset);
1497
+ }
1498
+ else {
1499
+ elementToOffset.style.transform = `translate3d(0, ${Math.round(sibling.offset)}px, 0)`;
1500
+ adjustClientRect(sibling.clientRect, offset, 0);
1501
+ }
1502
+ });
1503
+ }
1504
+ /**
1505
+ * Caches the position of the drop list.
1506
+ * @private
1507
+ * @return {?}
1508
+ */
1509
+ _cacheOwnPosition() {
1510
+ this._clientRect = this.element.getBoundingClientRect();
1511
+ }
1512
+ /**
1513
+ * Refreshes the position cache of the items and sibling containers.
1514
+ * @private
1515
+ * @return {?}
1516
+ */
1517
+ _cacheItemPositions() {
1518
+ /** @type {?} */
1519
+ const isHorizontal = this._orientation === 'horizontal';
1520
+ this._itemPositions = this._activeDraggables.map(drag => {
1521
+ /** @type {?} */
1522
+ const elementToMeasure = this._dragDropRegistry.isDragging(drag) ?
1523
+ // If the element is being dragged, we have to measure the
1524
+ // placeholder, because the element is hidden.
1525
+ drag.getPlaceholderElement() :
1526
+ drag.getRootElement();
1527
+ /** @type {?} */
1528
+ const clientRect = elementToMeasure.getBoundingClientRect();
1529
+ return {
1530
+ drag,
1531
+ offset: 0,
1532
+ // We need to clone the `clientRect` here, because all the values on it are readonly
1533
+ // and we need to be able to update them. Also we can't use a spread here, because
1534
+ // the values on a `ClientRect` aren't own properties. See:
1535
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#Notes
1536
+ clientRect: {
1537
+ top: clientRect.top,
1538
+ right: clientRect.right,
1539
+ bottom: clientRect.bottom,
1540
+ left: clientRect.left,
1541
+ width: clientRect.width,
1542
+ height: clientRect.height
1543
+ }
1544
+ };
1545
+ }).sort((a, b) => {
1546
+ return isHorizontal ? a.clientRect.left - b.clientRect.left :
1547
+ a.clientRect.top - b.clientRect.top;
1548
+ });
1549
+ }
1550
+ /**
1551
+ * Resets the container to its initial state.
1552
+ * @private
1553
+ * @return {?}
1554
+ */
1555
+ _reset() {
1556
+ this._isDragging = false;
1557
+ // TODO(crisbeto): may have to wait for the animations to finish.
1558
+ this._activeDraggables.forEach(item => item.getRootElement().style.transform = '');
1559
+ this._siblings.forEach(sibling => sibling._stopReceiving(this));
1560
+ this._activeDraggables = [];
1561
+ this._itemPositions = [];
1562
+ this._previousSwap.drag = null;
1563
+ this._previousSwap.delta = 0;
1564
+ }
1565
+ /**
1566
+ * Gets the offset in pixels by which the items that aren't being dragged should be moved.
1567
+ * @private
1568
+ * @param {?} currentIndex Index of the item currently being dragged.
1569
+ * @param {?} siblings All of the items in the list.
1570
+ * @param {?} delta Direction in which the user is moving.
1571
+ * @return {?}
1572
+ */
1573
+ _getSiblingOffsetPx(currentIndex, siblings, delta) {
1574
+ /** @type {?} */
1575
+ const isHorizontal = this._orientation === 'horizontal';
1576
+ /** @type {?} */
1577
+ const currentPosition = siblings[currentIndex].clientRect;
1578
+ /** @type {?} */
1579
+ const immediateSibling = siblings[currentIndex + delta * -1];
1580
+ /** @type {?} */
1581
+ let siblingOffset = currentPosition[isHorizontal ? 'width' : 'height'] * delta;
1582
+ if (immediateSibling) {
1583
+ /** @type {?} */
1584
+ const start = isHorizontal ? 'left' : 'top';
1585
+ /** @type {?} */
1586
+ const end = isHorizontal ? 'right' : 'bottom';
1587
+ // Get the spacing between the start of the current item and the end of the one immediately
1588
+ // after it in the direction in which the user is dragging, or vice versa. We add it to the
1589
+ // offset in order to push the element to where it will be when it's inline and is influenced
1590
+ // by the `margin` of its siblings.
1591
+ if (delta === -1) {
1592
+ siblingOffset -= immediateSibling.clientRect[start] - currentPosition[end];
1593
+ }
1594
+ else {
1595
+ siblingOffset += currentPosition[start] - immediateSibling.clientRect[end];
1596
+ }
1597
+ }
1598
+ return siblingOffset;
1599
+ }
1600
+ /**
1601
+ * Checks whether the pointer coordinates are close to the drop container.
1602
+ * @private
1603
+ * @param {?} pointerX Coordinates along the X axis.
1604
+ * @param {?} pointerY Coordinates along the Y axis.
1605
+ * @return {?}
1606
+ */
1607
+ _isPointerNearDropContainer(pointerX, pointerY) {
1608
+ const { top, right, bottom, left, width, height } = this._clientRect;
1609
+ /** @type {?} */
1610
+ const xThreshold = width * DROP_PROXIMITY_THRESHOLD;
1611
+ /** @type {?} */
1612
+ const yThreshold = height * DROP_PROXIMITY_THRESHOLD;
1613
+ return pointerY > top - yThreshold && pointerY < bottom + yThreshold &&
1614
+ pointerX > left - xThreshold && pointerX < right + xThreshold;
1615
+ }
1616
+ /**
1617
+ * Gets the offset in pixels by which the item that is being dragged should be moved.
1618
+ * @private
1619
+ * @param {?} currentPosition Current position of the item.
1620
+ * @param {?} newPosition Position of the item where the current item should be moved.
1621
+ * @param {?} delta Direction in which the user is moving.
1622
+ * @return {?}
1623
+ */
1624
+ _getItemOffsetPx(currentPosition, newPosition, delta) {
1625
+ /** @type {?} */
1626
+ const isHorizontal = this._orientation === 'horizontal';
1627
+ /** @type {?} */
1628
+ let itemOffset = isHorizontal ? newPosition.left - currentPosition.left :
1629
+ newPosition.top - currentPosition.top;
1630
+ // Account for differences in the item width/height.
1631
+ if (delta === -1) {
1632
+ itemOffset += isHorizontal ? newPosition.width - currentPosition.width :
1633
+ newPosition.height - currentPosition.height;
1634
+ }
1635
+ return itemOffset;
1636
+ }
1637
+ /**
1638
+ * Gets the index of an item in the drop container, based on the position of the user's pointer.
1639
+ * @private
1640
+ * @param {?} item Item that is being sorted.
1641
+ * @param {?} pointerX Position of the user's pointer along the X axis.
1642
+ * @param {?} pointerY Position of the user's pointer along the Y axis.
1643
+ * @param {?=} delta Direction in which the user is moving their pointer.
1644
+ * @return {?}
1645
+ */
1646
+ _getItemIndexFromPointerPosition(item, pointerX, pointerY, delta) {
1647
+ /** @type {?} */
1648
+ const isHorizontal = this._orientation === 'horizontal';
1649
+ return findIndex(this._itemPositions, ({ drag, clientRect }, _, array) => {
1650
+ if (drag === item) {
1651
+ // If there's only one item left in the container, it must be
1652
+ // the dragged item itself so we use it as a reference.
1653
+ return array.length < 2;
1654
+ }
1655
+ if (delta) {
1656
+ /** @type {?} */
1657
+ const direction = isHorizontal ? delta.x : delta.y;
1658
+ // If the user is still hovering over the same item as last time, and they didn't change
1659
+ // the direction in which they're dragging, we don't consider it a direction swap.
1660
+ if (drag === this._previousSwap.drag && direction === this._previousSwap.delta) {
1661
+ return false;
1662
+ }
1663
+ }
1664
+ return isHorizontal ?
1665
+ // Round these down since most browsers report client rects with
1666
+ // sub-pixel precision, whereas the pointer coordinates are rounded to pixels.
1667
+ pointerX >= Math.floor(clientRect.left) && pointerX <= Math.floor(clientRect.right) :
1668
+ pointerY >= Math.floor(clientRect.top) && pointerY <= Math.floor(clientRect.bottom);
1669
+ });
1670
+ }
1671
+ /**
1672
+ * Checks whether the user's pointer is positioned over the container.
1673
+ * @param {?} x Pointer position along the X axis.
1674
+ * @param {?} y Pointer position along the Y axis.
1675
+ * @return {?}
1676
+ */
1677
+ _isOverContainer(x, y) {
1678
+ return isInsideClientRect(this._clientRect, x, y);
1679
+ }
1680
+ /**
1681
+ * Figures out whether an item should be moved into a sibling
1682
+ * drop container, based on its current position.
1683
+ * @param {?} item Drag item that is being moved.
1684
+ * @param {?} x Position of the item along the X axis.
1685
+ * @param {?} y Position of the item along the Y axis.
1686
+ * @return {?}
1687
+ */
1688
+ _getSiblingContainerFromPosition(item, x, y) {
1689
+ return this._siblings.find(sibling => sibling._canReceive(item, x, y));
1690
+ }
1691
+ /**
1692
+ * Checks whether the drop list can receive the passed-in item.
1693
+ * @param {?} item Item that is being dragged into the list.
1694
+ * @param {?} x Position of the item along the X axis.
1695
+ * @param {?} y Position of the item along the Y axis.
1696
+ * @return {?}
1697
+ */
1698
+ _canReceive(item, x, y) {
1699
+ if (!this.enterPredicate(item, this) || !isInsideClientRect(this._clientRect, x, y)) {
1700
+ return false;
1701
+ }
1702
+ /** @type {?} */
1703
+ const elementFromPoint = this._document.elementFromPoint(x, y);
1704
+ // If there's no element at the pointer position, then
1705
+ // the client rect is probably scrolled out of the view.
1706
+ if (!elementFromPoint) {
1707
+ return false;
1708
+ }
1709
+ // The `ClientRect`, that we're using to find the container over which the user is
1710
+ // hovering, doesn't give us any information on whether the element has been scrolled
1711
+ // out of the view or whether it's overlapping with other containers. This means that
1712
+ // we could end up transferring the item into a container that's invisible or is positioned
1713
+ // below another one. We use the result from `elementFromPoint` to get the top-most element
1714
+ // at the pointer position and to find whether it's one of the intersecting drop containers.
1715
+ return elementFromPoint === this.element || this.element.contains(elementFromPoint);
1716
+ }
1717
+ /**
1718
+ * Called by one of the connected drop lists when a dragging sequence has started.
1719
+ * @param {?} sibling Sibling in which dragging has started.
1720
+ * @return {?}
1721
+ */
1722
+ _startReceiving(sibling) {
1723
+ /** @type {?} */
1724
+ const activeSiblings = this._activeSiblings;
1725
+ if (!activeSiblings.has(sibling)) {
1726
+ activeSiblings.add(sibling);
1727
+ this._cacheOwnPosition();
1728
+ }
1729
+ }
1730
+ /**
1731
+ * Called by a connected drop list when dragging has stopped.
1732
+ * @param {?} sibling Sibling whose dragging has stopped.
1733
+ * @return {?}
1734
+ */
1735
+ _stopReceiving(sibling) {
1736
+ this._activeSiblings.delete(sibling);
1737
+ }
1738
+ }
1739
+ /**
1740
+ * Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
1741
+ * @param {?} clientRect `ClientRect` that should be updated.
1742
+ * @param {?} top Amount to add to the `top` position.
1743
+ * @param {?} left Amount to add to the `left` position.
1744
+ * @return {?}
1745
+ */
1746
+ function adjustClientRect(clientRect, top, left) {
1747
+ clientRect.top += top;
1748
+ clientRect.bottom = clientRect.top + clientRect.height;
1749
+ clientRect.left += left;
1750
+ clientRect.right = clientRect.left + clientRect.width;
1751
+ }
1752
+ /**
1753
+ * Finds the index of an item that matches a predicate function. Used as an equivalent
1754
+ * of `Array.prototype.find` which isn't part of the standard Google typings.
1755
+ * @template T
1756
+ * @param {?} array Array in which to look for matches.
1757
+ * @param {?} predicate Function used to determine whether an item is a match.
1758
+ * @return {?}
1759
+ */
1760
+ function findIndex(array, predicate) {
1761
+ for (let i = 0; i < array.length; i++) {
1762
+ if (predicate(array[i], i, array)) {
1763
+ return i;
1764
+ }
1765
+ }
1766
+ return -1;
1767
+ }
1768
+ /**
1769
+ * Checks whether some coordinates are within a `ClientRect`.
1770
+ * @param {?} clientRect ClientRect that is being checked.
1771
+ * @param {?} x Coordinates along the X axis.
1772
+ * @param {?} y Coordinates along the Y axis.
1773
+ * @return {?}
1774
+ */
1775
+ function isInsideClientRect(clientRect, x, y) {
1776
+ const { top, bottom, left, right } = clientRect;
1777
+ return y >= top && y <= bottom && x >= left && x <= right;
1778
+ }
1779
+
1780
+ /**
1781
+ * @fileoverview added by tsickle
1782
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1783
+ */
1784
+ /**
1785
+ * Event options that can be used to bind an active, capturing event.
1786
+ * @type {?}
1787
+ */
1788
+ const activeCapturingEventOptions = normalizePassiveListenerOptions({
1789
+ passive: false,
1790
+ capture: true
1791
+ });
1792
+ /**
1793
+ * Service that keeps track of all the drag item and drop container
1794
+ * instances, and manages global event listeners on the `document`.
1795
+ * \@docs-private
1796
+ * @template I, C
1797
+ */
1798
+ // Note: this class is generic, rather than referencing CdkDrag and CdkDropList directly, in order
1799
+ // to avoid circular imports. If we were to reference them here, importing the registry into the
1800
+ // classes that are registering themselves will introduce a circular import.
1801
+ class DragDropRegistry {
1802
+ /**
1803
+ * @param {?} _ngZone
1804
+ * @param {?} _document
1805
+ */
1806
+ constructor(_ngZone, _document) {
1807
+ this._ngZone = _ngZone;
1808
+ /**
1809
+ * Registered drop container instances.
1810
+ */
1811
+ this._dropInstances = new Set();
1812
+ /**
1813
+ * Registered drag item instances.
1814
+ */
1815
+ this._dragInstances = new Set();
1816
+ /**
1817
+ * Drag item instances that are currently being dragged.
1818
+ */
1819
+ this._activeDragInstances = new Set();
1820
+ /**
1821
+ * Keeps track of the event listeners that we've bound to the `document`.
1822
+ */
1823
+ this._globalListeners = new Map();
1824
+ /**
1825
+ * Emits the `touchmove` or `mousemove` events that are dispatched
1826
+ * while the user is dragging a drag item instance.
1827
+ */
1828
+ this.pointerMove = new Subject();
1829
+ /**
1830
+ * Emits the `touchend` or `mouseup` events that are dispatched
1831
+ * while the user is dragging a drag item instance.
1832
+ */
1833
+ this.pointerUp = new Subject();
1834
+ /**
1835
+ * Event listener that will prevent the default browser action while the user is dragging.
1836
+ * @param event Event whose default action should be prevented.
1837
+ */
1838
+ this._preventDefaultWhileDragging = (event) => {
1839
+ if (this._activeDragInstances.size) {
1840
+ event.preventDefault();
1841
+ }
1842
+ };
1843
+ this._document = _document;
1844
+ }
1845
+ /**
1846
+ * Adds a drop container to the registry.
1847
+ * @param {?} drop
1848
+ * @return {?}
1849
+ */
1850
+ registerDropContainer(drop) {
1851
+ if (!this._dropInstances.has(drop)) {
1852
+ if (this.getDropContainer(drop.id)) {
1853
+ throw Error(`Drop instance with id "${drop.id}" has already been registered.`);
1854
+ }
1855
+ this._dropInstances.add(drop);
1856
+ }
1857
+ }
1858
+ /**
1859
+ * Adds a drag item instance to the registry.
1860
+ * @param {?} drag
1861
+ * @return {?}
1862
+ */
1863
+ registerDragItem(drag) {
1864
+ this._dragInstances.add(drag);
1865
+ // The `touchmove` event gets bound once, ahead of time, because WebKit
1866
+ // won't preventDefault on a dynamically-added `touchmove` listener.
1867
+ // See https://bugs.webkit.org/show_bug.cgi?id=184250.
1868
+ if (this._dragInstances.size === 1) {
1869
+ this._ngZone.runOutsideAngular(() => {
1870
+ // The event handler has to be explicitly active,
1871
+ // because newer browsers make it passive by default.
1872
+ this._document.addEventListener('touchmove', this._preventDefaultWhileDragging, activeCapturingEventOptions);
1873
+ });
1874
+ }
1875
+ }
1876
+ /**
1877
+ * Removes a drop container from the registry.
1878
+ * @param {?} drop
1879
+ * @return {?}
1880
+ */
1881
+ removeDropContainer(drop) {
1882
+ this._dropInstances.delete(drop);
1883
+ }
1884
+ /**
1885
+ * Removes a drag item instance from the registry.
1886
+ * @param {?} drag
1887
+ * @return {?}
1888
+ */
1889
+ removeDragItem(drag) {
1890
+ this._dragInstances.delete(drag);
1891
+ this.stopDragging(drag);
1892
+ if (this._dragInstances.size === 0) {
1893
+ this._document.removeEventListener('touchmove', this._preventDefaultWhileDragging, activeCapturingEventOptions);
1894
+ }
1895
+ }
1896
+ /**
1897
+ * Starts the dragging sequence for a drag instance.
1898
+ * @param {?} drag Drag instance which is being dragged.
1899
+ * @param {?} event Event that initiated the dragging.
1900
+ * @return {?}
1901
+ */
1902
+ startDragging(drag, event) {
1903
+ this._activeDragInstances.add(drag);
1904
+ if (this._activeDragInstances.size === 1) {
1905
+ /** @type {?} */
1906
+ const isTouchEvent = event.type.startsWith('touch');
1907
+ /** @type {?} */
1908
+ const moveEvent = isTouchEvent ? 'touchmove' : 'mousemove';
1909
+ /** @type {?} */
1910
+ const upEvent = isTouchEvent ? 'touchend' : 'mouseup';
1911
+ // We explicitly bind __active__ listeners here, because newer browsers will default to
1912
+ // passive ones for `mousemove` and `touchmove`. The events need to be active, because we
1913
+ // use `preventDefault` to prevent the page from scrolling while the user is dragging.
1914
+ this._globalListeners
1915
+ .set(moveEvent, {
1916
+ handler: (e) => this.pointerMove.next((/** @type {?} */ (e))),
1917
+ options: activeCapturingEventOptions
1918
+ })
1919
+ .set(upEvent, {
1920
+ handler: (e) => this.pointerUp.next((/** @type {?} */ (e))),
1921
+ options: true
1922
+ })
1923
+ // Preventing the default action on `mousemove` isn't enough to disable text selection
1924
+ // on Safari so we need to prevent the selection event as well. Alternatively this can
1925
+ // be done by setting `user-select: none` on the `body`, however it has causes a style
1926
+ // recalculation which can be expensive on pages with a lot of elements.
1927
+ .set('selectstart', {
1928
+ handler: this._preventDefaultWhileDragging,
1929
+ options: activeCapturingEventOptions
1930
+ });
1931
+ // TODO(crisbeto): prevent mouse wheel scrolling while
1932
+ // dragging until we've set up proper scroll handling.
1933
+ if (!isTouchEvent) {
1934
+ this._globalListeners.set('wheel', {
1935
+ handler: this._preventDefaultWhileDragging,
1936
+ options: activeCapturingEventOptions
1937
+ });
1938
+ }
1939
+ this._ngZone.runOutsideAngular(() => {
1940
+ this._globalListeners.forEach((config, name) => {
1941
+ this._document.addEventListener(name, config.handler, config.options);
1942
+ });
1943
+ });
1944
+ }
1945
+ }
1946
+ /**
1947
+ * Stops dragging a drag item instance.
1948
+ * @param {?} drag
1949
+ * @return {?}
1950
+ */
1951
+ stopDragging(drag) {
1952
+ this._activeDragInstances.delete(drag);
1953
+ if (this._activeDragInstances.size === 0) {
1954
+ this._clearGlobalListeners();
1955
+ }
1956
+ }
1957
+ /**
1958
+ * Gets whether a drag item instance is currently being dragged.
1959
+ * @param {?} drag
1960
+ * @return {?}
1961
+ */
1962
+ isDragging(drag) {
1963
+ return this._activeDragInstances.has(drag);
1964
+ }
1965
+ /**
1966
+ * Gets a drop container by its id.
1967
+ * @deprecated No longer being used. To be removed.
1968
+ * \@breaking-change 8.0.0
1969
+ * @param {?} id
1970
+ * @return {?}
1971
+ */
1972
+ getDropContainer(id) {
1973
+ return Array.from(this._dropInstances).find(instance => instance.id === id);
1974
+ }
1975
+ /**
1976
+ * @return {?}
1977
+ */
1978
+ ngOnDestroy() {
1979
+ this._dragInstances.forEach(instance => this.removeDragItem(instance));
1980
+ this._dropInstances.forEach(instance => this.removeDropContainer(instance));
1981
+ this._clearGlobalListeners();
1982
+ this.pointerMove.complete();
1983
+ this.pointerUp.complete();
1984
+ }
1985
+ /**
1986
+ * Clears out the global event listeners from the `document`.
1987
+ * @private
1988
+ * @return {?}
1989
+ */
1990
+ _clearGlobalListeners() {
1991
+ this._globalListeners.forEach((config, name) => {
1992
+ this._document.removeEventListener(name, config.handler, config.options);
1993
+ });
1994
+ this._globalListeners.clear();
1995
+ }
1996
+ }
1997
+ DragDropRegistry.decorators = [
1998
+ { type: Injectable, args: [{ providedIn: 'root' },] },
1999
+ ];
2000
+ /** @nocollapse */
2001
+ DragDropRegistry.ctorParameters = () => [
2002
+ { type: NgZone },
2003
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
2004
+ ];
2005
+ /** @nocollapse */ DragDropRegistry.ngInjectableDef = defineInjectable({ factory: function DragDropRegistry_Factory() { return new DragDropRegistry(inject(NgZone), inject(DOCUMENT)); }, token: DragDropRegistry, providedIn: "root" });
2006
+
2007
+ /**
2008
+ * @fileoverview added by tsickle
2009
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2010
+ */
2011
+ /**
2012
+ * Default configuration to be used when creating a `DragRef`.
2013
+ * @type {?}
2014
+ */
2015
+ const DEFAULT_CONFIG = {
2016
+ dragStartThreshold: 5,
2017
+ pointerDirectionChangeThreshold: 5
2018
+ };
2019
+ /**
2020
+ * Service that allows for drag-and-drop functionality to be attached to DOM elements.
2021
+ */
2022
+ class DragDrop {
2023
+ /**
2024
+ * @param {?} _document
2025
+ * @param {?} _ngZone
2026
+ * @param {?} _viewportRuler
2027
+ * @param {?} _dragDropRegistry
2028
+ */
2029
+ constructor(_document, _ngZone, _viewportRuler, _dragDropRegistry) {
2030
+ this._document = _document;
2031
+ this._ngZone = _ngZone;
2032
+ this._viewportRuler = _viewportRuler;
2033
+ this._dragDropRegistry = _dragDropRegistry;
2034
+ }
2035
+ /**
2036
+ * Turns an element into a draggable item.
2037
+ * @template T
2038
+ * @param {?} element Element to which to attach the dragging functionality.
2039
+ * @param {?=} config Object used to configure the dragging behavior.
2040
+ * @return {?}
2041
+ */
2042
+ createDrag(element, config = DEFAULT_CONFIG) {
2043
+ return new DragRef(element, config, this._document, this._ngZone, this._viewportRuler, this._dragDropRegistry);
2044
+ }
2045
+ /**
2046
+ * Turns an element into a drop list.
2047
+ * @template T
2048
+ * @param {?} element Element to which to attach the drop list functionality.
2049
+ * @return {?}
2050
+ */
2051
+ createDropList(element) {
2052
+ return new DropListRef(element, this._dragDropRegistry, this._document);
2053
+ }
2054
+ }
2055
+ DragDrop.decorators = [
2056
+ { type: Injectable, args: [{ providedIn: 'root' },] },
2057
+ ];
2058
+ /** @nocollapse */
2059
+ DragDrop.ctorParameters = () => [
2060
+ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
2061
+ { type: NgZone },
2062
+ { type: ViewportRuler },
2063
+ { type: DragDropRegistry }
2064
+ ];
2065
+ /** @nocollapse */ DragDrop.ngInjectableDef = defineInjectable({ factory: function DragDrop_Factory() { return new DragDrop(inject(DOCUMENT), inject(NgZone), inject(ViewportRuler), inject(DragDropRegistry)); }, token: DragDrop, providedIn: "root" });
2066
+
2067
+ /**
2068
+ * @fileoverview added by tsickle
2069
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2070
+ */
2071
+ /**
2072
+ * Injection token that is used to provide a CdkDropList instance to CdkDrag.
2073
+ * Used for avoiding circular imports.
2074
+ * @type {?}
2075
+ */
2076
+ const CDK_DROP_LIST = new InjectionToken('CDK_DROP_LIST');
2077
+ /**
2078
+ * Injection token that is used to provide a CdkDropList instance to CdkDrag.
2079
+ * Used for avoiding circular imports.
2080
+ * @deprecated Use `CDK_DROP_LIST` instead.
2081
+ * \@breaking-change 8.0.0
2082
+ * @type {?}
2083
+ */
2084
+ const CDK_DROP_LIST_CONTAINER = CDK_DROP_LIST;
2085
+
2086
+ /**
2087
+ * @fileoverview added by tsickle
2088
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2089
+ */
2090
+
2091
+ /**
2092
+ * @fileoverview added by tsickle
2093
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2094
+ */
2095
+ /**
2096
+ * Injection token that can be used for a `CdkDrag` to provide itself as a parent to the
2097
+ * drag-specific child directive (`CdkDragHandle`, `CdkDragPreview` etc.). Used primarily
2098
+ * to avoid circular imports.
2099
+ * \@docs-private
2100
+ * @type {?}
2101
+ */
2102
+ const CDK_DRAG_PARENT = new InjectionToken('CDK_DRAG_PARENT');
2103
+
2104
+ /**
2105
+ * @fileoverview added by tsickle
2106
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2107
+ */
2108
+ /**
2109
+ * Handle that can be used to drag and CdkDrag instance.
2110
+ */
2111
+ class CdkDragHandle {
2112
+ /**
2113
+ * @param {?} element
2114
+ * @param {?=} parentDrag
2115
+ */
2116
+ constructor(element, parentDrag) {
2117
+ this.element = element;
2118
+ /**
2119
+ * Emits when the state of the handle has changed.
2120
+ */
2121
+ this._stateChanges = new Subject();
2122
+ this._disabled = false;
2123
+ this._parentDrag = parentDrag;
2124
+ toggleNativeDragInteractions(element.nativeElement, false);
2125
+ }
2126
+ /**
2127
+ * Whether starting to drag through this handle is disabled.
2128
+ * @return {?}
2129
+ */
2130
+ get disabled() { return this._disabled; }
2131
+ /**
2132
+ * @param {?} value
2133
+ * @return {?}
2134
+ */
2135
+ set disabled(value) {
2136
+ this._disabled = coerceBooleanProperty(value);
2137
+ this._stateChanges.next(this);
2138
+ }
2139
+ /**
2140
+ * @return {?}
2141
+ */
2142
+ ngOnDestroy() {
2143
+ this._stateChanges.complete();
2144
+ }
2145
+ }
2146
+ CdkDragHandle.decorators = [
2147
+ { type: Directive, args: [{
2148
+ selector: '[cdkDragHandle]',
2149
+ host: {
2150
+ 'class': 'cdk-drag-handle'
2151
+ }
2152
+ },] },
2153
+ ];
2154
+ /** @nocollapse */
2155
+ CdkDragHandle.ctorParameters = () => [
2156
+ { type: ElementRef },
2157
+ { type: undefined, decorators: [{ type: Inject, args: [CDK_DRAG_PARENT,] }, { type: Optional }] }
2158
+ ];
2159
+ CdkDragHandle.propDecorators = {
2160
+ disabled: [{ type: Input, args: ['cdkDragHandleDisabled',] }]
2161
+ };
2162
+
2163
+ /**
2164
+ * @fileoverview added by tsickle
2165
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2166
+ */
2167
+ /**
2168
+ * Element that will be used as a template for the placeholder of a CdkDrag when
2169
+ * it is being dragged. The placeholder is displayed in place of the element being dragged.
2170
+ * @template T
2171
+ */
2172
+ class CdkDragPlaceholder {
2173
+ /**
2174
+ * @param {?} templateRef
2175
+ */
2176
+ constructor(templateRef) {
2177
+ this.templateRef = templateRef;
2178
+ }
2179
+ }
2180
+ CdkDragPlaceholder.decorators = [
2181
+ { type: Directive, args: [{
2182
+ selector: 'ng-template[cdkDragPlaceholder]'
2183
+ },] },
2184
+ ];
2185
+ /** @nocollapse */
2186
+ CdkDragPlaceholder.ctorParameters = () => [
2187
+ { type: TemplateRef }
2188
+ ];
2189
+ CdkDragPlaceholder.propDecorators = {
2190
+ data: [{ type: Input }]
2191
+ };
2192
+
2193
+ /**
2194
+ * @fileoverview added by tsickle
2195
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2196
+ */
2197
+ /**
2198
+ * Element that will be used as a template for the preview
2199
+ * of a CdkDrag when it is being dragged.
2200
+ * @template T
2201
+ */
2202
+ class CdkDragPreview {
2203
+ /**
2204
+ * @param {?} templateRef
2205
+ */
2206
+ constructor(templateRef) {
2207
+ this.templateRef = templateRef;
2208
+ }
2209
+ }
2210
+ CdkDragPreview.decorators = [
2211
+ { type: Directive, args: [{
2212
+ selector: 'ng-template[cdkDragPreview]'
2213
+ },] },
2214
+ ];
2215
+ /** @nocollapse */
2216
+ CdkDragPreview.ctorParameters = () => [
2217
+ { type: TemplateRef }
2218
+ ];
2219
+ CdkDragPreview.propDecorators = {
2220
+ data: [{ type: Input }]
2221
+ };
2222
+
2223
+ /**
2224
+ * @fileoverview added by tsickle
2225
+ * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2226
+ */
2227
+ /**
2228
+ * Injection token that can be used to configure the behavior of `CdkDrag`.
2229
+ * @type {?}
2230
+ */
2231
+ const CDK_DRAG_CONFIG = new InjectionToken('CDK_DRAG_CONFIG', {
2232
+ providedIn: 'root',
2233
+ factory: CDK_DRAG_CONFIG_FACTORY
2234
+ });
2235
+ /**
2236
+ * \@docs-private
2237
+ * @return {?}
2238
+ */
2239
+ function CDK_DRAG_CONFIG_FACTORY() {
2240
+ return { dragStartThreshold: 5, pointerDirectionChangeThreshold: 5 };
2241
+ }
2242
+ /**
2243
+ * Element that can be moved inside a CdkDropList container.
2244
+ * @template T
2245
+ */
2246
+ class CdkDrag {
2247
+ /**
2248
+ * @param {?} element
2249
+ * @param {?} dropContainer
2250
+ * @param {?} _document
2251
+ * @param {?} _ngZone
2252
+ * @param {?} _viewContainerRef
2253
+ * @param {?} viewportRuler
2254
+ * @param {?} dragDropRegistry
2255
+ * @param {?} config
2256
+ * @param {?} _dir
2257
+ * @param {?=} dragDrop
2258
+ */
2259
+ constructor(element, dropContainer, _document, _ngZone, _viewContainerRef, viewportRuler, dragDropRegistry, config, _dir,
2260
+ /**
2261
+ * @deprecated `viewportRuler` and `dragDropRegistry` parameters
2262
+ * to be removed. Also `dragDrop` parameter to be made required.
2263
+ * @breaking-change 8.0.0.
2264
+ */
2265
+ dragDrop) {
2266
+ this.element = element;
2267
+ this.dropContainer = dropContainer;
2268
+ this._document = _document;
2269
+ this._ngZone = _ngZone;
2270
+ this._viewContainerRef = _viewContainerRef;
2271
+ this._dir = _dir;
2272
+ this._destroyed = new Subject();
2273
+ this._disabled = false;
2274
+ /**
2275
+ * Emits when the user starts dragging the item.
2276
+ */
2277
+ this.started = new EventEmitter();
2278
+ /**
2279
+ * Emits when the user has released a drag item, before any animations have started.
2280
+ */
2281
+ this.released = new EventEmitter();
2282
+ /**
2283
+ * Emits when the user stops dragging an item in the container.
2284
+ */
2285
+ this.ended = new EventEmitter();
2286
+ /**
2287
+ * Emits when the user has moved the item into a new container.
2288
+ */
2289
+ this.entered = new EventEmitter();
2290
+ /**
2291
+ * Emits when the user removes the item its container by dragging it into another container.
2292
+ */
2293
+ this.exited = new EventEmitter();
2294
+ /**
2295
+ * Emits when the user drops the item inside a container.
2296
+ */
2297
+ this.dropped = new EventEmitter();
2298
+ /**
2299
+ * Emits as the user is dragging the item. Use with caution,
2300
+ * because this event will fire for every pixel that the user has dragged.
2301
+ */
2302
+ this.moved = new Observable((observer) => {
2303
+ /** @type {?} */
2304
+ const subscription = this._dragRef.moved.pipe(map(movedEvent => ({
2305
+ source: this,
2306
+ pointerPosition: movedEvent.pointerPosition,
2307
+ event: movedEvent.event,
2308
+ delta: movedEvent.delta
2309
+ }))).subscribe(observer);
2310
+ return () => {
2311
+ subscription.unsubscribe();
2312
+ };
2313
+ });
2314
+ // @breaking-change 8.0.0 Remove null check once the paramter is made required.
2315
+ if (dragDrop) {
2316
+ this._dragRef = dragDrop.createDrag(element, config);
2317
+ }
2318
+ else {
2319
+ this._dragRef = new DragRef(element, config, _document, _ngZone, viewportRuler, dragDropRegistry);
1003
2320
  }
1004
- placeholder.classList.add('cdk-drag-placeholder');
1005
- return placeholder;
2321
+ this._dragRef.data = this;
2322
+ this._syncInputs(this._dragRef);
2323
+ this._proxyEvents(this._dragRef);
1006
2324
  }
1007
2325
  /**
1008
- * Figures out the coordinates at which an element was picked up.
1009
- * @private
1010
- * @param {?} referenceElement Element that initiated the dragging.
1011
- * @param {?} event Event that initiated the dragging.
2326
+ * Whether starting to drag this element is disabled.
1012
2327
  * @return {?}
1013
2328
  */
1014
- _getPointerPositionInElement(referenceElement, event) {
1015
- /** @type {?} */
1016
- const elementRect = this._rootElement.getBoundingClientRect();
1017
- /** @type {?} */
1018
- const handleElement = referenceElement === this._rootElement ? null : referenceElement;
1019
- /** @type {?} */
1020
- const referenceRect = handleElement ? handleElement.getBoundingClientRect() : elementRect;
1021
- /** @type {?} */
1022
- const point = this._isTouchEvent(event) ? event.targetTouches[0] : event;
1023
- /** @type {?} */
1024
- const x = point.pageX - referenceRect.left - this._scrollPosition.left;
1025
- /** @type {?} */
1026
- const y = point.pageY - referenceRect.top - this._scrollPosition.top;
1027
- return {
1028
- x: referenceRect.left - elementRect.left + x,
1029
- y: referenceRect.top - elementRect.top + y
1030
- };
2329
+ get disabled() {
2330
+ return this._disabled || (this.dropContainer && this.dropContainer.disabled);
1031
2331
  }
1032
2332
  /**
1033
- * Animates the preview element from its current position to the location of the drop placeholder.
1034
- * @private
1035
- * @return {?} Promise that resolves when the animation completes.
2333
+ * @param {?} value
2334
+ * @return {?}
1036
2335
  */
1037
- _animatePreviewToPlaceholder() {
1038
- // If the user hasn't moved yet, the transitionend event won't fire.
1039
- if (!this._hasMoved) {
1040
- return Promise.resolve();
1041
- }
1042
- /** @type {?} */
1043
- const placeholderRect = this._placeholder.getBoundingClientRect();
1044
- // Apply the class that adds a transition to the preview.
1045
- this._preview.classList.add('cdk-drag-animating');
1046
- // Move the preview to the placeholder position.
1047
- this._preview.style.transform = getTransform(placeholderRect.left, placeholderRect.top);
1048
- // If the element doesn't have a `transition`, the `transitionend` event won't fire. Since
1049
- // we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
1050
- // apply its style, we take advantage of the available info to figure out whether we need to
1051
- // bind the event in the first place.
1052
- /** @type {?} */
1053
- const duration = getTransformTransitionDurationInMs(this._preview);
1054
- if (duration === 0) {
1055
- return Promise.resolve();
1056
- }
1057
- return this._ngZone.runOutsideAngular(() => {
1058
- return new Promise(resolve => {
1059
- /** @type {?} */
1060
- const handler = (/** @type {?} */ (((event) => {
1061
- if (!event || (event.target === this._preview && event.propertyName === 'transform')) {
1062
- this._preview.removeEventListener('transitionend', handler);
1063
- resolve();
1064
- clearTimeout(timeout);
1065
- }
1066
- })));
1067
- // If a transition is short enough, the browser might not fire the `transitionend` event.
1068
- // Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
1069
- // fire if the transition hasn't completed when it was supposed to.
1070
- /** @type {?} */
1071
- const timeout = setTimeout((/** @type {?} */ (handler)), duration * 1.5);
1072
- this._preview.addEventListener('transitionend', handler);
1073
- });
1074
- });
2336
+ set disabled(value) {
2337
+ this._disabled = coerceBooleanProperty(value);
2338
+ this._dragRef.disabled = this._disabled;
1075
2339
  }
1076
2340
  /**
1077
- * Helper to remove an element from the DOM and to do all the necessary null checks.
1078
- * @private
1079
- * @param {?} element Element to be removed.
2341
+ * Returns the element that is being used as a placeholder
2342
+ * while the current element is being dragged.
1080
2343
  * @return {?}
1081
2344
  */
1082
- _removeElement(element) {
1083
- if (element && element.parentNode) {
1084
- element.parentNode.removeChild(element);
1085
- }
2345
+ getPlaceholderElement() {
2346
+ return this._dragRef.getPlaceholderElement();
1086
2347
  }
1087
2348
  /**
1088
- * Determines the point of the page that was touched by the user.
1089
- * @private
1090
- * @param {?} event
2349
+ * Returns the root draggable element.
1091
2350
  * @return {?}
1092
2351
  */
1093
- _getPointerPositionOnPage(event) {
1094
- /** @type {?} */
1095
- const point = this._isTouchEvent(event) ? event.touches[0] : event;
1096
- return {
1097
- x: point.pageX - this._scrollPosition.left,
1098
- y: point.pageY - this._scrollPosition.top
1099
- };
2352
+ getRootElement() {
2353
+ return this._dragRef.getRootElement();
1100
2354
  }
1101
2355
  /**
1102
- * Gets the pointer position on the page, accounting for any position constraints.
1103
- * @private
1104
- * @param {?} event
2356
+ * Resets a standalone drag item to its initial position.
1105
2357
  * @return {?}
1106
2358
  */
1107
- _getConstrainedPointerPosition(event) {
1108
- /** @type {?} */
1109
- const point = this._getPointerPositionOnPage(event);
1110
- /** @type {?} */
1111
- const dropContainerLock = this.dropContainer ? this.dropContainer.lockAxis : null;
1112
- if (this.lockAxis === 'x' || dropContainerLock === 'x') {
1113
- point.y = this._pickupPositionOnPage.y;
1114
- }
1115
- else if (this.lockAxis === 'y' || dropContainerLock === 'y') {
1116
- point.x = this._pickupPositionOnPage.x;
1117
- }
1118
- return point;
2359
+ reset() {
2360
+ this._dragRef.reset();
1119
2361
  }
1120
2362
  /**
1121
- * Determines whether an event is a touch event.
1122
- * @private
1123
- * @param {?} event
1124
2363
  * @return {?}
1125
2364
  */
1126
- _isTouchEvent(event) {
1127
- return event.type.startsWith('touch');
2365
+ ngAfterViewInit() {
2366
+ // We need to wait for the zone to stabilize, in order for the reference
2367
+ // element to be in the proper place in the DOM. This is mostly relevant
2368
+ // for draggable elements inside portals since they get stamped out in
2369
+ // their original DOM position and then they get transferred to the portal.
2370
+ this._ngZone.onStable.asObservable()
2371
+ .pipe(take(1), takeUntil(this._destroyed))
2372
+ .subscribe(() => {
2373
+ this._updateRootElement();
2374
+ // Listen for any newly-added handles.
2375
+ this._handles.changes.pipe(startWith(this._handles),
2376
+ // Sync the new handles with the DragRef.
2377
+ tap((handles) => {
2378
+ /** @type {?} */
2379
+ const childHandleElements = handles
2380
+ .filter(handle => handle._parentDrag === this)
2381
+ .map(handle => handle.element);
2382
+ this._dragRef.withHandles(childHandleElements);
2383
+ }),
2384
+ // Listen if the state of any of the handles changes.
2385
+ switchMap((handles) => {
2386
+ return merge(...handles.map(item => item._stateChanges));
2387
+ }), takeUntil(this._destroyed)).subscribe(handleInstance => {
2388
+ // Enabled/disable the handle that changed in the DragRef.
2389
+ /** @type {?} */
2390
+ const dragRef = this._dragRef;
2391
+ /** @type {?} */
2392
+ const handle = handleInstance.element.nativeElement;
2393
+ handleInstance.disabled ? dragRef.disableHandle(handle) : dragRef.enableHandle(handle);
2394
+ });
2395
+ });
1128
2396
  }
1129
2397
  /**
1130
- * Destroys the preview element and its ViewRef.
1131
- * @private
2398
+ * @param {?} changes
1132
2399
  * @return {?}
1133
2400
  */
1134
- _destroyPreview() {
1135
- if (this._preview) {
1136
- this._removeElement(this._preview);
1137
- }
1138
- if (this._previewRef) {
1139
- this._previewRef.destroy();
2401
+ ngOnChanges(changes) {
2402
+ /** @type {?} */
2403
+ const rootSelectorChange = changes.rootElementSelector;
2404
+ // We don't have to react to the first change since it's being
2405
+ // handled in `ngAfterViewInit` where it needs to be deferred.
2406
+ if (rootSelectorChange && !rootSelectorChange.firstChange) {
2407
+ this._updateRootElement();
1140
2408
  }
1141
- this._preview = this._previewRef = (/** @type {?} */ (null));
1142
2409
  }
1143
2410
  /**
1144
- * Destroys the placeholder element and its ViewRef.
1145
- * @private
1146
2411
  * @return {?}
1147
2412
  */
1148
- _destroyPlaceholder() {
1149
- if (this._placeholder) {
1150
- this._removeElement(this._placeholder);
1151
- }
1152
- if (this._placeholderRef) {
1153
- this._placeholderRef.destroy();
1154
- }
1155
- this._placeholder = this._placeholderRef = (/** @type {?} */ (null));
2413
+ ngOnDestroy() {
2414
+ this._destroyed.next();
2415
+ this._destroyed.complete();
2416
+ this._dragRef.dispose();
1156
2417
  }
1157
2418
  /**
1158
- * Updates the current drag delta, based on the user's current pointer position on the page.
2419
+ * Syncs the root element with the `DragRef`.
1159
2420
  * @private
1160
- * @param {?} pointerPositionOnPage
1161
2421
  * @return {?}
1162
2422
  */
1163
- _updatePointerDirectionDelta(pointerPositionOnPage) {
1164
- const { x, y } = pointerPositionOnPage;
1165
- /** @type {?} */
1166
- const delta = this._pointerDirectionDelta;
1167
- /** @type {?} */
1168
- const positionSinceLastChange = this._pointerPositionAtLastDirectionChange;
1169
- // Amount of pixels the user has dragged since the last time the direction changed.
2423
+ _updateRootElement() {
1170
2424
  /** @type {?} */
1171
- const changeX = Math.abs(x - positionSinceLastChange.x);
2425
+ const element = this.element.nativeElement;
1172
2426
  /** @type {?} */
1173
- const changeY = Math.abs(y - positionSinceLastChange.y);
1174
- // Because we handle pointer events on a per-pixel basis, we don't want the delta
1175
- // to change for every pixel, otherwise anything that depends on it can look erratic.
1176
- // To make the delta more consistent, we track how much the user has moved since the last
1177
- // delta change and we only update it after it has reached a certain threshold.
1178
- if (changeX > this._config.pointerDirectionChangeThreshold) {
1179
- delta.x = x > positionSinceLastChange.x ? 1 : -1;
1180
- positionSinceLastChange.x = x;
1181
- }
1182
- if (changeY > this._config.pointerDirectionChangeThreshold) {
1183
- delta.y = y > positionSinceLastChange.y ? 1 : -1;
1184
- positionSinceLastChange.y = y;
2427
+ const rootElement = this.rootElementSelector ?
2428
+ getClosestMatchingAncestor(element, this.rootElementSelector) : element;
2429
+ if (rootElement && rootElement.nodeType !== this._document.ELEMENT_NODE) {
2430
+ throw Error(`cdkDrag must be attached to an element node. ` +
2431
+ `Currently attached to "${rootElement.nodeName}".`);
1185
2432
  }
1186
- return delta;
2433
+ this._dragRef.withRootElement(rootElement || element);
1187
2434
  }
1188
2435
  /**
1189
- * Gets the root draggable element, based on the `rootElementSelector`.
2436
+ * Gets the boundary element, based on the `boundaryElementSelector`.
1190
2437
  * @private
1191
2438
  * @return {?}
1192
2439
  */
1193
- _getRootElement() {
1194
- if (this.rootElementSelector) {
1195
- /** @type {?} */
1196
- const selector = this.rootElementSelector;
1197
- /** @type {?} */
1198
- let currentElement = (/** @type {?} */ (this.element.nativeElement.parentElement));
1199
- while (currentElement) {
1200
- // IE doesn't support `matches` so we have to fall back to `msMatchesSelector`.
1201
- if (currentElement.matches ? currentElement.matches(selector) :
1202
- ((/** @type {?} */ (currentElement))).msMatchesSelector(selector)) {
1203
- return currentElement;
2440
+ _getBoundaryElement() {
2441
+ /** @type {?} */
2442
+ const selector = this.boundaryElementSelector;
2443
+ return selector ? getClosestMatchingAncestor(this.element.nativeElement, selector) : null;
2444
+ }
2445
+ /**
2446
+ * Syncs the inputs of the CdkDrag with the options of the underlying DragRef.
2447
+ * @private
2448
+ * @param {?} ref
2449
+ * @return {?}
2450
+ */
2451
+ _syncInputs(ref) {
2452
+ ref.beforeStarted.subscribe(() => {
2453
+ if (!ref.isDragging()) {
2454
+ /** @type {?} */
2455
+ const dir = this._dir;
2456
+ /** @type {?} */
2457
+ const placeholder = this._placeholderTemplate ? {
2458
+ template: this._placeholderTemplate.templateRef,
2459
+ context: this._placeholderTemplate.data,
2460
+ viewContainer: this._viewContainerRef
2461
+ } : null;
2462
+ /** @type {?} */
2463
+ const preview = this._previewTemplate ? {
2464
+ template: this._previewTemplate.templateRef,
2465
+ context: this._previewTemplate.data,
2466
+ viewContainer: this._viewContainerRef
2467
+ } : null;
2468
+ ref.disabled = this.disabled;
2469
+ ref.lockAxis = this.lockAxis;
2470
+ ref
2471
+ .withBoundaryElement(this._getBoundaryElement())
2472
+ .withPlaceholderTemplate(placeholder)
2473
+ .withPreviewTemplate(preview);
2474
+ if (dir) {
2475
+ ref.withDirection(dir.value);
1204
2476
  }
1205
- currentElement = currentElement.parentElement;
1206
2477
  }
1207
- }
1208
- return this.element.nativeElement;
2478
+ });
1209
2479
  }
1210
2480
  /**
1211
- * Unsubscribes from the global subscriptions.
2481
+ * Proxies the events from a DragRef to events that
2482
+ * match the interfaces of the CdkDrag outputs.
1212
2483
  * @private
2484
+ * @param {?} ref
1213
2485
  * @return {?}
1214
2486
  */
1215
- _removeSubscriptions() {
1216
- this._pointerMoveSubscription.unsubscribe();
1217
- this._pointerUpSubscription.unsubscribe();
2487
+ _proxyEvents(ref) {
2488
+ ref.started.subscribe(() => {
2489
+ this.started.emit({ source: this });
2490
+ });
2491
+ ref.released.subscribe(() => {
2492
+ this.released.emit({ source: this });
2493
+ });
2494
+ ref.ended.subscribe(() => {
2495
+ this.ended.emit({ source: this });
2496
+ });
2497
+ ref.entered.subscribe(event => {
2498
+ this.entered.emit({
2499
+ container: event.container.data,
2500
+ item: this
2501
+ });
2502
+ });
2503
+ ref.exited.subscribe(event => {
2504
+ this.exited.emit({
2505
+ container: event.container.data,
2506
+ item: this
2507
+ });
2508
+ });
2509
+ ref.dropped.subscribe(event => {
2510
+ this.dropped.emit({
2511
+ previousIndex: event.previousIndex,
2512
+ currentIndex: event.currentIndex,
2513
+ previousContainer: event.previousContainer.data,
2514
+ container: event.container.data,
2515
+ isPointerOverContainer: event.isPointerOverContainer,
2516
+ item: this
2517
+ });
2518
+ });
1218
2519
  }
1219
2520
  }
1220
2521
  CdkDrag.decorators = [
@@ -1223,25 +2524,23 @@ CdkDrag.decorators = [
1223
2524
  exportAs: 'cdkDrag',
1224
2525
  host: {
1225
2526
  'class': 'cdk-drag',
1226
- '[class.cdk-drag-dragging]': '_hasStartedDragging && _isDragging()',
2527
+ '[class.cdk-drag-dragging]': '_dragRef.isDragging()',
1227
2528
  },
1228
- providers: [{
1229
- provide: CDK_DRAG_PARENT,
1230
- useExisting: CdkDrag
1231
- }]
2529
+ providers: [{ provide: CDK_DRAG_PARENT, useExisting: CdkDrag }]
1232
2530
  },] },
1233
2531
  ];
1234
2532
  /** @nocollapse */
1235
2533
  CdkDrag.ctorParameters = () => [
1236
2534
  { type: ElementRef },
1237
- { type: undefined, decorators: [{ type: Inject, args: [CDK_DROP_LIST_CONTAINER,] }, { type: Optional }, { type: SkipSelf }] },
2535
+ { type: undefined, decorators: [{ type: Inject, args: [CDK_DROP_LIST,] }, { type: Optional }, { type: SkipSelf }] },
1238
2536
  { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] },
1239
2537
  { type: NgZone },
1240
2538
  { type: ViewContainerRef },
1241
2539
  { type: ViewportRuler },
1242
2540
  { type: DragDropRegistry },
1243
2541
  { type: undefined, decorators: [{ type: Inject, args: [CDK_DRAG_CONFIG,] }] },
1244
- { type: Directionality, decorators: [{ type: Optional }] }
2542
+ { type: Directionality, decorators: [{ type: Optional }] },
2543
+ { type: DragDrop }
1245
2544
  ];
1246
2545
  CdkDrag.propDecorators = {
1247
2546
  _handles: [{ type: ContentChildren, args: [CdkDragHandle, { descendants: true },] }],
@@ -1250,8 +2549,10 @@ CdkDrag.propDecorators = {
1250
2549
  data: [{ type: Input, args: ['cdkDragData',] }],
1251
2550
  lockAxis: [{ type: Input, args: ['cdkDragLockAxis',] }],
1252
2551
  rootElementSelector: [{ type: Input, args: ['cdkDragRootElement',] }],
2552
+ boundaryElementSelector: [{ type: Input, args: ['cdkDragBoundary',] }],
1253
2553
  disabled: [{ type: Input, args: ['cdkDragDisabled',] }],
1254
2554
  started: [{ type: Output, args: ['cdkDragStarted',] }],
2555
+ released: [{ type: Output, args: ['cdkDragReleased',] }],
1255
2556
  ended: [{ type: Output, args: ['cdkDragEnded',] }],
1256
2557
  entered: [{ type: Output, args: ['cdkDragEntered',] }],
1257
2558
  exited: [{ type: Output, args: ['cdkDragExited',] }],
@@ -1259,103 +2560,23 @@ CdkDrag.propDecorators = {
1259
2560
  moved: [{ type: Output, args: ['cdkDragMoved',] }]
1260
2561
  };
1261
2562
  /**
1262
- * Gets a 3d `transform` that can be applied to an element.
1263
- * @param {?} x Desired position of the element along the X axis.
1264
- * @param {?} y Desired position of the element along the Y axis.
1265
- * @return {?}
1266
- */
1267
- function getTransform(x, y) {
1268
- // Round the transforms since some browsers will
1269
- // blur the elements, for sub-pixel transforms.
1270
- return `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`;
1271
- }
1272
- /**
1273
- * Creates a deep clone of an element.
1274
- * @param {?} node
1275
- * @return {?}
1276
- */
1277
- function deepCloneNode(node) {
1278
- /** @type {?} */
1279
- const clone = (/** @type {?} */ (node.cloneNode(true)));
1280
- // Remove the `id` to avoid having multiple elements with the same id on the page.
1281
- clone.removeAttribute('id');
1282
- return clone;
1283
- }
1284
-
1285
- /**
1286
- * @fileoverview added by tsickle
1287
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1288
- */
1289
-
1290
- /**
1291
- * Moves an item one index in an array to another.
1292
- * @template T
1293
- * @param {?} array Array in which to move the item.
1294
- * @param {?} fromIndex Starting index of the item.
1295
- * @param {?} toIndex Index to which the item should be moved.
1296
- * @return {?}
1297
- */
1298
- function moveItemInArray(array, fromIndex, toIndex) {
1299
- /** @type {?} */
1300
- const from = clamp(fromIndex, array.length - 1);
1301
- /** @type {?} */
1302
- const to = clamp(toIndex, array.length - 1);
1303
- if (from === to) {
1304
- return;
1305
- }
1306
- /** @type {?} */
1307
- const target = array[from];
1308
- /** @type {?} */
1309
- const delta = to < from ? -1 : 1;
1310
- for (let i = from; i !== to; i += delta) {
1311
- array[i] = array[i + delta];
1312
- }
1313
- array[to] = target;
1314
- }
1315
- /**
1316
- * Moves an item from one array to another.
1317
- * @template T
1318
- * @param {?} currentArray Array from which to transfer the item.
1319
- * @param {?} targetArray Array into which to put the item.
1320
- * @param {?} currentIndex Index of the item in its current array.
1321
- * @param {?} targetIndex Index at which to insert the item.
1322
- * @return {?}
1323
- */
1324
- function transferArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
1325
- /** @type {?} */
1326
- const from = clamp(currentIndex, currentArray.length - 1);
1327
- /** @type {?} */
1328
- const to = clamp(targetIndex, targetArray.length);
1329
- if (currentArray.length) {
1330
- targetArray.splice(to, 0, currentArray.splice(from, 1)[0]);
1331
- }
1332
- }
1333
- /**
1334
- * Copies an item from one array to another, leaving it in its
1335
- * original position in current array.
1336
- * @template T
1337
- * @param {?} currentArray Array from which to copy the item.
1338
- * @param {?} targetArray Array into which is copy the item.
1339
- * @param {?} currentIndex Index of the item in its current array.
1340
- * @param {?} targetIndex Index at which to insert the item.
1341
- *
2563
+ * Gets the closest ancestor of an element that matches a selector.
2564
+ * @param {?} element
2565
+ * @param {?} selector
1342
2566
  * @return {?}
1343
2567
  */
1344
- function copyArrayItem(currentArray, targetArray, currentIndex, targetIndex) {
2568
+ function getClosestMatchingAncestor(element, selector) {
1345
2569
  /** @type {?} */
1346
- const to = clamp(targetIndex, targetArray.length);
1347
- if (currentArray.length) {
1348
- targetArray.splice(to, 0, currentArray[currentIndex]);
2570
+ let currentElement = (/** @type {?} */ (element.parentElement));
2571
+ while (currentElement) {
2572
+ // IE doesn't support `matches` so we have to fall back to `msMatchesSelector`.
2573
+ if (currentElement.matches ? currentElement.matches(selector) :
2574
+ ((/** @type {?} */ (currentElement))).msMatchesSelector(selector)) {
2575
+ return currentElement;
2576
+ }
2577
+ currentElement = currentElement.parentElement;
1349
2578
  }
1350
- }
1351
- /**
1352
- * Clamps a number between zero and a maximum.
1353
- * @param {?} value
1354
- * @param {?} max
1355
- * @return {?}
1356
- */
1357
- function clamp(value, max) {
1358
- return Math.max(0, Math.min(max, value));
2579
+ return null;
1359
2580
  }
1360
2581
 
1361
2582
  /**
@@ -1375,6 +2596,19 @@ class CdkDropListGroup {
1375
2596
  * Drop lists registered inside the group.
1376
2597
  */
1377
2598
  this._items = new Set();
2599
+ this._disabled = false;
2600
+ }
2601
+ /**
2602
+ * Whether starting a dragging sequence from inside this group is disabled.
2603
+ * @return {?}
2604
+ */
2605
+ get disabled() { return this._disabled; }
2606
+ /**
2607
+ * @param {?} value
2608
+ * @return {?}
2609
+ */
2610
+ set disabled(value) {
2611
+ this._disabled = coerceBooleanProperty(value);
1378
2612
  }
1379
2613
  /**
1380
2614
  * @return {?}
@@ -1389,6 +2623,9 @@ CdkDropListGroup.decorators = [
1389
2623
  exportAs: 'cdkDropListGroup',
1390
2624
  },] },
1391
2625
  ];
2626
+ CdkDropListGroup.propDecorators = {
2627
+ disabled: [{ type: Input, args: ['cdkDropListGroupDisabled',] }]
2628
+ };
1392
2629
 
1393
2630
  /**
1394
2631
  * @fileoverview added by tsickle
@@ -1398,14 +2635,11 @@ CdkDropListGroup.decorators = [
1398
2635
  * Counter used to generate unique ids for drop zones.
1399
2636
  * @type {?}
1400
2637
  */
1401
- let _uniqueIdCounter = 0;
1402
- /**
1403
- * Proximity, as a ratio to width/height, at which a
1404
- * dragged item will affect the drop container.
1405
- * @type {?}
1406
- */
1407
- const DROP_PROXIMITY_THRESHOLD = 0.05;
2638
+ let _uniqueIdCounter$1 = 0;
1408
2639
  const ɵ0 = undefined;
2640
+ // @breaking-change 8.0.0 `CdkDropList` implements `CdkDropListContainer` for backwards
2641
+ // compatiblity. The implements clause, as well as all the methods that it enforces can
2642
+ // be removed when `CdkDropListContainer` is deleted.
1409
2643
  /**
1410
2644
  * Container that wraps a set of draggable items.
1411
2645
  * @template T
@@ -1413,17 +2647,28 @@ const ɵ0 = undefined;
1413
2647
  class CdkDropList {
1414
2648
  /**
1415
2649
  * @param {?} element
1416
- * @param {?} _dragDropRegistry
2650
+ * @param {?} dragDropRegistry
1417
2651
  * @param {?} _changeDetectorRef
1418
2652
  * @param {?=} _dir
1419
2653
  * @param {?=} _group
2654
+ * @param {?=} _document
2655
+ * @param {?=} dragDrop
2656
+ */
2657
+ constructor(element, dragDropRegistry, _changeDetectorRef, _dir, _group, _document,
2658
+ /**
2659
+ * @deprecated `dragDropRegistry` and `_document` parameters to be removed.
2660
+ * Also `dragDrop` parameter to be made required.
2661
+ * @breaking-change 8.0.0.
1420
2662
  */
1421
- constructor(element, _dragDropRegistry, _changeDetectorRef, _dir, _group) {
2663
+ dragDrop) {
1422
2664
  this.element = element;
1423
- this._dragDropRegistry = _dragDropRegistry;
1424
2665
  this._changeDetectorRef = _changeDetectorRef;
1425
2666
  this._dir = _dir;
1426
2667
  this._group = _group;
2668
+ /**
2669
+ * Emits when the list has been destroyed.
2670
+ */
2671
+ this._destroyed = new Subject();
1427
2672
  /**
1428
2673
  * Other draggable containers that this container is connected to and into which the
1429
2674
  * container's items can be transferred. Can either be references to other drop containers,
@@ -1438,477 +2683,246 @@ class CdkDropList {
1438
2683
  * Unique ID for the drop zone. Can be used as a reference
1439
2684
  * in the `connectedTo` of another `CdkDropList`.
1440
2685
  */
1441
- this.id = `cdk-drop-list-${_uniqueIdCounter++}`;
2686
+ this.id = `cdk-drop-list-${_uniqueIdCounter$1++}`;
1442
2687
  this._disabled = false;
1443
2688
  /**
1444
2689
  * Function that is used to determine whether an item
1445
2690
  * is allowed to be moved into a drop container.
1446
2691
  */
1447
2692
  this.enterPredicate = () => true;
1448
- /**
1449
- * Emits when the user drops an item inside the container.
1450
- */
1451
- this.dropped = new EventEmitter();
1452
- /**
1453
- * Emits when the user has moved a new drag item into this container.
1454
- */
1455
- this.entered = new EventEmitter();
1456
- /**
1457
- * Emits when the user removes an item from the container
1458
- * by dragging it into another container.
1459
- */
1460
- this.exited = new EventEmitter();
1461
- /**
1462
- * Emits as the user is swapping items while actively dragging.
1463
- */
1464
- this.sorted = new EventEmitter();
1465
- /**
1466
- * Whether an item in the container is being dragged.
1467
- */
1468
- this._dragging = false;
1469
- /**
1470
- * Cache of the dimensions of all the items and the sibling containers.
1471
- */
1472
- this._positionCache = { items: [], siblings: [], self: (/** @type {?} */ ({})) };
1473
- /**
1474
- * Keeps track of the item that was last swapped with the dragged item, as
1475
- * well as what direction the pointer was moving in when the swap occured.
1476
- */
1477
- this._previousSwap = { drag: (/** @type {?} */ (null)), delta: 0 };
1478
- }
1479
- /**
1480
- * Whether starting a dragging sequence from this container is disabled.
1481
- * @return {?}
1482
- */
1483
- get disabled() { return this._disabled; }
1484
- /**
1485
- * @param {?} value
1486
- * @return {?}
1487
- */
1488
- set disabled(value) {
1489
- this._disabled = coerceBooleanProperty(value);
1490
- }
1491
- /**
1492
- * @return {?}
1493
- */
1494
- ngOnInit() {
1495
- this._dragDropRegistry.registerDropContainer(this);
1496
- if (this._group) {
1497
- this._group._items.add(this);
1498
- }
1499
- }
1500
- /**
1501
- * @return {?}
1502
- */
1503
- ngOnDestroy() {
1504
- this._dragDropRegistry.removeDropContainer(this);
1505
- if (this._group) {
1506
- this._group._items.delete(this);
1507
- }
1508
- }
1509
- /**
1510
- * Starts dragging an item.
1511
- * @return {?}
1512
- */
1513
- start() {
1514
- this._dragging = true;
1515
- this._activeDraggables = this._draggables.toArray();
1516
- this._cachePositions();
1517
- this._changeDetectorRef.markForCheck();
1518
- }
1519
- /**
1520
- * Drops an item into this container.
1521
- * @param {?} item Item being dropped into the container.
1522
- * @param {?} currentIndex Index at which the item should be inserted.
1523
- * @param {?} previousContainer Container from which the item got dragged in.
1524
- * @return {?}
1525
- */
1526
- drop(item, currentIndex, previousContainer) {
1527
- this._reset();
1528
- this.dropped.emit({
1529
- item,
1530
- currentIndex,
1531
- previousIndex: previousContainer.getItemIndex(item),
1532
- container: this,
1533
- // TODO(crisbeto): reconsider whether to make this null if the containers are the same.
1534
- previousContainer
1535
- });
1536
- }
1537
- /**
1538
- * Emits an event to indicate that the user moved an item into the container.
1539
- * @param {?} item Item that was moved into the container.
1540
- * @param {?} pointerX Position of the item along the X axis.
1541
- * @param {?} pointerY Position of the item along the Y axis.
1542
- * @return {?}
1543
- */
1544
- enter(item, pointerX, pointerY) {
1545
- this.entered.emit({ item, container: this });
1546
- this.start();
1547
- // We use the coordinates of where the item entered the drop
1548
- // zone to figure out at which index it should be inserted.
1549
- /** @type {?} */
1550
- const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY);
1551
- /** @type {?} */
1552
- const currentIndex = this._activeDraggables.indexOf(item);
1553
- /** @type {?} */
1554
- const newPositionReference = this._activeDraggables[newIndex];
1555
- /** @type {?} */
1556
- const placeholder = item.getPlaceholderElement();
1557
- // Since the item may be in the `activeDraggables` already (e.g. if the user dragged it
1558
- // into another container and back again), we have to ensure that it isn't duplicated.
1559
- if (currentIndex > -1) {
1560
- this._activeDraggables.splice(currentIndex, 1);
1561
- }
1562
- // Don't use items that are being dragged as a reference, because
1563
- // their element has been moved down to the bottom of the body.
1564
- if (newPositionReference && !this._dragDropRegistry.isDragging(newPositionReference)) {
1565
- /** @type {?} */
1566
- const element = newPositionReference.getRootElement();
1567
- (/** @type {?} */ (element.parentElement)).insertBefore(placeholder, element);
1568
- this._activeDraggables.splice(newIndex, 0, item);
1569
- }
1570
- else {
1571
- this.element.nativeElement.appendChild(placeholder);
1572
- this._activeDraggables.push(item);
1573
- }
1574
- // The transform needs to be cleared so it doesn't throw off the measurements.
1575
- placeholder.style.transform = '';
1576
- // Note that the positions were already cached when we called `start` above,
1577
- // but we need to refresh them since the amount of items has changed.
1578
- this._cachePositions();
1579
- }
1580
- /**
1581
- * Removes an item from the container after it was dragged into another container by the user.
1582
- * @param {?} item Item that was dragged out.
1583
- * @return {?}
1584
- */
1585
- exit(item) {
1586
- this._reset();
1587
- this.exited.emit({ item, container: this });
1588
- }
1589
- /**
1590
- * Figures out the index of an item in the container.
1591
- * @param {?} item Item whose index should be determined.
1592
- * @return {?}
1593
- */
1594
- getItemIndex(item) {
1595
- if (!this._dragging) {
1596
- return this._draggables.toArray().indexOf(item);
1597
- }
1598
- // Items are sorted always by top/left in the cache, however they flow differently in RTL.
1599
- // The rest of the logic still stands no matter what orientation we're in, however
1600
- // we need to invert the array when determining the index.
1601
- /** @type {?} */
1602
- const items = this.orientation === 'horizontal' && this._dir && this._dir.value === 'rtl' ?
1603
- this._positionCache.items.slice().reverse() : this._positionCache.items;
1604
- return findIndex(items, currentItem => currentItem.drag === item);
1605
- }
1606
- /**
1607
- * Sorts an item inside the container based on its position.
1608
- * @param {?} item Item to be sorted.
1609
- * @param {?} pointerX Position of the item along the X axis.
1610
- * @param {?} pointerY Position of the item along the Y axis.
1611
- * @param {?} pointerDelta
1612
- * @return {?}
1613
- */
1614
- _sortItem(item, pointerX, pointerY, pointerDelta) {
1615
- // Don't sort the item if it's out of range.
1616
- if (!this._isPointerNearDropContainer(pointerX, pointerY)) {
1617
- return;
1618
- }
1619
- /** @type {?} */
1620
- const siblings = this._positionCache.items;
1621
- /** @type {?} */
1622
- const newIndex = this._getItemIndexFromPointerPosition(item, pointerX, pointerY, pointerDelta);
1623
- if (newIndex === -1 && siblings.length > 0) {
1624
- return;
1625
- }
1626
- /** @type {?} */
1627
- const isHorizontal = this.orientation === 'horizontal';
1628
- /** @type {?} */
1629
- const currentIndex = findIndex(siblings, currentItem => currentItem.drag === item);
1630
- /** @type {?} */
1631
- const siblingAtNewPosition = siblings[newIndex];
1632
- /** @type {?} */
1633
- const currentPosition = siblings[currentIndex].clientRect;
1634
- /** @type {?} */
1635
- const newPosition = siblingAtNewPosition.clientRect;
1636
- /** @type {?} */
1637
- const delta = currentIndex > newIndex ? 1 : -1;
1638
- this._previousSwap.drag = siblingAtNewPosition.drag;
1639
- this._previousSwap.delta = isHorizontal ? pointerDelta.x : pointerDelta.y;
1640
- // How many pixels the item's placeholder should be offset.
1641
- /** @type {?} */
1642
- const itemOffset = this._getItemOffsetPx(currentPosition, newPosition, delta);
1643
- // How many pixels all the other items should be offset.
1644
- /** @type {?} */
1645
- const siblingOffset = this._getSiblingOffsetPx(currentIndex, siblings, delta);
1646
- // Save the previous order of the items before moving the item to its new index.
1647
- // We use this to check whether an item has been moved as a result of the sorting.
1648
- /** @type {?} */
1649
- const oldOrder = siblings.slice();
1650
- // Shuffle the array in place.
1651
- moveItemInArray(siblings, currentIndex, newIndex);
1652
- this.sorted.emit({
1653
- previousIndex: currentIndex,
1654
- currentIndex: newIndex,
1655
- container: this,
1656
- item
1657
- });
1658
- siblings.forEach((sibling, index) => {
1659
- // Don't do anything if the position hasn't changed.
1660
- if (oldOrder[index] === sibling) {
1661
- return;
1662
- }
1663
- /** @type {?} */
1664
- const isDraggedItem = sibling.drag === item;
1665
- /** @type {?} */
1666
- const offset = isDraggedItem ? itemOffset : siblingOffset;
1667
- /** @type {?} */
1668
- const elementToOffset = isDraggedItem ? item.getPlaceholderElement() :
1669
- sibling.drag.getRootElement();
1670
- // Update the offset to reflect the new position.
1671
- sibling.offset += offset;
1672
- // Since we're moving the items with a `transform`, we need to adjust their cached
1673
- // client rects to reflect their new position, as well as swap their positions in the cache.
1674
- // Note that we shouldn't use `getBoundingClientRect` here to update the cache, because the
1675
- // elements may be mid-animation which will give us a wrong result.
1676
- if (isHorizontal) {
1677
- // Round the transforms since some browsers will
1678
- // blur the elements, for sub-pixel transforms.
1679
- elementToOffset.style.transform = `translate3d(${Math.round(sibling.offset)}px, 0, 0)`;
1680
- this._adjustClientRect(sibling.clientRect, 0, offset);
1681
- }
1682
- else {
1683
- elementToOffset.style.transform = `translate3d(0, ${Math.round(sibling.offset)}px, 0)`;
1684
- this._adjustClientRect(sibling.clientRect, offset, 0);
1685
- }
2693
+ /**
2694
+ * Emits when the user drops an item inside the container.
2695
+ */
2696
+ this.dropped = new EventEmitter();
2697
+ /**
2698
+ * Emits when the user has moved a new drag item into this container.
2699
+ */
2700
+ this.entered = new EventEmitter();
2701
+ /**
2702
+ * Emits when the user removes an item from the container
2703
+ * by dragging it into another container.
2704
+ */
2705
+ this.exited = new EventEmitter();
2706
+ /**
2707
+ * Emits as the user is swapping items while actively dragging.
2708
+ */
2709
+ this.sorted = new EventEmitter();
2710
+ // @breaking-change 8.0.0 Remove null check once `dragDrop` parameter is made required.
2711
+ if (dragDrop) {
2712
+ this._dropListRef = dragDrop.createDropList(element);
2713
+ }
2714
+ else {
2715
+ this._dropListRef = new DropListRef(element, dragDropRegistry, _document || document);
2716
+ }
2717
+ this._dropListRef.data = this;
2718
+ this._dropListRef.enterPredicate = (drag, drop) => {
2719
+ return this.enterPredicate(drag.data, drop.data);
2720
+ };
2721
+ this._syncInputs(this._dropListRef);
2722
+ this._handleEvents(this._dropListRef);
2723
+ CdkDropList._dropLists.push(this);
2724
+ if (_group) {
2725
+ _group._items.add(this);
2726
+ }
2727
+ }
2728
+ /**
2729
+ * Whether starting a dragging sequence from this container is disabled.
2730
+ * @return {?}
2731
+ */
2732
+ get disabled() {
2733
+ return this._disabled || (!!this._group && this._group.disabled);
2734
+ }
2735
+ /**
2736
+ * @param {?} value
2737
+ * @return {?}
2738
+ */
2739
+ set disabled(value) {
2740
+ this._disabled = coerceBooleanProperty(value);
2741
+ }
2742
+ /**
2743
+ * @return {?}
2744
+ */
2745
+ ngAfterContentInit() {
2746
+ this._draggables.changes
2747
+ .pipe(startWith(this._draggables), takeUntil(this._destroyed))
2748
+ .subscribe((items) => {
2749
+ this._dropListRef.withItems(items.map(drag => drag._dragRef));
1686
2750
  });
1687
2751
  }
1688
2752
  /**
1689
- * Figures out whether an item should be moved into a sibling
1690
- * drop container, based on its current position.
1691
- * @param {?} item Drag item that is being moved.
1692
- * @param {?} x Position of the item along the X axis.
1693
- * @param {?} y Position of the item along the Y axis.
1694
2753
  * @return {?}
1695
2754
  */
1696
- _getSiblingContainerFromPosition(item, x, y) {
2755
+ ngOnDestroy() {
1697
2756
  /** @type {?} */
1698
- const result = this._positionCache.siblings
1699
- .find(sibling => isInsideClientRect(sibling.clientRect, x, y));
1700
- return result && result.drop.enterPredicate(item, result.drop) ? result.drop : null;
2757
+ const index = CdkDropList._dropLists.indexOf(this);
2758
+ if (index > -1) {
2759
+ CdkDropList._dropLists.splice(index, 1);
2760
+ }
2761
+ if (this._group) {
2762
+ this._group._items.delete(this);
2763
+ }
2764
+ this._dropListRef.dispose();
2765
+ this._destroyed.next();
2766
+ this._destroyed.complete();
1701
2767
  }
1702
2768
  /**
1703
- * Checks whether an item that started in this container can be returned to it,
1704
- * after it was moved out into another container.
1705
- * @param {?} x Position of the item along the X axis.
1706
- * @param {?} y Position of the item along the Y axis.
2769
+ * Starts dragging an item.
1707
2770
  * @return {?}
1708
2771
  */
1709
- _canReturnItem(x, y) {
1710
- return isInsideClientRect(this._positionCache.self, x, y);
2772
+ start() {
2773
+ this._dropListRef.start();
1711
2774
  }
1712
2775
  /**
1713
- * Refreshes the position cache of the items and sibling containers.
1714
- * @private
2776
+ * Drops an item into this container.
2777
+ * @param {?} item Item being dropped into the container.
2778
+ * @param {?} currentIndex Index at which the item should be inserted.
2779
+ * @param {?} previousContainer Container from which the item got dragged in.
2780
+ * @param {?} isPointerOverContainer Whether the user's pointer was over the
2781
+ * container when the item was dropped.
1715
2782
  * @return {?}
1716
2783
  */
1717
- _cachePositions() {
1718
- /** @type {?} */
1719
- const isHorizontal = this.orientation === 'horizontal';
1720
- this._positionCache.self = this.element.nativeElement.getBoundingClientRect();
1721
- this._positionCache.items = this._activeDraggables
1722
- .map(drag => {
1723
- /** @type {?} */
1724
- const elementToMeasure = this._dragDropRegistry.isDragging(drag) ?
1725
- // If the element is being dragged, we have to measure the
1726
- // placeholder, because the element is hidden.
1727
- drag.getPlaceholderElement() :
1728
- drag.getRootElement();
1729
- /** @type {?} */
1730
- const clientRect = elementToMeasure.getBoundingClientRect();
1731
- return {
1732
- drag,
1733
- offset: 0,
1734
- // We need to clone the `clientRect` here, because all the values on it are readonly
1735
- // and we need to be able to update them. Also we can't use a spread here, because
1736
- // the values on a `ClientRect` aren't own properties. See:
1737
- // https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#Notes
1738
- clientRect: {
1739
- top: clientRect.top,
1740
- right: clientRect.right,
1741
- bottom: clientRect.bottom,
1742
- left: clientRect.left,
1743
- width: clientRect.width,
1744
- height: clientRect.height
1745
- }
1746
- };
1747
- })
1748
- .sort((a, b) => {
1749
- return isHorizontal ? a.clientRect.left - b.clientRect.left :
1750
- a.clientRect.top - b.clientRect.top;
1751
- });
1752
- this._positionCache.siblings = this._getConnectedLists().map(drop => ({
1753
- drop,
1754
- clientRect: drop.element.nativeElement.getBoundingClientRect()
1755
- }));
2784
+ drop(item, currentIndex, previousContainer, isPointerOverContainer) {
2785
+ this._dropListRef.drop(item._dragRef, currentIndex, ((/** @type {?} */ (previousContainer)))._dropListRef, isPointerOverContainer);
1756
2786
  }
1757
2787
  /**
1758
- * Resets the container to its initial state.
1759
- * @private
2788
+ * Emits an event to indicate that the user moved an item into the container.
2789
+ * @param {?} item Item that was moved into the container.
2790
+ * @param {?} pointerX Position of the item along the X axis.
2791
+ * @param {?} pointerY Position of the item along the Y axis.
1760
2792
  * @return {?}
1761
2793
  */
1762
- _reset() {
1763
- this._dragging = false;
1764
- // TODO(crisbeto): may have to wait for the animations to finish.
1765
- this._activeDraggables.forEach(item => item.getRootElement().style.transform = '');
1766
- this._activeDraggables = [];
1767
- this._positionCache.items = [];
1768
- this._positionCache.siblings = [];
1769
- this._previousSwap.drag = null;
1770
- this._previousSwap.delta = 0;
2794
+ enter(item, pointerX, pointerY) {
2795
+ this._dropListRef.enter(item._dragRef, pointerX, pointerY);
1771
2796
  }
1772
2797
  /**
1773
- * Updates the top/left positions of a `ClientRect`, as well as their bottom/right counterparts.
1774
- * @private
1775
- * @param {?} clientRect `ClientRect` that should be updated.
1776
- * @param {?} top Amount to add to the `top` position.
1777
- * @param {?} left Amount to add to the `left` position.
2798
+ * Removes an item from the container after it was dragged into another container by the user.
2799
+ * @param {?} item Item that was dragged out.
1778
2800
  * @return {?}
1779
2801
  */
1780
- _adjustClientRect(clientRect, top, left) {
1781
- clientRect.top += top;
1782
- clientRect.bottom = clientRect.top + clientRect.height;
1783
- clientRect.left += left;
1784
- clientRect.right = clientRect.left + clientRect.width;
2802
+ exit(item) {
2803
+ this._dropListRef.exit(item._dragRef);
1785
2804
  }
1786
2805
  /**
1787
- * Gets the index of an item in the drop container, based on the position of the user's pointer.
1788
- * @private
1789
- * @param {?} item Item that is being sorted.
1790
- * @param {?} pointerX Position of the user's pointer along the X axis.
1791
- * @param {?} pointerY Position of the user's pointer along the Y axis.
1792
- * @param {?=} delta Direction in which the user is moving their pointer.
2806
+ * Figures out the index of an item in the container.
2807
+ * @param {?} item Item whose index should be determined.
1793
2808
  * @return {?}
1794
2809
  */
1795
- _getItemIndexFromPointerPosition(item, pointerX, pointerY, delta) {
1796
- /** @type {?} */
1797
- const isHorizontal = this.orientation === 'horizontal';
1798
- return findIndex(this._positionCache.items, ({ drag, clientRect }, _, array) => {
1799
- if (drag === item) {
1800
- // If there's only one item left in the container, it must be
1801
- // the dragged item itself so we use it as a reference.
1802
- return array.length < 2;
1803
- }
1804
- if (delta) {
1805
- /** @type {?} */
1806
- const direction = isHorizontal ? delta.x : delta.y;
1807
- // If the user is still hovering over the same item as last time, and they didn't change
1808
- // the direction in which they're dragging, we don't consider it a direction swap.
1809
- if (drag === this._previousSwap.drag && direction === this._previousSwap.delta) {
1810
- return false;
1811
- }
1812
- }
1813
- return isHorizontal ?
1814
- // Round these down since most browsers report client rects with
1815
- // sub-pixel precision, whereas the pointer coordinates are rounded to pixels.
1816
- pointerX >= Math.floor(clientRect.left) && pointerX <= Math.floor(clientRect.right) :
1817
- pointerY >= Math.floor(clientRect.top) && pointerY <= Math.floor(clientRect.bottom);
1818
- });
2810
+ getItemIndex(item) {
2811
+ return this._dropListRef.getItemIndex(item._dragRef);
1819
2812
  }
1820
2813
  /**
1821
- * Checks whether the pointer coordinates are close to the drop container.
1822
- * @private
1823
- * @param {?} pointerX Coordinates along the X axis.
1824
- * @param {?} pointerY Coordinates along the Y axis.
2814
+ * Sorts an item inside the container based on its position.
2815
+ * @param {?} item Item to be sorted.
2816
+ * @param {?} pointerX Position of the item along the X axis.
2817
+ * @param {?} pointerY Position of the item along the Y axis.
2818
+ * @param {?} pointerDelta Direction in which the pointer is moving along each axis.
1825
2819
  * @return {?}
1826
2820
  */
1827
- _isPointerNearDropContainer(pointerX, pointerY) {
1828
- const { top, right, bottom, left, width, height } = this._positionCache.self;
1829
- /** @type {?} */
1830
- const xThreshold = width * DROP_PROXIMITY_THRESHOLD;
1831
- /** @type {?} */
1832
- const yThreshold = height * DROP_PROXIMITY_THRESHOLD;
1833
- return pointerY > top - yThreshold && pointerY < bottom + yThreshold &&
1834
- pointerX > left - xThreshold && pointerX < right + xThreshold;
2821
+ _sortItem(item, pointerX, pointerY, pointerDelta) {
2822
+ return this._dropListRef._sortItem(item._dragRef, pointerX, pointerY, pointerDelta);
1835
2823
  }
1836
2824
  /**
1837
- * Gets the offset in pixels by which the item that is being dragged should be moved.
1838
- * @private
1839
- * @param {?} currentPosition Current position of the item.
1840
- * @param {?} newPosition Position of the item where the current item should be moved.
1841
- * @param {?} delta Direction in which the user is moving.
2825
+ * Figures out whether an item should be moved into a sibling
2826
+ * drop container, based on its current position.
2827
+ * @param {?} item Drag item that is being moved.
2828
+ * @param {?} x Position of the item along the X axis.
2829
+ * @param {?} y Position of the item along the Y axis.
1842
2830
  * @return {?}
1843
2831
  */
1844
- _getItemOffsetPx(currentPosition, newPosition, delta) {
1845
- /** @type {?} */
1846
- const isHorizontal = this.orientation === 'horizontal';
2832
+ _getSiblingContainerFromPosition(item, x, y) {
1847
2833
  /** @type {?} */
1848
- let itemOffset = isHorizontal ? newPosition.left - currentPosition.left :
1849
- newPosition.top - currentPosition.top;
1850
- // Account for differences in the item width/height.
1851
- if (delta === -1) {
1852
- itemOffset += isHorizontal ? newPosition.width - currentPosition.width :
1853
- newPosition.height - currentPosition.height;
1854
- }
1855
- return itemOffset;
2834
+ const result = this._dropListRef._getSiblingContainerFromPosition(item._dragRef, x, y);
2835
+ return result ? result.data : null;
1856
2836
  }
1857
2837
  /**
1858
- * Gets the offset in pixels by which the items that aren't being dragged should be moved.
2838
+ * Checks whether the user's pointer is positioned over the container.
2839
+ * @param {?} x Pointer position along the X axis.
2840
+ * @param {?} y Pointer position along the Y axis.
2841
+ * @return {?}
2842
+ */
2843
+ _isOverContainer(x, y) {
2844
+ return this._dropListRef._isOverContainer(x, y);
2845
+ }
2846
+ /**
2847
+ * Syncs the inputs of the CdkDropList with the options of the underlying DropListRef.
1859
2848
  * @private
1860
- * @param {?} currentIndex Index of the item currently being dragged.
1861
- * @param {?} siblings All of the items in the list.
1862
- * @param {?} delta Direction in which the user is moving.
2849
+ * @param {?} ref
1863
2850
  * @return {?}
1864
2851
  */
1865
- _getSiblingOffsetPx(currentIndex, siblings, delta) {
1866
- /** @type {?} */
1867
- const isHorizontal = this.orientation === 'horizontal';
1868
- /** @type {?} */
1869
- const currentPosition = siblings[currentIndex].clientRect;
1870
- /** @type {?} */
1871
- const immediateSibling = siblings[currentIndex + delta * -1];
1872
- /** @type {?} */
1873
- let siblingOffset = currentPosition[isHorizontal ? 'width' : 'height'] * delta;
1874
- if (immediateSibling) {
1875
- /** @type {?} */
1876
- const start = isHorizontal ? 'left' : 'top';
2852
+ _syncInputs(ref) {
2853
+ if (this._dir) {
2854
+ this._dir.change
2855
+ .pipe(startWith(this._dir.value), takeUntil(this._destroyed))
2856
+ .subscribe(value => ref.withDirection(value));
2857
+ }
2858
+ ref.beforeStarted.subscribe(() => {
1877
2859
  /** @type {?} */
1878
- const end = isHorizontal ? 'right' : 'bottom';
1879
- // Get the spacing between the start of the current item and the end of the one immediately
1880
- // after it in the direction in which the user is dragging, or vice versa. We add it to the
1881
- // offset in order to push the element to where it will be when it's inline and is influenced
1882
- // by the `margin` of its siblings.
1883
- if (delta === -1) {
1884
- siblingOffset -= immediateSibling.clientRect[start] - currentPosition[end];
1885
- }
1886
- else {
1887
- siblingOffset += currentPosition[start] - immediateSibling.clientRect[end];
2860
+ const siblings = coerceArray(this.connectedTo).map(drop => {
2861
+ return typeof drop === 'string' ?
2862
+ (/** @type {?} */ (CdkDropList._dropLists.find(list => list.id === drop))) : drop;
2863
+ });
2864
+ if (this._group) {
2865
+ this._group._items.forEach(drop => {
2866
+ if (siblings.indexOf(drop) === -1) {
2867
+ siblings.push(drop);
2868
+ }
2869
+ });
1888
2870
  }
1889
- }
1890
- return siblingOffset;
2871
+ ref.lockAxis = this.lockAxis;
2872
+ ref
2873
+ .connectedTo(siblings.filter(drop => drop && drop !== this).map(list => list._dropListRef))
2874
+ .withOrientation(this.orientation);
2875
+ });
1891
2876
  }
1892
2877
  /**
1893
- * Gets an array of unique drop lists that the current list is connected to.
2878
+ * Handles events from the underlying DropListRef.
1894
2879
  * @private
2880
+ * @param {?} ref
1895
2881
  * @return {?}
1896
2882
  */
1897
- _getConnectedLists() {
1898
- /** @type {?} */
1899
- const siblings = coerceArray(this.connectedTo).map(drop => {
1900
- return typeof drop === 'string' ? (/** @type {?} */ (this._dragDropRegistry.getDropContainer(drop))) : drop;
2883
+ _handleEvents(ref) {
2884
+ ref.beforeStarted.subscribe(() => {
2885
+ this._changeDetectorRef.markForCheck();
1901
2886
  });
1902
- if (this._group) {
1903
- this._group._items.forEach(drop => {
1904
- if (siblings.indexOf(drop) === -1) {
1905
- siblings.push(drop);
1906
- }
2887
+ ref.entered.subscribe(event => {
2888
+ this.entered.emit({
2889
+ container: this,
2890
+ item: event.item.data
1907
2891
  });
1908
- }
1909
- return siblings.filter(drop => drop && drop !== this);
2892
+ });
2893
+ ref.exited.subscribe(event => {
2894
+ this.exited.emit({
2895
+ container: this,
2896
+ item: event.item.data
2897
+ });
2898
+ });
2899
+ ref.sorted.subscribe(event => {
2900
+ this.sorted.emit({
2901
+ previousIndex: event.previousIndex,
2902
+ currentIndex: event.currentIndex,
2903
+ container: this,
2904
+ item: event.item.data
2905
+ });
2906
+ });
2907
+ ref.dropped.subscribe(event => {
2908
+ this.dropped.emit({
2909
+ previousIndex: event.previousIndex,
2910
+ currentIndex: event.currentIndex,
2911
+ previousContainer: event.previousContainer.data,
2912
+ container: event.container.data,
2913
+ item: event.item.data,
2914
+ isPointerOverContainer: event.isPointerOverContainer
2915
+ });
2916
+ // Mark for check since all of these events run outside of change
2917
+ // detection and we're not guaranteed for something else to have triggered it.
2918
+ this._changeDetectorRef.markForCheck();
2919
+ });
1910
2920
  }
1911
2921
  }
2922
+ /**
2923
+ * Keeps track of the drop lists that are currently on the page.
2924
+ */
2925
+ CdkDropList._dropLists = [];
1912
2926
  CdkDropList.decorators = [
1913
2927
  { type: Directive, args: [{
1914
2928
  selector: '[cdkDropList], cdk-drop-list',
@@ -1921,7 +2935,8 @@ CdkDropList.decorators = [
1921
2935
  host: {
1922
2936
  'class': 'cdk-drop-list',
1923
2937
  '[id]': 'id',
1924
- '[class.cdk-drop-list-dragging]': '_dragging'
2938
+ '[class.cdk-drop-list-dragging]': '_dropListRef.isDragging()',
2939
+ '[class.cdk-drop-list-receiving]': '_dropListRef.isReceiving()',
1925
2940
  }
1926
2941
  },] },
1927
2942
  ];
@@ -1931,10 +2946,16 @@ CdkDropList.ctorParameters = () => [
1931
2946
  { type: DragDropRegistry },
1932
2947
  { type: ChangeDetectorRef },
1933
2948
  { type: Directionality, decorators: [{ type: Optional }] },
1934
- { type: CdkDropListGroup, decorators: [{ type: Optional }, { type: SkipSelf }] }
2949
+ { type: CdkDropListGroup, decorators: [{ type: Optional }, { type: SkipSelf }] },
2950
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] },
2951
+ { type: DragDrop }
1935
2952
  ];
1936
2953
  CdkDropList.propDecorators = {
1937
- _draggables: [{ type: ContentChildren, args: [forwardRef(() => CdkDrag),] }],
2954
+ _draggables: [{ type: ContentChildren, args: [forwardRef(() => CdkDrag), {
2955
+ // Explicitly set to false since some of the logic below makes assumptions about it.
2956
+ // The `.withItems` call below should be updated if we ever need to switch this to `true`.
2957
+ descendants: false
2958
+ },] }],
1938
2959
  connectedTo: [{ type: Input, args: ['cdkDropListConnectedTo',] }],
1939
2960
  data: [{ type: Input, args: ['cdkDropListData',] }],
1940
2961
  orientation: [{ type: Input, args: ['cdkDropListOrientation',] }],
@@ -1947,38 +2968,6 @@ CdkDropList.propDecorators = {
1947
2968
  exited: [{ type: Output, args: ['cdkDropListExited',] }],
1948
2969
  sorted: [{ type: Output, args: ['cdkDropListSorted',] }]
1949
2970
  };
1950
- /**
1951
- * Finds the index of an item that matches a predicate function. Used as an equivalent
1952
- * of `Array.prototype.find` which isn't part of the standard Google typings.
1953
- * @template T
1954
- * @param {?} array Array in which to look for matches.
1955
- * @param {?} predicate Function used to determine whether an item is a match.
1956
- * @return {?}
1957
- */
1958
- function findIndex(array, predicate) {
1959
- for (let i = 0; i < array.length; i++) {
1960
- if (predicate(array[i], i, array)) {
1961
- return i;
1962
- }
1963
- }
1964
- return -1;
1965
- }
1966
- /**
1967
- * Checks whether some coordinates are within a `ClientRect`.
1968
- * @param {?} clientRect ClientRect that is being checked.
1969
- * @param {?} x Coordinates along the X axis.
1970
- * @param {?} y Coordinates along the Y axis.
1971
- * @return {?}
1972
- */
1973
- function isInsideClientRect(clientRect, x, y) {
1974
- const { top, bottom, left, right } = clientRect;
1975
- return y >= top && y <= bottom && x >= left && x <= right;
1976
- }
1977
-
1978
- /**
1979
- * @fileoverview added by tsickle
1980
- * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
1981
- */
1982
2971
 
1983
2972
  /**
1984
2973
  * @fileoverview added by tsickle
@@ -2004,6 +2993,9 @@ DragDropModule.decorators = [
2004
2993
  CdkDragPreview,
2005
2994
  CdkDragPlaceholder,
2006
2995
  ],
2996
+ providers: [
2997
+ DragDrop,
2998
+ ]
2007
2999
  },] },
2008
3000
  ];
2009
3001
 
@@ -2017,5 +3009,5 @@ DragDropModule.decorators = [
2017
3009
  * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
2018
3010
  */
2019
3011
 
2020
- export { CdkDropList, CdkDropListGroup, CDK_DROP_LIST_CONTAINER, CDK_DRAG_CONFIG_FACTORY, CDK_DRAG_CONFIG, CdkDrag, CdkDragHandle, moveItemInArray, transferArrayItem, copyArrayItem, CdkDragPreview, CdkDragPlaceholder, DragDropModule, DragDropRegistry, CDK_DRAG_PARENT as ɵa };
3012
+ export { DragDrop, DragRef, DropListRef, CdkDropList, CDK_DROP_LIST, CDK_DROP_LIST_CONTAINER, moveItemInArray, transferArrayItem, copyArrayItem, DragDropModule, DragDropRegistry, CdkDropListGroup, CDK_DRAG_CONFIG_FACTORY, CDK_DRAG_CONFIG, CdkDrag, CdkDragHandle, CdkDragPreview, CdkDragPlaceholder, CDK_DRAG_PARENT as ɵb };
2021
3013
  //# sourceMappingURL=drag-drop.js.map