@@ -22,14 +22,15 @@ import {DragDropRegistry} from './drag-drop-registry';
2222import {
2323 combineTransforms ,
2424 DragCSSStyleDeclaration ,
25- extendStyles ,
25+ getTransform ,
2626 toggleNativeDragInteractions ,
2727 toggleVisibility ,
2828} from './dom/styling' ;
29- import { getTransformTransitionDurationInMs } from './dom/transition-duration' ;
3029import { getMutableClientRect , adjustDomRect } from './dom/dom-rect' ;
3130import { ParentPositionTracker } from './dom/parent-position-tracker' ;
3231import { deepCloneNode } from './dom/clone-node' ;
32+ import { DragPreviewTemplate , PreviewRef } from './preview-ref' ;
33+ import { getRootNode } from './dom/root-node' ;
3334
3435/** Object that can be used to configure the behavior of DragRef. */
3536export interface DragRefConfig {
@@ -82,11 +83,6 @@ interface DragHelperTemplate<T = any> {
8283 context : T ;
8384}
8485
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-
9086/** Point on the page or within an element. */
9187export interface Point {
9288 x : number ;
@@ -118,10 +114,7 @@ export type PreviewContainer = 'global' | 'parent' | ElementRef<HTMLElement> | H
118114 */
119115export class DragRef < T = any > {
120116 /** 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 ;
125118
126119 /** Container into which to insert the preview. */
127120 private _previewContainer : PreviewContainer | undefined ;
@@ -627,9 +620,8 @@ export class DragRef<T = any> {
627620
628621 /** Destroys the preview element and its ViewRef. */
629622 private _destroyPreview ( ) {
630- this . _preview ?. remove ( ) ;
631- this . _previewRef ?. destroy ( ) ;
632- this . _preview = this . _previewRef = null ! ;
623+ this . _preview ?. destroy ( ) ;
624+ this . _preview = null ;
633625 }
634626
635627 /** Destroys the placeholder element and its ViewRef. */
@@ -834,14 +826,24 @@ export class DragRef<T = any> {
834826
835827 // Create the preview after the initial transform has
836828 // 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 ) ) ;
838841
839842 // We move the element out at the end of the body and we make it hidden, because keeping it in
840843 // place will throw off the consumer's `:last-child` selectors. We can't remove the element
841844 // from the DOM completely, because iOS will stop firing all subsequent events in the chain.
842845 toggleVisibility ( element , false , dragImportantProperties ) ;
843846 this . _document . body . appendChild ( parent . replaceChild ( placeholder , element ) ) ;
844- this . _getPreviewInsertionPoint ( parent , shadowRoot ) . appendChild ( this . _preview ) ;
845847 this . started . next ( { source : this , event} ) ; // Emit before notifying the container.
846848 dropContainer . start ( ) ;
847849 this . _initialContainer = dropContainer ;
@@ -1056,75 +1058,6 @@ export class DragRef<T = any> {
10561058 }
10571059 }
10581060
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-
11281061 /**
11291062 * Animates the preview element from its current position to the location of the drop placeholder.
11301063 * @returns Promise that resolves when the animation completes.
@@ -1138,7 +1071,7 @@ export class DragRef<T = any> {
11381071 const placeholderRect = this . _placeholder . getBoundingClientRect ( ) ;
11391072
11401073 // 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' ) ;
11421075
11431076 // Move the preview to the placeholder position.
11441077 this . _applyPreviewTransform ( placeholderRect . left , placeholderRect . top ) ;
@@ -1147,7 +1080,7 @@ export class DragRef<T = any> {
11471080 // we need to trigger a style recalculation in order for the `cdk-drag-animating` class to
11481081 // apply its style, we take advantage of the available info to figure out whether we need to
11491082 // bind the event in the first place.
1150- const duration = getTransformTransitionDurationInMs ( this . _preview ) ;
1083+ const duration = this . _preview ! . getTransitionDuration ( ) ;
11511084
11521085 if ( duration === 0 ) {
11531086 return Promise . resolve ( ) ;
@@ -1170,7 +1103,7 @@ export class DragRef<T = any> {
11701103 // Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
11711104 // fire if the transition hasn't completed when it was supposed to.
11721105 const timeout = setTimeout ( handler as Function , duration * 1.5 ) ;
1173- this . _preview . addEventListener ( 'transitionend' , handler ) ;
1106+ this . _preview ! . addEventListener ( 'transitionend' , handler ) ;
11741107 } ) ;
11751108 } ) ;
11761109 }
@@ -1373,7 +1306,7 @@ export class DragRef<T = any> {
13731306 // it could be completely different and the transform might not make sense anymore.
13741307 const initialTransform = this . _previewTemplate ?. template ? undefined : this . _initialTransform ;
13751308 const transform = getTransform ( x , y ) ;
1376- this . _preview . style . transform = combineTransforms ( transform , initialTransform ) ;
1309+ this . _preview ! . setTransform ( combineTransforms ( transform , initialTransform ) ) ;
13771310 }
13781311
13791312 /**
@@ -1559,7 +1492,7 @@ export class DragRef<T = any> {
15591492 // we cached it too early before the element dimensions were computed.
15601493 if ( ! this . _previewRect || ( ! this . _previewRect . width && ! this . _previewRect . height ) ) {
15611494 this . _previewRect = this . _preview
1562- ? this . _preview . getBoundingClientRect ( )
1495+ ? this . _preview ! . getBoundingClientRect ( )
15631496 : this . _initialDomRect ! ;
15641497 }
15651498
@@ -1589,17 +1522,6 @@ export class DragRef<T = any> {
15891522 }
15901523}
15911524
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-
16031525/** Clamps a value between a minimum and a maximum. */
16041526function clamp ( value : number , min : number , max : number ) {
16051527 return Math . max ( min , Math . min ( max , value ) ) ;
@@ -1613,33 +1535,6 @@ function isTouchEvent(event: MouseEvent | TouchEvent): event is TouchEvent {
16131535 return event . type [ 0 ] === 't' ;
16141536}
16151537
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-
16431538/** Callback invoked for `selectstart` events inside the shadow DOM. */
16441539function shadowDomSelectStart ( event : Event ) {
16451540 event . preventDefault ( ) ;
0 commit comments