share modal
This commit is contained in:
@@ -18,15 +18,17 @@ const AppActionSheet = ({
|
|||||||
if (isWeb && webModal) {
|
if (isWeb && webModal) {
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<View style={styles.webOverlay} pointerEvents="box-none">
|
<View style={styles.webOverlay}>
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={onClose}
|
onPress={onClose}
|
||||||
style={StyleSheet.absoluteFill}
|
accessibilityRole="button"
|
||||||
pointerEvents="auto"
|
style={styles.webBackdrop}
|
||||||
/>
|
/>
|
||||||
<BlurView intensity={40} tint="dark" style={styles.webModalCard}>
|
<View style={styles.webModalWrapper} pointerEvents="box-none">
|
||||||
{children}
|
<BlurView intensity={40} tint="dark" style={styles.webModalCard}>
|
||||||
</BlurView>
|
{children}
|
||||||
|
</BlurView>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
@@ -70,10 +72,18 @@ export default AppActionSheet;
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
webOverlay: {
|
webOverlay: {
|
||||||
...StyleSheet.absoluteFillObject,
|
...StyleSheet.absoluteFillObject,
|
||||||
|
position: "fixed",
|
||||||
|
zIndex: 100,
|
||||||
|
},
|
||||||
|
webBackdrop: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.55)",
|
||||||
|
},
|
||||||
|
webModalWrapper: {
|
||||||
|
flex: 1,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
padding: 24,
|
padding: 24,
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.55)",
|
|
||||||
},
|
},
|
||||||
webModalCard: {
|
webModalCard: {
|
||||||
width: 480,
|
width: 480,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
View,
|
View,
|
||||||
|
findNodeHandle,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { SheetManager } from "react-native-actions-sheet";
|
import { SheetManager } from "react-native-actions-sheet";
|
||||||
|
|
||||||
@@ -45,15 +46,33 @@ const ShareModal = ({ payload }) => {
|
|||||||
|
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
const copyTimeout = useRef(null);
|
const copyTimeout = useRef(null);
|
||||||
|
const modalRef = useRef(null);
|
||||||
|
const [webVisible, setWebVisible] = useState(true);
|
||||||
const blurProps =
|
const blurProps =
|
||||||
Platform.OS === "android"
|
Platform.OS === "android"
|
||||||
? { experimentalBlurMethod: "dimezisBlurView" }
|
? { experimentalBlurMethod: "dimezisBlurView" }
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
const closeSheet = useCallback(() => {
|
const closeSheet = useCallback(() => {
|
||||||
return SheetManager.hide("Share");
|
if (isWeb) {
|
||||||
|
setWebVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const maybePromise = SheetManager.hide("Share");
|
||||||
|
return Promise.resolve(maybePromise);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("share.sheet.close", error);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isWeb) {
|
||||||
|
setWebVisible(true);
|
||||||
|
}
|
||||||
|
}, [payload]);
|
||||||
|
|
||||||
const shareText = useMemo(() => {
|
const shareText = useMemo(() => {
|
||||||
return [shareMessage, url].filter(Boolean).join(" ");
|
return [shareMessage, url].filter(Boolean).join(" ");
|
||||||
}, [shareMessage, url]);
|
}, [shareMessage, url]);
|
||||||
@@ -72,6 +91,46 @@ const ShareModal = ({ payload }) => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isWeb || typeof document === "undefined" || !webVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePointerDown = (event) => {
|
||||||
|
const node = modalRef.current;
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const domNode = findNodeHandle(node);
|
||||||
|
if (domNode && typeof domNode.contains === "function") {
|
||||||
|
if (domNode.contains(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domNode === event.target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSheet();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
closeSheet();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener("pointerdown", handlePointerDown);
|
||||||
|
document.addEventListener("keydown", handleKeyDown);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener("pointerdown", handlePointerDown);
|
||||||
|
document.removeEventListener("keydown", handleKeyDown);
|
||||||
|
};
|
||||||
|
}, [closeSheet, webVisible]);
|
||||||
|
|
||||||
const handleCopy = useCallback(async () => {
|
const handleCopy = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
if (copyTimeout.current) {
|
if (copyTimeout.current) {
|
||||||
@@ -288,85 +347,93 @@ const ShareModal = ({ payload }) => {
|
|||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
const webContent = (
|
if (isWeb && !webVisible) {
|
||||||
<View style={styles.webContainer}>
|
return null;
|
||||||
<View style={styles.webHeader}>
|
}
|
||||||
<Text style={styles.webHeading}>{heading}</Text>
|
|
||||||
<Pressable
|
|
||||||
onPress={closeSheet}
|
|
||||||
hitSlop={12}
|
|
||||||
style={styles.webCloseButton}
|
|
||||||
>
|
|
||||||
<Feather name="x" size={16} color={Palette.white} />
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={styles.webSubheading}>{shareMessage}</Text>
|
|
||||||
|
|
||||||
<View style={styles.webContent}>
|
|
||||||
<View style={styles.webLinkCard}>
|
|
||||||
<Text style={styles.webLinkLabel}>{linkLabel}</Text>
|
|
||||||
<View style={styles.webLinkActions}>
|
|
||||||
<Pressable
|
|
||||||
onPress={handleCopy}
|
|
||||||
style={[
|
|
||||||
styles.webActionButton,
|
|
||||||
styles.webPrimaryButton,
|
|
||||||
copied && styles.webActionButtonActive,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Feather
|
|
||||||
name={copied ? "check" : "copy"}
|
|
||||||
size={16}
|
|
||||||
color={Palette.white}
|
|
||||||
/>
|
|
||||||
<Text style={styles.webActionLabel}>
|
|
||||||
{copied ? "Lien copié" : "Copier le lien"}
|
|
||||||
</Text>
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
<Pressable
|
|
||||||
onPress={onSystemShare}
|
|
||||||
style={[styles.webActionButton, styles.webSecondaryButton]}
|
|
||||||
>
|
|
||||||
<Feather name="share-2" size={16} color={Palette.white} />
|
|
||||||
<Text style={styles.webActionLabel}>Partager</Text>
|
|
||||||
</Pressable>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.webOptionsCard}>
|
|
||||||
<Text style={styles.webSectionHeading}>{sectionTitle}</Text>
|
|
||||||
<View style={styles.webOptionsGrid}>
|
|
||||||
{shareOptions.map((option, index) => {
|
|
||||||
const Icon = option?.Icon ?? Feather;
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
key={option?.key || index}
|
|
||||||
onPress={() => handleShareOption(option)}
|
|
||||||
style={styles.webOptionRow}
|
|
||||||
>
|
|
||||||
<View style={styles.webOptionIcon}>
|
|
||||||
<Icon size={18} color={Palette.white} />
|
|
||||||
</View>
|
|
||||||
<Text style={styles.webOptionLabel}>{option?.label}</Text>
|
|
||||||
<Feather
|
|
||||||
name="chevron-right"
|
|
||||||
size={16}
|
|
||||||
color="rgba(255, 255, 255, 0.6)"
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppActionSheet id="Share" webModal={isWeb} onClose={closeSheet}>
|
<AppActionSheet id="Share" webModal={isWeb} onClose={closeSheet}>
|
||||||
{isWeb ? webContent : mobileContent}
|
{isWeb ? (
|
||||||
|
<View
|
||||||
|
ref={modalRef}
|
||||||
|
collapsable={false}
|
||||||
|
style={styles.webContainer}
|
||||||
|
>
|
||||||
|
<View style={styles.webHeader}>
|
||||||
|
<Text style={styles.webHeading}>{heading}</Text>
|
||||||
|
<Pressable
|
||||||
|
onPress={closeSheet}
|
||||||
|
hitSlop={12}
|
||||||
|
style={styles.webCloseButton}
|
||||||
|
>
|
||||||
|
<Feather name="x" size={16} color={Palette.white} />
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={styles.webSubheading}>{shareMessage}</Text>
|
||||||
|
|
||||||
|
<View style={styles.webContent}>
|
||||||
|
<View style={styles.webLinkCard}>
|
||||||
|
<Text style={styles.webLinkLabel}>{linkLabel}</Text>
|
||||||
|
<View style={styles.webLinkActions}>
|
||||||
|
<Pressable
|
||||||
|
onPress={handleCopy}
|
||||||
|
style={[
|
||||||
|
styles.webActionButton,
|
||||||
|
styles.webPrimaryButton,
|
||||||
|
copied && styles.webActionButtonActive,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Feather
|
||||||
|
name={copied ? "check" : "copy"}
|
||||||
|
size={16}
|
||||||
|
color={Palette.white}
|
||||||
|
/>
|
||||||
|
<Text style={styles.webActionLabel}>
|
||||||
|
{copied ? "Lien copié" : "Copier le lien"}
|
||||||
|
</Text>
|
||||||
|
</Pressable>
|
||||||
|
|
||||||
|
<Pressable
|
||||||
|
onPress={onSystemShare}
|
||||||
|
style={[styles.webActionButton, styles.webSecondaryButton]}
|
||||||
|
>
|
||||||
|
<Feather name="share-2" size={16} color={Palette.white} />
|
||||||
|
<Text style={styles.webActionLabel}>Partager</Text>
|
||||||
|
</Pressable>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.webOptionsCard}>
|
||||||
|
<Text style={styles.webSectionHeading}>{sectionTitle}</Text>
|
||||||
|
<View style={styles.webOptionsGrid}>
|
||||||
|
{shareOptions.map((option, index) => {
|
||||||
|
const Icon = option?.Icon ?? Feather;
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
key={option?.key || index}
|
||||||
|
onPress={() => handleShareOption(option)}
|
||||||
|
style={styles.webOptionRow}
|
||||||
|
>
|
||||||
|
<View style={styles.webOptionIcon}>
|
||||||
|
<Icon size={18} color={Palette.white} />
|
||||||
|
</View>
|
||||||
|
<Text style={styles.webOptionLabel}>{option?.label}</Text>
|
||||||
|
<Feather
|
||||||
|
name="chevron-right"
|
||||||
|
size={16}
|
||||||
|
color="rgba(255, 255, 255, 0.6)"
|
||||||
|
/>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
mobileContent
|
||||||
|
)}
|
||||||
</AppActionSheet>
|
</AppActionSheet>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ const ShareQrModal = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<View style={StyleSheet.absoluteFill} pointerEvents="box-none">
|
<View style={styles.overlay}>
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={onClose}
|
onPress={onClose}
|
||||||
style={[StyleSheet.absoluteFill, styles.backdrop]}
|
accessibilityRole="button"
|
||||||
|
style={styles.backdrop}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={styles.centerWrapper} pointerEvents="box-none">
|
<View style={styles.centerWrapper} pointerEvents="box-none">
|
||||||
@@ -71,7 +72,12 @@ const ShareQrModal = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
zIndex: 200,
|
||||||
|
},
|
||||||
backdrop: {
|
backdrop: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.65)",
|
backgroundColor: "rgba(0, 0, 0, 0.65)",
|
||||||
},
|
},
|
||||||
centerWrapper: {
|
centerWrapper: {
|
||||||
|
|||||||
Reference in New Issue
Block a user