@@ -231,8 +231,7 @@ export class Drag implements IDisposable {
231
231
return ;
232
232
}
233
233
let style = this . dragImage . style ;
234
- style . top = `${ clientY } px` ;
235
- style . left = `${ clientX } px` ;
234
+ style . transform = `translate(${ clientX } px, ${ clientY } px)` ;
236
235
}
237
236
238
237
/**
@@ -371,7 +370,7 @@ export class Drag implements IDisposable {
371
370
let prevElem = this . _currentElement ;
372
371
373
372
// Find the current indicated element at the given position.
374
- let currElem = this . document . elementFromPoint ( event . clientX , event . clientY ) ;
373
+ let currElem = Private . findElementBehidBackdrop ( event , this . document ) ;
375
374
376
375
// Update the current element reference.
377
376
this . _currentElement = currElem ;
@@ -415,8 +414,7 @@ export class Drag implements IDisposable {
415
414
let style = this . dragImage . style ;
416
415
style . pointerEvents = 'none' ;
417
416
style . position = 'fixed' ;
418
- style . top = `${ clientY } px` ;
419
- style . left = `${ clientX } px` ;
417
+ style . transform = `translate(${ clientX } px, ${ clientY } px)` ;
420
418
const body =
421
419
this . document instanceof Document
422
420
? this . document . body
@@ -789,25 +787,8 @@ export namespace Drag {
789
787
cursor : string ,
790
788
doc : Document | ShadowRoot = document
791
789
) : IDisposable {
792
- let id = ++ overrideCursorID ;
793
- const body =
794
- doc instanceof Document
795
- ? doc . body
796
- : ( doc . firstElementChild as HTMLElement ) ;
797
- body . style . cursor = cursor ;
798
- body . classList . add ( 'lm-mod-override-cursor' ) ;
799
- return new DisposableDelegate ( ( ) => {
800
- if ( id === overrideCursorID ) {
801
- body . style . cursor = '' ;
802
- body . classList . remove ( 'lm-mod-override-cursor' ) ;
803
- }
804
- } ) ;
790
+ return Private . overrideCursor ( cursor , doc ) ;
805
791
}
806
-
807
- /**
808
- * The internal id for the active cursor override.
809
- */
810
- let overrideCursorID = 0 ;
811
792
}
812
793
813
794
/**
@@ -851,6 +832,32 @@ namespace Private {
851
832
distance : number ;
852
833
}
853
834
835
+ /**
836
+ * Find the event target using pointer position.
837
+ */
838
+ export function findElementBehidBackdrop (
839
+ event : PointerEvent ,
840
+ root : Document | ShadowRoot = document
841
+ ) {
842
+ // Check if we already cached element for this event.
843
+ if ( lastElementSearch && event == lastElementSearch . event ) {
844
+ return lastElementSearch . element ;
845
+ }
846
+ Private . cursorBackdrop . style . zIndex = '-1000' ;
847
+ const element : Element | null = root . elementFromPoint (
848
+ event . clientX ,
849
+ event . clientY
850
+ ) ;
851
+ Private . cursorBackdrop . style . zIndex = '' ;
852
+ lastElementSearch = { event, element } ;
853
+ return element ;
854
+ }
855
+
856
+ let lastElementSearch : {
857
+ event : PointerEvent ;
858
+ element : Element | null ;
859
+ } | null = null ;
860
+
854
861
/**
855
862
* Find the drag scroll target under the mouse, if any.
856
863
*/
@@ -860,7 +867,7 @@ namespace Private {
860
867
let y = event . clientY ;
861
868
862
869
// Get the element under the mouse.
863
- let element : Element | null = document . elementFromPoint ( x , y ) ;
870
+ let element : Element | null = findElementBehidBackdrop ( event ) ;
864
871
865
872
// Search for a scrollable target based on the mouse position.
866
873
// The null assert in third clause of for-loop is required due to:
@@ -1211,4 +1218,67 @@ namespace Private {
1211
1218
'link-move' : actionTable [ 'link' ] | actionTable [ 'move' ] ,
1212
1219
all : actionTable [ 'copy' ] | actionTable [ 'link' ] | actionTable [ 'move' ]
1213
1220
} ;
1221
+
1222
+ /**
1223
+ * Implementation of `Drag.overrideCursor`.
1224
+ */
1225
+ export function overrideCursor (
1226
+ cursor : string ,
1227
+ doc : Document | ShadowRoot = document
1228
+ ) : IDisposable {
1229
+ let id = ++ overrideCursorID ;
1230
+ const body =
1231
+ doc instanceof Document
1232
+ ? doc . body
1233
+ : ( doc . firstElementChild as HTMLElement ) ;
1234
+ if ( ! cursorBackdrop . isConnected ) {
1235
+ body . appendChild ( cursorBackdrop ) ;
1236
+ document . addEventListener ( 'pointermove' , alignBackdrop , {
1237
+ capture : true ,
1238
+ passive : true
1239
+ } ) ;
1240
+ }
1241
+ cursorBackdrop . style . cursor = cursor ;
1242
+ return new DisposableDelegate ( ( ) => {
1243
+ if ( id === overrideCursorID && cursorBackdrop . isConnected ) {
1244
+ document . removeEventListener ( 'pointermove' , alignBackdrop , true ) ;
1245
+ body . removeChild ( cursorBackdrop ) ;
1246
+ }
1247
+ } ) ;
1248
+ }
1249
+
1250
+ /**
1251
+ * Move cursor backdrop to match cursor position.
1252
+ */
1253
+ function alignBackdrop ( event : PointerEvent ) {
1254
+ if ( ! cursorBackdrop ) {
1255
+ return ;
1256
+ }
1257
+ cursorBackdrop . style . transform = `translate(${ event . clientX } px, ${ event . clientY } px)` ;
1258
+ }
1259
+
1260
+ /**
1261
+ * Create cursor backdrop node.
1262
+ */
1263
+ function createCursorBackdrop ( ) : HTMLElement {
1264
+ const backdrop = document . createElement ( 'div' ) ;
1265
+ backdrop . classList . add ( 'lm-cursor-backdrop' ) ;
1266
+ return backdrop ;
1267
+ }
1268
+
1269
+ /**
1270
+ * The internal id for the active cursor override.
1271
+ */
1272
+ let overrideCursorID = 0 ;
1273
+
1274
+ /**
1275
+ * A backdrop node overriding pointer cursor.
1276
+ *
1277
+ * #### Notes
1278
+ * We use a backdrop node rather than setting the cursor directly on the body
1279
+ * because setting it on body requires more extensive style recalculation for
1280
+ * reliable application of the cursor, this is the cursor not being overriden
1281
+ * when over child elements with another style like `cursor: other!important`.
1282
+ */
1283
+ export const cursorBackdrop : HTMLElement = createCursorBackdrop ( ) ;
1214
1284
}
0 commit comments