@moontra/moonui-pro 2.11.2 → 2.11.4

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.ts CHANGED
@@ -1776,23 +1776,7 @@ interface FileUploadProProps {
1776
1776
  headers?: Record<string, string>;
1777
1777
  serviceConfig?: {
1778
1778
  type: 'aws-s3' | 'cloudinary' | 'firebase' | 'custom';
1779
- awsConfig?: {
1780
- region: string;
1781
- bucket: string;
1782
- accessKeyId?: string;
1783
- secretAccessKey?: string;
1784
- sessionToken?: string;
1785
- };
1786
- cloudinaryConfig?: {
1787
- cloudName: string;
1788
- uploadPreset: string;
1789
- apiKey?: string;
1790
- apiSecret?: string;
1791
- };
1792
- firebaseConfig?: {
1793
- storageBucket: string;
1794
- folder?: string;
1795
- };
1779
+ config?: any;
1796
1780
  };
1797
1781
  onUpload?: (files: FileUploadItem[]) => Promise<void>;
1798
1782
  onProgress?: (fileId: string, progress: number) => void;
package/dist/index.mjs CHANGED
@@ -59071,43 +59071,6 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59071
59071
  }
59072
59072
  return metadata;
59073
59073
  }, [duplicateCheck]);
59074
- const uploadToService = useCallback(async (fileItem) => {
59075
- if (!serviceConfig)
59076
- return null;
59077
- const { file } = fileItem;
59078
- switch (serviceConfig.type) {
59079
- case "aws-s3":
59080
- if (uploadStrategy === "presigned" && endpoint) {
59081
- const response = await fetch(endpoint, {
59082
- method: "PUT",
59083
- body: file,
59084
- headers: {
59085
- "Content-Type": file.type,
59086
- ...headers
59087
- }
59088
- });
59089
- return response.ok ? { url: response.url } : null;
59090
- }
59091
- break;
59092
- case "cloudinary":
59093
- if (serviceConfig.cloudinaryConfig) {
59094
- const { cloudName, uploadPreset } = serviceConfig.cloudinaryConfig;
59095
- const formData = new FormData();
59096
- formData.append("file", file);
59097
- formData.append("upload_preset", uploadPreset);
59098
- const response = await fetch(
59099
- `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`,
59100
- {
59101
- method: "POST",
59102
- body: formData
59103
- }
59104
- );
59105
- return response.json();
59106
- }
59107
- break;
59108
- }
59109
- return null;
59110
- }, [serviceConfig, uploadStrategy, endpoint, headers]);
59111
59074
  const resizeImage = useCallback(async (file) => {
59112
59075
  if (!imageResize || !file.type.startsWith("image/"))
59113
59076
  return file;
@@ -59155,6 +59118,166 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59155
59118
  reader.readAsDataURL(file);
59156
59119
  });
59157
59120
  }, [imageResize]);
59121
+ const uploadToService = useCallback(async (fileItem) => {
59122
+ if (!serviceConfig)
59123
+ return null;
59124
+ const { file } = fileItem;
59125
+ let processedFile = file;
59126
+ if (imageResize && file.type.startsWith("image/")) {
59127
+ processedFile = await resizeImage(file);
59128
+ }
59129
+ try {
59130
+ switch (serviceConfig.type) {
59131
+ case "aws-s3": {
59132
+ const { config } = serviceConfig;
59133
+ if (!config)
59134
+ throw new Error("AWS S3 config is required");
59135
+ const { bucketUrl, bucketName, region, accessKeyId, policy, signature, algorithm, credential, date, fields } = config;
59136
+ if (!bucketUrl && !bucketName) {
59137
+ throw new Error("AWS S3 requires either bucketUrl or bucketName");
59138
+ }
59139
+ if (bucketUrl && !bucketName) {
59140
+ const formData2 = new FormData();
59141
+ formData2.append("file", processedFile || file);
59142
+ const response2 = await fetch(bucketUrl, {
59143
+ method: "POST",
59144
+ body: formData2,
59145
+ headers: {
59146
+ ...headers,
59147
+ ...config.headers || {}
59148
+ }
59149
+ });
59150
+ if (!response2.ok) {
59151
+ throw new Error(`Upload failed: ${response2.statusText}`);
59152
+ }
59153
+ return await response2.json();
59154
+ }
59155
+ const s3Endpoint = bucketUrl || `https://${bucketName}.s3.${region || "us-east-1"}.amazonaws.com/`;
59156
+ const key = fields?.key || `uploads/${Date.now()}_${file.name}`;
59157
+ const formData = new FormData();
59158
+ if (fields) {
59159
+ Object.entries(fields).forEach(([k3, v]) => {
59160
+ if (k3 !== "file") {
59161
+ formData.append(k3, v);
59162
+ }
59163
+ });
59164
+ } else {
59165
+ formData.append("key", key);
59166
+ if (accessKeyId)
59167
+ formData.append("AWSAccessKeyId", accessKeyId);
59168
+ formData.append("Content-Type", file.type);
59169
+ if (policy)
59170
+ formData.append("policy", policy);
59171
+ if (signature)
59172
+ formData.append("signature", signature);
59173
+ if (algorithm)
59174
+ formData.append("x-amz-algorithm", algorithm);
59175
+ if (credential)
59176
+ formData.append("x-amz-credential", credential);
59177
+ if (date)
59178
+ formData.append("x-amz-date", date);
59179
+ }
59180
+ formData.append("file", processedFile || file);
59181
+ const response = await fetch(s3Endpoint, {
59182
+ method: "POST",
59183
+ body: formData
59184
+ });
59185
+ if (!response.ok && response.status !== 204) {
59186
+ const errorText = await response.text();
59187
+ throw new Error(`S3 upload failed: ${response.status} - ${errorText}`);
59188
+ }
59189
+ return {
59190
+ url: `${s3Endpoint}${key}`,
59191
+ key,
59192
+ bucket: bucketName,
59193
+ etag: response.headers.get("ETag"),
59194
+ location: response.headers.get("Location") || `${s3Endpoint}${key}`
59195
+ };
59196
+ }
59197
+ case "cloudinary": {
59198
+ const { config } = serviceConfig;
59199
+ if (!config)
59200
+ throw new Error("Cloudinary config is required");
59201
+ const { cloudName, uploadPreset, apiKey } = config;
59202
+ const formData = new FormData();
59203
+ formData.append("file", processedFile || file);
59204
+ formData.append("upload_preset", uploadPreset);
59205
+ if (apiKey) {
59206
+ formData.append("api_key", apiKey);
59207
+ }
59208
+ if (imageResize) {
59209
+ formData.append("eager", `w_${imageResize.maxWidth},h_${imageResize.maxHeight},c_limit,q_${Math.round(imageResize.quality * 100)}`);
59210
+ }
59211
+ const response = await fetch(
59212
+ `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`,
59213
+ {
59214
+ method: "POST",
59215
+ body: formData
59216
+ }
59217
+ );
59218
+ if (!response.ok)
59219
+ throw new Error("Cloudinary upload failed");
59220
+ const result = await response.json();
59221
+ return {
59222
+ url: result.secure_url,
59223
+ publicId: result.public_id,
59224
+ format: result.format,
59225
+ width: result.width,
59226
+ height: result.height,
59227
+ bytes: result.bytes,
59228
+ cloudName
59229
+ };
59230
+ }
59231
+ case "firebase": {
59232
+ const { config } = serviceConfig;
59233
+ if (!config)
59234
+ throw new Error("Firebase config is required");
59235
+ const { storageBucket, folder = "uploads" } = config;
59236
+ const fileName = `${folder}/${Date.now()}-${file.name}`;
59237
+ const uploadUrl = `https://storage.googleapis.com/upload/storage/v1/b/${storageBucket}/o?uploadType=media&name=${encodeURIComponent(fileName)}`;
59238
+ const response = await fetch(uploadUrl, {
59239
+ method: "POST",
59240
+ body: processedFile || file,
59241
+ headers: {
59242
+ "Content-Type": file.type,
59243
+ ...headers
59244
+ // Should include Authorization: Bearer [token]
59245
+ }
59246
+ });
59247
+ if (!response.ok)
59248
+ throw new Error("Firebase upload failed");
59249
+ const result = await response.json();
59250
+ return {
59251
+ url: `https://storage.googleapis.com/${storageBucket}/${fileName}`,
59252
+ name: result.name,
59253
+ bucket: result.bucket,
59254
+ generation: result.generation,
59255
+ contentType: result.contentType,
59256
+ size: result.size
59257
+ };
59258
+ }
59259
+ case "custom": {
59260
+ if (!endpoint)
59261
+ throw new Error("Custom endpoint is required");
59262
+ const formData = new FormData();
59263
+ formData.append("file", file);
59264
+ const response = await fetch(endpoint, {
59265
+ method: "POST",
59266
+ body: formData,
59267
+ headers
59268
+ });
59269
+ if (!response.ok)
59270
+ throw new Error("Custom upload failed");
59271
+ return response.json();
59272
+ }
59273
+ default:
59274
+ throw new Error(`Unsupported service type: ${serviceConfig.type}`);
59275
+ }
59276
+ } catch (error2) {
59277
+ console.error("Upload service error:", error2);
59278
+ throw error2;
59279
+ }
59280
+ }, [serviceConfig, endpoint, headers, imageResize, resizeImage]);
59158
59281
  const uploadFileChunked = useCallback(async (fileItem) => {
59159
59282
  const { file } = fileItem;
59160
59283
  const chunks = [];
@@ -59176,14 +59299,23 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59176
59299
  let uploadedBytes = 0;
59177
59300
  const startTime = Date.now();
59178
59301
  try {
59302
+ let processedFile = file;
59303
+ if (imageResize && file.type.startsWith("image/")) {
59304
+ processedFile = await resizeImage(file);
59305
+ }
59306
+ if (serviceConfig) {
59307
+ const uploadResult = await uploadToService({ ...fileItem, file: processedFile });
59308
+ setFiles((prev) => prev.map(
59309
+ (f) => f.id === fileItem.id ? { ...f, status: "success", progress: 100, result: uploadResult } : f
59310
+ ));
59311
+ onComplete?.(fileItem.id, uploadResult);
59312
+ return;
59313
+ }
59179
59314
  for (const chunk of chunks) {
59180
59315
  if (abortController.signal.aborted) {
59181
59316
  throw new Error("Upload cancelled");
59182
59317
  }
59183
- const serviceResult = await uploadToService(fileItem);
59184
- if (!serviceResult) {
59185
- await new Promise((resolve) => setTimeout(resolve, 100 + Math.random() * 200));
59186
- }
59318
+ await new Promise((resolve) => setTimeout(resolve, 100 + Math.random() * 200));
59187
59319
  uploadedBytes += chunk.end - chunk.start;
59188
59320
  const progress = Math.round(uploadedBytes / file.size * 100);
59189
59321
  const elapsedTime = (Date.now() - startTime) / 1e3;
@@ -59215,7 +59347,7 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59215
59347
  } finally {
59216
59348
  uploadQueue.current.delete(fileItem.id);
59217
59349
  }
59218
- }, [chunkSize, onProgress, onComplete, onError]);
59350
+ }, [chunkSize, onProgress, onComplete, onError, serviceConfig, uploadToService, resizeImage, imageResize]);
59219
59351
  const processFiles = useCallback(async (fileList) => {
59220
59352
  const fileArray = Array.from(fileList);
59221
59353
  setError(null);
@@ -59616,7 +59748,9 @@ var FileUploadItem = ({
59616
59748
  ] }),
59617
59749
  /* @__PURE__ */ jsxs("div", { className: cn(
59618
59750
  "flex-1 min-w-0",
59619
- variant === "grid" && "text-center"
59751
+ variant === "grid" && "text-center",
59752
+ allowBulkOperations && variant !== "grid" && "ml-8"
59753
+ // Add margin when checkbox is present
59620
59754
  ), children: [
59621
59755
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
59622
59756
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.11.2",
3
+ "version": "2.11.4",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -81,23 +81,7 @@ export interface FileUploadProProps {
81
81
  // Service integrations
82
82
  serviceConfig?: {
83
83
  type: 'aws-s3' | 'cloudinary' | 'firebase' | 'custom'
84
- awsConfig?: {
85
- region: string
86
- bucket: string
87
- accessKeyId?: string
88
- secretAccessKey?: string
89
- sessionToken?: string
90
- }
91
- cloudinaryConfig?: {
92
- cloudName: string
93
- uploadPreset: string
94
- apiKey?: string
95
- apiSecret?: string
96
- }
97
- firebaseConfig?: {
98
- storageBucket: string
99
- folder?: string
100
- }
84
+ config?: any
101
85
  }
102
86
 
103
87
  // Callbacks
@@ -614,56 +598,6 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
614
598
  return metadata
615
599
  }, [duplicateCheck])
616
600
 
617
- // Service specific upload handler
618
- const uploadToService = useCallback(async (fileItem: FileUploadItem): Promise<any> => {
619
- if (!serviceConfig) return null
620
-
621
- const { file } = fileItem
622
-
623
- switch (serviceConfig.type) {
624
- case 'aws-s3':
625
- // AWS S3 upload logic
626
- if (uploadStrategy === 'presigned' && endpoint) {
627
- const response = await fetch(endpoint, {
628
- method: 'PUT',
629
- body: file,
630
- headers: {
631
- 'Content-Type': file.type,
632
- ...headers
633
- }
634
- })
635
- return response.ok ? { url: response.url } : null
636
- }
637
- break
638
-
639
- case 'cloudinary':
640
- // Cloudinary upload logic
641
- if (serviceConfig.cloudinaryConfig) {
642
- const { cloudName, uploadPreset } = serviceConfig.cloudinaryConfig
643
- const formData = new FormData()
644
- formData.append('file', file)
645
- formData.append('upload_preset', uploadPreset)
646
-
647
- const response = await fetch(
648
- `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`,
649
- {
650
- method: 'POST',
651
- body: formData
652
- }
653
- )
654
- return response.json()
655
- }
656
- break
657
-
658
- case 'firebase':
659
- // Firebase upload would be handled by the onUpload callback
660
- // as it requires Firebase SDK integration
661
- break
662
- }
663
-
664
- return null
665
- }, [serviceConfig, uploadStrategy, endpoint, headers])
666
-
667
601
  // Image resize handler
668
602
  const resizeImage = useCallback(async (file: File): Promise<File> => {
669
603
  if (!imageResize || !file.type.startsWith('image/')) return file
@@ -722,6 +656,202 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
722
656
  reader.readAsDataURL(file)
723
657
  })
724
658
  }, [imageResize])
659
+
660
+ // Service specific upload handler
661
+ const uploadToService = useCallback(async (fileItem: FileUploadItem): Promise<any> => {
662
+ if (!serviceConfig) return null
663
+
664
+ const { file } = fileItem
665
+ let processedFile = file
666
+
667
+ // Resize image if needed
668
+ if (imageResize && file.type.startsWith('image/')) {
669
+ processedFile = await resizeImage(file)
670
+ }
671
+
672
+ try {
673
+ switch (serviceConfig.type) {
674
+ case 'aws-s3': {
675
+ // AWS S3 Direct Upload
676
+ const { config } = serviceConfig as any
677
+ if (!config) throw new Error('AWS S3 config is required')
678
+
679
+ const { bucketUrl, bucketName, region, accessKeyId, policy, signature, algorithm, credential, date, fields } = config
680
+
681
+ if (!bucketUrl && !bucketName) {
682
+ throw new Error('AWS S3 requires either bucketUrl or bucketName')
683
+ }
684
+
685
+ // Option 1: Direct upload to custom S3-compatible endpoint
686
+ if (bucketUrl && !bucketName) {
687
+ const formData = new FormData()
688
+ formData.append('file', processedFile || file)
689
+
690
+ const response = await fetch(bucketUrl, {
691
+ method: 'POST',
692
+ body: formData,
693
+ headers: {
694
+ ...headers,
695
+ ...(config.headers || {})
696
+ }
697
+ })
698
+
699
+ if (!response.ok) {
700
+ throw new Error(`Upload failed: ${response.statusText}`)
701
+ }
702
+
703
+ return await response.json()
704
+ }
705
+
706
+ // Option 2: AWS S3 POST upload with policy-based authentication
707
+ // This requires server-side generation of policy and signature
708
+ const s3Endpoint = bucketUrl || `https://${bucketName}.s3.${region || 'us-east-1'}.amazonaws.com/`
709
+ const key = fields?.key || `uploads/${Date.now()}_${file.name}`
710
+
711
+ const formData = new FormData()
712
+
713
+ // AWS S3 POST policy fields must be added in specific order
714
+ if (fields) {
715
+ // Add all policy fields first
716
+ Object.entries(fields).forEach(([k, v]) => {
717
+ if (k !== 'file') {
718
+ formData.append(k, v as string)
719
+ }
720
+ })
721
+ } else {
722
+ // Basic fields for public bucket upload
723
+ formData.append('key', key)
724
+ if (accessKeyId) formData.append('AWSAccessKeyId', accessKeyId)
725
+ formData.append('Content-Type', file.type)
726
+ if (policy) formData.append('policy', policy)
727
+ if (signature) formData.append('signature', signature)
728
+ if (algorithm) formData.append('x-amz-algorithm', algorithm)
729
+ if (credential) formData.append('x-amz-credential', credential)
730
+ if (date) formData.append('x-amz-date', date)
731
+ }
732
+
733
+ // File must be the last field
734
+ formData.append('file', processedFile || file)
735
+
736
+ const response = await fetch(s3Endpoint, {
737
+ method: 'POST',
738
+ body: formData
739
+ })
740
+
741
+ // S3 returns 204 No Content on success for POST uploads
742
+ if (!response.ok && response.status !== 204) {
743
+ const errorText = await response.text()
744
+ throw new Error(`S3 upload failed: ${response.status} - ${errorText}`)
745
+ }
746
+
747
+ return {
748
+ url: `${s3Endpoint}${key}`,
749
+ key,
750
+ bucket: bucketName,
751
+ etag: response.headers.get('ETag'),
752
+ location: response.headers.get('Location') || `${s3Endpoint}${key}`
753
+ }
754
+ }
755
+
756
+ case 'cloudinary': {
757
+ // Cloudinary upload logic
758
+ const { config } = serviceConfig as any
759
+ if (!config) throw new Error('Cloudinary config is required')
760
+
761
+ const { cloudName, uploadPreset, apiKey } = config
762
+ const formData = new FormData()
763
+ formData.append('file', processedFile || file)
764
+ formData.append('upload_preset', uploadPreset)
765
+
766
+ if (apiKey) {
767
+ formData.append('api_key', apiKey)
768
+ }
769
+
770
+ // Add optional transformations
771
+ if (imageResize) {
772
+ formData.append('eager', `w_${imageResize.maxWidth},h_${imageResize.maxHeight},c_limit,q_${Math.round(imageResize.quality * 100)}`)
773
+ }
774
+
775
+ const response = await fetch(
776
+ `https://api.cloudinary.com/v1_1/${cloudName}/auto/upload`,
777
+ {
778
+ method: 'POST',
779
+ body: formData
780
+ }
781
+ )
782
+
783
+ if (!response.ok) throw new Error('Cloudinary upload failed')
784
+ const result = await response.json()
785
+
786
+ return {
787
+ url: result.secure_url,
788
+ publicId: result.public_id,
789
+ format: result.format,
790
+ width: result.width,
791
+ height: result.height,
792
+ bytes: result.bytes,
793
+ cloudName
794
+ }
795
+ }
796
+
797
+ case 'firebase': {
798
+ // Firebase Storage REST API upload (no SDK required)
799
+ const { config } = serviceConfig as any
800
+ if (!config) throw new Error('Firebase config is required')
801
+
802
+ const { storageBucket, folder = 'uploads' } = config
803
+ const fileName = `${folder}/${Date.now()}-${file.name}`
804
+
805
+ // Firebase Storage uses Google Cloud Storage REST API
806
+ const uploadUrl = `https://storage.googleapis.com/upload/storage/v1/b/${storageBucket}/o?uploadType=media&name=${encodeURIComponent(fileName)}`
807
+
808
+ const response = await fetch(uploadUrl, {
809
+ method: 'POST',
810
+ body: processedFile || file,
811
+ headers: {
812
+ 'Content-Type': file.type,
813
+ ...headers // Should include Authorization: Bearer [token]
814
+ }
815
+ })
816
+
817
+ if (!response.ok) throw new Error('Firebase upload failed')
818
+ const result = await response.json()
819
+
820
+ return {
821
+ url: `https://storage.googleapis.com/${storageBucket}/${fileName}`,
822
+ name: result.name,
823
+ bucket: result.bucket,
824
+ generation: result.generation,
825
+ contentType: result.contentType,
826
+ size: result.size
827
+ }
828
+ }
829
+
830
+ case 'custom': {
831
+ // Custom endpoint upload
832
+ if (!endpoint) throw new Error('Custom endpoint is required')
833
+
834
+ const formData = new FormData()
835
+ formData.append('file', file)
836
+
837
+ const response = await fetch(endpoint, {
838
+ method: 'POST',
839
+ body: formData,
840
+ headers: headers
841
+ })
842
+
843
+ if (!response.ok) throw new Error('Custom upload failed')
844
+ return response.json()
845
+ }
846
+
847
+ default:
848
+ throw new Error(`Unsupported service type: ${serviceConfig.type}`)
849
+ }
850
+ } catch (error) {
851
+ console.error('Upload service error:', error)
852
+ throw error
853
+ }
854
+ }, [serviceConfig, endpoint, headers, imageResize, resizeImage])
725
855
 
726
856
  // Chunked upload simülasyonu
727
857
  const uploadFileChunked = useCallback(async (fileItem: FileUploadItem) => {
@@ -754,19 +884,34 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
754
884
  const startTime = Date.now()
755
885
 
756
886
  try {
757
- // Chunk'ları sırayla yükle
887
+ // Image resize if needed
888
+ let processedFile = file
889
+ if (imageResize && file.type.startsWith('image/')) {
890
+ processedFile = await resizeImage(file)
891
+ }
892
+
893
+ // If service config exists, do the actual upload
894
+ if (serviceConfig) {
895
+ const uploadResult = await uploadToService({ ...fileItem, file: processedFile })
896
+
897
+ // Update progress to 100% immediately for service uploads
898
+ setFiles(prev => prev.map(f =>
899
+ f.id === fileItem.id
900
+ ? { ...f, status: 'success', progress: 100, result: uploadResult }
901
+ : f
902
+ ))
903
+
904
+ onComplete?.(fileItem.id, uploadResult)
905
+ return
906
+ }
907
+
908
+ // Regular chunk upload simulation for non-service uploads
758
909
  for (const chunk of chunks) {
759
910
  if (abortController.signal.aborted) {
760
911
  throw new Error('Upload cancelled')
761
912
  }
762
913
 
763
- // Try service-specific upload first
764
- const serviceResult = await uploadToService(fileItem)
765
-
766
- if (!serviceResult) {
767
- // Fallback to chunk upload simulation
768
- await new Promise(resolve => setTimeout(resolve, 100 + Math.random() * 200))
769
- }
914
+ await new Promise(resolve => setTimeout(resolve, 100 + Math.random() * 200))
770
915
 
771
916
  uploadedBytes += (chunk.end - chunk.start)
772
917
  const progress = Math.round((uploadedBytes / file.size) * 100)
@@ -815,7 +960,7 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
815
960
  } finally {
816
961
  uploadQueue.current.delete(fileItem.id)
817
962
  }
818
- }, [chunkSize, onProgress, onComplete, onError])
963
+ }, [chunkSize, onProgress, onComplete, onError, serviceConfig, uploadToService, resizeImage, imageResize])
819
964
 
820
965
  // Dosya işleme
821
966
  const processFiles = useCallback(async (fileList: FileList | File[]) => {
@@ -1304,7 +1449,8 @@ const FileUploadItem = ({
1304
1449
  {/* File Info */}
1305
1450
  <div className={cn(
1306
1451
  "flex-1 min-w-0",
1307
- variant === 'grid' && "text-center"
1452
+ variant === 'grid' && "text-center",
1453
+ allowBulkOperations && variant !== 'grid' && "ml-8" // Add margin when checkbox is present
1308
1454
  )}>
1309
1455
  <div className="flex items-start justify-between gap-2">
1310
1456
  <div className="flex-1 min-w-0">