@teamnhz/rn-ui-toolkit 1.2.9 → 1.3.0
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
|
|
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
|
-
|
|
18
|
-
|
|
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";
|
|
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
|
-
|
|
588
|
+
import { Colors, Images, Scale, Typography } from "../../styles";
|
|
589
|
+
// Permissions
|
|
586
590
|
import { cameraPermissions, galleryPermissions, checkMicroPhonePermission, } from "../../utils/permissions";
|
|
587
|
-
const ImagePicker = ({ visible, onClose,
|
|
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
|
-
|
|
596
|
+
// Compress Image
|
|
597
|
+
const compressImage = async (imagePath) => {
|
|
610
598
|
if (!enableCompression)
|
|
611
|
-
return
|
|
599
|
+
return imagePath;
|
|
612
600
|
try {
|
|
613
|
-
|
|
601
|
+
const compressedImage = await ImageCompressor.compress(imagePath, {
|
|
602
|
+
maxWidth: imageCompressionOptions.maxWidth,
|
|
603
|
+
quality: imageCompressionOptions.quality,
|
|
604
|
+
});
|
|
605
|
+
return compressedImage;
|
|
614
606
|
}
|
|
615
|
-
catch {
|
|
616
|
-
|
|
607
|
+
catch (error) {
|
|
608
|
+
console.error("Image compression error:", error);
|
|
609
|
+
return imagePath;
|
|
617
610
|
}
|
|
618
611
|
};
|
|
619
|
-
|
|
612
|
+
// Compress Video
|
|
613
|
+
const compressVideo = async (videoUri) => {
|
|
620
614
|
if (!enableCompression)
|
|
621
|
-
return
|
|
615
|
+
return videoUri;
|
|
622
616
|
try {
|
|
623
|
-
|
|
617
|
+
const compressedVideo = await VideoCompressor.compress(videoUri, {
|
|
618
|
+
compressionMethod: videoCompressionOptions.compressionMethod,
|
|
619
|
+
});
|
|
620
|
+
return compressedVideo;
|
|
624
621
|
}
|
|
625
|
-
catch {
|
|
626
|
-
|
|
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
|
|
629
|
+
await cameraPermissions(async (granted) => {
|
|
631
630
|
if (!granted)
|
|
632
631
|
return;
|
|
633
632
|
if (mediaType === "photo") {
|
|
634
633
|
try {
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
cropped = await ImageCropPicker.openCropper({
|
|
642
|
-
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
|
|
655
|
-
if (!
|
|
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
|
-
|
|
660
|
+
}
|
|
661
|
+
launchCamera({ mediaType: "video", durationLimit: 60, videoQuality: "high" }, async (res) => {
|
|
658
662
|
if (res?.assets?.length) {
|
|
659
|
-
const
|
|
660
|
-
|
|
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
|
|
673
|
+
await galleryPermissions(async (granted) => {
|
|
668
674
|
if (!granted)
|
|
669
675
|
return;
|
|
670
676
|
if (mediaType === "photo") {
|
|
671
677
|
try {
|
|
672
|
-
|
|
673
|
-
|
|
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
|
-
|
|
682
|
-
|
|
681
|
+
multiple: true,
|
|
682
|
+
maxFiles: 5,
|
|
683
683
|
});
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
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
|
|
694
|
-
|
|
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"
|
|
701
|
-
if (
|
|
702
|
-
const
|
|
703
|
-
|
|
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
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
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:
|
|
716
|
-
|
|
717
|
-
React.createElement(Text, { style:
|
|
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:
|
|
720
|
-
|
|
721
|
-
React.createElement(Text, { style:
|
|
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
|
|
725
|
-
container: {
|
|
726
|
-
flex: 1,
|
|
727
|
-
padding: 16,
|
|
728
|
-
},
|
|
741
|
+
const styles = StyleSheet.create({
|
|
742
|
+
container: { flex: 1, padding: 16 },
|
|
729
743
|
row: {
|
|
730
744
|
flexDirection: "row",
|
|
731
745
|
alignItems: "center",
|
|
732
|
-
|
|
746
|
+
marginVertical: 6,
|
|
733
747
|
},
|
|
734
748
|
text: {
|
|
735
|
-
|
|
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
|
});
|