1
1
// @ts -check
2
2
import { ActivityBlock } from './ActivityBlock.js' ;
3
3
4
- import { Data } from '@symbiotejs/symbiote' ;
4
+ import { applyStyles , Data } from '@symbiotejs/symbiote' ;
5
5
import { EventType } from '../blocks/UploadCtxProvider/EventEmitter.js' ;
6
6
import { UploadSource } from '../blocks/utils/UploadSource.js' ;
7
7
import { serializeCsv } from '../blocks/utils/comma-separated.js' ;
@@ -138,7 +138,9 @@ export class UploaderPublicApi {
138
138
139
139
/** @param {{ captureCamera?: boolean } } options */
140
140
openSystemDialog = ( options = { } ) => {
141
- let accept = serializeCsv ( mergeFileTypes ( [ this . cfg . accept ?? '' , ...( this . cfg . imgOnly ? IMAGE_ACCEPT_LIST : [ ] ) ] ) ) ;
141
+ const accept = serializeCsv (
142
+ mergeFileTypes ( [ this . cfg . accept ?? '' , ...( this . cfg . imgOnly ? IMAGE_ACCEPT_LIST : [ ] ) ] ) ,
143
+ ) ;
142
144
143
145
if ( this . cfg . accept && ! ! this . cfg . imgOnly ) {
144
146
console . warn (
@@ -147,7 +149,16 @@ export class UploaderPublicApi {
147
149
'The value of `accept` will be concatenated with the internal image mime types list.' ,
148
150
) ;
149
151
}
152
+
153
+ const INPUT_ATTR_NAME = 'uploadcare-file-input' ;
150
154
const fileInput = document . createElement ( 'input' ) ;
155
+ fileInput . setAttribute ( INPUT_ATTR_NAME , '' ) ;
156
+ applyStyles ( fileInput , {
157
+ opacity : 0 ,
158
+ height : 0 ,
159
+ width : 0 ,
160
+ visibility : 'hidden' ,
161
+ } ) ;
151
162
fileInput . type = 'file' ;
152
163
fileInput . multiple = this . cfg . multiple ;
153
164
if ( options . captureCamera ) {
@@ -156,18 +167,33 @@ export class UploaderPublicApi {
156
167
} else {
157
168
fileInput . accept = accept ;
158
169
}
170
+ fileInput . addEventListener (
171
+ 'change' ,
172
+ ( ) => {
173
+ if ( ! fileInput . files ) {
174
+ return ;
175
+ }
176
+ [ ...fileInput . files ] . forEach ( ( file ) =>
177
+ this . addFileFromObject ( file , { source : options . captureCamera ? UploadSource . CAMERA : UploadSource . LOCAL } ) ,
178
+ ) ;
179
+ // To call uploadTrigger UploadList should draw file items first:
180
+ this . _ctx . $ [ '*currentActivity' ] = ActivityBlock . activities . UPLOAD_LIST ;
181
+ this . _ctx . setOrAddState ( '*modalActive' , true ) ;
182
+ fileInput . remove ( ) ;
183
+ } ,
184
+ {
185
+ once : true ,
186
+ } ,
187
+ ) ;
188
+
189
+ document . querySelectorAll ( `[${ INPUT_ATTR_NAME } ]` ) . forEach ( ( el ) => el . remove ( ) ) ;
190
+
191
+ /**
192
+ * Some browsers (e.g. Safari) require the file input to be in the DOM to work properly. Without it the file input
193
+ * will open system dialog but won't trigger the change event sometimes.
194
+ */
195
+ document . body . appendChild ( fileInput ) ;
159
196
fileInput . dispatchEvent ( new MouseEvent ( 'click' ) ) ;
160
- fileInput . onchange = ( ) => {
161
- // @ts -ignore TODO: fix this
162
- [ ...fileInput [ 'files' ] ] . forEach ( ( file ) =>
163
- this . addFileFromObject ( file , { source : options . captureCamera ? UploadSource . CAMERA : UploadSource . LOCAL } ) ,
164
- ) ;
165
- // To call uploadTrigger UploadList should draw file items first:
166
- this . _ctx . $ [ '*currentActivity' ] = ActivityBlock . activities . UPLOAD_LIST ;
167
- this . _ctx . setOrAddState ( '*modalActive' , true ) ;
168
- // @ts -ignore TODO: fix this
169
- fileInput [ 'value' ] = '' ;
170
- } ;
171
197
} ;
172
198
173
199
/**
0 commit comments