@umbraco-ui/uui-file-dropzone 1.17.0-rc.4 → 1.17.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.
@@ -62,7 +62,11 @@
62
62
  "events": [
63
63
  {
64
64
  "name": "change",
65
- "description": "fires when the a file has been selected."
65
+ "description": "fires when a file has been selected."
66
+ },
67
+ {
68
+ "name": "reject",
69
+ "description": "fires when files are rejected due to not matching the accept attribute."
66
70
  }
67
71
  ],
68
72
  "slots": [
@@ -5,5 +5,6 @@ export declare class UUIFileDropzoneEvent extends UUIEvent<{
5
5
  folders: UUIFileFolder[];
6
6
  }, UUIFileDropzoneElement> {
7
7
  static readonly CHANGE: string;
8
+ static readonly REJECT: string;
8
9
  constructor(evName: string, eventInit?: any | null);
9
10
  }
package/lib/index.js CHANGED
@@ -9,6 +9,9 @@ class UUIFileDropzoneEvent extends UUIEvent {
9
9
  static {
10
10
  this.CHANGE = "change";
11
11
  }
12
+ static {
13
+ this.REJECT = "reject";
14
+ }
12
15
  constructor(evName, eventInit = {}) {
13
16
  super(evName, {
14
17
  ...{ bubbles: true },
@@ -72,26 +75,45 @@ let UUIFileDropzoneElement = class extends LabelMixin("", LitElement) {
72
75
  browse() {
73
76
  this._input.click();
74
77
  }
78
+ /**
79
+ * Process a single file entry and categorize it as accepted or rejected.
80
+ * @param entry - The data transfer item containing the file
81
+ * @param files - Array to store accepted files
82
+ * @param rejectedFiles - Array to store rejected files
83
+ */
84
+ _processFileEntry(entry, files, rejectedFiles) {
85
+ const file = entry.getAsFile();
86
+ if (!file) return;
87
+ if (this._isAccepted(file)) {
88
+ files.push(file);
89
+ } else {
90
+ rejectedFiles.push(file);
91
+ }
92
+ }
93
+ /**
94
+ * Check if folder upload should be processed based on component settings.
95
+ * @returns true if folder upload is allowed and multiple files are enabled
96
+ */
97
+ _shouldProcessFolder() {
98
+ return !this.disallowFolderUpload && this.multiple;
99
+ }
75
100
  async _getAllEntries(dataTransferItemList) {
76
101
  const queue = [...dataTransferItemList];
77
102
  const folders = [];
78
103
  const files = [];
104
+ const rejectedFiles = [];
79
105
  for (const entry of queue) {
80
106
  if (entry?.kind !== "file") continue;
81
107
  const fileEntry = this._getEntry(entry);
82
108
  if (!fileEntry) continue;
83
109
  if (!fileEntry.isDirectory) {
84
- const file = entry.getAsFile();
85
- if (!file) continue;
86
- if (this._isAccepted(file)) {
87
- files.push(file);
88
- }
89
- } else if (!this.disallowFolderUpload && this.multiple) {
110
+ this._processFileEntry(entry, files, rejectedFiles);
111
+ } else if (this._shouldProcessFolder()) {
90
112
  const structure = await this._mkdir(fileEntry);
91
113
  folders.push(structure);
92
114
  }
93
115
  }
94
- return { files, folders };
116
+ return { files, folders, rejectedFiles };
95
117
  }
96
118
  /**
97
119
  * Get the directory entry from a DataTransferItem.
@@ -106,37 +128,40 @@ let UUIFileDropzoneElement = class extends LabelMixin("", LitElement) {
106
128
  }
107
129
  return dir;
108
130
  }
131
+ // Process entries from a directory reader
132
+ async _processEntries(entries, folders, files) {
133
+ for (const en of entries) {
134
+ if (en.isFile) {
135
+ const file = await this._getAsFile(en);
136
+ if (this._isAccepted(file)) {
137
+ files.push(file);
138
+ }
139
+ } else if (en.isDirectory) {
140
+ const directory = await this._mkdir(en);
141
+ folders.push(directory);
142
+ }
143
+ }
144
+ }
145
+ // Read entries from a directory reader recursively
146
+ async _readAllEntries(reader, folders, files) {
147
+ return new Promise((resolve, reject) => {
148
+ reader.readEntries(async (entries) => {
149
+ if (!entries.length) {
150
+ resolve();
151
+ return;
152
+ }
153
+ await this._processEntries(entries, folders, files);
154
+ await this._readAllEntries(reader, folders, files);
155
+ resolve();
156
+ }, reject);
157
+ });
158
+ }
109
159
  // Make directory structure
110
160
  async _mkdir(entry) {
111
161
  const reader = entry.createReader();
112
162
  const folders = [];
113
163
  const files = [];
114
- const readEntries = (reader2) => {
115
- return new Promise((resolve, reject) => {
116
- reader2.readEntries(async (entries) => {
117
- if (!entries.length) {
118
- resolve();
119
- return;
120
- }
121
- for (const en of entries) {
122
- if (en.isFile) {
123
- const file = await this._getAsFile(en);
124
- if (this._isAccepted(file)) {
125
- files.push(file);
126
- }
127
- } else if (en.isDirectory) {
128
- const directory = await this._mkdir(
129
- en
130
- );
131
- folders.push(directory);
132
- }
133
- }
134
- await readEntries(reader2);
135
- resolve();
136
- }, reject);
137
- });
138
- };
139
- await readEntries(reader);
164
+ await this._readAllEntries(reader, folders, files);
140
165
  const result = { folderName: entry.name, folders, files };
141
166
  return result;
142
167
  }
@@ -170,13 +195,24 @@ let UUIFileDropzoneElement = class extends LabelMixin("", LitElement) {
170
195
  if (this.multiple === false && fileSystemResult.files.length) {
171
196
  fileSystemResult.files = [fileSystemResult.files[0]];
172
197
  fileSystemResult.folders = [];
198
+ fileSystemResult.rejectedFiles = [];
199
+ }
200
+ if (fileSystemResult.rejectedFiles.length > 0) {
201
+ this.dispatchEvent(
202
+ new UUIFileDropzoneEvent(UUIFileDropzoneEvent.REJECT, {
203
+ detail: { files: fileSystemResult.rejectedFiles, folders: [] }
204
+ })
205
+ );
173
206
  }
174
207
  if (!fileSystemResult.files.length && !fileSystemResult.folders.length) {
175
208
  return;
176
209
  }
177
210
  this.dispatchEvent(
178
211
  new UUIFileDropzoneEvent(UUIFileDropzoneEvent.CHANGE, {
179
- detail: fileSystemResult
212
+ detail: {
213
+ files: fileSystemResult.files,
214
+ folders: fileSystemResult.folders
215
+ }
180
216
  })
181
217
  );
182
218
  }
@@ -198,12 +234,24 @@ let UUIFileDropzoneElement = class extends LabelMixin("", LitElement) {
198
234
  files.splice(1, files.length - 1);
199
235
  }
200
236
  const allowedFiles = files.filter((file) => this._isAccepted(file));
237
+ const rejectedFiles = files.filter((file) => !this._isAccepted(file));
238
+ const shouldReportRejections = rejectedFiles.length > 0 && (this.multiple || allowedFiles.length === 0);
239
+ if (shouldReportRejections) {
240
+ this.dispatchEvent(
241
+ new UUIFileDropzoneEvent(UUIFileDropzoneEvent.REJECT, {
242
+ detail: { files: rejectedFiles, folders: [] }
243
+ })
244
+ );
245
+ }
201
246
  if (!allowedFiles.length) {
202
247
  return;
203
248
  }
204
249
  this.dispatchEvent(
205
250
  new UUIFileDropzoneEvent(UUIFileDropzoneEvent.CHANGE, {
206
- detail: { files: allowedFiles, folders: [] }
251
+ detail: {
252
+ files: allowedFiles,
253
+ folders: []
254
+ }
207
255
  })
208
256
  );
209
257
  }
@@ -8,7 +8,8 @@ export interface UUIFileFolder {
8
8
  declare const UUIFileDropzoneElement_base: (new (...args: any[]) => import("@umbraco-ui/uui-base/lib/mixins").LabelMixinInterface) & typeof LitElement;
9
9
  /**
10
10
  * @element uui-file-dropzone
11
- * @fires {UUIFileDropzoneEvent} change - fires when the a file has been selected.
11
+ * @fires {UUIFileDropzoneEvent} change - fires when a file has been selected.
12
+ * @fires {UUIFileDropzoneEvent} reject - fires when files are rejected due to not matching the accept attribute.
12
13
  * @slot - For the content of the dropzone
13
14
  * @description - Dropzone for file upload. Supports native browsing and drag n drop.
14
15
  */
@@ -45,12 +46,26 @@ export declare class UUIFileDropzoneElement extends UUIFileDropzoneElement_base
45
46
  */
46
47
  browse(): void;
47
48
  constructor();
49
+ /**
50
+ * Process a single file entry and categorize it as accepted or rejected.
51
+ * @param entry - The data transfer item containing the file
52
+ * @param files - Array to store accepted files
53
+ * @param rejectedFiles - Array to store rejected files
54
+ */
55
+ private _processFileEntry;
56
+ /**
57
+ * Check if folder upload should be processed based on component settings.
58
+ * @returns true if folder upload is allowed and multiple files are enabled
59
+ */
60
+ private _shouldProcessFolder;
48
61
  private _getAllEntries;
49
62
  /**
50
63
  * Get the directory entry from a DataTransferItem.
51
64
  * @remark Supports both WebKit and non-WebKit browsers.
52
65
  */
53
66
  private _getEntry;
67
+ private _processEntries;
68
+ private _readAllEntries;
54
69
  private _mkdir;
55
70
  private _isAccepted;
56
71
  private _getAsFile;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umbraco-ui/uui-file-dropzone",
3
- "version": "1.17.0-rc.4",
3
+ "version": "1.17.0",
4
4
  "license": "MIT",
5
5
  "keywords": [
6
6
  "Umbraco",
@@ -30,8 +30,8 @@
30
30
  "custom-elements.json"
31
31
  ],
32
32
  "dependencies": {
33
- "@umbraco-ui/uui-base": "1.17.0-rc.4",
34
- "@umbraco-ui/uui-symbol-file-dropzone": "1.17.0-rc.4"
33
+ "@umbraco-ui/uui-base": "1.17.0",
34
+ "@umbraco-ui/uui-symbol-file-dropzone": "1.17.0"
35
35
  },
36
36
  "scripts": {
37
37
  "build": "npm run analyze && tsc --build && rollup -c rollup.config.js",
@@ -42,5 +42,5 @@
42
42
  "access": "public"
43
43
  },
44
44
  "homepage": "https://uui.umbraco.com/?path=/story/uui-file-dropzone",
45
- "gitHead": "a4a929fa86b765eff039d33969e4117f493aaa29"
45
+ "gitHead": "7d602fc76ed33f3100ead94a01e1d6f1eedf0f5e"
46
46
  }