@destyler/file-upload 0.0.7-beta.7 → 0.0.7-beta.9

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/dist/index.cjs DELETED
@@ -1,580 +0,0 @@
1
- 'use strict';
2
-
3
- const anatomy$1 = require('@zag-js/anatomy');
4
- const domQuery = require('@zag-js/dom-query');
5
- const i18nUtils = require('@zag-js/i18n-utils');
6
- const fileUtils = require('@zag-js/file-utils');
7
- const core = require('@zag-js/core');
8
- const utils = require('@zag-js/utils');
9
- const types = require('@zag-js/types');
10
-
11
- const anatomy = anatomy$1.createAnatomy("file-upload").parts(
12
- "root",
13
- "dropzone",
14
- "item",
15
- "itemDeleteTrigger",
16
- "itemGroup",
17
- "itemName",
18
- "itemPreview",
19
- "itemPreviewImage",
20
- "itemSizeText",
21
- "label",
22
- "trigger",
23
- "clearTrigger"
24
- );
25
- const parts = anatomy.build();
26
-
27
- const dom = domQuery.createScope({
28
- getRootId: (ctx) => ctx.ids?.root ?? `file-upload:${ctx.id}`,
29
- getDropzoneId: (ctx) => ctx.ids?.dropzone ?? `file-upload:${ctx.id}:dropzone`,
30
- getHiddenInputId: (ctx) => ctx.ids?.hiddenInput ?? `file-upload:${ctx.id}:input`,
31
- getTriggerId: (ctx) => ctx.ids?.trigger ?? `file-upload:${ctx.id}:trigger`,
32
- getLabelId: (ctx) => ctx.ids?.label ?? `file-upload:${ctx.id}:label`,
33
- getItemId: (ctx, id) => ctx.ids?.item?.(id) ?? `file-upload:${ctx.id}:item:${id}`,
34
- getItemNameId: (ctx, id) => ctx.ids?.itemName?.(id) ?? `file-upload:${ctx.id}:item-name:${id}`,
35
- getItemSizeTextId: (ctx, id) => ctx.ids?.itemSizeText?.(id) ?? `file-upload:${ctx.id}:item-size:${id}`,
36
- getItemPreviewId: (ctx, id) => ctx.ids?.itemPreview?.(id) ?? `file-upload:${ctx.id}:item-preview:${id}`,
37
- getRootEl: (ctx) => dom.getById(ctx, dom.getRootId(ctx)),
38
- getHiddenInputEl: (ctx) => dom.getById(ctx, dom.getHiddenInputId(ctx)),
39
- getDropzoneEl: (ctx) => dom.getById(ctx, dom.getDropzoneId(ctx))
40
- });
41
-
42
- function isEventWithFiles(event) {
43
- const target = domQuery.getEventTarget(event);
44
- if (!event.dataTransfer)
45
- return !!target && "files" in target;
46
- return event.dataTransfer.types.some((type) => {
47
- return type === "Files" || type === "application/x-moz-file";
48
- });
49
- }
50
- function isFilesWithinRange(ctx, incomingCount) {
51
- if (!ctx.multiple && incomingCount > 1)
52
- return false;
53
- if (!ctx.multiple && incomingCount + ctx.acceptedFiles.length === 2)
54
- return true;
55
- if (incomingCount + ctx.acceptedFiles.length > ctx.maxFiles)
56
- return false;
57
- return true;
58
- }
59
- function getFilesFromEvent(ctx, files) {
60
- const acceptedFiles = [];
61
- const rejectedFiles = [];
62
- files.forEach((file) => {
63
- const [accepted, acceptError] = fileUtils.isValidFileType(file, ctx.acceptAttr);
64
- const [sizeMatch, sizeError] = fileUtils.isValidFileSize(file, ctx.minFileSize, ctx.maxFileSize);
65
- const validateErrors = ctx.validate?.(file, {
66
- acceptedFiles: ctx.acceptedFiles,
67
- rejectedFiles: ctx.rejectedFiles
68
- });
69
- const valid = validateErrors ? validateErrors.length === 0 : true;
70
- if (accepted && sizeMatch && valid) {
71
- acceptedFiles.push(file);
72
- } else {
73
- const errors = [acceptError, sizeError];
74
- if (!valid)
75
- errors.push(...validateErrors ?? []);
76
- rejectedFiles.push({ file, errors: errors.filter(Boolean) });
77
- }
78
- });
79
- if (!isFilesWithinRange(ctx, acceptedFiles.length)) {
80
- acceptedFiles.forEach((file) => {
81
- rejectedFiles.push({ file, errors: ["TOO_MANY_FILES"] });
82
- });
83
- acceptedFiles.splice(0);
84
- }
85
- return {
86
- acceptedFiles,
87
- rejectedFiles
88
- };
89
- }
90
-
91
- function connect(state, send, normalize) {
92
- const disabled = state.context.disabled;
93
- const allowDrop = state.context.allowDrop;
94
- const translations = state.context.translations;
95
- const dragging = state.matches("dragging");
96
- const focused = state.matches("focused") && !disabled;
97
- return {
98
- dragging,
99
- focused,
100
- openFilePicker() {
101
- send("OPEN");
102
- },
103
- deleteFile(file) {
104
- send({ type: "FILE.DELETE", file });
105
- },
106
- acceptedFiles: state.context.acceptedFiles,
107
- rejectedFiles: state.context.rejectedFiles,
108
- setFiles(files) {
109
- const count = files.length;
110
- send({ type: "FILES.SET", files, count });
111
- },
112
- clearRejectedFiles() {
113
- send({ type: "REJECTED_FILES.CLEAR" });
114
- },
115
- clearFiles() {
116
- send({ type: "FILES.CLEAR" });
117
- },
118
- getFileSize(file) {
119
- return i18nUtils.formatBytes(file.size, state.context.locale);
120
- },
121
- createFileUrl(file, cb) {
122
- const win = dom.getWin(state.context);
123
- const url = win.URL.createObjectURL(file);
124
- cb(url);
125
- return () => win.URL.revokeObjectURL(url);
126
- },
127
- setClipboardFiles(dt) {
128
- const items = Array.from(dt?.items ?? []);
129
- const files = items.reduce((acc, item) => {
130
- if (item.kind !== "file")
131
- return acc;
132
- const file = item.getAsFile();
133
- if (!file)
134
- return acc;
135
- return [...acc, file];
136
- }, []);
137
- if (!files.length)
138
- return false;
139
- send({ type: "FILES.SET", files });
140
- return true;
141
- },
142
- getRootProps() {
143
- return normalize.element({
144
- ...parts.root.attrs,
145
- "dir": state.context.dir,
146
- "id": dom.getRootId(state.context),
147
- "data-disabled": domQuery.dataAttr(disabled),
148
- "data-dragging": domQuery.dataAttr(dragging)
149
- });
150
- },
151
- getDropzoneProps() {
152
- return normalize.element({
153
- ...parts.dropzone.attrs,
154
- "dir": state.context.dir,
155
- "id": dom.getDropzoneId(state.context),
156
- "tabIndex": disabled ? void 0 : 0,
157
- "role": "button",
158
- "aria-label": translations.dropzone,
159
- "aria-disabled": disabled,
160
- "data-invalid": domQuery.dataAttr(state.context.invalid),
161
- "data-disabled": domQuery.dataAttr(disabled),
162
- "data-dragging": domQuery.dataAttr(dragging),
163
- onKeyDown(event) {
164
- if (event.defaultPrevented)
165
- return;
166
- if (!domQuery.isSelfTarget(event))
167
- return;
168
- if (event.key !== "Enter" && event.key !== " ")
169
- return;
170
- send({ type: "DROPZONE.CLICK", src: "keydown" });
171
- },
172
- onClick(event) {
173
- const isLabel = event.currentTarget.localName === "label";
174
- if (isLabel)
175
- event.preventDefault();
176
- send("DROPZONE.CLICK");
177
- },
178
- onDragOver(event) {
179
- if (!allowDrop)
180
- return;
181
- event.preventDefault();
182
- event.stopPropagation();
183
- try {
184
- event.dataTransfer.dropEffect = "copy";
185
- } catch {
186
- }
187
- const hasFiles = isEventWithFiles(event);
188
- if (!hasFiles)
189
- return;
190
- const count = event.dataTransfer.items.length;
191
- send({ type: "DROPZONE.DRAG_OVER", count });
192
- },
193
- onDragLeave(event) {
194
- if (!allowDrop || disabled)
195
- return;
196
- if (domQuery.contains(event.currentTarget, event.relatedTarget))
197
- return;
198
- send({ type: "DROPZONE.DRAG_LEAVE" });
199
- },
200
- onDrop(event) {
201
- if (allowDrop) {
202
- event.preventDefault();
203
- event.stopPropagation();
204
- }
205
- const hasFiles = isEventWithFiles(event);
206
- if (disabled || !hasFiles)
207
- return;
208
- send({ type: "DROPZONE.DROP", files: Array.from(event.dataTransfer.files) });
209
- },
210
- onFocus() {
211
- send("DROPZONE.FOCUS");
212
- },
213
- onBlur() {
214
- send("DROPZONE.BLUR");
215
- }
216
- });
217
- },
218
- getTriggerProps() {
219
- return normalize.button({
220
- ...parts.trigger.attrs,
221
- "dir": state.context.dir,
222
- "id": dom.getTriggerId(state.context),
223
- disabled,
224
- "data-disabled": domQuery.dataAttr(disabled),
225
- "data-invalid": domQuery.dataAttr(state.context.invalid),
226
- "type": "button",
227
- onClick(event) {
228
- if (disabled)
229
- return;
230
- if (domQuery.contains(dom.getDropzoneEl(state.context), event.currentTarget)) {
231
- event.stopPropagation();
232
- }
233
- send("OPEN");
234
- }
235
- });
236
- },
237
- getHiddenInputProps() {
238
- return normalize.input({
239
- id: dom.getHiddenInputId(state.context),
240
- tabIndex: -1,
241
- disabled,
242
- type: "file",
243
- required: state.context.required,
244
- capture: state.context.capture,
245
- name: state.context.name,
246
- accept: state.context.acceptAttr,
247
- webkitdirectory: state.context.directory ? "" : void 0,
248
- multiple: state.context.multiple || state.context.maxFiles > 1,
249
- onClick(event) {
250
- event.stopPropagation();
251
- event.currentTarget.value = "";
252
- },
253
- onChange(event) {
254
- if (disabled)
255
- return;
256
- const { files } = event.currentTarget;
257
- send({ type: "FILES.SET", files: files ? Array.from(files) : [] });
258
- },
259
- style: domQuery.visuallyHiddenStyle
260
- });
261
- },
262
- getItemGroupProps() {
263
- return normalize.element({
264
- ...parts.itemGroup.attrs,
265
- "dir": state.context.dir,
266
- "data-disabled": domQuery.dataAttr(disabled)
267
- });
268
- },
269
- getItemProps(props) {
270
- const { file } = props;
271
- return normalize.element({
272
- ...parts.item.attrs,
273
- "dir": state.context.dir,
274
- "id": dom.getItemId(state.context, file.name),
275
- "data-disabled": domQuery.dataAttr(disabled)
276
- });
277
- },
278
- getItemNameProps(props) {
279
- const { file } = props;
280
- return normalize.element({
281
- ...parts.itemName.attrs,
282
- "dir": state.context.dir,
283
- "id": dom.getItemNameId(state.context, file.name),
284
- "data-disabled": domQuery.dataAttr(disabled)
285
- });
286
- },
287
- getItemSizeTextProps(props) {
288
- const { file } = props;
289
- return normalize.element({
290
- ...parts.itemSizeText.attrs,
291
- "dir": state.context.dir,
292
- "id": dom.getItemSizeTextId(state.context, file.name),
293
- "data-disabled": domQuery.dataAttr(disabled)
294
- });
295
- },
296
- getItemPreviewProps(props) {
297
- const { file } = props;
298
- return normalize.element({
299
- ...parts.itemPreview.attrs,
300
- "dir": state.context.dir,
301
- "id": dom.getItemPreviewId(state.context, file.name),
302
- "data-disabled": domQuery.dataAttr(disabled)
303
- });
304
- },
305
- getItemPreviewImageProps(props) {
306
- const { file, url } = props;
307
- const isImage = file.type.startsWith("image/");
308
- if (!isImage) {
309
- throw new Error("Preview Image is only supported for image files");
310
- }
311
- return normalize.img({
312
- ...parts.itemPreviewImage.attrs,
313
- "alt": translations.itemPreview?.(file),
314
- "src": url,
315
- "data-disabled": domQuery.dataAttr(disabled)
316
- });
317
- },
318
- getItemDeleteTriggerProps(props) {
319
- const { file } = props;
320
- return normalize.button({
321
- ...parts.itemDeleteTrigger.attrs,
322
- "dir": state.context.dir,
323
- "type": "button",
324
- disabled,
325
- "data-disabled": domQuery.dataAttr(disabled),
326
- "aria-label": translations.deleteFile?.(file),
327
- onClick() {
328
- if (disabled)
329
- return;
330
- send({ type: "FILE.DELETE", file });
331
- }
332
- });
333
- },
334
- getLabelProps() {
335
- return normalize.label({
336
- ...parts.label.attrs,
337
- "dir": state.context.dir,
338
- "id": dom.getLabelId(state.context),
339
- "htmlFor": dom.getHiddenInputId(state.context),
340
- "data-disabled": domQuery.dataAttr(disabled)
341
- });
342
- },
343
- getClearTriggerProps() {
344
- return normalize.button({
345
- ...parts.clearTrigger.attrs,
346
- "dir": state.context.dir,
347
- "type": "button",
348
- disabled,
349
- "hidden": state.context.acceptedFiles.length === 0,
350
- "data-disabled": domQuery.dataAttr(disabled),
351
- onClick(event) {
352
- if (event.defaultPrevented)
353
- return;
354
- if (disabled)
355
- return;
356
- send({ type: "FILES.CLEAR" });
357
- }
358
- });
359
- }
360
- };
361
- }
362
-
363
- const invoke = {
364
- change: (ctx) => {
365
- ctx.onFileChange?.({
366
- acceptedFiles: ctx.acceptedFiles,
367
- rejectedFiles: ctx.rejectedFiles
368
- });
369
- },
370
- accept: (ctx) => {
371
- ctx.onFileAccept?.({ files: ctx.acceptedFiles });
372
- },
373
- reject: (ctx) => {
374
- ctx.onFileReject?.({ files: ctx.rejectedFiles });
375
- }
376
- };
377
- const set = {
378
- files: (ctx, acceptedFiles, rejectedFiles) => {
379
- ctx.acceptedFiles = core.ref(acceptedFiles);
380
- invoke.accept(ctx);
381
- if (rejectedFiles) {
382
- ctx.rejectedFiles = core.ref(rejectedFiles);
383
- invoke.reject(ctx);
384
- }
385
- invoke.change(ctx);
386
- }
387
- };
388
- function machine(userContext) {
389
- const ctx = utils.compact(userContext);
390
- return core.createMachine(
391
- {
392
- id: "fileupload",
393
- initial: "idle",
394
- context: {
395
- minFileSize: 0,
396
- maxFileSize: Number.POSITIVE_INFINITY,
397
- maxFiles: 1,
398
- allowDrop: true,
399
- accept: ctx.accept,
400
- preventDocumentDrop: true,
401
- ...ctx,
402
- acceptedFiles: core.ref([]),
403
- rejectedFiles: core.ref([]),
404
- translations: {
405
- dropzone: "dropzone",
406
- itemPreview: (file) => `preview of ${file.name}`,
407
- deleteFile: (file) => `delete file ${file.name}`,
408
- ...ctx.translations
409
- }
410
- },
411
- computed: {
412
- acceptAttr: (ctx2) => fileUtils.getAcceptAttrString(ctx2.accept),
413
- multiple: (ctx2) => ctx2.maxFiles > 1
414
- },
415
- watch: {
416
- acceptedFiles: ["syncInputElement"]
417
- },
418
- on: {
419
- "FILES.SET": {
420
- actions: ["setFilesFromEvent"]
421
- },
422
- "FILE.DELETE": {
423
- actions: ["removeFile"]
424
- },
425
- "FILES.CLEAR": {
426
- actions: ["clearFiles"]
427
- },
428
- "REJECTED_FILES.CLEAR": {
429
- actions: ["clearRejectedFiles"]
430
- }
431
- },
432
- activities: ["preventDocumentDrop"],
433
- states: {
434
- idle: {
435
- on: {
436
- "OPEN": {
437
- actions: ["openFilePicker"]
438
- },
439
- "DROPZONE.CLICK": {
440
- actions: ["openFilePicker"]
441
- },
442
- "DROPZONE.FOCUS": "focused",
443
- "DROPZONE.DRAG_OVER": "dragging"
444
- }
445
- },
446
- focused: {
447
- on: {
448
- "DROPZONE.BLUR": "idle",
449
- "OPEN": {
450
- actions: ["openFilePicker"]
451
- },
452
- "DROPZONE.CLICK": {
453
- actions: ["openFilePicker"]
454
- },
455
- "DROPZONE.DRAG_OVER": "dragging"
456
- }
457
- },
458
- dragging: {
459
- on: {
460
- "DROPZONE.DROP": {
461
- target: "idle",
462
- actions: ["setFilesFromEvent"]
463
- },
464
- "DROPZONE.DRAG_LEAVE": "idle"
465
- }
466
- }
467
- }
468
- },
469
- {
470
- activities: {
471
- preventDocumentDrop(ctx2) {
472
- if (!ctx2.preventDocumentDrop)
473
- return;
474
- if (!ctx2.allowDrop)
475
- return;
476
- if (ctx2.disabled)
477
- return;
478
- const doc = dom.getDoc(ctx2);
479
- const onDragOver = (event) => {
480
- event?.preventDefault();
481
- };
482
- const onDrop = (event) => {
483
- if (domQuery.contains(dom.getRootEl(ctx2), domQuery.getEventTarget(event)))
484
- return;
485
- event.preventDefault();
486
- };
487
- return utils.callAll(domQuery.addDomEvent(doc, "dragover", onDragOver, false), domQuery.addDomEvent(doc, "drop", onDrop, false));
488
- }
489
- },
490
- actions: {
491
- syncInputElement(ctx2) {
492
- queueMicrotask(() => {
493
- const inputEl = dom.getHiddenInputEl(ctx2);
494
- if (!inputEl)
495
- return;
496
- const win = dom.getWin(ctx2);
497
- const dataTransfer = new win.DataTransfer();
498
- ctx2.acceptedFiles.forEach((v) => {
499
- dataTransfer.items.add(v);
500
- });
501
- inputEl.files = dataTransfer.files;
502
- });
503
- },
504
- openFilePicker(ctx2) {
505
- domQuery.raf(() => {
506
- dom.getHiddenInputEl(ctx2)?.click();
507
- });
508
- },
509
- setFilesFromEvent(ctx2, evt) {
510
- const result = getFilesFromEvent(ctx2, evt.files);
511
- const { acceptedFiles, rejectedFiles } = result;
512
- if (ctx2.multiple) {
513
- const files = core.ref([...ctx2.acceptedFiles, ...acceptedFiles]);
514
- set.files(ctx2, files, rejectedFiles);
515
- return;
516
- }
517
- if (acceptedFiles.length) {
518
- const files = core.ref([acceptedFiles[0]]);
519
- set.files(ctx2, files, rejectedFiles);
520
- } else if (rejectedFiles.length) {
521
- set.files(ctx2, ctx2.acceptedFiles, rejectedFiles);
522
- }
523
- },
524
- removeFile(ctx2, evt) {
525
- const nextFiles = ctx2.acceptedFiles.filter((file) => file !== evt.file);
526
- ctx2.acceptedFiles = core.ref(nextFiles);
527
- invoke.change(ctx2);
528
- },
529
- clearRejectedFiles(ctx2) {
530
- ctx2.rejectedFiles = core.ref([]);
531
- invoke.change(ctx2);
532
- },
533
- clearFiles(ctx2) {
534
- ctx2.acceptedFiles = core.ref([]);
535
- ctx2.rejectedFiles = core.ref([]);
536
- invoke.change(ctx2);
537
- }
538
- },
539
- compareFns: {
540
- acceptedFiles: (a, b) => a.length === b.length && a.every((file, i) => fileUtils.isFileEqual(file, b[i]))
541
- }
542
- }
543
- );
544
- }
545
-
546
- const props = types.createProps()([
547
- "accept",
548
- "allowDrop",
549
- "capture",
550
- "dir",
551
- "directory",
552
- "disabled",
553
- "getRootNode",
554
- "id",
555
- "ids",
556
- "locale",
557
- "maxFiles",
558
- "maxFileSize",
559
- "minFileSize",
560
- "name",
561
- "invalid",
562
- "onFileAccept",
563
- "onFileReject",
564
- "onFileChange",
565
- "preventDocumentDrop",
566
- "required",
567
- "translations",
568
- "validate"
569
- ]);
570
- const splitProps = utils.createSplitProps(props);
571
- const itemProps = types.createProps()(["file"]);
572
- const splitItemProps = utils.createSplitProps(itemProps);
573
-
574
- exports.anatomy = anatomy;
575
- exports.connect = connect;
576
- exports.itemProps = itemProps;
577
- exports.machine = machine;
578
- exports.props = props;
579
- exports.splitItemProps = splitItemProps;
580
- exports.splitProps = splitProps;