@shipstatic/drop 0.1.8 → 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 CHANGED
@@ -107,15 +107,15 @@ function MyUploader() {
107
107
  {drop.isDragging ? '📂 Drop here' : '📁 Click or drag files/folders'}
108
108
  </div>
109
109
 
110
- {/* Status - using state machine */}
111
- {drop.state.status && (
110
+ {/* Status - using state machine phase */}
111
+ {drop.status && (
112
112
  <p>
113
- <strong>{drop.state.status.title}:</strong> {drop.state.status.details}
113
+ <strong>{drop.status.title}:</strong> {drop.status.details}
114
114
  </p>
115
115
  )}
116
116
 
117
117
  {/* File list */}
118
- {drop.state.files.map(file => (
118
+ {drop.files.map(file => (
119
119
  <div key={file.id}>
120
120
  {file.name} - {file.status}
121
121
  </div>
@@ -124,7 +124,7 @@ function MyUploader() {
124
124
  {/* Upload button */}
125
125
  <button
126
126
  onClick={handleUpload}
127
- disabled={drop.state.value !== 'ready'}
127
+ disabled={drop.phase !== 'ready'}
128
128
  >
129
129
  Upload {drop.getValidFiles().length} files
130
130
  </button>
@@ -232,17 +232,22 @@ interface DropOptions {
232
232
 
233
233
  **Returns:**
234
234
 
235
+ ```typescript
235
236
  ```typescript
236
237
  interface DropReturn {
237
- // State machine
238
- /** Current state of the drop hook */
239
- state: DropState;
240
-
241
238
  // Convenience getters (computed from state)
239
+ /** Current phase of the state machine */
240
+ phase: DropStateValue;
242
241
  /** Whether currently processing files (ZIP extraction, etc.) */
243
242
  isProcessing: boolean;
244
243
  /** Whether user is currently dragging over the dropzone */
245
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;
246
251
 
247
252
  // Primary API: Prop getters for easy integration
248
253
  /** Get props to spread on dropzone element (handles drag & drop) */
@@ -289,22 +294,16 @@ type DropStateValue =
289
294
  | 'ready' // Files are valid and ready for deployment
290
295
  | 'error'; // An error occurred during processing
291
296
 
292
- interface DropState {
293
- value: DropStateValue;
294
- files: ProcessedFile[];
295
- sourceName: string;
296
- status: DropStatus | null;
297
- }
298
-
299
297
  interface DropStatus {
300
298
  title: string;
301
299
  details: string;
300
+ errors?: string[];
302
301
  }
303
302
  ```
304
303
 
305
304
  ## State Machine
306
305
 
307
- The drop hook uses a state machine for predictable, clear state management. Instead of multiple boolean flags, you have a single `state.value` that represents exactly what's happening.
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.
308
307
 
309
308
  ### State Flow
310
309
 
@@ -320,9 +319,8 @@ error → dragging → processing → ... (retry)
320
319
 
321
320
  ```tsx
322
321
  function StatusIndicator({ drop }) {
323
- const { state } = drop;
324
-
325
- switch (state.value) {
322
+ // Use drop.phase to switch-case on the state
323
+ switch (drop.phase) {
326
324
  case 'idle':
327
325
  return <p>Drop files here or click to select</p>;
328
326
 
@@ -330,12 +328,12 @@ function StatusIndicator({ drop }) {
330
328
  return <p>Drop your files now!</p>;
331
329
 
332
330
  case 'processing':
333
- return <p>{state.status?.details || 'Processing...'}</p>;
331
+ return <p>{drop.status?.details || 'Processing...'}</p>;
334
332
 
335
333
  case 'ready':
336
334
  return (
337
335
  <div>
338
- <p>✓ {state.files.length} files ready</p>
336
+ <p>✓ {drop.files.length} files ready</p>
339
337
  <button>Upload to Ship</button>
340
338
  </div>
341
339
  );
@@ -343,8 +341,8 @@ function StatusIndicator({ drop }) {
343
341
  case 'error':
344
342
  return (
345
343
  <div>
346
- <p>✗ {state.status?.title}</p>
347
- <p>{state.status?.details}</p>
344
+ <p>✗ {drop.status?.title}</p>
345
+ <p>{drop.status?.details}</p>
348
346
  <button onClick={drop.clearAll}>Try Again</button>
349
347
  </div>
350
348
  );
@@ -357,14 +355,14 @@ function StatusIndicator({ drop }) {
357
355
  For simpler use cases, boolean convenience getters are provided:
358
356
 
359
357
  ```tsx
360
- // These are computed from state.value (read-only projections)
361
- drop.isProcessing // true when state.value === 'processing'
362
- drop.isDragging // true when state.value === 'dragging'
363
-
364
- // For error information, use the state object
365
- drop.state.value === 'error' // Check if in error state
366
- drop.state.status?.title // Error title
367
- drop.state.status?.details // Error details
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
368
366
  ```
369
367
 
370
368
  ### Benefits
@@ -384,7 +382,8 @@ Each file in the `state.files` array contains its own `status` and `statusMessag
384
382
  function FileList({ drop }) {
385
383
  return (
386
384
  <div>
387
- {drop.state.files.map(file => (
385
+ {/* Flattened access to files array */}
386
+ {drop.files.map(file => (
388
387
  <div key={file.id}>
389
388
  <span>{file.path}</span>
390
389
 
@@ -401,7 +400,7 @@ function FileList({ drop }) {
401
400
  ))}
402
401
 
403
402
  {/* If validation fails, allow user to clear all and try again */}
404
- {drop.state.value === 'error' && (
403
+ {drop.phase === 'error' && (
405
404
  <button onClick={drop.clearAll}>
406
405
  Clear All & Try Again
407
406
  </button>
@@ -422,10 +421,10 @@ function FileList({ drop }) {
422
421
  When files fail validation or processing, check the error state:
423
422
 
424
423
  ```tsx
425
- {drop.state.value === 'error' && drop.state.status && (
424
+ {drop.phase === 'error' && drop.status && (
426
425
  <div>
427
- <p>{drop.state.status.title}</p>
428
- <p>{drop.state.status.details}</p>
426
+ <p>{drop.status.title}</p>
427
+ <p>{drop.status.details}</p>
429
428
  </div>
430
429
  )}
431
430
  ```
@@ -455,10 +454,10 @@ Use `clearAll()` to reset and try again:
455
454
 
456
455
  ```tsx
457
456
  // If validation fails, show user which files failed
458
- {drop.state.value === 'error' && (
457
+ {drop.phase === 'error' && (
459
458
  <div>
460
459
  <p>Validation failed. Please fix the issues and try again:</p>
461
- {drop.state.files.map(file => (
460
+ {drop.files.map(file => (
462
461
  <div key={file.id}>
463
462
  {file.path}: {file.statusMessage}
464
463
  </div>
package/dist/index.cjs CHANGED
@@ -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);
@@ -11888,6 +11887,7 @@ function useDrop(options) {
11888
11887
  const inputRef = react.useRef(null);
11889
11888
  const isProcessing = react.useMemo(() => state.value === "processing", [state.value]);
11890
11889
  const isDragging = react.useMemo(() => state.value === "dragging", [state.value]);
11890
+ const validFiles = react.useMemo(() => ship.getValidFiles(state.files), [state.files]);
11891
11891
  const processFiles = react.useCallback(async (newFiles) => {
11892
11892
  if (isProcessingRef.current) {
11893
11893
  console.warn("File processing already in progress. Ignoring duplicate call.");
@@ -11953,7 +11953,11 @@ function useDrop(options) {
11953
11953
  value: "error",
11954
11954
  files: validation.files,
11955
11955
  sourceName: detectedSourceName,
11956
- status: { title: validation.error.error, details: validation.error.details }
11956
+ status: {
11957
+ title: validation.error.error,
11958
+ details: validation.error.details,
11959
+ errors: validation.error.errors
11960
+ }
11957
11961
  });
11958
11962
  onValidationError?.(validation.error);
11959
11963
  } else if (validation.validFiles.length > 0) {
@@ -11998,9 +12002,6 @@ function useDrop(options) {
11998
12002
  setState(initialState);
11999
12003
  isProcessingRef.current = false;
12000
12004
  }, []);
12001
- const getValidFilesCallback = react.useCallback(() => {
12002
- return getValidFiles(state.files);
12003
- }, [state.files]);
12004
12005
  const updateFileStatus = react.useCallback((fileId, fileState) => {
12005
12006
  setState((prev) => ({
12006
12007
  ...prev,
@@ -12091,10 +12092,14 @@ function useDrop(options) {
12091
12092
  }), [handleInputChange]);
12092
12093
  return {
12093
12094
  // State machine
12094
- state,
12095
+ // state, // REMOVED
12095
12096
  // Convenience getters (computed from state)
12097
+ phase: state.value,
12096
12098
  isProcessing,
12097
12099
  isDragging,
12100
+ files: state.files,
12101
+ sourceName: state.sourceName,
12102
+ status: state.status,
12098
12103
  // Primary API: Prop getters
12099
12104
  getDropzoneProps,
12100
12105
  getInputProps,
@@ -12103,7 +12108,7 @@ function useDrop(options) {
12103
12108
  processFiles,
12104
12109
  clearAll,
12105
12110
  // Helpers
12106
- getValidFiles: getValidFilesCallback,
12111
+ validFiles,
12107
12112
  updateFileStatus
12108
12113
  };
12109
12114
  }
@@ -12135,10 +12140,10 @@ exports.FILE_STATUSES = FILE_STATUSES;
12135
12140
  exports.createProcessedFile = createProcessedFile;
12136
12141
  exports.extractZipToFiles = extractZipToFiles;
12137
12142
  exports.formatFileSize = formatFileSize;
12138
- exports.getValidFiles = getValidFiles;
12139
12143
  exports.isZipFile = isZipFile;
12140
12144
  exports.normalizePath = normalizePath;
12141
12145
  exports.stripCommonPrefix = stripCommonPrefix;
12146
+ exports.traverseFileTree = traverseFileTree;
12142
12147
  exports.useDrop = useDrop;
12143
12148
  //# sourceMappingURL=index.cjs.map
12144
12149
  //# sourceMappingURL=index.cjs.map