Thibault Malbranche 6 years ago
parent
commit
322a264d59
15 changed files with 907 additions and 797 deletions
  1. 3
    3
      .eslintrc.js
  2. 0
    470
      js/WebViewTypes.js
  3. 3
    1
      package.json
  4. 134
    129
      src/WebView.android.tsx
  5. 182
    167
      src/WebView.ios.tsx
  6. 0
    2
      src/index.ts
  7. 0
    4
      src/test.ts
  8. 0
    12
      src/test.tsx
  9. 0
    4
      src/utils.ts
  10. 5
    3
      tsconfig.json
  11. 54
    0
      types/WebView.android.d.ts
  12. 114
    0
      types/WebView.ios.d.ts
  13. 6
    0
      types/WebViewShared.d.ts
  14. 358
    0
      types/types/WebViewTypes.d.ts
  15. 48
    2
      yarn.lock

+ 3
- 3
.eslintrc.js View File

@@ -1,8 +1,8 @@
1 1
 module.exports = {
2 2
   // Airbnb is the base, prettier is here so that eslint doesn't conflict with prettier
3
-  extends: ['airbnb-base', 'prettier', 'prettier/react'],
3
+  extends: ['airbnb', 'prettier', 'prettier/react'],
4 4
   parser: 'typescript-eslint-parser',
5
-  plugins: ['react', 'react-native', 'typescript'],
5
+  plugins: ['react-native', 'typescript'],
6 6
   rules: {
7 7
     // Parens will be needed for arrow functions
8 8
     'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }],
@@ -42,7 +42,7 @@ module.exports = {
42 42
     {
43 43
       files: ['*.ts?(x)'],
44 44
       parser: 'typescript-eslint-parser',
45
-      plugins: ['react', 'react-native', 'typescript'],
45
+      plugins: ['react-native', 'typescript'],
46 46
     },
47 47
   ],
48 48
   settings: {

+ 0
- 470
js/WebViewTypes.js View File

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

+ 3
- 1
package.json View File

@@ -32,9 +32,11 @@
32 32
     "@types/react": "16.7.7",
33 33
     "@types/react-native": "^0.57.6",
34 34
     "eslint": "5.9.0",
35
+    "eslint-config-airbnb": "17.1.0",
35 36
     "eslint-config-airbnb-base": "13.1.0",
36 37
     "eslint-config-prettier": "3.3.0",
37 38
     "eslint-plugin-import": "2.14.0",
39
+    "eslint-plugin-jsx-a11y": "6.1.2",
38 40
     "eslint-plugin-react": "7.11.1",
39 41
     "eslint-plugin-react-native": "3.5.0",
40 42
     "eslint-plugin-typescript": "0.14.0",
@@ -49,4 +51,4 @@
49 51
     "type": "git",
50 52
     "url": "https://github.com/react-native-community/react-native-webview.git"
51 53
   }
52
-}
54
+}

+ 134
- 129
src/WebView.android.tsx View File

@@ -25,7 +25,24 @@ import {
25 25
   WebViewSource,
26 26
   WebViewProgressEvent,
27 27
 } from './types/WebViewTypes';
28
-import { isWebViewUriSource } from './utils';
28
+
29
+const styles = StyleSheet.create({
30
+  container: {
31
+    flex: 1,
32
+  },
33
+  hidden: {
34
+    height: 0,
35
+    flex: 0, // disable 'flex:1' when hiding a View
36
+  },
37
+  loadingView: {
38
+    flex: 1,
39
+    justifyContent: 'center',
40
+    alignItems: 'center',
41
+  },
42
+  loadingProgressBar: {
43
+    height: 20,
44
+  },
45
+});
29 46
 
30 47
 enum WebViewState {
31 48
   IDLE = 'IDLE',
@@ -33,6 +50,9 @@ enum WebViewState {
33 50
   ERROR = 'ERROR',
34 51
 }
35 52
 
53
+const isWebViewUriSource = (source: any): source is WebViewSourceUri =>
54
+  typeof source !== 'number' && !('html' in source);
55
+
36 56
 const defaultRenderLoading = (): React.ReactNode => (
37 57
   <View style={styles.loadingView}>
38 58
     <ActivityIndicator style={styles.loadingProgressBar} />
@@ -44,6 +64,8 @@ type State = {
44 64
   lastErrorEvent: WebViewError | null;
45 65
 };
46 66
 
67
+const RNCWebView = requireNativeComponent('RNCWebView');
68
+
47 69
 /**
48 70
  * Renders a native WebView.
49 71
  */
@@ -74,6 +96,117 @@ export default class WebView extends React.Component<
74 96
 
75 97
   webViewRef = React.createRef<React.ComponentClass>();
76 98
 
99
+  goForward = (): void => {
100
+    UIManager.dispatchViewManagerCommand(
101
+      this.getWebViewHandle(),
102
+      UIManager.RNCWebView.Commands.goForward,
103
+      null,
104
+    );
105
+  };
106
+
107
+  goBack = (): void => {
108
+    UIManager.dispatchViewManagerCommand(
109
+      this.getWebViewHandle(),
110
+      UIManager.RNCWebView.Commands.goBack,
111
+      null,
112
+    );
113
+  };
114
+
115
+  reload = (): void => {
116
+    this.setState({
117
+      viewState: WebViewState.LOADING,
118
+    });
119
+    UIManager.dispatchViewManagerCommand(
120
+      this.getWebViewHandle(),
121
+      UIManager.RNCWebView.Commands.reload,
122
+      null,
123
+    );
124
+  };
125
+
126
+  stopLoading = (): void => {
127
+    UIManager.dispatchViewManagerCommand(
128
+      this.getWebViewHandle(),
129
+      UIManager.RNCWebView.Commands.stopLoading,
130
+      null,
131
+    );
132
+  };
133
+
134
+  postMessage = (data: string): void => {
135
+    UIManager.dispatchViewManagerCommand(
136
+      this.getWebViewHandle(),
137
+      UIManager.RNCWebView.Commands.postMessage,
138
+      [String(data)],
139
+    );
140
+  };
141
+
142
+  /**
143
+   * Injects a javascript string into the referenced WebView. Deliberately does not
144
+   * return a response because using eval() to return a response breaks this method
145
+   * on pages with a Content Security Policy that disallows eval(). If you need that
146
+   * functionality, look into postMessage/onMessage.
147
+   */
148
+  injectJavaScript = (data: string): void => {
149
+    UIManager.dispatchViewManagerCommand(
150
+      this.getWebViewHandle(),
151
+      UIManager.RNCWebView.Commands.injectJavaScript,
152
+      [data],
153
+    );
154
+  };
155
+
156
+  /**
157
+   * We return an event with a bunch of fields including:
158
+   *  url, title, loading, canGoBack, canGoForward
159
+   */
160
+  updateNavigationState = (event: WebViewNavigationEvent): void => {
161
+    if (this.props.onNavigationStateChange) {
162
+      this.props.onNavigationStateChange(event.nativeEvent);
163
+    }
164
+  };
165
+
166
+  getWebViewHandle = (): number | null =>
167
+    findNodeHandle(this.webViewRef.current);
168
+
169
+  onLoadingStart = (event: WebViewNavigationEvent): void => {
170
+    const { onLoadStart } = this.props;
171
+    onLoadStart && onLoadStart(event);
172
+    this.updateNavigationState(event);
173
+  };
174
+
175
+  onLoadingError = (event: WebViewErrorEvent): void => {
176
+    event.persist(); // persist this event because we need to store it
177
+    const { onError, onLoadEnd } = this.props;
178
+    onError && onError(event);
179
+    onLoadEnd && onLoadEnd(event);
180
+    console.warn('Encountered an error loading page', event.nativeEvent);
181
+
182
+    this.setState({
183
+      lastErrorEvent: event.nativeEvent,
184
+      viewState: WebViewState.ERROR,
185
+    });
186
+  };
187
+
188
+  onLoadingFinish = (event: WebViewNavigationEvent): void => {
189
+    const { onLoad, onLoadEnd } = this.props;
190
+    onLoad && onLoad(event);
191
+    onLoadEnd && onLoadEnd(event);
192
+    this.setState({
193
+      viewState: WebViewState.IDLE,
194
+    });
195
+    this.updateNavigationState(event);
196
+  };
197
+
198
+  onMessage = (event: WebViewMessageEvent): void => {
199
+    const { onMessage } = this.props;
200
+    onMessage && onMessage(event);
201
+  };
202
+
203
+  onLoadingProgress = (
204
+    event: NativeSyntheticEvent<WebViewProgressEvent>,
205
+  ): void => {
206
+    const { onLoadProgress } = this.props;
207
+    onLoadProgress && onLoadProgress(event);
208
+  };
209
+
77 210
   render(): React.ReactNode {
78 211
     let otherView = null;
79 212
 
@@ -180,132 +313,4 @@ export default class WebView extends React.Component<
180 313
       </View>
181 314
     );
182 315
   }
183
-
184
-  goForward = () => {
185
-    UIManager.dispatchViewManagerCommand(
186
-      this.getWebViewHandle(),
187
-      UIManager.RNCWebView.Commands.goForward,
188
-      null,
189
-    );
190
-  };
191
-
192
-  goBack = () => {
193
-    UIManager.dispatchViewManagerCommand(
194
-      this.getWebViewHandle(),
195
-      UIManager.RNCWebView.Commands.goBack,
196
-      null,
197
-    );
198
-  };
199
-
200
-  reload = () => {
201
-    this.setState({
202
-      viewState: WebViewState.LOADING,
203
-    });
204
-    UIManager.dispatchViewManagerCommand(
205
-      this.getWebViewHandle(),
206
-      UIManager.RNCWebView.Commands.reload,
207
-      null,
208
-    );
209
-  };
210
-
211
-  stopLoading = () => {
212
-    UIManager.dispatchViewManagerCommand(
213
-      this.getWebViewHandle(),
214
-      UIManager.RNCWebView.Commands.stopLoading,
215
-      null,
216
-    );
217
-  };
218
-
219
-  postMessage = (data: string) => {
220
-    UIManager.dispatchViewManagerCommand(
221
-      this.getWebViewHandle(),
222
-      UIManager.RNCWebView.Commands.postMessage,
223
-      [String(data)],
224
-    );
225
-  };
226
-
227
-  /**
228
-   * Injects a javascript string into the referenced WebView. Deliberately does not
229
-   * return a response because using eval() to return a response breaks this method
230
-   * on pages with a Content Security Policy that disallows eval(). If you need that
231
-   * functionality, look into postMessage/onMessage.
232
-   */
233
-  injectJavaScript = (data: string) => {
234
-    UIManager.dispatchViewManagerCommand(
235
-      this.getWebViewHandle(),
236
-      UIManager.RNCWebView.Commands.injectJavaScript,
237
-      [data],
238
-    );
239
-  };
240
-
241
-  /**
242
-   * We return an event with a bunch of fields including:
243
-   *  url, title, loading, canGoBack, canGoForward
244
-   */
245
-  updateNavigationState = (event: WebViewNavigationEvent) => {
246
-    if (this.props.onNavigationStateChange) {
247
-      this.props.onNavigationStateChange(event.nativeEvent);
248
-    }
249
-  };
250
-
251
-  getWebViewHandle = () => findNodeHandle(this.webViewRef.current);
252
-
253
-  onLoadingStart = (event: WebViewNavigationEvent) => {
254
-    const onLoadStart = this.props.onLoadStart;
255
-    onLoadStart && onLoadStart(event);
256
-    this.updateNavigationState(event);
257
-  };
258
-
259
-  onLoadingError = (event: WebViewErrorEvent) => {
260
-    event.persist(); // persist this event because we need to store it
261
-    const { onError, onLoadEnd } = this.props;
262
-    onError && onError(event);
263
-    onLoadEnd && onLoadEnd(event);
264
-    console.warn('Encountered an error loading page', event.nativeEvent);
265
-
266
-    this.setState({
267
-      lastErrorEvent: event.nativeEvent,
268
-      viewState: WebViewState.ERROR,
269
-    });
270
-  };
271
-
272
-  onLoadingFinish = (event: WebViewNavigationEvent) => {
273
-    const { onLoad, onLoadEnd } = this.props;
274
-    onLoad && onLoad(event);
275
-    onLoadEnd && onLoadEnd(event);
276
-    this.setState({
277
-      viewState: WebViewState.IDLE,
278
-    });
279
-    this.updateNavigationState(event);
280
-  };
281
-
282
-  onMessage = (event: WebViewMessageEvent) => {
283
-    const { onMessage } = this.props;
284
-    onMessage && onMessage(event);
285
-  };
286
-
287
-  onLoadingProgress = (event: NativeSyntheticEvent<WebViewProgressEvent>) => {
288
-    const { onLoadProgress } = this.props;
289
-    onLoadProgress && onLoadProgress(event);
290
-  };
291 316
 }
292
-
293
-const RNCWebView = requireNativeComponent('RNCWebView');
294
-
295
-const styles = StyleSheet.create({
296
-  container: {
297
-    flex: 1,
298
-  },
299
-  hidden: {
300
-    height: 0,
301
-    flex: 0, // disable 'flex:1' when hiding a View
302
-  },
303
-  loadingView: {
304
-    flex: 1,
305
-    justifyContent: 'center',
306
-    alignItems: 'center',
307
-  },
308
-  loadingProgressBar: {
309
-    height: 20,
310
-  },
311
-});

+ 182
- 167
src/WebView.ios.tsx View File

@@ -31,17 +31,19 @@ import {
31 31
 type DecelerationRate = number | 'normal' | 'fast';
32 32
 
33 33
 // Imported from https://github.com/facebook/react-native/blob/master/Libraries/Components/ScrollView/processDecelerationRate.js
34
-function processDecelerationRate(decelerationRate?: DecelerationRate) {
34
+function processDecelerationRate(
35
+  decelerationRate?: DecelerationRate,
36
+): number | undefined {
35 37
   if (decelerationRate === 'normal') {
36
-    decelerationRate = 0.998;
37
-  } else if (decelerationRate === 'fast') {
38
-    decelerationRate = 0.99;
38
+    return 0.998;
39
+  }
40
+  if (decelerationRate === 'fast') {
41
+    return 0.99;
39 42
   }
40 43
   return decelerationRate;
41 44
 }
42 45
 
43
-const RNCUIWebViewManager = NativeModules.RNCUIWebViewManager;
44
-const RNCWKWebViewManager = NativeModules.RNCWKWebViewManager;
46
+const { RNCWKWebViewManager, RNCUIWebViewManager } = NativeModules;
45 47
 
46 48
 const BGWASH = 'rgba(255,255,255,0.8)';
47 49
 
@@ -67,7 +69,7 @@ type State = {
67 69
   lastErrorEvent: WebViewError | null;
68 70
 };
69 71
 
70
-const defaultRenderLoading = () => (
72
+const defaultRenderLoading = (): React.ReactNode => (
71 73
   <View style={styles.loadingView}>
72 74
     <ActivityIndicator />
73 75
   </View>
@@ -76,7 +78,7 @@ const defaultRenderError = (
76 78
   errorDomain: string | undefined,
77 79
   errorCode: number,
78 80
   errorDesc: string,
79
-) => (
81
+): React.ReactNode => (
80 82
   <View style={styles.errorContainer}>
81 83
     <Text style={styles.errorTextTitle}>Error loading page</Text>
82 84
     <Text style={styles.errorText}>{`Domain: ${errorDomain}`}</Text>
@@ -120,7 +122,7 @@ export default class WebView extends React.Component<
120 122
     originWhitelist: WebViewShared.defaultOriginWhitelist,
121 123
   };
122 124
 
123
-  static isFileUploadSupported = async () =>
125
+  static isFileUploadSupported = async (): Promise<boolean> =>
124 126
     // no native implementation for iOS, depends only on permissions
125 127
     true;
126 128
 
@@ -152,149 +154,14 @@ export default class WebView extends React.Component<
152 154
     }
153 155
   }
154 156
 
155
-  render(): React.ReactNode {
156
-    let otherView = null;
157
-
158
-    let scalesPageToFit;
159
-
160
-    if (this.props.useWebKit) {
161
-      ({ scalesPageToFit } = this.props);
162
-    } else {
163
-      ({ scalesPageToFit = true } = this.props);
164
-    }
165
-
166
-    if (this.state.viewState === WebViewState.LOADING) {
167
-      otherView = (this.props.renderLoading || defaultRenderLoading)();
168
-    } else if (this.state.viewState === WebViewState.ERROR) {
169
-      const errorEvent = this.state.lastErrorEvent;
170
-      invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
171
-      otherView = (this.props.renderError || defaultRenderError)(
172
-        errorEvent!.domain,
173
-        errorEvent!.code,
174
-        errorEvent!.description,
175
-      );
176
-    } else if (this.state.viewState !== WebViewState.IDLE) {
177
-      console.error(
178
-        `RNCWebView invalid state encountered: ${this.state.viewState}`,
179
-      );
180
-    }
181
-
182
-    const webViewStyles = [styles.container, styles.webView, this.props.style];
183
-    if (
184
-      this.state.viewState === WebViewState.LOADING
185
-      || this.state.viewState === WebViewState.ERROR
186
-    ) {
187
-      // if we're in either LOADING or ERROR states, don't show the webView
188
-      webViewStyles.push(styles.hidden);
189
-    }
190
-
191
-    const nativeConfig = this.props.nativeConfig || {};
192
-
193
-    let viewManager = nativeConfig.viewManager;
194
-
195
-    if (this.props.useWebKit) {
196
-      viewManager = viewManager || RNCWKWebViewManager;
197
-    } else {
198
-      viewManager = viewManager || RNCUIWebViewManager;
199
-    }
200
-
201
-    const compiledWhitelist = [
202
-      'about:blank',
203
-      ...(this.props.originWhitelist || []),
204
-    ].map(WebViewShared.originWhitelistToRegex);
205
-    const onShouldStartLoadWithRequest = (
206
-      event: NativeSyntheticEvent<WebViewIOSLoadRequestEvent>,
207
-    ) => {
208
-      let shouldStart = true;
209
-      const { url } = event.nativeEvent;
210
-      const origin = WebViewShared.extractOrigin(url);
211
-      const passesWhitelist = compiledWhitelist.some(x =>
212
-        new RegExp(x).test(origin),
213
-      );
214
-      shouldStart = shouldStart && passesWhitelist;
215
-      if (!passesWhitelist) {
216
-        Linking.openURL(url);
217
-      }
218
-      if (this.props.onShouldStartLoadWithRequest) {
219
-        shouldStart
220
-          = shouldStart
221
-          && this.props.onShouldStartLoadWithRequest(event.nativeEvent);
222
-      }
223
-      invariant(viewManager != null, 'viewManager expected to be non-null');
224
-      viewManager.startLoadWithResult(
225
-        !!shouldStart,
226
-        event.nativeEvent.lockIdentifier,
227
-      );
228
-    };
229
-
230
-    const decelerationRate = processDecelerationRate(
231
-      this.props.decelerationRate,
232
-    );
233
-
234
-    let source: WebViewSource = this.props.source || {};
235
-    if (!this.props.source && this.props.html) {
236
-      source = { html: this.props.html };
237
-    } else if (!this.props.source && this.props.url) {
238
-      source = { uri: this.props.url };
239
-    }
240
-
241
-    const messagingEnabled = typeof this.props.onMessage === 'function';
242
-
243
-    let NativeWebView = nativeConfig.component;
244
-
245
-    if (this.props.useWebKit) {
246
-      NativeWebView = NativeWebView || RNCWKWebView;
247
-    } else {
248
-      NativeWebView = NativeWebView || RNCUIWebView;
249
-    }
250
-
251
-    const webView = (
252
-      <NativeWebView
253
-        ref={this.webViewRef}
254
-        key="webViewKey"
255
-        style={webViewStyles}
256
-        source={Image.resolveAssetSource(source as WebViewSourceUri)} // typing issue of not compatible of WebViewSourceHtml in react native.
257
-        injectedJavaScript={this.props.injectedJavaScript}
258
-        bounces={this.props.bounces}
259
-        scrollEnabled={this.props.scrollEnabled}
260
-        pagingEnabled={this.props.pagingEnabled}
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
-        userAgent={this.props.userAgent}
271
-        onLoadingStart={this._onLoadingStart}
272
-        onLoadingFinish={this._onLoadingFinish}
273
-        onLoadingError={this._onLoadingError}
274
-        onLoadingProgress={this._onLoadingProgress}
275
-        messagingEnabled={messagingEnabled}
276
-        onMessage={this._onMessage}
277
-        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
278
-        scalesPageToFit={scalesPageToFit}
279
-        allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
280
-        mediaPlaybackRequiresUserAction={
281
-          this.props.mediaPlaybackRequiresUserAction
282
-        }
283
-        dataDetectorTypes={this.props.dataDetectorTypes}
284
-        allowsLinkPreview={this.props.allowsLinkPreview}
285
-        {...nativeConfig.props}
286
-      />
287
-    );
288
-
289
-    return (
290
-      <View style={styles.container}>
291
-        {webView}
292
-        {otherView}
293
-      </View>
294
-    );
295
-  }
296
-
297
-  _getCommands() {
157
+  _getCommands(): {
158
+    goForward: () => void,
159
+    goBack: () => void,
160
+    reload: () => void,
161
+    stopLoading: () => void,
162
+    postMessage: () => void,
163
+    injectJavaScript: () => void,
164
+  } {
298 165
     if (!this.props.useWebKit) {
299 166
       return UIManager.RNCUIWebView.Commands;
300 167
     }
@@ -305,7 +172,7 @@ export default class WebView extends React.Component<
305 172
   /**
306 173
    * Go forward one page in the web view's history.
307 174
    */
308
-  goForward = () => {
175
+  goForward = (): void => {
309 176
     UIManager.dispatchViewManagerCommand(
310 177
       this.getWebViewHandle(),
311 178
       this._getCommands().goForward,
@@ -316,7 +183,7 @@ export default class WebView extends React.Component<
316 183
   /**
317 184
    * Go back one page in the web view's history.
318 185
    */
319
-  goBack = () => {
186
+  goBack = (): void => {
320 187
     UIManager.dispatchViewManagerCommand(
321 188
       this.getWebViewHandle(),
322 189
       this._getCommands().goBack,
@@ -327,7 +194,7 @@ export default class WebView extends React.Component<
327 194
   /**
328 195
    * Reloads the current page.
329 196
    */
330
-  reload = () => {
197
+  reload = (): void => {
331 198
     this.setState({ viewState: WebViewState.LOADING });
332 199
     UIManager.dispatchViewManagerCommand(
333 200
       this.getWebViewHandle(),
@@ -339,7 +206,7 @@ export default class WebView extends React.Component<
339 206
   /**
340 207
    * Stop loading the current page.
341 208
    */
342
-  stopLoading = () => {
209
+  stopLoading = (): void => {
343 210
     UIManager.dispatchViewManagerCommand(
344 211
       this.getWebViewHandle(),
345 212
       this._getCommands().stopLoading,
@@ -357,7 +224,7 @@ export default class WebView extends React.Component<
357 224
    * document.addEventListener('message', e => { document.title = e.data; });
358 225
    * ```
359 226
    */
360
-  postMessage = (data: string) => {
227
+  postMessage = (data: string): void => {
361 228
     UIManager.dispatchViewManagerCommand(
362 229
       this.getWebViewHandle(),
363 230
       this._getCommands().postMessage,
@@ -371,7 +238,7 @@ export default class WebView extends React.Component<
371 238
    * on pages with a Content Security Policy that disallows eval(). If you need that
372 239
    * functionality, look into postMessage/onMessage.
373 240
    */
374
-  injectJavaScript = (data: string) => {
241
+  injectJavaScript = (data: string): void => {
375 242
     UIManager.dispatchViewManagerCommand(
376 243
       this.getWebViewHandle(),
377 244
       this._getCommands().injectJavaScript,
@@ -383,7 +250,7 @@ export default class WebView extends React.Component<
383 250
    * We return an event with a bunch of fields including:
384 251
    *  url, title, loading, canGoBack, canGoForward
385 252
    */
386
-  _updateNavigationState = (event: WebViewNavigationEvent) => {
253
+  _updateNavigationState = (event: WebViewNavigationEvent): void => {
387 254
     if (this.props.onNavigationStateChange) {
388 255
       this.props.onNavigationStateChange(event.nativeEvent);
389 256
     }
@@ -392,15 +259,16 @@ export default class WebView extends React.Component<
392 259
   /**
393 260
    * Returns the native `WebView` node.
394 261
    */
395
-  getWebViewHandle = () => findNodeHandle(this.webViewRef.current);
262
+  getWebViewHandle = (): number | null =>
263
+    findNodeHandle(this.webViewRef.current);
396 264
 
397
-  _onLoadingStart = (event: WebViewNavigationEvent) => {
265
+  _onLoadingStart = (event: WebViewNavigationEvent): void => {
398 266
     const onLoadStart = this.props.onLoadStart;
399 267
     onLoadStart && onLoadStart(event);
400 268
     this._updateNavigationState(event);
401 269
   };
402 270
 
403
-  _onLoadingError = (event: WebViewErrorEvent) => {
271
+  _onLoadingError = (event: WebViewErrorEvent): void => {
404 272
     event.persist(); // persist this event because we need to store it
405 273
     const { onError, onLoadEnd } = this.props;
406 274
     onError && onError(event);
@@ -413,7 +281,7 @@ export default class WebView extends React.Component<
413 281
     });
414 282
   };
415 283
 
416
-  _onLoadingFinish = (event: WebViewNavigationEvent) => {
284
+  _onLoadingFinish = (event: WebViewNavigationEvent): void => {
417 285
     const { onLoad, onLoadEnd } = this.props;
418 286
     onLoad && onLoad(event);
419 287
     onLoadEnd && onLoadEnd(event);
@@ -423,17 +291,19 @@ export default class WebView extends React.Component<
423 291
     this._updateNavigationState(event);
424 292
   };
425 293
 
426
-  _onMessage = (event: WebViewMessageEvent) => {
294
+  _onMessage = (event: WebViewMessageEvent): void => {
427 295
     const { onMessage } = this.props;
428 296
     onMessage && onMessage(event);
429 297
   };
430 298
 
431
-  _onLoadingProgress = (event: NativeSyntheticEvent<WebViewProgressEvent>) => {
299
+  _onLoadingProgress = (
300
+    event: NativeSyntheticEvent<WebViewProgressEvent>,
301
+  ): void => {
432 302
     const { onLoadProgress } = this.props;
433 303
     onLoadProgress && onLoadProgress(event);
434 304
   };
435 305
 
436
-  componentDidUpdate(prevProps: WebViewSharedProps) {
306
+  componentDidUpdate(prevProps: WebViewSharedProps): void {
437 307
     if (!(prevProps.useWebKit && this.props.useWebKit)) {
438 308
       return;
439 309
     }
@@ -455,13 +325,158 @@ export default class WebView extends React.Component<
455 325
       | 'allowsInlineMediaPlayback'
456 326
       | 'mediaPlaybackRequiresUserAction'
457 327
       | 'dataDetectorTypes',
458
-  ) {
328
+  ): void {
459 329
     if (this.props[propName] !== prevProps[propName]) {
460 330
       console.error(
461 331
         `Changes to property ${propName} do nothing after the initial render.`,
462 332
       );
463 333
     }
464 334
   }
335
+
336
+  render(): React.ReactNode {
337
+    let otherView = null;
338
+
339
+    let scalesPageToFit;
340
+
341
+    if (this.props.useWebKit) {
342
+      ({ scalesPageToFit } = this.props);
343
+    } else {
344
+      ({ scalesPageToFit = true } = this.props);
345
+    }
346
+
347
+    if (this.state.viewState === WebViewState.LOADING) {
348
+      otherView = (this.props.renderLoading || defaultRenderLoading)();
349
+    } else if (this.state.viewState === WebViewState.ERROR) {
350
+      const errorEvent = this.state.lastErrorEvent;
351
+      if (errorEvent) {
352
+        otherView = (this.props.renderError || defaultRenderError)(
353
+          errorEvent.domain,
354
+          errorEvent.code,
355
+          errorEvent.description,
356
+        );
357
+      } else {
358
+        invariant(errorEvent != null, 'lastErrorEvent expected to be non-null');
359
+      }
360
+    } else if (this.state.viewState !== WebViewState.IDLE) {
361
+      console.error(
362
+        `RNCWebView invalid state encountered: ${this.state.viewState}`,
363
+      );
364
+    }
365
+
366
+    const webViewStyles = [styles.container, styles.webView, this.props.style];
367
+    if (
368
+      this.state.viewState === WebViewState.LOADING
369
+      || this.state.viewState === WebViewState.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 nativeConfig = this.props.nativeConfig || {};
376
+
377
+    let { viewManager } = nativeConfig;
378
+
379
+    if (this.props.useWebKit) {
380
+      viewManager = viewManager || RNCWKWebViewManager;
381
+    } else {
382
+      viewManager = viewManager || RNCUIWebViewManager;
383
+    }
384
+
385
+    const compiledWhitelist = [
386
+      'about:blank',
387
+      ...(this.props.originWhitelist || []),
388
+    ].map(WebViewShared.originWhitelistToRegex);
389
+    const onShouldStartLoadWithRequest = (
390
+      event: NativeSyntheticEvent<WebViewIOSLoadRequestEvent>,
391
+    ): void => {
392
+      let shouldStart = true;
393
+      const { url } = event.nativeEvent;
394
+      const origin = WebViewShared.extractOrigin(url);
395
+      const passesWhitelist = compiledWhitelist.some(
396
+        (x): boolean => new RegExp(x).test(origin),
397
+      );
398
+      shouldStart = shouldStart && passesWhitelist;
399
+      if (!passesWhitelist) {
400
+        Linking.openURL(url);
401
+      }
402
+      if (this.props.onShouldStartLoadWithRequest) {
403
+        shouldStart
404
+          = shouldStart
405
+          && this.props.onShouldStartLoadWithRequest(event.nativeEvent);
406
+      }
407
+      invariant(viewManager != null, 'viewManager expected to be non-null');
408
+      viewManager.startLoadWithResult(
409
+        !!shouldStart,
410
+        event.nativeEvent.lockIdentifier,
411
+      );
412
+    };
413
+
414
+    const decelerationRate = processDecelerationRate(
415
+      this.props.decelerationRate,
416
+    );
417
+
418
+    let source: WebViewSource = this.props.source || {};
419
+    if (!this.props.source && this.props.html) {
420
+      source = { html: this.props.html };
421
+    } else if (!this.props.source && this.props.url) {
422
+      source = { uri: this.props.url };
423
+    }
424
+
425
+    const messagingEnabled = typeof this.props.onMessage === 'function';
426
+
427
+    let NativeWebView = nativeConfig.component;
428
+
429
+    if (this.props.useWebKit) {
430
+      NativeWebView = NativeWebView || RNCWKWebView;
431
+    } else {
432
+      NativeWebView = NativeWebView || RNCUIWebView;
433
+    }
434
+
435
+    const webView = (
436
+      <NativeWebView
437
+        ref={this.webViewRef}
438
+        key="webViewKey"
439
+        style={webViewStyles}
440
+        source={Image.resolveAssetSource(source as WebViewSourceUri)} // typing issue of not compatible of WebViewSourceHtml in react native.
441
+        injectedJavaScript={this.props.injectedJavaScript}
442
+        bounces={this.props.bounces}
443
+        scrollEnabled={this.props.scrollEnabled}
444
+        pagingEnabled={this.props.pagingEnabled}
445
+        decelerationRate={decelerationRate}
446
+        contentInset={this.props.contentInset}
447
+        automaticallyAdjustContentInsets={
448
+          this.props.automaticallyAdjustContentInsets
449
+        }
450
+        hideKeyboardAccessoryView={this.props.hideKeyboardAccessoryView}
451
+        allowsBackForwardNavigationGestures={
452
+          this.props.allowsBackForwardNavigationGestures
453
+        }
454
+        userAgent={this.props.userAgent}
455
+        onLoadingStart={this._onLoadingStart}
456
+        onLoadingFinish={this._onLoadingFinish}
457
+        onLoadingError={this._onLoadingError}
458
+        onLoadingProgress={this._onLoadingProgress}
459
+        messagingEnabled={messagingEnabled}
460
+        onMessage={this._onMessage}
461
+        onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
462
+        scalesPageToFit={scalesPageToFit}
463
+        allowsInlineMediaPlayback={this.props.allowsInlineMediaPlayback}
464
+        mediaPlaybackRequiresUserAction={
465
+          this.props.mediaPlaybackRequiresUserAction
466
+        }
467
+        dataDetectorTypes={this.props.dataDetectorTypes}
468
+        allowsLinkPreview={this.props.allowsLinkPreview}
469
+        {...nativeConfig.props}
470
+      />
471
+    );
472
+
473
+    return (
474
+      <View style={styles.container}>
475
+        {webView}
476
+        {otherView}
477
+      </View>
478
+    );
479
+  }
465 480
 }
466 481
 
467 482
 const RNCUIWebView = requireNativeComponent('RNCUIWebView');

+ 0
- 2
src/index.ts View File

@@ -1,2 +0,0 @@
1
-export * from './types/WebViewTypes';
2
-export * from './WebView.ios';

+ 0
- 4
src/test.ts View File

@@ -1,4 +0,0 @@
1
-const a
2
-  = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
3
-
4
-console.log(a);

+ 0
- 12
src/test.tsx View File

@@ -1,12 +0,0 @@
1
-import React from 'react';
2
-
3
-const Test: React.SFC<{
4
-  show: boolean;
5
-}> = ({ show }): React.ReactElement<string> => show && <div />;
6
-
7
-const a =
8
-  'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
9
-
10
-console.log(a);
11
-
12
-export default Test;

+ 0
- 4
src/utils.ts View File

@@ -1,4 +0,0 @@
1
-import { WebViewSourceUri } from './types/WebViewTypes';
2
-
3
-export const isWebViewUriSource = (source: any): source is WebViewSourceUri =>
4
-  typeof source !== 'number' && !('html' in source);

+ 5
- 3
tsconfig.json View File

@@ -1,20 +1,22 @@
1 1
 {
2 2
   "compilerOptions": {
3 3
     "allowSyntheticDefaultImports": true,
4
+    "declaration": true,
5
+    "emitDeclarationOnly": true,
4 6
     "esModuleInterop": true,
5 7
     "jsx": "react-native",
6 8
     "lib": ["es6"],
7 9
     "module": "esnext",
8 10
     "moduleResolution": "node",
9
-    "noEmit": true,
10 11
     "noFallthroughCasesInSwitch": true,
11 12
     "noImplicitReturns": true,
12 13
     "noUnusedLocals": true,
13 14
     "noUnusedParameters": true,
15
+    "outDir": "./types/",
14 16
     "pretty": true,
15 17
     "skipLibCheck": true,
16 18
     "strict": true
17 19
   },
18
-  "include": ["src", "./typings.d.ts", "types", "test"],
19
-  "exclude": ["node_modules"]
20
+  "include": ["src", "index.js"],
21
+  "exclude": ["node_modules", "index.flow.js", "types"]
20 22
 }

+ 54
- 0
types/WebView.android.d.ts View File

@@ -0,0 +1,54 @@
1
+import React from 'react';
2
+import { NativeSyntheticEvent } from 'react-native';
3
+import { WebViewError, WebViewSharedProps, WebViewProgressEvent } from './types/WebViewTypes';
4
+declare enum WebViewState {
5
+    IDLE = "IDLE",
6
+    LOADING = "LOADING",
7
+    ERROR = "ERROR"
8
+}
9
+declare type State = {
10
+    viewState: WebViewState;
11
+    lastErrorEvent: WebViewError | null;
12
+};
13
+/**
14
+ * Renders a native WebView.
15
+ */
16
+export default class WebView extends React.Component<WebViewSharedProps, State> {
17
+    static defaultProps: {
18
+        overScrollMode: string;
19
+        javaScriptEnabled: boolean;
20
+        thirdPartyCookiesEnabled: boolean;
21
+        scalesPageToFit: boolean;
22
+        allowFileAccess: boolean;
23
+        saveFormDataDisabled: boolean;
24
+        originWhitelist: string[];
25
+    };
26
+    static isFileUploadSupported: () => Promise<boolean>;
27
+    state: State;
28
+    webViewRef: React.RefObject<React.ComponentClass<{}, any>>;
29
+    goForward: () => void;
30
+    goBack: () => void;
31
+    reload: () => void;
32
+    stopLoading: () => void;
33
+    postMessage: (data: string) => void;
34
+    /**
35
+     * Injects a javascript string into the referenced WebView. Deliberately does not
36
+     * return a response because using eval() to return a response breaks this method
37
+     * on pages with a Content Security Policy that disallows eval(). If you need that
38
+     * functionality, look into postMessage/onMessage.
39
+     */
40
+    injectJavaScript: (data: string) => void;
41
+    /**
42
+     * We return an event with a bunch of fields including:
43
+     *  url, title, loading, canGoBack, canGoForward
44
+     */
45
+    updateNavigationState: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
46
+    getWebViewHandle: () => number | null;
47
+    onLoadingStart: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
48
+    onLoadingError: (event: NativeSyntheticEvent<WebViewError>) => void;
49
+    onLoadingFinish: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
50
+    onMessage: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewMessage>) => void;
51
+    onLoadingProgress: (event: NativeSyntheticEvent<WebViewProgressEvent>) => void;
52
+    render(): React.ReactNode;
53
+}
54
+export {};

+ 114
- 0
types/WebView.ios.d.ts View File

@@ -0,0 +1,114 @@
1
+import React from 'react';
2
+import { NativeSyntheticEvent } from 'react-native';
3
+import { WebViewError, WebViewSharedProps, WebViewProgressEvent } from './types/WebViewTypes';
4
+declare enum WebViewState {
5
+    IDLE = "IDLE",
6
+    LOADING = "LOADING",
7
+    ERROR = "ERROR"
8
+}
9
+declare enum NavigationType {
10
+    click = "click",
11
+    formsubmit = "formsubmit",
12
+    backforward = "backforward",
13
+    reload = "reload",
14
+    formresubmit = "formresubmit",
15
+    other = "other"
16
+}
17
+declare type State = {
18
+    viewState: WebViewState;
19
+    lastErrorEvent: WebViewError | null;
20
+};
21
+/**
22
+ * `WebView` renders web content in a native view.
23
+ *
24
+ *```
25
+ * import React, { Component } from 'react';
26
+ * import { WebView } from 'react-native';
27
+ *
28
+ * class MyWeb extends Component {
29
+ *   render() {
30
+ *     return (
31
+ *       <WebView
32
+ *         source={{uri: 'https://github.com/facebook/react-native'}}
33
+ *         style={{marginTop: 20}}
34
+ *       />
35
+ *     );
36
+ *   }
37
+ * }
38
+ *```
39
+ *
40
+ * You can use this component to navigate back and forth in the web view's
41
+ * history and configure various properties for the web content.
42
+ */
43
+export default class WebView extends React.Component<WebViewSharedProps, State> {
44
+    static JSNavigationScheme: string;
45
+    static NavigationType: typeof NavigationType;
46
+    static defaultProps: {
47
+        useWebKit: boolean;
48
+        originWhitelist: string[];
49
+    };
50
+    static isFileUploadSupported: () => Promise<boolean>;
51
+    state: State;
52
+    webViewRef: React.RefObject<React.ComponentClass<{}, any>>;
53
+    UNSAFE_componentWillMount(): void;
54
+    _getCommands(): {
55
+        goForward: () => void;
56
+        goBack: () => void;
57
+        reload: () => void;
58
+        stopLoading: () => void;
59
+        postMessage: () => void;
60
+        injectJavaScript: () => void;
61
+    };
62
+    /**
63
+     * Go forward one page in the web view's history.
64
+     */
65
+    goForward: () => void;
66
+    /**
67
+     * Go back one page in the web view's history.
68
+     */
69
+    goBack: () => void;
70
+    /**
71
+     * Reloads the current page.
72
+     */
73
+    reload: () => void;
74
+    /**
75
+     * Stop loading the current page.
76
+     */
77
+    stopLoading: () => void;
78
+    /**
79
+     * Posts a message to the web view, which will emit a `message` event.
80
+     * Accepts one argument, `data`, which must be a string.
81
+     *
82
+     * In your webview, you'll need to something like the following.
83
+     *
84
+     * ```js
85
+     * document.addEventListener('message', e => { document.title = e.data; });
86
+     * ```
87
+     */
88
+    postMessage: (data: string) => void;
89
+    /**
90
+     * Injects a javascript string into the referenced WebView. Deliberately does not
91
+     * return a response because using eval() to return a response breaks this method
92
+     * on pages with a Content Security Policy that disallows eval(). If you need that
93
+     * functionality, look into postMessage/onMessage.
94
+     */
95
+    injectJavaScript: (data: string) => void;
96
+    /**
97
+     * We return an event with a bunch of fields including:
98
+     *  url, title, loading, canGoBack, canGoForward
99
+     */
100
+    _updateNavigationState: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
101
+    /**
102
+     * Returns the native `WebView` node.
103
+     */
104
+    getWebViewHandle: () => number | null;
105
+    _onLoadingStart: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
106
+    _onLoadingError: (event: NativeSyntheticEvent<WebViewError>) => void;
107
+    _onLoadingFinish: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewNavigation>) => void;
108
+    _onMessage: (event: NativeSyntheticEvent<import("./types/WebViewTypes").WebViewMessage>) => void;
109
+    _onLoadingProgress: (event: NativeSyntheticEvent<WebViewProgressEvent>) => void;
110
+    componentDidUpdate(prevProps: WebViewSharedProps): void;
111
+    _showRedboxOnPropChanges(prevProps: WebViewSharedProps, propName: 'allowsInlineMediaPlayback' | 'mediaPlaybackRequiresUserAction' | 'dataDetectorTypes'): void;
112
+    render(): React.ReactNode;
113
+}
114
+export {};

+ 6
- 0
types/WebViewShared.d.ts View File

@@ -0,0 +1,6 @@
1
+declare const WebViewShared: {
2
+    defaultOriginWhitelist: string[];
3
+    extractOrigin: (url: string) => string;
4
+    originWhitelistToRegex: (originWhitelist: string) => string;
5
+};
6
+export default WebViewShared;

+ 358
- 0
types/types/WebViewTypes.d.ts View File

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

+ 48
- 2
yarn.lock View File

@@ -892,6 +892,13 @@ argv-formatter@~1.0.0:
892 892
   version "1.0.0"
893 893
   resolved "https://registry.yarnpkg.com/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9"
894 894
 
895
+aria-query@^3.0.0:
896
+  version "3.0.0"
897
+  resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc"
898
+  dependencies:
899
+    ast-types-flow "0.0.7"
900
+    commander "^2.11.0"
901
+
895 902
 arr-diff@^1.0.1:
896 903
   version "1.1.0"
897 904
   resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a"
@@ -996,6 +1003,10 @@ assign-symbols@^1.0.0:
996 1003
   version "1.0.0"
997 1004
   resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
998 1005
 
1006
+ast-types-flow@0.0.7, ast-types-flow@^0.0.7:
1007
+  version "0.0.7"
1008
+  resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
1009
+
999 1010
 async-limiter@~1.0.0:
1000 1011
   version "1.0.0"
1001 1012
   resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
@@ -1022,6 +1033,12 @@ aws4@^1.8.0:
1022 1033
   version "1.8.0"
1023 1034
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
1024 1035
 
1036
+axobject-query@^2.0.1:
1037
+  version "2.0.2"
1038
+  resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
1039
+  dependencies:
1040
+    ast-types-flow "0.0.7"
1041
+
1025 1042
 babel-code-frame@^6.22.0:
1026 1043
   version "6.26.0"
1027 1044
   resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -1537,7 +1554,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
1537 1554
   dependencies:
1538 1555
     delayed-stream "~1.0.0"
1539 1556
 
1540
-commander@^2.9.0:
1557
+commander@^2.11.0, commander@^2.9.0:
1541 1558
   version "2.19.0"
1542 1559
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
1543 1560
 
@@ -1775,6 +1792,10 @@ cyclist@~0.2.2:
1775 1792
   version "0.2.2"
1776 1793
   resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
1777 1794
 
1795
+damerau-levenshtein@^1.0.4:
1796
+  version "1.0.4"
1797
+  resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514"
1798
+
1778 1799
 dashdash@^1.12.0:
1779 1800
   version "1.14.1"
1780 1801
   resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -1990,6 +2011,10 @@ ee-first@1.1.1:
1990 2011
   version "1.1.1"
1991 2012
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
1992 2013
 
2014
+emoji-regex@^6.5.1:
2015
+  version "6.5.1"
2016
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.5.1.tgz#9baea929b155565c11ea41c6626eaa65cef992c2"
2017
+
1993 2018
 encodeurl@~1.0.1, encodeurl@~1.0.2:
1994 2019
   version "1.0.2"
1995 2020
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@@ -2076,7 +2101,7 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
2076 2101
   version "1.0.5"
2077 2102
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
2078 2103
 
2079
-eslint-config-airbnb-base@13.1.0:
2104
+eslint-config-airbnb-base@13.1.0, eslint-config-airbnb-base@^13.1.0:
2080 2105
   version "13.1.0"
2081 2106
   resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c"
2082 2107
   dependencies:
@@ -2084,6 +2109,14 @@ eslint-config-airbnb-base@13.1.0:
2084 2109
     object.assign "^4.1.0"
2085 2110
     object.entries "^1.0.4"
2086 2111
 
2112
+eslint-config-airbnb@17.1.0:
2113
+  version "17.1.0"
2114
+  resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz#3964ed4bc198240315ff52030bf8636f42bc4732"
2115
+  dependencies:
2116
+    eslint-config-airbnb-base "^13.1.0"
2117
+    object.assign "^4.1.0"
2118
+    object.entries "^1.0.4"
2119
+
2087 2120
 eslint-config-prettier@3.3.0:
2088 2121
   version "3.3.0"
2089 2122
   resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.3.0.tgz#41afc8d3b852e757f06274ed6c44ca16f939a57d"
@@ -2119,6 +2152,19 @@ eslint-plugin-import@2.14.0:
2119 2152
     read-pkg-up "^2.0.0"
2120 2153
     resolve "^1.6.0"
2121 2154
 
2155
+eslint-plugin-jsx-a11y@6.1.2:
2156
+  version "6.1.2"
2157
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.2.tgz#69bca4890b36dcf0fe16dd2129d2d88b98f33f88"
2158
+  dependencies:
2159
+    aria-query "^3.0.0"
2160
+    array-includes "^3.0.3"
2161
+    ast-types-flow "^0.0.7"
2162
+    axobject-query "^2.0.1"
2163
+    damerau-levenshtein "^1.0.4"
2164
+    emoji-regex "^6.5.1"
2165
+    has "^1.0.3"
2166
+    jsx-ast-utils "^2.0.1"
2167
+
2122 2168
 eslint-plugin-react-native-globals@^0.1.1:
2123 2169
   version "0.1.2"
2124 2170
   resolved "https://registry.yarnpkg.com/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz#ee1348bc2ceb912303ce6bdbd22e2f045ea86ea2"