@@ -43,8 +43,15 @@ export function useAnimations(columns: Column[], autoSized: Ref<boolean>) {
43
43
resetTracking ( ) ;
44
44
} ) ;
45
45
46
- return function headerPointerDown ( { currentTarget : th , x, pointerId } : PointerEvent & { currentTarget : HTMLElement } , column : Column ) {
46
+ // Note that it's possible to skip pointerup events in some edge cases (at least happens in Chromium 82).
47
+ // Examples include stressing the thing like a madman (not sure what triggers the bug then)
48
+ // or judicious use of Alt-Tab when dragging.
49
+ return function headerPointerDown ( { currentTarget : th , x : x0 , button } : PointerEvent & { currentTarget : HTMLElement } , column : Column ) {
50
+ if ( button !== 0 ) return ;
51
+
47
52
let i = columns . indexOf ( column ) ;
53
+ // We missed a pointerup but nevermind, the old listeners are still in place
54
+ if ( column . dragged ) return ;
48
55
49
56
function thresholds ( ) {
50
57
return [
@@ -54,53 +61,72 @@ export function useAnimations(columns: Column[], autoSized: Ref<boolean>) {
54
61
}
55
62
56
63
let [ left , right ] = thresholds ( ) ;
57
- let translateX : CSSUnitValue ;
64
+ let translateX : CSSUnitValue ;
58
65
let transform : CSSTransformValue ;
59
66
60
- const preventClick = ( e : Event ) => e . stopImmediatePropagation ( ) ;
61
-
62
- const moveHandler = ( event : PointerEvent ) => {
63
- let delta = event . x - x ;
64
-
65
- // start dragging after a significant amount of movement
66
- if ( ! column . dragged ) {
67
- if ( Math . abs ( delta ) < 4 ) return ;
68
- column . dragged = true ;
69
- window . addEventListener ( 'click' , preventClick , { once : true , capture : true } )
70
- transform = new CSSTransformValue ( [ new CSSTranslate ( translateX = CSS . px ( 0 ) , CSS . px ( 0 ) ) ] ) ;
71
- }
67
+ const listeners = {
68
+ handleEvent ( e : PointerEvent ) {
69
+ switch ( e . type ) {
70
+ case 'click' :
71
+ e . stopImmediatePropagation ( ) ;
72
+ break ;
73
+ case 'pointermove' :
74
+ this . move ( e ) ;
75
+ break ;
76
+ case 'pointerup' :
77
+ if ( e . button === 0 )
78
+ this . up ( ) ;
79
+ break ;
80
+ }
81
+ } ,
72
82
73
- // swap columns if required
74
- if ( delta < left ) {
75
- const other = columns [ -- i ] ;
76
- x -= other . width ;
77
- columns . splice ( i , 2 , column , other ) ;
78
- delta = event . x - x ;
79
- [ left , right ] = thresholds ( ) ;
80
- }
81
- else if ( delta > right ) {
82
- const other = columns [ ++ i ] ;
83
- x += other . width ;
84
- columns . splice ( i - 1 , 2 , other , column ) ;
85
- delta = event . x - x ;
86
- [ left , right ] = thresholds ( ) ;
87
- }
83
+ move ( { x , buttons } : PointerEvent ) {
84
+ let delta = x - x0 ;
85
+
86
+ // start dragging after a significant amount of movement
87
+ if ( ! column . dragged ) {
88
+ if ( Math . abs ( delta ) < 4 ) return ;
89
+ column . dragged = true ;
90
+ window . addEventListener ( 'click' , this , { once : true , capture : true } )
91
+ transform = new CSSTransformValue ( [ new CSSTranslate ( translateX = CSS . px ( 0 ) , CSS . px ( 0 ) ) ] ) ;
92
+ }
93
+ else if ( ( buttons & 1 ) === 0 ) {
94
+ // button was released without us noticing. This is bad :(
95
+ this . up ( ) ;
96
+ return ;
97
+ }
88
98
89
- translateX . value = delta ;
90
- th . attributeStyleMap . set ( 'transform' , transform ) ;
99
+ // swap columns if required
100
+ if ( delta < left ) {
101
+ const other = columns [ -- i ] ;
102
+ x0 -= other . width ;
103
+ delta = x - x0 ;
104
+ columns . splice ( i , 2 , column , other ) ;
105
+ [ left , right ] = thresholds ( ) ;
106
+ }
107
+ else if ( delta > right ) {
108
+ const other = columns [ ++ i ] ;
109
+ x0 += other . width ;
110
+ delta = x - x0 ;
111
+ columns . splice ( i - 1 , 2 , other , column ) ;
112
+ [ left , right ] = thresholds ( ) ;
113
+ }
114
+
115
+ translateX . value = delta ;
116
+ th . attributeStyleMap . set ( 'transform' , transform ) ;
117
+ } ,
118
+
119
+ up ( ) {
120
+ [ 'pointermove' , 'pointerup' ]
121
+ . forEach ( name => window . removeEventListener ( name , this , true ) ) ;
122
+ if ( ! column . dragged ) return ;
123
+ column . dragged = false ;
124
+ th . attributeStyleMap . delete ( 'transform' ) ;
125
+ setTimeout ( ( ) => window . removeEventListener ( 'click' , this , true ) , 0 ) ;
126
+ }
91
127
} ;
92
128
93
- window . addEventListener ( 'pointermove' , moveHandler , true ) ;
94
-
95
- window . addEventListener ( 'pointerup' , ( ) => {
96
- window . removeEventListener ( 'pointermove' , moveHandler , true ) ;
97
- if ( ! column . dragged ) return ;
98
- column . dragged = false ;
99
- th . attributeStyleMap . delete ( 'transform' ) ;
100
- setTimeout ( ( ) => window . removeEventListener ( 'click' , preventClick , true ) , 0 ) ;
101
- } , {
102
- once : true ,
103
- capture : true
104
- } ) ;
129
+ [ 'pointermove' , 'pointerup' ]
130
+ . forEach ( name => window . addEventListener ( name , listeners , true ) ) ;
105
131
}
106
132
}
0 commit comments