@shipstatic/drop 0.1.7 → 0.1.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/README.md +69 -43
- package/dist/index.cjs +68 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -10
- package/dist/index.d.ts +19 -10
- package/dist/index.js +69 -47
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -4,10 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
A focused React hook for preparing files for deployment with [@shipstatic/ship](https://github.com/shipstatic/ship). Handles ZIP extraction, path normalization, and validation - everything needed before calling `ship.deploy()`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Built-in drag & drop support with prop getters! No need to manually implement drag & drop handlers - just spread `{...drop.getDropzoneProps()}` on your container and `{...drop.getInputProps()}` on the input element. Folder structure preservation is handled automatically.
|
|
8
8
|
|
|
9
9
|
**Note:** MD5 calculation is handled by Ship SDK during deployment. Drop focuses on file processing and UI state management.
|
|
10
10
|
|
|
11
|
+
## Table of Contents
|
|
12
|
+
|
|
13
|
+
- [Why Headless?](#why-headless)
|
|
14
|
+
- [Features](#features)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Requirements](#requirements)
|
|
17
|
+
- [Quick Start](#quick-start)
|
|
18
|
+
- [Configuration Architecture](#️-configuration-architecture)
|
|
19
|
+
- [Advanced Usage](#advanced-programmatic-file-picker)
|
|
20
|
+
- [API Reference](#api)
|
|
21
|
+
- [State Machine](#state-machine)
|
|
22
|
+
- [Error Handling](#error-handling)
|
|
23
|
+
- [Types](#types)
|
|
24
|
+
- [Ship SDK Integration](#direct-ship-sdk-integration)
|
|
25
|
+
- [Architecture Decisions](#architecture-decisions)
|
|
26
|
+
|
|
11
27
|
## Why Headless?
|
|
12
28
|
|
|
13
29
|
This package provides **zero UI components** - just a React hook with built-in drag & drop functionality. You bring your own styling.
|
|
@@ -16,8 +32,7 @@ This package provides **zero UI components** - just a React hook with built-in d
|
|
|
16
32
|
1. **Built-in drag & drop** - Proper folder support with `webkitGetAsEntry` API, all handled internally
|
|
17
33
|
2. **Prop getters API** - Similar to `react-dropzone`, just spread props on your elements
|
|
18
34
|
3. **Full styling control** - No imposed CSS, design system, or theming
|
|
19
|
-
4. **
|
|
20
|
-
5. **Ship SDK integration** - Purpose-built for Ship deployments, not a generic file upload library
|
|
35
|
+
4. **Ship SDK integration** - Purpose-built for Ship deployments, not a generic file upload library
|
|
21
36
|
|
|
22
37
|
**What's different from other libraries:**
|
|
23
38
|
- Generic dropzone libraries don't preserve folder structure properly
|
|
@@ -34,6 +49,7 @@ This package provides **zero UI components** - just a React hook with built-in d
|
|
|
34
49
|
- 🔒 **Path Sanitization** - Defense-in-depth protection against directory traversal attacks
|
|
35
50
|
- 📁 **Folder Structure Preservation** - Proper folder paths via `webkitRelativePath`
|
|
36
51
|
- 🎨 **Headless UI** - No visual components, just logic and state management
|
|
52
|
+
- 📘 **Full TypeScript Support** - Complete type definitions with discriminated unions for state machine
|
|
37
53
|
- 🚀 **Focused Scope** - File processing and UI state only. MD5 calculation and deployment handled by Ship SDK
|
|
38
54
|
|
|
39
55
|
## Installation
|
|
@@ -44,6 +60,17 @@ npm install @shipstatic/drop
|
|
|
44
60
|
pnpm add @shipstatic/drop
|
|
45
61
|
```
|
|
46
62
|
|
|
63
|
+
## Requirements
|
|
64
|
+
|
|
65
|
+
- **React**: ^18.0.0 or ^19.0.0
|
|
66
|
+
- **TypeScript**: Full TypeScript support with exported types
|
|
67
|
+
- **Browsers**: Modern browsers with support for:
|
|
68
|
+
- File API (universal support)
|
|
69
|
+
- DataTransfer API for drag & drop (universal support)
|
|
70
|
+
- `webkitGetAsEntry` for folder uploads (Chrome, Edge, Safari 11.1+, Firefox 50+)
|
|
71
|
+
|
|
72
|
+
**Note on folder uploads**: The folder drag & drop feature uses the `webkitGetAsEntry` API. While widely supported, older browsers may only support file-by-file selection. ZIP extraction works universally as a fallback.
|
|
73
|
+
|
|
47
74
|
## Quick Start
|
|
48
75
|
|
|
49
76
|
```tsx
|
|
@@ -80,15 +107,15 @@ function MyUploader() {
|
|
|
80
107
|
{drop.isDragging ? '📂 Drop here' : '📁 Click or drag files/folders'}
|
|
81
108
|
</div>
|
|
82
109
|
|
|
83
|
-
{/* Status - using state machine */}
|
|
84
|
-
{drop.
|
|
110
|
+
{/* Status - using state machine phase */}
|
|
111
|
+
{drop.status && (
|
|
85
112
|
<p>
|
|
86
|
-
<strong>{drop.
|
|
113
|
+
<strong>{drop.status.title}:</strong> {drop.status.details}
|
|
87
114
|
</p>
|
|
88
115
|
)}
|
|
89
116
|
|
|
90
117
|
{/* File list */}
|
|
91
|
-
{drop.
|
|
118
|
+
{drop.files.map(file => (
|
|
92
119
|
<div key={file.id}>
|
|
93
120
|
{file.name} - {file.status}
|
|
94
121
|
</div>
|
|
@@ -97,7 +124,7 @@ function MyUploader() {
|
|
|
97
124
|
{/* Upload button */}
|
|
98
125
|
<button
|
|
99
126
|
onClick={handleUpload}
|
|
100
|
-
disabled={drop.
|
|
127
|
+
disabled={drop.phase !== 'ready'}
|
|
101
128
|
>
|
|
102
129
|
Upload {drop.getValidFiles().length} files
|
|
103
130
|
</button>
|
|
@@ -205,17 +232,22 @@ interface DropOptions {
|
|
|
205
232
|
|
|
206
233
|
**Returns:**
|
|
207
234
|
|
|
235
|
+
```typescript
|
|
208
236
|
```typescript
|
|
209
237
|
interface DropReturn {
|
|
210
|
-
// State machine
|
|
211
|
-
/** Current state of the drop hook */
|
|
212
|
-
state: DropState;
|
|
213
|
-
|
|
214
238
|
// Convenience getters (computed from state)
|
|
239
|
+
/** Current phase of the state machine */
|
|
240
|
+
phase: DropStateValue;
|
|
215
241
|
/** Whether currently processing files (ZIP extraction, etc.) */
|
|
216
242
|
isProcessing: boolean;
|
|
217
243
|
/** Whether user is currently dragging over the dropzone */
|
|
218
244
|
isDragging: boolean;
|
|
245
|
+
/** Flattened access to files */
|
|
246
|
+
files: ProcessedFile[];
|
|
247
|
+
/** Flattened access to source name */
|
|
248
|
+
sourceName: string;
|
|
249
|
+
/** Flattened access to status */
|
|
250
|
+
status: DropStatus | null;
|
|
219
251
|
|
|
220
252
|
// Primary API: Prop getters for easy integration
|
|
221
253
|
/** Get props to spread on dropzone element (handles drag & drop) */
|
|
@@ -231,7 +263,7 @@ interface DropReturn {
|
|
|
231
263
|
type: 'file';
|
|
232
264
|
style: { display: string };
|
|
233
265
|
multiple: boolean;
|
|
234
|
-
webkitdirectory: string;
|
|
266
|
+
webkitdirectory: string; // Note: React expects string ('') for boolean attributes
|
|
235
267
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
|
236
268
|
};
|
|
237
269
|
|
|
@@ -262,22 +294,16 @@ type DropStateValue =
|
|
|
262
294
|
| 'ready' // Files are valid and ready for deployment
|
|
263
295
|
| 'error'; // An error occurred during processing
|
|
264
296
|
|
|
265
|
-
interface DropState {
|
|
266
|
-
value: DropStateValue;
|
|
267
|
-
files: ProcessedFile[];
|
|
268
|
-
sourceName: string;
|
|
269
|
-
status: DropStatus | null;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
297
|
interface DropStatus {
|
|
273
298
|
title: string;
|
|
274
299
|
details: string;
|
|
300
|
+
errors?: string[];
|
|
275
301
|
}
|
|
276
302
|
```
|
|
277
303
|
|
|
278
304
|
## State Machine
|
|
279
305
|
|
|
280
|
-
The drop hook uses a state machine for predictable, clear state management. Instead of multiple boolean flags, you have a single `
|
|
306
|
+
The drop hook uses a state machine for predictable, clear state management. Instead of multiple boolean flags, you have a single `drop.phase` that represents exactly what's happening.
|
|
281
307
|
|
|
282
308
|
### State Flow
|
|
283
309
|
|
|
@@ -293,9 +319,8 @@ error → dragging → processing → ... (retry)
|
|
|
293
319
|
|
|
294
320
|
```tsx
|
|
295
321
|
function StatusIndicator({ drop }) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
switch (state.value) {
|
|
322
|
+
// Use drop.phase to switch-case on the state
|
|
323
|
+
switch (drop.phase) {
|
|
299
324
|
case 'idle':
|
|
300
325
|
return <p>Drop files here or click to select</p>;
|
|
301
326
|
|
|
@@ -303,12 +328,12 @@ function StatusIndicator({ drop }) {
|
|
|
303
328
|
return <p>Drop your files now!</p>;
|
|
304
329
|
|
|
305
330
|
case 'processing':
|
|
306
|
-
return <p>{
|
|
331
|
+
return <p>{drop.status?.details || 'Processing...'}</p>;
|
|
307
332
|
|
|
308
333
|
case 'ready':
|
|
309
334
|
return (
|
|
310
335
|
<div>
|
|
311
|
-
<p>✓ {
|
|
336
|
+
<p>✓ {drop.files.length} files ready</p>
|
|
312
337
|
<button>Upload to Ship</button>
|
|
313
338
|
</div>
|
|
314
339
|
);
|
|
@@ -316,8 +341,8 @@ function StatusIndicator({ drop }) {
|
|
|
316
341
|
case 'error':
|
|
317
342
|
return (
|
|
318
343
|
<div>
|
|
319
|
-
<p>✗ {
|
|
320
|
-
<p>{
|
|
344
|
+
<p>✗ {drop.status?.title}</p>
|
|
345
|
+
<p>{drop.status?.details}</p>
|
|
321
346
|
<button onClick={drop.clearAll}>Try Again</button>
|
|
322
347
|
</div>
|
|
323
348
|
);
|
|
@@ -330,14 +355,14 @@ function StatusIndicator({ drop }) {
|
|
|
330
355
|
For simpler use cases, boolean convenience getters are provided:
|
|
331
356
|
|
|
332
357
|
```tsx
|
|
333
|
-
// These are computed from
|
|
334
|
-
drop.isProcessing // true when
|
|
335
|
-
drop.isDragging // true when
|
|
336
|
-
|
|
337
|
-
// For error information, use the
|
|
338
|
-
drop.
|
|
339
|
-
drop.
|
|
340
|
-
drop.
|
|
358
|
+
// These are computed from drop.phase (read-only projections)
|
|
359
|
+
drop.isProcessing // true when phase === 'processing'
|
|
360
|
+
drop.isDragging // true when phase === 'dragging'
|
|
361
|
+
|
|
362
|
+
// For error information, use the flattened status object
|
|
363
|
+
drop.phase === 'error' // Check if in error state
|
|
364
|
+
drop.status?.title // Error title
|
|
365
|
+
drop.status?.details // Error details
|
|
341
366
|
```
|
|
342
367
|
|
|
343
368
|
### Benefits
|
|
@@ -357,7 +382,8 @@ Each file in the `state.files` array contains its own `status` and `statusMessag
|
|
|
357
382
|
function FileList({ drop }) {
|
|
358
383
|
return (
|
|
359
384
|
<div>
|
|
360
|
-
{
|
|
385
|
+
{/* Flattened access to files array */}
|
|
386
|
+
{drop.files.map(file => (
|
|
361
387
|
<div key={file.id}>
|
|
362
388
|
<span>{file.path}</span>
|
|
363
389
|
|
|
@@ -374,7 +400,7 @@ function FileList({ drop }) {
|
|
|
374
400
|
))}
|
|
375
401
|
|
|
376
402
|
{/* If validation fails, allow user to clear all and try again */}
|
|
377
|
-
{drop.
|
|
403
|
+
{drop.phase === 'error' && (
|
|
378
404
|
<button onClick={drop.clearAll}>
|
|
379
405
|
Clear All & Try Again
|
|
380
406
|
</button>
|
|
@@ -395,10 +421,10 @@ function FileList({ drop }) {
|
|
|
395
421
|
When files fail validation or processing, check the error state:
|
|
396
422
|
|
|
397
423
|
```tsx
|
|
398
|
-
{drop.
|
|
424
|
+
{drop.phase === 'error' && drop.status && (
|
|
399
425
|
<div>
|
|
400
|
-
<p>{drop.
|
|
401
|
-
<p>{drop.
|
|
426
|
+
<p>{drop.status.title}</p>
|
|
427
|
+
<p>{drop.status.details}</p>
|
|
402
428
|
</div>
|
|
403
429
|
)}
|
|
404
430
|
```
|
|
@@ -428,10 +454,10 @@ Use `clearAll()` to reset and try again:
|
|
|
428
454
|
|
|
429
455
|
```tsx
|
|
430
456
|
// If validation fails, show user which files failed
|
|
431
|
-
{drop.
|
|
457
|
+
{drop.phase === 'error' && (
|
|
432
458
|
<div>
|
|
433
459
|
<p>Validation failed. Please fix the issues and try again:</p>
|
|
434
|
-
{drop.
|
|
460
|
+
{drop.files.map(file => (
|
|
435
461
|
<div key={file.id}>
|
|
436
462
|
{file.path}: {file.statusMessage}
|
|
437
463
|
</div>
|
package/dist/index.cjs
CHANGED
|
@@ -37,9 +37,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
37
37
|
|
|
38
38
|
// node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/dist/jszip.min.js
|
|
39
39
|
var require_jszip_min = __commonJS({
|
|
40
|
-
"node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/dist/jszip.min.js"(exports, module) {
|
|
40
|
+
"node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/dist/jszip.min.js"(exports$1, module) {
|
|
41
41
|
!(function(e) {
|
|
42
|
-
if ("object" == typeof exports && "undefined" != typeof module) module.exports = e();
|
|
42
|
+
if ("object" == typeof exports$1 && "undefined" != typeof module) module.exports = e();
|
|
43
43
|
else if ("function" == typeof define && define.amd) define([], e);
|
|
44
44
|
else {
|
|
45
45
|
("undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this).JSZip = e();
|
|
@@ -2349,7 +2349,7 @@ var require_jszip_min = __commonJS({
|
|
|
2349
2349
|
|
|
2350
2350
|
// node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json
|
|
2351
2351
|
var require_db = __commonJS({
|
|
2352
|
-
"node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json"(exports, module) {
|
|
2352
|
+
"node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/db.json"(exports$1, module) {
|
|
2353
2353
|
module.exports = {
|
|
2354
2354
|
"application/1d-interleaved-parityfec": {
|
|
2355
2355
|
source: "iana"
|
|
@@ -11697,7 +11697,7 @@ var require_db = __commonJS({
|
|
|
11697
11697
|
|
|
11698
11698
|
// node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js
|
|
11699
11699
|
var require_mime_db = __commonJS({
|
|
11700
|
-
"node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js"(exports, module) {
|
|
11700
|
+
"node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db/index.js"(exports$1, module) {
|
|
11701
11701
|
module.exports = require_db();
|
|
11702
11702
|
}
|
|
11703
11703
|
});
|
|
@@ -11813,7 +11813,6 @@ async function createProcessedFile(file, options) {
|
|
|
11813
11813
|
status: FILE_STATUSES.PENDING
|
|
11814
11814
|
};
|
|
11815
11815
|
}
|
|
11816
|
-
var getValidFiles = ship.getValidFiles;
|
|
11817
11816
|
function stripCommonPrefix(files) {
|
|
11818
11817
|
if (files.length === 0) return files;
|
|
11819
11818
|
const paths = files.map((f) => f.path);
|
|
@@ -11835,35 +11834,39 @@ function stripCommonPrefix(files) {
|
|
|
11835
11834
|
}));
|
|
11836
11835
|
}
|
|
11837
11836
|
async function traverseFileTree(entry, files, currentPath = "") {
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
const
|
|
11853
|
-
|
|
11854
|
-
|
|
11837
|
+
try {
|
|
11838
|
+
if (entry.isFile) {
|
|
11839
|
+
const file = await new Promise((resolve, reject) => {
|
|
11840
|
+
entry.file(resolve, reject);
|
|
11841
|
+
});
|
|
11842
|
+
const relativePath = currentPath ? `${currentPath}/${file.name}` : file.name;
|
|
11843
|
+
Object.defineProperty(file, "webkitRelativePath", {
|
|
11844
|
+
value: relativePath,
|
|
11845
|
+
writable: false
|
|
11846
|
+
});
|
|
11847
|
+
files.push(file);
|
|
11848
|
+
} else if (entry.isDirectory) {
|
|
11849
|
+
const dirReader = entry.createReader();
|
|
11850
|
+
let allEntries = [];
|
|
11851
|
+
const readEntriesBatch = async () => {
|
|
11852
|
+
const batch = await new Promise(
|
|
11853
|
+
(resolve, reject) => {
|
|
11854
|
+
dirReader.readEntries(resolve, reject);
|
|
11855
|
+
}
|
|
11856
|
+
);
|
|
11857
|
+
if (batch.length > 0) {
|
|
11858
|
+
allEntries = allEntries.concat(batch);
|
|
11859
|
+
await readEntriesBatch();
|
|
11855
11860
|
}
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11861
|
+
};
|
|
11862
|
+
await readEntriesBatch();
|
|
11863
|
+
for (const childEntry of allEntries) {
|
|
11864
|
+
const entryPath = childEntry.isDirectory ? currentPath ? `${currentPath}/${childEntry.name}` : childEntry.name : currentPath;
|
|
11865
|
+
await traverseFileTree(childEntry, files, entryPath);
|
|
11860
11866
|
}
|
|
11861
|
-
};
|
|
11862
|
-
await readEntriesBatch();
|
|
11863
|
-
for (const childEntry of allEntries) {
|
|
11864
|
-
const entryPath = childEntry.isDirectory ? currentPath ? `${currentPath}/${childEntry.name}` : childEntry.name : currentPath;
|
|
11865
|
-
await traverseFileTree(childEntry, files, entryPath);
|
|
11866
11867
|
}
|
|
11868
|
+
} catch (error) {
|
|
11869
|
+
console.warn(`Error traversing file tree for entry ${entry.name}:`, error);
|
|
11867
11870
|
}
|
|
11868
11871
|
}
|
|
11869
11872
|
function useDrop(options) {
|
|
@@ -11884,6 +11887,7 @@ function useDrop(options) {
|
|
|
11884
11887
|
const inputRef = react.useRef(null);
|
|
11885
11888
|
const isProcessing = react.useMemo(() => state.value === "processing", [state.value]);
|
|
11886
11889
|
const isDragging = react.useMemo(() => state.value === "dragging", [state.value]);
|
|
11890
|
+
const validFiles = react.useMemo(() => ship.getValidFiles(state.files), [state.files]);
|
|
11887
11891
|
const processFiles = react.useCallback(async (newFiles) => {
|
|
11888
11892
|
if (isProcessingRef.current) {
|
|
11889
11893
|
console.warn("File processing already in progress. Ignoring duplicate call.");
|
|
@@ -11949,7 +11953,11 @@ function useDrop(options) {
|
|
|
11949
11953
|
value: "error",
|
|
11950
11954
|
files: validation.files,
|
|
11951
11955
|
sourceName: detectedSourceName,
|
|
11952
|
-
status: {
|
|
11956
|
+
status: {
|
|
11957
|
+
title: validation.error.error,
|
|
11958
|
+
details: validation.error.details,
|
|
11959
|
+
errors: validation.error.errors
|
|
11960
|
+
}
|
|
11953
11961
|
});
|
|
11954
11962
|
onValidationError?.(validation.error);
|
|
11955
11963
|
} else if (validation.validFiles.length > 0) {
|
|
@@ -11994,9 +12002,6 @@ function useDrop(options) {
|
|
|
11994
12002
|
setState(initialState);
|
|
11995
12003
|
isProcessingRef.current = false;
|
|
11996
12004
|
}, []);
|
|
11997
|
-
const getValidFilesCallback = react.useCallback(() => {
|
|
11998
|
-
return getValidFiles(state.files);
|
|
11999
|
-
}, [state.files]);
|
|
12000
12005
|
const updateFileStatus = react.useCallback((fileId, fileState) => {
|
|
12001
12006
|
setState((prev) => ({
|
|
12002
12007
|
...prev,
|
|
@@ -12029,14 +12034,27 @@ function useDrop(options) {
|
|
|
12029
12034
|
let hasEntries = false;
|
|
12030
12035
|
for (const item of items) {
|
|
12031
12036
|
if (item.kind === "file") {
|
|
12032
|
-
|
|
12033
|
-
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12037
|
+
try {
|
|
12038
|
+
const entry = item.webkitGetAsEntry?.();
|
|
12039
|
+
if (entry) {
|
|
12040
|
+
hasEntries = true;
|
|
12041
|
+
await traverseFileTree(
|
|
12042
|
+
entry,
|
|
12043
|
+
files,
|
|
12044
|
+
entry.isDirectory ? entry.name : ""
|
|
12045
|
+
);
|
|
12046
|
+
} else {
|
|
12047
|
+
const file = item.getAsFile();
|
|
12048
|
+
if (file) {
|
|
12049
|
+
files.push(file);
|
|
12050
|
+
}
|
|
12051
|
+
}
|
|
12052
|
+
} catch (error) {
|
|
12053
|
+
console.warn("Error processing drop item:", error);
|
|
12054
|
+
const file = item.getAsFile();
|
|
12055
|
+
if (file) {
|
|
12056
|
+
files.push(file);
|
|
12057
|
+
}
|
|
12040
12058
|
}
|
|
12041
12059
|
}
|
|
12042
12060
|
}
|
|
@@ -12074,10 +12092,14 @@ function useDrop(options) {
|
|
|
12074
12092
|
}), [handleInputChange]);
|
|
12075
12093
|
return {
|
|
12076
12094
|
// State machine
|
|
12077
|
-
state,
|
|
12095
|
+
// state, // REMOVED
|
|
12078
12096
|
// Convenience getters (computed from state)
|
|
12097
|
+
phase: state.value,
|
|
12079
12098
|
isProcessing,
|
|
12080
12099
|
isDragging,
|
|
12100
|
+
files: state.files,
|
|
12101
|
+
sourceName: state.sourceName,
|
|
12102
|
+
status: state.status,
|
|
12081
12103
|
// Primary API: Prop getters
|
|
12082
12104
|
getDropzoneProps,
|
|
12083
12105
|
getInputProps,
|
|
@@ -12086,7 +12108,7 @@ function useDrop(options) {
|
|
|
12086
12108
|
processFiles,
|
|
12087
12109
|
clearAll,
|
|
12088
12110
|
// Helpers
|
|
12089
|
-
|
|
12111
|
+
validFiles,
|
|
12090
12112
|
updateFileStatus
|
|
12091
12113
|
};
|
|
12092
12114
|
}
|
|
@@ -12118,10 +12140,10 @@ exports.FILE_STATUSES = FILE_STATUSES;
|
|
|
12118
12140
|
exports.createProcessedFile = createProcessedFile;
|
|
12119
12141
|
exports.extractZipToFiles = extractZipToFiles;
|
|
12120
12142
|
exports.formatFileSize = formatFileSize;
|
|
12121
|
-
exports.getValidFiles = getValidFiles;
|
|
12122
12143
|
exports.isZipFile = isZipFile;
|
|
12123
12144
|
exports.normalizePath = normalizePath;
|
|
12124
12145
|
exports.stripCommonPrefix = stripCommonPrefix;
|
|
12146
|
+
exports.traverseFileTree = traverseFileTree;
|
|
12125
12147
|
exports.useDrop = useDrop;
|
|
12126
12148
|
//# sourceMappingURL=index.cjs.map
|
|
12127
12149
|
//# sourceMappingURL=index.cjs.map
|