Thibault Malbranche 5 years ago
parent
commit
3f02dda910

+ 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
 ---

+ 7
- 4
package.json View File

@@ -25,21 +25,24 @@
25 25
     "react-native": ">=0.57 <0.59"
26 26
   },
27 27
   "dependencies": {
28
-    "escape-string-regexp": "^1.0.5",
29
-    "fbjs": "^0.8.17"
28
+    "escape-string-regexp": "1.0.5",
29
+    "invariant": "2.2.4"
30 30
   },
31 31
   "devDependencies": {
32 32
     "@babel/core": "^7.2.2",
33 33
     "@semantic-release/git": "7.0.5",
34
+    "@types/escape-string-regexp": "^1.0.0",
35
+    "@types/invariant": "^2.2.29",
34 36
     "@types/react": "^16.6.3",
35
-    "@types/react-native": "^0.57.8",
37
+    "@types/react-native": "0.57.40",
36 38
     "babel-jest": "^24.0.0",
37 39
     "flow-bin": "^0.80.0",
38 40
     "jest": "^24.0.0",
39 41
     "metro-react-native-babel-preset": "^0.51.1",
40 42
     "react": "16.6.3",
41 43
     "react-native": "^0.57.8",
42
-    "semantic-release": "15.10.3"
44
+    "semantic-release": "15.10.3",
45
+    "typescript": "^3.3.3333"
43 46
   },
44 47
   "repository": {
45 48
     "type": "git",

js/WebView.android.js → src/WebView.android.tsx View File

@@ -1,49 +1,40 @@
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 React from 'react';
12 2
 
13
-import ReactNative, {
3
+import {
14 4
   ActivityIndicator,
15 5
   Image,
16 6
   requireNativeComponent,
17
-  StyleSheet,
18
-  UIManager,
7
+  UIManager as NotTypedUIManager,
19 8
   View,
20 9
   NativeModules,
10
+  WebViewUriSource,
11
+  ImageSourcePropType,
12
+  findNodeHandle,
21 13
 } from 'react-native';
22 14
 
23
-import invariant from 'fbjs/lib/invariant';
24
-import keyMirror from 'fbjs/lib/keyMirror';
15
+import invariant from 'invariant';
25 16
 
26 17
 import {
27 18
   defaultOriginWhitelist,
28 19
   createOnShouldStartLoadWithRequest,
20
+  getViewManagerConfig,
29 21
 } from './WebViewShared';
30
-import type {
31
-  WebViewError,
22
+import {
32 23
   WebViewErrorEvent,
33 24
   WebViewMessageEvent,
34 25
   WebViewNavigationEvent,
35 26
   WebViewProgressEvent,
36
-  WebViewSharedProps,
37
-  WebViewSource,
27
+  AndroidWebViewProps,
28
+  NativeWebViewAndroid,
29
+  State,
30
+  CustomUIManager,
38 31
 } from './WebViewTypes';
39 32
 
40
-const resolveAssetSource = Image.resolveAssetSource;
33
+import styles from './WebView.styles';
41 34
 
42
-const WebViewState = keyMirror({
43
-  IDLE: null,
44
-  LOADING: null,
45
-  ERROR: null,
46
-});
35
+const UIManager = NotTypedUIManager as CustomUIManager;
36
+
37
+const resolveAssetSource = Image.resolveAssetSource;
47 38
 
48 39
 const defaultRenderLoading = () => (
49 40
   <View style={styles.loadingView}>
@@ -51,15 +42,10 @@ const defaultRenderLoading = () => (
51 42
   </View>
52 43
 );
53 44
 
54
-type State = {|
55
-  viewState: WebViewState,
56
-  lastErrorEvent: ?WebViewError,
57
-|};
58
-
59 45
 /**
60 46
  * Renders a native WebView.
61 47
  */
62
-class WebView extends React.Component<WebViewSharedProps, State> {
48
+class WebView extends React.Component<AndroidWebViewProps, State> {
63 49
   static defaultProps = {
64 50
     overScrollMode: 'always',
65 51
     javaScriptEnabled: true,
@@ -77,113 +63,88 @@ class WebView extends React.Component<WebViewSharedProps, State> {
77 63
     return NativeModules.RNCWebView.isFileUploadSupported();
78 64
   };
79 65
 
80
-  state = {
81
-    viewState: this.props.startInLoadingState
82
-      ? WebViewState.LOADING
83
-      : WebViewState.IDLE,
66
+  state: State = {
67
+    viewState: this.props.startInLoadingState ? 'LOADING' : 'IDLE',
84 68
     lastErrorEvent: null,
85 69
   };
86 70
 
87
-  webViewRef = React.createRef();
71
+  webViewRef = React.createRef<NativeWebViewAndroid>();
88 72
 
89 73
   render() {
74
+    const {
75
+      onMessage,
76
+      onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
77
+      originWhitelist,
78
+      renderError,
79
+      renderLoading,
80
+      source,
81
+      style,
82
+      nativeConfig = {},
83
+      ...otherProps
84
+    } = this.props;
90 85
     let otherView = null;
91 86
 
92
-    if (this.state.viewState === WebViewState.LOADING) {
93
-      otherView = (this.props.renderLoading || defaultRenderLoading)();
94
-    } else if (this.state.viewState === WebViewState.ERROR) {
87
+    if (this.state.viewState === 'LOADING') {
88
+      otherView = (renderLoading || defaultRenderLoading)();
89
+    } else if (this.state.viewState === 'ERROR') {
95 90
       const errorEvent = this.state.lastErrorEvent;
96 91
       invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
97 92
       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) {
93
+        renderError &&
94
+        renderError(errorEvent.domain, errorEvent.code, errorEvent.description);
95
+    } else if (this.state.viewState !== 'IDLE') {
105 96
       console.error(
106 97
         'RNCWebView invalid state encountered: ' + this.state.viewState,
107 98
       );
108 99
     }
109 100
 
110
-    const webViewStyles = [styles.container, this.props.style];
101
+    const webViewStyles = [styles.container, style];
111 102
     if (
112
-      this.state.viewState === WebViewState.LOADING ||
113
-      this.state.viewState === WebViewState.ERROR
103
+      this.state.viewState === 'LOADING' ||
104
+      this.state.viewState === 'ERROR'
114 105
     ) {
115 106
       // if we're in either LOADING or ERROR states, don't show the webView
116 107
       webViewStyles.push(styles.hidden);
117 108
     }
118 109
 
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) {
110
+    if (
111
+      (source as WebViewUriSource).method === 'POST' &&
112
+      (source as WebViewUriSource).headers
113
+    ) {
127 114
       console.warn(
128 115
         'WebView: `source.headers` is not supported when using POST.',
129 116
       );
130
-    } else if (source.method === 'GET' && source.body) {
117
+    } else if (
118
+      (source as WebViewUriSource).method === 'GET' &&
119
+      (source as WebViewUriSource).body
120
+    ) {
131 121
       console.warn('WebView: `source.body` is not supported when using GET.');
132 122
     }
133 123
 
134
-    const nativeConfig = this.props.nativeConfig || {};
135
-
136
-    let NativeWebView = nativeConfig.component || RNCWebView;
124
+    let NativeWebView =
125
+      (nativeConfig.component as typeof NativeWebViewAndroid) || RNCWebView;
137 126
 
138 127
     const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
139 128
       this.onShouldStartLoadWithRequestCallback,
140
-      this.props.originWhitelist,
141
-      this.props.onShouldStartLoadWithRequest,
129
+      originWhitelist,
130
+      onShouldStartLoadWithRequestProp,
142 131
     );
143 132
 
144 133
     const webView = (
145 134
       <NativeWebView
146
-        ref={this.webViewRef}
135
+        {...otherProps}
147 136
         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}
137
+        messagingEnabled={typeof onMessage === 'function'}
172 138
         onLoadingError={this.onLoadingError}
139
+        onLoadingFinish={this.onLoadingFinish}
173 140
         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}
141
+        onLoadingStart={this.onLoadingStart}
142
+        onMessage={this.onMessage}
143
+        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
144
+        ref={this.webViewRef}
145
+        // TODO: find a better way to type this.
146
+        source={resolveAssetSource(source as ImageSourcePropType)}
147
+        style={webViewStyles}
187 148
         {...nativeConfig.props}
188 149
       />
189 150
     );
@@ -196,14 +157,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
196 157
     );
197 158
   }
198 159
 
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;
160
+  getCommands = () => getViewManagerConfig('RNCWebView').Commands;
207 161
 
208 162
   goForward = () => {
209 163
     UIManager.dispatchViewManagerCommand(
@@ -223,7 +177,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
223 177
 
224 178
   reload = () => {
225 179
     this.setState({
226
-      viewState: WebViewState.LOADING,
180
+      viewState: 'LOADING',
227 181
     });
228 182
     UIManager.dispatchViewManagerCommand(
229 183
       this.getWebViewHandle(),
@@ -272,8 +226,13 @@ class WebView extends React.Component<WebViewSharedProps, State> {
272 226
     }
273 227
   };
274 228
 
229
+  /**
230
+   * Returns the native `WebView` node.
231
+   */
275 232
   getWebViewHandle = () => {
276
-    return ReactNative.findNodeHandle(this.webViewRef.current);
233
+    const nodeHandle = findNodeHandle(this.webViewRef.current);
234
+    invariant(nodeHandle != null, 'nodeHandle expected to be non-null');
235
+    return nodeHandle as number;
277 236
   };
278 237
 
279 238
   onLoadingStart = (event: WebViewNavigationEvent) => {
@@ -291,7 +250,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
291 250
 
292 251
     this.setState({
293 252
       lastErrorEvent: event.nativeEvent,
294
-      viewState: WebViewState.ERROR,
253
+      viewState: 'ERROR',
295 254
     });
296 255
   };
297 256
 
@@ -300,7 +259,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
300 259
     onLoad && onLoad(event);
301 260
     onLoadEnd && onLoadEnd(event);
302 261
     this.setState({
303
-      viewState: WebViewState.IDLE,
262
+      viewState: 'IDLE',
304 263
     });
305 264
     this.updateNavigationState(event);
306 265
   };
@@ -329,24 +288,8 @@ class WebView extends React.Component<WebViewSharedProps, State> {
329 288
   };
330 289
 }
331 290
 
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
-});
291
+const RNCWebView = requireNativeComponent(
292
+  'RNCWebView',
293
+) as typeof NativeWebViewAndroid;
351 294
 
352 295
 module.exports = WebView;

js/WebView.ios.js → src/WebView.ios.tsx View File

@@ -4,99 +4,71 @@
4 4
  * This source code is licensed under the MIT license found in the
5 5
  * LICENSE file in the root directory of this source tree.
6 6
  *
7
- * @format
8
- * @flow
9 7
  */
10 8
 
11 9
 import React from 'react';
12 10
 import {
13 11
   ActivityIndicator,
14
-  Linking,
15
-  StyleSheet,
16 12
   Text,
17
-  UIManager,
13
+  UIManager as NotTypedUIManager,
18 14
   View,
19 15
   requireNativeComponent,
20 16
   NativeModules,
21 17
   Image,
22 18
   findNodeHandle,
19
+  ImageSourcePropType,
23 20
 } from 'react-native';
24
-
25
-import invariant from 'fbjs/lib/invariant';
26
-import keyMirror from 'fbjs/lib/keyMirror';
21
+import invariant from 'invariant';
27 22
 
28 23
 import {
29 24
   defaultOriginWhitelist,
30 25
   createOnShouldStartLoadWithRequest,
26
+  getViewManagerConfig,
31 27
 } from './WebViewShared';
32
-import type {
33
-  WebViewEvent,
34
-  WebViewError,
28
+import {
35 29
   WebViewErrorEvent,
36 30
   WebViewMessageEvent,
37 31
   WebViewNavigationEvent,
38
-  WebViewSharedProps,
39
-  WebViewSource,
40 32
   WebViewProgressEvent,
33
+  IOSWebViewProps,
34
+  DecelerationRateConstant,
35
+  NativeWebViewIOS,
36
+  ViewManager,
37
+  State,
38
+  CustomUIManager,
41 39
 } from './WebViewTypes';
42 40
 
41
+import styles from './WebView.styles';
42
+
43
+const UIManager = NotTypedUIManager as CustomUIManager;
44
+
43 45
 const resolveAssetSource = Image.resolveAssetSource;
44 46
 let didWarnAboutUIWebViewUsage = false;
45 47
 // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
46
-function processDecelerationRate(decelerationRate) {
48
+const processDecelerationRate = (
49
+  decelerationRate: DecelerationRateConstant | number | undefined,
50
+) => {
47 51
   if (decelerationRate === 'normal') {
48 52
     decelerationRate = 0.998;
49 53
   } else if (decelerationRate === 'fast') {
50 54
     decelerationRate = 0.99;
51 55
   }
52 56
   return decelerationRate;
53
-}
57
+};
54 58
 
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
-];
59
+const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager as ViewManager;
60
+const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager as ViewManager;
93 61
 
94 62
 const defaultRenderLoading = () => (
95 63
   <View style={styles.loadingView}>
96 64
     <ActivityIndicator />
97 65
   </View>
98 66
 );
99
-const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
67
+const defaultRenderError = (
68
+  errorDomain: string | undefined,
69
+  errorCode: number,
70
+  errorDesc: string,
71
+) => (
100 72
   <View style={styles.errorContainer}>
101 73
     <Text style={styles.errorTextTitle}>Error loading page</Text>
102 74
     <Text style={styles.errorText}>{'Domain: ' + errorDomain}</Text>
@@ -105,32 +77,7 @@ const defaultRenderError = (errorDomain, errorCode, errorDesc) => (
105 77
   </View>
106 78
 );
107 79
 
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
-
80
+class WebView extends React.Component<IOSWebViewProps, State> {
134 81
   static defaultProps = {
135 82
     useWebKit: true,
136 83
     cacheEnabled: true,
@@ -143,14 +90,12 @@ class WebView extends React.Component<WebViewSharedProps, State> {
143 90
     return true;
144 91
   };
145 92
 
146
-  state = {
147
-    viewState: this.props.startInLoadingState
148
-      ? WebViewState.LOADING
149
-      : WebViewState.IDLE,
93
+  state: State = {
94
+    viewState: this.props.startInLoadingState ? 'LOADING' : 'IDLE',
150 95
     lastErrorEvent: null,
151 96
   };
152 97
 
153
-  webViewRef = React.createRef();
98
+  webViewRef = React.createRef<NativeWebViewIOS>();
154 99
 
155 100
   UNSAFE_componentWillMount() {
156 101
     if (!this.props.useWebKit && !didWarnAboutUIWebViewUsage) {
@@ -185,108 +130,80 @@ class WebView extends React.Component<WebViewSharedProps, State> {
185 130
   }
186 131
 
187 132
   render() {
188
-    let otherView = null;
189
-
190
-    let scalesPageToFit;
133
+    const {
134
+      decelerationRate: decelerationRateProp,
135
+      nativeConfig = {},
136
+      onMessage,
137
+      onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp,
138
+      originWhitelist,
139
+      renderError,
140
+      renderLoading,
141
+      scalesPageToFit = this.props.useWebKit ? undefined : true,
142
+      style,
143
+      useWebKit,
144
+      ...otherProps
145
+    } = this.props;
191 146
 
192
-    if (this.props.useWebKit) {
193
-      ({ scalesPageToFit } = this.props);
194
-    } else {
195
-      ({ scalesPageToFit = true } = this.props);
196
-    }
147
+    let otherView = null;
197 148
 
198
-    if (this.state.viewState === WebViewState.LOADING) {
199
-      otherView = (this.props.renderLoading || defaultRenderLoading)();
200
-    } else if (this.state.viewState === WebViewState.ERROR) {
149
+    if (this.state.viewState === 'LOADING') {
150
+      otherView = (renderLoading || defaultRenderLoading)();
151
+    } else if (this.state.viewState === 'ERROR') {
201 152
       const errorEvent = this.state.lastErrorEvent;
202 153
       invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
203
-      otherView = (this.props.renderError || defaultRenderError)(
154
+      otherView = (renderError || defaultRenderError)(
204 155
         errorEvent.domain,
205 156
         errorEvent.code,
206 157
         errorEvent.description,
207 158
       );
208
-    } else if (this.state.viewState !== WebViewState.IDLE) {
159
+    } else if (this.state.viewState !== 'IDLE') {
209 160
       console.error(
210 161
         'RNCWebView invalid state encountered: ' + this.state.viewState,
211 162
       );
212 163
     }
213 164
 
214
-    const webViewStyles = [styles.container, styles.webView, this.props.style];
165
+    const webViewStyles = [styles.container, styles.webView, style];
215 166
     if (
216
-      this.state.viewState === WebViewState.LOADING ||
217
-      this.state.viewState === WebViewState.ERROR
167
+      this.state.viewState === 'LOADING' ||
168
+      this.state.viewState === 'ERROR'
218 169
     ) {
219 170
       // if we're in either LOADING or ERROR states, don't show the webView
220 171
       webViewStyles.push(styles.hidden);
221 172
     }
222 173
 
223
-    const nativeConfig = this.props.nativeConfig || {};
224
-
225 174
     const onShouldStartLoadWithRequest = createOnShouldStartLoadWithRequest(
226 175
       this.onShouldStartLoadWithRequestCallback,
227
-      this.props.originWhitelist,
228
-      this.props.onShouldStartLoadWithRequest,
176
+      originWhitelist,
177
+      onShouldStartLoadWithRequestProp,
229 178
     );
230 179
 
231
-    const decelerationRate = processDecelerationRate(
232
-      this.props.decelerationRate,
233
-    );
180
+    const decelerationRate = processDecelerationRate(decelerationRateProp);
234 181
 
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;
182
+    let NativeWebView = nativeConfig.component as typeof NativeWebViewIOS;
243 183
 
244
-    if (this.props.useWebKit) {
245
-      NativeWebView = NativeWebView || RNCWKWebView;
184
+    if (useWebKit) {
185
+      NativeWebView = NativeWebViewIOS || RNCWKWebView;
246 186
     } else {
247
-      NativeWebView = NativeWebView || RNCUIWebView;
187
+      NativeWebView = NativeWebViewIOS || RNCUIWebView;
248 188
     }
249 189
 
250 190
     const webView = (
251 191
       <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}
192
+        {...otherProps}
261 193
         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}
194
+        key="webViewKey"
195
+        messagingEnabled={typeof onMessage === 'function'}
274 196
         onLoadingError={this._onLoadingError}
197
+        onLoadingFinish={this._onLoadingFinish}
275 198
         onLoadingProgress={this._onLoadingProgress}
199
+        onLoadingStart={this._onLoadingStart}
276 200
         onMessage={this._onMessage}
277
-        messagingEnabled={typeof this.props.onMessage === 'function'}
278 201
         onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
202
+        ref={this.webViewRef}
279 203
         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}
204
+        // TODO: find a better way to type this.
205
+        source={resolveAssetSource(this.props.source as ImageSourcePropType)}
206
+        style={webViewStyles}
290 207
         {...nativeConfig.props}
291 208
       />
292 209
     );
@@ -299,17 +216,10 @@ class WebView extends React.Component<WebViewSharedProps, State> {
299 216
     );
300 217
   }
301 218
 
302
-  _getViewManagerConfig = (viewManagerName: string) => {
303
-    if (!UIManager.getViewManagerConfig) {
304
-      return UIManager[viewManagerName];
305
-    }
306
-    return UIManager.getViewManagerConfig(viewManagerName);
307
-  };
308
-
309 219
   _getCommands = () =>
310 220
     !this.props.useWebKit
311
-      ? this._getViewManagerConfig('RNCUIWebView').Commands
312
-      : this._getViewManagerConfig('RNCWKWebView').Commands;
221
+      ? getViewManagerConfig('RNCUIWebView').Commands
222
+      : getViewManagerConfig('RNCWKWebView').Commands;
313 223
 
314 224
   /**
315 225
    * Go forward one page in the web view's history.
@@ -337,7 +247,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
337 247
    * Reloads the current page.
338 248
    */
339 249
   reload = () => {
340
-    this.setState({ viewState: WebViewState.LOADING });
250
+    this.setState({ viewState: 'LOADING' });
341 251
     UIManager.dispatchViewManagerCommand(
342 252
       this.getWebViewHandle(),
343 253
       this._getCommands().reload,
@@ -402,7 +312,9 @@ class WebView extends React.Component<WebViewSharedProps, State> {
402 312
    * Returns the native `WebView` node.
403 313
    */
404 314
   getWebViewHandle = () => {
405
-    return findNodeHandle(this.webViewRef.current);
315
+    const nodeHandle = findNodeHandle(this.webViewRef.current);
316
+    invariant(nodeHandle != null, 'nodeHandle expected to be non-null');
317
+    return nodeHandle as number;
406 318
   };
407 319
 
408 320
   _onLoadingStart = (event: WebViewNavigationEvent) => {
@@ -420,7 +332,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
420 332
 
421 333
     this.setState({
422 334
       lastErrorEvent: event.nativeEvent,
423
-      viewState: WebViewState.ERROR,
335
+      viewState: 'ERROR',
424 336
     });
425 337
   };
426 338
 
@@ -429,7 +341,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
429 341
     onLoad && onLoad(event);
430 342
     onLoadEnd && onLoadEnd(event);
431 343
     this.setState({
432
-      viewState: WebViewState.IDLE,
344
+      viewState: 'IDLE',
433 345
     });
434 346
     this._updateNavigationState(event);
435 347
   };
@@ -460,7 +372,7 @@ class WebView extends React.Component<WebViewSharedProps, State> {
460 372
     viewManager.startLoadWithResult(!!shouldStart, lockIdentifier);
461 373
   };
462 374
 
463
-  componentDidUpdate(prevProps: WebViewSharedProps) {
375
+  componentDidUpdate(prevProps: IOSWebViewProps) {
464 376
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
465 377
       return;
466 378
     }
@@ -477,7 +389,10 @@ class WebView extends React.Component<WebViewSharedProps, State> {
477 389
     }
478 390
   }
479 391
 
480
-  _showRedboxOnPropChanges(prevProps, propName: string) {
392
+  _showRedboxOnPropChanges(
393
+    prevProps: IOSWebViewProps,
394
+    propName: keyof IOSWebViewProps,
395
+  ) {
481 396
     if (this.props[propName] !== prevProps[propName]) {
482 397
       console.error(
483 398
         `Changes to property ${propName} do nothing after the initial render.`,
@@ -486,43 +401,11 @@ class WebView extends React.Component<WebViewSharedProps, State> {
486 401
   }
487 402
 }
488 403
 
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
-});
404
+const RNCUIWebView: typeof NativeWebViewIOS = requireNativeComponent(
405
+  'RNCUIWebView',
406
+);
407
+const RNCWKWebView: typeof NativeWebViewIOS = requireNativeComponent(
408
+  'RNCWKWebView',
409
+);
527 410
 
528 411
 module.exports = 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;

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

@@ -9,13 +9,15 @@
9 9
  */
10 10
 
11 11
 import escapeStringRegexp from 'escape-string-regexp';
12
-import { Linking } from 'react-native';
13
-import type {
12
+import { Linking, UIManager as NotTypedUIManager } from 'react-native';
13
+import {
14 14
   WebViewNavigationEvent,
15
-  WebViewNavigation,
16 15
   OnShouldStartLoadWithRequest,
16
+  CustomUIManager,
17 17
 } from './WebViewTypes';
18 18
 
19
+const UIManager = NotTypedUIManager as CustomUIManager;
20
+
19 21
 const defaultOriginWhitelist = ['http://*', 'https://*'];
20 22
 
21 23
 const extractOrigin = (url: string): string => {
@@ -24,16 +26,14 @@ const extractOrigin = (url: string): string => {
24 26
 };
25 27
 
26 28
 const originWhitelistToRegex = (originWhitelist: string): string =>
27
-    `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
29
+  `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
28 30
 
29
-const passesWhitelist = (compiledWhitelist: Array<string>, url: string) => {
31
+const passesWhitelist = (compiledWhitelist: string[], url: string) => {
30 32
   const origin = extractOrigin(url);
31 33
   return compiledWhitelist.some(x => new RegExp(x).test(origin));
32 34
 };
33 35
 
34
-const compileWhitelist = (
35
-  originWhitelist: ?$ReadOnlyArray<string>,
36
-): Array<string> =>
36
+const compileWhitelist = (originWhitelist: string[]): string[] =>
37 37
   ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
38 38
 
39 39
 const createOnShouldStartLoadWithRequest = (
@@ -42,8 +42,8 @@ const createOnShouldStartLoadWithRequest = (
42 42
     url: string,
43 43
     lockIdentifier: number,
44 44
   ) => void,
45
-  originWhitelist: ?$ReadOnlyArray<string>,
46
-  onShouldStartLoadWithRequest: ?OnShouldStartLoadWithRequest,
45
+  originWhitelist: string[],
46
+  onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest,
47 47
 ) => {
48 48
   return ({ nativeEvent }: WebViewNavigationEvent) => {
49 49
     let shouldStart = true;
@@ -51,7 +51,7 @@ const createOnShouldStartLoadWithRequest = (
51 51
 
52 52
     if (!passesWhitelist(compileWhitelist(originWhitelist), url)) {
53 53
       Linking.openURL(url);
54
-      shouldStart = false
54
+      shouldStart = false;
55 55
     }
56 56
 
57 57
     if (onShouldStartLoadWithRequest) {
@@ -62,4 +62,17 @@ const createOnShouldStartLoadWithRequest = (
62 62
   };
63 63
 };
64 64
 
65
-export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest };
65
+const getViewManagerConfig = (
66
+  viewManagerName: 'RNCUIWebView' | 'RNCWKWebView' | 'RNCWebView',
67
+) => {
68
+  if (!UIManager.getViewManagerConfig) {
69
+    return UIManager[viewManagerName];
70
+  }
71
+  return UIManager.getViewManagerConfig(viewManagerName);
72
+};
73
+
74
+export {
75
+  defaultOriginWhitelist,
76
+  createOnShouldStartLoadWithRequest,
77
+  getViewManagerConfig,
78
+};

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


+ 628
- 0
src/WebViewTypes.ts View File

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

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


+ 20
- 0
tsconfig.json View File

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

+ 22
- 7
yarn.lock View File

@@ -786,6 +786,11 @@
786 786
     into-stream "^4.0.0"
787 787
     lodash "^4.17.4"
788 788
 
789
+"@types/escape-string-regexp@^1.0.0":
790
+  version "1.0.0"
791
+  resolved "https://registry.yarnpkg.com/@types/escape-string-regexp/-/escape-string-regexp-1.0.0.tgz#052d16d87db583b72daceae4eaabddb66954424c"
792
+  integrity sha512-KAruqgk9/340M4MYYasdBET+lyYN8KMXUuRKWO72f4SbmIMMFp9nnJiXUkJS0HC2SFe4x0R/fLozXIzqoUfSjA==
793
+
789 794
 "@types/events@*":
790 795
   version "3.0.0"
791 796
   resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
@@ -800,6 +805,11 @@
800 805
     "@types/minimatch" "*"
801 806
     "@types/node" "*"
802 807
 
808
+"@types/invariant@^2.2.29":
809
+  version "2.2.29"
810
+  resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.29.tgz#aa845204cd0a289f65d47e0de63a6a815e30cc66"
811
+  integrity sha512-lRVw09gOvgviOfeUrKc/pmTiRZ7g7oDOU6OAutyuSHpm1/o2RaBQvRhgK8QEdu+FFuw/wnWb29A/iuxv9i8OpQ==
812
+
803 813
 "@types/minimatch@*":
804 814
   version "3.0.3"
805 815
   resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@@ -815,10 +825,10 @@
815 825
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.0.tgz#4c48fed958d6dcf9487195a0ef6456d5f6e0163a"
816 826
   integrity sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg==
817 827
 
818
-"@types/react-native@^0.57.8":
819
-  version "0.57.38"
820
-  resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.38.tgz#2ff6ed1a7cc207afbfd87bf496513d96931d1446"
821
-  integrity sha512-bmY2ad/vQgP0HMT7Q7EQzirDBt5ibp+kBHclTnY7/i5MrdqE1oY+3b9NkDg3ohXlumr7p5stAG6I55nhfeUV6Q==
828
+"@types/react-native@0.57.40":
829
+  version "0.57.40"
830
+  resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.40.tgz#a227acb6b2c7372cb678202df4cfe716ace9ce94"
831
+  integrity sha512-nCcF9gNYp/VeV5QBtHbn/VnXZG+T8EsMxZFx8qqZfBe1gxJUsldXgOXYd1kcrrYzUX0LqG/KipDBX++fB2qQ0g==
822 832
   dependencies:
823 833
     "@types/prop-types" "*"
824 834
     "@types/react" "*"
@@ -2468,7 +2478,7 @@ escape-html@~1.0.3:
2468 2478
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
2469 2479
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
2470 2480
 
2471
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
2481
+escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
2472 2482
   version "1.0.5"
2473 2483
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
2474 2484
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@@ -2741,7 +2751,7 @@ fbjs-scripts@^1.0.0:
2741 2751
     semver "^5.1.0"
2742 2752
     through2 "^2.0.0"
2743 2753
 
2744
-fbjs@^0.8.17, fbjs@^0.8.9:
2754
+fbjs@^0.8.9:
2745 2755
   version "0.8.17"
2746 2756
   resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
2747 2757
   integrity sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=
@@ -3511,7 +3521,7 @@ into-stream@^4.0.0:
3511 3521
     from2 "^2.1.1"
3512 3522
     p-is-promise "^2.0.0"
3513 3523
 
3514
-invariant@^2.2.4:
3524
+invariant@2.2.4, invariant@^2.2.4:
3515 3525
   version "2.2.4"
3516 3526
   resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
3517 3527
   integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
@@ -7999,6 +8009,11 @@ typedarray@^0.0.6:
7999 8009
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
8000 8010
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
8001 8011
 
8012
+typescript@^3.3.3333:
8013
+  version "3.3.3333"
8014
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
8015
+  integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==
8016
+
8002 8017
 ua-parser-js@^0.7.18:
8003 8018
   version "0.7.19"
8004 8019
   resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"