Browse Source

feat(typescript): Source code rewrite using typescript (#425)

Rewrote the whole repository into typescript. This will provide way better and up to date documentation. This should also add some safety for people contributing 😄 .
Flow types were not working until now which is why this PR doesn't have them but feel free to PR.

This also fixes #384 #435 #206 #171 #168.
Thibault Malbranche 5 years ago
parent
commit
453b7dd3a0
No account linked to committer's email address

+ 1
- 1
.circleci/config.yml View File

@@ -35,7 +35,7 @@ jobs:
35 35
 
36 36
       - run:
37 37
           name: Run Tests
38
-          command: yarn ci:test
38
+          command: yarn ci
39 39
 
40 40
   publish:
41 41
     <<: *defaults

+ 1
- 0
.eslintignore View File

@@ -0,0 +1 @@
1
+lib/

+ 75
- 0
.eslintrc.js View File

@@ -0,0 +1,75 @@
1
+module.exports = {
2
+  // Airbnb is the base, prettier is here so that eslint doesn't conflict with prettier
3
+  extends: ['airbnb', 'prettier', 'prettier/react'],
4
+  parser: '@typescript-eslint/parser',
5
+  plugins: ['react', 'react-native', 'import', '@typescript-eslint'],
6
+  rules: {
7
+    'no-console': 'off',
8
+    // Lines will be broken before binary operators
9
+    'operator-linebreak': ['error', 'before'],
10
+    // Allow imports from dev and peer dependencies
11
+    'import/no-extraneous-dependencies': [
12
+      'error',
13
+      { devDependencies: true, peerDependencies: true },
14
+    ],
15
+    'react/jsx-filename-extension': ['error', { extensions: ['.tsx'] }],
16
+    // This rule doesn't play nice with Prettier
17
+    'react/jsx-one-expression-per-line': 'off',
18
+    // This rule doesn't play nice with Prettier
19
+    'react/jsx-wrap-multilines': 'off',
20
+    // Remove this rule because we only destructure props, but never state
21
+    'react/destructuring-assignment': 'off',
22
+    'react/prop-types': 'off',
23
+    '@typescript-eslint/adjacent-overload-signatures': 'error',
24
+    '@typescript-eslint/array-type': ['error', 'array'],
25
+    '@typescript-eslint/generic-type-naming': ['error', '^[a-zA-Z]+$'],
26
+    '@typescript-eslint/no-angle-bracket-type-assertion': 'error',
27
+    '@typescript-eslint/no-array-constructor': 'error',
28
+    '@typescript-eslint/no-empty-interface': 'error',
29
+    '@typescript-eslint/no-explicit-any': 'error',
30
+    '@typescript-eslint/no-extraneous-class': 'error',
31
+    '@typescript-eslint/no-inferrable-types': 'error',
32
+    '@typescript-eslint/no-misused-new': 'error',
33
+    '@typescript-eslint/no-namespace': 'error',
34
+    '@typescript-eslint/no-non-null-assertion': 'error',
35
+    '@typescript-eslint/no-object-literal-type-assertion': 'error',
36
+    '@typescript-eslint/no-parameter-properties': 'error',
37
+    '@typescript-eslint/no-this-alias': 'error',
38
+    '@typescript-eslint/no-triple-slash-reference': 'error',
39
+    '@typescript-eslint/no-type-alias': [
40
+      'error',
41
+      {
42
+        allowAliases: 'always',
43
+        allowCallbacks: 'always',
44
+        allowMappedTypes: 'always',
45
+      },
46
+    ],
47
+    '@typescript-eslint/no-unused-vars': [
48
+      'error',
49
+      { ignoreRestSiblings: true },
50
+    ],
51
+    '@typescript-eslint/prefer-interface': 'error',
52
+    '@typescript-eslint/prefer-namespace-keyword': 'error',
53
+    '@typescript-eslint/type-annotation-spacing': 'error',
54
+  },
55
+  settings: {
56
+    'import/resolver': {
57
+      node: {
58
+        extensions: [
59
+          '.js',
60
+          '.android.js',
61
+          '.ios.js',
62
+          '.jsx',
63
+          '.android.jsx',
64
+          '.ios.jsx',
65
+          '.tsx',
66
+          '.ts',
67
+          '.android.tsx',
68
+          '.android.ts',
69
+          '.ios.tsx',
70
+          '.ios.ts',
71
+        ],
72
+      },
73
+    },
74
+  },
75
+};

+ 3
- 1
.gitignore View File

@@ -51,4 +51,6 @@ bundles/
51 51
 
52 52
 android/gradle
53 53
 android/gradlew
54
-android/gradlew.bat
54
+android/gradlew.bat
55
+
56
+lib/

+ 10
- 0
.prettierrc.js View File

@@ -0,0 +1,10 @@
1
+// https://prettier.io/docs/en/options.html
2
+
3
+module.exports = {
4
+  // Enables semicolons at the end of statements
5
+  semi: true,
6
+  // Formats strings with single quotes ('') instead of quotes ("")
7
+  singleQuote: true,
8
+  // Adds a trailing comma at the end of all lists (including function arguments)
9
+  trailingComma: 'all',
10
+};

+ 9
- 0
.vscode/settings.json View File

@@ -0,0 +1,9 @@
1
+{
2
+  "typescript.tsdk": "node_modules/typescript/lib",
3
+  "eslint.validate": [
4
+    "javascript",
5
+    "javascriptreact",
6
+    "typescript",
7
+    "typescriptreact"
8
+  ]
9
+}

+ 94
- 96
docs/Reference.md View File

@@ -96,9 +96,9 @@ _Note that using static HTML requires the WebView property [originWhiteList](Ref
96 96
 
97 97
 Controls whether to adjust the content inset for web views that are placed behind a navigation bar, tab bar, or toolbar. The default value is `true`.
98 98
 
99
-| Type | Required |
100
-| ---- | -------- |
101
-| bool | No       |
99
+| Type | Required | Platform |
100
+| ---- | -------- | -------- |
101
+| bool | No       | iOS      |
102 102
 
103 103
 ---
104 104
 
@@ -154,28 +154,29 @@ Example:
154 154
 
155 155
 ```jsx
156 156
 <WebView
157
-   source={{ uri: "https://facebook.github.io/react-native" }}
158
-   onError={(syntheticEvent) => {
159
-     const { nativeEvent } = syntheticEvent
160
-     console.warn('WebView error: ', nativeEvent)
161
-   }}
162
- />
157
+  source={{ uri: 'https://facebook.github.io/react-native' }}
158
+  onError={syntheticEvent => {
159
+    const { nativeEvent } = syntheticEvent;
160
+    console.warn('WebView error: ', nativeEvent);
161
+  }}
162
+/>
163 163
 ```
164 164
 
165 165
 Function passed to `onError` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
166 166
 
167
- ```
168
- canGoBack
169
- canGoForward
170
- code
171
- description
172
- didFailProvisionalNavigation
173
- domain
174
- loading
175
- target
176
- title
177
- url
178 167
 ```
168
+canGoBack
169
+canGoForward
170
+code
171
+description
172
+didFailProvisionalNavigation
173
+domain
174
+loading
175
+target
176
+title
177
+url
178
+```
179
+
179 180
 > **_Note_**
180 181
 > Domain is only used on iOS
181 182
 
@@ -193,8 +194,8 @@ Example:
193 194
 
194 195
 ```jsx
195 196
 <WebView
196
-  source={{uri: 'https://facebook.github.io/react-native'}}
197
-  onLoad={(syntheticEvent) => {
197
+  source={{ uri: 'https://facebook.github.io/react-native' }}
198
+  onLoad={syntheticEvent => {
198 199
     const { nativeEvent } = syntheticEvent;
199 200
     this.url = nativeEvent.url;
200 201
   }}
@@ -203,13 +204,13 @@ Example:
203 204
 
204 205
 Function passed to `onLoad` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
205 206
 
206
- ```
207
- canGoBack
208
- canGoForward
209
- loading
210
- target
211
- title
212
- url
207
+```
208
+canGoBack
209
+canGoForward
210
+loading
211
+target
212
+title
213
+url
213 214
 ```
214 215
 
215 216
 ---
@@ -222,13 +223,12 @@ Function that is invoked when the `WebView` load succeeds or fails.
222 223
 | -------- | -------- |
223 224
 | function | No       |
224 225
 
225
-
226 226
 Example:
227 227
 
228 228
 ```jsx
229 229
 <WebView
230
-  source={{uri: 'https://facebook.github.io/react-native'}}
231
-  onLoadEnd={(syntheticEvent) => {
230
+  source={{ uri: 'https://facebook.github.io/react-native' }}
231
+  onLoadEnd={syntheticEvent => {
232 232
     // update component to be aware of loading status
233 233
     const { nativeEvent } = syntheticEvent;
234 234
     this.isLoading = nativeEvent.loading;
@@ -238,13 +238,13 @@ Example:
238 238
 
239 239
 Function passed to `onLoadEnd` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
240 240
 
241
- ```
242
- canGoBack
243
- canGoForward
244
- loading
245
- target
246
- title
247
- url
241
+```
242
+canGoBack
243
+canGoForward
244
+loading
245
+target
246
+title
247
+url
248 248
 ```
249 249
 
250 250
 ---
@@ -257,13 +257,12 @@ Function that is invoked when the `WebView` starts loading.
257 257
 | -------- | -------- |
258 258
 | function | No       |
259 259
 
260
-
261 260
 Example:
262 261
 
263 262
 ```jsx
264 263
 <WebView
265
-  source={{uri: 'https://facebook.github.io/react-native/='}}
266
-  onLoadStart={(syntheticEvent) => {
264
+  source={{ uri: 'https://facebook.github.io/react-native/=' }}
265
+  onLoadStart={syntheticEvent => {
267 266
     // update component to be aware of loading status
268 267
     const { nativeEvent } = syntheticEvent;
269 268
     this.isLoading = nativeEvent.loading;
@@ -273,13 +272,13 @@ Example:
273 272
 
274 273
 Function passed to `onLoadStart` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
275 274
 
276
- ```
277
- canGoBack
278
- canGoForward
279
- loading
280
- target
281
- title
282
- url
275
+```
276
+canGoBack
277
+canGoForward
278
+loading
279
+target
280
+title
281
+url
283 282
 ```
284 283
 
285 284
 ---
@@ -301,23 +300,23 @@ Example:
301 300
 
302 301
 ```jsx
303 302
 <WebView
304
-   source={{ uri: "https://facebook.github.io/react-native" }}
305
-   onLoadProgress={({ nativeEvent }) => {
306
-     this.loadingProgress = nativeEvent.progress
307
-   }}
308
- />
303
+  source={{ uri: 'https://facebook.github.io/react-native' }}
304
+  onLoadProgress={({ nativeEvent }) => {
305
+    this.loadingProgress = nativeEvent.progress;
306
+  }}
307
+/>
309 308
 ```
310 309
 
311 310
 Function passed to `onLoadProgress` is called with a SyntheticEvent wrapping a nativeEvent with these properties:
312 311
 
313
- ```
314
- canGoBack
315
- canGoForward
316
- loading
317
- progress
318
- target
319
- title
320
- url
312
+```
313
+canGoBack
314
+canGoForward
315
+loading
316
+progress
317
+target
318
+title
319
+url
321 320
 ```
322 321
 
323 322
 ---
@@ -348,23 +347,24 @@ Example:
348 347
 
349 348
 ```jsx
350 349
 <WebView
351
-   source={{ uri: "https://facebook.github.io/react-native" }}
352
-   onNavigationStateChange={(navState) => {
350
+  source={{ uri: 'https://facebook.github.io/react-native' }}
351
+  onNavigationStateChange={navState => {
353 352
     // Keep track of going back navigation within component
354 353
     this.canGoBack = navState.canGoBack;
355
-}} />
354
+  }}
355
+/>
356 356
 ```
357 357
 
358 358
 The `navState` object includes these properties:
359 359
 
360
- ```
361
- canGoBack
362
- canGoForward
363
- loading
364
- navigationType
365
- target
366
- title
367
- url
360
+```
361
+canGoBack
362
+canGoForward
363
+loading
364
+navigationType
365
+target
366
+title
367
+url
368 368
 ```
369 369
 
370 370
 ---
@@ -382,9 +382,9 @@ Example:
382 382
 ```jsx
383 383
 //only allow URIs that begin with https:// or git://
384 384
 <WebView
385
-   source={{ uri: "https://facebook.github.io/react-native" }}
386
-   originWhitelist={['https://*', 'git://*']}
387
- />
385
+  source={{ uri: 'https://facebook.github.io/react-native' }}
386
+  originWhitelist={['https://*', 'git://*']}
387
+/>
388 388
 ```
389 389
 
390 390
 ---
@@ -397,17 +397,16 @@ Function that returns a view to show if there's an error.
397 397
 | -------- | -------- |
398 398
 | function | No       |
399 399
 
400
-
401 400
 Example:
402 401
 
403 402
 ```jsx
404 403
 <WebView
405
-   source={{ uri: "https://facebook.github.io/react-native" }}
406
-   renderError={(errorName) => <Error name={errorName} /> }
407
- />
404
+  source={{ uri: 'https://facebook.github.io/react-native' }}
405
+  renderError={errorName => <Error name={errorName} />}
406
+/>
408 407
 ```
409 408
 
410
-The function passed to `renderError` will be called with the name of the error 
409
+The function passed to `renderError` will be called with the name of the error
411 410
 
412 411
 ---
413 412
 
@@ -419,15 +418,14 @@ Function that returns a loading indicator. The startInLoadingState prop must be
419 418
 | -------- | -------- |
420 419
 | function | No       |
421 420
 
422
-
423 421
 Example:
424 422
 
425 423
 ```jsx
426 424
 <WebView
427
-   source={{ uri: "https://facebook.github.io/react-native" }}
428
-   startInLoadingState={true}
429
-   renderLoading={() => <Loading /> }
430
- />
425
+  source={{ uri: 'https://facebook.github.io/react-native' }}
426
+  startInLoadingState={true}
427
+  renderLoading={() => <Loading />}
428
+/>
431 429
 ```
432 430
 
433 431
 ---
@@ -446,7 +444,7 @@ On iOS, when [`useWebKit=true`](Reference.md#usewebkit), this prop will not work
446 444
 
447 445
 ### `onShouldStartLoadWithRequest`
448 446
 
449
-Function that allows custom handling of any web view requests. Return `true` from the function to continue loading the request and `false` to stop loading. 
447
+Function that allows custom handling of any web view requests. Return `true` from the function to continue loading the request and `false` to stop loading.
450 448
 
451 449
 On Android, is not called on the first load.
452 450
 
@@ -458,10 +456,10 @@ Example:
458 456
 
459 457
 ```jsx
460 458
 <WebView
461
-  source={{ uri: "https://facebook.github.io/react-native" }}
462
-  onShouldStartLoadWithRequest={(request) => {
459
+  source={{ uri: 'https://facebook.github.io/react-native' }}
460
+  onShouldStartLoadWithRequest={request => {
463 461
     // Only allow navigating within this website
464
-    return request.url.startsWith("https://facebook.github.io/react-native")
462
+    return request.url.startsWith('https://facebook.github.io/react-native');
465 463
   }}
466 464
 />
467 465
 ```
@@ -483,10 +481,10 @@ Example:
483 481
 
484 482
 ```jsx
485 483
 <WebView
486
-  source={{ uri: "https://facebook.github.io/react-native" }}
487
-  onShouldStartLoadWithRequest={(request) => {
484
+  source={{ uri: 'https://facebook.github.io/react-native' }}
485
+  onShouldStartLoadWithRequest={request => {
488 486
     // Only allow navigating within this website
489
-    return request.url.startsWith("https://facebook.github.io/react-native")
487
+    return request.url.startsWith('https://facebook.github.io/react-native');
490 488
   }}
491 489
 />
492 490
 ```
@@ -528,9 +526,9 @@ Example:
528 526
 
529 527
 ```jsx
530 528
 <WebView
531
-   source={{ uri: "https://facebook.github.io/react-native" }}
532
-   style={{marginTop: 20}}
533
- />
529
+  source={{ uri: 'https://facebook.github.io/react-native' }}
530
+  style={{ marginTop: 20 }}
531
+/>
534 532
 ```
535 533
 
536 534
 ---

+ 8
- 0
index.d.ts View File

@@ -0,0 +1,8 @@
1
+import { ComponentType } from 'react';
2
+// eslint-disable-next-line
3
+import { IOSWebViewProps, AndroidWebViewProps } from './lib/WebViewTypes';
4
+
5
+declare const WebView: ComponentType<IOSWebViewProps & AndroidWebViewProps>;
6
+
7
+export { WebView };
8
+export default WebView;

+ 2
- 1
index.js View File

@@ -1,3 +1,4 @@
1
-import WebView from './js/WebView';
1
+import WebView from './lib/WebView';
2 2
 
3 3
 export { WebView };
4
+export default WebView;

+ 8
- 3
jest.config.js View File

@@ -88,7 +88,7 @@ module.exports = {
88 88
   // notifyMode: "failure-change",
89 89
 
90 90
   // A preset that is used as a base for Jest's configuration
91
-  preset: "react-native",
91
+  preset: 'react-native',
92 92
 
93 93
   // Run tests from one or more projects
94 94
   // projects: null,
@@ -129,7 +129,7 @@ module.exports = {
129 129
   // snapshotSerializers: [],
130 130
 
131 131
   // The test environment that will be used for testing
132
-  testEnvironment: "node",
132
+  testEnvironment: 'node',
133 133
 
134 134
   // Options that will be passed to the testEnvironment
135 135
   // testEnvironmentOptions: {},
@@ -164,7 +164,12 @@ module.exports = {
164 164
   // timers: "real",
165 165
 
166 166
   // A map from regular expressions to paths to transformers
167
-  // transform: null,
167
+  transform: {
168
+    '^.+\\.ts(x)?$': 'ts-jest',
169
+    '^.+\\.js$': 'babel-jest',
170
+    '^.+\\.(bmp|gif|jpg|jpeg|mp4|png|psd|svg|webp)$':
171
+      '<rootDir>/node_modules/react-native/jest/assetFileTransformer.js',
172
+  },
168 173
 
169 174
   // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
170 175
   // transformIgnorePatterns: [

+ 0
- 352
js/WebView.android.js View File

@@ -1,352 +0,0 @@
1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11
-import React from 'react';
12
-
13
-import ReactNative, {
14
-  ActivityIndicator,
15
-  Image,
16
-  requireNativeComponent,
17
-  StyleSheet,
18
-  UIManager,
19
-  View,
20
-  NativeModules,
21
-} from 'react-native';
22
-
23
-import invariant from 'fbjs/lib/invariant';
24
-import keyMirror from 'fbjs/lib/keyMirror';
25
-
26
-import {
27
-  defaultOriginWhitelist,
28
-  createOnShouldStartLoadWithRequest,
29
-} from './WebViewShared';
30
-import type {
31
-  WebViewError,
32
-  WebViewErrorEvent,
33
-  WebViewMessageEvent,
34
-  WebViewNavigationEvent,
35
-  WebViewProgressEvent,
36
-  WebViewSharedProps,
37
-  WebViewSource,
38
-} from './WebViewTypes';
39
-
40
-const resolveAssetSource = Image.resolveAssetSource;
41
-
42
-const WebViewState = keyMirror({
43
-  IDLE: null,
44
-  LOADING: null,
45
-  ERROR: null,
46
-});
47
-
48
-const defaultRenderLoading = () => (
49
-  <View style={styles.loadingView}>
50
-    <ActivityIndicator style={styles.loadingProgressBar} />
51
-  </View>
52
-);
53
-
54
-type State = {|
55
-  viewState: WebViewState,
56
-  lastErrorEvent: ?WebViewError,
57
-|};
58
-
59
-/**
60
- * Renders a native WebView.
61
- */
62
-class WebView extends React.Component<WebViewSharedProps, State> {
63
-  static defaultProps = {
64
-    overScrollMode: 'always',
65
-    javaScriptEnabled: true,
66
-    thirdPartyCookiesEnabled: true,
67
-    scalesPageToFit: true,
68
-    allowFileAccess: false,
69
-    saveFormDataDisabled: false,
70
-    cacheEnabled: true,
71
-    androidHardwareAccelerationDisabled: false,
72
-    originWhitelist: defaultOriginWhitelist,
73
-  };
74
-
75
-  static isFileUploadSupported = async () => {
76
-    // native implementation should return "true" only for Android 5+
77
-    return NativeModules.RNCWebView.isFileUploadSupported();
78
-  };
79
-
80
-  state = {
81
-    viewState: this.props.startInLoadingState
82
-      ? WebViewState.LOADING
83
-      : WebViewState.IDLE,
84
-    lastErrorEvent: null,
85
-  };
86
-
87
-  webViewRef = React.createRef();
88
-
89
-  render() {
90
-    let otherView = null;
91
-
92
-    if (this.state.viewState === WebViewState.LOADING) {
93
-      otherView = (this.props.renderLoading || defaultRenderLoading)();
94
-    } else if (this.state.viewState === WebViewState.ERROR) {
95
-      const errorEvent = this.state.lastErrorEvent;
96
-      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
97
-      otherView =
98
-        this.props.renderError &&
99
-        this.props.renderError(
100
-          errorEvent.domain,
101
-          errorEvent.code,
102
-          errorEvent.description,
103
-        );
104
-    } else if (this.state.viewState !== WebViewState.IDLE) {
105
-      console.error(
106
-        'RNCWebView invalid state encountered: ' + this.state.viewState,
107
-      );
108
-    }
109
-
110
-    const webViewStyles = [styles.container, this.props.style];
111
-    if (
112
-      this.state.viewState === WebViewState.LOADING ||
113
-      this.state.viewState === WebViewState.ERROR
114
-    ) {
115
-      // if we're in either LOADING or ERROR states, don't show the webView
116
-      webViewStyles.push(styles.hidden);
117
-    }
118
-
119
-    let source: WebViewSource = this.props.source || {};
120
-    if (!this.props.source && this.props.html) {
121
-      source = { html: this.props.html };
122
-    } else if (!this.props.source && this.props.url) {
123
-      source = { uri: this.props.url };
124
-    }
125
-
126
-    if (source.method === 'POST' && source.headers) {
127
-      console.warn(
128
-        'WebView: `source.headers` is not supported when using POST.',
129
-      );
130
-    } else if (source.method === 'GET' && source.body) {
131
-      console.warn('WebView: `source.body` is not supported when using GET.');
132
-    }
133
-
134
-    const nativeConfig = this.props.nativeConfig || {};
135
-
136
-    let NativeWebView = nativeConfig.component || RNCWebView;
137
-
138
-    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
139
-      this.onShouldStartLoadWithRequestCallback,
140
-      this.props.originWhitelist,
141
-      this.props.onShouldStartLoadWithRequest,
142
-    );
143
-
144
-    const webView = (
145
-      <NativeWebView
146
-        ref={this.webViewRef}
147
-        key="webViewKey"
148
-        style={webViewStyles}
149
-        source={resolveAssetSource(source)}
150
-        scalesPageToFit={this.props.scalesPageToFit}
151
-        allowFileAccess={this.props.allowFileAccess}
152
-        injectedJavaScript={this.props.injectedJavaScript}
153
-        userAgent={this.props.userAgent}
154
-        javaScriptEnabled={this.props.javaScriptEnabled}
155
-        androidHardwareAccelerationDisabled={
156
-          this.props.androidHardwareAccelerationDisabled
157
-        }
158
-        thirdPartyCookiesEnabled={this.props.thirdPartyCookiesEnabled}
159
-        domStorageEnabled={this.props.domStorageEnabled}
160
-        cacheEnabled={this.props.cacheEnabled}
161
-        onMessage={this.onMessage}
162
-        messagingEnabled={typeof this.props.onMessage === 'function'}
163
-        overScrollMode={this.props.overScrollMode}
164
-        contentInset={this.props.contentInset}
165
-        automaticallyAdjustContentInsets={
166
-          this.props.automaticallyAdjustContentInsets
167
-        }
168
-        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
169
-        onContentSizeChange={this.props.onContentSizeChange}
170
-        onLoadingStart={this.onLoadingStart}
171
-        onLoadingFinish={this.onLoadingFinish}
172
-        onLoadingError={this.onLoadingError}
173
-        onLoadingProgress={this.onLoadingProgress}
174
-        testID={this.props.testID}
175
-        geolocationEnabled={this.props.geolocationEnabled}
176
-        mediaPlaybackRequiresUserAction={
177
-          this.props.mediaPlaybackRequiresUserAction
178
-        }
179
-        allowUniversalAccessFromFileURLs={
180
-          this.props.allowUniversalAccessFromFileURLs
181
-        }
182
-        mixedContentMode={this.props.mixedContentMode}
183
-        saveFormDataDisabled={this.props.saveFormDataDisabled}
184
-        urlPrefixesForDefaultIntent={this.props.urlPrefixesForDefaultIntent}
185
-        showsHorizontalScrollIndicator={this.props.showsHorizontalScrollIndicator}
186
-        showsVerticalScrollIndicator={this.props.showsVerticalScrollIndicator}
187
-        {...nativeConfig.props}
188
-      />
189
-    );
190
-
191
-    return (
192
-      <View style={styles.container}>
193
-        {webView}
194
-        {otherView}
195
-      </View>
196
-    );
197
-  }
198
-
199
-  getViewManagerConfig = (viewManagerName: string) => {
200
-    if (!UIManager.getViewManagerConfig) {
201
-      return UIManager[viewManagerName];
202
-    }
203
-    return UIManager.getViewManagerConfig(viewManagerName);
204
-  };
205
-
206
-  getCommands = () => this.getViewManagerConfig('RNCWebView').Commands;
207
-
208
-  goForward = () => {
209
-    UIManager.dispatchViewManagerCommand(
210
-      this.getWebViewHandle(),
211
-      this.getCommands().goForward,
212
-      null,
213
-    );
214
-  };
215
-
216
-  goBack = () => {
217
-    UIManager.dispatchViewManagerCommand(
218
-      this.getWebViewHandle(),
219
-      this.getCommands().goBack,
220
-      null,
221
-    );
222
-  };
223
-
224
-  reload = () => {
225
-    this.setState({
226
-      viewState: WebViewState.LOADING,
227
-    });
228
-    UIManager.dispatchViewManagerCommand(
229
-      this.getWebViewHandle(),
230
-      this.getCommands().reload,
231
-      null,
232
-    );
233
-  };
234
-
235
-  stopLoading = () => {
236
-    UIManager.dispatchViewManagerCommand(
237
-      this.getWebViewHandle(),
238
-      this.getCommands().stopLoading,
239
-      null,
240
-    );
241
-  };
242
-
243
-  postMessage = (data: string) => {
244
-    UIManager.dispatchViewManagerCommand(
245
-      this.getWebViewHandle(),
246
-      this.getCommands().postMessage,
247
-      [String(data)],
248
-    );
249
-  };
250
-
251
-  /**
252
-   * Injects a javascript string into the referenced WebView. Deliberately does not
253
-   * return a response because using eval() to return a response breaks this method
254
-   * on pages with a Content Security Policy that disallows eval(). If you need that
255
-   * functionality, look into postMessage/onMessage.
256
-   */
257
-  injectJavaScript = (data: string) => {
258
-    UIManager.dispatchViewManagerCommand(
259
-      this.getWebViewHandle(),
260
-      this.getCommands().injectJavaScript,
261
-      [data],
262
-    );
263
-  };
264
-
265
-  /**
266
-   * We return an event with a bunch of fields including:
267
-   *  url, title, loading, canGoBack, canGoForward
268
-   */
269
-  updateNavigationState = (event: WebViewNavigationEvent) => {
270
-    if (this.props.onNavigationStateChange) {
271
-      this.props.onNavigationStateChange(event.nativeEvent);
272
-    }
273
-  };
274
-
275
-  getWebViewHandle = () => {
276
-    return ReactNative.findNodeHandle(this.webViewRef.current);
277
-  };
278
-
279
-  onLoadingStart = (event: WebViewNavigationEvent) => {
280
-    const onLoadStart = this.props.onLoadStart;
281
-    onLoadStart && onLoadStart(event);
282
-    this.updateNavigationState(event);
283
-  };
284
-
285
-  onLoadingError = (event: WebViewErrorEvent) => {
286
-    event.persist(); // persist this event because we need to store it
287
-    const { onError, onLoadEnd } = this.props;
288
-    onError && onError(event);
289
-    onLoadEnd && onLoadEnd(event);
290
-    console.warn('Encountered an error loading page', event.nativeEvent);
291
-
292
-    this.setState({
293
-      lastErrorEvent: event.nativeEvent,
294
-      viewState: WebViewState.ERROR,
295
-    });
296
-  };
297
-
298
-  onLoadingFinish = (event: WebViewNavigationEvent) => {
299
-    const { onLoad, onLoadEnd } = this.props;
300
-    onLoad && onLoad(event);
301
-    onLoadEnd && onLoadEnd(event);
302
-    this.setState({
303
-      viewState: WebViewState.IDLE,
304
-    });
305
-    this.updateNavigationState(event);
306
-  };
307
-
308
-  onMessage = (event: WebViewMessageEvent) => {
309
-    const { onMessage } = this.props;
310
-    onMessage && onMessage(event);
311
-  };
312
-
313
-  onLoadingProgress = (event: WebViewProgressEvent) => {
314
-    const { onLoadProgress } = this.props;
315
-    onLoadProgress && onLoadProgress(event);
316
-  };
317
-
318
-  onShouldStartLoadWithRequestCallback = (
319
-    shouldStart: boolean,
320
-    url: string,
321
-  ) => {
322
-    if (shouldStart) {
323
-      UIManager.dispatchViewManagerCommand(
324
-        this.getWebViewHandle(),
325
-        this.getCommands().loadUrl,
326
-        [String(url)],
327
-      );
328
-    }
329
-  };
330
-}
331
-
332
-const RNCWebView = requireNativeComponent('RNCWebView');
333
-
334
-const styles = StyleSheet.create({
335
-  container: {
336
-    flex: 1,
337
-  },
338
-  hidden: {
339
-    height: 0,
340
-    flex: 0, // disable 'flex:1' when hiding a View
341
-  },
342
-  loadingView: {
343
-    flex: 1,
344
-    justifyContent: 'center',
345
-    alignItems: 'center',
346
-  },
347
-  loadingProgressBar: {
348
-    height: 20,
349
-  },
350
-});
351
-
352
-module.exports = WebView;

+ 0
- 528
js/WebView.ios.js View File

@@ -1,528 +0,0 @@
1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11
-import React from 'react';
12
-import {
13
-  ActivityIndicator,
14
-  Linking,
15
-  StyleSheet,
16
-  Text,
17
-  UIManager,
18
-  View,
19
-  requireNativeComponent,
20
-  NativeModules,
21
-  Image,
22
-  findNodeHandle,
23
-} from 'react-native';
24
-
25
-import invariant from 'fbjs/lib/invariant';
26
-import keyMirror from 'fbjs/lib/keyMirror';
27
-
28
-import {
29
-  defaultOriginWhitelist,
30
-  createOnShouldStartLoadWithRequest,
31
-} from './WebViewShared';
32
-import type {
33
-  WebViewEvent,
34
-  WebViewError,
35
-  WebViewErrorEvent,
36
-  WebViewMessageEvent,
37
-  WebViewNavigationEvent,
38
-  WebViewSharedProps,
39
-  WebViewSource,
40
-  WebViewProgressEvent,
41
-} from './WebViewTypes';
42
-
43
-const resolveAssetSource = Image.resolveAssetSource;
44
-let didWarnAboutUIWebViewUsage = false;
45
-// Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
46
-function processDecelerationRate(decelerationRate) {
47
-  if (decelerationRate === 'normal') {
48
-    decelerationRate = 0.998;
49
-  } else if (decelerationRate === 'fast') {
50
-    decelerationRate = 0.99;
51
-  }
52
-  return decelerationRate;
53
-}
54
-
55
-const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager;
56
-const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager;
57
-
58
-const BGWASH = 'rgba(255,255,255,0.8)';
59
-
60
-const WebViewState = keyMirror({
61
-  IDLE: null,
62
-  LOADING: null,
63
-  ERROR: null,
64
-});
65
-
66
-const NavigationType = keyMirror({
67
-  click: true,
68
-  formsubmit: true,
69
-  backforward: true,
70
-  reload: true,
71
-  formresubmit: true,
72
-  other: true,
73
-});
74
-
75
-const JSNavigationScheme = 'react-js-navigation';
76
-
77
-type State = {|
78
-  viewState: WebViewState,
79
-  lastErrorEvent: ?WebViewError,
80
-|};
81
-
82
-const DataDetectorTypes = [
83
-  'phoneNumber',
84
-  'link',
85
-  'address',
86
-  'calendarEvent',
87
-  'trackingNumber',
88
-  'flightNumber',
89
-  'lookupSuggestion',
90
-  'none',
91
-  'all',
92
-];
93
-
94
-const defaultRenderLoading = () => (
95
-  <View style={styles.loadingView}>
96
-    <ActivityIndicator />
97
-  </View>
98
-);
99
-const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
100
-  <View style={styles.errorContainer}>
101
-    <Text style={styles.errorTextTitle}>Error loading page</Text>
102
-    <Text style={styles.errorText}>{'Domain: ' + errorDomain}</Text>
103
-    <Text style={styles.errorText}>{'Error Code: ' + errorCode}</Text>
104
-    <Text style={styles.errorText}>{'Description: ' + errorDesc}</Text>
105
-  </View>
106
-);
107
-
108
-/**
109
- * `WebView` renders web content in a native view.
110
- *
111
- *```
112
- * import React, { Component } from 'react';
113
- * import { WebView } from 'react-native';
114
- *
115
- * class MyWeb extends Component {
116
- *   render() {
117
- *     return (
118
- *       <WebView
119
- *         source={{uri: 'https://github.com/facebook/react-native'}}
120
- *         style={{marginTop: 20}}
121
- *       />
122
- *     );
123
- *   }
124
- * }
125
- *```
126
- *
127
- * You can use this component to navigate back and forth in the web view's
128
- * history and configure various properties for the web content.
129
- */
130
-class WebView extends React.Component<WebViewSharedProps, State> {
131
-  static JSNavigationScheme = JSNavigationScheme;
132
-  static NavigationType = NavigationType;
133
-
134
-  static defaultProps = {
135
-    useWebKit: true,
136
-    cacheEnabled: true,
137
-    originWhitelist: defaultOriginWhitelist,
138
-    useSharedProcessPool: true,
139
-  };
140
-
141
-  static isFileUploadSupported = async () => {
142
-    // no native implementation for iOS, depends only on permissions
143
-    return true;
144
-  };
145
-
146
-  state = {
147
-    viewState: this.props.startInLoadingState
148
-      ? WebViewState.LOADING
149
-      : WebViewState.IDLE,
150
-    lastErrorEvent: null,
151
-  };
152
-
153
-  webViewRef = React.createRef();
154
-
155
-  UNSAFE_componentWillMount() {
156
-    if (!this.props.useWebKit && !didWarnAboutUIWebViewUsage) {
157
-      didWarnAboutUIWebViewUsage = true;
158
-      console.warn(
159
-        'UIWebView is deprecated and will be removed soon, please use WKWebView (do not override useWebkit={true} prop),' +
160
-          ' more infos here: https://github.com/react-native-community/react-native-webview/issues/312',
161
-      );
162
-    }
163
-    if (
164
-      this.props.useWebKit === true &&
165
-      this.props.scalesPageToFit !== undefined
166
-    ) {
167
-      console.warn(
168
-        'The scalesPageToFit property is not supported when useWebKit = true',
169
-      );
170
-    }
171
-    if (
172
-      !this.props.useWebKit &&
173
-      this.props.allowsBackForwardNavigationGestures
174
-    ) {
175
-      console.warn(
176
-        'The allowsBackForwardNavigationGestures property is not supported when useWebKit = false',
177
-      );
178
-    }
179
-
180
-    if (!this.props.useWebKit && this.props.incognito) {
181
-      console.warn(
182
-        'The incognito property is not supported when useWebKit = false',
183
-      );
184
-    }
185
-  }
186
-
187
-  render() {
188
-    let otherView = null;
189
-
190
-    let scalesPageToFit;
191
-
192
-    if (this.props.useWebKit) {
193
-      ({ scalesPageToFit } = this.props);
194
-    } else {
195
-      ({ scalesPageToFit = true } = this.props);
196
-    }
197
-
198
-    if (this.state.viewState === WebViewState.LOADING) {
199
-      otherView = (this.props.renderLoading || defaultRenderLoading)();
200
-    } else if (this.state.viewState === WebViewState.ERROR) {
201
-      const errorEvent = this.state.lastErrorEvent;
202
-      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
203
-      otherView = (this.props.renderError || defaultRenderError)(
204
-        errorEvent.domain,
205
-        errorEvent.code,
206
-        errorEvent.description,
207
-      );
208
-    } else if (this.state.viewState !== WebViewState.IDLE) {
209
-      console.error(
210
-        'RNCWebView invalid state encountered: ' + this.state.viewState,
211
-      );
212
-    }
213
-
214
-    const webViewStyles = [styles.container, styles.webView, this.props.style];
215
-    if (
216
-      this.state.viewState === WebViewState.LOADING ||
217
-      this.state.viewState === WebViewState.ERROR
218
-    ) {
219
-      // if we're in either LOADING or ERROR states, don't show the webView
220
-      webViewStyles.push(styles.hidden);
221
-    }
222
-
223
-    const nativeConfig = this.props.nativeConfig || {};
224
-
225
-    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
226
-      this.onShouldStartLoadWithRequestCallback,
227
-      this.props.originWhitelist,
228
-      this.props.onShouldStartLoadWithRequest,
229
-    );
230
-
231
-    const decelerationRate = processDecelerationRate(
232
-      this.props.decelerationRate,
233
-    );
234
-
235
-    let source: WebViewSource = this.props.source || {};
236
-    if (!this.props.source && this.props.html) {
237
-      source = { html: this.props.html };
238
-    } else if (!this.props.source && this.props.url) {
239
-      source = { uri: this.props.url };
240
-    }
241
-
242
-    let NativeWebView = nativeConfig.component;
243
-
244
-    if (this.props.useWebKit) {
245
-      NativeWebView = NativeWebView || RNCWKWebView;
246
-    } else {
247
-      NativeWebView = NativeWebView || RNCUIWebView;
248
-    }
249
-
250
-    const webView = (
251
-      <NativeWebView
252
-        ref={this.webViewRef}
253
-        key="webViewKey"
254
-        style={webViewStyles}
255
-        source={resolveAssetSource(source)}
256
-        injectedJavaScript={this.props.injectedJavaScript}
257
-        bounces={this.props.bounces}
258
-        scrollEnabled={this.props.scrollEnabled}
259
-        pagingEnabled={this.props.pagingEnabled}
260
-        cacheEnabled={this.props.cacheEnabled}
261
-        decelerationRate={decelerationRate}
262
-        contentInset={this.props.contentInset}
263
-        automaticallyAdjustContentInsets={
264
-          this.props.automaticallyAdjustContentInsets
265
-        }
266
-        hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView}
267
-        allowsBackForwardNavigationGestures={
268
-          this.props.allowsBackForwardNavigationGestures
269
-        }
270
-        incognito={this.props.incognito}
271
-        userAgent={this.props.userAgent}
272
-        onLoadingStart={this._onLoadingStart}
273
-        onLoadingFinish={this._onLoadingFinish}
274
-        onLoadingError={this._onLoadingError}
275
-        onLoadingProgress={this._onLoadingProgress}
276
-        onMessage={this._onMessage}
277
-        messagingEnabled={typeof this.props.onMessage === 'function'}
278
-        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
279
-        scalesPageToFit={scalesPageToFit}
280
-        allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
281
-        mediaPlaybackRequiresUserAction={
282
-          this.props.mediaPlaybackRequiresUserAction
283
-        }
284
-        dataDetectorTypes={this.props.dataDetectorTypes}
285
-        useSharedProcessPool={this.props.useSharedProcessPool}
286
-        allowsLinkPreview={this.props.allowsLinkPreview}
287
-        showsHorizontalScrollIndicator={this.props.showsHorizontalScrollIndicator}
288
-        showsVerticalScrollIndicator={this.props.showsVerticalScrollIndicator}
289
-        directionalLockEnabled={this.props.directionalLockEnabled}
290
-        {...nativeConfig.props}
291
-      />
292
-    );
293
-
294
-    return (
295
-      <View style={styles.container}>
296
-        {webView}
297
-        {otherView}
298
-      </View>
299
-    );
300
-  }
301
-
302
-  _getViewManagerConfig = (viewManagerName: string) => {
303
-    if (!UIManager.getViewManagerConfig) {
304
-      return UIManager[viewManagerName];
305
-    }
306
-    return UIManager.getViewManagerConfig(viewManagerName);
307
-  };
308
-
309
-  _getCommands = () =>
310
-    !this.props.useWebKit
311
-      ? this._getViewManagerConfig('RNCUIWebView').Commands
312
-      : this._getViewManagerConfig('RNCWKWebView').Commands;
313
-
314
-  /**
315
-   * Go forward one page in the web view's history.
316
-   */
317
-  goForward = () => {
318
-    UIManager.dispatchViewManagerCommand(
319
-      this.getWebViewHandle(),
320
-      this._getCommands().goForward,
321
-      null,
322
-    );
323
-  };
324
-
325
-  /**
326
-   * Go back one page in the web view's history.
327
-   */
328
-  goBack = () => {
329
-    UIManager.dispatchViewManagerCommand(
330
-      this.getWebViewHandle(),
331
-      this._getCommands().goBack,
332
-      null,
333
-    );
334
-  };
335
-
336
-  /**
337
-   * Reloads the current page.
338
-   */
339
-  reload = () => {
340
-    this.setState({ viewState: WebViewState.LOADING });
341
-    UIManager.dispatchViewManagerCommand(
342
-      this.getWebViewHandle(),
343
-      this._getCommands().reload,
344
-      null,
345
-    );
346
-  };
347
-
348
-  /**
349
-   * Stop loading the current page.
350
-   */
351
-  stopLoading = () => {
352
-    UIManager.dispatchViewManagerCommand(
353
-      this.getWebViewHandle(),
354
-      this._getCommands().stopLoading,
355
-      null,
356
-    );
357
-  };
358
-
359
-  /**
360
-   * Posts a message to the web view, which will emit a `message` event.
361
-   * Accepts one argument, `data`, which must be a string.
362
-   *
363
-   * In your webview, you'll need to something like the following.
364
-   *
365
-   * ```js
366
-   * document.addEventListener('message', e => { document.title = e.data; });
367
-   * ```
368
-   */
369
-  postMessage = (data: string) => {
370
-    UIManager.dispatchViewManagerCommand(
371
-      this.getWebViewHandle(),
372
-      this._getCommands().postMessage,
373
-      [String(data)],
374
-    );
375
-  };
376
-
377
-  /**
378
-   * Injects a javascript string into the referenced WebView. Deliberately does not
379
-   * return a response because using eval() to return a response breaks this method
380
-   * on pages with a Content Security Policy that disallows eval(). If you need that
381
-   * functionality, look into postMessage/onMessage.
382
-   */
383
-  injectJavaScript = (data: string) => {
384
-    UIManager.dispatchViewManagerCommand(
385
-      this.getWebViewHandle(),
386
-      this._getCommands().injectJavaScript,
387
-      [data],
388
-    );
389
-  };
390
-
391
-  /**
392
-   * We return an event with a bunch of fields including:
393
-   *  url, title, loading, canGoBack, canGoForward
394
-   */
395
-  _updateNavigationState = (event: WebViewNavigationEvent) => {
396
-    if (this.props.onNavigationStateChange) {
397
-      this.props.onNavigationStateChange(event.nativeEvent);
398
-    }
399
-  };
400
-
401
-  /**
402
-   * Returns the native `WebView` node.
403
-   */
404
-  getWebViewHandle = () => {
405
-    return findNodeHandle(this.webViewRef.current);
406
-  };
407
-
408
-  _onLoadingStart = (event: WebViewNavigationEvent) => {
409
-    const onLoadStart = this.props.onLoadStart;
410
-    onLoadStart && onLoadStart(event);
411
-    this._updateNavigationState(event);
412
-  };
413
-
414
-  _onLoadingError = (event: WebViewErrorEvent) => {
415
-    event.persist(); // persist this event because we need to store it
416
-    const { onError, onLoadEnd } = this.props;
417
-    onError && onError(event);
418
-    onLoadEnd && onLoadEnd(event);
419
-    console.warn('Encountered an error loading page', event.nativeEvent);
420
-
421
-    this.setState({
422
-      lastErrorEvent: event.nativeEvent,
423
-      viewState: WebViewState.ERROR,
424
-    });
425
-  };
426
-
427
-  _onLoadingFinish = (event: WebViewNavigationEvent) => {
428
-    const { onLoad, onLoadEnd } = this.props;
429
-    onLoad && onLoad(event);
430
-    onLoadEnd && onLoadEnd(event);
431
-    this.setState({
432
-      viewState: WebViewState.IDLE,
433
-    });
434
-    this._updateNavigationState(event);
435
-  };
436
-
437
-  _onMessage = (event: WebViewMessageEvent) => {
438
-    const { onMessage } = this.props;
439
-    onMessage && onMessage(event);
440
-  };
441
-
442
-  _onLoadingProgress = (event: WebViewProgressEvent) => {
443
-    const { onLoadProgress } = this.props;
444
-    onLoadProgress && onLoadProgress(event);
445
-  };
446
-
447
-  onShouldStartLoadWithRequestCallback = (
448
-    shouldStart: boolean,
449
-    url: string,
450
-    lockIdentifier: number,
451
-  ) => {
452
-    let viewManager = (this.props.nativeConfig || {}).viewManager;
453
-
454
-    if (this.props.useWebKit) {
455
-      viewManager = viewManager || RNCWKWebViewManager;
456
-    } else {
457
-      viewManager = viewManager || RNCUIWebViewManager;
458
-    }
459
-    invariant(viewManager != null, 'viewManager expected to be non-null');
460
-    viewManager.startLoadWithResult(!!shouldStart, lockIdentifier);
461
-  };
462
-
463
-  componentDidUpdate(prevProps: WebViewSharedProps) {
464
-    if (!(prevProps.useWebKit && this.props.useWebKit)) {
465
-      return;
466
-    }
467
-
468
-    this._showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback');
469
-    this._showRedboxOnPropChanges(prevProps, 'incognito');
470
-    this._showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction');
471
-    this._showRedboxOnPropChanges(prevProps, 'dataDetectorTypes');
472
-
473
-    if (this.props.scalesPageToFit !== undefined) {
474
-      console.warn(
475
-        'The scalesPageToFit property is not supported when useWebKit = true',
476
-      );
477
-    }
478
-  }
479
-
480
-  _showRedboxOnPropChanges(prevProps, propName: string) {
481
-    if (this.props[propName] !== prevProps[propName]) {
482
-      console.error(
483
-        `Changes to property ${propName} do nothing after the initial render.`,
484
-      );
485
-    }
486
-  }
487
-}
488
-
489
-const RNCUIWebView = requireNativeComponent('RNCUIWebView');
490
-const RNCWKWebView = requireNativeComponent('RNCWKWebView');
491
-
492
-const styles = StyleSheet.create({
493
-  container: {
494
-    flex: 1,
495
-  },
496
-  errorContainer: {
497
-    flex: 1,
498
-    justifyContent: 'center',
499
-    alignItems: 'center',
500
-    backgroundColor: BGWASH,
501
-  },
502
-  errorText: {
503
-    fontSize: 14,
504
-    textAlign: 'center',
505
-    marginBottom: 2,
506
-  },
507
-  errorTextTitle: {
508
-    fontSize: 15,
509
-    fontWeight: '500',
510
-    marginBottom: 10,
511
-  },
512
-  hidden: {
513
-    height: 0,
514
-    flex: 0, // disable 'flex:1' when hiding a View
515
-  },
516
-  loadingView: {
517
-    backgroundColor: BGWASH,
518
-    flex: 1,
519
-    justifyContent: 'center',
520
-    alignItems: 'center',
521
-    height: 100,
522
-  },
523
-  webView: {
524
-    backgroundColor: '#ffffff',
525
-  },
526
-});
527
-
528
-module.exports = WebView;

+ 40
- 20
package.json View File

@@ -11,38 +11,58 @@
11 11
   "version": "5.3.1",
12 12
   "homepage": "https://github.com/react-native-community/react-native-webview#readme",
13 13
   "scripts": {
14
-    "test:js": "jest",
15
-    "test:ios:flow": "flow check",
16
-    "test:android:flow": "flow check --flowconfig-name .flowconfig.android",
14
+    "ci": "CI=true && yarn lint && yarn test",
17 15
     "ci:publish": "yarn semantic-release",
18
-    "ci:test": "yarn ci:test:flow && yarn ci:test:js",
19
-    "ci:test:flow": "yarn test:ios:flow && yarn test:android:flow",
20
-    "ci:test:js": "yarn test:js",
21
-    "semantic-release": "semantic-release"
16
+    "lint": "yarn tsc --noEmit && yarn eslint ./src --ext .ts,.tsx",
17
+    "build": "yarn tsc",
18
+    "prepack": "yarn build",
19
+    "test": "yarn jest"
22 20
   },
23 21
   "peerDependencies": {
24 22
     "react": "^16.0",
25
-    "react-native": ">=0.57 <0.59"
23
+    "react-native": ">=0.57 <0.60"
26 24
   },
27 25
   "dependencies": {
28
-    "escape-string-regexp": "^1.0.5",
29
-    "fbjs": "^0.8.17"
26
+    "escape-string-regexp": "1.0.5",
27
+    "invariant": "2.2.4"
30 28
   },
31 29
   "devDependencies": {
32
-    "@babel/core": "^7.2.2",
30
+    "@babel/core": "7.3.4",
33 31
     "@semantic-release/git": "7.0.5",
34
-    "@types/react": "^16.6.3",
35
-    "@types/react-native": "^0.57.8",
32
+    "@types/escape-string-regexp": "1.0.0",
33
+    "@types/invariant": "^2.2.29",
34
+    "@types/jest": "24.0.11",
35
+    "@types/react": "16.8.8",
36
+    "@types/react-native": "0.57.40",
37
+    "@typescript-eslint/eslint-plugin": "1.4.2",
38
+    "@typescript-eslint/parser": "1.4.2",
39
+    "babel-eslint": "10.0.1",
36 40
     "babel-jest": "^24.0.0",
37
-    "flow-bin": "^0.80.0",
38
-    "jest": "^24.0.0",
39
-    "metro-react-native-babel-preset": "^0.51.1",
40
-    "react": "16.6.3",
41
-    "react-native": "^0.57.8",
42
-    "semantic-release": "15.10.3"
41
+    "eslint": "5.15.1",
42
+    "eslint-config-airbnb": "17.1.0",
43
+    "eslint-config-prettier": "4.1.0",
44
+    "eslint-plugin-import": "2.16.0",
45
+    "eslint-plugin-jsx-a11y": "6.2.1",
46
+    "eslint-plugin-react": "7.12.4",
47
+    "eslint-plugin-react-native": "3.6.0",
48
+    "jest": "24.5.0",
49
+    "metro-react-native-babel-preset": "0.53.1",
50
+    "react": "16.8.3",
51
+    "react-native": "0.59.1",
52
+    "semantic-release": "15.10.3",
53
+    "ts-jest": "24.0.0",
54
+    "typescript": "3.3.3333"
43 55
   },
44 56
   "repository": {
45 57
     "type": "git",
46 58
     "url": "https://github.com/react-native-community/react-native-webview.git"
47
-  }
59
+  },
60
+  "files": [
61
+    "android",
62
+    "ios",
63
+    "lib",
64
+    "index.js",
65
+    "index.d.ts",
66
+    "react-native-webview.podspec"
67
+  ]
48 68
 }

+ 304
- 0
src/WebView.android.tsx View File

@@ -0,0 +1,304 @@
1
+import React from 'react';
2
+
3
+import {
4
+  ActivityIndicator,
5
+  Image,
6
+  requireNativeComponent,
7
+  UIManager as NotTypedUIManager,
8
+  View,
9
+  NativeModules,
10
+  ImageSourcePropType,
11
+  findNodeHandle,
12
+} from 'react-native';
13
+
14
+import invariant from 'invariant';
15
+
16
+import {
17
+  defaultOriginWhitelist,
18
+  createOnShouldStartLoadWithRequest,
19
+  getViewManagerConfig,
20
+} from './WebViewShared';
21
+import {
22
+  WebViewErrorEvent,
23
+  WebViewMessageEvent,
24
+  WebViewNavigationEvent,
25
+  WebViewProgressEvent,
26
+  AndroidWebViewProps,
27
+  NativeWebViewAndroid,
28
+  State,
29
+  CustomUIManager,
30
+} from './WebViewTypes';
31
+
32
+import styles from './WebView.styles';
33
+
34
+const UIManager = NotTypedUIManager as CustomUIManager;
35
+
36
+const RNCWebView = requireNativeComponent(
37
+  'RNCWebView',
38
+) as typeof NativeWebViewAndroid;
39
+const { resolveAssetSource } = Image;
40
+
41
+const defaultRenderLoading = () => (
42
+  <View style={styles.loadingView}>
43
+    <ActivityIndicator style={styles.loadingProgressBar} />
44
+  </View>
45
+);
46
+
47
+/**
48
+ * Renders a native WebView.
49
+ */
50
+class WebView extends React.Component<AndroidWebViewProps, State> {
51
+  static defaultProps = {
52
+    overScrollMode: 'always',
53
+    javaScriptEnabled: true,
54
+    thirdPartyCookiesEnabled: true,
55
+    scalesPageToFit: true,
56
+    allowFileAccess: false,
57
+    saveFormDataDisabled: false,
58
+    cacheEnabled: true,
59
+    androidHardwareAccelerationDisabled: false,
60
+    originWhitelist: defaultOriginWhitelist,
61
+  };
62
+
63
+  static isFileUploadSupported = async () => {
64
+    // native implementation should return "true" only for Android 5+
65
+    return NativeModules.RNCWebView.isFileUploadSupported();
66
+  };
67
+
68
+  state: State = {
69
+    viewState: this.props.startInLoadingState ? 'LOADING' : 'IDLE',
70
+    lastErrorEvent: null,
71
+  };
72
+
73
+  webViewRef = React.createRef<NativeWebViewAndroid>();
74
+
75
+  getCommands = () => getViewManagerConfig('RNCWebView').Commands;
76
+
77
+  goForward = () => {
78
+    UIManager.dispatchViewManagerCommand(
79
+      this.getWebViewHandle(),
80
+      this.getCommands().goForward,
81
+      null,
82
+    );
83
+  };
84
+
85
+  goBack = () => {
86
+    UIManager.dispatchViewManagerCommand(
87
+      this.getWebViewHandle(),
88
+      this.getCommands().goBack,
89
+      null,
90
+    );
91
+  };
92
+
93
+  reload = () => {
94
+    this.setState({
95
+      viewState: 'LOADING',
96
+    });
97
+    UIManager.dispatchViewManagerCommand(
98
+      this.getWebViewHandle(),
99
+      this.getCommands().reload,
100
+      null,
101
+    );
102
+  };
103
+
104
+  stopLoading = () => {
105
+    UIManager.dispatchViewManagerCommand(
106
+      this.getWebViewHandle(),
107
+      this.getCommands().stopLoading,
108
+      null,
109
+    );
110
+  };
111
+
112
+  postMessage = (data: string) => {
113
+    UIManager.dispatchViewManagerCommand(
114
+      this.getWebViewHandle(),
115
+      this.getCommands().postMessage,
116
+      [String(data)],
117
+    );
118
+  };
119
+
120
+  /**
121
+   * Injects a javascript string into the referenced WebView. Deliberately does not
122
+   * return a response because using eval() to return a response breaks this method
123
+   * on pages with a Content Security Policy that disallows eval(). If you need that
124
+   * functionality, look into postMessage/onMessage.
125
+   */
126
+  injectJavaScript = (data: string) => {
127
+    UIManager.dispatchViewManagerCommand(
128
+      this.getWebViewHandle(),
129
+      this.getCommands().injectJavaScript,
130
+      [data],
131
+    );
132
+  };
133
+
134
+  /**
135
+   * We return an event with a bunch of fields including:
136
+   *  url, title, loading, canGoBack, canGoForward
137
+   */
138
+  updateNavigationState = (event: WebViewNavigationEvent) => {
139
+    if (this.props.onNavigationStateChange) {
140
+      this.props.onNavigationStateChange(event.nativeEvent);
141
+    }
142
+  };
143
+
144
+  /**
145
+   * Returns the native `WebView` node.
146
+   */
147
+  getWebViewHandle = () => {
148
+    const nodeHandle = findNodeHandle(this.webViewRef.current);
149
+    invariant(nodeHandle != null, 'nodeHandle expected to be non-null');
150
+    return nodeHandle as number;
151
+  };
152
+
153
+  onLoadingStart = (event: WebViewNavigationEvent) => {
154
+    const { onLoadStart } = this.props;
155
+    if (onLoadStart) {
156
+      onLoadStart(event);
157
+    }
158
+    this.updateNavigationState(event);
159
+  };
160
+
161
+  onLoadingError = (event: WebViewErrorEvent) => {
162
+    event.persist(); // persist this event because we need to store it
163
+    const { onError, onLoadEnd } = this.props;
164
+    if (onError) {
165
+      onError(event);
166
+    }
167
+    if (onLoadEnd) {
168
+      onLoadEnd(event);
169
+    }
170
+    console.warn('Encountered an error loading page', event.nativeEvent);
171
+
172
+    this.setState({
173
+      lastErrorEvent: event.nativeEvent,
174
+      viewState: 'ERROR',
175
+    });
176
+  };
177
+
178
+  onLoadingFinish = (event: WebViewNavigationEvent) => {
179
+    const { onLoad, onLoadEnd } = this.props;
180
+    if (onLoad) {
181
+      onLoad(event);
182
+    }
183
+    if (onLoadEnd) {
184
+      onLoadEnd(event);
185
+    }
186
+    this.setState({
187
+      viewState: 'IDLE',
188
+    });
189
+    this.updateNavigationState(event);
190
+  };
191
+
192
+  onMessage = (event: WebViewMessageEvent) => {
193
+    const { onMessage } = this.props;
194
+    if (onMessage) {
195
+      onMessage(event);
196
+    }
197
+  };
198
+
199
+  onLoadingProgress = (event: WebViewProgressEvent) => {
200
+    const { onLoadProgress } = this.props;
201
+    if (onLoadProgress) {
202
+      onLoadProgress(event);
203
+    }
204
+  };
205
+
206
+  onShouldStartLoadWithRequestCallback = (
207
+    shouldStart: boolean,
208
+    url: string,
209
+  ) => {
210
+    if (shouldStart) {
211
+      UIManager.dispatchViewManagerCommand(
212
+        this.getWebViewHandle(),
213
+        this.getCommands().loadUrl,
214
+        [String(url)],
215
+      );
216
+    }
217
+  };
218
+
219
+  render() {
220
+    const {
221
+      onMessage,
222
+      onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
223
+      originWhitelist,
224
+      renderError,
225
+      renderLoading,
226
+      source,
227
+      style,
228
+      nativeConfig = {},
229
+      ...otherProps
230
+    } = this.props;
231
+    let otherView = null;
232
+
233
+    if (this.state.viewState === 'LOADING') {
234
+      otherView = (renderLoading || defaultRenderLoading)();
235
+    } else if (this.state.viewState === 'ERROR') {
236
+      const errorEvent = this.state.lastErrorEvent;
237
+      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
238
+      otherView
239
+        = renderError
240
+        && renderError(errorEvent.domain, errorEvent.code, errorEvent.description);
241
+    } else if (this.state.viewState !== 'IDLE') {
242
+      console.error(
243
+        `RNCWebView invalid state encountered: ${this.state.viewState}`,
244
+      );
245
+    }
246
+
247
+    const webViewStyles = [styles.container, style];
248
+    if (
249
+      this.state.viewState === 'LOADING'
250
+      || this.state.viewState === 'ERROR'
251
+    ) {
252
+      // if we're in either LOADING or ERROR states, don't show the webView
253
+      webViewStyles.push(styles.hidden);
254
+    }
255
+
256
+    if (source && 'method' in source) {
257
+      if (source.method === 'POST' && source.headers) {
258
+        console.warn(
259
+          'WebView: `source.headers` is not supported when using POST.',
260
+        );
261
+      } else if (source.method === 'GET' && source.body) {
262
+        console.warn('WebView: `source.body` is not supported when using GET.');
263
+      }
264
+    }
265
+
266
+    const NativeWebView
267
+      = (nativeConfig.component as typeof NativeWebViewAndroid) || RNCWebView;
268
+
269
+    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
270
+      this.onShouldStartLoadWithRequestCallback,
271
+      // casting cause it's in the default props
272
+      originWhitelist as ReadonlyArray<string>,
273
+      onShouldStartLoadWithRequestProp,
274
+    );
275
+
276
+    const webView = (
277
+      <NativeWebView
278
+        key="webViewKey"
279
+        {...otherProps}
280
+        messagingEnabled={typeof onMessage === 'function'}
281
+        onLoadingError={this.onLoadingError}
282
+        onLoadingFinish={this.onLoadingFinish}
283
+        onLoadingProgress={this.onLoadingProgress}
284
+        onLoadingStart={this.onLoadingStart}
285
+        onMessage={this.onMessage}
286
+        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
287
+        ref={this.webViewRef}
288
+        // TODO: find a better way to type this.
289
+        source={resolveAssetSource(source as ImageSourcePropType)}
290
+        style={webViewStyles}
291
+        {...nativeConfig.props}
292
+      />
293
+    );
294
+
295
+    return (
296
+      <View style={styles.container}>
297
+        {webView}
298
+        {otherView}
299
+      </View>
300
+    );
301
+  }
302
+}
303
+
304
+export default WebView;

+ 422
- 0
src/WebView.ios.tsx View File

@@ -0,0 +1,422 @@
1
+import React from 'react';
2
+import {
3
+  ActivityIndicator,
4
+  Text,
5
+  UIManager as NotTypedUIManager,
6
+  View,
7
+  requireNativeComponent,
8
+  NativeModules,
9
+  Image,
10
+  findNodeHandle,
11
+  ImageSourcePropType,
12
+} from 'react-native';
13
+import invariant from 'invariant';
14
+
15
+import {
16
+  defaultOriginWhitelist,
17
+  createOnShouldStartLoadWithRequest,
18
+  getViewManagerConfig,
19
+} from './WebViewShared';
20
+import {
21
+  WebViewErrorEvent,
22
+  WebViewMessageEvent,
23
+  WebViewNavigationEvent,
24
+  WebViewProgressEvent,
25
+  IOSWebViewProps,
26
+  DecelerationRateConstant,
27
+  NativeWebViewIOS,
28
+  ViewManager,
29
+  State,
30
+  CustomUIManager,
31
+  WebViewNativeConfig,
32
+} from './WebViewTypes';
33
+
34
+import styles from './WebView.styles';
35
+
36
+const UIManager = NotTypedUIManager as CustomUIManager;
37
+
38
+const { resolveAssetSource } = Image;
39
+let didWarnAboutUIWebViewUsage = false;
40
+// Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
41
+const processDecelerationRate = (
42
+  decelerationRate: DecelerationRateConstant | number | undefined,
43
+) => {
44
+  let newDecelerationRate = decelerationRate;
45
+  if (newDecelerationRate === 'normal') {
46
+    newDecelerationRate = 0.998;
47
+  } else if (newDecelerationRate === 'fast') {
48
+    newDecelerationRate = 0.99;
49
+  }
50
+  return newDecelerationRate;
51
+};
52
+
53
+const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager as ViewManager;
54
+const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager as ViewManager;
55
+
56
+const RNCUIWebView: typeof NativeWebViewIOS = requireNativeComponent(
57
+  'RNCUIWebView',
58
+);
59
+const RNCWKWebView: typeof NativeWebViewIOS = requireNativeComponent(
60
+  'RNCWKWebView',
61
+);
62
+
63
+const defaultRenderLoading = () => (
64
+  <View style={styles.loadingView}>
65
+    <ActivityIndicator />
66
+  </View>
67
+);
68
+const defaultRenderError = (
69
+  errorDomain: string | undefined,
70
+  errorCode: number,
71
+  errorDesc: string,
72
+) => (
73
+  <View style={styles.errorContainer}>
74
+    <Text style={styles.errorTextTitle}>Error loading page</Text>
75
+    <Text style={styles.errorText}>{`Domain: ${errorDomain}`}</Text>
76
+    <Text style={styles.errorText}>{`Error Code: ${errorCode}`}</Text>
77
+    <Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
78
+  </View>
79
+);
80
+
81
+class WebView extends React.Component<IOSWebViewProps, State> {
82
+  static defaultProps = {
83
+    useWebKit: true,
84
+    cacheEnabled: true,
85
+    originWhitelist: defaultOriginWhitelist,
86
+    useSharedProcessPool: true,
87
+  };
88
+
89
+  static isFileUploadSupported = async () => {
90
+    // no native implementation for iOS, depends only on permissions
91
+    return true;
92
+  };
93
+
94
+  state: State = {
95
+    viewState: this.props.startInLoadingState ? 'LOADING' : 'IDLE',
96
+    lastErrorEvent: null,
97
+  };
98
+
99
+  webViewRef = React.createRef<NativeWebViewIOS>();
100
+
101
+  // eslint-disable-next-line camelcase
102
+  UNSAFE_componentWillMount() {
103
+    if (!this.props.useWebKit && !didWarnAboutUIWebViewUsage) {
104
+      didWarnAboutUIWebViewUsage = true;
105
+      console.warn(
106
+        'UIWebView is deprecated and will be removed soon, please use WKWebView (do not override useWebkit={true} prop),'
107
+          + ' more infos here: https://github.com/react-native-community/react-native-webview/issues/312',
108
+      );
109
+    }
110
+    if (
111
+      this.props.useWebKit === true
112
+      && this.props.scalesPageToFit !== undefined
113
+    ) {
114
+      console.warn(
115
+        'The scalesPageToFit property is not supported when useWebKit = true',
116
+      );
117
+    }
118
+    if (
119
+      !this.props.useWebKit
120
+      && this.props.allowsBackForwardNavigationGestures
121
+    ) {
122
+      console.warn(
123
+        'The allowsBackForwardNavigationGestures property is not supported when useWebKit = false',
124
+      );
125
+    }
126
+
127
+    if (!this.props.useWebKit && this.props.incognito) {
128
+      console.warn(
129
+        'The incognito property is not supported when useWebKit = false',
130
+      );
131
+    }
132
+  }
133
+
134
+  // eslint-disable-next-line react/sort-comp
135
+  getCommands = () =>
136
+    !this.props.useWebKit
137
+      ? getViewManagerConfig('RNCUIWebView').Commands
138
+      : getViewManagerConfig('RNCWKWebView').Commands;
139
+
140
+  /**
141
+   * Go forward one page in the web view's history.
142
+   */
143
+  goForward = () => {
144
+    UIManager.dispatchViewManagerCommand(
145
+      this.getWebViewHandle(),
146
+      this.getCommands().goForward,
147
+      null,
148
+    );
149
+  };
150
+
151
+  /**
152
+   * Go back one page in the web view's history.
153
+   */
154
+  goBack = () => {
155
+    UIManager.dispatchViewManagerCommand(
156
+      this.getWebViewHandle(),
157
+      this.getCommands().goBack,
158
+      null,
159
+    );
160
+  };
161
+
162
+  /**
163
+   * Reloads the current page.
164
+   */
165
+  reload = () => {
166
+    this.setState({ viewState: 'LOADING' });
167
+    UIManager.dispatchViewManagerCommand(
168
+      this.getWebViewHandle(),
169
+      this.getCommands().reload,
170
+      null,
171
+    );
172
+  };
173
+
174
+  /**
175
+   * Stop loading the current page.
176
+   */
177
+  stopLoading = () => {
178
+    UIManager.dispatchViewManagerCommand(
179
+      this.getWebViewHandle(),
180
+      this.getCommands().stopLoading,
181
+      null,
182
+    );
183
+  };
184
+
185
+  /**
186
+   * Posts a message to the web view, which will emit a `message` event.
187
+   * Accepts one argument, `data`, which must be a string.
188
+   *
189
+   * In your webview, you'll need to something like the following.
190
+   *
191
+   * ```js
192
+   * document.addEventListener('message', e => { document.title = e.data; });
193
+   * ```
194
+   */
195
+  postMessage = (data: string) => {
196
+    UIManager.dispatchViewManagerCommand(
197
+      this.getWebViewHandle(),
198
+      this.getCommands().postMessage,
199
+      [String(data)],
200
+    );
201
+  };
202
+
203
+  /**
204
+   * Injects a javascript string into the referenced WebView. Deliberately does not
205
+   * return a response because using eval() to return a response breaks this method
206
+   * on pages with a Content Security Policy that disallows eval(). If you need that
207
+   * functionality, look into postMessage/onMessage.
208
+   */
209
+  injectJavaScript = (data: string) => {
210
+    UIManager.dispatchViewManagerCommand(
211
+      this.getWebViewHandle(),
212
+      this.getCommands().injectJavaScript,
213
+      [data],
214
+    );
215
+  };
216
+
217
+  /**
218
+   * We return an event with a bunch of fields including:
219
+   *  url, title, loading, canGoBack, canGoForward
220
+   */
221
+  updateNavigationState = (event: WebViewNavigationEvent) => {
222
+    if (this.props.onNavigationStateChange) {
223
+      this.props.onNavigationStateChange(event.nativeEvent);
224
+    }
225
+  };
226
+
227
+  /**
228
+   * Returns the native `WebView` node.
229
+   */
230
+  getWebViewHandle = () => {
231
+    const nodeHandle = findNodeHandle(this.webViewRef.current);
232
+    invariant(nodeHandle != null, 'nodeHandle expected to be non-null');
233
+    return nodeHandle as number;
234
+  };
235
+
236
+  onLoadingStart = (event: WebViewNavigationEvent) => {
237
+    const { onLoadStart } = this.props;
238
+    if (onLoadStart) {
239
+      onLoadStart(event);
240
+    }
241
+    this.updateNavigationState(event);
242
+  };
243
+
244
+  onLoadingError = (event: WebViewErrorEvent) => {
245
+    event.persist(); // persist this event because we need to store it
246
+    const { onError, onLoadEnd } = this.props;
247
+    if (onLoadEnd) {
248
+      onLoadEnd(event);
249
+    }
250
+    if (onError) {
251
+      onError(event);
252
+    }
253
+    console.warn('Encountered an error loading page', event.nativeEvent);
254
+
255
+    this.setState({
256
+      lastErrorEvent: event.nativeEvent,
257
+      viewState: 'ERROR',
258
+    });
259
+  };
260
+
261
+  onLoadingFinish = (event: WebViewNavigationEvent) => {
262
+    const { onLoad, onLoadEnd } = this.props;
263
+    if (onLoad) {
264
+      onLoad(event);
265
+    }
266
+    if (onLoadEnd) {
267
+      onLoadEnd(event);
268
+    }
269
+    this.setState({
270
+      viewState: 'IDLE',
271
+    });
272
+    this.updateNavigationState(event);
273
+  };
274
+
275
+  onMessage = (event: WebViewMessageEvent) => {
276
+    const { onMessage } = this.props;
277
+    if (onMessage) {
278
+      onMessage(event);
279
+    }
280
+  };
281
+
282
+  onLoadingProgress = (event: WebViewProgressEvent) => {
283
+    const { onLoadProgress } = this.props;
284
+    if (onLoadProgress) {
285
+      onLoadProgress(event);
286
+    }
287
+  };
288
+
289
+  onShouldStartLoadWithRequestCallback = (
290
+    shouldStart: boolean,
291
+    _url: string,
292
+    lockIdentifier: number,
293
+  ) => {
294
+    let { viewManager }: WebViewNativeConfig = this.props.nativeConfig || {};
295
+
296
+    if (this.props.useWebKit) {
297
+      viewManager = viewManager || RNCWKWebViewManager;
298
+    } else {
299
+      viewManager = viewManager || RNCUIWebViewManager;
300
+    }
301
+    invariant(viewManager != null, 'viewManager expected to be non-null');
302
+    viewManager.startLoadWithResult(!!shouldStart, lockIdentifier);
303
+  };
304
+
305
+  componentDidUpdate(prevProps: IOSWebViewProps) {
306
+    if (!(prevProps.useWebKit && this.props.useWebKit)) {
307
+      return;
308
+    }
309
+
310
+    this.showRedboxOnPropChanges(prevProps, 'allowsInlineMediaPlayback');
311
+    this.showRedboxOnPropChanges(prevProps, 'incognito');
312
+    this.showRedboxOnPropChanges(prevProps, 'mediaPlaybackRequiresUserAction');
313
+    this.showRedboxOnPropChanges(prevProps, 'dataDetectorTypes');
314
+
315
+    if (this.props.scalesPageToFit !== undefined) {
316
+      console.warn(
317
+        'The scalesPageToFit property is not supported when useWebKit = true',
318
+      );
319
+    }
320
+  }
321
+
322
+  showRedboxOnPropChanges(
323
+    prevProps: IOSWebViewProps,
324
+    propName: keyof IOSWebViewProps,
325
+  ) {
326
+    if (this.props[propName] !== prevProps[propName]) {
327
+      console.error(
328
+        `Changes to property ${propName} do nothing after the initial render.`,
329
+      );
330
+    }
331
+  }
332
+
333
+  render() {
334
+    const {
335
+      decelerationRate: decelerationRateProp,
336
+      nativeConfig = {},
337
+      onMessage,
338
+      onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
339
+      originWhitelist,
340
+      renderError,
341
+      renderLoading,
342
+      scalesPageToFit = this.props.useWebKit ? undefined : true,
343
+      style,
344
+      useWebKit,
345
+      ...otherProps
346
+    } = this.props;
347
+
348
+    let otherView = null;
349
+
350
+    if (this.state.viewState === 'LOADING') {
351
+      otherView = (renderLoading || defaultRenderLoading)();
352
+    } else if (this.state.viewState === 'ERROR') {
353
+      const errorEvent = this.state.lastErrorEvent;
354
+      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
355
+      otherView = (renderError || defaultRenderError)(
356
+        errorEvent.domain,
357
+        errorEvent.code,
358
+        errorEvent.description,
359
+      );
360
+    } else if (this.state.viewState !== 'IDLE') {
361
+      console.error(
362
+        `RNCWebView invalid state encountered: ${this.state.viewState}`,
363
+      );
364
+    }
365
+
366
+    const webViewStyles = [styles.container, styles.webView, style];
367
+    if (
368
+      this.state.viewState === 'LOADING'
369
+      || this.state.viewState === 'ERROR'
370
+    ) {
371
+      // if we're in either LOADING or ERROR states, don't show the webView
372
+      webViewStyles.push(styles.hidden);
373
+    }
374
+
375
+    const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
376
+      this.onShouldStartLoadWithRequestCallback,
377
+      // casting cause it's in the default props
378
+      originWhitelist as ReadonlyArray<string>,
379
+      onShouldStartLoadWithRequestProp,
380
+    );
381
+
382
+    const decelerationRate = processDecelerationRate(decelerationRateProp);
383
+
384
+    let NativeWebView = nativeConfig.component as typeof NativeWebViewIOS;
385
+
386
+    if (useWebKit) {
387
+      NativeWebView = NativeWebView || RNCWKWebView;
388
+    } else {
389
+      NativeWebView = NativeWebView || RNCUIWebView;
390
+    }
391
+
392
+    const webView = (
393
+      <NativeWebView
394
+        key="webViewKey"
395
+        {...otherProps}
396
+        decelerationRate={decelerationRate}
397
+        messagingEnabled={typeof onMessage === 'function'}
398
+        onLoadingError={this.onLoadingError}
399
+        onLoadingFinish={this.onLoadingFinish}
400
+        onLoadingProgress={this.onLoadingProgress}
401
+        onLoadingStart={this.onLoadingStart}
402
+        onMessage={this.onMessage}
403
+        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
404
+        ref={this.webViewRef}
405
+        scalesPageToFit={scalesPageToFit}
406
+        // TODO: find a better way to type this.
407
+        source={resolveAssetSource(this.props.source as ImageSourcePropType)}
408
+        style={webViewStyles}
409
+        {...nativeConfig.props}
410
+      />
411
+    );
412
+
413
+    return (
414
+      <View style={styles.container}>
415
+        {webView}
416
+        {otherView}
417
+      </View>
418
+    );
419
+  }
420
+}
421
+
422
+export default WebView;

+ 53
- 0
src/WebView.styles.ts View File

@@ -0,0 +1,53 @@
1
+import { StyleSheet, ViewStyle, TextStyle } from 'react-native';
2
+
3
+interface Styles {
4
+  container: ViewStyle;
5
+  errorContainer: ViewStyle;
6
+  errorText: TextStyle;
7
+  errorTextTitle: TextStyle;
8
+  hidden: ViewStyle;
9
+  loadingView: ViewStyle;
10
+  webView: ViewStyle;
11
+  loadingProgressBar: ViewStyle;
12
+}
13
+
14
+const BGWASH = 'rgba(255,255,255,0.8)';
15
+
16
+const styles = StyleSheet.create<Styles>({
17
+  container: {
18
+    flex: 1,
19
+  },
20
+  errorContainer: {
21
+    flex: 1,
22
+    justifyContent: 'center',
23
+    alignItems: 'center',
24
+    backgroundColor: BGWASH,
25
+  },
26
+  hidden: {
27
+    height: 0,
28
+    flex: 0, // disable 'flex:1' when hiding a View
29
+  },
30
+  loadingView: {
31
+    flex: 1,
32
+    justifyContent: 'center',
33
+    alignItems: 'center',
34
+  },
35
+  loadingProgressBar: {
36
+    height: 20,
37
+  },
38
+  errorText: {
39
+    fontSize: 14,
40
+    textAlign: 'center',
41
+    marginBottom: 2,
42
+  },
43
+  errorTextTitle: {
44
+    fontSize: 15,
45
+    fontWeight: '500',
46
+    marginBottom: 10,
47
+  },
48
+  webView: {
49
+    backgroundColor: '#ffffff',
50
+  },
51
+});
52
+
53
+export default styles;

+ 5
- 0
src/WebView.tsx View File

@@ -0,0 +1,5 @@
1
+// This files provides compatibility with out out tree platform.
2
+import { WebView } from 'react-native';
3
+
4
+export { WebView };
5
+export default WebView;

js/WebViewShared.js → src/WebViewShared.ts View File

@@ -1,39 +1,34 @@
1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11 1
 import escapeStringRegexp from 'escape-string-regexp';
12
-import { Linking } from 'react-native';
13
-import type {
2
+import { Linking, UIManager as NotTypedUIManager } from 'react-native';
3
+import {
14 4
   WebViewNavigationEvent,
15
-  WebViewNavigation,
16 5
   OnShouldStartLoadWithRequest,
6
+  CustomUIManager,
17 7
 } from './WebViewTypes';
18 8
 
9
+const UIManager = NotTypedUIManager as CustomUIManager;
10
+
19 11
 const defaultOriginWhitelist = ['http://*', 'https://*'];
20 12
 
21 13
 const extractOrigin = (url: string): string => {
22
-  const result = /^[A-Za-z][A-Za-z0-9\+\-\.]+:(\/\/)?[^/]*/.exec(url);
14
+  const result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url);
23 15
   return result === null ? '' : result[0];
24 16
 };
25 17
 
26 18
 const originWhitelistToRegex = (originWhitelist: string): string =>
27
-    `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
19
+  `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
28 20
 
29
-const passesWhitelist = (compiledWhitelist: Array<string>, url: string) => {
21
+const passesWhitelist = (
22
+  compiledWhitelist: ReadonlyArray<string>,
23
+  url: string,
24
+) => {
30 25
   const origin = extractOrigin(url);
31 26
   return compiledWhitelist.some(x => new RegExp(x).test(origin));
32 27
 };
33 28
 
34 29
 const compileWhitelist = (
35
-  originWhitelist: ?$ReadOnlyArray<string>,
36
-): Array<string> =>
30
+  originWhitelist: ReadonlyArray<string>,
31
+): ReadonlyArray<string> =>
37 32
   ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
38 33
 
39 34
 const createOnShouldStartLoadWithRequest = (
@@ -42,8 +37,8 @@ const createOnShouldStartLoadWithRequest = (
42 37
     url: string,
43 38
     lockIdentifier: number,
44 39
   ) => void,
45
-  originWhitelist: ?$ReadOnlyArray<string>,
46
-  onShouldStartLoadWithRequest: ?OnShouldStartLoadWithRequest,
40
+  originWhitelist: ReadonlyArray<string>,
41
+  onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest,
47 42
 ) => {
48 43
   return ({ nativeEvent }: WebViewNavigationEvent) => {
49 44
     let shouldStart = true;
@@ -51,7 +46,7 @@ const createOnShouldStartLoadWithRequest = (
51 46
 
52 47
     if (!passesWhitelist(compileWhitelist(originWhitelist), url)) {
53 48
       Linking.openURL(url);
54
-      shouldStart = false
49
+      shouldStart = false;
55 50
     }
56 51
 
57 52
     if (onShouldStartLoadWithRequest) {
@@ -62,4 +57,17 @@ const createOnShouldStartLoadWithRequest = (
62 57
   };
63 58
 };
64 59
 
65
-export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest };
60
+const getViewManagerConfig = (
61
+  viewManagerName: 'RNCUIWebView' | 'RNCWKWebView' | 'RNCWebView',
62
+) => {
63
+  if (!UIManager.getViewManagerConfig) {
64
+    return UIManager[viewManagerName];
65
+  }
66
+  return UIManager.getViewManagerConfig(viewManagerName);
67
+};
68
+
69
+export {
70
+  defaultOriginWhitelist,
71
+  createOnShouldStartLoadWithRequest,
72
+  getViewManagerConfig,
73
+};

js/WebViewTypes.js → src/WebViewTypes.ts View File

@@ -1,72 +1,135 @@
1
-/**
2
- * Copyright (c) 2015-present, Facebook, Inc.
3
- *
4
- * This source code is licensed under the MIT license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- *
7
- * @format
8
- * @flow
9
- */
10
-
11
-'use strict';
12
-
13
-import type { Node, Element, ComponentType } from 'react';
14
-
15
-import type { SyntheticEvent } from 'CoreEventTypes';
16
-import type { EdgeInsetsProp } from 'EdgeInsetsPropType';
17
-import type { ViewStyleProp } from 'StyleSheet';
18
-import type { ViewProps } from 'ViewPropTypes';
19
-
20
-export type WebViewNativeEvent = $ReadOnly<{|
21
-  url: string,
22
-  loading: boolean,
23
-  title: string,
24
-  canGoBack: boolean,
25
-  canGoForward: boolean,
26
-  lockIdentifier: number,
27
-|}>;
28
-
29
-export type WebViewProgressEvent = $ReadOnly<{|
30
-  ...WebViewNativeEvent,
31
-  progress: number,
32
-|}>;
33
-
34
-export type WebViewNavigation = $ReadOnly<{|
35
-  ...WebViewNativeEvent,
1
+/* eslint-disable react/no-multi-comp */
2
+
3
+import { ReactElement, Component } from 'react';
4
+import {
5
+  NativeSyntheticEvent,
6
+  ViewProps,
7
+  NativeMethodsMixin,
8
+  Constructor,
9
+  UIManagerStatic,
10
+} from 'react-native';
11
+
12
+export interface WebViewCommands {
13
+  goForward: Function;
14
+  goBack: Function;
15
+  reload: Function;
16
+  stopLoading: Function;
17
+  postMessage: Function;
18
+  injectJavaScript: Function;
19
+  loadUrl: Function;
20
+}
21
+
22
+export interface CustomUIManager extends UIManagerStatic {
23
+  getViewManagerConfig?: (
24
+    name: string,
25
+  ) => {
26
+    Commands: WebViewCommands;
27
+  };
28
+  dispatchViewManagerCommand: (
29
+    viewHandle: number,
30
+    command: Function,
31
+    params: object | null,
32
+  ) => void;
33
+  RNCUIWebView: {
34
+    Commands: WebViewCommands;
35
+  };
36
+  RNCWKWebView: {
37
+    Commands: WebViewCommands;
38
+  };
39
+  RNCWebView: {
40
+    Commands: WebViewCommands;
41
+  };
42
+}
43
+
44
+type WebViewState = 'IDLE' | 'LOADING' | 'ERROR';
45
+
46
+interface BaseState {
47
+  viewState: WebViewState;
48
+}
49
+
50
+interface NormalState extends BaseState {
51
+  viewState: 'IDLE' | 'LOADING';
52
+  lastErrorEvent: WebViewError | null;
53
+}
54
+
55
+interface ErrorState extends BaseState {
56
+  viewState: 'ERROR';
57
+  lastErrorEvent: WebViewError;
58
+}
59
+
60
+export type State = NormalState | ErrorState;
61
+
62
+// eslint-disable-next-line react/prefer-stateless-function
63
+declare class NativeWebViewIOSComponent extends Component<
64
+  IOSNativeWebViewProps
65
+> {}
66
+declare const NativeWebViewIOSBase: Constructor<NativeMethodsMixin> &
67
+  typeof NativeWebViewIOSComponent;
68
+export class NativeWebViewIOS extends NativeWebViewIOSBase {}
69
+
70
+// eslint-disable-next-line react/prefer-stateless-function
71
+declare class NativeWebViewAndroidComponent extends Component<
72
+  AndroidNativeWebViewProps
73
+> {}
74
+declare const NativeWebViewAndroidBase: Constructor<NativeMethodsMixin> &
75
+  typeof NativeWebViewAndroidComponent;
76
+export class NativeWebViewAndroid extends NativeWebViewAndroidBase {}
77
+
78
+export interface ContentInsetProp {
79
+  top?: number;
80
+  left?: number;
81
+  bottom?: number;
82
+  right?: number;
83
+}
84
+
85
+export interface WebViewNativeEvent {
86
+  url: string;
87
+  loading: boolean;
88
+  title: string;
89
+  canGoBack: boolean;
90
+  canGoForward: boolean;
91
+  lockIdentifier: number;
92
+}
93
+
94
+export interface WebViewProgressEvent extends WebViewNativeEvent {
95
+  progress: number;
96
+}
97
+
98
+export interface WebViewNavigation extends WebViewNativeEvent {
36 99
   navigationType:
37 100
     | 'click'
38 101
     | 'formsubmit'
39 102
     | 'backforward'
40 103
     | 'reload'
41 104
     | 'formresubmit'
42
-    | 'other',
43
-|}>;
105
+    | 'other';
106
+}
44 107
 
45
-export type WebViewMessage = $ReadOnly<{|
46
-  ...WebViewNativeEvent,
47
-  data: string,
48
-|}>;
108
+export type DecelerationRateConstant = 'normal' | 'fast';
49 109
 
50
-export type WebViewError = $ReadOnly<{|
51
-  ...WebViewNativeEvent,
110
+export interface WebViewMessage extends WebViewNativeEvent {
111
+  data: string;
112
+}
113
+
114
+export interface WebViewError extends WebViewNativeEvent {
52 115
   /**
53 116
    * `domain` is only used on iOS
54 117
    */
55
-  domain: ?string,
56
-  code: number,
57
-  description: string,
58
-|}>;
118
+  domain?: string;
119
+  code: number;
120
+  description: string;
121
+}
59 122
 
60
-export type WebViewEvent = SyntheticEvent<WebViewNativeEvent>;
123
+export type WebViewEvent = NativeSyntheticEvent<WebViewNativeEvent>;
61 124
 
62
-export type WebViewNavigationEvent = SyntheticEvent<WebViewNavigation>;
125
+export type WebViewNavigationEvent = NativeSyntheticEvent<WebViewNavigation>;
63 126
 
64
-export type WebViewMessageEvent = SyntheticEvent<WebViewMessage>;
127
+export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
65 128
 
66
-export type WebViewErrorEvent = SyntheticEvent<WebViewError>;
129
+export type WebViewErrorEvent = NativeSyntheticEvent<WebViewError>;
67 130
 
68
-export type DataDetectorTypes =
69
-  | 'phoneNumber'
131
+export type DataDetectorTypes
132
+  = | 'phoneNumber'
70 133
   | 'link'
71 134
   | 'address'
72 135
   | 'calendarEvent'
@@ -78,23 +141,23 @@ export type DataDetectorTypes =
78 141
 
79 142
 export type OverScrollModeType = 'always' | 'content' | 'never';
80 143
 
81
-export type WebViewSourceUri = $ReadOnly<{|
144
+export interface WebViewSourceUri {
82 145
   /**
83 146
    * The URI to load in the `WebView`. Can be a local or remote file.
84 147
    */
85
-  uri?: ?string,
148
+  uri: string;
86 149
 
87 150
   /**
88 151
    * The HTTP Method to use. Defaults to GET if not specified.
89 152
    * NOTE: On Android, only GET and POST are supported.
90 153
    */
91
-  method?: string,
154
+  method?: string;
92 155
 
93 156
   /**
94 157
    * Additional HTTP headers to send with the request.
95 158
    * NOTE: On Android, this can only be used with GET requests.
96 159
    */
97
-  headers?: Object,
160
+  headers?: Object;
98 161
 
99 162
   /**
100 163
    * The HTTP body to send with the request. This must be a valid
@@ -102,56 +165,117 @@ export type WebViewSourceUri = $ReadOnly<{|
102 165
    * additional encoding (e.g. URL-escaping or base64) applied.
103 166
    * NOTE: On Android, this can only be used with POST requests.
104 167
    */
105
-  body?: string,
106
-|}>;
168
+  body?: string;
169
+}
107 170
 
108
-export type WebViewSourceHtml = $ReadOnly<{|
171
+export interface WebViewSourceHtml {
109 172
   /**
110 173
    * A static HTML page to display in the WebView.
111 174
    */
112
-  html?: ?string,
175
+  html: string;
113 176
   /**
114 177
    * The base URL to be used for any relative links in the HTML.
115 178
    */
116
-  baseUrl?: ?string,
117
-|}>;
179
+  baseUrl: string;
180
+}
118 181
 
119 182
 export type WebViewSource = WebViewSourceUri | WebViewSourceHtml;
120 183
 
121
-export type WebViewNativeConfig = $ReadOnly<{|
184
+export interface ViewManager {
185
+  startLoadWithResult: Function;
186
+}
187
+
188
+export interface WebViewNativeConfig {
122 189
   /**
123 190
    * The native component used to render the WebView.
124 191
    */
125
-  component?: ComponentType<WebViewSharedProps>,
192
+  component?: typeof NativeWebViewIOS | typeof NativeWebViewAndroid;
126 193
   /**
127 194
    * Set props directly on the native component WebView. Enables custom props which the
128 195
    * original WebView doesn't pass through.
129 196
    */
130
-  props?: ?Object,
197
+  props?: Object;
131 198
   /**
132 199
    * Set the ViewManager to use for communication with the native side.
133 200
    * @platform ios
134 201
    */
135
-  viewManager?: ?Object,
136
-|}>;
202
+  viewManager?: ViewManager;
203
+}
137 204
 
138 205
 export type OnShouldStartLoadWithRequest = (
139 206
   event: WebViewNavigation,
140 207
 ) => boolean;
141 208
 
142
-export type IOSWebViewProps = $ReadOnly<{|
209
+export interface CommonNativeWebViewProps extends ViewProps {
210
+  cacheEnabled?: boolean;
211
+  injectedJavaScript?: string;
212
+  mediaPlaybackRequiresUserAction?: boolean;
213
+  messagingEnabled: boolean;
214
+  onLoadingError: (event: WebViewErrorEvent) => void;
215
+  onLoadingFinish: (event: WebViewNavigationEvent) => void;
216
+  onLoadingProgress: (event: WebViewProgressEvent) => void;
217
+  onLoadingStart: (event: WebViewNavigationEvent) => void;
218
+  onMessage: (event: WebViewMessageEvent) => void;
219
+  onShouldStartLoadWithRequest: (event: WebViewNavigationEvent) => void;
220
+  scalesPageToFit?: boolean;
221
+  showsHorizontalScrollIndicator?: boolean;
222
+  showsVerticalScrollIndicator?: boolean;
223
+  // TODO: find a better way to type this.
224
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
225
+  source: any;
226
+  userAgent?: string;
227
+}
228
+
229
+export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps {
230
+  allowFileAccess?: boolean;
231
+  allowUniversalAccessFromFileURLs?: boolean;
232
+  androidHardwareAccelerationDisabled?: boolean;
233
+  domStorageEnabled?: boolean;
234
+  geolocationEnabled?: boolean;
235
+  javaScriptEnabled?: boolean;
236
+  mixedContentMode?: 'never' | 'always' | 'compatibility';
237
+  onContentSizeChange?: (event: WebViewEvent) => void;
238
+  overScrollMode?: OverScrollModeType;
239
+  saveFormDataDisabled?: boolean;
240
+  thirdPartyCookiesEnabled?: boolean;
241
+  urlPrefixesForDefaultIntent?: ReadonlyArray<string>;
242
+}
243
+
244
+export interface IOSNativeWebViewProps extends CommonNativeWebViewProps {
245
+  allowsBackForwardNavigationGestures?: boolean;
246
+  allowsInlineMediaPlayback?: boolean;
247
+  allowsLinkPreview?: boolean;
248
+  automaticallyAdjustContentInsets?: boolean;
249
+  bounces?: boolean;
250
+  contentInset?: ContentInsetProp;
251
+  dataDetectorTypes?: DataDetectorTypes | ReadonlyArray<DataDetectorTypes>;
252
+  decelerationRate?: number;
253
+  directionalLockEnabled?: boolean;
254
+  hideKeyboardAccessoryView?: boolean;
255
+  incognito?: boolean;
256
+  pagingEnabled?: boolean;
257
+  scrollEnabled?: boolean;
258
+  useSharedProcessPool?: boolean;
259
+}
260
+
261
+export interface IOSWebViewProps extends WebViewSharedProps {
143 262
   /**
144 263
    * If true, use WKWebView instead of UIWebView.
145 264
    * @platform ios
146 265
    */
147
-  useWebKit?: ?boolean,
266
+  useWebKit?: boolean;
267
+
268
+  /**
269
+   * Does not store any data within the lifetime of the WebView.
270
+   */
271
+  incognito?: boolean;
148 272
 
149 273
   /**
150 274
    * Boolean value that determines whether the web view bounces
151 275
    * when it reaches the edge of the content. The default value is `true`.
152 276
    * @platform ios
153 277
    */
154
-  bounces?: ?boolean,
278
+  bounces?: boolean;
155 279
 
156 280
   /**
157 281
    * A floating-point number that determines how quickly the scroll view
@@ -164,14 +288,14 @@ export type IOSWebViewProps = $ReadOnly<{|
164 288
    *   - fast: 0.99 (the default for iOS web view)
165 289
    * @platform ios
166 290
    */
167
-  decelerationRate?: ?('fast' | 'normal' | number),
291
+  decelerationRate?: DecelerationRateConstant | number;
168 292
 
169 293
   /**
170 294
    * Boolean value that determines whether scrolling is enabled in the
171 295
    * `WebView`. The default value is `true`.
172 296
    * @platform ios
173 297
    */
174
-  scrollEnabled?: ?boolean,
298
+  scrollEnabled?: boolean;
175 299
 
176 300
   /**
177 301
    * If the value of this property is true, the scroll view stops on multiples
@@ -179,14 +303,22 @@ export type IOSWebViewProps = $ReadOnly<{|
179 303
    * The default value is false.
180 304
    * @platform ios
181 305
    */
182
-  pagingEnabled?: ?boolean,
306
+  pagingEnabled?: boolean;
307
+
308
+  /**
309
+   * Controls whether to adjust the content inset for web views that are
310
+   * placed behind a navigation bar, tab bar, or toolbar. The default value
311
+   * is `true`.
312
+   * @platform ios
313
+   */
314
+  automaticallyAdjustContentInsets?: boolean;
183 315
 
184 316
   /**
185 317
    * The amount by which the web view content is inset from the edges of
186 318
    * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
187 319
    * @platform ios
188 320
    */
189
-  contentInset?: ?EdgeInsetsProp,
321
+  contentInset?: ContentInsetProp;
190 322
 
191 323
   /**
192 324
    * Determines the types of data converted to clickable URLs in the web view's content.
@@ -210,7 +342,7 @@ export type IOSWebViewProps = $ReadOnly<{|
210 342
    *
211 343
    * @platform ios
212 344
    */
213
-  dataDetectorTypes?: ?DataDetectorTypes | $ReadOnlyArray<DataDetectorTypes>,
345
+  dataDetectorTypes?: DataDetectorTypes | ReadonlyArray<DataDetectorTypes>;
214 346
 
215 347
   /**
216 348
    * Boolean that determines whether HTML5 videos play inline or use the
@@ -221,28 +353,28 @@ export type IOSWebViewProps = $ReadOnly<{|
221 353
    * document must also include the `webkit-playsinline` attribute.
222 354
    * @platform ios
223 355
    */
224
-  allowsInlineMediaPlayback?: ?boolean,
356
+  allowsInlineMediaPlayback?: boolean;
225 357
   /**
226 358
    * Hide the accessory view when the keyboard is open. Default is false to be
227 359
    * backward compatible.
228 360
    */
229
-  hideKeyboardAccessoryView?: ?boolean,
361
+  hideKeyboardAccessoryView?: boolean;
230 362
   /**
231 363
    * A Boolean value indicating whether horizontal swipe gestures will trigger
232 364
    * back-forward list navigations.
233 365
    */
234
-  allowsBackForwardNavigationGestures?: ?boolean,
366
+  allowsBackForwardNavigationGestures?: boolean;
235 367
   /**
236 368
    * A Boolean value indicating whether WebKit WebView should be created using a shared
237 369
    * process pool, enabling WebViews to share cookies and localStorage between each other.
238 370
    * Default is true but can be set to false for backwards compatibility.
239 371
    * @platform ios
240 372
    */
241
-  useSharedProcessPool?: ?boolean,
373
+  useSharedProcessPool?: boolean;
242 374
   /**
243 375
    * The custom user agent string.
244 376
    */
245
-  userAgent?: ?string,
377
+  userAgent?: string;
246 378
 
247 379
   /**
248 380
    * A Boolean value that determines whether pressing on a link
@@ -252,19 +384,19 @@ export type IOSWebViewProps = $ReadOnly<{|
252 384
    * In iOS 10 and later, the default value is `true`; before that, the default value is `false`.
253 385
    * @platform ios
254 386
    */
255
-  allowsLinkPreview?: ?boolean,
387
+  allowsLinkPreview?: boolean;
256 388
 
257 389
   /**
258 390
    * A Boolean value that determines whether scrolling is disabled in a particular direction.
259 391
    * The default value is `true`.
260 392
    * @platform ios
261 393
    */
262
-  directionalLockEnabled?: ?boolean,
263
-|}>;
394
+  directionalLockEnabled?: boolean;
395
+}
264 396
 
265
-export type AndroidWebViewProps = $ReadOnly<{|
266
-  onNavigationStateChange?: (event: WebViewNavigation) => mixed,
267
-  onContentSizeChange?: (event: WebViewEvent) => mixed,
397
+export interface AndroidWebViewProps extends WebViewSharedProps {
398
+  onNavigationStateChange?: (event: WebViewNavigation) => void;
399
+  onContentSizeChange?: (event: WebViewEvent) => void;
268 400
 
269 401
   /**
270 402
    * https://developer.android.com/reference/android/view/View#OVER_SCROLL_NEVER
@@ -276,13 +408,13 @@ export type AndroidWebViewProps = $ReadOnly<{|
276 408
    *
277 409
    * @platform android
278 410
    */
279
-  overScrollMode?: ?OverScrollModeType,
411
+  overScrollMode?: OverScrollModeType;
280 412
 
281 413
   /**
282 414
    * Sets whether Geolocation is enabled. The default is false.
283 415
    * @platform android
284 416
    */
285
-  geolocationEnabled?: ?boolean,
417
+  geolocationEnabled?: boolean;
286 418
 
287 419
   /**
288 420
    * Boolean that sets whether JavaScript running in the context of a file
@@ -290,19 +422,19 @@ export type AndroidWebViewProps = $ReadOnly<{|
290 422
    * Including accessing content from other file scheme URLs
291 423
    * @platform android
292 424
    */
293
-  allowUniversalAccessFromFileURLs?: ?boolean,
425
+  allowUniversalAccessFromFileURLs?: boolean;
294 426
 
295 427
   /**
296 428
    * Sets whether the webview allow access to file system.
297 429
    * @platform android
298 430
    */
299
-  allowFileAccess?: ?boolean,
431
+  allowFileAccess?: boolean;
300 432
 
301 433
   /**
302 434
    * Used on Android only, controls whether form autocomplete data should be saved
303 435
    * @platform android
304 436
    */
305
-  saveFormDataDisabled?: ?boolean,
437
+  saveFormDataDisabled?: boolean;
306 438
 
307 439
   /**
308 440
    * Used on Android only, controls whether the given list of URL prefixes should
@@ -311,21 +443,21 @@ export type AndroidWebViewProps = $ReadOnly<{|
311 443
    * Use this to list URLs that WebView cannot handle, e.g. a PDF url.
312 444
    * @platform android
313 445
    */
314
-  urlPrefixesForDefaultIntent?: $ReadOnlyArray<string>,
446
+  urlPrefixesForDefaultIntent?: ReadonlyArray<string>;
315 447
 
316 448
   /**
317 449
    * Boolean value to enable JavaScript in the `WebView`. Used on Android only
318 450
    * as JavaScript is enabled by default on iOS. The default value is `true`.
319 451
    * @platform android
320 452
    */
321
-  javaScriptEnabled?: ?boolean,
453
+  javaScriptEnabled?: boolean;
322 454
 
323 455
   /**
324 456
    * Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android only
325 457
    * as Hardware Acceleration is a feature only for Android. The default value is `false`.
326 458
    * @platform android
327 459
    */
328
-  androidHardwareAccelerationDisabled?: ?boolean,
460
+  androidHardwareAccelerationDisabled?: boolean;
329 461
 
330 462
   /**
331 463
    * Boolean value to enable third party cookies in the `WebView`. Used on
@@ -333,20 +465,20 @@ export type AndroidWebViewProps = $ReadOnly<{|
333 465
    * default on Android Kitkat and below and on iOS. The default value is `true`.
334 466
    * @platform android
335 467
    */
336
-  thirdPartyCookiesEnabled?: ?boolean,
468
+  thirdPartyCookiesEnabled?: boolean;
337 469
 
338 470
   /**
339 471
    * Boolean value to control whether DOM Storage is enabled. Used only in
340 472
    * Android.
341 473
    * @platform android
342 474
    */
343
-  domStorageEnabled?: ?boolean,
475
+  domStorageEnabled?: boolean;
344 476
 
345 477
   /**
346 478
    * Sets the user-agent for the `WebView`.
347 479
    * @platform android
348 480
    */
349
-  userAgent?: ?string,
481
+  userAgent?: string;
350 482
 
351 483
   /**
352 484
    * Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
@@ -358,77 +490,53 @@ export type AndroidWebViewProps = $ReadOnly<{|
358 490
    * - `'compatibility'` -  WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
359 491
    * @platform android
360 492
    */
361
-  mixedContentMode?: ?('never' | 'always' | 'compatibility'),
362
-|}>;
363
-
364
-export type WebViewSharedProps = $ReadOnly<{|
365
-  ...ViewProps,
366
-  ...IOSWebViewProps,
367
-  ...AndroidWebViewProps,
368
-  /**
369
-   * Deprecated. Use `source` instead.
370
-   */
371
-  url?: ?string,
372
-  /**
373
-   * Deprecated. Use `source` instead.
374
-   */
375
-  html?: ?string,
493
+  mixedContentMode?: 'never' | 'always' | 'compatibility';
494
+}
376 495
 
496
+export interface WebViewSharedProps extends ViewProps {
377 497
   /**
378 498
    * Loads static html or a uri (with optional headers) in the WebView.
379 499
    */
380
-  source?: ?WebViewSource,
381
-
382
-  /**
383
-   * Does not store any data within the lifetime of the WebView.
384
-   */
385
-  incognito?: ?boolean,
500
+  source?: WebViewSource;
386 501
 
387 502
   /**
388 503
    * Function that returns a view to show if there's an error.
389 504
    */
390
-  renderError: (
391
-    errorDomain: ?string,
505
+  renderError?: (
506
+    errorDomain: string | undefined,
392 507
     errorCode: number,
393 508
     errorDesc: string,
394
-  ) => Element<any>, // view to show if there's an error
509
+  ) => ReactElement; // view to show if there's an error
395 510
 
396 511
   /**
397 512
    * Function that returns a loading indicator.
398 513
    */
399
-  renderLoading: () => Element<any>,
514
+  renderLoading?: () => ReactElement;
400 515
 
401 516
   /**
402 517
    * Function that is invoked when the `WebView` has finished loading.
403 518
    */
404
-  onLoad: (event: WebViewNavigationEvent) => mixed,
519
+  onLoad?: (event: WebViewNavigationEvent) => void;
405 520
 
406 521
   /**
407 522
    * Function that is invoked when the `WebView` load succeeds or fails.
408 523
    */
409
-  onLoadEnd: (event: WebViewNavigationEvent | WebViewErrorEvent) => mixed,
524
+  onLoadEnd?: (event: WebViewNavigationEvent | WebViewErrorEvent) => void;
410 525
 
411 526
   /**
412 527
    * Function that is invoked when the `WebView` starts loading.
413 528
    */
414
-  onLoadStart: (event: WebViewNavigationEvent) => mixed,
529
+  onLoadStart?: (event: WebViewNavigationEvent) => void;
415 530
 
416 531
   /**
417 532
    * Function that is invoked when the `WebView` load fails.
418 533
    */
419
-  onError: (event: WebViewErrorEvent) => mixed,
420
-
421
-  /**
422
-   * Controls whether to adjust the content inset for web views that are
423
-   * placed behind a navigation bar, tab bar, or toolbar. The default value
424
-   * is `true`.
425
-   */
426
-  automaticallyAdjustContentInsets?: ?boolean,
534
+  onError?: (event: WebViewErrorEvent) => void;
427 535
 
428 536
   /**
429 537
    * Function that is invoked when the `WebView` loading starts or ends.
430 538
    */
431
-  onNavigationStateChange?: (event: WebViewNavigation) => mixed,
539
+  onNavigationStateChange?: (event: WebViewNavigation) => void;
432 540
 
433 541
   /**
434 542
    * Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`.
@@ -437,36 +545,36 @@ export type WebViewSharedProps = $ReadOnly<{|
437 545
    * `window.ReactNativeWebView.postMessage` accepts one argument, `data`, which will be
438 546
    * available on the event object, `event.nativeEvent.data`. `data` must be a string.
439 547
    */
440
-  onMessage?: (event: WebViewMessageEvent) => mixed,
548
+  onMessage?: (event: WebViewMessageEvent) => void;
441 549
 
442 550
   /**
443 551
    * Function that is invoked when the `WebView` is loading.
444 552
    */
445
-  onLoadProgress?: (event: WebViewProgressEvent) => mixed,
553
+  onLoadProgress?: (event: WebViewProgressEvent) => void;
446 554
 
447 555
   /**
448 556
    * Boolean value that forces the `WebView` to show the loading view
449 557
    * on the first load.
450 558
    */
451
-  startInLoadingState?: ?boolean,
559
+  startInLoadingState?: boolean;
452 560
 
453 561
   /**
454 562
    * Set this to provide JavaScript that will be injected into the web page
455 563
    * when the view loads.
456 564
    */
457
-  injectedJavaScript?: ?string,
565
+  injectedJavaScript?: string;
458 566
 
459 567
   /**
460 568
    * Boolean value that determines whether a horizontal scroll indicator is
461 569
    * shown in the `WebView`. The default value is `true`.
462 570
    */
463
-  showsHorizontalScrollIndicator?: ?boolean,
571
+  showsHorizontalScrollIndicator?: boolean;
464 572
 
465 573
   /**
466 574
    * Boolean value that determines whether a vertical scroll indicator is
467 575
    * shown in the `WebView`. The default value is `true`.
468 576
    */
469
-  showsVerticalScrollIndicator?: ?boolean,
577
+  showsVerticalScrollIndicator?: boolean;
470 578
 
471 579
   /**
472 580
    * Boolean that controls whether the web content is scaled to fit
@@ -475,13 +583,13 @@ export type WebViewSharedProps = $ReadOnly<{|
475 583
    *
476 584
    * On iOS, when `useWebKit=true`, this prop will not work.
477 585
    */
478
-  scalesPageToFit?: ?boolean,
586
+  scalesPageToFit?: boolean;
479 587
 
480 588
   /**
481 589
    * Boolean that determines whether HTML5 audio and video requires the user
482 590
    * to tap them before they start playing. The default value is `true`.
483 591
    */
484
-  mediaPlaybackRequiresUserAction?: ?boolean,
592
+  mediaPlaybackRequiresUserAction?: boolean;
485 593
 
486 594
   /**
487 595
    * List of origin strings to allow being navigated to. The strings allow
@@ -490,26 +598,23 @@ export type WebViewSharedProps = $ReadOnly<{|
490 598
    * this whitelist, we will open the URL in Safari.
491 599
    * The default whitelisted origins are "http://*" and "https://*".
492 600
    */
493
-  originWhitelist?: $ReadOnlyArray<string>,
601
+  originWhitelist?: ReadonlyArray<string>;
494 602
 
495 603
   /**
496 604
    * Function that allows custom handling of any web view requests. Return
497 605
    * `true` from the function to continue loading the request and `false`
498 606
    * to stop loading. The `navigationType` is always `other` on android.
499 607
    */
500
-  onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest,
608
+  onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest;
501 609
 
502 610
   /**
503 611
    * Override the native component used to render the WebView. Enables a custom native
504 612
    * WebView which uses the same JavaScript as the original WebView.
505 613
    */
506
-  nativeConfig?: ?WebViewNativeConfig,
614
+  nativeConfig?: WebViewNativeConfig;
507 615
 
508 616
   /**
509 617
    * Should caching be enabled. Default is true.
510 618
    */
511
-  cacheEnabled?: ?boolean,
512
-
513
-  style?: ViewStyleProp,
514
-  children: Node,
515
-|}>;
619
+  cacheEnabled?: boolean;
620
+}

js/__tests__/WebViewShared-test.js → src/__tests__/WebViewShared-test.js View File


js/__tests__/__snapshots__/WebViewShared-test.js.snap → src/__tests__/__snapshots__/WebViewShared-test.js.snap View File


+ 24
- 0
tsconfig.json View File

@@ -0,0 +1,24 @@
1
+{
2
+  "include": ["src/*"],
3
+  "compilerOptions": {
4
+    "baseUrl": "./src/",
5
+    "jsx": "react-native",
6
+    "module": "esnext",
7
+    "moduleResolution": "node",
8
+    "lib": ["es2017"],
9
+    "declaration": true,
10
+    "declarationMap": true,
11
+    "outDir": "lib",
12
+    "allowSyntheticDefaultImports": true,
13
+    "esModuleInterop": true,
14
+    "forceConsistentCasingInFileNames": true,
15
+    "noFallthroughCasesInSwitch": true,
16
+    "noImplicitReturns": true,
17
+    "noUnusedLocals": true,
18
+    "noUnusedParameters": true,
19
+    "pretty": true,
20
+    "resolveJsonModule": true,
21
+    "skipLibCheck": true,
22
+    "strict": true
23
+  }
24
+}

+ 0
- 483
typings/index.d.ts View File

@@ -1,483 +0,0 @@
1
-import { ComponentType, ReactElement, ReactNode, Component } from 'react';
2
-import { Insets, NativeSyntheticEvent, StyleProp, ViewProps, ViewStyle } from 'react-native';
3
-
4
-export interface WebViewNativeEvent {
5
-  readonly url: string;
6
-  readonly loading: boolean;
7
-  readonly title: string;
8
-  readonly canGoBack: boolean;
9
-  readonly canGoForward: boolean;
10
-}
11
-
12
-export interface WebViewIOSLoadRequestEvent extends WebViewNativeEvent {
13
-  target: number;
14
-  lockIdentifier: number;
15
-  navigationType: "click" | "formsubmit" | "backforward" | "reload" | "formresubmit" | "other";
16
-}
17
-
18
-export interface WebViewProgressEvent extends WebViewNativeEvent {
19
-  readonly progress: number;
20
-}
21
-
22
-export interface WebViewNavigation extends WebViewNativeEvent {
23
-  readonly navigationType:
24
-    | 'click'
25
-    | 'formsubmit'
26
-    | 'backforward'
27
-    | 'reload'
28
-    | 'formresubmit'
29
-    | 'other';
30
-}
31
-
32
-export interface WebViewMessage extends WebViewNativeEvent {
33
-  readonly data: string;
34
-}
35
-
36
-export interface WebViewError extends WebViewNativeEvent {
37
-  readonly domain?: string;
38
-  readonly code: number;
39
-  readonly description: string;
40
-}
41
-
42
-export type WebViewEvent = NativeSyntheticEvent<WebViewNativeEvent>;
43
-
44
-export type WebViewNavigationEvent = NativeSyntheticEvent<WebViewNavigation>;
45
-
46
-export type WebViewMessageEvent = NativeSyntheticEvent<WebViewMessage>;
47
-
48
-export type WebViewErrorEvent = NativeSyntheticEvent<WebViewError>;
49
-
50
-export type DataDetectorTypes =
51
-  | 'phoneNumber'
52
-  | 'link'
53
-  | 'address'
54
-  | 'calendarEvent'
55
-  | 'trackingNumber'
56
-  | 'flightNumber'
57
-  | 'lookupSuggestion'
58
-  | 'none'
59
-  | 'all';
60
-
61
-export type OverScrollModeType = 'always' | 'content' | 'never';
62
-
63
-export interface WebViewSourceUri {
64
-  /**
65
-   * The URI to load in the `WebView`. Can be a local or remote file.
66
-   */
67
-  uri?: string;
68
-
69
-  /**
70
-   * The HTTP Method to use. Defaults to GET if not specified.
71
-   * NOTE: On Android, only GET and POST are supported.
72
-   */
73
-  method?: string;
74
-
75
-  /**
76
-   * Additional HTTP headers to send with the request.
77
-   * NOTE: On Android, this can only be used with GET requests.
78
-   */
79
-  headers?: {[key: string]: string};
80
-
81
-  /**
82
-   * The HTTP body to send with the request. This must be a valid
83
-   * UTF-8 string, and will be sent exactly as specified, with no
84
-   * additional encoding (e.g. URL-escaping or base64) applied.
85
-   * NOTE: On Android, this can only be used with POST requests.
86
-   */
87
-  body?: string;
88
-}
89
-
90
-export interface WebViewSourceHtml {
91
-  /**
92
-   * A static HTML page to display in the WebView.
93
-   */
94
-  html?: string;
95
-  /**
96
-   * The base URL to be used for any relative links in the HTML.
97
-   */
98
-  baseUrl?: string;
99
-}
100
-
101
-export type WebViewSource = WebViewSourceUri | WebViewSourceHtml;
102
-
103
-export interface WebViewNativeConfig {
104
-  /*
105
-    * The native component used to render the WebView.
106
-    */
107
-  component?: ComponentType<WebViewSharedProps>;
108
-  /*
109
-    * Set props directly on the native component WebView. Enables custom props which the
110
-    * original WebView doesn't pass through.
111
-    */
112
-  props?: any;
113
-  /*
114
-    * Set the ViewManager to use for communication with the native side.
115
-    * @platform ios
116
-    */
117
-  viewManager?: any;
118
-}
119
-
120
-export interface IOSWebViewProps {
121
-  /**
122
-   * If true, use WKWebView instead of UIWebView.
123
-   * @platform ios
124
-   */
125
-  useWebKit?: boolean;
126
-
127
-  /**
128
-   * Boolean value that determines whether the web view bounces
129
-   * when it reaches the edge of the content. The default value is `true`.
130
-   * @platform ios
131
-   */
132
-  bounces?: boolean;
133
-
134
-  /**
135
-   * A floating-point number that determines how quickly the scroll view
136
-   * decelerates after the user lifts their finger. You may also use the
137
-   * string shortcuts `"normal"` and `"fast"` which match the underlying iOS
138
-   * settings for `UIScrollViewDecelerationRateNormal` and
139
-   * `UIScrollViewDecelerationRateFast` respectively:
140
-   *
141
-   *   - normal: 0.998
142
-   *   - fast: 0.99 (the default for iOS web view)
143
-   * @platform ios
144
-   */
145
-  decelerationRate?: 'fast' | 'normal' | number;
146
-
147
-  /**
148
-   * Boolean value that determines whether scrolling is enabled in the
149
-   * `WebView`. The default value is `true`.
150
-   * @platform ios
151
-   */
152
-  scrollEnabled?: boolean;
153
-
154
-  /**
155
-   * A Boolean value that determines whether scrolling is disabled in a particular direction.
156
-   * The default value is `true`.
157
-   * @platform ios
158
-   */
159
-  directionalLockEnabled?: boolean;
160
-
161
-  /**
162
-   * If the value of this property is true, the scroll view stops on multiples
163
-   * of the scroll view’s bounds when the user scrolls.
164
-   * The default value is false.
165
-   * @platform ios
166
-   */
167
-  pagingEnabled?: boolean,
168
-
169
-  /**
170
-   * The amount by which the web view content is inset from the edges of
171
-   * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
172
-   * @platform ios
173
-   */
174
-  contentInset?: Insets;
175
-
176
-  /**
177
-   * Determines the types of data converted to clickable URLs in the web view's content.
178
-   * By default only phone numbers are detected.
179
-   *
180
-   * You can provide one type or an array of many types.
181
-   *
182
-   * Possible values for `dataDetectorTypes` are:
183
-   *
184
-   * - `'phoneNumber'`
185
-   * - `'link'`
186
-   * - `'address'`
187
-   * - `'calendarEvent'`
188
-   * - `'none'`
189
-   * - `'all'`
190
-   *
191
-   * With the new WebKit implementation, we have three new values:
192
-   * - `'trackingNumber'`,
193
-   * - `'flightNumber'`,
194
-   * - `'lookupSuggestion'`,
195
-   *
196
-   * @platform ios
197
-   */
198
-  dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[];
199
-
200
-  /**
201
-   * Function that allows custom handling of any web view requests. Return
202
-   * `true` from the function to continue loading the request and `false`
203
-   * to stop loading.
204
-   * @platform ios
205
-   */
206
-  onShouldStartLoadWithRequest?: (event: WebViewIOSLoadRequestEvent) => any;
207
-
208
-  /**
209
-   * Boolean that determines whether HTML5 videos play inline or use the
210
-   * native full-screen controller. The default value is `false`.
211
-   *
212
-   * **NOTE** : In order for video to play inline, not only does this
213
-   * property need to be set to `true`, but the video element in the HTML
214
-   * document must also include the `webkit-playsinline` attribute.
215
-   * @platform ios
216
-   */
217
-  allowsInlineMediaPlayback?: boolean;
218
-  /**
219
-   * Hide the accessory view when the keyboard is open. Default is false to be
220
-   * backward compatible.
221
-   */
222
-  hideKeyboardAccessoryView?: boolean;
223
-  /**
224
-   * If true, this will be able horizontal swipe gestures when using the WKWebView. The default value is `false`.
225
-   */
226
-  allowsBackForwardNavigationGestures?: boolean;
227
-
228
-  /**
229
-   * A Boolean value that determines whether pressing on a link
230
-   * displays a preview of the destination for the link.
231
-   *
232
-   * This property is available on devices that support 3D Touch.
233
-   * In iOS 10 and later, the default value is `true`; before that, the default value is `false`.
234
-   * @platform ios
235
-   */
236
-  allowsLinkPreview?: boolean;
237
-}
238
-
239
-export interface AndroidWebViewProps {
240
-  onNavigationStateChange?: (event: WebViewNavigation) => any;
241
-  onContentSizeChange?: (event: WebViewEvent) => any;
242
-
243
-  /**
244
-   * https://developer.android.com/reference/android/view/View#OVER_SCROLL_NEVER
245
-   * Sets the overScrollMode. Possible values are:
246
-   *
247
-   * - `'always'` (default)
248
-   * - `'content'`
249
-   * - `'never'`
250
-   *
251
-   * @platform android
252
-   */
253
-  overScrollMode?: OverScrollModeType;
254
-
255
-  /**
256
-   * Sets whether Geolocation is enabled. The default is false.
257
-   * @platform android
258
-   */
259
-  geolocationEnabled?: boolean;
260
-
261
-  /**
262
-   * Boolean that sets whether JavaScript running in the context of a file
263
-   * scheme URL should be allowed to access content from any origin.
264
-   * Including accessing content from other file scheme URLs
265
-   * @platform android
266
-   */
267
-  allowUniversalAccessFromFileURLs?: boolean;
268
-
269
-  /**
270
-   * Sets whether the webview allow access to file system.
271
-   * @platform android
272
-   */
273
-  allowFileAccess?: boolean;
274
-
275
-  /**
276
-   * Used on Android only, controls whether form autocomplete data should be saved
277
-   * @platform android
278
-   */
279
-  saveFormDataDisabled?: boolean;
280
-
281
-  /*
282
-    * Used on Android only, controls whether the given list of URL prefixes should
283
-    * make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a
284
-    * default activity intent for those URL instead of loading it within the webview.
285
-    * Use this to list URLs that WebView cannot handle, e.g. a PDF url.
286
-    * @platform android
287
-    */
288
-  urlPrefixesForDefaultIntent?: string[];
289
-
290
-  /**
291
-   * Boolean value to enable JavaScript in the `WebView`. Used on Android only
292
-   * as JavaScript is enabled by default on iOS. The default value is `true`.
293
-   * @platform android
294
-   */
295
-  javaScriptEnabled?: boolean;
296
-
297
-  /**
298
-   * Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android only
299
-   * as Hardware Acceleration is a feature only for Android. The default value is `false`.
300
-   * @platform android
301
-   */
302
-  androidHardwareAccelerationDisabled?: boolean;
303
-
304
-  /**
305
-   * Boolean value to enable third party cookies in the `WebView`. Used on
306
-   * Android Lollipop and above only as third party cookies are enabled by
307
-   * default on Android Kitkat and below and on iOS. The default value is `true`.
308
-   * @platform android
309
-   */
310
-  thirdPartyCookiesEnabled?: boolean;
311
-
312
-  /**
313
-   * Boolean value to control whether DOM Storage is enabled. Used only in
314
-   * Android.
315
-   * @platform android
316
-   */
317
-  domStorageEnabled?: boolean;
318
-
319
-  /**
320
-   * Sets the user-agent for the `WebView`.
321
-   * @platform android
322
-   */
323
-  userAgent?: string;
324
-
325
-  /**
326
-   * Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin.
327
-   *
328
-   * Possible values for `mixedContentMode` are:
329
-   *
330
-   * - `'never'` (default) - WebView will not allow a secure origin to load content from an insecure origin.
331
-   * - `'always'` - WebView will allow a secure origin to load content from any other origin, even if that origin is insecure.
332
-   * - `'compatibility'` -  WebView will attempt to be compatible with the approach of a modern web browser with regard to mixed content.
333
-   * @platform android
334
-   */
335
-  mixedContentMode?: 'never' | 'always' | 'compatibility';
336
-}
337
-
338
-export interface WebViewSharedProps extends ViewProps, IOSWebViewProps, AndroidWebViewProps {
339
-  /**
340
-   * @Deprecated. Use `source` instead.
341
-   */
342
-  url?: string;
343
-  /**
344
-   * @Deprecated. Use `source` instead.
345
-   */
346
-  html?: string;
347
-
348
-  /**
349
-   * Loads static html or a uri (with optional headers) in the WebView.
350
-   */
351
-  source?: WebViewSource;
352
-
353
-  /**
354
-   * Function that returns a view to show if there's an error.
355
-   */
356
-  renderError?: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => ReactElement<any>; // view to show if there's an error
357
-
358
-  /**
359
-   * Function that returns a loading indicator.
360
-   */
361
-  renderLoading?: () => ReactElement<any>;
362
-
363
-  /**
364
-   * Function that is invoked when the `WebView` has finished loading.
365
-   */
366
-  onLoad?: (event: WebViewNavigationEvent) => any;
367
-
368
-  /**
369
-   * Function that is invoked when the `WebView` load succeeds or fails.
370
-   */
371
-  onLoadEnd?: (event: WebViewNavigationEvent | WebViewErrorEvent) => any;
372
-
373
-  /**
374
-   * Function that is invoked when the `WebView` starts loading.
375
-   */
376
-  onLoadStart?: (event: WebViewNavigationEvent) => any;
377
-
378
-  /**
379
-   * Function that is invoked when the `WebView` load fails.
380
-   */
381
-  onError?: (event: WebViewErrorEvent) => any;
382
-
383
-  /**
384
-   * Controls whether to adjust the content inset for web views that are
385
-   * placed behind a navigation bar, tab bar, or toolbar. The default value
386
-   * is `true`.
387
-   */
388
-  automaticallyAdjustContentInsets?: boolean;
389
-
390
-  /**
391
-   * Function that is invoked when the `WebView` loading starts or ends.
392
-   */
393
-  onNavigationStateChange?: (event: WebViewNavigation) => any;
394
-
395
-  /**
396
-   * A function that is invoked when the webview calls `window.postMessage`.
397
-   * Setting this property will inject a `postMessage` global into your
398
-   * webview, but will still call pre-existing values of `postMessage`.
399
-   *
400
-   * `window.postMessage` accepts one argument, `data`, which will be
401
-   * available on the event object, `event.nativeEvent.data`. `data`
402
-   * must be a string.
403
-   */
404
-  onMessage?: (event: WebViewMessageEvent) => any;
405
-
406
-  /**
407
-   * Function that is invoked when the `WebView` is loading.
408
-   */
409
-  onLoadProgress?: (event: NativeSyntheticEvent<WebViewProgressEvent>) => any;
410
-
411
-  /**
412
-   * Boolean value that forces the `WebView` to show the loading view
413
-   * on the first load.
414
-   */
415
-  startInLoadingState?: boolean;
416
-
417
-  /**
418
-   * Set this to provide JavaScript that will be injected into the web page
419
-   * when the view loads.
420
-   */
421
-  injectedJavaScript?: string;
422
-
423
-  /**
424
-   * Boolean that controls whether the web content is scaled to fit
425
-   * the view and enables the user to change the scale. The default value
426
-   * is `true`.
427
-   *
428
-   * On iOS, when `useWebKit=true`, this prop will not work.
429
-   */
430
-  scalesPageToFit?: boolean;
431
-
432
-  /**
433
-   * Boolean that determines whether HTML5 audio and video requires the user
434
-   * to tap them before they start playing. The default value is `true`.
435
-   */
436
-  mediaPlaybackRequiresUserAction?: boolean;
437
-
438
-  /**
439
-   * List of origin strings to allow being navigated to. The strings allow
440
-   * wildcards and get matched against *just* the origin (not the full URL).
441
-   * If the user taps to navigate to a new page but the new page is not in
442
-   * this whitelist, we will open the URL in Safari.
443
-   * The default whitelisted origins are "http://*" and "https://*".
444
-   */
445
-  originWhitelist?: string[];
446
-
447
-  /**
448
-   * Boolean value that determines whether caching is enabled in the
449
-   * `WebView`. The default value is `true` - i.e. caching is *enabled by default*
450
-   */
451
-  cacheEnabled?: boolean,
452
-
453
-  /**
454
-   * Override the native component used to render the WebView. Enables a custom native
455
-   * WebView which uses the same JavaScript as the original WebView.
456
-   */
457
-  nativeConfig?: WebViewNativeConfig;
458
-
459
-  /**
460
-   * A Boolean value that controls whether the horizontal scroll indicator is visible
461
-   * The default value is `true`.
462
-   */
463
-  showsHorizontalScrollIndicator?: boolean;
464
-
465
-  /**
466
-   * A Boolean value that controls whether the vertical scroll indicator is visible
467
-   * The default value is `true`
468
-   */
469
-  showsVerticalScrollIndicator?: boolean;
470
-
471
-  style?: StyleProp<ViewStyle>;
472
-  children?: ReactNode;
473
-}
474
-
475
-export class WebView extends Component<WebViewSharedProps> {
476
-  static isFileUploadSupported: () => Promise<boolean>;
477
-  public goForward: () => void;
478
-  public goBack: () => void;
479
-  public reload: () => void;
480
-  public stopLoading: () => void;
481
-  public postMessage: (msg: string) => void;
482
-  public injectJavaScript: (js: string) => void;
483
-}

+ 1454
- 529
yarn.lock
File diff suppressed because it is too large
View File