@@ -22,14 +22,15 @@ import {DragDropRegistry} from './drag-drop-registry';
22
22
import {
23
23
combineTransforms ,
24
24
DragCSSStyleDeclaration ,
25
- extendStyles ,
25
+ getTransform ,
26
26
toggleNativeDragInteractions ,
27
27
toggleVisibility ,
28
28
} from './dom/styling' ;
29
- import { getTransformTransitionDurationInMs } from './dom/transition-duration' ;
30
29
import { getMutableClientRect , adjustDomRect } from './dom/dom-rect' ;
31
30
import { ParentPositionTracker } from './dom/parent-position-tracker' ;
32
31
import { deepCloneNode } from './dom/clone-node' ;
32
+ import { DragPreviewTemplate , PreviewRef } from './preview-ref' ;
33
+ import { getRootNode } from './dom/root-node' ;
33
34
34
35
/** Object that can be used to configure the behavior of DragRef. */
35
36
export interface DragRefConfig {
@@ -82,11 +83,6 @@ interface DragHelperTemplate<T = any> {
82
83
context : T ;
83
84
}
84
85
85
- /** Template that can be used to create a drag preview element. */
86
- interface DragPreviewTemplate < T = any > extends DragHelperTemplate < T > {
87
- matchSize ?: boolean ;
88
- }
89
-
90
86
/** Point on the page or within an element. */
91
87
export interface Point {
92
88
x : number ;
@@ -118,10 +114,7 @@ export type PreviewContainer = 'global' | 'parent' | ElementRef<HTMLElement> | H
118
114
*/
119
115
export class DragRef < T = any > {
120
116
/** Element displayed next to the user's pointer while the element is dragged. */
121
- private _preview : HTMLElement ;
122
-
123
- /** Reference to the view of the preview element. */
124
- private _previewRef : EmbeddedViewRef < any > | null ;
117
+ private _preview : PreviewRef | null ;
125
118
126
119
/** Container into which to insert the preview. */
127
120
private _previewContainer : PreviewContainer | undefined ;
@@ -627,9 +620,8 @@ export class DragRef<T = any> {
627
620
628
621
/** Destroys the preview element and its ViewRef. */
629
622
private _destroyPreview ( ) {
630
- this . _preview ?. remove ( ) ;
631
- this . _previewRef ?. destroy ( ) ;
632
- this . _preview = this . _previewRef = null ! ;
623
+ this . _preview ?. destroy ( ) ;
624
+ this . _preview = null ;
633
625
}
634
626
635
627
/** Destroys the placeholder element and its ViewRef. */
@@ -834,14 +826,24 @@ export class DragRef<T = any> {
834
826
835
827
// Create the preview after the initial transform has
836
828
// been cached, because it can be affected by the transform.
837
- this . _preview = this . _createPreviewElement ( ) ;
829
+ this . _preview = new PreviewRef (
830
+ this . _document ,
831
+ this . _rootElement ,
832
+ this . _direction ,
833
+ this . _initialDomRect ! ,
834
+ this . _previewTemplate || null ,
835
+ this . previewClass || null ,
836
+ this . _pickupPositionOnPage ,
837
+ this . _initialTransform ,
838
+ this . _config . zIndex || 1000 ,
839
+ ) ;
840
+ this . _preview . attach ( this . _getPreviewInsertionPoint ( parent , shadowRoot ) ) ;
838
841
839
842
// We move the element out at the end of the body and we make it hidden, because keeping it in
840
843
// place will throw off the consumer's `:last-child` selectors. We can't remove the element
841
844
// from the DOM completely, because iOS will stop firing all subsequent events in the chain.
842
845
toggleVisibility ( element , false , dragImportantProperties ) ;
843
846
this . _document . body . appendChild ( parent . replaceChild ( placeholder , element ) ) ;
844
- this . _getPreviewInsertionPoint ( parent , shadowRoot ) . appendChild ( this . _preview ) ;
845
847
this . started . next ( { source : this , event} ) ; // Emit before notifying the container.
846
848
dropContainer . start ( ) ;
847
849
this . _initialContainer = dropContainer ;
@@ -1056,75 +1058,6 @@ export class DragRef<T = any> {
1056
1058
}
1057
1059
}
1058
1060
1059
- /**
1060
- * Creates the element that will be rendered next to the user's pointer
1061
- * and will be used as a preview of the element that is being dragged.
1062
- */
1063
- private _createPreviewElement ( ) : HTMLElement {
1064
- const previewConfig = this . _previewTemplate ;
1065
- const previewClass = this . previewClass ;
1066
- const previewTemplate = previewConfig ? previewConfig . template : null ;
1067
- let preview : HTMLElement ;
1068
-
1069
- if ( previewTemplate && previewConfig ) {
1070
- // Measure the element before we've inserted the preview
1071
- // since the insertion could throw off the measurement.
1072
- const rootRect = previewConfig . matchSize ? this . _initialDomRect : null ;
1073
- const viewRef = previewConfig . viewContainer . createEmbeddedView (
1074
- previewTemplate ,
1075
- previewConfig . context ,
1076
- ) ;
1077
- viewRef . detectChanges ( ) ;
1078
- preview = getRootNode ( viewRef , this . _document ) ;
1079
- this . _previewRef = viewRef ;
1080
- if ( previewConfig . matchSize ) {
1081
- matchElementSize ( preview , rootRect ! ) ;
1082
- } else {
1083
- preview . style . transform = getTransform (
1084
- this . _pickupPositionOnPage . x ,
1085
- this . _pickupPositionOnPage . y ,
1086
- ) ;
1087
- }
1088
- } else {
1089
- preview = deepCloneNode ( this . _rootElement ) ;
1090
- matchElementSize ( preview , this . _initialDomRect ! ) ;
1091
-
1092
- if ( this . _initialTransform ) {
1093
- preview . style . transform = this . _initialTransform ;
1094
- }
1095
- }
1096
-
1097
- extendStyles (
1098
- preview . style ,
1099
- {
1100
- // It's important that we disable the pointer events on the preview, because
1101
- // it can throw off the `document.elementFromPoint` calls in the `CdkDropList`.
1102
- 'pointer-events' : 'none' ,
1103
- // We have to reset the margin, because it can throw off positioning relative to the viewport.
1104
- 'margin' : '0' ,
1105
- 'position' : 'fixed' ,
1106
- 'top' : '0' ,
1107
- 'left' : '0' ,
1108
- 'z-index' : `${ this . _config . zIndex || 1000 } ` ,
1109
- } ,
1110
- dragImportantProperties ,
1111
- ) ;
1112
-
1113
- toggleNativeDragInteractions ( preview , false ) ;
1114
- preview . classList . add ( 'cdk-drag-preview' ) ;
1115
- preview . setAttribute ( 'dir' , this . _direction ) ;
1116
-
1117
- if ( previewClass ) {
1118
- if ( Array . isArray ( previewClass ) ) {
1119
- previewClass . forEach ( className => preview . classList . add ( className ) ) ;
1120
- } else {
1121
- preview . classList . add ( previewClass ) ;
1122
- }
1123
- }
1124
-
1125
- return preview ;
1126
- }
1127
-
1128
1061
/**
1129
1062
* Animates the preview element from its current position to the location of the drop placeholder.
1130
1063
* @returns Promise that resolves when the animation completes.
@@ -1138,7 +1071,7 @@ export class DragRef<T = any> {
1138
1071
const placeholderRect = this . _placeholder . getBoundingClientRect ( ) ;
1139
1072
1140
1073
// Apply the class that adds a transition to the preview.
1141
- this . _preview . classList . add ( 'cdk-drag-animating' ) ;
1074
+ this . _preview ! . addClass ( 'cdk-drag-animating' ) ;
1142
1075
1143
1076
// Move the preview to the placeholder position.
1144
1077
this . _applyPreviewTransform ( placeholderRect . left , placeholderRect . top ) ;
@@ -1147,7 +1080,7 @@ export class DragRef<T = any> {
1147
1080
// we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
1148
1081
// apply its style, we take advantage of the available info to figure out whether we need to
1149
1082
// bind the event in the first place.
1150
- const duration = getTransformTransitionDurationInMs ( this . _preview ) ;
1083
+ const duration = this . _preview ! . getTransitionDuration ( ) ;
1151
1084
1152
1085
if ( duration === 0 ) {
1153
1086
return Promise . resolve ( ) ;
@@ -1170,7 +1103,7 @@ export class DragRef<T = any> {
1170
1103
// Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
1171
1104
// fire if the transition hasn't completed when it was supposed to.
1172
1105
const timeout = setTimeout ( handler as Function , duration * 1.5 ) ;
1173
- this . _preview . addEventListener ( 'transitionend' , handler ) ;
1106
+ this . _preview ! . addEventListener ( 'transitionend' , handler ) ;
1174
1107
} ) ;
1175
1108
} ) ;
1176
1109
}
@@ -1373,7 +1306,7 @@ export class DragRef<T = any> {
1373
1306
// it could be completely different and the transform might not make sense anymore.
1374
1307
const initialTransform = this . _previewTemplate ?. template ? undefined : this . _initialTransform ;
1375
1308
const transform = getTransform ( x , y ) ;
1376
- this . _preview . style . transform = combineTransforms ( transform , initialTransform ) ;
1309
+ this . _preview ! . setTransform ( combineTransforms ( transform , initialTransform ) ) ;
1377
1310
}
1378
1311
1379
1312
/**
@@ -1559,7 +1492,7 @@ export class DragRef<T = any> {
1559
1492
// we cached it too early before the element dimensions were computed.
1560
1493
if ( ! this . _previewRect || ( ! this . _previewRect . width && ! this . _previewRect . height ) ) {
1561
1494
this . _previewRect = this . _preview
1562
- ? this . _preview . getBoundingClientRect ( )
1495
+ ? this . _preview ! . getBoundingClientRect ( )
1563
1496
: this . _initialDomRect ! ;
1564
1497
}
1565
1498
@@ -1589,17 +1522,6 @@ export class DragRef<T = any> {
1589
1522
}
1590
1523
}
1591
1524
1592
- /**
1593
- * Gets a 3d `transform` that can be applied to an element.
1594
- * @param x Desired position of the element along the X axis.
1595
- * @param y Desired position of the element along the Y axis.
1596
- */
1597
- function getTransform ( x : number , y : number ) : string {
1598
- // Round the transforms since some browsers will
1599
- // blur the elements for sub-pixel transforms.
1600
- return `translate3d(${ Math . round ( x ) } px, ${ Math . round ( y ) } px, 0)` ;
1601
- }
1602
-
1603
1525
/** Clamps a value between a minimum and a maximum. */
1604
1526
function clamp ( value : number , min : number , max : number ) {
1605
1527
return Math . max ( min , Math . min ( max , value ) ) ;
@@ -1613,33 +1535,6 @@ function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
1613
1535
return event . type [ 0 ] === 't' ;
1614
1536
}
1615
1537
1616
- /**
1617
- * Gets the root HTML element of an embedded view.
1618
- * If the root is not an HTML element it gets wrapped in one.
1619
- */
1620
- function getRootNode ( viewRef : EmbeddedViewRef < any > , _document : Document ) : HTMLElement {
1621
- const rootNodes : Node [ ] = viewRef . rootNodes ;
1622
-
1623
- if ( rootNodes . length === 1 && rootNodes [ 0 ] . nodeType === _document . ELEMENT_NODE ) {
1624
- return rootNodes [ 0 ] as HTMLElement ;
1625
- }
1626
-
1627
- const wrapper = _document . createElement ( 'div' ) ;
1628
- rootNodes . forEach ( node => wrapper . appendChild ( node ) ) ;
1629
- return wrapper ;
1630
- }
1631
-
1632
- /**
1633
- * Matches the target element's size to the source's size.
1634
- * @param target Element that needs to be resized.
1635
- * @param sourceRect Dimensions of the source element.
1636
- */
1637
- function matchElementSize ( target : HTMLElement , sourceRect : DOMRect ) : void {
1638
- target . style . width = `${ sourceRect . width } px` ;
1639
- target . style . height = `${ sourceRect . height } px` ;
1640
- target . style . transform = getTransform ( sourceRect . left , sourceRect . top ) ;
1641
- }
1642
-
1643
1538
/** Callback invoked for `selectstart` events inside the shadow DOM. */
1644
1539
function shadowDomSelectStart ( event : Event ) {
1645
1540
event . preventDefault ( ) ;
0 commit comments