-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathWebViewContainer.tsx
More file actions
122 lines (109 loc) · 3.6 KB
/
Copy pathWebViewContainer.tsx
File metadata and controls
122 lines (109 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import { useScripts } from "@/src/features/scripts/hooks/useScripts";
import { useCallback, useRef } from "react";
import { StyleSheet, View, ViewProps } from "react-native";
import {
WebView,
WebViewMessageEvent,
WebViewNavigation,
} from "react-native-webview";
import { useBrowser } from "../../hooks/useBrowser";
import { normalizeUrl } from "../../utils/urlUtils";
const SCROLL_DIRECTION_THRESHOLD = 8;
function getInjectionScripts(
url: string,
runAt: "document-start" | "document-ready" | "document-end",
getScriptsByRunAt: any
) {
return getScriptsByRunAt(url, runAt)
.map((script: any) => script.code)
.join("\n");
}
type WebViewContainerProps = {
bottomPadding?: number;
onScrollDirectionChange?: (direction: "up" | "down") => void;
} & ViewProps;
export default function WebViewContainer({
bottomPadding = 0,
style,
onScrollDirectionChange,
...props
}: WebViewContainerProps) {
const { activeTab, updateTabById } = useBrowser();
const { getScriptsByRunAt, logExecution } = useScripts();
const webviewRef = useRef<WebView>(null);
// Prepare URL
const url = activeTab?.url ? normalizeUrl(activeTab.url) : "about:blank";
// Inject scripts at different lifecycle points
const injectedJavaScriptBeforeContentLoaded = activeTab?.url
? getInjectionScripts(url, "document-start", getScriptsByRunAt)
: "";
const injectedJavaScript = activeTab?.url
? getInjectionScripts(url, "document-ready", getScriptsByRunAt)
: "";
// Handle navigation events
const onNavigationStateChange = useCallback(
(navState: WebViewNavigation) => {
if (!activeTab) return;
updateTabById(activeTab.id, {
url: navState.url,
title: navState.title ?? "",
canGoBack: navState.canGoBack,
canGoForward: navState.canGoForward,
isLoading: navState.loading,
});
},
[activeTab, updateTabById]
);
// Handle JS execution results
const onMessage = useCallback((event: WebViewMessageEvent) => {
// TODO: Log execution results
}, []);
// Inject CSS to add bottom padding to the body
const injectedCSS = `
const style = document.createElement('style');
style.innerHTML = 'body { padding-bottom: ${bottomPadding}px !important; box-sizing: border-box; }';
document.head.appendChild(style);
`;
const lastScrollY = useRef(0);
const lastDirection = useRef<"up" | "down" | null>(null); // pixels
const handleScroll = (event: any) => {
const currentY = event.nativeEvent.contentOffset?.y ?? 0;
const diff = currentY - lastScrollY.current;
if (Math.abs(diff) > SCROLL_DIRECTION_THRESHOLD) {
const newDirection = diff > 0 ? "down" : "up";
if (newDirection !== lastDirection.current) {
onScrollDirectionChange?.(newDirection);
lastDirection.current = newDirection;
}
}
lastScrollY.current = currentY;
};
return (
<View style={[styles.container, style]} {...props}>
<WebView
ref={webviewRef}
source={{ uri: url }}
injectedJavaScriptBeforeContentLoaded={
injectedJavaScriptBeforeContentLoaded
}
injectedJavaScript={injectedJavaScript}
onNavigationStateChange={onNavigationStateChange}
onMessage={onMessage}
startInLoadingState={true}
allowsInlineMediaPlayback
javaScriptEnabled
domStorageEnabled
setSupportMultipleWindows={false}
allowsBackForwardNavigationGestures
originWhitelist={["*"]}
onScroll={handleScroll}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#ecf0f1",
},
});