@moontra/moonui-pro 2.11.1 → 2.11.3

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
@@ -58976,6 +58976,10 @@ var MoonUIFileUploadPro = t__default.forwardRef(
58976
58976
  onPreview,
58977
58977
  onBulkSelect,
58978
58978
  customValidation,
58979
+ serviceConfig,
58980
+ imageResize,
58981
+ endpoint,
58982
+ headers,
58979
58983
  ...props
58980
58984
  }, ref) => {
58981
58985
  const { hasProAccess, isLoading } = useSubscription();
@@ -59067,6 +59071,213 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59067
59071
  }
59068
59072
  return metadata;
59069
59073
  }, [duplicateCheck]);
59074
+ const resizeImage = useCallback(async (file) => {
59075
+ if (!imageResize || !file.type.startsWith("image/"))
59076
+ return file;
59077
+ const { maxWidth, maxHeight, quality } = imageResize;
59078
+ return new Promise((resolve) => {
59079
+ const img = new Image();
59080
+ const reader = new FileReader();
59081
+ reader.onload = (e) => {
59082
+ img.src = e.target?.result;
59083
+ img.onload = () => {
59084
+ const canvas = document.createElement("canvas");
59085
+ const ctx = canvas.getContext("2d");
59086
+ let width = img.width;
59087
+ let height = img.height;
59088
+ if (width > maxWidth || height > maxHeight) {
59089
+ const aspectRatio = width / height;
59090
+ if (width > height) {
59091
+ width = maxWidth;
59092
+ height = maxWidth / aspectRatio;
59093
+ } else {
59094
+ height = maxHeight;
59095
+ width = maxHeight * aspectRatio;
59096
+ }
59097
+ }
59098
+ canvas.width = width;
59099
+ canvas.height = height;
59100
+ ctx.drawImage(img, 0, 0, width, height);
59101
+ canvas.toBlob(
59102
+ (blob) => {
59103
+ if (blob) {
59104
+ const resizedFile = new window.File([blob], file.name, {
59105
+ type: file.type,
59106
+ lastModified: Date.now()
59107
+ });
59108
+ resolve(resizedFile);
59109
+ } else {
59110
+ resolve(file);
59111
+ }
59112
+ },
59113
+ file.type,
59114
+ quality
59115
+ );
59116
+ };
59117
+ };
59118
+ reader.readAsDataURL(file);
59119
+ });
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]);
59070
59281
  const uploadFileChunked = useCallback(async (fileItem) => {
59071
59282
  const { file } = fileItem;
59072
59283
  const chunks = [];
@@ -59088,6 +59299,18 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59088
59299
  let uploadedBytes = 0;
59089
59300
  const startTime = Date.now();
59090
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
+ }
59091
59314
  for (const chunk of chunks) {
59092
59315
  if (abortController.signal.aborted) {
59093
59316
  throw new Error("Upload cancelled");
@@ -59124,7 +59347,7 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59124
59347
  } finally {
59125
59348
  uploadQueue.current.delete(fileItem.id);
59126
59349
  }
59127
- }, [chunkSize, onProgress, onComplete, onError]);
59350
+ }, [chunkSize, onProgress, onComplete, onError, serviceConfig, uploadToService, resizeImage, imageResize]);
59128
59351
  const processFiles = useCallback(async (fileList) => {
59129
59352
  const fileArray = Array.from(fileList);
59130
59353
  setError(null);
@@ -59163,14 +59386,15 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59163
59386
  const newFileItems = [];
59164
59387
  for (const file of validFiles) {
59165
59388
  const id = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
59166
- const preview = await createPreview(file);
59167
- const metadata = await createMetadata(file);
59389
+ const processedFile = await resizeImage(file);
59390
+ const preview = await createPreview(processedFile);
59391
+ const metadata = await createMetadata(processedFile);
59168
59392
  newFileItems.push({
59169
59393
  id,
59170
- file,
59394
+ file: processedFile,
59171
59395
  status: "pending",
59172
59396
  progress: 0,
59173
- totalBytes: file.size,
59397
+ totalBytes: processedFile.size,
59174
59398
  preview,
59175
59399
  metadata
59176
59400
  });
@@ -59196,7 +59420,8 @@ var MoonUIFileUploadPro = t__default.forwardRef(
59196
59420
  createPreview,
59197
59421
  createMetadata,
59198
59422
  onUpload,
59199
- uploadFileChunked
59423
+ uploadFileChunked,
59424
+ resizeImage
59200
59425
  ]);
59201
59426
  const handleDrop = useCallback((e) => {
59202
59427
  e.preventDefault();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.11.1",
3
+ "version": "2.11.3",
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
@@ -477,6 +461,10 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
477
461
  onPreview,
478
462
  onBulkSelect,
479
463
  customValidation,
464
+ serviceConfig,
465
+ imageResize,
466
+ endpoint,
467
+ headers,
480
468
  ...props
481
469
  }, ref) => {
482
470
 
@@ -610,6 +598,261 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
610
598
  return metadata
611
599
  }, [duplicateCheck])
612
600
 
601
+ // Image resize handler
602
+ const resizeImage = useCallback(async (file: File): Promise<File> => {
603
+ if (!imageResize || !file.type.startsWith('image/')) return file
604
+
605
+ const { maxWidth, maxHeight, quality } = imageResize
606
+
607
+ return new Promise((resolve) => {
608
+ const img = new Image()
609
+ const reader = new FileReader()
610
+
611
+ reader.onload = (e) => {
612
+ img.src = e.target?.result as string
613
+
614
+ img.onload = () => {
615
+ const canvas = document.createElement('canvas')
616
+ const ctx = canvas.getContext('2d')!
617
+
618
+ let width = img.width
619
+ let height = img.height
620
+
621
+ // Calculate new dimensions
622
+ if (width > maxWidth || height > maxHeight) {
623
+ const aspectRatio = width / height
624
+ if (width > height) {
625
+ width = maxWidth
626
+ height = maxWidth / aspectRatio
627
+ } else {
628
+ height = maxHeight
629
+ width = maxHeight * aspectRatio
630
+ }
631
+ }
632
+
633
+ canvas.width = width
634
+ canvas.height = height
635
+ ctx.drawImage(img, 0, 0, width, height)
636
+
637
+ canvas.toBlob(
638
+ (blob) => {
639
+ if (blob) {
640
+ // Create a resized file
641
+ const resizedFile = new window.File([blob], file.name, {
642
+ type: file.type,
643
+ lastModified: Date.now()
644
+ })
645
+ resolve(resizedFile)
646
+ } else {
647
+ resolve(file)
648
+ }
649
+ },
650
+ file.type,
651
+ quality
652
+ )
653
+ }
654
+ }
655
+
656
+ reader.readAsDataURL(file)
657
+ })
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])
855
+
613
856
  // Chunked upload simülasyonu
614
857
  const uploadFileChunked = useCallback(async (fileItem: FileUploadItem) => {
615
858
  const { file } = fileItem
@@ -641,13 +884,33 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
641
884
  const startTime = Date.now()
642
885
 
643
886
  try {
644
- // 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
645
909
  for (const chunk of chunks) {
646
910
  if (abortController.signal.aborted) {
647
911
  throw new Error('Upload cancelled')
648
912
  }
649
913
 
650
- // Chunk upload simülasyonu
651
914
  await new Promise(resolve => setTimeout(resolve, 100 + Math.random() * 200))
652
915
 
653
916
  uploadedBytes += (chunk.end - chunk.start)
@@ -697,7 +960,7 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
697
960
  } finally {
698
961
  uploadQueue.current.delete(fileItem.id)
699
962
  }
700
- }, [chunkSize, onProgress, onComplete, onError])
963
+ }, [chunkSize, onProgress, onComplete, onError, serviceConfig, uploadToService, resizeImage, imageResize])
701
964
 
702
965
  // Dosya işleme
703
966
  const processFiles = useCallback(async (fileList: FileList | File[]) => {
@@ -752,15 +1015,19 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
752
1015
 
753
1016
  for (const file of validFiles) {
754
1017
  const id = `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`
755
- const preview = await createPreview(file)
756
- const metadata = await createMetadata(file)
1018
+
1019
+ // Resize image if needed
1020
+ const processedFile = await resizeImage(file)
1021
+
1022
+ const preview = await createPreview(processedFile)
1023
+ const metadata = await createMetadata(processedFile)
757
1024
 
758
1025
  newFileItems.push({
759
1026
  id,
760
- file,
1027
+ file: processedFile,
761
1028
  status: 'pending',
762
1029
  progress: 0,
763
- totalBytes: file.size,
1030
+ totalBytes: processedFile.size,
764
1031
  preview,
765
1032
  metadata
766
1033
  })
@@ -790,7 +1057,8 @@ export const MoonUIFileUploadPro = React.forwardRef<HTMLDivElement, FileUploadPr
790
1057
  createPreview,
791
1058
  createMetadata,
792
1059
  onUpload,
793
- uploadFileChunked
1060
+ uploadFileChunked,
1061
+ resizeImage
794
1062
  ])
795
1063
 
796
1064
  // Drag & Drop handlers