@shipstatic/drop 0.1.8 → 0.1.10

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.d.cts CHANGED
@@ -62,6 +62,7 @@ type DropStateValue = 'idle' | 'dragging' | 'processing' | 'ready' | 'error';
62
62
  interface DropStatus {
63
63
  title: string;
64
64
  details: string;
65
+ errors?: string[];
65
66
  }
66
67
  /**
67
68
  * State machine state for the drop hook
@@ -84,12 +85,21 @@ interface DropOptions {
84
85
  stripPrefix?: boolean;
85
86
  }
86
87
  interface DropReturn {
87
- /** Current state of the drop hook */
88
- state: DropState;
88
+ /** Current phase of the state machine */
89
+ phase: DropStateValue;
89
90
  /** Whether currently processing files (ZIP extraction, etc.) */
90
91
  isProcessing: boolean;
91
92
  /** Whether user is currently dragging over the dropzone */
92
93
  isDragging: boolean;
94
+ /** Flattened access to files */
95
+ files: ProcessedFile[];
96
+ /** Flattened access to source name */
97
+ sourceName: string;
98
+ /** Flattened access to status */
99
+ status: {
100
+ title: string;
101
+ details: string;
102
+ } | null;
93
103
  /** Get props to spread on dropzone element (handles drag & drop) */
94
104
  getDropzoneProps: () => {
95
105
  onDragOver: (e: React.DragEvent) => void;
@@ -115,7 +125,7 @@ interface DropReturn {
115
125
  /** Clear all files and reset state */
116
126
  clearAll: () => void;
117
127
  /** Get only valid files ready for upload */
118
- getValidFiles: () => ProcessedFile[];
128
+ validFiles: ProcessedFile[];
119
129
  /** Update upload state for a specific file (status, progress, message) */
120
130
  updateFileStatus: (fileId: string, state: {
121
131
  status: FileStatus;
@@ -144,7 +154,6 @@ declare function useDrop(options: DropOptions): DropReturn;
144
154
  * Unified file processing utilities
145
155
  * Converts Files directly to ProcessedFiles
146
156
  */
147
-
148
157
  /**
149
158
  * Format file size to human-readable string
150
159
  * Re-exported from Ship SDK for convenience
@@ -166,16 +175,16 @@ declare function createProcessedFile(file: File, options?: {
166
175
  /** Custom path (defaults to webkitRelativePath or file.name) */
167
176
  path?: string;
168
177
  }): Promise<ProcessedFile>;
169
- /**
170
- * Get only the valid files (status: READY) from a list
171
- * Re-exported from Ship SDK for convenience
172
- */
173
- declare const getValidFiles: (files: ProcessedFile[]) => ProcessedFile[];
174
178
  /**
175
179
  * Strip common directory prefix from file paths
176
180
  * Only strips if ALL files share the same prefix
177
181
  */
178
182
  declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
183
+ /**
184
+ * Recursively traverse FileSystemEntry from drag & drop to collect all files
185
+ * Properly sets webkitRelativePath to preserve folder structure
186
+ */
187
+ declare function traverseFileTree(entry: FileSystemEntry, files: File[], currentPath?: string): Promise<void>;
179
188
 
180
189
  interface ZipExtractionResult {
181
190
  /** Extracted files as regular File objects */
@@ -203,4 +212,4 @@ declare function normalizePath(path: string): string;
203
212
  */
204
213
  declare function isZipFile(file: File): boolean;
205
214
 
206
- export { type ClientError, type DropOptions, type DropReturn, type DropState, type DropStateValue, type DropStatus, FILE_STATUSES, type FileStatus, type ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, getValidFiles, isZipFile, normalizePath, stripCommonPrefix, useDrop };
215
+ export { type ClientError, type DropOptions, type DropReturn, type DropState, type DropStateValue, type DropStatus, FILE_STATUSES, type FileStatus, type ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree, useDrop };
package/dist/index.d.ts CHANGED
@@ -62,6 +62,7 @@ type DropStateValue = 'idle' | 'dragging' | 'processing' | 'ready' | 'error';
62
62
  interface DropStatus {
63
63
  title: string;
64
64
  details: string;
65
+ errors?: string[];
65
66
  }
66
67
  /**
67
68
  * State machine state for the drop hook
@@ -84,12 +85,21 @@ interface DropOptions {
84
85
  stripPrefix?: boolean;
85
86
  }
86
87
  interface DropReturn {
87
- /** Current state of the drop hook */
88
- state: DropState;
88
+ /** Current phase of the state machine */
89
+ phase: DropStateValue;
89
90
  /** Whether currently processing files (ZIP extraction, etc.) */
90
91
  isProcessing: boolean;
91
92
  /** Whether user is currently dragging over the dropzone */
92
93
  isDragging: boolean;
94
+ /** Flattened access to files */
95
+ files: ProcessedFile[];
96
+ /** Flattened access to source name */
97
+ sourceName: string;
98
+ /** Flattened access to status */
99
+ status: {
100
+ title: string;
101
+ details: string;
102
+ } | null;
93
103
  /** Get props to spread on dropzone element (handles drag & drop) */
94
104
  getDropzoneProps: () => {
95
105
  onDragOver: (e: React.DragEvent) => void;
@@ -115,7 +125,7 @@ interface DropReturn {
115
125
  /** Clear all files and reset state */
116
126
  clearAll: () => void;
117
127
  /** Get only valid files ready for upload */
118
- getValidFiles: () => ProcessedFile[];
128
+ validFiles: ProcessedFile[];
119
129
  /** Update upload state for a specific file (status, progress, message) */
120
130
  updateFileStatus: (fileId: string, state: {
121
131
  status: FileStatus;
@@ -144,7 +154,6 @@ declare function useDrop(options: DropOptions): DropReturn;
144
154
  * Unified file processing utilities
145
155
  * Converts Files directly to ProcessedFiles
146
156
  */
147
-
148
157
  /**
149
158
  * Format file size to human-readable string
150
159
  * Re-exported from Ship SDK for convenience
@@ -166,16 +175,16 @@ declare function createProcessedFile(file: File, options?: {
166
175
  /** Custom path (defaults to webkitRelativePath or file.name) */
167
176
  path?: string;
168
177
  }): Promise<ProcessedFile>;
169
- /**
170
- * Get only the valid files (status: READY) from a list
171
- * Re-exported from Ship SDK for convenience
172
- */
173
- declare const getValidFiles: (files: ProcessedFile[]) => ProcessedFile[];
174
178
  /**
175
179
  * Strip common directory prefix from file paths
176
180
  * Only strips if ALL files share the same prefix
177
181
  */
178
182
  declare function stripCommonPrefix(files: ProcessedFile[]): ProcessedFile[];
183
+ /**
184
+ * Recursively traverse FileSystemEntry from drag & drop to collect all files
185
+ * Properly sets webkitRelativePath to preserve folder structure
186
+ */
187
+ declare function traverseFileTree(entry: FileSystemEntry, files: File[], currentPath?: string): Promise<void>;
179
188
 
180
189
  interface ZipExtractionResult {
181
190
  /** Extracted files as regular File objects */
@@ -203,4 +212,4 @@ declare function normalizePath(path: string): string;
203
212
  */
204
213
  declare function isZipFile(file: File): boolean;
205
214
 
206
- export { type ClientError, type DropOptions, type DropReturn, type DropState, type DropStateValue, type DropStatus, FILE_STATUSES, type FileStatus, type ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, getValidFiles, isZipFile, normalizePath, stripCommonPrefix, useDrop };
215
+ export { type ClientError, type DropOptions, type DropReturn, type DropState, type DropStateValue, type DropStatus, FILE_STATUSES, type FileStatus, type ProcessedFile, type ZipExtractionResult, createProcessedFile, extractZipToFiles, formatFileSize, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree, useDrop };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useState, useRef, useMemo, useCallback } from 'react';
2
- import { formatFileSize as formatFileSize$1, getValidFiles as getValidFiles$1, filterJunk, validateFiles } from '@shipstatic/ship';
2
+ import { formatFileSize as formatFileSize$1, getValidFiles, filterJunk, validateFiles } from '@shipstatic/ship';
3
3
 
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -11811,7 +11811,6 @@ async function createProcessedFile(file, options) {
11811
11811
  status: FILE_STATUSES.PENDING
11812
11812
  };
11813
11813
  }
11814
- var getValidFiles = getValidFiles$1;
11815
11814
  function stripCommonPrefix(files) {
11816
11815
  if (files.length === 0) return files;
11817
11816
  const paths = files.map((f) => f.path);
@@ -11827,10 +11826,20 @@ function stripCommonPrefix(files) {
11827
11826
  }
11828
11827
  if (commonDepth === 0) return files;
11829
11828
  const prefix = segments.slice(0, commonDepth).join("/") + "/";
11830
- return files.map((f) => ({
11831
- ...f,
11832
- path: f.path.startsWith(prefix) ? f.path.slice(prefix.length) : f.path
11833
- }));
11829
+ return files.map((f) => {
11830
+ const newPath = f.path.startsWith(prefix) ? f.path.slice(prefix.length) : f.path;
11831
+ if (f.file) {
11832
+ Object.defineProperty(f.file, "webkitRelativePath", {
11833
+ value: newPath,
11834
+ writable: false,
11835
+ configurable: true
11836
+ });
11837
+ }
11838
+ return {
11839
+ ...f,
11840
+ path: newPath
11841
+ };
11842
+ });
11834
11843
  }
11835
11844
  async function traverseFileTree(entry, files, currentPath = "") {
11836
11845
  try {
@@ -11841,7 +11850,8 @@ async function traverseFileTree(entry, files, currentPath = "") {
11841
11850
  const relativePath = currentPath ? `${currentPath}/${file.name}` : file.name;
11842
11851
  Object.defineProperty(file, "webkitRelativePath", {
11843
11852
  value: relativePath,
11844
- writable: false
11853
+ writable: false,
11854
+ configurable: true
11845
11855
  });
11846
11856
  files.push(file);
11847
11857
  } else if (entry.isDirectory) {
@@ -11886,6 +11896,7 @@ function useDrop(options) {
11886
11896
  const inputRef = useRef(null);
11887
11897
  const isProcessing = useMemo(() => state.value === "processing", [state.value]);
11888
11898
  const isDragging = useMemo(() => state.value === "dragging", [state.value]);
11899
+ const validFiles = useMemo(() => getValidFiles(state.files), [state.files]);
11889
11900
  const processFiles = useCallback(async (newFiles) => {
11890
11901
  if (isProcessingRef.current) {
11891
11902
  console.warn("File processing already in progress. Ignoring duplicate call.");
@@ -11951,7 +11962,11 @@ function useDrop(options) {
11951
11962
  value: "error",
11952
11963
  files: validation.files,
11953
11964
  sourceName: detectedSourceName,
11954
- status: { title: validation.error.error, details: validation.error.details }
11965
+ status: {
11966
+ title: validation.error.error,
11967
+ details: validation.error.details,
11968
+ errors: validation.error.errors
11969
+ }
11955
11970
  });
11956
11971
  onValidationError?.(validation.error);
11957
11972
  } else if (validation.validFiles.length > 0) {
@@ -11996,9 +12011,6 @@ function useDrop(options) {
11996
12011
  setState(initialState);
11997
12012
  isProcessingRef.current = false;
11998
12013
  }, []);
11999
- const getValidFilesCallback = useCallback(() => {
12000
- return getValidFiles(state.files);
12001
- }, [state.files]);
12002
12014
  const updateFileStatus = useCallback((fileId, fileState) => {
12003
12015
  setState((prev) => ({
12004
12016
  ...prev,
@@ -12028,21 +12040,21 @@ function useDrop(options) {
12028
12040
  e.preventDefault();
12029
12041
  const items = Array.from(e.dataTransfer.items);
12030
12042
  const files = [];
12031
- let hasEntries = false;
12043
+ const entriesToTraverse = [];
12032
12044
  for (const item of items) {
12033
12045
  if (item.kind === "file") {
12034
12046
  try {
12035
12047
  const entry = item.webkitGetAsEntry?.();
12036
- if (entry) {
12037
- hasEntries = true;
12038
- await traverseFileTree(
12039
- entry,
12040
- files,
12041
- entry.isDirectory ? entry.name : ""
12042
- );
12048
+ if (entry && entry.isDirectory) {
12049
+ entriesToTraverse.push({ entry, path: entry.name });
12043
12050
  } else {
12044
12051
  const file = item.getAsFile();
12045
12052
  if (file) {
12053
+ Object.defineProperty(file, "webkitRelativePath", {
12054
+ value: file.name,
12055
+ writable: false,
12056
+ configurable: true
12057
+ });
12046
12058
  files.push(file);
12047
12059
  }
12048
12060
  }
@@ -12055,7 +12067,12 @@ function useDrop(options) {
12055
12067
  }
12056
12068
  }
12057
12069
  }
12058
- if (!hasEntries && e.dataTransfer.files.length > 0) {
12070
+ if (entriesToTraverse.length > 0) {
12071
+ await Promise.all(entriesToTraverse.map(
12072
+ (item) => traverseFileTree(item.entry, files, item.path)
12073
+ ));
12074
+ }
12075
+ if (files.length === 0 && e.dataTransfer.files.length > 0) {
12059
12076
  files.push(...Array.from(e.dataTransfer.files));
12060
12077
  }
12061
12078
  if (files.length > 0) {
@@ -12089,10 +12106,13 @@ function useDrop(options) {
12089
12106
  }), [handleInputChange]);
12090
12107
  return {
12091
12108
  // State machine
12092
- state,
12093
12109
  // Convenience getters (computed from state)
12110
+ phase: state.value,
12094
12111
  isProcessing,
12095
12112
  isDragging,
12113
+ files: state.files,
12114
+ sourceName: state.sourceName,
12115
+ status: state.status,
12096
12116
  // Primary API: Prop getters
12097
12117
  getDropzoneProps,
12098
12118
  getInputProps,
@@ -12101,7 +12121,7 @@ function useDrop(options) {
12101
12121
  processFiles,
12102
12122
  clearAll,
12103
12123
  // Helpers
12104
- getValidFiles: getValidFilesCallback,
12124
+ validFiles,
12105
12125
  updateFileStatus
12106
12126
  };
12107
12127
  }
@@ -12129,6 +12149,6 @@ mime-db/index.js:
12129
12149
  *)
12130
12150
  */
12131
12151
 
12132
- export { FILE_STATUSES, createProcessedFile, extractZipToFiles, formatFileSize, getValidFiles, isZipFile, normalizePath, stripCommonPrefix, useDrop };
12152
+ export { FILE_STATUSES, createProcessedFile, extractZipToFiles, formatFileSize, isZipFile, normalizePath, stripCommonPrefix, traverseFileTree, useDrop };
12133
12153
  //# sourceMappingURL=index.js.map
12134
12154
  //# sourceMappingURL=index.js.map