share modal
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user