@tradly/asset 1.0.16 → 1.0.18

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.
@@ -249,7 +249,7 @@ var MediaApiService = /*#__PURE__*/function () {
249
249
  key: "uploadMedia",
250
250
  value: (function () {
251
251
  var _uploadMedia = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(files, authKey) {
252
- var auth_key, all_files_uri, upload_files, upload_full_files, i, element, file_data, responseFiles, index, path, fileURI, originalFile, fileBody, fileResponse, blob, res, mediaData, _t3, _t4;
252
+ var auth_key, all_files_uri, upload_files, upload_full_files, i, element, file_data, responseFiles, index, path, fileURI, originalFile, fileBody, uri, fileResponse, blob, res, mediaData, _t3, _t4, _t5;
253
253
  return _regenerator().w(function (_context4) {
254
254
  while (1) switch (_context4.p = _context4.n) {
255
255
  case 0:
@@ -266,7 +266,7 @@ var MediaApiService = /*#__PURE__*/function () {
266
266
  i = 0;
267
267
  case 2:
268
268
  if (!(i < files.length)) {
269
- _context4.n = 17;
269
+ _context4.n = 21;
270
270
  break;
271
271
  }
272
272
  element = files[i]; // Check if file already has a path (from previous upload)
@@ -284,7 +284,7 @@ var MediaApiService = /*#__PURE__*/function () {
284
284
 
285
285
  // Upload files when we've processed all files
286
286
  if (!(files.length === i + 1 && upload_files.length > 0)) {
287
- _context4.n = 16;
287
+ _context4.n = 20;
288
288
  break;
289
289
  }
290
290
  _context4.p = 3;
@@ -295,7 +295,7 @@ var MediaApiService = /*#__PURE__*/function () {
295
295
  index = 0;
296
296
  case 5:
297
297
  if (!(index < responseFiles.length)) {
298
- _context4.n = 13;
298
+ _context4.n = 17;
299
299
  break;
300
300
  }
301
301
  path = responseFiles[index].signedUrl;
@@ -305,20 +305,46 @@ var MediaApiService = /*#__PURE__*/function () {
305
305
  fileBody = originalFile; // Handle React Native file URIs
306
306
  // If file has a uri property, it's from React Native - fetch it first
307
307
  if (!(originalFile.uri && typeof originalFile.uri === "string")) {
308
- _context4.n = 9;
308
+ _context4.n = 13;
309
309
  break;
310
310
  }
311
- _context4.n = 7;
312
- return fetch(originalFile.uri);
313
- case 7:
314
- fileResponse = _context4.v;
311
+ // For React Native, handle file://, content://, or http:// URIs
312
+ uri = originalFile.uri;
313
+ _context4.p = 7;
315
314
  _context4.n = 8;
316
- return fileResponse.blob();
315
+ return fetch(uri);
317
316
  case 8:
317
+ fileResponse = _context4.v;
318
+ if (!fileResponse.blob) {
319
+ _context4.n = 10;
320
+ break;
321
+ }
322
+ _context4.n = 9;
323
+ return fileResponse.blob();
324
+ case 9:
318
325
  blob = _context4.v;
319
326
  fileBody = blob;
320
- case 9:
321
- _context4.n = 10;
327
+ _context4.n = 11;
328
+ break;
329
+ case 10:
330
+ // Fallback: use the response as-is if blob() is not available
331
+ // Some React Native versions might need different handling
332
+ fileBody = fileResponse;
333
+ case 11:
334
+ _context4.n = 13;
335
+ break;
336
+ case 12:
337
+ _context4.p = 12;
338
+ _t3 = _context4.v;
339
+ // If fetch fails, try using the URI directly
340
+ // Some React Native environments might handle this differently
341
+ console.warn("Fetch failed for URI, trying direct upload:", _t3);
342
+ // For S3 PUT, we need the actual file content
343
+ // If fetch fails, we'll try to use the file object directly
344
+ // This might require additional React Native file handling libraries
345
+ throw new Error("Failed to read file from URI: ".concat(uri, ". Make sure the file URI is accessible. Error: ").concat(_t3.message));
346
+ case 13:
347
+ _context4.n = 14;
322
348
  return fetch(path, {
323
349
  method: "PUT",
324
350
  headers: {
@@ -326,26 +352,26 @@ var MediaApiService = /*#__PURE__*/function () {
326
352
  },
327
353
  body: fileBody
328
354
  });
329
- case 10:
355
+ case 14:
330
356
  res = _context4.v;
331
357
  if (res.ok) {
332
358
  all_files_uri.push(fileURI);
333
359
  } else {
334
360
  console.error("Failed to upload file ".concat(index + 1));
335
361
  }
336
- _context4.n = 12;
362
+ _context4.n = 16;
337
363
  break;
338
- case 11:
339
- _context4.p = 11;
340
- _t3 = _context4.v;
341
- console.error("Error uploading file ".concat(index + 1, ":"), _t3);
342
- case 12:
364
+ case 15:
365
+ _context4.p = 15;
366
+ _t4 = _context4.v;
367
+ console.error("Error uploading file ".concat(index + 1, ":"), _t4);
368
+ case 16:
343
369
  index++;
344
370
  _context4.n = 5;
345
371
  break;
346
- case 13:
372
+ case 17:
347
373
  if (!(all_files_uri.length > 0)) {
348
- _context4.n = 14;
374
+ _context4.n = 18;
349
375
  break;
350
376
  }
351
377
  mediaData = all_files_uri.map(function (url, index) {
@@ -358,7 +384,7 @@ var MediaApiService = /*#__PURE__*/function () {
358
384
  mime_type: originalFile.type
359
385
  };
360
386
  }); // Save to media API - POST /v1/media with { media: [...] }
361
- _context4.n = 14;
387
+ _context4.n = 18;
362
388
  return this.apiCall({
363
389
  method: "POST",
364
390
  path: "/v1/media",
@@ -366,25 +392,25 @@ var MediaApiService = /*#__PURE__*/function () {
366
392
  media: mediaData
367
393
  }
368
394
  });
369
- case 14:
370
- _context4.n = 16;
395
+ case 18:
396
+ _context4.n = 20;
371
397
  break;
372
- case 15:
373
- _context4.p = 15;
374
- _t4 = _context4.v;
375
- console.error("Upload error:", _t4);
398
+ case 19:
399
+ _context4.p = 19;
400
+ _t5 = _context4.v;
401
+ console.error("Upload error:", _t5);
376
402
  if (this.onError) {
377
- this.onError(_t4);
403
+ this.onError(_t5);
378
404
  }
379
- throw _t4;
380
- case 16:
405
+ throw _t5;
406
+ case 20:
381
407
  i++;
382
408
  _context4.n = 2;
383
409
  break;
384
- case 17:
410
+ case 21:
385
411
  return _context4.a(2, all_files_uri);
386
412
  }
387
- }, _callee4, this, [[6, 11], [3, 15]]);
413
+ }, _callee4, this, [[7, 12], [6, 15], [3, 19]]);
388
414
  }));
389
415
  function uploadMedia(_x5, _x6) {
390
416
  return _uploadMedia.apply(this, arguments);
@@ -243,7 +243,7 @@ var MediaApiService = /*#__PURE__*/function () {
243
243
  key: "uploadMedia",
244
244
  value: (function () {
245
245
  var _uploadMedia = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(files, authKey) {
246
- var auth_key, all_files_uri, upload_files, upload_full_files, i, element, file_data, responseFiles, index, path, fileURI, originalFile, fileBody, fileResponse, blob, res, mediaData, _t3, _t4;
246
+ var auth_key, all_files_uri, upload_files, upload_full_files, i, element, file_data, responseFiles, index, path, fileURI, originalFile, fileBody, uri, fileResponse, blob, res, mediaData, _t3, _t4, _t5;
247
247
  return _regenerator().w(function (_context4) {
248
248
  while (1) switch (_context4.p = _context4.n) {
249
249
  case 0:
@@ -260,7 +260,7 @@ var MediaApiService = /*#__PURE__*/function () {
260
260
  i = 0;
261
261
  case 2:
262
262
  if (!(i < files.length)) {
263
- _context4.n = 17;
263
+ _context4.n = 21;
264
264
  break;
265
265
  }
266
266
  element = files[i]; // Check if file already has a path (from previous upload)
@@ -278,7 +278,7 @@ var MediaApiService = /*#__PURE__*/function () {
278
278
 
279
279
  // Upload files when we've processed all files
280
280
  if (!(files.length === i + 1 && upload_files.length > 0)) {
281
- _context4.n = 16;
281
+ _context4.n = 20;
282
282
  break;
283
283
  }
284
284
  _context4.p = 3;
@@ -289,7 +289,7 @@ var MediaApiService = /*#__PURE__*/function () {
289
289
  index = 0;
290
290
  case 5:
291
291
  if (!(index < responseFiles.length)) {
292
- _context4.n = 13;
292
+ _context4.n = 17;
293
293
  break;
294
294
  }
295
295
  path = responseFiles[index].signedUrl;
@@ -299,20 +299,46 @@ var MediaApiService = /*#__PURE__*/function () {
299
299
  fileBody = originalFile; // Handle React Native file URIs
300
300
  // If file has a uri property, it's from React Native - fetch it first
301
301
  if (!(originalFile.uri && typeof originalFile.uri === "string")) {
302
- _context4.n = 9;
302
+ _context4.n = 13;
303
303
  break;
304
304
  }
305
- _context4.n = 7;
306
- return fetch(originalFile.uri);
307
- case 7:
308
- fileResponse = _context4.v;
305
+ // For React Native, handle file://, content://, or http:// URIs
306
+ uri = originalFile.uri;
307
+ _context4.p = 7;
309
308
  _context4.n = 8;
310
- return fileResponse.blob();
309
+ return fetch(uri);
311
310
  case 8:
311
+ fileResponse = _context4.v;
312
+ if (!fileResponse.blob) {
313
+ _context4.n = 10;
314
+ break;
315
+ }
316
+ _context4.n = 9;
317
+ return fileResponse.blob();
318
+ case 9:
312
319
  blob = _context4.v;
313
320
  fileBody = blob;
314
- case 9:
315
- _context4.n = 10;
321
+ _context4.n = 11;
322
+ break;
323
+ case 10:
324
+ // Fallback: use the response as-is if blob() is not available
325
+ // Some React Native versions might need different handling
326
+ fileBody = fileResponse;
327
+ case 11:
328
+ _context4.n = 13;
329
+ break;
330
+ case 12:
331
+ _context4.p = 12;
332
+ _t3 = _context4.v;
333
+ // If fetch fails, try using the URI directly
334
+ // Some React Native environments might handle this differently
335
+ console.warn("Fetch failed for URI, trying direct upload:", _t3);
336
+ // For S3 PUT, we need the actual file content
337
+ // If fetch fails, we'll try to use the file object directly
338
+ // This might require additional React Native file handling libraries
339
+ throw new Error("Failed to read file from URI: ".concat(uri, ". Make sure the file URI is accessible. Error: ").concat(_t3.message));
340
+ case 13:
341
+ _context4.n = 14;
316
342
  return fetch(path, {
317
343
  method: "PUT",
318
344
  headers: {
@@ -320,26 +346,26 @@ var MediaApiService = /*#__PURE__*/function () {
320
346
  },
321
347
  body: fileBody
322
348
  });
323
- case 10:
349
+ case 14:
324
350
  res = _context4.v;
325
351
  if (res.ok) {
326
352
  all_files_uri.push(fileURI);
327
353
  } else {
328
354
  console.error("Failed to upload file ".concat(index + 1));
329
355
  }
330
- _context4.n = 12;
356
+ _context4.n = 16;
331
357
  break;
332
- case 11:
333
- _context4.p = 11;
334
- _t3 = _context4.v;
335
- console.error("Error uploading file ".concat(index + 1, ":"), _t3);
336
- case 12:
358
+ case 15:
359
+ _context4.p = 15;
360
+ _t4 = _context4.v;
361
+ console.error("Error uploading file ".concat(index + 1, ":"), _t4);
362
+ case 16:
337
363
  index++;
338
364
  _context4.n = 5;
339
365
  break;
340
- case 13:
366
+ case 17:
341
367
  if (!(all_files_uri.length > 0)) {
342
- _context4.n = 14;
368
+ _context4.n = 18;
343
369
  break;
344
370
  }
345
371
  mediaData = all_files_uri.map(function (url, index) {
@@ -352,7 +378,7 @@ var MediaApiService = /*#__PURE__*/function () {
352
378
  mime_type: originalFile.type
353
379
  };
354
380
  }); // Save to media API - POST /v1/media with { media: [...] }
355
- _context4.n = 14;
381
+ _context4.n = 18;
356
382
  return this.apiCall({
357
383
  method: "POST",
358
384
  path: "/v1/media",
@@ -360,25 +386,25 @@ var MediaApiService = /*#__PURE__*/function () {
360
386
  media: mediaData
361
387
  }
362
388
  });
363
- case 14:
364
- _context4.n = 16;
389
+ case 18:
390
+ _context4.n = 20;
365
391
  break;
366
- case 15:
367
- _context4.p = 15;
368
- _t4 = _context4.v;
369
- console.error("Upload error:", _t4);
392
+ case 19:
393
+ _context4.p = 19;
394
+ _t5 = _context4.v;
395
+ console.error("Upload error:", _t5);
370
396
  if (this.onError) {
371
- this.onError(_t4);
397
+ this.onError(_t5);
372
398
  }
373
- throw _t4;
374
- case 16:
399
+ throw _t5;
400
+ case 20:
375
401
  i++;
376
402
  _context4.n = 2;
377
403
  break;
378
- case 17:
404
+ case 21:
379
405
  return _context4.a(2, all_files_uri);
380
406
  }
381
- }, _callee4, this, [[6, 11], [3, 15]]);
407
+ }, _callee4, this, [[7, 12], [6, 15], [3, 19]]);
382
408
  }));
383
409
  function uploadMedia(_x5, _x6) {
384
410
  return _uploadMedia.apply(this, arguments);
@@ -79,6 +79,7 @@ var FileUpload = function FileUpload(_ref) {
79
79
  onUploadError = _ref.onUploadError,
80
80
  picker = _ref.picker,
81
81
  pickerOptions = _ref.pickerOptions,
82
+ icon = _ref.icon,
82
83
  _ref$theme = _ref.theme,
83
84
  theme = _ref$theme === void 0 ? defaultTheme : _ref$theme,
84
85
  containerStyle = _ref.containerStyle,
@@ -97,14 +98,44 @@ var FileUpload = function FileUpload(_ref) {
97
98
 
98
99
  // Convert file picker result to File-like object for apiService
99
100
  var convertToFile = function convertToFile(pickerResult) {
100
- // Picker typically returns: { uri, type, fileName, fileSize, width, height }
101
- // We need to create a File-like object that apiService.uploadMedia expects
102
- // For React Native, we'll use the URI directly and let uploadMedia handle it
101
+ // Handle different picker formats:
102
+ // react-native-image-picker: { uri, fileName, mimeType, fileSize, ... }
103
+ // expo-image-picker: { uri, fileName, mimeType, ... }
104
+ // Custom: { uri, name, type, ... }
105
+
106
+ // Extract URI (can be file://, content://, or http://)
107
+ var uri = pickerResult.uri || pickerResult.path;
108
+
109
+ // Extract file name (handle different property names)
110
+ var fileName = pickerResult.fileName || pickerResult.name;
111
+
112
+ // If no fileName, try to extract from URI
113
+ if (!fileName && uri) {
114
+ var uriParts = uri.split("/");
115
+ var lastPart = uriParts[uriParts.length - 1];
116
+ fileName = lastPart ? lastPart.split("?")[0] : null; // Remove query params if any
117
+ }
118
+
119
+ // Final fallback
120
+ if (!fileName) {
121
+ // Try to guess from mimeType
122
+ var _mimeType = pickerResult.mimeType || pickerResult.type || "";
123
+ if (_mimeType.includes("image")) {
124
+ fileName = _mimeType.includes("jpeg") || _mimeType.includes("jpg") ? "image.jpg" : _mimeType.includes("png") ? "image.png" : _mimeType.includes("gif") ? "image.gif" : "image.jpg";
125
+ } else if (_mimeType.includes("video")) {
126
+ fileName = "video.mp4";
127
+ } else {
128
+ fileName = "file";
129
+ }
130
+ }
131
+
132
+ // Extract MIME type (handle different property names)
133
+ var mimeType = pickerResult.mimeType || pickerResult.type || "image/jpeg"; // Default fallback
103
134
 
104
135
  return {
105
- uri: pickerResult.uri,
106
- name: pickerResult.fileName || pickerResult.uri.split("/").pop() || "image.jpg",
107
- type: pickerResult.type || pickerResult.mimeType || "image/jpeg",
136
+ uri: uri,
137
+ name: fileName,
138
+ type: mimeType,
108
139
  // Keep original picker result for potential use
109
140
  _pickerResult: pickerResult
110
141
  };
@@ -195,7 +226,8 @@ var FileUpload = function FileUpload(_ref) {
195
226
  case 2:
196
227
  result = _context2.v;
197
228
  // Handle different picker response formats
198
- // react-native-image-picker: { assets: [...] }
229
+ // react-native-image-picker: { assets: [{ uri, fileName, mimeType, ... }] }
230
+ // Example: { assets: [{ uri: "file:///...", fileName: "image.jpg", mimeType: "image/jpeg" }] }
199
231
  // expo-image-picker: { assets: [...] }
200
232
  // Custom: could be array directly or { assets: [...] }
201
233
  assets = Array.isArray(result) ? result : (result === null || result === void 0 ? void 0 : result.assets) || result || [];
@@ -256,19 +288,20 @@ var FileUpload = function FileUpload(_ref) {
256
288
  borderRadius: theme.radius.md
257
289
  }, buttonStyle],
258
290
  disabled: isLoading,
259
- children: [/*#__PURE__*/_jsx(View, {
291
+ children: [icon && /*#__PURE__*/_jsx(View, {
260
292
  style: [styles.iconContainer, {
261
293
  backgroundColor: theme.colors.uploadIconBackground,
262
294
  borderRadius: theme.radius.xl,
263
295
  marginBottom: theme.spacing.sm,
264
296
  padding: theme.spacing.md
265
297
  }, iconContainerStyle],
266
- children: /*#__PURE__*/_jsx(CameraIcon, {})
298
+ children: icon
267
299
  }), /*#__PURE__*/_jsx(Text, {
268
300
  style: [styles.title, {
269
301
  color: theme.colors.uploadText,
270
- marginTop: theme.spacing.sm,
271
- fontSize: theme.typography.caption.fontSize
302
+ fontSize: theme.typography.body.fontSize,
303
+ fontWeight: theme.typography.body.fontWeight,
304
+ marginTop: icon ? theme.spacing.sm : 0
272
305
  }, titleStyle],
273
306
  children: title
274
307
  })]
@@ -17,6 +17,7 @@ import { View, FlatList, Image, TouchableOpacity, StyleSheet, Dimensions } from
17
17
  import FileUpload from './FileUpload.native';
18
18
  import ImagesSkeleton from './ImagesSkeleton.native';
19
19
  import Pagination from './Pagination.native';
20
+ import { CameraIcon } from './Icons.native';
20
21
  import { defaultTheme } from './theme';
21
22
  import { jsx as _jsx } from "react/jsx-runtime";
22
23
  var _Dimensions$get = Dimensions.get('window'),
@@ -134,7 +135,8 @@ var ImagesGallery = function ImagesGallery(_ref) {
134
135
  onUploadError: onError,
135
136
  picker: picker,
136
137
  pickerOptions: pickerOptions,
137
- theme: theme
138
+ theme: theme,
139
+ icon: /*#__PURE__*/_jsx(CameraIcon, {})
138
140
  })
139
141
  });
140
142
  }
@@ -4,13 +4,13 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
4
4
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
5
5
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
6
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
7
- import React from 'react';
8
- import { Modal, View, Text, TouchableOpacity, StyleSheet, Dimensions, Animated, TouchableWithoutFeedback } from 'react-native';
9
- import MediaTab from './MediaTab.native';
10
- import { CloseIcon } from './Icons.native';
11
- import { createTheme } from './theme';
7
+ import React from "react";
8
+ import { Modal, View, Text, TouchableOpacity, StyleSheet, Dimensions, Animated, TouchableWithoutFeedback } from "react-native";
9
+ import MediaTab from "./MediaTab.native";
10
+ import { CloseIcon } from "./Icons.native";
11
+ import { createTheme } from "./theme";
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- var _Dimensions$get = Dimensions.get('window'),
13
+ var _Dimensions$get = Dimensions.get("window"),
14
14
  SCREEN_HEIGHT = _Dimensions$get.height;
15
15
  var MediaPopup = function MediaPopup(_ref) {
16
16
  var isOpen = _ref.isOpen,
@@ -18,11 +18,11 @@ var MediaPopup = function MediaPopup(_ref) {
18
18
  onSelect = _ref.onSelect,
19
19
  currentData = _ref.currentData,
20
20
  _ref$options = _ref.options,
21
- options = _ref$options === void 0 ? ['image'] : _ref$options,
21
+ options = _ref$options === void 0 ? ["image"] : _ref$options,
22
22
  apiService = _ref.apiService,
23
23
  onError = _ref.onError,
24
24
  _ref$title = _ref.title,
25
- title = _ref$title === void 0 ? 'Media Gallery' : _ref$title,
25
+ title = _ref$title === void 0 ? "Media Gallery" : _ref$title,
26
26
  picker = _ref.picker,
27
27
  pickerOptions = _ref.pickerOptions,
28
28
  theme = _ref.theme,
@@ -94,9 +94,7 @@ var MediaPopup = function MediaPopup(_ref) {
94
94
  }],
95
95
  children: [/*#__PURE__*/_jsxs(View, {
96
96
  style: [styles.header, {
97
- borderBottomColor: currentTheme.colors.border,
98
- marginBottom: currentTheme.spacing.lg,
99
- paddingBottom: currentTheme.spacing.md
97
+ marginBottom: currentTheme.spacing.md
100
98
  }, headerStyle],
101
99
  children: [/*#__PURE__*/_jsx(Text, {
102
100
  style: [styles.title, {
@@ -140,11 +138,11 @@ var MediaPopup = function MediaPopup(_ref) {
140
138
  var styles = StyleSheet.create({
141
139
  overlay: {
142
140
  flex: 1,
143
- justifyContent: 'flex-end'
141
+ justifyContent: "flex-end"
144
142
  },
145
143
  container: {
146
- width: '100%',
147
- shadowColor: '#000',
144
+ width: "100%",
145
+ shadowColor: "#000",
148
146
  shadowOffset: {
149
147
  width: 0,
150
148
  height: -2
@@ -152,13 +150,12 @@ var styles = StyleSheet.create({
152
150
  shadowOpacity: 0.25,
153
151
  shadowRadius: 3.84,
154
152
  elevation: 5,
155
- overflow: 'hidden' // Ensure content doesn't overflow
153
+ overflow: "hidden" // Ensure content doesn't overflow
156
154
  },
157
155
  header: {
158
- flexDirection: 'row',
159
- alignItems: 'center',
160
- justifyContent: 'space-between',
161
- borderBottomWidth: 1
156
+ flexDirection: "row",
157
+ alignItems: "center",
158
+ justifyContent: "space-between"
162
159
  },
163
160
  title: {
164
161
  flex: 1
@@ -105,12 +105,11 @@ var MediaTab = function MediaTab(_ref) {
105
105
  backgroundColor: theme.colors.tabBackground,
106
106
  borderBottomColor: theme.colors.border,
107
107
  paddingHorizontal: theme.spacing.xs,
108
- // Center align if only one tab
109
- justifyContent: availableTabs.length === 1 ? "center" : "flex-start"
108
+ // Always left align
109
+ justifyContent: "flex-start"
110
110
  }, tabListStyle],
111
111
  children: availableTabs.map(function (type, index) {
112
112
  var isSelected = index === selectedIndex;
113
- var isSingleTab = availableTabs.length === 1;
114
113
  return /*#__PURE__*/_jsxs(TouchableOpacity, {
115
114
  onPress: function onPress() {
116
115
  return setSelectedIndex(index);
@@ -118,9 +117,7 @@ var MediaTab = function MediaTab(_ref) {
118
117
  style: [styles.tabButton, {
119
118
  paddingVertical: theme.spacing.md,
120
119
  paddingHorizontal: theme.spacing.lg,
121
- // If single tab, don't use flex: 1, use auto width
122
- flex: isSingleTab ? 0 : 1,
123
- alignSelf: isSingleTab ? "center" : "stretch"
120
+ flex: 1
124
121
  }, tabButtonStyle, isSelected ? [styles.tabButtonActive, tabButtonActiveStyle] : [styles.tabButtonInactive, tabButtonInactiveStyle]],
125
122
  children: [/*#__PURE__*/_jsx(Text, {
126
123
  style: [styles.tabButtonText, {
@@ -162,8 +159,7 @@ var styles = StyleSheet.create({
162
159
  tabButton: {
163
160
  alignItems: "center",
164
161
  justifyContent: "center",
165
- position: "relative",
166
- minWidth: 80 // Minimum width for single tab
162
+ position: "relative"
167
163
  },
168
164
  tabButtonActive: {
169
165
  // Active state styling applied via theme
@@ -17,6 +17,7 @@ import { View, FlatList, TouchableOpacity, StyleSheet, Dimensions, Text } from '
17
17
  import FileUpload from './FileUpload.native';
18
18
  import ImagesSkeleton from './ImagesSkeleton.native';
19
19
  import Pagination from './Pagination.native';
20
+ import { CameraIcon } from './Icons.native';
20
21
  import { defaultTheme } from './theme';
21
22
  // Note: You'll need to install react-native-video for video playback
22
23
  // import Video from 'react-native-video'
@@ -135,7 +136,8 @@ var VideosGallery = function VideosGallery(_ref) {
135
136
  onUploadError: onError,
136
137
  picker: picker,
137
138
  pickerOptions: pickerOptions,
138
- theme: theme
139
+ theme: theme,
140
+ icon: /*#__PURE__*/_jsx(CameraIcon, {})
139
141
  })
140
142
  });
141
143
  }
@@ -85,6 +85,7 @@ var FileUpload = function FileUpload(_ref) {
85
85
  onUploadError = _ref.onUploadError,
86
86
  picker = _ref.picker,
87
87
  pickerOptions = _ref.pickerOptions,
88
+ icon = _ref.icon,
88
89
  _ref$theme = _ref.theme,
89
90
  theme = _ref$theme === void 0 ? _theme.defaultTheme : _ref$theme,
90
91
  containerStyle = _ref.containerStyle,
@@ -103,14 +104,44 @@ var FileUpload = function FileUpload(_ref) {
103
104
 
104
105
  // Convert file picker result to File-like object for apiService
105
106
  var convertToFile = function convertToFile(pickerResult) {
106
- // Picker typically returns: { uri, type, fileName, fileSize, width, height }
107
- // We need to create a File-like object that apiService.uploadMedia expects
108
- // For React Native, we'll use the URI directly and let uploadMedia handle it
107
+ // Handle different picker formats:
108
+ // react-native-image-picker: { uri, fileName, mimeType, fileSize, ... }
109
+ // expo-image-picker: { uri, fileName, mimeType, ... }
110
+ // Custom: { uri, name, type, ... }
111
+
112
+ // Extract URI (can be file://, content://, or http://)
113
+ var uri = pickerResult.uri || pickerResult.path;
114
+
115
+ // Extract file name (handle different property names)
116
+ var fileName = pickerResult.fileName || pickerResult.name;
117
+
118
+ // If no fileName, try to extract from URI
119
+ if (!fileName && uri) {
120
+ var uriParts = uri.split("/");
121
+ var lastPart = uriParts[uriParts.length - 1];
122
+ fileName = lastPart ? lastPart.split("?")[0] : null; // Remove query params if any
123
+ }
124
+
125
+ // Final fallback
126
+ if (!fileName) {
127
+ // Try to guess from mimeType
128
+ var _mimeType = pickerResult.mimeType || pickerResult.type || "";
129
+ if (_mimeType.includes("image")) {
130
+ fileName = _mimeType.includes("jpeg") || _mimeType.includes("jpg") ? "image.jpg" : _mimeType.includes("png") ? "image.png" : _mimeType.includes("gif") ? "image.gif" : "image.jpg";
131
+ } else if (_mimeType.includes("video")) {
132
+ fileName = "video.mp4";
133
+ } else {
134
+ fileName = "file";
135
+ }
136
+ }
137
+
138
+ // Extract MIME type (handle different property names)
139
+ var mimeType = pickerResult.mimeType || pickerResult.type || "image/jpeg"; // Default fallback
109
140
 
110
141
  return {
111
- uri: pickerResult.uri,
112
- name: pickerResult.fileName || pickerResult.uri.split("/").pop() || "image.jpg",
113
- type: pickerResult.type || pickerResult.mimeType || "image/jpeg",
142
+ uri: uri,
143
+ name: fileName,
144
+ type: mimeType,
114
145
  // Keep original picker result for potential use
115
146
  _pickerResult: pickerResult
116
147
  };
@@ -201,7 +232,8 @@ var FileUpload = function FileUpload(_ref) {
201
232
  case 2:
202
233
  result = _context2.v;
203
234
  // Handle different picker response formats
204
- // react-native-image-picker: { assets: [...] }
235
+ // react-native-image-picker: { assets: [{ uri, fileName, mimeType, ... }] }
236
+ // Example: { assets: [{ uri: "file:///...", fileName: "image.jpg", mimeType: "image/jpeg" }] }
205
237
  // expo-image-picker: { assets: [...] }
206
238
  // Custom: could be array directly or { assets: [...] }
207
239
  assets = Array.isArray(result) ? result : (result === null || result === void 0 ? void 0 : result.assets) || result || [];
@@ -262,19 +294,20 @@ var FileUpload = function FileUpload(_ref) {
262
294
  borderRadius: theme.radius.md
263
295
  }, buttonStyle],
264
296
  disabled: isLoading,
265
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
297
+ children: [icon && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
266
298
  style: [styles.iconContainer, {
267
299
  backgroundColor: theme.colors.uploadIconBackground,
268
300
  borderRadius: theme.radius.xl,
269
301
  marginBottom: theme.spacing.sm,
270
302
  padding: theme.spacing.md
271
303
  }, iconContainerStyle],
272
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icons.CameraIcon, {})
304
+ children: icon
273
305
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
274
306
  style: [styles.title, {
275
307
  color: theme.colors.uploadText,
276
- marginTop: theme.spacing.sm,
277
- fontSize: theme.typography.caption.fontSize
308
+ fontSize: theme.typography.body.fontSize,
309
+ fontWeight: theme.typography.body.fontWeight,
310
+ marginTop: icon ? theme.spacing.sm : 0
278
311
  }, titleStyle],
279
312
  children: title
280
313
  })]
@@ -10,6 +10,7 @@ var _reactNative = require("react-native");
10
10
  var _FileUpload = _interopRequireDefault(require("./FileUpload.native"));
11
11
  var _ImagesSkeleton = _interopRequireDefault(require("./ImagesSkeleton.native"));
12
12
  var _Pagination = _interopRequireDefault(require("./Pagination.native"));
13
+ var _Icons = require("./Icons.native");
13
14
  var _theme = require("./theme");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -143,7 +144,8 @@ var ImagesGallery = function ImagesGallery(_ref) {
143
144
  onUploadError: onError,
144
145
  picker: picker,
145
146
  pickerOptions: pickerOptions,
146
- theme: theme
147
+ theme: theme,
148
+ icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icons.CameraIcon, {})
147
149
  })
148
150
  });
149
151
  }
@@ -17,7 +17,7 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
17
17
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
18
18
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
19
19
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
20
- var _Dimensions$get = _reactNative.Dimensions.get('window'),
20
+ var _Dimensions$get = _reactNative.Dimensions.get("window"),
21
21
  SCREEN_HEIGHT = _Dimensions$get.height;
22
22
  var MediaPopup = function MediaPopup(_ref) {
23
23
  var isOpen = _ref.isOpen,
@@ -25,11 +25,11 @@ var MediaPopup = function MediaPopup(_ref) {
25
25
  onSelect = _ref.onSelect,
26
26
  currentData = _ref.currentData,
27
27
  _ref$options = _ref.options,
28
- options = _ref$options === void 0 ? ['image'] : _ref$options,
28
+ options = _ref$options === void 0 ? ["image"] : _ref$options,
29
29
  apiService = _ref.apiService,
30
30
  onError = _ref.onError,
31
31
  _ref$title = _ref.title,
32
- title = _ref$title === void 0 ? 'Media Gallery' : _ref$title,
32
+ title = _ref$title === void 0 ? "Media Gallery" : _ref$title,
33
33
  picker = _ref.picker,
34
34
  pickerOptions = _ref.pickerOptions,
35
35
  theme = _ref.theme,
@@ -101,9 +101,7 @@ var MediaPopup = function MediaPopup(_ref) {
101
101
  }],
102
102
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
103
103
  style: [styles.header, {
104
- borderBottomColor: currentTheme.colors.border,
105
- marginBottom: currentTheme.spacing.lg,
106
- paddingBottom: currentTheme.spacing.md
104
+ marginBottom: currentTheme.spacing.md
107
105
  }, headerStyle],
108
106
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
109
107
  style: [styles.title, {
@@ -147,11 +145,11 @@ var MediaPopup = function MediaPopup(_ref) {
147
145
  var styles = _reactNative.StyleSheet.create({
148
146
  overlay: {
149
147
  flex: 1,
150
- justifyContent: 'flex-end'
148
+ justifyContent: "flex-end"
151
149
  },
152
150
  container: {
153
- width: '100%',
154
- shadowColor: '#000',
151
+ width: "100%",
152
+ shadowColor: "#000",
155
153
  shadowOffset: {
156
154
  width: 0,
157
155
  height: -2
@@ -159,13 +157,12 @@ var styles = _reactNative.StyleSheet.create({
159
157
  shadowOpacity: 0.25,
160
158
  shadowRadius: 3.84,
161
159
  elevation: 5,
162
- overflow: 'hidden' // Ensure content doesn't overflow
160
+ overflow: "hidden" // Ensure content doesn't overflow
163
161
  },
164
162
  header: {
165
- flexDirection: 'row',
166
- alignItems: 'center',
167
- justifyContent: 'space-between',
168
- borderBottomWidth: 1
163
+ flexDirection: "row",
164
+ alignItems: "center",
165
+ justifyContent: "space-between"
169
166
  },
170
167
  title: {
171
168
  flex: 1
@@ -114,12 +114,11 @@ var MediaTab = function MediaTab(_ref) {
114
114
  backgroundColor: theme.colors.tabBackground,
115
115
  borderBottomColor: theme.colors.border,
116
116
  paddingHorizontal: theme.spacing.xs,
117
- // Center align if only one tab
118
- justifyContent: availableTabs.length === 1 ? "center" : "flex-start"
117
+ // Always left align
118
+ justifyContent: "flex-start"
119
119
  }, tabListStyle],
120
120
  children: availableTabs.map(function (type, index) {
121
121
  var isSelected = index === selectedIndex;
122
- var isSingleTab = availableTabs.length === 1;
123
122
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
124
123
  onPress: function onPress() {
125
124
  return setSelectedIndex(index);
@@ -127,9 +126,7 @@ var MediaTab = function MediaTab(_ref) {
127
126
  style: [styles.tabButton, {
128
127
  paddingVertical: theme.spacing.md,
129
128
  paddingHorizontal: theme.spacing.lg,
130
- // If single tab, don't use flex: 1, use auto width
131
- flex: isSingleTab ? 0 : 1,
132
- alignSelf: isSingleTab ? "center" : "stretch"
129
+ flex: 1
133
130
  }, tabButtonStyle, isSelected ? [styles.tabButtonActive, tabButtonActiveStyle] : [styles.tabButtonInactive, tabButtonInactiveStyle]],
134
131
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
135
132
  style: [styles.tabButtonText, {
@@ -171,8 +168,7 @@ var styles = _reactNative.StyleSheet.create({
171
168
  tabButton: {
172
169
  alignItems: "center",
173
170
  justifyContent: "center",
174
- position: "relative",
175
- minWidth: 80 // Minimum width for single tab
171
+ position: "relative"
176
172
  },
177
173
  tabButtonActive: {
178
174
  // Active state styling applied via theme
@@ -10,6 +10,7 @@ var _reactNative = require("react-native");
10
10
  var _FileUpload = _interopRequireDefault(require("./FileUpload.native"));
11
11
  var _ImagesSkeleton = _interopRequireDefault(require("./ImagesSkeleton.native"));
12
12
  var _Pagination = _interopRequireDefault(require("./Pagination.native"));
13
+ var _Icons = require("./Icons.native");
13
14
  var _theme = require("./theme");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
15
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -143,7 +144,8 @@ var VideosGallery = function VideosGallery(_ref) {
143
144
  onUploadError: onError,
144
145
  picker: picker,
145
146
  pickerOptions: pickerOptions,
146
- theme: theme
147
+ theme: theme,
148
+ icon: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Icons.CameraIcon, {})
147
149
  })
148
150
  });
149
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tradly/asset",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "A reusable media gallery component for uploading and selecting images, videos, and files with Tradly authentication",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/esm/index.js",