@georapbox/files-dropzone-element 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -7
- package/dist/files-dropzone-defined.d.ts +3 -0
- package/dist/files-dropzone-defined.d.ts.map +1 -0
- package/dist/files-dropzone-defined.js +83 -1
- package/dist/files-dropzone-defined.js.map +1 -1
- package/dist/files-dropzone.d.ts +177 -0
- package/dist/files-dropzone.d.ts.map +1 -0
- package/dist/files-dropzone.js +83 -1
- package/dist/files-dropzone.js.map +1 -1
- package/dist/utils/files-selector.d.ts +2 -0
- package/dist/utils/files-selector.d.ts.map +1 -0
- package/dist/utils/is-valid-file.d.ts +9 -0
- package/dist/utils/is-valid-file.d.ts.map +1 -0
- package/package.json +13 -10
- package/src/files-dropzone.js +329 -137
- package/src/utils/files-selector.js +26 -18
- package/src/utils/is-valid-file.js +5 -3
package/src/files-dropzone.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a value that may be of type T, or null.
|
|
5
|
+
*
|
|
6
|
+
* @template T
|
|
7
|
+
* @typedef {T | null} Nullable
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
import { isValidFile } from './utils/is-valid-file.js';
|
|
2
11
|
import { getFilesFromEvent } from './utils/files-selector.js';
|
|
3
12
|
|
|
@@ -8,66 +17,83 @@ const FILE_TOO_SMALL = 'FILE_TOO_SMALL';
|
|
|
8
17
|
const INVALID_MIME_TYPE = 'INVALID_MIME_TYPE';
|
|
9
18
|
const template = document.createElement('template');
|
|
10
19
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
20
|
+
const styles = /* css */`
|
|
21
|
+
*,
|
|
22
|
+
*::before,
|
|
23
|
+
*::after {
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
}
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
:host([hidden]),
|
|
28
|
+
[hidden] {
|
|
29
|
+
display: none !important;
|
|
30
|
+
}
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
:host {
|
|
33
|
+
--dropzone-border-width: 2px;
|
|
34
|
+
--dropzone-border-style: dashed;
|
|
35
|
+
--dropzone-border-radius: 0.25rem;
|
|
36
|
+
--dropzone-border-color: #6c757d;
|
|
37
|
+
--dropzone-border-color-dragover: #0d6efd;
|
|
38
|
+
--dropzone-border-color-hover: var(--dropzone-border-color-dragover);
|
|
39
|
+
--dropzone-background-color: #ffffff;
|
|
40
|
+
--dropzone-background-color-dragover: #f4f4f5;
|
|
41
|
+
--dropzone-background-color-hover: var(--dropzone-background-color-dragover);
|
|
42
|
+
--dropzone-body-color: #3f3f46;
|
|
43
|
+
--dropzone-body-color-dragover: var(--dropzone-body-color);
|
|
44
|
+
--dropzone-body-color-hover: var(--dropzone-body-color-dragover);
|
|
45
|
+
--dropzone-focus-shadow-rgb: 49,132,253;
|
|
46
|
+
--dropzone-focus-box-shadow: 0 0 0 0.25rem rgba(var(--dropzone-focus-shadow-rgb), 0.5);
|
|
47
|
+
--transition-duration: 0.2s; /* for backwards compatibility */
|
|
48
|
+
--dropzone-transition-duration: var(--transition-duration);
|
|
49
|
+
|
|
50
|
+
display: block;
|
|
51
|
+
}
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
:host(:not([no-style])) .dropzone {
|
|
54
|
+
border: var(--dropzone-border-width) var(--dropzone-border-style) var(--dropzone-border-color);
|
|
55
|
+
border-radius: var(--dropzone-border-radius);
|
|
56
|
+
padding: 3rem 1rem;
|
|
57
|
+
overflow: hidden;
|
|
58
|
+
background-color: var(--dropzone-background-color);
|
|
59
|
+
color: var(--dropzone-body-color);
|
|
60
|
+
text-align: center;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
transition: border var(--dropzone-transition-duration) ease-in-out, background-color var(--dropzone-transition-duration) ease-in-out, color var(--dropzone-transition-duration) ease-in-out, box-shadow var(--dropzone-transition-duration) ease-in-out;
|
|
63
|
+
}
|
|
51
64
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
:host(:not([no-style])[no-click]) .dropzone {
|
|
66
|
+
cursor: default;
|
|
67
|
+
}
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
69
|
+
:host(:not([no-style])[disabled]) .dropzone {
|
|
70
|
+
opacity: 0.8;
|
|
71
|
+
cursor: not-allowed;
|
|
72
|
+
}
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
:host(:not([no-style]):not([disabled])) .dropzone--dragover {
|
|
75
|
+
border-color: var(--dropzone-border-color-dragover);
|
|
76
|
+
background-color: var(--dropzone-background-color-dragover);
|
|
77
|
+
color: var(--dropzone-body-color-dragover);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
:host(:not([no-style]):not([disabled])) .dropzone:focus-visible {
|
|
81
|
+
outline: none;
|
|
82
|
+
box-shadow: var(--dropzone-focus-box-shadow);
|
|
83
|
+
}
|
|
66
84
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
@media (hover: hover) {
|
|
86
|
+
:host(:not([no-style]):not([disabled])) .dropzone:not(.dropzone--dragover):hover {
|
|
87
|
+
border-color: var(--dropzone-border-color-hover);
|
|
88
|
+
background-color: var(--dropzone-background-color-hover);
|
|
89
|
+
color: var(--dropzone-body-color-hover);
|
|
70
90
|
}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
template.innerHTML = /* html */`
|
|
95
|
+
<style>
|
|
96
|
+
${styles}
|
|
71
97
|
</style>
|
|
72
98
|
|
|
73
99
|
<input type="file" id="fileInput" hidden>
|
|
@@ -77,26 +103,100 @@ template.innerHTML = /* html */`
|
|
|
77
103
|
</div>
|
|
78
104
|
`;
|
|
79
105
|
|
|
106
|
+
/**
|
|
107
|
+
* @summary A custom element that allows users to drag and drop files into it.
|
|
108
|
+
* @documentation https://github.com/georapbox/files-dropzone-element
|
|
109
|
+
*
|
|
110
|
+
* @tagname files-dropzone - This is the default tag name, unless overridden by the `defineCustomElement` method.
|
|
111
|
+
*
|
|
112
|
+
* @property {string} accept - A comma-separated list of unique file type specifiers describing file types to allow.
|
|
113
|
+
* @property {boolean} disabled - Determines whether the dropzone is disabled.
|
|
114
|
+
* @property {number} maxFiles - The maximum number of files allowed to be dropped.
|
|
115
|
+
* @property {number} maxSize - The maximum file size allowed in bytes.
|
|
116
|
+
* @property {number} minSize - The minimum file size allowed in bytes.
|
|
117
|
+
* @property {boolean} multiple - Allows multiple files to be dropped.
|
|
118
|
+
* @property {boolean} noClick - Prevents the file dialog from opening when the dropzone is clicked.
|
|
119
|
+
* @property {boolean} noDrag - Prevents the dropzone from reacting to drag events.
|
|
120
|
+
* @property {boolean} noKeyboard - Prevents the dropzone from reacting to keyboard events.
|
|
121
|
+
* @property {boolean} autoFocus - Automatically focuses the dropzone when it's connected to the DOM.
|
|
122
|
+
* @property {boolean} noStyle - Prevents the dropzone from applying any styling.
|
|
123
|
+
*
|
|
124
|
+
* @attribute {string} accept - Reflects the accept property.
|
|
125
|
+
* @attribute {boolean} disabled - Reflects the disabled property.
|
|
126
|
+
* @attribute {number} max-files - Reflects the maxFiles property.
|
|
127
|
+
* @attribute {number} max-size - Reflects the maxSize property.
|
|
128
|
+
* @attribute {number} min-size - Reflects the minSize property.
|
|
129
|
+
* @attribute {boolean} multiple - Reflects the multiple property.
|
|
130
|
+
* @attribute {boolean} no-click - Reflects the noClick property.
|
|
131
|
+
* @attribute {boolean} no-drag - Reflects the noDrag property.
|
|
132
|
+
* @attribute {boolean} no-keyboard - Reflects the noKeyboard property.
|
|
133
|
+
* @attribute {boolean} auto-focus - Reflects the autoFocus property.
|
|
134
|
+
* @attribute {boolean} no-style - Reflects the noStyle property.
|
|
135
|
+
*
|
|
136
|
+
* @slot - The default slot content of the dropzone.
|
|
137
|
+
*
|
|
138
|
+
* @csspart dropzone - The dropzone element.
|
|
139
|
+
* @csspart dropzone--dragover - The state of the dropzone when dragging over it.
|
|
140
|
+
*
|
|
141
|
+
* @cssproperty --dropzone-border-width - The border width of the dropzone.
|
|
142
|
+
* @cssproperty --dropzone-border-style - The border style of the dropzone.
|
|
143
|
+
* @cssproperty --dropzone-border-radius - The border radius of the dropzone.
|
|
144
|
+
* @cssproperty --dropzone-border-color - The border color of the dropzone.
|
|
145
|
+
* @cssproperty --dropzone-border-color-dragover - The border color of the dropzone when dragging over it.
|
|
146
|
+
* @cssproperty --dropzone-border-color-hover - The border color of the dropzone when hovering over it.
|
|
147
|
+
* @cssproperty --dropzone-background-color - The background color of the dropzone.
|
|
148
|
+
* @cssproperty --dropzone-background-color-dragover - The background color of the dropzone when dragging over it.
|
|
149
|
+
* @cssproperty --dropzone-background-color-hover - The background color of the dropzone when hovering over it.
|
|
150
|
+
* @cssproperty --dropzone-body-color - The text color of the dropzone.
|
|
151
|
+
* @cssproperty --dropzone-body-color-dragover - The text color of the dropzone when dragging over it.
|
|
152
|
+
* @cssproperty --dropzone-body-color-hover - The text color of the dropzone when hovering over it.
|
|
153
|
+
* @cssproperty --dropzone-focus-shadow-rgb - The RGB value of the dropzone's focus shadow.
|
|
154
|
+
* @cssproperty --dropzone-focus-box-shadow - The box shadow of the dropzone when focused.
|
|
155
|
+
* @cssproperty --dropzone-transition-duration - The transition's duration for the dropzone area.
|
|
156
|
+
*
|
|
157
|
+
* @event files-dropzone-drop - Fired when files are dropped.
|
|
158
|
+
* @event files-dropzone-drop-accepted - Fired when files dropped files are accepted.
|
|
159
|
+
* @event files-dropzone-drop-rejected - Fired when files dropped files are rejected.
|
|
160
|
+
* @event files-dropzone-dragenter - Fired when files are dragged into the dropzone.
|
|
161
|
+
* @event files-dropzone-dragover - Fired when files are dragged over the dropzone.
|
|
162
|
+
* @event files-dropzone-dragleave - Fired when files are dragged out of the dropzone.
|
|
163
|
+
* @event files-dropzone-error - Fired when there is any error in the process of reading dropped files or directories.
|
|
164
|
+
*
|
|
165
|
+
* @method defineCustomElement - Static method. Defines a custom element with the given name.
|
|
166
|
+
* @method openFileDialog - Instance method. Opens the file dialog programmatically.
|
|
167
|
+
*/
|
|
80
168
|
class FilesDropzone extends HTMLElement {
|
|
81
|
-
|
|
82
|
-
#
|
|
169
|
+
/** @type {Nullable<HTMLInputElement>} */
|
|
170
|
+
#fileInput = null;
|
|
171
|
+
|
|
172
|
+
/** @type {Nullable<HTMLElement>} */
|
|
173
|
+
#dropzoneEl = null;
|
|
83
174
|
|
|
84
175
|
constructor() {
|
|
85
176
|
super();
|
|
86
177
|
|
|
87
178
|
if (!this.shadowRoot) {
|
|
88
|
-
this.attachShadow({ mode: 'open' });
|
|
89
|
-
|
|
179
|
+
const shadowRoot = this.attachShadow({ mode: 'open' });
|
|
180
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
90
181
|
}
|
|
91
182
|
|
|
92
|
-
|
|
93
|
-
|
|
183
|
+
if (this.shadowRoot) {
|
|
184
|
+
this.#fileInput = /** @type {Nullable<HTMLInputElement>} */(this.shadowRoot.getElementById('fileInput'));
|
|
185
|
+
this.#dropzoneEl = this.shadowRoot.getElementById('dropzoneEl');
|
|
186
|
+
}
|
|
94
187
|
}
|
|
95
188
|
|
|
96
189
|
static get observedAttributes() {
|
|
97
190
|
return ['accept', 'disabled', 'multiple', 'no-keyboard'];
|
|
98
191
|
}
|
|
99
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Lifecycle method that is called when attributes are changed, added, removed, or replaced.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} name - The name of the attribute.
|
|
197
|
+
* @param {string} oldValue - The old value of the attribute.
|
|
198
|
+
* @param {string} newValue - The new value of the attribute.
|
|
199
|
+
*/
|
|
100
200
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
101
201
|
if (name === 'accept' && oldValue !== newValue && this.#fileInput) {
|
|
102
202
|
this.#fileInput.accept = this.accept;
|
|
@@ -106,9 +206,9 @@ class FilesDropzone extends HTMLElement {
|
|
|
106
206
|
this.#fileInput.disabled = this.disabled;
|
|
107
207
|
|
|
108
208
|
if (this.disabled) {
|
|
109
|
-
this.#dropzoneEl
|
|
209
|
+
this.#dropzoneEl?.removeAttribute('tabindex');
|
|
110
210
|
} else {
|
|
111
|
-
this.#dropzoneEl
|
|
211
|
+
this.#dropzoneEl?.setAttribute('tabindex', '0');
|
|
112
212
|
}
|
|
113
213
|
}
|
|
114
214
|
|
|
@@ -125,6 +225,9 @@ class FilesDropzone extends HTMLElement {
|
|
|
125
225
|
}
|
|
126
226
|
}
|
|
127
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Lifecycle method that is called when the element is added to the DOM.
|
|
230
|
+
*/
|
|
128
231
|
connectedCallback() {
|
|
129
232
|
this.#upgradeProperty('accept');
|
|
130
233
|
this.#upgradeProperty('disabled');
|
|
@@ -138,47 +241,60 @@ class FilesDropzone extends HTMLElement {
|
|
|
138
241
|
this.#upgradeProperty('autoFocus');
|
|
139
242
|
this.#upgradeProperty('noStyle');
|
|
140
243
|
|
|
141
|
-
this.#fileInput
|
|
142
|
-
this.#dropzoneEl
|
|
143
|
-
this.#dropzoneEl
|
|
144
|
-
this.#dropzoneEl
|
|
145
|
-
this.#dropzoneEl
|
|
146
|
-
this.#dropzoneEl
|
|
147
|
-
this.#dropzoneEl
|
|
244
|
+
this.#fileInput?.addEventListener('change', this.#handleFileInputChange);
|
|
245
|
+
this.#dropzoneEl?.addEventListener('dragenter', this.#handleDragEnter);
|
|
246
|
+
this.#dropzoneEl?.addEventListener('dragover', this.#handleDragOver);
|
|
247
|
+
this.#dropzoneEl?.addEventListener('dragleave', this.#handleDragLeave);
|
|
248
|
+
this.#dropzoneEl?.addEventListener('drop', this.#handleDrop);
|
|
249
|
+
this.#dropzoneEl?.addEventListener('click', this.#handleClick);
|
|
250
|
+
this.#dropzoneEl?.addEventListener('keyup', this.#handleKeyUp);
|
|
148
251
|
|
|
149
|
-
this.autoFocus && this.#dropzoneEl
|
|
252
|
+
this.autoFocus && this.#dropzoneEl?.focus();
|
|
150
253
|
}
|
|
151
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Lifecycle method that is called when the element is removed from the DOM.
|
|
257
|
+
*/
|
|
152
258
|
disconnectedCallback() {
|
|
153
|
-
this.#fileInput
|
|
154
|
-
this.#dropzoneEl
|
|
155
|
-
this.#dropzoneEl
|
|
156
|
-
this.#dropzoneEl
|
|
157
|
-
this.#dropzoneEl
|
|
158
|
-
this.#dropzoneEl
|
|
159
|
-
this.#dropzoneEl
|
|
259
|
+
this.#fileInput?.removeEventListener('change', this.#handleFileInputChange);
|
|
260
|
+
this.#dropzoneEl?.removeEventListener('dragenter', this.#handleDragEnter);
|
|
261
|
+
this.#dropzoneEl?.removeEventListener('dragover', this.#handleDragOver);
|
|
262
|
+
this.#dropzoneEl?.removeEventListener('dragleave', this.#handleDragLeave);
|
|
263
|
+
this.#dropzoneEl?.removeEventListener('drop', this.#handleDrop);
|
|
264
|
+
this.#dropzoneEl?.removeEventListener('click', this.#handleClick);
|
|
265
|
+
this.#dropzoneEl?.removeEventListener('keyup', this.#handleKeyUp);
|
|
160
266
|
}
|
|
161
267
|
|
|
268
|
+
/**
|
|
269
|
+
* @type {string} - A comma-separated list of unique file type specifiers describing file types to allow.
|
|
270
|
+
* @attribute accept - Reflects the accept property.
|
|
271
|
+
*/
|
|
162
272
|
get accept() {
|
|
163
|
-
return this.getAttribute('accept');
|
|
273
|
+
return this.getAttribute('accept') || '';
|
|
164
274
|
}
|
|
165
275
|
|
|
166
276
|
set accept(value) {
|
|
167
|
-
this.setAttribute('accept', value);
|
|
277
|
+
this.setAttribute('accept', value != null ? value.toString() : value);
|
|
168
278
|
}
|
|
169
279
|
|
|
280
|
+
/**
|
|
281
|
+
* @type {boolean} - Determines whether the dropzone is disabled.
|
|
282
|
+
* @default false
|
|
283
|
+
* @attribute disabled - Reflects the disabled property.
|
|
284
|
+
*/
|
|
170
285
|
get disabled() {
|
|
171
286
|
return this.hasAttribute('disabled');
|
|
172
287
|
}
|
|
173
288
|
|
|
174
289
|
set disabled(value) {
|
|
175
|
-
|
|
176
|
-
this.setAttribute('disabled', '');
|
|
177
|
-
} else {
|
|
178
|
-
this.removeAttribute('disabled');
|
|
179
|
-
}
|
|
290
|
+
this.toggleAttribute('disabled', !!value);
|
|
180
291
|
}
|
|
181
292
|
|
|
293
|
+
/**
|
|
294
|
+
* @type {number} - The maximum number of files allowed to be dropped.
|
|
295
|
+
* @default Infinity
|
|
296
|
+
* @attribute max-files - Reflects the maxFiles property.
|
|
297
|
+
*/
|
|
182
298
|
get maxFiles() {
|
|
183
299
|
const num = Number(this.getAttribute('max-files')) || 0;
|
|
184
300
|
|
|
@@ -190,9 +306,14 @@ class FilesDropzone extends HTMLElement {
|
|
|
190
306
|
}
|
|
191
307
|
|
|
192
308
|
set maxFiles(value) {
|
|
193
|
-
this.setAttribute('max-files', value);
|
|
309
|
+
this.setAttribute('max-files', value != null ? value.toString() : value);
|
|
194
310
|
}
|
|
195
311
|
|
|
312
|
+
/**
|
|
313
|
+
* @type {number} - The maximum file size allowed in bytes.
|
|
314
|
+
* @default Infinity
|
|
315
|
+
* @attribute max-size - Reflects the maxSize property.
|
|
316
|
+
*/
|
|
196
317
|
get maxSize() {
|
|
197
318
|
const value = this.getAttribute('max-size');
|
|
198
319
|
|
|
@@ -206,9 +327,14 @@ class FilesDropzone extends HTMLElement {
|
|
|
206
327
|
}
|
|
207
328
|
|
|
208
329
|
set maxSize(value) {
|
|
209
|
-
this.setAttribute('max-size', value);
|
|
330
|
+
this.setAttribute('max-size', value != null ? value.toString() : value);
|
|
210
331
|
}
|
|
211
332
|
|
|
333
|
+
/**
|
|
334
|
+
* @type {number} - The minimum file size allowed in bytes.
|
|
335
|
+
* @default 0
|
|
336
|
+
* @attribute min-size - Reflects the minSize property.
|
|
337
|
+
*/
|
|
212
338
|
get minSize() {
|
|
213
339
|
const value = this.getAttribute('min-size');
|
|
214
340
|
|
|
@@ -222,82 +348,93 @@ class FilesDropzone extends HTMLElement {
|
|
|
222
348
|
}
|
|
223
349
|
|
|
224
350
|
set minSize(value) {
|
|
225
|
-
this.setAttribute('min-size', value);
|
|
351
|
+
this.setAttribute('min-size', value != null ? value.toString() : value);
|
|
226
352
|
}
|
|
227
353
|
|
|
354
|
+
/**
|
|
355
|
+
* @type {boolean} - Allows multiple files to be dropped.
|
|
356
|
+
* @default false
|
|
357
|
+
* @attribute multiple - Reflects the multiple property.
|
|
358
|
+
*/
|
|
228
359
|
get multiple() {
|
|
229
360
|
return this.hasAttribute('multiple');
|
|
230
361
|
}
|
|
231
362
|
|
|
232
363
|
set multiple(value) {
|
|
233
|
-
|
|
234
|
-
this.setAttribute('multiple', '');
|
|
235
|
-
} else {
|
|
236
|
-
this.removeAttribute('multiple');
|
|
237
|
-
}
|
|
364
|
+
this.toggleAttribute('multiple', !!value);
|
|
238
365
|
}
|
|
239
366
|
|
|
367
|
+
/**
|
|
368
|
+
* @type {boolean} - Prevents the file dialog from opening when the dropzone is clicked.
|
|
369
|
+
* @default false
|
|
370
|
+
* @attribute no-click - Reflects the noClick property.
|
|
371
|
+
*/
|
|
240
372
|
get noClick() {
|
|
241
373
|
return this.hasAttribute('no-click');
|
|
242
374
|
}
|
|
243
375
|
|
|
244
376
|
set noClick(value) {
|
|
245
|
-
|
|
246
|
-
this.setAttribute('no-click', '');
|
|
247
|
-
} else {
|
|
248
|
-
this.removeAttribute('no-click');
|
|
249
|
-
}
|
|
377
|
+
this.toggleAttribute('no-click', !!value);
|
|
250
378
|
}
|
|
251
379
|
|
|
380
|
+
/**
|
|
381
|
+
* @type {boolean} - Prevents the dropzone from reacting to drag events.
|
|
382
|
+
* @default false
|
|
383
|
+
* @attribute no-drag - Reflects the noDrag property.
|
|
384
|
+
*/
|
|
252
385
|
get noDrag() {
|
|
253
386
|
return this.hasAttribute('no-drag');
|
|
254
387
|
}
|
|
255
388
|
|
|
256
389
|
set noDrag(value) {
|
|
257
|
-
|
|
258
|
-
this.setAttribute('no-drag', '');
|
|
259
|
-
} else {
|
|
260
|
-
this.removeAttribute('no-drag');
|
|
261
|
-
}
|
|
390
|
+
this.toggleAttribute('no-drag', !!value);
|
|
262
391
|
}
|
|
263
392
|
|
|
393
|
+
/**
|
|
394
|
+
* @type {boolean} - Prevents the dropzone from reacting to keyboard events.
|
|
395
|
+
* @default false
|
|
396
|
+
* @attribute no-keyboard - Reflects the noKeyboard property.
|
|
397
|
+
*/
|
|
264
398
|
get noKeyboard() {
|
|
265
399
|
return this.hasAttribute('no-keyboard');
|
|
266
400
|
}
|
|
267
401
|
|
|
268
402
|
set noKeyboard(value) {
|
|
269
|
-
|
|
270
|
-
this.setAttribute('no-keyboard', '');
|
|
271
|
-
} else {
|
|
272
|
-
this.removeAttribute('no-keyboard');
|
|
273
|
-
}
|
|
403
|
+
this.toggleAttribute('no-keyboard', !!value);
|
|
274
404
|
}
|
|
275
405
|
|
|
406
|
+
/**
|
|
407
|
+
* @type {boolean} - Automatically focuses the dropzone when it's connected to the DOM.
|
|
408
|
+
* @default false
|
|
409
|
+
* @attribute auto-focus - Reflects the autoFocus property.
|
|
410
|
+
*/
|
|
276
411
|
get autoFocus() {
|
|
277
412
|
return this.hasAttribute('auto-focus');
|
|
278
413
|
}
|
|
279
414
|
|
|
280
415
|
set autoFocus(value) {
|
|
281
|
-
|
|
282
|
-
this.setAttribute('auto-focus', '');
|
|
283
|
-
} else {
|
|
284
|
-
this.removeAttribute('auto-focus');
|
|
285
|
-
}
|
|
416
|
+
this.toggleAttribute('auto-focus', !!value);
|
|
286
417
|
}
|
|
287
418
|
|
|
419
|
+
/**
|
|
420
|
+
* @type {boolean} - Prevents the dropzone from applying any styling.
|
|
421
|
+
* @default false
|
|
422
|
+
* @attribute no-style - Reflects the noStyle property.
|
|
423
|
+
*/
|
|
288
424
|
get noStyle() {
|
|
289
425
|
return this.hasAttribute('no-style');
|
|
290
426
|
}
|
|
291
427
|
|
|
292
428
|
set noStyle(value) {
|
|
293
|
-
|
|
294
|
-
this.setAttribute('no-style', '');
|
|
295
|
-
} else {
|
|
296
|
-
this.removeAttribute('no-style');
|
|
297
|
-
}
|
|
429
|
+
this.toggleAttribute('no-style', !!value);
|
|
298
430
|
}
|
|
299
431
|
|
|
300
|
-
|
|
432
|
+
/**
|
|
433
|
+
* Handles the change event of the file input.
|
|
434
|
+
*
|
|
435
|
+
* @param {*} evt - The event object.
|
|
436
|
+
*/
|
|
437
|
+
#handleFileInputChange = async evt => {
|
|
301
438
|
try {
|
|
302
439
|
this.#handleFilesSelect(await getFilesFromEvent(evt));
|
|
303
440
|
} catch (error) {
|
|
@@ -309,7 +446,10 @@ class FilesDropzone extends HTMLElement {
|
|
|
309
446
|
}
|
|
310
447
|
};
|
|
311
448
|
|
|
312
|
-
|
|
449
|
+
/**
|
|
450
|
+
* Handles the dragenter event of the dropzone.
|
|
451
|
+
*/
|
|
452
|
+
#handleDragEnter = () => {
|
|
313
453
|
if (this.disabled || this.noDrag) {
|
|
314
454
|
return;
|
|
315
455
|
}
|
|
@@ -320,7 +460,12 @@ class FilesDropzone extends HTMLElement {
|
|
|
320
460
|
}));
|
|
321
461
|
};
|
|
322
462
|
|
|
323
|
-
|
|
463
|
+
/**
|
|
464
|
+
* Handles the dragover event of the dropzone.
|
|
465
|
+
*
|
|
466
|
+
* @param {*} evt - The event object.
|
|
467
|
+
*/
|
|
468
|
+
#handleDragOver = evt => {
|
|
324
469
|
evt.preventDefault();
|
|
325
470
|
|
|
326
471
|
if (this.disabled || this.noDrag) {
|
|
@@ -330,8 +475,10 @@ class FilesDropzone extends HTMLElement {
|
|
|
330
475
|
|
|
331
476
|
evt.dataTransfer.dropEffect = 'copy';
|
|
332
477
|
|
|
333
|
-
this.#dropzoneEl
|
|
334
|
-
|
|
478
|
+
if (this.#dropzoneEl) {
|
|
479
|
+
this.#dropzoneEl.classList.add('dropzone--dragover');
|
|
480
|
+
this.#dropzoneEl.part.add('dropzone--dragover');
|
|
481
|
+
}
|
|
335
482
|
|
|
336
483
|
this.dispatchEvent(new Event(`${COMPONENT_NAME}-dragover`, {
|
|
337
484
|
bubbles: true,
|
|
@@ -339,13 +486,18 @@ class FilesDropzone extends HTMLElement {
|
|
|
339
486
|
}));
|
|
340
487
|
};
|
|
341
488
|
|
|
342
|
-
|
|
489
|
+
/**
|
|
490
|
+
* Handles the dragleave event of the dropzone.
|
|
491
|
+
*/
|
|
492
|
+
#handleDragLeave = () => {
|
|
343
493
|
if (this.disabled || this.noDrag) {
|
|
344
494
|
return;
|
|
345
495
|
}
|
|
346
496
|
|
|
347
|
-
this.#dropzoneEl
|
|
348
|
-
|
|
497
|
+
if (this.#dropzoneEl) {
|
|
498
|
+
this.#dropzoneEl.classList.remove('dropzone--dragover');
|
|
499
|
+
this.#dropzoneEl.part.remove('dropzone--dragover');
|
|
500
|
+
}
|
|
349
501
|
|
|
350
502
|
this.dispatchEvent(new Event(`${COMPONENT_NAME}-dragleave`, {
|
|
351
503
|
bubbles: true,
|
|
@@ -353,15 +505,22 @@ class FilesDropzone extends HTMLElement {
|
|
|
353
505
|
}));
|
|
354
506
|
};
|
|
355
507
|
|
|
356
|
-
|
|
508
|
+
/**
|
|
509
|
+
* Handles the drop event of the dropzone.
|
|
510
|
+
*
|
|
511
|
+
* @param {*} evt - The event object.
|
|
512
|
+
*/
|
|
513
|
+
#handleDrop = async evt => {
|
|
357
514
|
if (this.disabled || this.noDrag) {
|
|
358
515
|
return;
|
|
359
516
|
}
|
|
360
517
|
|
|
361
518
|
evt.preventDefault();
|
|
362
519
|
|
|
363
|
-
this.#dropzoneEl
|
|
364
|
-
|
|
520
|
+
if (this.#dropzoneEl) {
|
|
521
|
+
this.#dropzoneEl.classList.remove('dropzone--dragover');
|
|
522
|
+
this.#dropzoneEl.part.remove('dropzone--dragover');
|
|
523
|
+
}
|
|
365
524
|
|
|
366
525
|
try {
|
|
367
526
|
this.#handleFilesSelect(await getFilesFromEvent(evt));
|
|
@@ -374,24 +533,37 @@ class FilesDropzone extends HTMLElement {
|
|
|
374
533
|
}
|
|
375
534
|
};
|
|
376
535
|
|
|
377
|
-
|
|
536
|
+
/**
|
|
537
|
+
* Handles the click event of the dropzone.
|
|
538
|
+
*/
|
|
539
|
+
#handleClick = () => {
|
|
378
540
|
if (this.disabled || this.noClick) {
|
|
379
541
|
return;
|
|
380
542
|
}
|
|
381
543
|
|
|
382
|
-
this.#fileInput
|
|
544
|
+
this.#fileInput?.click();
|
|
383
545
|
};
|
|
384
546
|
|
|
385
|
-
|
|
547
|
+
/**
|
|
548
|
+
* Handles the keyup event of the dropzone.
|
|
549
|
+
*
|
|
550
|
+
* @param {*} evt - The event object.
|
|
551
|
+
*/
|
|
552
|
+
#handleKeyUp = evt => {
|
|
386
553
|
if (this.disabled || this.noKeyboard) {
|
|
387
554
|
return;
|
|
388
555
|
}
|
|
389
556
|
|
|
390
557
|
if (evt.key === ' ' || evt.key === 'Enter') {
|
|
391
|
-
this.#fileInput
|
|
558
|
+
this.#fileInput?.click();
|
|
392
559
|
}
|
|
393
560
|
};
|
|
394
561
|
|
|
562
|
+
/**
|
|
563
|
+
* Handles the selection of files.
|
|
564
|
+
*
|
|
565
|
+
* @param {File[]} files - The files to handle.
|
|
566
|
+
*/
|
|
395
567
|
#handleFilesSelect(files) {
|
|
396
568
|
if (!Array.isArray(files) || !files.length) {
|
|
397
569
|
return;
|
|
@@ -492,31 +664,51 @@ class FilesDropzone extends HTMLElement {
|
|
|
492
664
|
}));
|
|
493
665
|
}
|
|
494
666
|
|
|
495
|
-
this.#fileInput
|
|
667
|
+
if (this.#fileInput) {
|
|
668
|
+
this.#fileInput.value = this.#fileInput.defaultValue;
|
|
669
|
+
}
|
|
496
670
|
}
|
|
497
671
|
|
|
672
|
+
/**
|
|
673
|
+
* Opens the file dialog programmatically.
|
|
674
|
+
*/
|
|
498
675
|
openFileDialog() {
|
|
499
676
|
if (this.disabled) {
|
|
500
677
|
return;
|
|
501
678
|
}
|
|
502
679
|
|
|
503
|
-
this.#fileInput
|
|
680
|
+
this.#fileInput?.click();
|
|
504
681
|
}
|
|
505
682
|
|
|
506
683
|
/**
|
|
507
|
-
* https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
|
|
508
684
|
* This is to safe guard against cases where, for instance, a framework may have added the element to the page and set a
|
|
509
685
|
* value on one of its properties, but lazy loaded its definition. Without this guard, the upgraded element would miss that
|
|
510
686
|
* property and the instance property would prevent the class property setter from ever being called.
|
|
687
|
+
*
|
|
688
|
+
* https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
|
|
689
|
+
*
|
|
690
|
+
* @param {'accept' | 'disabled' | 'maxFiles' | 'maxSize' | 'minSize' | 'multiple' | 'noClick' | 'noDrag' | 'noKeyboard' | 'autoFocus' | 'noStyle'} prop - The property name to upgrade.
|
|
511
691
|
*/
|
|
512
692
|
#upgradeProperty(prop) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
693
|
+
/** @type {any} */
|
|
694
|
+
const instance = this;
|
|
695
|
+
|
|
696
|
+
if (Object.prototype.hasOwnProperty.call(instance, prop)) {
|
|
697
|
+
const value = instance[prop];
|
|
698
|
+
delete instance[prop];
|
|
699
|
+
instance[prop] = value;
|
|
517
700
|
}
|
|
518
701
|
}
|
|
519
702
|
|
|
703
|
+
/**
|
|
704
|
+
* Defines a custom element with the given name.
|
|
705
|
+
* The name must contain a dash (-).
|
|
706
|
+
*
|
|
707
|
+
* @param {string} [elementName='files-dropzone'] - The name of the custom element.
|
|
708
|
+
* @example
|
|
709
|
+
*
|
|
710
|
+
* FilesDropzone.defineCustomElement('my-dropzone');
|
|
711
|
+
*/
|
|
520
712
|
static defineCustomElement(elementName = COMPONENT_NAME) {
|
|
521
713
|
if (typeof window !== 'undefined' && !window.customElements.get(elementName)) {
|
|
522
714
|
window.customElements.define(elementName, FilesDropzone);
|