@teamnhz/rn-ui-toolkit 1.2.9 → 1.3.1

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.
@@ -1,40 +1,11 @@
1
1
  import React from "react";
2
- import { ViewStyle, TextStyle, ImageStyle } from "react-native";
3
- import { cameraPermissions, galleryPermissions, checkMicroPhonePermission } from "../../utils/permissions";
4
- type CustomStyles = {
5
- container?: ViewStyle;
6
- row?: ViewStyle;
7
- text?: TextStyle;
8
- icon?: ImageStyle;
9
- backgroundColor?: any;
10
- };
2
+ import { ViewStyle } from "react-native";
11
3
  type Props = {
12
- visible: boolean;
13
- onClose: () => void;
14
4
  mediaType: "photo" | "video";
15
5
  isMultiSelect?: boolean;
16
6
  onSuccess: (data: any) => void;
17
- labels?: {
18
- camera?: string;
19
- gallery?: string;
20
- cancel?: string;
21
- };
22
- icons?: {
23
- camera?: any;
24
- gallery?: any;
25
- cancel?: any;
26
- };
27
- styles?: CustomStyles;
28
- permissionHandlers?: {
29
- camera?: typeof cameraPermissions;
30
- gallery?: typeof galleryPermissions;
31
- microphone?: typeof checkMicroPhonePermission;
32
- };
33
- pickerOptions?: {
34
- camera?: object;
35
- gallery?: object;
36
- cropper?: object;
37
- };
7
+ visible: boolean;
8
+ onClose: () => void;
38
9
  enableCompression?: boolean;
39
10
  imageCompressionOptions?: {
40
11
  maxWidth?: number;
@@ -43,6 +14,10 @@ type Props = {
43
14
  videoCompressionOptions?: {
44
15
  compressionMethod?: "auto" | "manual";
45
16
  };
17
+ customStyle?: ViewStyle;
18
+ sheetBackgroundColor?: string;
19
+ textColor?: string;
20
+ iconTintColor?: string;
46
21
  };
47
22
  declare const ImagePicker: React.FC<Props>;
48
23
  export default ImagePicker;
@@ -328,6 +328,7 @@
328
328
  // StyleSheet,
329
329
  // Image,
330
330
  // Alert,
331
+ // ViewStyle,
331
332
  // } from "react-native";
332
333
  // import { BottomSheet, Dividers } from "../index";
333
334
  // import { launchCamera, launchImageLibrary } from "react-native-image-picker";
@@ -359,6 +360,7 @@
359
360
  // videoCompressionOptions?: {
360
361
  // compressionMethod?: "auto" | "manual";
361
362
  // };
363
+ // customStyle?:ViewStyle
362
364
  // };
363
365
  // const ImagePicker: React.FC<Props> = ({
364
366
  // mediaType,
@@ -369,6 +371,7 @@
369
371
  // enableCompression = true,
370
372
  // imageCompressionOptions = { maxWidth: 1080, quality: 0.7 },
371
373
  // videoCompressionOptions = { compressionMethod: "auto" },
374
+ // customStyle
372
375
  // }) => {
373
376
  // // Success handler
374
377
  // const onComplete = useCallback(
@@ -538,7 +541,7 @@
538
541
  // });
539
542
  // };
540
543
  // return (
541
- // <BottomSheet visible={visible} onClose={onClose} height={230}>
544
+ // <BottomSheet visible={visible} onClose={onClose} height={230} sheetBackground={customStyle?.backgroundColor}>
542
545
  // <View style={styles.container}>
543
546
  // {/* Camera */}
544
547
  // <TouchableOpacity style={styles.row} onPress={handleCamera}>
@@ -577,168 +580,177 @@
577
580
  // },
578
581
  // });
579
582
  import React, { useCallback } from "react";
580
- import { View, Text, TouchableOpacity, StyleSheet, Image, } from "react-native";
581
- import { BottomSheet, Dividers } from "../index"; // ✅ YOUR ORIGINAL BOTTOMSHEET
583
+ import { View, Text, TouchableOpacity, StyleSheet, Image, Alert, } from "react-native";
584
+ import { BottomSheet, Dividers } from "../index";
582
585
  import { launchCamera, launchImageLibrary } from "react-native-image-picker";
583
586
  import ImageCropPicker from "react-native-image-crop-picker";
584
587
  import { Image as ImageCompressor, Video as VideoCompressor, } from "react-native-compressor";
585
- // Permission functions (user can override)
588
+ import { Colors, Images, Scale, Typography } from "../../styles";
589
+ // Permissions
586
590
  import { cameraPermissions, galleryPermissions, checkMicroPhonePermission, } from "../../utils/permissions";
587
- const ImagePicker = ({ visible, onClose, mediaType, isMultiSelect = false, onSuccess, labels = {
588
- camera: "Camera",
589
- gallery: "Gallery",
590
- cancel: "Cancel",
591
- }, icons = {
592
- camera: null,
593
- gallery: null,
594
- cancel: null,
595
- }, styles: customStyle = {}, permissionHandlers = {
596
- camera: cameraPermissions,
597
- gallery: galleryPermissions,
598
- microphone: checkMicroPhonePermission,
599
- }, pickerOptions = {
600
- camera: {},
601
- gallery: {},
602
- cropper: {},
603
- }, enableCompression = true, imageCompressionOptions = { maxWidth: 1080, quality: 0.7 }, videoCompressionOptions = { compressionMethod: "auto" }, }) => {
604
- const s = { ...defaultStyles, ...customStyle };
591
+ const ImagePicker = ({ mediaType, isMultiSelect = false, onSuccess, visible, onClose, enableCompression = true, imageCompressionOptions = { maxWidth: 1080, quality: 0.7 }, videoCompressionOptions = { compressionMethod: "auto" }, customStyle, sheetBackgroundColor, textColor, iconTintColor, }) => {
605
592
  const onComplete = useCallback((data) => {
606
593
  onSuccess(data);
607
594
  onClose();
608
595
  }, [onSuccess, onClose]);
609
- const compressImage = async (path) => {
596
+ // Compress Image
597
+ const compressImage = async (imagePath) => {
610
598
  if (!enableCompression)
611
- return path;
599
+ return imagePath;
612
600
  try {
613
- return await ImageCompressor.compress(path, imageCompressionOptions);
601
+ const compressedImage = await ImageCompressor.compress(imagePath, {
602
+ maxWidth: imageCompressionOptions.maxWidth,
603
+ quality: imageCompressionOptions.quality,
604
+ });
605
+ return compressedImage;
614
606
  }
615
- catch {
616
- return path;
607
+ catch (error) {
608
+ console.error("Image compression error:", error);
609
+ return imagePath;
617
610
  }
618
611
  };
619
- const compressVideo = async (uri) => {
612
+ // Compress Video
613
+ const compressVideo = async (videoUri) => {
620
614
  if (!enableCompression)
621
- return uri;
615
+ return videoUri;
622
616
  try {
623
- return await VideoCompressor.compress(uri, videoCompressionOptions);
617
+ const compressedVideo = await VideoCompressor.compress(videoUri, {
618
+ compressionMethod: videoCompressionOptions.compressionMethod,
619
+ });
620
+ return compressedVideo;
624
621
  }
625
- catch {
626
- return uri;
622
+ catch (error) {
623
+ console.error("Video compression error:", error);
624
+ return videoUri;
627
625
  }
628
626
  };
627
+ // Camera
629
628
  const handleCamera = async () => {
630
- await permissionHandlers.camera?.(async (granted) => {
629
+ await cameraPermissions(async (granted) => {
631
630
  if (!granted)
632
631
  return;
633
632
  if (mediaType === "photo") {
634
633
  try {
635
- const img = await ImageCropPicker.openCamera({
636
- mediaType: "photo",
637
- ...pickerOptions.camera,
638
- });
639
- let cropped = img;
640
- if (!isMultiSelect) {
641
- cropped = await ImageCropPicker.openCropper({
642
- path: img.path,
634
+ const response = await ImageCropPicker.openCamera({ mediaType: "photo" });
635
+ if (isMultiSelect) {
636
+ const comp = await compressImage(response.path);
637
+ onComplete([{ ...response, path: comp }]);
638
+ }
639
+ else {
640
+ const cropped = await ImageCropPicker.openCropper({
641
+ path: response?.path,
642
+ width: response?.width,
643
+ height: response?.height,
643
644
  mediaType: "photo",
644
645
  freeStyleCropEnabled: true,
645
- ...pickerOptions.cropper,
646
646
  });
647
+ const comp = await compressImage(cropped.path);
648
+ onComplete({ ...cropped, path: comp });
647
649
  }
648
- const compressed = await compressImage(cropped.path);
649
- onComplete({ ...cropped, path: compressed });
650
650
  }
651
- catch { }
651
+ catch (err) {
652
+ console.log("Camera error:", err);
653
+ }
652
654
  }
653
655
  else {
654
- const micGranted = await permissionHandlers.microphone?.();
655
- if (!micGranted)
656
+ const micPermission = await checkMicroPhonePermission();
657
+ if (!micPermission) {
658
+ Alert.alert("Microphone Permission Required", "Please enable microphone access to record videos.");
656
659
  return;
657
- launchCamera({ mediaType: "video", ...pickerOptions.camera }, async (res) => {
660
+ }
661
+ launchCamera({ mediaType: "video", durationLimit: 60, videoQuality: "high" }, async (res) => {
658
662
  if (res?.assets?.length) {
659
- const compressed = await compressVideo(res.assets[0].uri);
660
- onComplete({ path: compressed });
663
+ const uri = res.assets[0].uri;
664
+ const comp = await compressVideo(uri);
665
+ onComplete({ path: comp, duration: res.assets[0].duration });
661
666
  }
662
667
  });
663
668
  }
664
669
  });
665
670
  };
671
+ // Gallery
666
672
  const handleGallery = async () => {
667
- await permissionHandlers.gallery?.(async (granted) => {
673
+ await galleryPermissions(async (granted) => {
668
674
  if (!granted)
669
675
  return;
670
676
  if (mediaType === "photo") {
671
677
  try {
672
- let result = await ImageCropPicker.openPicker({
673
- mediaType: "photo",
674
- multiple: isMultiSelect,
675
- ...pickerOptions.gallery,
676
- });
677
- if (!isMultiSelect) {
678
- result = await ImageCropPicker.openCropper({
679
- path: result.path,
678
+ if (isMultiSelect) {
679
+ const images = await ImageCropPicker.openPicker({
680
680
  mediaType: "photo",
681
- freeStyleCropEnabled: true,
682
- ...pickerOptions.cropper,
681
+ multiple: true,
682
+ maxFiles: 5,
683
683
  });
684
- }
685
- if (isMultiSelect) {
686
- const compressed = await Promise.all(result.map(async (img) => ({
684
+ if (images.length > 5) {
685
+ Alert.alert("Limit Exceeded", "You can select up to 5 images.");
686
+ return;
687
+ }
688
+ const compressed = await Promise.all(images.map(async (img) => ({
687
689
  ...img,
688
690
  path: await compressImage(img.path),
689
691
  })));
690
692
  onComplete(compressed);
691
693
  }
692
694
  else {
693
- const compressed = await compressImage(result.path);
694
- onComplete({ ...result, path: compressed });
695
+ const response = await ImageCropPicker.openPicker({
696
+ mediaType: "photo",
697
+ });
698
+ const cropped = await ImageCropPicker.openCropper({
699
+ path: response?.path,
700
+ width: response?.width,
701
+ height: response?.height,
702
+ mediaType: "photo",
703
+ freeStyleCropEnabled: true,
704
+ });
705
+ const comp = await compressImage(cropped.path);
706
+ onComplete({ ...cropped, path: comp });
695
707
  }
696
708
  }
697
- catch { }
709
+ catch (err) {
710
+ console.log("Gallery error:", err);
711
+ }
698
712
  }
699
713
  else {
700
- launchImageLibrary({ mediaType: "video", ...pickerOptions.gallery }, async (res) => {
701
- if (res?.assets?.length) {
702
- const compressed = await compressVideo(res.assets[0].uri);
703
- onComplete({ path: compressed });
714
+ launchImageLibrary({ mediaType: "video" }, async (result) => {
715
+ if (result?.assets?.length) {
716
+ const uri = result.assets[0].uri;
717
+ const comp = await compressVideo(uri);
718
+ onComplete({ path: comp, duration: result.assets[0].duration });
704
719
  }
705
720
  });
706
721
  }
707
722
  });
708
723
  };
709
- return (React.createElement(BottomSheet, { visible: visible, onClose: onClose, height: 230, sheetBackground: customStyle?.backgroundColor },
710
- React.createElement(View, { style: s.container },
711
- React.createElement(TouchableOpacity, { style: s.row, onPress: handleCamera },
712
- icons.camera && React.createElement(Image, { source: icons.camera, style: s.icon }),
713
- React.createElement(Text, { style: s.text }, labels.camera)),
724
+ const appliedTextColor = textColor || Colors.white;
725
+ const appliedIconColor = iconTintColor || textColor || Colors.white;
726
+ return (React.createElement(BottomSheet, { visible: visible, onClose: onClose, height: 230, sheetBackground: sheetBackgroundColor },
727
+ React.createElement(View, { style: styles.container },
728
+ React.createElement(TouchableOpacity, { style: styles.row, onPress: handleCamera },
729
+ React.createElement(Image, { source: Images.video_icon, style: [styles.icon, { tintColor: appliedIconColor }] }),
730
+ React.createElement(Text, { style: [styles.text, { color: appliedTextColor }] }, "Camera")),
714
731
  React.createElement(Dividers, { small: true }),
715
- React.createElement(TouchableOpacity, { style: s.row, onPress: handleGallery },
716
- icons.gallery && React.createElement(Image, { source: icons.gallery, style: s.icon }),
717
- React.createElement(Text, { style: s.text }, labels.gallery)),
732
+ React.createElement(TouchableOpacity, { style: styles.row, onPress: handleGallery },
733
+ React.createElement(Image, { source: Images.image_icon, style: [styles.icon, { tintColor: appliedIconColor }] }),
734
+ React.createElement(Text, { style: [styles.text, { color: appliedTextColor }] }, "Gallery")),
718
735
  React.createElement(Dividers, { small: true }),
719
- React.createElement(TouchableOpacity, { style: s.row, onPress: onClose },
720
- icons.cancel && React.createElement(Image, { source: icons.cancel, style: s.icon }),
721
- React.createElement(Text, { style: s.text }, labels.cancel)))));
736
+ React.createElement(TouchableOpacity, { style: styles.row, onPress: onClose },
737
+ React.createElement(Image, { source: Images.cancel, style: [styles.icon, { tintColor: appliedIconColor }] }),
738
+ React.createElement(Text, { style: [styles.text, { color: appliedTextColor }] }, "Cancel")))));
722
739
  };
723
740
  export default ImagePicker;
724
- const defaultStyles = StyleSheet.create({
725
- container: {
726
- flex: 1,
727
- padding: 16,
728
- },
741
+ const styles = StyleSheet.create({
742
+ container: { paddingVertical: 10, paddingHorizontal: 16 },
729
743
  row: {
730
744
  flexDirection: "row",
731
745
  alignItems: "center",
732
- paddingVertical: 10,
746
+ marginVertical: 6,
733
747
  },
734
748
  text: {
735
- fontSize: 16,
736
- color: "white",
749
+ ...Typography.style.standardU(),
737
750
  },
738
751
  icon: {
739
- width: 20,
740
- height: 20,
752
+ width: Scale.moderateScale(20),
753
+ height: Scale.moderateScale(20),
741
754
  marginRight: 10,
742
- tintColor: "white",
743
755
  },
744
756
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamnhz/rn-ui-toolkit",
3
- "version": "1.2.9",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [