7
7
import { h , Fragment } from 'preact' ;
8
8
import './report-upload-box.css' ;
9
9
import { LhrViewerButton } from './lhci-components' ;
10
- import { useState , useEffect } from 'preact/hooks' ;
10
+ import { useState , useEffect , useRef } from 'preact/hooks' ;
11
11
import clsx from 'clsx' ;
12
12
13
13
/** @typedef {import('../app.jsx').ToastMessage } ToastMessage */
14
14
/** @typedef {import('../app.jsx').ReportData } ReportData */
15
15
/** @typedef {'filename'|'hostname'|'pathname'|'path'|'timestamp-hostname'|'timestamp-pathname' } DisplayType */
16
16
/** @typedef {{variant: 'base'|'compare', displayType: DisplayType, report: ReportData|undefined, setReport: (d: ReportData) => void, addToast: (t: ToastMessage) => void, showOpenLhrLink?: boolean, dragTarget?: 'self' | 'document'} } ReportUploadBoxProps */
17
- /** @typedef {{isDragging: boolean, dragTarget: HTMLElement|undefined} } DragData */
17
+ /** @typedef {HTMLElement|undefined } DragData */
18
18
19
19
/** @param {string } s @return {LH.Result|Error } */
20
20
export function parseStringAsLhr ( s ) {
@@ -91,60 +91,60 @@ function handleFileInput(props, fileList) {
91
91
} ) ;
92
92
}
93
93
94
- /** @param {ReportUploadBoxProps } props @param {DragData } dragData @param {(d: DragData ) => void } setDragData @param {Event } e */
95
- function handleDragEnter ( props , dragData , setDragData , e ) {
94
+ /** @param {ReportUploadBoxProps } props @param {import('preact/hooks').Ref< DragData> } dragTargetRef @param {(b: boolean ) => void } setIsDragging @param {Event } e */
95
+ function handleDragEnter ( props , dragTargetRef , setIsDragging , e ) {
96
96
if ( ! ( e . target instanceof HTMLElement ) ) return ;
97
- if ( dragData . isDragging && dragData . dragTarget === e . target ) return ;
98
97
e . stopPropagation ( ) ;
99
98
e . preventDefault ( ) ;
100
- setDragData ( { isDragging : true , dragTarget : e . target } ) ;
99
+ setIsDragging ( true ) ;
100
+ dragTargetRef . current = e . target ;
101
101
}
102
102
103
- /** @param {ReportUploadBoxProps } props @param {DragData } dragData @param {(d: DragData ) => void } setDragData @param {Event } e */
104
- function handleDragLeave ( props , dragData , setDragData , e ) {
105
- if ( e . target !== dragData . dragTarget ) return ;
103
+ /** @param {ReportUploadBoxProps } props @param {import('preact/hooks').Ref< DragData> } dragTargetRef @param {(b: boolean ) => void } setIsDragging @param {Event } e */
104
+ function handleDragLeave ( props , dragTargetRef , setIsDragging , e ) {
105
+ if ( e . target !== dragTargetRef . current ) return ;
106
106
e . stopPropagation ( ) ;
107
107
e . preventDefault ( ) ;
108
- setDragData ( { isDragging : false , dragTarget : undefined } ) ;
108
+ setIsDragging ( false ) ;
109
+ dragTargetRef . current = undefined ;
109
110
}
110
111
111
- /** @param {ReportUploadBoxProps } props @param {DragData } dragData @param {(d: DragData ) => void } setDragData @param {Event } e */
112
- function handleDragOver ( props , dragData , setDragData , e ) {
113
- if ( ! dragData . dragTarget ) return ;
112
+ /** @param {ReportUploadBoxProps } props @param {import('preact/hooks').Ref< DragData> } dragTargetRef @param {(b: boolean ) => void } setIsDragging @param {Event } e */
113
+ function handleDragOver ( props , dragTargetRef , setIsDragging , e ) {
114
+ if ( ! dragTargetRef . current ) return ;
114
115
e . stopPropagation ( ) ;
115
116
e . preventDefault ( ) ;
116
117
}
117
118
118
- /** @param {Pick<ReportUploadBoxProps, 'addToast'|'setReport'> } props @param {DragData } dragData @param {(d: DragData ) => void } setDragData @param {Event } e */
119
- function handleDrop ( props , dragData , setDragData , e ) {
120
- if ( ! dragData . dragTarget ) return ;
119
+ /** @param {Pick<ReportUploadBoxProps, 'addToast'|'setReport'> } props @param {import('preact/hooks').Ref< DragData> } dragTargetRef @param {(b: boolean ) => void } setIsDragging @param {Event } e */
120
+ function handleDrop ( props , dragTargetRef , setIsDragging , e ) {
121
+ if ( ! dragTargetRef . current ) return ;
121
122
if ( ! ( e instanceof DragEvent ) ) return ;
122
123
if ( ! e . dataTransfer ) return ;
123
124
e . stopPropagation ( ) ;
124
125
e . preventDefault ( ) ;
125
- setDragData ( { isDragging : false , dragTarget : undefined } ) ;
126
+ setIsDragging ( false ) ;
127
+ dragTargetRef . current = undefined ;
126
128
handleFileInput ( props , e . dataTransfer . files ) ;
127
129
}
128
130
129
131
/** @param {ReportUploadBoxProps } props */
130
132
export const ReportUploadBox = props => {
131
- const [ dragData , setDragData ] = useState ( {
132
- isDragging : false ,
133
- dragTarget : /** @type {HTMLElement|undefined } */ ( undefined ) ,
134
- } ) ;
133
+ const [ isDragging , setIsDragging ] = useState ( false ) ;
134
+ const dragTargetRef = useRef ( /** @type {HTMLElement|undefined } */ ( undefined ) ) ;
135
+
136
+ /** @param {Event } e */
137
+ const onDragEnter = e => handleDragEnter ( props , dragTargetRef , setIsDragging , e ) ;
138
+ /** @param {Event } e */
139
+ const onDragLeave = e => handleDragLeave ( props , dragTargetRef , setIsDragging , e ) ;
140
+ /** @param {Event } e */
141
+ const onDragOver = e => handleDragOver ( props , dragTargetRef , setIsDragging , e ) ;
142
+ /** @param {Event } e */
143
+ const onDrop = e => handleDrop ( props , dragTargetRef , setIsDragging , e ) ;
135
144
136
145
useEffect ( ( ) => {
137
146
if ( props . dragTarget !== 'document' ) return ;
138
147
139
- /** @param {Event } e */
140
- const onDragEnter = e => handleDragEnter ( props , dragData , setDragData , e ) ;
141
- /** @param {Event } e */
142
- const onDragLeave = e => handleDragLeave ( props , dragData , setDragData , e ) ;
143
- /** @param {Event } e */
144
- const onDragOver = e => handleDragOver ( props , dragData , setDragData , e ) ;
145
- /** @param {Event } e */
146
- const onDrop = e => handleDrop ( props , dragData , setDragData , e ) ;
147
-
148
148
document . addEventListener ( 'dragenter' , onDragEnter ) ;
149
149
document . addEventListener ( 'dragleave' , onDragLeave ) ;
150
150
document . addEventListener ( 'dragover' , onDragOver ) ;
@@ -156,17 +156,18 @@ export const ReportUploadBox = props => {
156
156
document . removeEventListener ( 'dragover' , onDragOver ) ;
157
157
document . removeEventListener ( 'drop' , onDrop ) ;
158
158
} ;
159
- } , [ props . dragTarget , props . addToast , props . setReport , dragData , setDragData ] ) ;
159
+ } , [ props . dragTarget , props . addToast , props . setReport , dragTargetRef . current ] ) ;
160
160
161
161
return (
162
162
< div
163
163
className = { clsx ( `report-upload-box report-upload-box--${ props . variant } ` , {
164
- 'report-upload-box--drop' : dragData . isDragging ,
164
+ 'report-upload-box--drop' : isDragging ,
165
+ 'report-upload-box--document-target' : props . dragTarget === 'document' ,
165
166
} ) }
166
- onDragEnter = { e => handleDragEnter ( props , dragData , setDragData , e ) }
167
- onDragLeave = { e => handleDragLeave ( props , dragData , setDragData , e ) }
168
- onDragOver = { e => handleDragOver ( props , dragData , setDragData , e ) }
169
- onDrop = { e => handleDrop ( props , dragData , setDragData , e ) }
167
+ onDragEnter = { onDragEnter }
168
+ onDragLeave = { onDragLeave }
169
+ onDragOver = { onDragOver }
170
+ onDrop = { onDrop }
170
171
>
171
172
< div className = "report-upload-box__drop-outline" > Drop your report to upload</ div >
172
173
< span className = "report-upload-box__label" >
0 commit comments