@angular/cdk 7.0.4 → 7.2.1

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