share modal

This commit is contained in:
2025-10-20 13:58:16 +02:00
parent 8e281e8f78
commit 2cb3af13e2
3 changed files with 169 additions and 86 deletions
+17 -7
View File
@@ -18,15 +18,17 @@ const AppActionSheet = ({
if (isWeb && webModal) {
return (
<Portal>
<View style={styles.webOverlay} pointerEvents="box-none">
<View style={styles.webOverlay}>
<Pressable
onPress={onClose}
style={StyleSheet.absoluteFill}
pointerEvents="auto"
accessibilityRole="button"
style={styles.webBackdrop}
/>
<BlurView intensity={40} tint="dark" style={styles.webModalCard}>
{children}
</BlurView>
<View style={styles.webModalWrapper} pointerEvents="box-none">
<BlurView intensity={40} tint="dark" style={styles.webModalCard}>
{children}
</BlurView>
</View>
</View>
</Portal>
);
@@ -70,10 +72,18 @@ export default AppActionSheet;
const styles = StyleSheet.create({
webOverlay: {
...StyleSheet.absoluteFillObject,
position: "fixed",
zIndex: 100,
},
webBackdrop: {
...StyleSheet.absoluteFillObject,
backgroundColor: "rgba(0, 0, 0, 0.55)",
},
webModalWrapper: {
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 24,
backgroundColor: "rgba(0, 0, 0, 0.55)",
},
webModalCard: {
width: 480,
+144 -77
View File
@@ -18,6 +18,7 @@ import {
StyleSheet,
Text,
View,
findNodeHandle,
} from "react-native";
import { SheetManager } from "react-native-actions-sheet";
@@ -45,15 +46,33 @@ const ShareModal = ({ payload }) => {
const [copied, setCopied] = useState(false);
const copyTimeout = useRef(null);
const modalRef = useRef(null);
const [webVisible, setWebVisible] = useState(true);
const blurProps =
Platform.OS === "android"
? { experimentalBlurMethod: "dimezisBlurView" }
: {};
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(() => {
return [shareMessage, url].filter(Boolean).join(" ");
}, [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 () => {
try {
if (copyTimeout.current) {
@@ -288,85 +347,93 @@ const ShareModal = ({ payload }) => {
</View>
);
const webContent = (
<View 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>
);
if (isWeb && !webVisible) {
return null;
}
return (
<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>
);
};
+8 -2
View File
@@ -23,10 +23,11 @@ const ShareQrModal = ({
return (
<Portal>
<View style={StyleSheet.absoluteFill} pointerEvents="box-none">
<View style={styles.overlay}>
<Pressable
onPress={onClose}
style={[StyleSheet.absoluteFill, styles.backdrop]}
accessibilityRole="button"
style={styles.backdrop}
/>
<View style={styles.centerWrapper} pointerEvents="box-none">
@@ -71,7 +72,12 @@ const ShareQrModal = ({
};
const styles = StyleSheet.create({
overlay: {
...StyleSheet.absoluteFillObject,
zIndex: 200,
},
backdrop: {
...StyleSheet.absoluteFillObject,
backgroundColor: "rgba(0, 0, 0, 0.65)",
},
centerWrapper: {