@exodus/react-native-webview 11.26.1-exodus.5 → 11.26.1-exodus.7

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.
Files changed (126) hide show
  1. package/.all-contributorsrc +185 -0
  2. package/.circleci/config.yml +66 -0
  3. package/.eslintignore +2 -0
  4. package/.eslintrc.js +94 -0
  5. package/.flowconfig +88 -0
  6. package/.flowconfig.android +88 -0
  7. package/.gitattributes +12 -0
  8. package/.github/CODEOWNERS +1 -0
  9. package/.github/ISSUE_TEMPLATE/bug-report.md +42 -0
  10. package/.github/ISSUE_TEMPLATE/feature_request.md +30 -0
  11. package/.github/workflows/android-ci.yml +35 -0
  12. package/.github/workflows/detox.yml +20 -0
  13. package/.github/workflows/ios-ci.yml +31 -0
  14. package/.github/workflows/scripts/install-vs-features.ps1 +108 -0
  15. package/.github/workflows/stale.yml +17 -0
  16. package/.gitignore +62 -0
  17. package/.prettierrc.js +10 -0
  18. package/.releaserc +15 -0
  19. package/.vscode/settings.json +9 -0
  20. package/android/.gradle/7.4.2/checksums/checksums.lock +0 -0
  21. package/android/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  22. package/android/.gradle/7.4.2/dependencies-accessors/gc.properties +0 -0
  23. package/android/.gradle/7.4.2/executionHistory/executionHistory.lock +0 -0
  24. package/android/.gradle/7.4.2/fileChanges/last-build.bin +0 -0
  25. package/android/.gradle/7.4.2/fileHashes/fileHashes.lock +0 -0
  26. package/android/.gradle/7.4.2/gc.properties +0 -0
  27. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  28. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  29. package/android/.gradle/vcs-1/gc.properties +0 -0
  30. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +25 -0
  31. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewUtils.java +51 -0
  32. package/babel.config.js +11 -0
  33. package/bin/setup +26 -0
  34. package/docs/Contributing.md +102 -0
  35. package/docs/Custom-Android.md +222 -0
  36. package/docs/Custom-iOS.md +236 -0
  37. package/docs/Debugging.md +101 -0
  38. package/docs/Getting-Started.md +142 -0
  39. package/docs/Guide.md +613 -0
  40. package/docs/Reference.md +1629 -0
  41. package/example/.gitignore +14 -0
  42. package/example/.watchmanconfig +1 -0
  43. package/example/App.tsx +262 -0
  44. package/example/android/.gradle/7.3.3/checksums/checksums.lock +0 -0
  45. package/example/android/.gradle/7.3.3/checksums/md5-checksums.bin +0 -0
  46. package/example/android/.gradle/7.3.3/checksums/sha1-checksums.bin +0 -0
  47. package/example/android/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock +0 -0
  48. package/example/android/.gradle/7.3.3/dependencies-accessors/gc.properties +0 -0
  49. package/example/android/.gradle/7.3.3/fileChanges/last-build.bin +0 -0
  50. package/example/android/.gradle/7.3.3/fileHashes/fileHashes.lock +0 -0
  51. package/example/android/.gradle/7.3.3/gc.properties +0 -0
  52. package/example/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  53. package/example/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  54. package/example/android/.gradle/vcs-1/gc.properties +0 -0
  55. package/example/android/build.gradle +15 -0
  56. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  57. package/example/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  58. package/example/android/gradle.properties +34 -0
  59. package/example/android/gradlew +234 -0
  60. package/example/android/gradlew.bat +89 -0
  61. package/example/android/settings.gradle +12 -0
  62. package/example/app.json +20 -0
  63. package/example/assets/test.html +9 -0
  64. package/example/babel.config.js +3 -0
  65. package/example/examples/Alerts.tsx +72 -0
  66. package/example/examples/ApplePay.tsx +23 -0
  67. package/example/examples/Background.tsx +54 -0
  68. package/example/examples/Downloads.tsx +57 -0
  69. package/example/examples/Injection.tsx +161 -0
  70. package/example/examples/LocalPageLoad.tsx +16 -0
  71. package/example/examples/Messaging.tsx +63 -0
  72. package/example/examples/NativeWebpage.tsx +22 -0
  73. package/example/examples/Scrolling.tsx +68 -0
  74. package/example/examples/Uploads.tsx +69 -0
  75. package/example/index.js +9 -0
  76. package/example/ios/Podfile +8 -0
  77. package/example/ios/Podfile.lock +445 -0
  78. package/index.js +5 -2
  79. package/ios/Podfile +10 -0
  80. package/ios/Podfile.lock +3 -0
  81. package/ios/Pods/Manifest.lock +3 -0
  82. package/ios/Pods/Pods.xcodeproj/project.pbxproj +397 -0
  83. package/ios/Pods/Pods.xcodeproj/xcuserdata/gabrielezenwankwo.xcuserdatad/xcschemes/Pods-RNCWebView.xcscheme +58 -0
  84. package/ios/Pods/Pods.xcodeproj/xcuserdata/gabrielezenwankwo.xcuserdatad/xcschemes/xcschememanagement.plist +16 -0
  85. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView-Info.plist +26 -0
  86. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView-acknowledgements.markdown +3 -0
  87. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView-acknowledgements.plist +29 -0
  88. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView-dummy.m +5 -0
  89. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView-umbrella.h +16 -0
  90. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView.debug.xcconfig +8 -0
  91. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView.modulemap +6 -0
  92. package/ios/Pods/Target Support Files/Pods-RNCWebView/Pods-RNCWebView.release.xcconfig +8 -0
  93. package/ios/RNCWebView.xcworkspace/contents.xcworkspacedata +32 -0
  94. package/jest-setups/jest.setup.js +8 -0
  95. package/jest.config.js +184 -0
  96. package/lib/UpdateOS.d.ts +6 -0
  97. package/lib/UpdateOS.d.ts.map +1 -0
  98. package/lib/UpdateOS.js +49 -0
  99. package/lib/WebView.android.d.ts.map +1 -0
  100. package/lib/WebView.android.js +19 -3
  101. package/lib/WebView.d.ts.map +1 -0
  102. package/lib/WebView.ios.d.ts.map +1 -0
  103. package/lib/WebView.ios.js +5 -2
  104. package/lib/WebView.styles.d.ts.map +1 -0
  105. package/lib/WebViewNativeComponent.android.d.ts.map +1 -0
  106. package/lib/WebViewNativeComponent.ios.d.ts.map +1 -0
  107. package/lib/WebViewShared.d.ts.map +1 -0
  108. package/lib/WebViewTypes.d.ts +5 -1
  109. package/lib/WebViewTypes.d.ts.map +1 -0
  110. package/lib/index.d.ts.map +1 -0
  111. package/metro.config.js +57 -0
  112. package/package.json +1 -1
  113. package/src/WebView.android.tsx +246 -0
  114. package/src/WebView.ios.tsx +221 -0
  115. package/src/WebView.styles.ts +44 -0
  116. package/src/WebView.tsx +18 -0
  117. package/src/WebViewNativeComponent.android.ts +8 -0
  118. package/src/WebViewNativeComponent.ios.ts +8 -0
  119. package/src/WebViewShared.tsx +257 -0
  120. package/src/WebViewTypes.ts +914 -0
  121. package/src/__tests__/WebViewShared-test.js +208 -0
  122. package/src/__tests__/__snapshots__/WebViewShared-test.js.snap +8 -0
  123. package/src/index.ts +4 -0
  124. package/tsconfig.json +24 -0
  125. package/yarn.lock +13895 -0
  126. package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt +0 -15
@@ -0,0 +1,257 @@
1
+ import escapeStringRegexp from 'escape-string-regexp';
2
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
3
+ import { Linking, View, ActivityIndicator, Text, Platform } from 'react-native';
4
+ import {
5
+ OnShouldStartLoadWithRequest,
6
+ ShouldStartLoadRequestEvent,
7
+ WebViewError,
8
+ WebViewErrorEvent,
9
+ WebViewMessageEvent,
10
+ WebViewMessage,
11
+ WebViewNavigationEvent,
12
+ WebViewProgressEvent,
13
+ WebViewNativeEvent,
14
+ } from './WebViewTypes';
15
+ import styles from './WebView.styles';
16
+
17
+ const defaultOriginWhitelist = ['https://*'] as const;
18
+
19
+ const extractOrigin = (url: string): string => {
20
+ const result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url);
21
+ return result === null ? '' : result[0];
22
+ };
23
+
24
+ const originWhitelistToRegex = (originWhitelist: string): string =>
25
+ `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}$`;
26
+
27
+ const _passesWhitelist = (
28
+ compiledWhitelist: readonly string[],
29
+ url: string,
30
+ ) => {
31
+ const origin = extractOrigin(url);
32
+ if (!origin) return false;
33
+ if (origin !== new URL(url).origin) return null;
34
+ return compiledWhitelist.some(x => new RegExp(x).test(origin));
35
+ };
36
+
37
+ const compileWhitelist = (
38
+ originWhitelist: readonly string[],
39
+ ): readonly string[] =>
40
+ ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
41
+
42
+ const createOnShouldStartLoadWithRequest = (
43
+ loadRequest: (
44
+ shouldStart: boolean,
45
+ url: string,
46
+ lockIdentifier: number,
47
+ ) => void,
48
+ originWhitelist: readonly string[],
49
+ onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest,
50
+ ) => {
51
+ return ({ nativeEvent }: ShouldStartLoadRequestEvent) => {
52
+ let shouldStart = true;
53
+ const { url, lockIdentifier } = nativeEvent;
54
+
55
+ if (!_passesWhitelist(compileWhitelist(originWhitelist), url)) {
56
+ Linking.canOpenURL(url).then((supported) => {
57
+ if (supported && /^https:\/\//.test(url)) {
58
+ return Linking.openURL(url);
59
+ }
60
+ console.warn(`Can't open url: ${url}`);
61
+ return undefined;
62
+ }).catch(e => {
63
+ console.warn('Error opening URL: ', e);
64
+ });
65
+ shouldStart = false;
66
+ } else if (onShouldStartLoadWithRequest) {
67
+ shouldStart = onShouldStartLoadWithRequest(nativeEvent);
68
+ }
69
+
70
+ loadRequest(shouldStart, url, lockIdentifier);
71
+ };
72
+ };
73
+
74
+ const defaultRenderLoading = () => (
75
+ <View style={styles.loadingOrErrorView}>
76
+ <ActivityIndicator />
77
+ </View>
78
+ );
79
+ const defaultRenderError = (
80
+ errorDomain: string | undefined,
81
+ errorCode: number,
82
+ errorDesc: string,
83
+ ) => (
84
+ <View style={styles.loadingOrErrorView}>
85
+ <Text style={styles.errorTextTitle}>Error loading page</Text>
86
+ <Text style={styles.errorText}>{`Domain: ${errorDomain}`}</Text>
87
+ <Text style={styles.errorText}>{`Error Code: ${errorCode}`}</Text>
88
+ <Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
89
+ </View>
90
+ );
91
+
92
+ export {
93
+ defaultOriginWhitelist,
94
+ createOnShouldStartLoadWithRequest,
95
+ defaultRenderLoading,
96
+ defaultRenderError,
97
+ };
98
+
99
+
100
+ export const useWebWiewLogic = ({
101
+ startInLoadingState,
102
+ onLoadStart,
103
+ onLoad,
104
+ onLoadEnd,
105
+ onError,
106
+ onMessageProp,
107
+ originWhitelist,
108
+ onShouldStartLoadWithRequestProp,
109
+ onShouldStartLoadWithRequestCallback,
110
+ validateMeta,
111
+ validateData,
112
+ }: {
113
+ startInLoadingState?: boolean
114
+ onLoadStart?: (event: WebViewNavigationEvent) => void;
115
+ onLoad?: (event: WebViewNavigationEvent) => void;
116
+ onLoadEnd?: (event: WebViewNavigationEvent | WebViewErrorEvent) => void;
117
+ onError?: (event: WebViewErrorEvent) => void;
118
+ onMessageProp?: (event: WebViewMessage) => void;
119
+ originWhitelist: readonly string[];
120
+ onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest;
121
+ onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string, lockIdentifier?: number | undefined) => void;
122
+ validateMeta: (event: WebViewNativeEvent) => WebViewNativeEvent;
123
+ validateData: (data: object) => object;
124
+ }) => {
125
+
126
+ const [viewState, setViewState] = useState<'IDLE' | 'LOADING' | 'ERROR'>(startInLoadingState ? "LOADING" : "IDLE");
127
+ const [lastErrorEvent, setLastErrorEvent] = useState<WebViewError | null>(null);
128
+ const startUrl = useRef<string | null>(null)
129
+
130
+ const passesWhitelist = (url: string) => {
131
+ if (!url || typeof url !== 'string') return false;
132
+ return _passesWhitelist(compileWhitelist(originWhitelist), url);
133
+ }
134
+
135
+ const passesWhitelistUse = useCallback(passesWhitelist, [originWhitelist])
136
+
137
+ const extractMeta = (nativeEvent: WebViewNativeEvent): WebViewNativeEvent => ({
138
+ url: String(nativeEvent.url),
139
+ loading: Boolean(nativeEvent.loading),
140
+ title: String(nativeEvent.title),
141
+ canGoBack: Boolean(nativeEvent.canGoBack),
142
+ canGoForward: Boolean(nativeEvent.canGoForward),
143
+ lockIdentifier: Number(nativeEvent.lockIdentifier),
144
+ });
145
+
146
+ const onLoadingStart = useCallback((event: WebViewNavigationEvent) => {
147
+ // Needed for android
148
+ startUrl.current = event.nativeEvent.url;
149
+ // !Needed for android
150
+
151
+ onLoadStart?.(event);
152
+ }, [onLoadStart]);
153
+
154
+ const onLoadingError = useCallback((event: WebViewErrorEvent) => {
155
+ event.persist();
156
+ if (onError) {
157
+ onError(event);
158
+ } else {
159
+ console.warn('Encountered an error loading page', event.nativeEvent);
160
+ }
161
+ onLoadEnd?.(event);
162
+ if (event.isDefaultPrevented()) { return };
163
+ setViewState('ERROR');
164
+ setLastErrorEvent(event.nativeEvent);
165
+ }, [onError, onLoadEnd]);
166
+
167
+ const onLoadingFinish = useCallback((event: WebViewNavigationEvent) => {
168
+ onLoad?.(event);
169
+ onLoadEnd?.(event);
170
+ const { nativeEvent: { url } } = event;
171
+ if (!passesWhitelistUse(url)) return;
172
+
173
+ // on Android, only if url === startUrl
174
+ if (Platform.OS !== "android" || url === startUrl.current) {
175
+ setViewState('IDLE');
176
+ }
177
+ // !on Android, only if url === startUrl
178
+ // REMOVED: updateNavigationState(event);
179
+ }, [onLoad, onLoadEnd, passesWhitelistUse]);
180
+
181
+ const onMessage = useCallback((event: WebViewMessageEvent) => {
182
+ const { nativeEvent } = event;
183
+ if (!passesWhitelistUse(nativeEvent.url)) return;
184
+
185
+ // TODO: can/should we perform any other validation?
186
+
187
+ const data = JSON.stringify(validateData(JSON.parse(nativeEvent.data)));
188
+ const meta = validateMeta(extractMeta(nativeEvent));
189
+
190
+ onMessageProp?.({ ...meta, data });
191
+ }, [onMessageProp, passesWhitelistUse, validateData, validateMeta]);
192
+
193
+ const onLoadingProgress = useCallback((event: WebViewProgressEvent) => {
194
+ const { nativeEvent: { progress } } = event;
195
+ if (!passesWhitelistUse(event.nativeEvent.url)) return;
196
+
197
+ // patch for Android only
198
+ if (Platform.OS === "android" && progress === 1) {
199
+ setViewState(prevViewState => prevViewState === 'LOADING' ? 'IDLE' : prevViewState);
200
+ }
201
+ // !patch for Android only
202
+ // REMOVED: onLoadProgress?.(event);
203
+ }, [passesWhitelistUse]);
204
+
205
+ const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(
206
+ onShouldStartLoadWithRequestCallback,
207
+ originWhitelist,
208
+ onShouldStartLoadWithRequestProp,
209
+ )
210
+ , [originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback])
211
+
212
+ return {
213
+ onShouldStartLoadWithRequest,
214
+ onLoadingStart,
215
+ onLoadingProgress,
216
+ onLoadingError,
217
+ onLoadingFinish,
218
+ onMessage,
219
+ passesWhitelist,
220
+ viewState,
221
+ setViewState,
222
+ lastErrorEvent,
223
+ }
224
+ };
225
+
226
+ export const versionPasses = (version: string | undefined, minimum: string | undefined): boolean => {
227
+ if (!version || !minimum) return false
228
+ if (typeof version !== 'string' || typeof minimum !== 'string') return false
229
+
230
+ if (minimum.includes(', ')) {
231
+ // We have a set of possible versions
232
+ const variants = minimum.split(', ')
233
+ // Every entry but the last one should be with an upper bound
234
+ if (!variants.slice(0, -1).every(x => x.includes(' <'))) return false
235
+ return variants.some(x => versionPasses(version, x)) // Any match passes
236
+ }
237
+
238
+ if (minimum.includes(' <')) {
239
+ const [min, max, ...rest] = minimum.split(' <')
240
+ if (rest.length > 0) return false
241
+ // Last check is required for correctness/formatting validation
242
+ return versionPasses(version, min) && !versionPasses(version, max) && versionPasses(max, version)
243
+ }
244
+
245
+ const versionRegex = /^[0-9]+(\.[0-9]+)*$/
246
+ if (!versionRegex.test(version) || !versionRegex.test(minimum)) return false
247
+ const versionParts = version.split('.').map(Number)
248
+ const minimumParts = minimum.split('.').map(Number)
249
+ const len = Math.max(versionParts.length, minimumParts.length)
250
+ for (let i = 0; i < len; i += 1) {
251
+ const ver = versionParts[i] || 0
252
+ const min = minimumParts[i] || 0
253
+ if (ver > min) return true
254
+ if (ver < min) return false
255
+ }
256
+ return true // equals
257
+ }